Why Bloom over p5.js
Same beginner-friendly syntax, very different ceiling
Bloom is inspired by Processing and p5.js, and for small sketches the experience is the same: write circle(x, y, r), see a circle. The difference shows up when a sketch gets big — thousands or hundreds of thousands of shapes per frame. This page lays out the measured difference and, just as importantly, the architectural reasons behind it — fairly, without overstating.
The benchmark
Headless Chromium, M1-class machine, an animated scatter of shapes from the same Bloom source, measured as sustained frames per second:
p5.js drops below 60fps at roughly 10–15k shapes and below 30fps at roughly 20–30k. Even Bloom's plain Canvas2D path — before any WebGL — was already about 2.2× p5 at the 30–50k range. With the WebGL renderer engaged, the gap widens further as counts climb.
Why Bloom wins
The gap is not micro-optimization — it comes from three concrete architectural differences. Each is a factual property of how the two systems draw, not a claim about code quality.
1. p5.js has no auto-batching
In p5.js, every shape is its own native draw call. Bloom's WebGL2 renderer accumulates every shape of a primitive type into one typed array and issues a single gl.drawArraysInstanced call per primitive type per frame. One draw call for 100k circles instead of 100k. This is the dominant factor at high counts.
2. Per-shape Color overhead
p5 builds and tracks color objects per shape. Bloom packs RGBA into a single 32-bit integer that the GPU unpacks for free in the shader — no per-shape allocation, no garbage to collect under a tight draw loop.
3. Redundant context writes
The naive Canvas2D approach reassigns ctx.fillStyle for every shape, and each assignment re-parses the CSS color string. Bloom's Canvas2D path diffs that state and skips unchanged writes — on a palette-reuse sketch, 156k writes instead of 360k (a 2.3× reduction). This is why even Bloom's non-WebGL path beats p5.
For the full mechanism behind all three — the instance buffer layout, the fused draw opcodes, and the WASM SIMD particle kernel that pushes 100k particles to 0.6ms/frame — see The Rendering Pipeline.
What's honest about this comparison
A fair benchmark names its own limits. These numbers are real, but they describe a specific regime: