IMPULSE runs 20,000 physics bodies at 120fps in a browser
Linus Ekenstam presents IMPULSE, a Rust physics engine running through WebAssembly with a WebGL2 renderer. He reports an 83KB binary handling 20,000 bodies at 120fps on an M5 MacBook Pro.

TL;DR
- IMPULSE is a Rust/WebAssembly 3D engine built with Gemini 4 Argon, with no external math crates or physics libraries, according to the build thread.
- The creator reports 20,000 bodies at 120fps on an M5 MacBook Pro in a later demo, while his optimization update distinguishes 20,000 drawn bodies from roughly 2,000 simultaneously colliding bodies.
- The 83KB figure follows compression: Ekenstam reported 82,713 bytes after running a compressor.
Ekenstam floated IMPULSE as a benchmark for future models. He also added a crude water plugin and wired in DialKit, a live-tuning interface library.
Wrecking balls, bridges and marble runs
Product designer Linus Ekenstam built IMPULSE after a couple of weeks testing Gemini 4 Argon. His brief was gloriously nerdy: a lightweight, reusable 3D engine with its own physics solver.
He demonstrated five setups in a later reel:
- A wrecking ball.
- A bridge simulator.
- A marble run.
- A water simulation.
- Physics objects attached to strings.
IMPULSE's wrecking ball, bridge, marble run and water demonstrations
Collision detection and joints
The initial architecture fits into roughly 1,200 lines of Rust. Rather than incorporating Rapier or Bullet, Ekenstam describes four custom physics components:
- Rotational dynamics: analytical world-space inverse inertia tensors, using
R × I_local^-1 × Rᵀ. - Box collisions: a 15-axis Separating Axis Theorem test for oriented-box contact manifolds.
- Contact resolution: iterative sequential impulses with Baumgarte stabilization.
- Joints: a 3×3 effective mass matrix for ball-and-socket and catenary bridge joints.
WebGL2 shadows and mouse dragging
Ekenstam skipped wgpu in favor of direct WebGL2 access through web-sys, citing compilation speed and binary size. The renderer includes:
- Shadows: two-pass 2048×2048 depth shadow mapping with 3×3 percentage-closer filtering.
- Geometry: procedural unit meshes with local-space rotational stripes.
- Interaction: screen-to-world ray unprojection for mouse-controlled spring dragging.
- Debugging: toggleable axis-aligned bounding boxes and contact-normal wireframes.
Spatial hashing and four draw calls
The initial stress test used more than 500 rigid bodies with lighting and shadows. At roughly 2,100 bodies, Ekenstam hit a GPU limit and asked the model to optimize the engine.
He subsequently reported roughly 20,000 drawn bodies and 2,000 simultaneously colliding bodies after three changes:
- Spatial hashing replaced all-pairs collision checks.
- Instanced rendering reduced body rendering to at most four draw calls, including shadows.
- Reusable buffers reduced allocations.
WebGL2 instancing executes multiple copies of geometry in one draw call, as described in MDN's API reference.
The expanded build was described as around 90KB. Ekenstam also demonstrated roughly 10,000 simulated bodies falling toward collisions in a separate scene.
The expanded stress test, labeled 20,000 bodies and 2,000 collisions
GitHub and playable access
Ekenstam asked whether to share a GitHub repository and live playable link. In a reply about publishing the code, he said he needed to put the project on Git.