Visualizer: cache idle plates and send method signatures once per class - #1155
Merged
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.