scripts(cmux-next): measure whether each surface paints its final layout on frame 1
Leo's perceived-speed program needs one number per surface: how far the first frame a person sees is from the settled one. scripts/cmux-next/perceived-speed.py gets it from the app's own debug.window_record frames (one JPEG per display frame, host-timed), so it covers native and web surfaces alike.
analyze DIRprints time to the first frame, time to settled, the share of the window that differs between the first and the settled frame (0 when the surface painted its final layout at once), a CLS-style repaint score, repaint count and dropped display frames.--stripwrites a before / first / between / settled contact strip.run --socket SOCK --out DIRdrives a DEV build in a capture slot: for each surface (New Tab, new workspace, Settings, palette, terminal, browser, workspace switch) it starts a recording, opens the surface the way a person does (key throughdebug.keyor an action), then closes it.table OUT...ranks the surfaces by frame-1-vs-settled area, then repaint score (medians over runs).
It's a warning tool, never a gate. The first ranking table goes to the coordinator from a slot run of this PR's DEV build.
Verification: python3 -I scripts/cmux-next/tests/test_perceived_speed.py (4 behavior tests on synthetic recordings: painted at once, skeleton then content, a stalled main thread dropping 6 frames, still changing at the end of the recording) passes locally.
Changelog
none
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Adds a perceived-speed tool to scripts/cmux-next that reports, per surface opening, how far the first visible frame is from the settled one. It reads the app's own debug.window_record frames (one host-timed JPEG per display frame), so it covers native and web surfaces; it's a warning tool, never a gate.
analyzeprints time to first frame, time to settle, frame-1-vs-settled area share (0 when the surface painted its final layout at once), a CLS-style repaint score, repaint count, and dropped display frames;--stripwrites a contact strip.rundrives a DEV build in a capture slot and opens each surface the way a person does (a key throughdebug.keyor an action, run with focus so it changes the view). Each run resets to a base workspace and starts on a clean profile (state removed per build key fromcmux/buildsand.acpmux/builds); Settings and What's New close with Cmd-W.find-socketmatches the app's debug socket by bundle id (newer DEV builds listen at hashed paths likecmux-debug--<hash>.sock, where a hyphenated build tag spells hyphens as dots);tableranks surfaces by frame-1-vs-settled area, then repaint score (medians over runs), and leaves no-change runs in a "no change" column.perceived-speed-slot.shtakes a slot lease, fetches the app on the slot host, records every surface, copies the recordings, and prints the ranking table. The app is staged once per job outside the lease, launches with App Nap disabled, and quits throughquitEndSessions. Recordings live outside the lease root so the slot is released before the slow copy back;PSPEED_KEEP_APPkeeps the staged app, and a run that loses the app still copies and ranks what it recorded. The workspace-switch surface gives the target workspace a terminal and switches byworkspace.selectFirstaction.- The defaults schema pins classic home, disables bounce and workspace-switch animations, and keeps the new-tab animation so recorded surfaces match defaults.
- Verification: 4 behavior tests pass against synthetic recordings covering painted-at-once, skeleton-then-content, a stalled main thread dropping 6 frames, and a surface still changing at the end of the recording; a fifth covers
find-socketpicking the right hashed socket. The What's New surface is covered via action. - The branch also carries merged base
feat-cmux-nextwork (browser profile ops/MCP tools, motion curve API with color mix at ABI 3, the fit bar layout fix, Chief sandbox and credits-mirror pieces); none affects the perceived-speed tool.