← back to all posts
three.jsperformancewebgl

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 single LineSegments. 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.