Feat/web client api parity#44
Open
joschaschmiedt wants to merge 16 commits into
Open
Conversation
…t, generic setters) Complete TODO #1: the web client now matches the Python client / proto surface. Stimuli: add the remaining generic setters — setName, setDrawMode (ShapeDrawMode string-union → proto enum), setOutlineColor, setOutlineWidth, and draw-order (bringToFront / sendToBack / swapDrawOrder; server returns NotSupported for now, see #43). conn.vtl: add list(), reusing a toVtlLineView mapper extracted from snapshot.ts. conn.animations: new client mirroring vstimd.animations — create (all 7 types), arm / disarm / delete / list / query, with *Frames|*Ms conversion via a cached server frame rate. VtlLine addressing reuses vtl.ts's vtlLineHandle. conn.config: new client — list / load / save / retrieve / upload. All proto types stay private; the public surface is hand-written domain types and string-union enums, matching the existing grating/vtl pattern. e2e coverage added for each (draw-order asserts the documented NotSupported gap). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
The animation type tag appeared in three forms: the server proto `type_name` (PascalCase, from list), the proto oneof field (camelCase in TS / snake_case in Python, from query), and the serde config-file enum tag (PascalCase variant name). Since the tag is persisted to config files, divergence between what one client writes and another reads is a real round-trip hazard. Make the Rust enum variant name the single canonical tag and pass it through everywhere: - proto: add `type_name` to QueryAnimationResponse so query carries the same string as list (no client-side derivation from the oneof). - server: populate it from `Animation::type_name()`, and add a guard test asserting `type_name()` equals the serde externally-tagged variant key — so it can never drift from what's written to / read from config files. - web + python clients: `query()` now passes the server `type_name` through verbatim, matching `list()`. The web client drops the camelCase mapping table; `AnimationTypeName` mirrors the server's PascalCase set for autocomplete only. All three components and the config file now agree on one tag (e.g. "FlashForNFrames", "MoveAlongPath2D"). Verified: Rust guard test, web e2e (13), python e2e-null (121). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
…n (config v2)
Stimuli and animations now serialize the same way: internally-tagged with a
`type` discriminator, instead of three different shapes (shapes were
double-nested `{"Shape":{"Rect":{…}}}`, grating/text single-level, animations
flat externally-tagged). A schema-driven UI and the planned JSON Schema both want
one uniform tagged-union form.
Server:
- Flatten the `Stimulus` enum: `Shape(ShapeStimulus)` → flat
`Rect|Ellipse|Circle|Grating|Text`; remove `ShapeStimulus`. Shape-specific
dispatch (tessellation, accessors) moves up to `Stimulus` via `is_shape()` /
`shape_appearance()`.
- Factor the shared shape params (flags/transform/appearance) into `ShapeCommon`,
`#[serde(flatten)]`-ed into each shape struct — DRY in Rust, flat in JSON, and a
reusable component for the JSON Schema.
- `#[serde(tag = "type")]` on both `Stimulus` and `Animation`.
- Bump CONFIG_VERSION 1 → 2 (clean break; no migration). Check the version before
the full parse so older files fail with a clear version error, not a serde error.
Tests:
- New v2 reference fixture; config_compat asserts v2 loads and v1 is rejected.
- config_roundtrip proves the internally-tagged + flatten form round-trips.
- python config e2e expects version 2.
Verified: full Rust test suite, web e2e (13), python e2e-null (121).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
…Copy clone) Pre-existing clippy findings surfaced after the config refactor: - grating tests: replace 3.14 phase values (flagged as approx PI) with 1.5. - vtl_state::vblank_mask: collapse nested if via Option::filter. - test setup: struct-update for SceneConfig, drop clone on Copy Color. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
First step-2 UI panel: a Trigger Lines panel reading snapshot.vtlLines, showing each line's name/bank:bit, direction, and live level (lit indicator), with a toggle button for input lines (conn.vtl.toggleInput). Wired into App beside the stimuli panel. Playwright smoke test covers register → render → toggle low→high. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
Second step-2 panel. Animations are not in the SceneSnapshot stream, so the panel polls conn.animations.list() every 500ms (and refreshes after each action) and shows name / canonical type / state, with arm·disarm·delete buttons gated on state. Wired into App. Playwright covers create → list → arm (state leaves idle); beforeEach now also clears animations for isolation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
…delete-all) Third step-2 panel. Adds the missing system client methods setAllEnabled and setDeferredMode (parity with the Python client), then a System panel with a background colour picker (from snapshot.serverInfo.background), show/hide-all, deferred-batch begin/apply/cancel, and a guarded delete-all. Photodiode is omitted — it has no runtime command yet (config/animation-only). Playwright covers Hide all → stimulus checkbox unchecks via the snapshot. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
benches/tess.rs referenced the pre-refactor stimulus API (DiscStimulus, ShapeStimulus, tessellate_stimulus) and no longer compiles. Remove it and its Cargo.toml stanza; it needs a rewrite against the current API. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
The VTL list (and thus the snapshot) now enumerates every bit in the configured banks, not just named lines, so any line can be observed/triggered for debugging (inputs simulate the hardware bridge; outputs override the animation-driven level). Web VtlPanel is rewritten as a clickable per-bank binary view: each bank renders its 64 bits as 1/0 cells (high = green), MSB-first in bytes; clicking toggles that line via toggleInput/toggleOutput. Named bits are underlined with a name tooltip. Playwright updated to toggle a named bit in the grid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
The bank view now defaults to binary. Adds a "Manual fire" control to the VTL group: pick In/Out, bank, and bit, then drive it — inputs fire a rising/falling edge (set_input_bit + set_input_rise/fall, simulating the hardware bridge), outputs set the level via set_staged_bit (overriding the animation-driven value). This makes any line triggerable for debugging without needing a registered name. vtl_group no longer holds a long-lived owner borrow (state is read inline and the names are cloned) so the output writes can take &mut VtlState. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
The create-animation dialog could only set the type-reactive trigger (EnableOnEdge/Couple); there was no way to gate a Flash/Flicker/Move on a VTL edge or pulse a line on completion, so trigger-driven animations couldn't be wired up. Add optional "Start on VTL edge" (bank/bit + rising/falling → config.start_trigger) and "Pulse VTL line on completion" (bank/bit → FinalAction::FINAL_ACTION_TRIGGER_LINE + final_action_trigger_line). Bank/bit entry so any line works, named or not — matching the VTL panel change. Engine support is already covered by the animation integration tests (flash_with_start_trigger_stays_armed_until_edge, final_action_trigger_line_*). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t4AuaVFXikaAAFt7oCZ1F
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.
No description provided.