DEV Community

Cover image for ๐Ÿง  From 2,500 to 1,000,000 Particles: Supercharging a Three.js Demo with WebAssembly
m1kc3b
m1kc3b

Posted on

๐Ÿง  From 2,500 to 1,000,000 Particles: Supercharging a Three.js Demo with WebAssembly

When I first explored the classic webgl_points_waves demo in Three.js, I was amazed by the simplicity and elegance of the animation โ€” around 2,500 particles oscillating in a wave pattern. But naturally, I wondered: What if we wanted 100ร— more particles? Could JavaScript handle it?

Spoiler: It canโ€™t. But WebAssembly can.

๐Ÿšง The Limits of JavaScript in Creative Code

JavaScript is great โ€” but when it comes to realtime simulations involving thousands or millions of calculations per frame, it quickly becomes the bottleneck.

Tasks like:

  • Particle simulations
  • Per-frame math on large arrays
  • Complex waveforms, physics, or procedural animations

โ€ฆoften demand performance beyond what the JS engine can safely deliver, especially in browsers where garbage collection and dynamic typing introduce runtime overhead.

๐Ÿš€ Rebuilding the Core in Rust

So I rewrote the simulation logic โ€” the part responsible for animating each particle based on time โ€” in Rust, and compiled it to WebAssembly. The rendering still uses Three.js and WebGL, but now the math is done in a much faster, memory-safe native module.

Without diving into the full code, here's the gist:

  • A buffer of f32 values is allocated and shared with JavaScript
  • Each frame, a Rust function updates the Y-position of every particle
  • The math involves some trigonometry and time-based modulation (based on sin, cos, and distance to origin)
  • Everything is vectorized and runs at near-native speed

In fact, the logic is so efficient that instead of 2,500 particles, we now simulate 1,000,000 โ€” in real time, in the browser.

๐ŸŽฎ Try It Live

๐Ÿ‘‰ Demo here

Click the JS or WASM button and check the FPS counter (top left corner). Itโ€™s eye-opening.

๐Ÿ“ฆ Under the Hood

The Rust code is compiled with wasm-bindgen, and exposes a very simple API to JavaScript. Integration is as easy as passing a buffer and a time value to the WASM function โ€” no boilerplate, no complex interop.

In Rust, everything runs in place, directly on the shared buffer. No allocation, no overhead. That means you get tight control over memory and massive performance gains, especially in repetitive workloads like particle animation.

๐Ÿ”ฅ Why WASM Matters for Creative Developers

This project is more than a performance flex โ€” it's a realistic case study in how WebAssembly can enhance creative web experiences:

โœ… Smooth animations
โœ… Clean interop with JS and WebGL
โœ… Minimal runtime cost
โœ… Scales to millions of data points

If you're building interactive 3D, simulations, or generative art, WASM is not a nice-to-have โ€” it's a superpower.

๐Ÿง  Learn More

For a deeper dive into how I built this and why I think WASM is the future for creative coding, check out my article.

Top comments (1)

Collapse
 
v_systems profile image
V_Systems • Edited

Apply your GLSL skills to the V Shader Hackathon, running until 22 May 2025!
Create unique Shader art to win up to $1000 โ€“ in collaboration with Gamedevjs.com

  • Create your original Shader
  • Upload the Javascript to the V Systems blockchain to turn it into an NFT
  • Be one of the 16 winners of prizes ranging $500-$1000

How to join: medium.com/vsystems/13-26-april-cr...

Any questions? Join our community!