The 5 Hardest Simulations We Shipped
Most sims take a day or two: an ODE system, a canvas loop, a few sliders. These five each took more than a week and forced us to rethink our whole approach.
Bridge Designer (FEM)
Assembling a global stiffness matrix from arbitrary beam elements, solving the sparse Ax = b with Gaussian elimination in JavaScript, and visualising stress in colour in real time. The hard part: ensuring the topology graph stays valid while the user drags nodes.
Lattice-Boltzmann Flow
Getting the D2Q9 BGK collision operator numerically stable while maintaining high Reynolds numbers. The Zou-He boundary conditions for inlet velocity are surprisingly non-trivial, and the streaming step demands cache-friendly memory layout — swapping two flat arrays instead of a 3D array.
Concert Hall Acoustics (FDTD)
Running a 2D finite-difference time-domain acoustic solver in a worker thread, streaming pressure field snapshots via SharedArrayBuffer, and rendering the wavefront as a colour gradient at 60 FPS — while the UI thread stays completely free.
Protein Folding (Monte Carlo)
HP lattice model folding with simulated annealing. The combinatorial explosion of conformations requires a careful annealing schedule — cool too fast and you get stuck in local minima, too slow and it never converges in the browser.
Quantum Circuit Simulator
Maintaining a 2ⁿ complex state vector in JavaScript Float64Array, applying unitary gates as matrix-vector products, and keeping the UI responsive for up to 10 qubits (1024 amplitudes). Gate serialisation as a JSON circuit description was a late but critical design decision.
Architecture Lessons
✅ What Worked: One file per sim
Every simulation is a single self-contained HTML file. No build step, no imports, no bundler. Deploying a new sim is a single git push. Readers can view-source and understand everything.
✅ What Worked: Shared component injection
A tiny components.js injects navbar, footer, and theme toggle into every page at runtime. 300 files share one nav definition. We've changed the nav three times — it took 30 seconds each time.
⚠️ Regret: Copy-paste CSS
Early sims have their own proprietary CSS. Later sims use the shared theme variables. We now have ~50 sims that are slightly inconsistent in font sizes and spacing. The fix is straightforward but boring.
⚠️ Regret: No simulation data schema
Simulations.json grew organically. We have three different conventions for category slugs, two for algorithm tags, and one sim with a typo in its ID that propagated everywhere. A schema validator on day one would have cost 30 minutes.
The one decision that changed everything: moving physics loops into Web Workers. Before Workers, any simulation doing more than ~10 000 operations per frame dropped the UI to sub-60 FPS on mobile. Worker threads allow the physics to run independently, posting positions to the main thread via transferable ArrayBuffers. The main thread only renders.
Performance: How We Hit 60 FPS on Mobile
Every simulation that runs at 60 FPS on a mid-range Android has at least three of these five properties:
- Typed arrays everywhere. Float32Array for positions and velocities. No garbage collection jitter mid-frame.
- Fixed timestep with interpolation. Physics runs at a fixed 60 Hz internally. If the frame rate drops, we sub-step and interpolate render positions — no simulation artifacts.
- InstancedMesh for particles. 1000 particles as one draw call. Without instancing this was 1000 separate draw calls — a 50× GPU overhead.
- Spatial hashing for collision pairs. Broad-phase collision detection in O(n) instead of O(n²). Critical above ~200 objects.
- Early culling. Simulations check document.hidden and paused the physics loop. Background tabs do zero work.
What Comes Next: Road to 500
The next 200 simulations will focus on areas we've under-served: biological systems (detailed genomics, neuroscience models), advanced materials science (molecular dynamics, DFT-lite), geophysics (seismic wave propagation, mantle convection at higher resolution), and educational/kids mode with simplified controls and guided discovery.
We're also migrating the heaviest sims to WebGPU compute shaders — the lattice-Boltzmann solver, the SPH fluid, and the FDTD acoustics. Compute shaders run 10–50× faster than the equivalent JavaScript, which means we can finally do 3D CFD in real time.