SCYTALEGUIDE
206Wave 10 · Secrets — how it was made

Scytale — transposition cipher as live geometry

A museum case for the oldest military cipher we can point to: a ninety-letter Spartan dispatch on an oiled leather strap, wound around a staff whose diameter you control. One circumference — five letters to the turn — stacks the columns into five clean rows and the dispatch reads along the wood. Every other girth shears it back into noise. The page's single job: make you feel the moment a shape becomes a key.

01Palette

Argued from the object in the case

#141008
Museum-dark umber — the unlit case interior; everything floats in it.
#9C7A4A
Olive-wood staff, canvas-grained; the key itself.
#6B4630
Oiled leather strap, mottled procedurally.
#EADFC8
Inscription bone — LINE/MARK token: the letters, the read-line, HUD numerals.
#A63A2E
Laconian-glaze crimson — marks only: the aligned lath, ticks, rules. Never body text.
#CBBDA0
Body ink, derived from the bone and dimmed — 10.3:1 on the umber, so copy never borrows the mark colour.

Per the wave rule, the bright bone is reserved for lines and marks; small text gets its own darker ink. The crimson appears in exactly three places — the "5" detent tick, the aligned read-lath under the letters, and the failure state's border — so the moment of decryption owns the only red on the page.

02Type

Lapidary and instrument

Marcellus

AIGOSPOTAMOI

A roman inscriptional face built from lapidary capitals — the letters on the strap are drawn with it into the glyph atlas, so the inscription and the headline are literally the same stone-cut voice. Display and body both; one face carries the museum.

Spline Sans Mono

SHEAR +0.20 L/TURN

The case instruments: circumference, shear, turns, the read-along-the-staff panel. A humanist mono that stays legible at 10px tracking wide — the modern conservator's label against the ancient object.

03Techniques

The signature: parametric helix winding

The whole site is one React Three Fiber scene, loaded with no build step via an ES-module importmap (react 18.3.1, @react-three/fiber 8.17.10, @react-three/drei 9.114.3, three 0.160.0, htm 3.1.1 — markup as htm tagged templates with explicit React.Fragment, since the fragment shorthand crashes R3F's reconciler in a no-JSX build). If the stack fails to resolve or WebGL is absent, a static SVG fallback ships instead of a dead canvas.

The strip is two things. The leather is a single ribbon BufferGeometry — 541 sample pairs, six per letter — whose vertices are re-marched every frame the geometry changes: wound samples follow the analytic helix (radius R = L·0.36 / 2π for circumference L in letters, axial pitch 0.325 per turn), and unwound samples switch to a numeric march with a gravity steer, so the loose tail dives off the staff, hits the case floor, and pools into a flat coil whose curvature decays as it feeds — the coil visibly un-pools as the intro winds. The ninety letters are one InstancedMesh: a canvas-drawn glyph atlas (27 cells, 96×128, drawn in Marcellus — no raster files) sampled by a per-instance cell attribute in a small ShaderMaterial, with a per-instance angle attribute driving a raking-light term so the row facing the read-line brightens. Each instance's basis is set so glyphs stand upright along the staff axis — which is precisely why the decoded rows read horizontally only when turns stack.

Everything the HUD says is measured, not scripted: shear is recovered from the instanced angles (the fold of the angular slip between letter 0 and letter round(L), converted to letters per turn), the read panel picks the physically nearest letter per turn along each axial line (idx = round(a + n·L)), and "letters read true" counts character matches against the dispatch. A wrong integer staff — four or six letters round — stacks its columns perfectly and still reads garbage, so the HUD gets its own state for it: COLUMNS TRUE · TEXT FALSE. The honest failure is driven, not narrated: CUT THE STRIP leaves 24 letters — 4.8 turns on the true staff, rows of four or five letters — and every wrong diameter produces fragments no worse, which is the real cryptographic point.

04Honest numbers

Measured from the running case

90 = 5 × 18letters on the strap — five rows of eighteen at the true circumference of 5 letters/turn
3.2 – 7.5slider range, letters per turn, 0.05 steps; radius spans 0.18–0.43 world units
+0.20 → 21/90at the resting 5.2 letters/turn the columns shear a fifth of a letter per wrap; 21 of 90 letters still read true
24 → 4.8 turnsthe cut strip on the true staff — rows recover 5,5,5,5,4 letters; the key becomes unprovable

The historical claims are hedged where the literature hedges: Plutarch (five centuries after Lysander) is the fullest source for the scytale as a cipher, and some modern scholarship reads the earlier mentions as a plain message-baton. The dispatch itself is our reconstruction — the battle of Aigospotamoi, 405 BC, is real; the strap's text is not a surviving artefact and the page says so.

05Iteration log

Three passes, driven

Pass 1 — Craft

Driving the diameter control headlessly caught a genuinely fatal defect that every load-probe passed: the WebGL fallback overlay used display:grid, which silently overrides the HTML hidden attribute — the entire 3D case was rendering perfectly behind its own fallback poster. One rule (#fallback[hidden]{display:none}) fixed it. Then framing: the first camera sat so close the staff read as a macro photo; pulled back to a museum shot (fov 36, dist ≈ 9.8), lifted the floor, and added a warm elliptical light-pool so the lower half of the case has depth instead of void.

Pass 2 — Depth

The unwound tail originally just hung — replaced with the gravity march so the remainder pools into a coil of still-inscribed leather on the case floor, and the intro visibly feeds it onto the staff for thirteen seconds. Added the second-read details: a faint Λ branded into the bare olive wood; the COLUMNS TRUE · TEXT FALSE state for wrong integer staffs; and after two seconds of held alignment the HUD quietly translates the dispatch. Verified the two-frame liveness diff and the drive-then-diff both pass, and asserted the aligned state decodes to exactly the five dispatch rows.

Pass 3 — Hardening

At 375px the staff crossed the headline — restructured the hero so the copy is static flow above the stage on small screens and re-aimed the narrow camera (rot 0.72, fov 41). Removed the case back-wall, invisible under fog (one ornament fewer). Fixed an honest-numbers slip in the copy: the cut strip's fifth row recovers four letters, not five. Confirmed reduced-motion (instant wind, demand frameloop), zero console errors across desktop, 375px and reduced-motion runs, and re-read every figure above against the shipped constants.