Open my homepage and a dragon flies in from the distance and lands in front of the camera. It is not a video — it is a real-time 3D model rendered with three.js. In a React project I use React Three Fiber (R3F) with @react-three/drei; the declarative style makes the 3D scene as manageable as any other React component.
Putting the model on a diet: 32MB to 1.8MB
The original dragon model was 32MB — completely unusable on the web, where the download alone would take seconds, let alone on mobile networks. Through geometry compression, texture downscaling, and trimming animation data, I got it down to about 1.8MB with almost no visible loss. Asset size is the first performance gate of 3D on the web; sort out your assets before talking about render optimization.
Flight path and animation blending
The entrance is a two-segment bezier path: take off from afar, pass a waypoint, then land in front of the camera. Once landed, the flying animation crossfades into idle and the dragon hovers gently in place. The path adapts to the device — on narrow portrait phone screens the dragon can crowd the text, so the mobile trajectory is lifted higher while the landing point stays the same.
Respecting user preferences
Not everyone wants things moving on their screen. I check prefers-reduced-motion: if the user has asked the system to reduce motion, the entire 3D scene is simply never loaded — not just paused, but no model download and no WebGL context at all, giving the performance and bandwidth back to the user.
Static export caveats
WebGL cannot render on the server, so the R3F canvas must be loaded with next/dynamic and ssr: false. The canvas sits behind the hero as a background with pointer-events: none, and the content layer stacks above it with z-index — the 3D stays purely visual and never interferes with interaction.
3D is not about showing off; it is a brand memory hook. Control your asset sizes, respect user preferences, and layer things properly — it can be spectacular without slowing your site down.
Max Chu