Agent chat: Worked for folds and unfolds with motion (cx-o90g7)

Closed
TE
18d ago
+586-11

cx-o90g7. Stacked on #20582 (its commits show here until it lands). SHOW LEO: hold for Leo before merge.

What

The "Worked for" fold moves instead of jumping:

  • Turn ends (running → done): the steps fold away as the answer and the edits card settle into place. The steps fade out while the new rows fade in, so no frame goes empty.
  • Reader opens the fold: the header keeps its place. The answer slides down (--agent-motion-move, 190 ms ease-out), then the opened steps fade in under it.
  • Reader closes the fold: the steps fade out (--agent-motion-out, 80 ms) while the answer slides up into place.
  • While the turn runs: "Working for Ns" carries the existing "Thinking" sweep. It stops when the clock stops.

Rows are placed absolutely, so nothing animates a height. Each row's translate runs from where it was drawn to its new place (a FLIP, the way the New Tab list moves). The bottom-pin glide is off while this runs, so the whole pane never slides. A toggled fold keeps its header still and stops following when it opens past the end.

Reduce Motion keeps only a short fade (≤100 ms) and no movement. With animation speed off, there is no motion at all.

Variants

For comparison, #foldMotion= picks the variant:

  • slide: proposed, and the default.
  • fade: rows jump, steps fade.
  • none: no motion.

scripts/agent-pane/fold-motion-tour.mjs records all three against the mock agent.

Captures

Side by side: before (this branch's base, #20582), slide, and fade only. Real speed, then 4Ɨ slower. Recorded headless in Chromium against the mock agent on the private builder. I watched them frame by frame.

worked for motion

Full quality:

worked for motion 4x slower

Full quality:

Real app (cmux NEXT DEV)

Fleet DEV builds on a capture mini: after = this head (4152f790a721), before = its base on feat-cmux-next (2a68993bc732). The chat is the app's showcase mock agent (9 steps Ɨ 350 ms per turn), at the default animation speed (fast). Each app's agent-pane bundle was checked before shooting: foldMotion is in the head's pane.js and absent from the base's. Stills are the main window, cropped to the sidebar and chat; the mini's machine name in the composer is blanked.

Composer overlap

The end of a long chat (five turns). In the before shots the last turn's time, Copy and Fork row is clipped by the composer's top edge, the multi-line draft included; in the after shots it sits clear of the composer.

Before, lightAfter, lightBefore, darkAfter, dark
Turn ended
After opening and closing the fold
Multi-line draft

Fold states

Before, lightAfter, lightBefore, darkAfter, dark
Running (Working for, sweep)
Folded
Opened

A still catches the sweep at one point of its pass; in the after clips the highlight moves across "Working for" while the turn runs (the base's label stays flat gray). In the opened shots the fold runs past the end, so the view stops following and shows the jump-to-latest button.

Clips: turn ends and folds, then the fold opens and closes

The slide, fade and none clips are from a DEV build of 284dd5005850, which fixed the fade and none issues the first recording showed; the stills and the base clip are unchanged (the opened still matched on 284dd5005850). Each is 8 s: send at 0.3 s, the turn ends and folds at about 3.5 s, open at about 4.7 s, close at about 6.5 s. The mode was set through the agent pane's registry.js customization (it puts #foldMotion=<mode> on the page and reloads it); no app code changed for the captures.

ModeClip
slide (default)
fade (7d1c6d2f2fd9)
none
before (base)

Watched frame by frame at 60 fps (284dd5005850):

  • slide: the answer slides down on open and up on close, and the steps fade in after it; no empty frame.
  • fade (re-recorded on 7d1c6d2f2fd9): no near-empty frame on open or close. Rows the fold moves fade from about 0.4 opacity and new steps from 0, settling over about 3 to 5 frames.
  • none: open and close are instant, and the "Worked for" header keeps its place in both.

Verification

  • bun run check passes on the builder.
  • Transcript tests pass: transcript-worked-fold, jump-latest, long-chat-updates. follow runs in the browser lane.
  • Seen in real cmux NEXT DEV builds of this head and its base: see Real app (cmux NEXT DEV) above.

Changelog

Changed: the agent chat's "Worked for" fold slides open and closed, and a finished turn folds its steps with a short crossfade.

šŸ¤– Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

The agent chat's "Worked for" fold now moves instead of jumping: finished turns fold their steps with a crossfade, and opening or closing a fold slides the rows that stay into place while the toggled header keeps its place on screen. The last turn's time, Copy and Fork rows always clear the composer, even with a long draft or while the next reply streams; slide is the default, with fade (moved rows fade from 0.4, steps from 0) and none variants selectable via #foldMotion=.

Also fixes turns that end on a tool call: the interim text now folds with the rest instead of remaining open as the answer, including when an edit runs a tool in the same step.

  • Rows sit absolutely and slide via translate (a FLIP); steps fade in or out where they are, so no height animates and no frame goes empty.
  • Reduce Motion keeps only a short fade; the transcript neither glides nor follows while a change plays.
  • The branch also carries participant avatars (SHA-256 deduplicated, read in the Channels page), agent.message.release withdrawal, the background-process registry, and daemon/Chief handoffs.