What it is
A concept pair of over-ear headphones, shown as a scroll story: it comes apart into twenty-eight pieces, with thirteen screens: each cup, the driver, materials, the headband, comfort and fit, cable and jack, a spec sheet and what is in the box, then it goes back together. You pick one of four finishes and turn the model by dragging, and a closing screen links back to the Lab. It is a study of the technique, not a product: nothing on the page is a claim about a real product.
Engineering decisions
- Everything is generated in code: lathe profiles for the shells, cap, driver and cushion rings, tubes for the headband and its pad, cylinders for screws and sliders. There is no model file and no texture download.
- Lighting is a handful of emissive panels rendered once through
PMREMGenerator into an environment map, so there is no HDRI to download. A radial gradient on a plane stands in for the contact shadow and spreads as the parts separate. - Camera poses, the explosion amount and the story text are data in
data.ts: one pose per step, spaced evenly along the scroll, so adding a screen is one pose plus one step. Spec sheet and in-the-box rows are an optional list on a step, rendered as an HTML dl; the label window scales with the frame spacing. samplePose interpolates between frames and moves for the first 80 % of each segment before resting, so the text arrives after the camera has settled. - GSAP scrubs one plain state object (
progress, scrub: 0.5, low because Lenis already smooths the wheel); the render loop reads it every frame. Scrolling never re-renders React. The canvas runs with frameloop="demand" and is invalidated whenever the progress, a drag, a rotation or a colour change moves something. - Parts peel off each side from the outside in (cap first outward, cushion first towards the ear), so a moving part never passes through one still at rest; discs only spin in their own plane, never tilt into a neighbour. Each part has a
lag, so they start at different moments but arrive together. A unit test checks the stack order at every explosion amount. - A drag only lasts until the next scroll: once the story moves, the model eases back (the shortest way round) to the angle the next screen is framed for.
- The turntable is a small pointer handler with momentum instead of orbit controls. The canvas has
touch-action: pan-y, so a vertical swipe scrolls the page and a horizontal drag turns the model. The Rotate buttons and the arrow keys on the finish picker are the keyboard route. - Interaction on top of the story: the model leans slightly towards the pointer; a raycast (only after the pointer or the model moves) finds the part under it, which gets an additive Fresnel rim glow and a floating name tag; a click (a short press that barely moved, so drags are unaffected) nudges that part, a hop out along its axis with a full turn in its own plane, ending exactly where it started. On "The driver" three additive rings leave the driver towards the ear. The "Make it yours" step has a Pull apart slider; the larger of it and the scroll pose wins. A small warm point light follows the pointer. Fast scrolling spreads the parts slightly and they spring back. "The driver" has a test tone button: a three-second sweep generated with Web Audio (no file), played through an analyser whose level speeds up the rings and pumps the driver cone.
- More feedback: the hover tag carries a one-line description of the part; a nudge throws a burst of additive sparks from the part; turning the model swings the loose cable the other way on a damped spring; picking a finish sweeps a short glow of its accent over the body; the LED brightens with the test tone.
- The headband pad is swept along the inside of the arch (offset along the arch's inward normal, elliptical section, rounded ends), so it stays tucked under the band all the way round.
- Turning by hand: a dial (
role="slider", arrow keys turn 15°, Page keys 90°, Home goes back to the start) whose ruler slides under a fixed needle as the model turns, with a degree readout; dragging the dial or the model both move it. - Living background: two large blurred radial glows behind the transparent canvas, one in the finish accent and one tinted per step (CSS colour transition), travel with the scroll, lean towards the pointer and brighten as the parts separate. A gsap ticker writes their transforms only when a value changes and stops while the stage is off-screen; under reduced motion they do not drift or follow the pointer.
- Finishes are a radio group with a roving tabindex. Colours and metalness ease towards the chosen finish.
- Quality tiers:
low (phones, 4 cores or fewer, or ?quality=low) uses lower DPR, fewer geometry segments, no clear coat and no antialiasing. ?debug shows the frame rate. - The canvas is
aria-hidden; the steps are real headings and paragraphs. If the graphics context is lost the poster is shown, and the canvas is rebuilt when the context comes back.
Performance notes
Three.js is the bulk of this page's JavaScript and loads only on this page, after the poster is in view and the browser is idle. Geometries, materials and the shadow texture are disposed when the page unmounts.
Reduced motion
No camera travel and no momentum. Each step cuts to its pose behind a 0.15 s fade, colours switch at once, and the Rotate buttons turn the model in one step. No pointer tilt, nudges, sparks, cable swing, finish glow, scroll spread or driver rings (the test tone still plays); the hover glow and tag appear without a fade and the slider jumps straight to its value.