Three.js in production: keeping 60fps on a budget
Practical rules for shipping WebGL on a marketing site without melting anyone's laptop.
This is placeholder content. Edit or delete it from the CMS at
/admin.
WebGL backgrounds are the pop-up shops of web design: delightful when done well, and a fire hazard when not. Here’s the checklist I actually use before shipping a Three.js scene on a page whose job is content, not the canvas.
Budget first, aesthetics second
Decide the frame budget before you open the editor. For an ambient background, I aim for under 2ms of GPU time per frame — the scene is a guest in someone’s browser, not the main act.
The checklist
- One draw call per concept. Points in a single
BufferGeometry, lines in a singleLineSegments. If you’re creating meshes in a loop, stop. setPixelRatio(Math.min(devicePixelRatio, 2))— retina is real, 3x rendering is not worth it.- Pause when hidden.
visibilitychange+cancelAnimationFrame. Background tabs shouldn’t cost battery. - Static frame for
prefers-reduced-motion. Accessibility isn’t a nice-to-have, and vestibular disorders are more common than you think. - No per-frame allocations. If
new THREE.Vector3()appears inside your render loop, the garbage collector will find you.
The part nobody tells you
The biggest win isn’t in the render loop — it’s in restraint. Four hundred particles look better than four thousand, because atmosphere comes from negative space. The same is true of most things.