Sheet 04 · Live

Horologia

Exploded 3D mechanical watch movement, disassembles on scroll.

  • Three.js
  • GSAP ScrollTrigger
  • Lenis
  • Web Audio API
  • Firebase
  • Vite

Imagery

SCREENSHOT_REQUIRED

A silent, autoplaying 10–20 second loop of the movement disassembling on scroll. This case study should be mostly video.

Two or three hero stills at 2x, plus one 10–20 second silent screen recording of the primary interaction.

SCREENSHOT_REQUIRED

The raycasting inspector open on one component, showing its material hardness, friction coefficient and horological function.

Two or three hero stills at 2x, plus one 10–20 second silent screen recording of the primary interaction.

What it is

A mechanical watch movement, generated procedurally in the browser, that takes itself apart as you scroll.

Fourteen components: a five-stage gear train with real teeth, an escapement with pallet jewels, a Glucydur balance wheel with a Breguet hairspring, a tourbillon cage, 27 ruby jewels and an automatic rotor. None of it is a downloaded model.

Why it exists

No client. No brief. No deadline.

It is an exercise in finding the ceiling of what a browser can do, and I would rather say that plainly than invent a business case for it after the fact.

The hard problem

A watch movement is not decorative geometry — it is a mechanism where every part exists because of the part next to it. Generating it procedurally means encoding the relationships, not just the shapes: tooth counts that mesh, an escapement that actually gates the gear train, a balance that sets the rate.

Getting it to look right is modelling. Getting it to be internally consistent is the interesting part.

The decisions

A raycasting inspector, not labels

Point at any component and it reports material hardness, friction coefficient and horological function. The information belongs to the part, so it is retrieved by pointing at the part.

The ticking is synthesised, not sampled

Web Audio at 28,800 vibrations per hour, with alternating pallet clicks, because a real escapement does not tick symmetrically. A sample loop would have been faster and would have sounded like a loop.

A live PBR material lab with five presets

The same geometry under different materials, changeable while it runs.

Saved configurations sync when Firebase is reachable and persist locally when it is not, so the piece works end to end with no network at all.

What I would do differently

It has no performance budget. I built it to find the ceiling, which meant I never asked what it costs on a mid-range Android — and mid-range Android is what most of the people I know are holding. I would now set that budget at the start and let it constrain the geometry, rather than measuring afterwards and hoping.

No brief also meant no definition of done. Fourteen components is where I stopped, not a number I chose. That was fine here because nobody was waiting for it; it would not have been fine anywhere else.

All work