Skip to content

Visualizer: cache idle plates and send method signatures once per class - #1155

Merged
BioCam merged 2 commits into
PyLabRobot:mainfrom
BioCam:visualizer-layer-perf
Jul 7, 2026
Merged

Visualizer: cache idle plates and send method signatures once per class#1155
BioCam merged 2 commits into
PyLabRobot:mainfrom
BioCam:visualizer-layer-perf

Conversation

@BioCam

@BioCam BioCam commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Motivation

On a busy deck the visualizer became expensive in two places, both of which are felt most on low-power hosts such as a Raspberry Pi: a live update stutters during a run, and the first connect is slow. This PR addresses both, with no change to what the user sees.

Idle-plate caching (runtime cost)

A whole-layer Konva redraw costs in proportion to the number of shapes on the layer, so after the recent change that forwards volume updates to the visualizer, a single well update repaints every other plate and tip rack on the deck. On a six-plate deck, updating one plate's 96 wells measured about 4.6 ms per frame.

While a plate or tip rack is idle its group is cached to an offscreen bitmap, so it blits in one operation instead of re-rendering all its wells or tips. When a state update arrives for a plate its cache is cleared so the change renders live, and it is re-cached once it has been idle briefly. The group hierarchy is untouched, so transforms, rotation, moves, and hit detection are unaffected. The same six-plate update drops to about 0.55 ms and, more importantly, stays flat as the deck grows.

The cache resolution tracks the on-screen device pixels so an idle plate stays as sharp as a live one, and is rebuilt sharper when the user zooms in. Sidebar hover highlights and per-item visibility toggles clear the affected plate's cache so their changes show immediately, then re-cache when idle.

Method signatures once per class (startup cost)

The initial resource message attached the full list of Python method signatures to every resource, so a plate repeated the same list on all 96 of its wells. This is the largest single cost at connect, and the browser must parse the whole blob before the first paint.

Signatures are identical for every instance of a class, so they are now sent once in a registry keyed by resource type; the browser attaches the matching signatures by type when it builds the tree. On a six-plate, six-tip-rack deck this shrinks the payload from about 2.7 MB to 0.77 MB (roughly 3.5x smaller). The UML method panel is populated exactly as before.

Testing

Existing visualizer tests pass (updated for the new message shape). Verified through a headless browser driving the real websocket: the cache lifecycle is correct (idle plates cached, active plate live, re-cached after idle, no stale bitmap); hit detection still works over cached plates; zoom, hover-highlight, and per-item visibility behave correctly; a real liquid-handling flow (tip pickup, aspirate, dispense) renders correctly with both changes active; and method signatures attach in the browser via the registry.

BioCam and others added 2 commits July 7, 2026 18:17
…aints

A whole-layer Konva redraw costs in proportion to the number of shapes on the
layer, so on a busy deck a single well update repaints every other plate and tip
rack too. On a 6-plate deck, updating one plate's 96 wells measured ~4.6 ms per
frame; on a Raspberry Pi that is enough to make the live view stutter during a
run.

While a plate or tip rack is idle its group is cached to an offscreen bitmap, so
it blits in one operation instead of re-rendering all its wells or tips. When a
state update arrives for a plate its cache is cleared so the change renders live,
and the plate is re-cached once it has been idle for a moment. The group
hierarchy is untouched, so transforms, rotation, moves, and hit detection are
unaffected. With this, the same 6-plate update drops to ~0.56 ms and, more
importantly, stays flat as the deck grows.

The bitmap resolution tracks the on-screen zoom and is rebuilt sharper when the
user zooms in, so a cached plate stays as crisp as a live one. Sidebar hover
highlights and per-item visibility toggles clear the affected plate's cache so
their changes show immediately, then re-cache when idle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… resource

The initial set_root_resource message attached the full list of Python method
signatures to every resource, so a deck of 96-well plates repeated the same
signature list on all 96 wells of each plate. On a busy deck this is the largest
single cost at connect, and the browser has to parse the whole blob before the
first paint - noticeably slow on a Raspberry Pi.

Method signatures are identical for every instance of a class, so they are now
sent once in a registry keyed by resource type. Each node still carries its type,
and the browser attaches the matching signatures by type when it builds the tree.
On a six-plate, six-tip-rack deck this shrinks the payload from about 2.7 MB to
0.77 MB (roughly 3.5x smaller). The resource_assigned message carries the same
registry for resources added after connect. Nothing the user sees changes; the
UML method panel is populated exactly as before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@BioCam
BioCam merged commit 88d6193 into PyLabRobot:main Jul 7, 2026
21 checks passed
@BioCam
BioCam deleted the visualizer-layer-perf branch July 7, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant