[cx-ncc.112.66, cx-ncc.112.74] cmux NEXT agent chat: the rail's lit band glides at rest, shows at 75%, and stays lit on hover

Merged
TE
14d ago
+253-15

Leo-ask: ask-50f889c053
Leo-ask: ask-8dbc4a81e1

Takes back #22228: it lit the prompts on screen at 60% and dimmed them back to rest while the pointer was on the rail, so the band barely showed where the reader was. This PR lights them at 75% and keeps them lit on hover. #22228's rail, geometry, fisheye, card, click and scrub are unchanged.

This PR carries over the parts of #24065 that #24058 (50826464) does not cover. #24058 already restored the compact rail as the default and made its band reach the bottom ticks (railScrollTop). It also keeps the band followed with the pointer on the rail (followPointer). This PR builds on that code. The full-height map (#22784) stays selectable from cmux.experiments, as #24058 left it. #24065 is closed in favour of #24058 plus this PR.

What Leo said

On the nightly, the agent chat's left-edge prompt rail (#22228, the Codex rail) "felt short". He explained: "it wouldn't show the highlighted bottom text where I was scrolling at the bottom, and it just didn't go to the bottom. It didn't show the bottom bits being highlighted." About the full-height map: "Why did you turn it into a whole mini map? ... I didn't want the mini map." From #24065's notes on the band's motion (Leo, 2026-10-21): "the wave didn't look good enough".

Change against #24058

#24058 (base)This PR
Lit band brightness60% over rest at 40%75%, through --acpmux-minimap-lit
Band with the pointer on the raildimmed back to reststays lit beside the fisheye
Band moving at restrows flick from rest to litbrighten and dim over 120 ms (--cmux-motion-micro)
Hover, scrub, data-reduce, prefers-reduced-motionswitch at oncestill switch at once
Keyboard focus, the pointer leaving the railswitch at oncestill switch at once: the active tick never glides, and a commit that changes the active row, hover or scrub marks the rail data-snap
Full-height map (full arm)as #24058 left itunchanged: the glide is scoped with :not(.acpmux-scrollmap)
Default arm, railScrollTop, followPointer, the bottom fix#24058unchanged
  • threadMinimap.css: a @media (prefers-reduced-motion: no-preference) block gives the rail at rest a color transition on ticks and transform, opacity on bars. The lit bar reads opacity: var(--acpmux-minimap-lit, 0.75). The two [data-hovering] … [data-tone="current"] rules that dimmed the band are gone.
  • lit.experiment.ts (new, registered): thread-minimap-lit with arms lit-60, lit-70, lit-75 (default) and lit-85. ThreadMinimap reads the arm once per pane and sets --acpmux-minimap-lit on the rail. Dogfood: {"thread-minimap-lit":"lit-60"} in cmux.experiments.

Timers and cleanup: this PR adds no timer, observer or animation loop. Each glide is a CSS transition that ends by itself after 120 ms. A hovered, scrubbed or Reduce Motion rail runs none. No new per-token work: the arm is read once per pane in a useState initializer.

Versions (gallery)

New entry agent-pane.thread-minimap-lit: 18 or 70 synthetic prompts (Prompt N: check the next step of the plan), with states mid-thread, at-the-end and hovered, and the four thread-minimap-lit arms side by side in the compare view.

Stills: the rail strip of each gallery frame at 2x, taken with Playwright's headless Chromium from the gallery host's builds. "Before" is base ea5f81f0 and "after" is this head, 61de4e98. Each frame waits for data-gallery-ready, then 600 ms for the transitions to finish. The computed bar opacities read in the same frames are: rest 0.4 everywhere; lit 0.6 before and 0.75 after; with the pointer on the rail, lit 0.4 before (dimmed) and 0.75 after; the hovered tick 1.

Before / after (dark, light):

Pointer on prompt 9 of 18, band on prompts 15 to 18. Before: the band drops back to rest. After: it stays lit.
before after long chat

At rest mid-thread:
before after rest

Seventy prompts at the bottom of the chat (#24058's fix, now lit at 75%):
before after seventy prompts bottom

Versions: lit at 60% (#22228's, the before), 70%, 75% and 85%; dark, then light:

At rest mid-thread:
lit arms mid thread

At the end of a 70-prompt chat:
lit arms at the end

Pointer on prompt 3, band on prompts 4 to 7:
lit arms hovered

Pick: 75% (the default). At 60% the band is a soft step over rest, most of all in light mode. At 85% in light mode the band is nearly as dark as the hovered tick, so the row under the pointer stops standing out. 75% reads as lit in both schemes and stays clearly under the hovered tick. The other arms stay selectable from cmux.experiments.

Gallery: agent-pane.thread-minimap-lit, agent-pane.thread-minimap/rest, agent-pane.thread-minimap/long-chat, agent-pane.thread-minimap/seventy-prompts-bottom

Tests

webviews/test/thread-minimap-default-wave.test.tsx adds:

  • the lit band ships at 75%, and lit-60 and lit-85 reach the rail's --acpmux-minimap-lit (rendered through VirtualTranscript);
  • the lit bar reads var(--acpmux-minimap-lit, 0.75), and no rule dims the rail's band under [data-hovering];
  • at rest the bar transitions transform and opacity, and the tick transitions color, over --cmux-motion-micro, both inside the no-preference query, and never on an active tick or a data-snap rail;
  • focusing a tick, and leaving it, marks the rail data-snap, and the next band move from the scroll clears it (rendered through VirtualTranscript).

thread-minimap-motion (browser lane) reads the bar's transition at rest: exactly transform, opacity, each 0.12 s with no delay.

Review: Codex (gpt-6.1-sol, xhigh) blocked 61de4e98 on focus and pointer-leave fading, and on the motion test's loose pattern; b6762ca4 fixes all three.

Observed / Not run

  • Observed on huge-blue (scripts/ci/run-webviews-tests.sh, bun 1.4.2): 14 of 15 files pass: thread-minimap default-wave, bottom, rail, current, feel, stream, tiny, room and card-glass, plus gallery agent-pane-entries, manifest, play-names and touched-rank. The 15th, gallery-coverage, fails its two cover checks with the same lists on base, none of them this PR's. vp lint and vp fmt --check are clean on the touched files. typecheck reports 3 errors, all in thread-minimap-stream.test.tsx, which this PR does not touch (base).
  • Not run locally: thread-minimap-motion's browser lane (CI only).

Changelog

  • Improved: the agent chat's prompt rail lights the prompts on screen more clearly, keeps them lit while you point at the rail, and glides the lit band as you scroll.

Webview only; no Swift change.

Agent session: cosmic-gray

🤖 Generated with Claude Code