Immersive Front Ends Without the Jank
3D and SVG can make an interface memorable without making it slow. When a scene earns its place, and the rules that keep it fast on a real phone.
Immersive and fast are not opposites. Most slow 3D sites are slow because of decisions made before anyone wrote a shader: a scene on the critical path, uncompressed assets, and a render loop that never stops. Get those three right and most of the performance work is done.
3D has to earn its place
Before any tooling question, I ask what the scene does that an image cannot. A product the visitor can turn in their hands, a space they can move through, data that genuinely has depth — those justify a GPU. A spinning logo behind the hero does not.
Decoration is not forbidden. It just has to be priced like everything else: bytes, main-thread time, battery. If the page reads the same with the scene replaced by a still image, ship the still image first and treat the scene as an enhancement.
The scene is not the page
The pattern that holds up best is also the simplest: a poster first, the scene later.
- A static poster renders with the HTML. A pre-rendered frame of the scene, sized for the slot and loaded eagerly if it is the largest element. That is what LCP measures, and it needs no JavaScript.
- The 3D bundle is code-split. Three.js and its loaders live in their own chunk behind a dynamic import. Visitors who never reach the scene never download it.
- The scene loads after first paint, or when it approaches the viewport. An IntersectionObserver is enough. The canvas fades in over the poster once its first frame is ready, and the layout never moves.
The renderer choice matters less than it used to. Three.js's WebGPURenderer falls back to a WebGL 2 backend when WebGPU is unavailable, so one codebase covers both. I still test the fallback deliberately, because a meaningful share of devices will take that path.
The asset pipeline is half the work
A raw export from a 3D tool is a source file, not a delivery file. It should go through a build step, the same way images do:
- glTF as the delivery format. It is the format the web tooling is built around.
- Geometry compression. Meshopt or Draco, after welding vertices and pruning unused data. Meshopt also compresses morph targets and animation.
- KTX2 textures. JPEG and PNG are small on the wire but expand to full size in GPU memory. KTX 2.0 with Basis Universal stays compressed on the GPU, which is where mobile devices run out first.
- Scripted, not manual. glTF Transform runs all of this from the command line, so the optimization is reproducible and lives in the repository rather than in someone's export settings.
Texture resolution is usually the biggest single saving. A 4K texture on an object that covers a fifth of a phone screen is memory spent on pixels nobody sees.
Render only when something changes
Most 3D examples run a loop sixty times a second, forever. That is right for a game and wrong for a product viewer that sits still most of the time.
- Render on demand. React Three Fiber's
frameloop="demand"draws a frame only when something changes. Its performance guide is the best short reference on this whole section. - Cap the device pixel ratio. A phone at 3x renders nine times the pixels of 1x. A cap of 1.5 or 2 is rarely visible and always measurable.
- Pause when nobody is looking. Stop the loop when the canvas leaves the viewport and when the tab is hidden.
- Cut draw calls. Instancing for repeated objects, shared geometries and materials, and level of detail for anything that can sit far from the camera.
A scene that is not moving should cost nothing.
SVG for the interface layer
Not every immersive effect needs a GPU context. Stroke drawing, icon transitions, shape morphing and scroll-linked diagrams belong in SVG: resolution-independent, accessible, and styled with the same CSS as the rest of the interface.
SVG has its own traps. Filters such as blur and turbulence are repainted on every frame they animate. Illustrations exported with thousands of paths are expensive to rasterize, and heavier still when they sit inside a component tree that re-renders. Keep motion on transform and opacity, simplify paths at build time, and inline only the SVGs that actually animate.
Motion is optional; content is not
Some visitors have asked their operating system for less motion, and prefers-reduced-motion passes that request to the page. For them, the scene becomes the poster, the stroke animation becomes the finished drawing, and nothing is lost except the movement.
It is also the best test of the design. If the reduced-motion version is complete, the interface never depended on animation to communicate.
Measure on the phone your users own
A development laptop hides every problem in this article. Test on a mid-range Android, or at minimum with 4–6× CPU throttling, and watch three numbers:
- LCP — it should be the poster, and nothing should shift when the scene arrives.
- INP — 200 milliseconds or less, including interactions while the scene is still initializing.
- Frame time — about 16 ms per frame at 60 fps. Frames that run past 50 ms are the ones visitors feel as jank.
Scene initialization is the usual INP trap. Shader compilation and texture upload happen on the main thread, often just as the visitor starts to scroll. Doing that work behind the poster, before the canvas is shown, keeps it out of the interactions that count.
Immersion is a design decision. Performance decides whether anyone stays long enough to see it.