The Lab
Techniques I’ve worked out on websites and projects, written up with the code that runs them.
P.S. A few of them are running on this page right now.
Fit
3D · WebGL · CameraAn orthographic camera has no field of view to fall back on, so framing the hero room in an unknown viewport is arithmetic: two candidate zooms, one per axis, and the more restrictive one wins.
The diorama in the hero at the top of the home page, at any window size. Drag the browser edge about. The room is framed identically on a phone and on a 4K panel, because the same 21 × 18.5 world units are being fitted either way.
Scrub
Scroll · Scroll · GSAPThe statement on the home page is not triggered by scroll. It's played by it. Thirteen words ink in, half a beat apart, and the beat that matters most is the one where nothing animates at all.
This runs on the home page, just past the selected-work list: 'Worlds rendered live in the browser. You feel them before you read them.' inks in word by word as you scroll it, holds still, then leaves. Scroll it slowly, then scroll back up. It un-inks, because scroll is the only clock it has.
Magnet
Interaction · GSAP · InteractionEvery text button and pill on this site leans toward the cursor as it approaches. The arithmetic is three lines. The thing that makes it read as weight rather than jitter is the fourth, and it's one GSAP call.
Every text button and pill on this site. The 'Start a project' pill in the home page hero is the nearest one, and the 'Go and look' button below this paragraph is another. Approach either slowly and watch it lean before you arrive.
Swarm
3D · WebGL · InstancingFive packets crawl the cable across the floor of the hero, and between them they cost one draw call and five floats. An InstancedMesh, a Catmull-Rom curve, and a matrix buffer the CPU rewrites every frame.
The cable running across the floor from the rack to the desk in the hero diorama. The faint green pulses crawling along it are the packet feed. Watch one for a few seconds and you'll see it swell as it passes the middle of its run.
Halftone
Interaction · WebGL · ShaderThe work index crossfades one project into another three pixels at a time. Quantise the screen coordinate, hash the square, threshold once per cell. A dissolve made of grain rather than of edge.
The work index. Hover a project row and the panel that parks beside it crossfades into that project. That crossfade is this shader, running at a three-pixel cell.
Pool
Interaction · Canvas · SimulationA pond you can tap, from two arrays and one line of arithmetic. The line is the wave equation written out longhand, and the thing that makes it look like water isn't the height. It's the slope.
Not on the site yet.
Shaft
3D · WebGL · GeometryThe beam through the workshop window is not a post-processing pass. It's a five-quad prism from the window rectangle to its projection on the floor, rebuilt from the live sun vector every frame.
The window in the hero diorama on the home page. Click the window itself. It advances the sun twelve hours over 2.4 seconds, and the shaft is rebuilt on every frame of that sweep.
Plume
3D · WebGL · ShaderThe steam off the coffee mug in the hero is one tall quad. The vertex shader folds it, the fragment shader carves its alpha out of scrolling noise, and nothing in it is a particle.
This is the plume rising off the mug on the desk in the hero diorama on the home page. One draw call, no simulation, and a per-frame cost of two uniform updates and an atan2.
Velocity
Scroll · Scroll · MotionHow fast you're scrolling is a design input, and the browser never hands you a usable number for it. One line of smoothing turns a spiky per-frame delta into the signal half this site leans on.
Open any case study from the work index and scroll. The hero lines lean as they leave. The faster you go, the further they lean, up to four degrees and no further.
Dissolve
Interaction · WebGL · ShaderEvery transition on this site is one shader eating the page from a corner. No slide, no wipe, no straight line anywhere. The whole trick is four lines, and it comes down to where you add the noise.
This is the same shader that runs when you open the menu from the button in the top right. Go on, open it, then come back.