JavaScript is fast, but for tight inner loops updating thousands of particles per frame, Rust's zero-cost abstractions and LLVM-optimized WASM output provide measurably smoother animation. The particle update loop touches 3,000 structs × 4 gravity wells = 12,000 force calculations per frame — perfect for WASM.
The ParticleSystem struct owns all state: particles, gravity wells, and the
Canvas 2D context (via web-sys). JavaScript calls tick(dt) and
render() each frame via requestAnimationFrame. No data crosses
the JS↔WASM boundary except scalars.
Click/tap anywhere on the canvas to reposition the fourth gravity well as an attractor.
The well's hue cycles with time, creating dynamic color shifts in nearby particles.
Touch events use passive: false to prevent scroll interference on mobile.
wasm-pack build rust/particles --target web --out-dir ../../resources/public/wasm/particles