The fun problem with putting a spiking neural network in the browser is that you have no idea what machine it's going to land on. The same page has to feel good on a laptop integrated GPU and on a desktop with a real discrete card. Hardcoding a neuron count means picking between "boring on fast hardware" and "a slideshow on slow hardware." Neither is great.
Measure first, then commit
So instead of guessing, the visualizer does a short warm-up pass when it loads. It runs a small batch of simulation steps, measures how long the GPU actually takes, and uses that to estimate a neuron count it can sustain at the target frame rate. Slow device, fewer neurons. Fast device, more. The point is to land near the hardware's real budget rather than a number I picked on my own machine.
Three backends, one interface
Under the hood there are three compute paths: WebGPU compute shaders for the fast
path, a WebGL2 fallback, and a plain CPU path when nothing else is available. They
all sit behind the same interface, so the rest of the app doesn't care which one is live, and it
can swap at runtime if a backend misbehaves.
What I'd revisit
The warm-up heuristic is deliberately simple right now — basically one measurement and a lookup. A smarter version would keep adjusting while it runs, since thermal throttling and background tabs change the budget over time. That's a later project. For now, "measure once, pick a sane number" already beats every fixed value I tried.
This is a quick note rather than a writeup — I'll do a proper one when I clean up the project.