Studio notesEngineering

The 3D web stack, and how to pick from it

WebGL, Three.js, React Three Fiber, Spline, Unity, WebGPU. What each one is actually for, what it costs you, and the decision we would make in your position.

Mainichi11 min read
Copied

Updated July 1, 2026

In short

  • Three.js is the floor. Almost everything else in the browser is a wrapper around it or a competitor to WebGL itself.
  • React Three Fiber is worth it if your app is already React, and is overhead if it is not.
  • Spline is a genuinely good answer for a self-contained visual moment and a poor one for anything that shares state with your app.
  • WebGPU is real and shipping, but a Three.js scene is the sane default until your bottleneck is actually compute.

Every few months someone asks us which 3D tool they should use for the web. The honest answer depends on one question almost nobody leads with: does the 3D need to know anything about the rest of your application?

The layer everything sits on

WebGL is the browser API that draws triangles on the GPU. It is low level in the way that assembly is low level: complete, unpleasant, and almost nobody writes it directly. Everything below is either a wrapper around it or, in one case, its replacement.

Three.js

The floor for real work. Three.js gives you scenes, cameras, materials, loaders and a render loop, and it is mature enough that most problems you hit have been hit before. If you are doing anything custom, you will end up here whether or not you start here.

The cost is that it is unopinionated. It will let you build something that runs at 12fps on a laptop and it will not warn you.

React Three Fiber

A React renderer for Three.js. Instead of imperatively constructing a graph, you declare it, and reconciliation handles the rest. It is not a wrapper in the usual sense: it produces the same Three.js objects, at the same cost.

jsx
// the same scene, declared
<mesh geometry={geo.chochin} material={materials.lantern} position={[0, 2.9, 0]}>
  <sprite material={materials.halo} scale={[3.4, 3.4, 1]} />
</mesh>
The value is composition and lifecycle. The value is not performance: it is the same renderer underneath.

Its companion library, drei, is a large collection of helpers: loaders, controls, materials, staging. It is excellent and it is where most of the sharp edges live, because helpers hide behaviour. One example that cost us real time:

Blender

Where models and animations come from. Free, and the export path to glTF is well trodden. The web-specific skill is not modelling, it is knowing what to cut: polygon budgets, texture atlases, how many bones a rig really needs.

The alternatives, honestly

Spline

A visual editor that exports a web-ready scene. Genuinely good, and we would recommend it without hesitation for a self-contained visual moment: a hero object, a product spin, something decorative that does not need to know what the user is doing.

Where it stops being the right answer is when the scene needs to share state with your application, when you need precise control over the frame budget, or when the interaction is the point rather than the look. At that boundary you are fighting the tool, and the migration is a rewrite.

Unity and WebGL builds

Unity exports to the web and the engine is enormously capable. The cost is the payload and the boot: you are shipping a runtime, and there is a loading screen. For a game people arrived intending to play, that is a fair trade. For a marketing page where the 3D has to be there before someone decides whether to stay, it is usually fatal.

WebGPU

The successor to WebGL, and it is shipping in the major browsers now rather than being a promise. It offers a modern API and, importantly, compute shaders, which open up work that was awkward or impossible before: large particle systems, simulation, GPU-side culling.

Three.js has a WebGPU renderer and TSL, its shading language, so you are not choosing between ecosystems. Our position: build the scene in Three.js, and move to the WebGPU renderer when you have an actual bottleneck that compute solves. Adopting it for a scene that draws a few hundred objects buys you nothing but a smaller supported-browser set.

What actually determines whether it works

The tool choice matters far less than three decisions that people make late and should make first.

Budget, decided up front

Decide the draw call and payload budget before modelling, not after. Our homepage carries a continuous 3D world and ships 144 kB of first-load JavaScript, because that number was a constraint from the start rather than a measurement at the end. Every technique in it was chosen for being cheap: unlit materials, no shadow pass, no postprocessing, procedural geometry merged per material, textures drawn to a canvas at runtime.

Accessibility and reduced motion

3D content is invisible to a screen reader and hostile to anyone with a vestibular disorder. That is not a reason to avoid it, it is a reason to design the fallback deliberately. The trick is to remove the motion the user did not ask for, not to ship them a different, deader page:

js
// scroll-linked travel is motion the user IS asking for: keep it.
// autonomous easing, camera sway and fov breathing are not: drop them.
const a = world.reduced ? 0 : chapter.dwell
const eased = t + (a * Math.sin(TAU * t)) / TAU
With dwell at zero the curve collapses to a straight line, so reduced motion is the identity case of the same formula rather than a second code path.

What happens when it fails

WebGL contexts are lost. Old GPUs are blocklisted. Assets 404. Wrap the scene in an error boundary and make sure the page is still usable and still sells without it. If your value proposition is inside the canvas, you have built something fragile.

What we would choose

  • A decorative hero object. Spline. It will be finished this week and it will look good.
  • A product configurator in a React app. React Three Fiber plus drei, models from Blender.
  • An interactive world across a whole page. React Three Fiber, with a hard budget and every technique chosen for cost. This is what our site does.
  • A real game. A game engine, or a platform that already has an audience. We build ours on Reddit, where people are already playing.
MarbleMazes. A real game on a platform that already has an audience, which is a distribution decision as much as a technical one.

The tools are all good. The projects that fail do so because nobody decided what the 3D was for, and no framework fixes that.

three.jsreact-three-fiberwebglwebgputooling