May 18, 2026

A forest glyph that wouldn't quite render right

A small animated icon looked fine on an emulator and stuttered on a real phone — because cheap in isolation isn't cheap in aggregate.


Every forest in the directory has a glyph — three concentric rings, counter-rotating; a tracer dot orbiting the inner one. It carries the same visual idiom as the breathing rings in Constellation and the orbital rings in Folk. The system is the icon, miniaturised.

A single glyph runs smoothly on any device. The trouble was that the directory shows several at once — every visible forest in a scrolling list. Five or six glyphs, each animating sixty times a second.

On an emulator it was fine. On a real phone it stuttered.

Before — five glyphs animating at once on a physical phone

What was actually happening

The animation itself wasn’t the problem; the render path under it was. The glyph was drawn through a vector layer that lives on the native side of a bridge — every frame, every rotation, every ring sent a small message across that bridge to schedule a redraw. One glyph at sixty frames a second is fine. Five glyphs, each carrying three independent rotations, isn’t — around twenty bridge messages per frame, all queued on the same thread the screen uses to paint.

The animations stayed fast in isolation. The rendering thread couldn’t keep up. Frames dropped in twos and threes — exactly the cadence the eye reads as stutter.

The fix

The glyph was rewritten to draw directly to a GPU canvas instead. Same three rings, same counter-rotation, same tracer dot — but they live on a single surface that the GPU repaints in one pass. No bridge messages, no per-ring scheduling, no per-frame indirection. The work that used to multiply linearly per glyph collapses into a single canvas update.

The animation runs from one shared clock on the UI thread; each ring reads the clock and computes its own angle in a worklet. No timers, no per-component animation drivers — just math, on a thread that doesn’t have to ask anyone else to schedule a redraw.

After — same animation, no dropped frames

The other half

The glyph fix was half the work. The directory itself has on the order of twelve thousand forests; mounting every row up front isn’t an option, glyph cost or not. The list is windowed — only a few viewports of rows are mounted at any moment, and as you scroll, rows further off unmount while new ones come in. Scroll position is preserved by the math, not by force.

It’s the same shape of solution a personal forest already uses for its message canvas, just applied to a directory rather than a chat thread — the same kind of windowed scroll.

The lesson

Visual fidelity is one budget; render-path cost is another. Something that’s smooth in isolation can be laggy in aggregate not because the animation is bad, but because the path it takes to the screen multiplies poorly.


← All posts