WebGL vs WebGPU: The Performance Gap
Why Your Browser is Choking on 3D (And How to Fix It)
I remember the first time I tried to render 10,000 interactive cubes in the browser using standard React Three Fiber. My MacBook Pro's fans spun up like a jet engine, and the frame rate tanked to a cinematic 12 FPS. The CPU was screaming.
For years, we've accepted this bottleneck. We optimized by reducing geometry, baking lighting, or strictly limiting interactivity. We treated the browser like a second-class citizen for 3D graphics.
But the game has changed.
I recently built a side-by-side experiment comparing a naive WebGL implementation against a modern WebGPU approach using Three.js and TSL (Three Shading Language). The difference wasn't just incremental; it was a generational leap. We are talking about moving from 15,000 objects at 15 FPS to 200,000 objects at a locked 60 FPS, all while the CPU usage dropped from 100% to near zero.
Here is what I learned about the shift from the Main Thread to the GPU, and why you need to start caring about TSL today.
The Problem: The CPU Bottleneck
In the traditional WebGL workflow (and specifically within the React ecosystem), we often fall into the trap of "Declarative Thinking". We treat 3D objects like DOM elements.
In my experiment, the WebGL mode did exactly this. I created a <mesh /> component for every single cube and used a loop to update its rotation every frame.
// The "Naive" WebGL Approach
useFrame((state, delta) => {
// This runs on the CPU, 60 times a second, for EVERY object.
// 10,000 objects = 600,000 function calls per second.
ref.current.rotation.x += delta;
});
Why this fails:
- Serialization Overhead: JavaScript has to calculate the new matrix for every object.
- Bus Saturation: The CPU has to send that updated data to the GPU every single frame.
- Single Thread: The browser's main thread is already busy handling React renders, DOM updates, and event listeners.
The result? The GPU is sitting there, bored, waiting for the CPU to finish its math homework.
The Solution: WebGPU and TSL
WebGPU isn't just "WebGL 3.0". It's a fundamental architectural shift that gives us low-level access to the graphics card, similar to Vulkan or Metal. But the real magic capability in Three.js is TSL (Three Shading Language).
TSL allows us to write shader logic using standard JavaScript/TypeScript syntax, which Three.js compiles into WGSL (WebGPU Shading Language). This means we can define the behavior of our objects and ship it directly to the GPU.
In the WebGPU mode of my experiment, I used a single InstancedMesh. But instead of updating the matrix in a JS loop, I defined the position and rotation as Nodes.
// The WebGPU + TSL Approach
import { time, instanceIndex, hash, vec3 } from 'three/tsl';
// Logic defined ONCE, runs purely on the GPU
const index = instanceIndex;
const seed = float(index).mul(0.123);
const t = time.mul(1.0);
// Procedural rotation calculated in the Vertex Shader
const angle = t.add(seed).mul(2.0);
const rotatedPos = rotateVector(positionLocal, axis, angle);
// No CPU update loop. 0% Main Thread usage.
material.positionNode = offset.add(rotatedPos);
The Impact:
- Zero CPU Usage: Once the shader is compiled and the buffers are loaded, the CPU does nothing. It just tells the GPU "Draw this again".
- Massive Scalability: I pushed the slider to 200,000 cubes. The frame rate stayed locked. The bottleneck shifted from "Scripting" (CPU) to "Fill Rate" (GPU pixels), which is exactly where you want it to be.
Technical Benchmark: "The Cube Storm"
I ran this test on a standard M3 MacBook Pro.
| Metric | WebGL (CPU Bound) | WebGPU (TSL Driven) |
|---|---|---|
| Object Count | 15,000 (Max stable) | 200,000+ |
| FPS | ~20-30 FPS | 60 FPS (Locked) |
| CPU Usage | 98% (Main Thread blocked) | < 2% (Idle) |
| Bottleneck | JavaScript Execution | GPU Fill Rate |
The difference is stark. In the WebGL version, the UI becomes unresponsive because the main thread is choked. In the WebGPU version, you can interact with the UI freely because the animation logic is detached from the JavaScript runtime.
Strategic Takeaway
If you are building data visualizations, digital twins, or immersive experiences for the web in 2026, you cannot afford to ignore WebGPU.
- Stop animating via CPU: If you are using
useFrameto update positions of static geometry, you are doing it wrong. - Embrace Instancing: Draw calls are expensive. Group your geometry.
- Learn TSL: It is the bridge that lets frontend developers write high-performance shader logic without learning a new syntax like GLSL or WGSL.
The browser is no longer the limit. Your architecture is.
It is time to let the GPU do the heavy lifting.
