Canvas 2D rendering will provide better performance and simpler architecture than Three.js for the developer analytics garden visualization
HypothesisCanvas 2D rendering will provide better performance and simpler architecture than Three.js for the developer analytics garden visualization
Canvas 2D eliminated WebGL context issues, simplified the rendering pipeline, and enabled L-system botanical encoding that maps naturally to developer metrics. Quadtree hit testing replaced raycasting.
Changelog
| Date | Summary |
|---|---|
| 2026-04-06 | Audited: added Changelog, domain tag, expanded Findings and Next Steps, last_audited stamped |
| 2026-03-15 | Initial creation |
Hypothesis
We bet that Canvas 2D would outperform Three.js for the BloomNet garden visualization. The rendering is fundamentally 2D : a top-down garden view : but the original implementation pulled in Three.js (a full 3D engine) for its scene graph and mouse-picking (raycasting). The hypothesis: strip the 3D machinery, switch to the browser’s native Canvas 2D API, and gain both a simpler rendering pipeline and better performance.
Method
Replaced Three.js 3D scene with Canvas 2D rendering. Implemented L-system botanical encoding where developer metrics map to plant properties : commit frequency drives growth rate, PR count drives branching factor, and session duration drives foliage density. Quadtree spatial index replaces Three.js raycasting for mouse hit testing: the quadtree partitions the canvas into cells, so a click only queries the few plants near the cursor rather than ray-projecting through the entire scene graph.
Results

Confirmed. Canvas 2D eliminated WebGL context tainted errors (which appeared when the canvas element crossed iframe boundaries), simplified the rendering pipeline to a single 2D context, and enabled botanical data encoding that maps naturally to developer metrics. Quadtree hit testing is faster and more predictable than raycasting : hit detection latency dropped from ~12ms to ~1ms on a garden with 15 plants.
The architectural simplification also paid off at development time: the Three.js renderer required managing scene nodes, camera projection, and a render loop; the Canvas 2D version is a single draw() function that repaints the canvas on each animation frame, which is far easier to debug and extend.
See topics/bloomnet-lsystem-botanical-data-encoding and topics/bloomnet-quadtree-canvas-hit-testing.
Findings
-
WebGL context isolation is fragile in multi-iframe layouts. Three.js’s WebGL renderer became “tainted” when the canvas element was embedded inside an iframe : a browser security restriction that does not apply to Canvas 2D. Switching eliminated an entire class of rendering failures that had no workaround.
-
L-system encoding is a natural fit for developer metrics. Botanical growth rules (branching, elongation, foliage density) map intuitively to development activity. A project with high commit frequency and many PRs produces a visually complex plant without any custom styling. The encoding is self-documenting.
-
Quadtree hit testing is the right tool for sparse 2D scenes. When the garden has 10-20 plants, the quadtree’s spatial partitioning keeps hit testing sub-millisecond. Three.js raycasting, designed for dense 3D scenes, was overkill and added latency.
Next Steps
The rendering is fast and the encoding is meaningful, but the visualization is still static data : it needs a live data pipeline to feed it. The next step is building a 4-source ingestion pipeline (JSONL sessions, stats-cache, history.jsonl backfill, GitHub API) to drive real-time garden growth. See experiments/bloomnet/2026-03-20-data-pipeline-maturity. After that, add screenshot verification for automated visual regression testing so rendering regressions are caught before they ship.