When Three.js improves a marketing website
Spatial interaction earns its place when it makes a proposition clearer, a system more explorable or a transition more memorable.
HTML remains the source of truth
Core messages, links and evidence stay server-rendered. WebGL enhances the interface; it is never the only place meaning exists. The practical test is simple: disable JavaScript and see whether the page still makes its argument. If it does not, the site has traded its search visibility for an effect — and search engines are not the only ones affected, because that is also what a visitor on a failing connection gets.
Motion needs a job
Camera movement should show hierarchy, shaders should support a transition, a 3D object should embody the subject. Bridge Consult assembles a bridge as its case study opens; FIDIC unfolds a contract atlas. Neither is a modal, and neither is decoration — each one is the subject of the page, moving. Anything that cannot answer what it is for gets removed, which on this site meant most of the first draft.
Performance is art direction
DPR caps, texture budgets, adaptive frame rates, pausing when the tab is hidden and isolated rendering layers shape the final aesthetic as much as materials do. Constrained devices are opted out entirely: Save-Data, two gigabytes of memory or two hardware threads get the CSS background instead of a WebGL context, which is what a WebGL failure would leave them with anyway — so there is no second code path to maintain.
The mobile GPU is a different budget
A desktop-comfortable scene can be unusable on a phone for reasons that never show up in a local test. This site rendered every frame twice in its archive — the scene into a render target, then a fullscreen composite for grain and vignette — and on a phone GPU that memory bandwidth is the entire budget. It now draws straight to the screen and only spins the composite up during a transition wipe.
Reduced motion is not an off switch
Respecting prefers-reduced-motion means slowing something down, not freezing it. This site paused its preloader object with animation-play-state, and on any phone with Reduce Motion enabled that read as a broken page — a cube standing still. It now turns slowly instead of dying. Accessibility settings describe a preference about movement, not a request for a stopped interface.
Load it late, or not at all
The three.js runtime is around 132 KB compressed and half a megabyte to parse, so when it loads matters as much as whether. Measured on this site it starts downloading roughly three seconds in, well past the window that decides LCP. Going further than that is not automatically better — the obvious next optimisation made the bundle larger, which is the sort of thing only a measurement tells you.