Repository navigation
ui/motion: spring token, sliding indicator, view swap, hover and depth primitives - #33766
Conversation
…th primitives The motion scale gains the one spring (chatSwitch's SWITCH_SPRING) as a CSS linear() token, --cmux-ease-spring and MOTION_SPRING, run over the large step. ui/motion adds four primitives with gallery variants: SlidingIndicator (a selection highlight that travels on transform), ViewSwap (an entrance on swapped content that never delays it), hover and reveal utilities (fill 80 ms, reveal 120 in / 80 out, no press), and DepthLayer (washes that lean toward the pointer, or drift once). The ACP inspector's Wire / Session switch uses the indicator. bench/motion-tabs.bench.ts measures response, shift, settle and idle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-fb75b7af9902231028aa
…ient loop Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-fb75b7af9902231028aa
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Gallery before/after for
States
Pick other states with a Passes: CI passes on CI passes on Written by web and size checks: green Shipped in:
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/41674078994 at 633c1ae failed: cmux-next Release compile (fleet fast check). |
|
Owned by an agent session · session |
|
Review (codex, router-review): SHIP at 47513d2 Reviewer: codex gpt-6-astra high, fast tier. Follow-ups: 4. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward. SHIP at 47513d2
Generator check passed; isolated hook probes reproduced findings 1 and 3. Full tests were unavailable without Bun and dependencies. Follow-ups:
|
|
Found 2 test failures on Blacksmith runners: Failures
|
check-default-cursor refuses a pointing hand in app UI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-fb75b7af9902231028aa
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Review (codex gpt-6.1-sol xhigh, router-review): BLOCK at 18284cd BLOCK at 18284cd
Generator consistency and TypeScript/TSX syntax checks passed. Bun tests and real-browser checks were unavailable. |
WebKit before Safari 17.2 (macOS 14.0 and 14.1) has no linear() easing, and Element.animate() throws on it inside a layout effect. springEasing() checks CSS.supports and returns the ease-out there; the sliding indicator, the view swap and the chat switch use it. Regression test: an engine without linear() slides on the ease-out (fails before this change). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-fb75b7af9902231028aa
|
Review (codex, router-review): SHIP at 546c1b6 Reviewer: codex gpt-6-astra high, fast tier. Follow-ups: 4. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward. SHIP at 546c1b6 Visual verdict: no images; Leo tries the build Generator consistency check passed. Runtime tests/build could not run: Bun and dependencies are absent.
Follow-ups:
|
The design-token check now covers radius and easing: the underline's 1px radius becomes the capsule, and the drift runs on --cmux-ease-out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-fb75b7af9902231028aa
A newer verdict blocks 906839e (no independent SHIP at the head).
popover-instant-open lists every Web Animations call under webviews/src: add the sliding indicator's and the view swap's. The agent pane's no-capsules check reads the underline's 999px radius as a pill: a 2px rule needs none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-fb75b7af9902231028aa
|
Review (codex, router-review): SHIP at 8d73ef1 Reviewer: codex gpt-6-astra high, fast tier. Follow-ups: 3. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward. SHIP at 8d73ef1
Generator consistency passed. Bun tests could not run because Bun and dependencies are unavailable. Follow-ups:
|
A newer verdict blocks ca23caa (no independent SHIP at the head).
teamleaderleo
left a comment
There was a problem hiding this comment.
Review (codex gpt-6.1-sol xhigh, next-review, since=20261103T152851Z): SHIP at ca23caa
SHIP at ca23caa
Visual verdict: no introduced regression in the supplied images; paired differences are confined to timestamps.
-
[P2] [follow-up] SlidingIndicator.tsx:130: Resizes during a slide are discarded, and completion never remeasures. A font change or wrapping during travel leaves the highlight at stale coordinates or dimensions until another resize or selection change. Cancel and place immediately, or remeasure on completion.
-
[P2] [follow-up] DepthLayer.tsx:60: Mounting parallax while hidden or motion-disabled permanently skips pointer listeners. Showing the surface or enabling motion does not rerun this effect. Reevaluate listener registration when visibility or motion settings change.
Follow-ups:
- Reconcile indicator resizes received during animation.
- Restore parallax listeners after visibility or motion changes.
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Summary
Leo (2026-11-03), after sending a short game menu animation: "i thought was cute and cool and i wanted to have more... nice stuff? around the app". The reference shows a chunky pill tab bar whose highlight slides between tabs, panels swapping while it moves, a stylised wipe between views and a slowly moving background layer for depth.
This PR adds that vocabulary as shared, budgeted primitives and puts the first one to use:
schemas/motion-scalegains the one spring (the chat switch'sSWITCH_SPRING) as alinear()easing run over thelargestep (240 ms; visibly settled by about 140 ms). The generator writes--cmux-ease-spring(CSS) andMOTION_SPRING/MOTION_SPRING_STEP(TypeScript); the native copy is unchanged (the app keeps its own spring physics).chatSwitch.tsnow reads the token instead of its own copy. Where the engine has nolinear()easing (WebKit before Safari 17.2, which macOS 14.0 and 14.1 ship),Element.animate()throws on it, so every spring use (these primitives and the chat switch) goes throughspringEasing(), which checksCSS.supportsand falls back to the ease-out. The popup's--ui-enter-ease/--ui-exit-easeare not folded in:cubic-bezier(0.2, 0, 0, 1)and the scale's ease-out draw visibly different curves, so folding them would change every popup's close and the panels' entrance.ui/motion/SlidingIndicator: a selection highlight for tab bars, segmented controls and pickers. The item's selected state changes on the click; the highlight is placed on the new item in the same commit and one finite Web Animation carries it there on transform only (no layout shift), interruptible from its drawn position. First frame is final (no motion on mount or on resize).ui/motion/ViewSwap: an entrance for swapped content (fade, edge slide, a slanted wipe, an accent sweep). The new content is in the DOM and interactive on the frame of the swap; there is no snapshot of the old content..ui-hover-fill,.ui-reveal-host/.ui-reveal): fill over 80 ms, a revealed control fades in over 120 ms and out over 80 ms, stays shown while its menu is open (data-popup-open), and a press changes nothing (no flash).ui/motion/DepthLayer: two soft accent washes behind a surface that lean toward the pointer (event-driven), or drift once.Not touched: the model picker (waits on #32980), Home and New Tab (another lane is migrating them right now). The depth layer and view swap are applied to Home and New Tab in a follow-up once that migration lands.
Gallery variants and picks
ui.motion-sliding-indicatorui.motion-view-swapui.motion-hover-feedbackui.motion-depth-layerDesign references:
zenless-zone-zero/live/motion-sunbringer-menu-animation-sheet,claude/live/settings-transcript-controls,cursor/live/hover-thread-row-pin-and-details.Loops, timers and observers (stop conditions)
iteration-count: 1(24 s), paused while the page is hidden (onevisibilitychangelistener); parallax runs only onpointermoveover the surface and settles within 240 ms of the last one. Both listeners are removed on unmount. Motion off, a zero motion token or Reduce Motion: still, and no pointer listener.motionMode(): motion off or a hidden page places at once; Reduce Motion places the indicator at once and turns every swap look into the fade.Performance
bench/motion-tabs.bench.ts(new; the model-picker-open bench pattern on the sharedbench/stability.tsandPERF_ROW): a real press and release on the next tab, 5 contexts x 6 switches, headless Chromium and WebKit on the Linux pool. "Before" for the gallery is thetodayvariant (each item fills itself at once, the base behavior); "before" for the inspector is the same bench run against the base tree.todaytopill-spring)The selection paints in the first frame either way; the highlight's travel happens after it and leaves nothing running.
Testing
src/ui/motion/motion.test.tsx(jsdom): first frame places the highlight with no animation; a selection change places it at once and slides on transform only, on the spring; Reduce Motion and motion off do not slide; an engine withoutlinear()easing slides on the ease-out instead of throwing (fails before the fallback); a view swap shows the new content in the same commit and animates paint only; every swap look keys only opacity, transform or clip-path.test/motion-scale.test.ts: the CSS and TS copies carry the spring; the spring starts and ends at rest and settles within its step.bun run checkand the tests above ran on the fleet:bun run checkexit 0, 18 tests pass with the chat switch suite (41636481602).Observed / Not run
bun run checkon the fleet.Changelog
Changed: The ACP inspector's Wire / Session switch slides its highlight between the two views.
Agent session: agent session
🤖 Generated with Claude Code