Showroom · Make-of
How Vesper was made
A fictional maison presents one automatic wristwatch — and the page contains no photographs at all. The watch is five layers of hand-set SVG posed in real CSS 3D: it tilts toward the pointer, keeps the visitor's actual time, pulls apart into an exploded stack as the reader scrolls, and carries a moonphase that is computed correct on the night it is viewed. No libraries, no WebGL, no images from anywhere.
View the site →What it demonstrates
That "3D product page" doesn't have to mean WebGL. Five flat drawings, stacked with
real depth (preserve-3d + translateZ under one
perspective), read as an object the moment they tilt together — because the parallax between
crystal, hands, dial and case is geometrically true. And the page keeps the house rule:
nothing is claimed that the code can't back. The hands show your time. The moon is your moon.
Techniques, honestly named
- A five-layer 3D stack — strap, case, dial, hands and crystal are
separate same-size SVGs at
translateZ−46 / 0 / 26 / 44 / 64 px inside oneperspective: 1150pxscene. Pointer position easesrotateX/rotateYtargets (spring-lerped, ±17°/±21°), and with no pointer — hover previews, phones — the watch sways on its own slow sines. - A glare that obeys the tilt — the crystal layer carries a clipped gradient streak whose rotation and offset are driven by the same rx/ry, so the highlight travels across the dome exactly opposite the tilt, the way a real box crystal catches a lamp.
- Scroll as disassembly — scroll progress feeds piecewise smoothstep curves that separate the layers to −150…+235 px, pitch the stack to 26°, swing it −24°, and scale it to fit; five labels fade in against the spread. The same curves reassemble it on the way down, so the journey reads: watch → parts → watch.
- Hands that keep real time at 4 Hz — hour and minute derive from
new Date()each frame, and the seconds hand advances in eight discrete steps a second (floor(ms / 125) · 0.125) — the exact cadence of a 28,800 vph movement, stated on the page and animated truthfully. The balance wheel in the movement diagram swings on a 250 ms CSS alternate loop: the true beat. - A guilloché dial plotted by code — an offscreen canvas draws 59
concentric barleycorn rings (radius + a small sine of the angle, phase advancing per
ring) over a midnight radial ground, then feeds the dial's clipped
<image>as a data URL. 59 rings on purpose: one per tooth of the classic moonphase wheel. - A moonphase that cannot drift — days since the known new moon of
2000-01-06 18:14 UTC, modulo the mean synodic month (29.530588853 days), give the moon's
age; the disc is drawn with the true terminator (limb semicircle + ellipse of semi-axis
R·|cos φ|, bulge chosen by quadrant) plus a little earthshine so even a new moon reads. The same rendering fills the dial's aperture and the essay's big moon — one source of truth, refreshed hourly. - Respectful fallbacks — reduced motion (or
?flat=1, or no JS) collapses the sticky stage into a plain document with the watch assembled and still; the movement animations stop; the copy still carries every fact. The rAF loop pauses onvisibilitychange, and everything animated is transform/opacity only.
Recreate it
The full recreation prompt — the layer stack and its depths, the tilt spring and glare mapping, the four scroll curves, the 4 Hz hand math, the guilloché recipe, the moonphase formula with its terminator construction, and the quality bar — is in the showroom vault.