Skip to content

Ticks and storage

Petar Liovic edited this page Sep 9, 2026 · 1 revision

How an update becomes a tick, how ticks are stored, and how those ticks are read two ways: per variable, and as a graph. Values are never stored.

A tick

The clock is requestAnimationFrame. One tick is one paint frame.

If a variable writes once or many times in that frame, the tick is still 1. No write is 0. The signal is a bit per frame, not the payload.

Storage

Each instrumented variable has a fixed Uint8Array ring (on the order of 50 frames). A moving head overwrites the oldest slot. Density is updated from the bit that fell out and the bit that went in, so a write does not scan the buffer.

A row also has a coarse role: local state, context, or an integrated store. That label only changes how a report is worded.

Two views of the same trace

The engine does not throw the per-variable history away when it builds the graph. It uses both.

Per variable (the ring).
Each hook is a short timeline of 0/1 ticks. Comparing two timelines answers: do these two move together, or does one follow the other?
Same frame means they pulsed together. Next frame means one pulsed, then the other. That is how “duplicate flags” and “effect caused a second paint” show up.

Across the app (the graph).
Those pairwise links become edges. Walking the graph answers a different question: what sits upstream of this mess?
A click that touches three contexts is one event with three targets, not three separate chains. The report can point at that event instead of listing every downstream write.

The ring decides whether two names are related.
The graph decides where to look first.

Very hot signals (pulsing in most of the window, e.g. animation) are treated as streams and are not used as causal evidence. Event nodes older than the interaction window are dropped.

Scheduling

Pairwise work is meant to run in requestIdleCallback. Dirty signals are snapshotted so writes during a pass belong to the next round. The intent is to stay off the interaction path. Actual cost still depends on how much you instrument.

Limits

No values. No reading your source. No link across a long async gap. The browser can still put two unrelated writes on the same frame.

Clone this wiki locally