This started as a pretty specific problem.
I wanted to take an arbitrary SVG and rotate it in isometric space with precision. That meant lifting vector paths into real 3D math instead of relying on CSS transforms or visual tricks.
Once I started doing that, two things became obvious pretty quickly:
Even when things were “fast enough,” the interaction didn't feel as direct as I wanted.
So I stopped trying to make React responsible for the renderer.
React still handles the UI: panels, sliders, editors, timelines.
But the renderer lives outside of the React lifecycle.
The core rendering state (camera, transforms, animation time) is stored in refs and updated imperatively. When something changes, the engine redraws immediately.
Dragging ends up looking like:
pointer move → update rotation → redraw
There's no reconciliation step in between.
React state still exists, but it's there to reflect what's happening, not to drive the render loop.
That separation made the interactions feel much more predictable.
Internally, everything goes through a small pipeline.
SVG paths are sampled using the browser's native APIs and converted into point data. That data is transformed in 3D space and projected using a proper orthographic projection matrix.
Rotations use quaternions to avoid gimbal lock and to keep interpolation stable. It's a bit more math up front, but it avoids edge cases once animation is involved.
For depth ordering, I use a simple painter's algorithm. A full z-buffer didn't seem justified for the complexity of the scenes I'm rendering.
A lot of the performance gains came from doing less work, not faster work.
Each stage of the pipeline caches its results. If geometry doesn't change, it isn't rebuilt. If rotation doesn't change, matrices aren't recomputed. Most frames only run part of the pipeline.
In the hot path, I reuse arrays instead of allocating new ones every frame. That reduces GC pressure and keeps frame timing consistent.
The goal wasn't to hit a specific FPS number. It was to keep feedback continuous and predictable while editing.
It runs inside a React app, but the renderer behaves more like a small real-time vector engine:
React manages structure and tooling. The engine handles geometry and time.
That split made it possible to support more complex math without constantly fighting the framework.
Follow along at @brdrck for more updates, screenshots, etc.