Shipping 3D on the web without killing performance
A practical checklist for Three.js and React Three Fiber sites that load fast, stay smooth and still work when WebGL doesn't.
A 3D hero can make a site unforgettable — or make it the slowest page a client ever opened. Here's the checklist I use so the 3D adds to the experience instead of taxing it.
Treat 3D as progressive enhancement
All real content lives in HTML. The canvas sits behind it with aria-hidden. If WebGL is missing, a lightweight CSS gradient backdrop takes its place. Search engines and screen readers never depend on the canvas.
Load it last
- Split three.js into its own chunk with
React.lazy(). - Mount the canvas only after hydration, inside
requestIdleCallback, so the headline paints first and Largest Contentful Paint stays fast.
One canvas, not many
Every <Canvas> is a separate WebGL context. Use one persistent, fixed canvas for the whole site and move the camera or objects as the visitor scrolls or navigates.
Let the device decide the quality
PerformanceMonitorlowers the pixel ratio when frame rate drops.- Fewer particles and no antialiasing on small screens.
- Procedural geometry (like an icosahedron) instead of downloading models when you can.
Compress anything you do download
npx gltf-transform optimize model.glb model.min.glb \
--compress meshopt --texture-compress ktx2
Aim for under 2–3 MB of total 3D payload.
Respect reduced motion
When prefers-reduced-motion is on, stop the rotation and switch the render loop to frameloop="demand". The scene becomes a still, beautiful backdrop — and battery life is spared.