Repository navigation
Paint, tour and play animations - #1483
Merged
Merged
Conversation
Eight worked animations under instructions/animations, each a draft folder plus a README: a request across layers, a state machine, a cache filling and evicting, a bounded queue with workers, retry with backoff, a two-lane race, a structure before and after, and a log replay. The animation instructions end with a References section naming each one and its read-only copy beside the drafts, written by the MCP client where the agent's files live; a reference that fails to parse is left out there and fails the tests, which insert every reference through the API. The canvas harness mounts each reference on a board, steps every frame of every scenario, and with VITE_ANIMATION_SHOTS=1 saves a screenshot per frame, so an author sees the result without Desktop. Agent-Session: b315a4f8-1333-461c-9be6-366ceb231b7f
The eight reference animations turned up where the guidance misled their authors. The animation instructions now name the third way to draw, a hand-made layout with arrows, tokens, travels and timelines declared while the script first runs, and the lifecycle attributes that need no script; they say how to move an element between frames, that every keyframe needs its start value for a jump to land, and that whiteboard.frames follows the active scenario. The API reference says where a string is a selector and where it is a card id, and the class guide names the card's head and dot. Agent-Session: b315a4f8-1333-461c-9be6-366ceb231b7f
An animation whose frames list code now has a tour: one stop per frame of the path showing, a frame's code as the stop's source and its caption as an explanation stop otherwise. The header's Expand becomes the diagrams' Tour control, which opens the fullscreen tour overlay with the figure as the stage and the guided tour panel beside it; an animation with no code keeps its plain Expand. The panel and the frames move together both ways: a stop picked in the panel shows its frame, and a frame reached by the controls, playback, the stage or a scenario switch moves the panel, which stays open on a scenario switch at the frame showing. Inline, a drawn element's code opens in the column with the tour at the frame showing, and while the column shows this tour it follows the frames and its own steps move them. Agent-Session: b315a4f8-1333-461c-9be6-366ceb231b7f
An animation the agent writes used to pop onto the board behind the generic
landing wipe. Now the block arrives from the stream with its stage built but
unseen; when the draw queue reaches it the host says "paint", the stage
brings the first frame in part by part, and the queue holds on the block
until the stage reports it painted, or until a cap.
- Draw queue: a "painting" phase for animation inserts, ended early by
painted(), with the slot ring but no content wipe on the figure.
- Stage protocol: StageInit.paint, a "paint" host message, a "painted"
stage message, and a long fallback so a stage never stays blank.
- Default painter for the kit's parts in document order within about a
second and a half: boxes settle in, arrows draw along their path.
- data-wb-paint orders a part or excludes it; data-wb-paint-style picks
fade, draw, wipe or none.
- whiteboard.on("paint") and whiteboard.timeline("paint") replace the
default painter; the hook also runs instantly on a cold load.
Cold loads, history and reduced motion do not paint.
Agent-Session: b315a4f8-1333-461c-9be6-366ceb231b7f
An animation is frames the reader steps through. A clip is its sibling:
one continuous timeline the reader plays, pauses, and jumps around by
named markers, for motion where the timing itself is the point. The two
share the sandboxed stage, the runtime, the draft checkout, the host
component, the code tour and the paint-in.
- Schema: clip {title, html, markers: {key, title, caption?, code?}[],
scenarios?: {key, label}[], code, height, pins}; the Animations
preference gates it with the animation.
- Runtime: whiteboard.clip(scenario?) builds a timeline with .marker();
marker handlers, whiteboard.markers and whiteboard.marker; the frame
API throws in a clip with a pointer to markers. Lifecycle attributes
follow the marker last reached. Reduced motion steps marker to marker.
- Protocol: mode, markers and scenario in the init; play, pause, seek and
scenario from the host; clip, time, marker and ended from the stage.
- Host: the block is now a shell over a frame player and a clip player
with shared controls; a Markers strip, a progress line with a tick per
marker, Space to play, arrows between markers; the tour's stops are
the markers; a rebooted stage resumes at its marker.
- Drafts check a clip out as markers.json; a reference clip,
request-timing, runs in the harness; the authoring guide and typings
cover clips.
Agent-Session: b315a4f8-1333-461c-9be6-366ceb231b7f
A clip jumps to its first marker as it activates, without motion, and that jump finished every animation on the page a frame later, including the paint-in a streamed clip had just begun: on a live board a new clip appeared at once. Paint animations now sit out that finish, as they do a frame shown without motion. The draw queue lost its head on a live board too. An animation released the queue when it unmounted, which under StrictMode's simulated unmount ran at mount; and updaters told the time themselves, so one React ran again ended a step early. The release on unmount goes (the cap covers a block that leaves mid-paint), every updater reads the clock before it is queued, and a control that would change nothing queues nothing. A stage under the system theme read "light dark" as dark on a light page; it now follows the reader's preference. Agent-Session: b315a4f8-1333-461c-9be6-366ceb231b7f
…nt-redesign-e33a0d Agent-Session: 62100749-c77c-4d19-ad48-c6d4ba1e867b Agent-Session: cbacb871-2558-4fe4-9272-77524bb21683 Agent-Session: ffed49d6-ca86-4940-b93c-e8eb7e0de440 Agent-Session: 7bc797d9-b46c-48dc-b281-4fce85dc15ad
thesiti92
approved these changes
Nov 4, 2026
milanb17
added a commit
that referenced
this pull request
Nov 4, 2026
Stacked on #1483 (the references and the scene API live there). An animation's `whiteboard.scene` draws every card as the same box, so a reader cannot tell a database from the service in front of it, or a third-party API from one of ours, without reading each title. This gives cards three presentational options and leaves the kinds out of the API: the typings and the authoring instructions say which form fits what, and two references draw their cards that way.   ## The options On `SceneCardOptions` (actor, store, table), and as `data-form`, `data-outline` and `data-color` on a hand-made `wb-node`: | Option | Values | Drawn as | | --- | --- | --- | | `form` | `box` (default), `pill`, `cut`, `cylinder`, `drum`, `stack`, `window`, `bars` | border radii, `corner-shape: bevel`, a lid pseudo-element for the cylinder and the drum, a box-shadow stack, a title-bar rule, side rules | | `outline` | `solid` (default), `dashed`, `dotted` | border style | | `color` | `ink`, `accent`, `teal`, `violet` | border colour at rest (and the card's dot); a frame's `tone` takes over while set | `teal` and `violet` join the stage theme as `--wb-teal` (the software map's storage colour) and `--wb-violet` (the merged purple), so both follow light and dark. Highlights, tones, `enter`/`exit`/`only` and the card's content work unchanged on every form; the stack keeps its echoes under the highlight ring. The option is called `form` rather than shape because lint reserves "shape" in identifiers. ## Suggested defaults, not a schema `whiteboard.d.ts` and the scene section of `animation.md` suggest: `window` for a client, `bars` for a service or worker of this codebase, `cylinder` for a database, `drum` for a cache, `stack` for a queue or topic, `pill` for a start or end, `cut` for a branch, `outline: "dashed"` for a third-party service, `teal` for stores and `violet` for queues. Nothing in the runtime knows those words. The request-across-layers and cache-fill-evict references use them; their READMEs say so. ## Verification - Every animation browser test, including the references harness stepping all nine references through every frame: 30 passed. The stage kit variables test passes with the two new colours. - `pnpm lint`, `pnpm format` and the canvas typecheck (which holds `whiteboard.d.ts` to the runtime's types) are clean. - The screenshots are frames the harness saved (`VITE_ANIMATION_SHOTS=1`), dark theme. Not checked: light theme and an isolated Desktop. The screenshots live on `pr-assets/scene-card-forms`, as `pr-assets/home-pr-pills` did; delete that branch with this PR. ## Second commit: a frame's remaining time along its step underline While an animation plays, the marker under the step showing is drawn left to right over the frame's duration, on a wash of the full underline, so the one mark that says "this step" also says how much of it is left. Frames without labels sweep a ring around the current dot. Designed first on the "Play timer" page of the Animations Scratchpad Paper file. - Only while playing: a frame reached by hand draws its underline whole, as before. - Pause holds the line where it is and Play resumes from there; a jump to another frame forgets it; Replay starts over. - Time up with the stage still settling holds the line full. - The strip and dots draw it with a CSS animation from inline custom properties (`--frame-timer-fill`, `--frame-timer-ms`, `--frame-timer-rest`), so nothing ticks in React. Reduced motion shows the whole underline at once, as today. - Two browser tests in `blocks.browser.test.tsx`: play runs the clock on the current step, pause holds it with a fraction between 0 and 1, a hand step drops it; and an unlabelled animation sweeps its current dot. ## Third commit: steady height, ported from #1459 #1459 could not merge onto the animations branch mechanically, since the block it changed had split into a frame player, a clip player and a paint-in. Its changes are ported here by hand: the hidden measuring copy (`measure` / `slotSizes` on init, `measured` back), `contentBottom` and `measureFrames` in the runtime, the block's `measuredHeight` rule with its one-second fallback and remeasure triggers (stage, scenario, theme, width, slot heights), and the caption row keeping its tallest caption, now in `StopCaption` for both players. Clips are not measured. Its tests come along; the animation and block browser suites pass (97). #1459 can be closed once this merges. ## Fourth commit: an expanded animation scales up Expand gave the stage the overlay's width but never made the drawing bigger. Now the stage keeps its inline width fullscreen and the block scales the whole canvas, code peeks included, to fit the room the controls leave, at most 2x, centred; a room smaller than the inline stage scrolls as before. The measured-height logic is untouched because the stage still lays out at one width. One browser test expands a block in a wide host and checks the stage scales above 1x, keeps its inline layout width, and its footprint grows with it. Seen while checking, not from these commits: a scene with four declared columns folded to two rows at a 614px stage keeps a 150px stage height, so the second row is clipped, inline and expanded alike. Reproduced on the commit before the steady-height port. Worth its own look. ## Fifth to seventh commits: scene layout, pacing, groups, change marks and a legend - **Cards size to their content**, 140 to 300px, centred in their columns, so a folded scene no longer stretches a card into a slab around a line of text. - **Edges are straight and level**: a fanned pair's offset moves the whole line, and scene rows centre their cards so an edge between a short card and a tall one runs level. - **Play replays a still frame**: a new stage's first frame, or the frame after a jump or Replay, is shown again with its motion when Play reaches it. A send's chip travels at half its old speed, 900 to 2400 ms, after a short lead. One browser test covers the replay. - **`s.group({ id, at, title, color })`** draws a washed, titled box behind the cards in its cells; hidden when the scene folds. - **`change: "added" | "modified" | "removed"`** on a card marks what the review did to that part: dot and left stripe in the change colour, struck title when removed. A frame's tone still colours the card over it. - **`s.legend([...])`** draws one row under the scene, a card-shaped glyph with the entry's marks and a label each. - The typings and `animation.md` describe all of it; request-across-layers groups its server, marks the API as modified and carries a legend. The cylinder form's text sits centred in its body. ## Later commits: layout room, routing, the state-only dot, an architecture reference - Storage-form labels centre in their drum or cylinder; the card dot shows only with a tone or change mark. - A new reference, `video-platform-architecture`: four grouped layers, forms, a dashed CDN and a legend, with upload and playback scenarios. - An edge bows clear of a card by the card's reach across the line, not its longest side, and a card near the line is passed toward the stage's middle; a frame hides other frames' chips. - A grouped scene opens its rows and columns to 72px so the layers stand apart and cross-layer edges can be followed. - Fullscreen, the stage always lays out at its inline width and scales to fit, down to 0.4x beside the tour pane, so it never folds, loses its groups, or measures a folded height.
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.
Summary
Six commits that rework how agents author and readers experience the
animationblock, and add its sibling,clip.packages/review/instructions/animations, each a draft folder with a README. The authoring instructions end with a References section; a browser test mounts every reference and steps every frame (VITE_ANIMATION_SHOTS=1saves a screenshot per frame).paint/painted, and a default painter brings parts in over ~1.5s. Authors can order, exclude or restyle parts, or replace the painter. Cold loads, history and reduced motion do not paint.markers.json, and a reference clip.Verification
pnpm lint,pnpm format:check, canvas app typecheck: clean.