Three.wasm - What it is and represents.
(Header image source: Three.js Tweet on X)
On April 1st, 2026, Three.js’ official X account posted:
The future of Three.js is WebAssembly
— Three.js (@threejs) April 1, 2026
While many in the community understood immediately that this was an April Fool’s joke, others were rather excited about this being “HUGE” for Web 3D.
What got people excited?
Every developer working with 3D graphics has at some point faced performance problems in their WebGL or WebGPU app. The general understanding is that 3D on the web is significantly slower than on native, even though the underlying hardware runs at the same speed.
WebAssembly, just like WebGPU, on the other hand, has a reputation of raw speed. The appeal of speeding up web graphics is there, and WebAssembly sounded like a plausible solution.
Why it could be the solution.
WebAssembly can speed up programs written in JavaScript for CPU-heavy tasks. The magnitude of the speedup will depend on how bad your JavaScript code was, and which compiler settings you enabled on your WASM build.
A lot of slow JavaScript code could also just be rewritten in better JavaScript and yield a great speedup. But if you do a 1:1 translation of JavaScript to C++, for example, you will likely be faster. Why is that?
Aside from its linear memory sidestepping any garbage collection hitches, C++ compilers do a lot of optimization on your code automatically for you. It will use SIMD automatically for you, fast floating point math, and a bunch of crazy tricks. As long as you set the right flags. (Godot’s WASM SIMD PR with 11 changes shows just what a crazy effect a compiler flag can have! Very kind of Adam to give us a shoutout there.)
So if it is faster to use WebAssembly, why did Three.js just joke about this? Why aren’t they doing this for real?
Why it is not the solution.
Frankly, the real CPU bottleneck for WebGL is not in the realm of the webpage, it’s in the realm of the browser implementation. Every WebGL call gets marshalled (think “transferred”, or “copied”) to a WebGL thread, checked for safety and then passed to the driver, which again adds overhead.
The overhead of every draw call cannot be optimized by WASM, as even WASM has to make the same WebGL calls. The only parts that it would optimize in Three.js would be vector math, maybe culling, parsing GLTF files, or geometry processing.
But the catch is that these are not bottlenecks. Three.js applications with performance problems suffocate on draw calls, not geometry processing.
And remember what I wrote about JavaScript code might as well be rewritten in better JavaScript for similar speed ups? Three.js has been optimized over 1.5 decades. Their code style handles garbage collection well, and they generally know how to write fast JavaScript.
So, switching would yield no benefit for the actual problem, barely any benefit where it could, and alienate a massive community that would find itself unable to read the code.
But before we get into what actually is the solution, I need to dispel some myths:
Why it isn’t not the solution.
Some claims were made that might be obviously kidding to some people, but some might get the wrong impression:
WASM is Not Debuggable
This is the main claim why the joke was resolved in the follow-up tweet.
In fact, Chrome Dev Tools and other browsers are perfectly able to step through C++ code and debug it just like JavaScript, inspecting variables and setting breakpoints. It supports the highly mature DWARF debugging format.
Possibly when writing raw WASM rather than C++ or Rust, you may struggle in general, though.
WASM is Faster than Native
WASM is definitely a subset of native code. There are many things you can do in native that you can’t on WebAssembly, but not the other way around. The best you can do is to match native.
WASM is HUGE (File Size)
This is generally a problem with the big engines that try to compile native-designed projects to Web. Because download times are not a problem there, they can design their engine with binary sizes of 20MB and beyond without any consequences. They can also afford loading everything ahead of time, rather than streaming data continuously.
It is, however, not a problem inherent to WASM. It’s a matter of using the right compiler flags (again!) and being diligent in which standard libraries you use in your programming language that gets compiled to WebAssembly, as well as avoiding loading everything up front.
What is the solution.
Avoid draw calls, and avoid draw calls again. We fixed those in Wonderland Engine by designing the entire engine around this. Most scenes, even with tens of thousands of objects and millions of vertices are rendered by Wonderland Engine in less than 10 (ten) draw calls!
How about a three.wonderland? Give it a try!