React DOM

One absolutely positioned div per particle.

Particles8,000
Vello
Not run yet
Konva
Not run yet
DOM
Measuring…
How it works

Every renderer runs the same simulation and the same controls, one at a time. Running them together would make them fight over one main thread, and every number would be wrong.

This is the control, and it is not a strawman. Elements are created once, colour, size and border radius are set once, and the per-frame work is a transform and an opacity, never top and left or a width.

Two things that look like optimisations are deliberately left out. Writing width and height each frame invalidates layout for every particle, so the pulse rides on the transform instead. And will-change is off: it buys a compositor layer per element, which helps for a handful and exhausts GPU memory at thirty thousand.

It still falls over long before the other two, which is why it stops at 12,000. Past that the main thread is busy for whole seconds at a time, the slider stops responding, and the tab is liable to be killed.

React Vello