cmux NEXT New Tab: the composer stays where it first painted
Leo saw the New Tab composer move around on the cmux NEXT nightly ("going to places"). It should stay where it first painted while the page loads, while you type, when you paste an image, and when Now Playing or a long draft shows up.
Two things moved it:
- In every template, including Cards (the new default since 9215b25d8a7), pasted or dropped attachments went above the field, so the typed text dropped by a tile's height.
- In the composer template, the page centered all of its content, so the card jumped up every time something grew under it: the Now Playing row, a pasted image, each new line of a long draft.
What changed:
- The composer template's card now sits at a fixed spot,
max(32px, 50vh - 102px)from the top. That's where centering put the resting page, so the empty page looks the same as before. - Attachments go under the field instead of above it. In Cards they use the field's 22px text inset, and the pill rounds to 28px while attachments make it taller than one line, so its ends don't cut into the tiles. They use the chat composer's tile size, and the remove badge is the chat composer's (before this, it drew as a stray button under the thumbnail on New Tab).
- Gallery:
composer-holds-its-placeandcomposer-template-holds-its-placetype a prompt, paste an image and start Now Playing, then check that the card and the field are where the empty page drew them.
Changelog
- cmux NEXT: the New Tab composer stays where it first painted while chats load, while you type, and when you paste an image, Now Playing starts or a draft gets long.
Testing
webviews/test/new-tab-composer-still.test.ts runs the real agent pane in Chromium and WebKit, with a stand-in host and a daemon whose chat list arrives late. It records the card's rect and the field's position on every frame and DOM change from document start, across loading, typing (suggestions open), a pasted image, Now Playing and a long draft. It checks five cases: Cards and Default at 900px and at 560px, and the composer template at 900px.
Red, with only the test file added to the base:
- At base 1fac57d4412: every case fails in both engines. Cards' text drops from 72 to 176 when an image is pasted, and Default's from 158 to 262. (The log printed 9 of the 10 failures before it was cut off. The 10th is webkit on the composer template, which failed at 0ae907b47da.)
- At base 0ae907b47da, before Cards existed: 6 of 6 fail. The composer template's card climbs from 380 to 226.5 as the image, Now Playing and the draft arrive.
Green at the head:
- At de1d4ea8364: 10 of 10 pass.
- Before the Cards merge: 6 of 6 passed in three back-to-back runs at 458873e98a0, and again at 714beaff0fc.
test/new-tab-paste-attachments.test.tspasses 6 of 6 at both heads. Command on Huge Blue:CMUX_BROWSER_TESTS=1 bun test test/new-tab-composer-still.test.ts, one process per file asscripts/ci/run-webviews-tests.shdoes. Run both files in one bun process and the still test's setup times out, so CI runs them one per process.
bun run check in webviews on Huge Blue: vp check, acpmux-protocol:check, browser-lanes, layers, type-scale, status-glyphs and system-blue pass. check:text-focus (10 Swift text fields) and check:dialog-keys (8 dialog buttons) fail the same way on the base. None of their findings are in files this PR changes.
Observed / Not run
- Observed: the red and green runs above, plus gallery renders of the two new stories in Linux Playwright WebKit (below).
- Not run: no capture of the real macOS app. The cmux-next media tour skips webview-only changes, and the
media-tour-maclabel that would force one doesn't exist in this repo. The capture minis have no bun, so the gallery can't be rendered in macOS WebKit there either.
Risk tier
Medium: webview app UI, 4 source files plus a test. Proof is below.
Review: SHIP at de1d4ea8364, from a correctness-first review subagent on the Cards merge and conflict resolution. It found nothing lost or duplicated, and nothing in Cards that moves the box. Its two low nits are left as they are:
- A long Cards draft without attachments still draws as a stadium. That comes from 9215b25d8a7.
- The test doesn't assert the strip's own position.
An earlier review gave SHIP with nits at 458873e98a0. Fixed in 714beaff0fc:
- The rect log compared string prefixes, so
field 100,18followed byfield 100,180would have been missed. It now compares whole rects. - The long-draft step now waits for Now Playing to draw.
- Removed an unused attachment variable.
Not changed, because both were already like this on the base:
- A worktree failure notice above the box still pushes it down. It only shows after you act.
- The document-attachment badge's
top: 20pxloses to the generaltop: 4pxrule.
Proof
Gallery stories agent-pane.new-tab / composer-holds-its-place (Cards) and composer-template-holds-its-place, rendered in Linux Playwright WebKit, not the macOS app. Each shows the page after typing, a pasted image and Now Playing. Before is base ba8b81c1c52 with only the story added; there, the story's own check fails with "the composer moved". After is the head, de1d4ea8364.
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes the cmux NEXT New Tab composer moving around while the page loads, while you type, when you paste an image, and when Now Playing or a long draft appears. The composer template's card now sits at a fixed spot, max(32px, 50vh - 102px) from the top, instead of re-centering on whatever grows under it, and attachments render under the field instead of above it, so the typed text keeps its place in every template.
- Attachments use the chat composer's tile size and remove badge; the Cards pill rounds to 28px when attachments make it taller than one line.
- Adds two gallery stories and a browser test covering Cards, Default, and composer templates across Chromium and WebKit at two window heights.