The Instrument
My portfolio in 3D: a scroll down through a stylised dilution refrigerator, one cold stage for each layer of how I build.

- scroll-linked stages, from interfaces to personal projects
- 10
- scales, 100 mm and 1 mm per unit, cut between
- 2
- quality tiers, stepped down at runtime
- 3
- Playwright smoke tests in CI
- 5
Overview
The Instrument is a spatial take on this portfolio. You scroll down through a stylised dilution refrigerator, the gold chandelier that cools superconducting quantum computers, and each stage holds one layer of how I build: interfaces, services, GPU servers, edge devices, digital twins and personal projects. It's a static Next.js export rendered live with React Three Fiber and custom GLSL. The hardware is procedural, and every physical number on it is a typical published value with its source on a sources page.
Problem → built → result
- Problem
- A 3D portfolio that still works as a page, for screen readers, slow phones and weak GPUs.
- Built
- Ten scroll-linked stages in React Three Fiber, a camera rig across two scales, posters from the scene.
- Result
- 10 stages · a static path for no WebGL and reduced motion
Features
- All copy is DOM; the canvas is aria-hidden and every stage has a screen-reader description of what the scene shows
- “Skip descent” is the first focusable element, and “Read as a page” removes the scene entirely
- Three quality tiers (pixel ratio, particle count, materials, post-processing), stepped down at runtime by a performance monitor
- Fully procedural hardware, no model files; shaders compile before the canvas fades in over the poster
- A sources page generated from the same data as the scene, so every number on screen has a citation
Decisions
- 1
Two spaces, one camera.
The large scene works at 1 unit = 100 mm and the chip at 1 unit = 1 mm. The camera cuts between them behind a short black veil, so no frustum spans metres and micrometres and no logarithmic depth buffer is needed.
- 2
Scroll-linked, not scroll-jacked.
Native scroll, smoothed by Lenis, is the only input; nothing intercepts the wheel or snaps. The camera damps its position on the curve, not the scroll, and J / K and 0–9 jump between stages.
- 3
React never renders per frame.
Per-frame values are mutated in place and read in the render loop; UI state lives in a tiny useSyncExternalStore store, so scrolling never triggers a React render.
- 4
Posters first.
A script renders one still per stage from the real scene. The stills are the LCP image, and the whole visual on the static path: no WebGL2, Save-Data, a blocklisted GPU or reduced motion.
Why it's shaped this way
A 3D site is only as good as its worst device. The scene is an enhancement over real HTML: every stage reads as text, and anything that can't run WebGL well gets the posters instead of a stutter.