webviews: Static status indicators and Reduce Motion stop every web loop (cx-sya4n)
cmux NEXT's web pages now stand still when status indicators are Static or Reduce Motion is on. The look comes in with the theme, like the scrollbar style does: WebTheme carries statusIndicators, and its document-start bootstrap sets data-status-indicators on <html>. Every page gets it, Home included, and the agent pane's theme sends the same value. Under static, no status loop runs:
- the mic's wait pulse
- the model picker and harness spinners
- the floating chat's breathing dot
- the Thinking sweep (the word stays muted)
- the reply caret's wait pulse
- the Jump to Latest dots
- Home's "writing" marker
Color-only marks also get a shape each:
- Floating status: a dot while it works, and a triangle drawn in the dot's own 6px box when it needs you, so nothing beside it moves.
- Subagent dots: โ and โ.
- Lineage badges: dot, !, โ, โ and ring.
Subagent dots name their state in the tooltip. The diff viewer's base-picker spinner stops under Reduce Motion instead of slowing down. This is cx-sya4n: blinking lights give a teammate headaches.
- Native:
WebThemecarriesstatusIndicators, which isstaticunder Reduce Motion orappearance.statusIndicator.animation: "static".- A
PageWebViewpushes its theme again when that setting or Reduce Motion changes. AgentPaneThemesends the same value, through two lines identical to #21664's, so the two merge without conflict.
- Web:
applyAgentThemesets the attribute from the agent theme. The CSS rules sit under:root[data-status-indicators=static].
The look reads StatusIndicatorSettings.animation from #21659, which has merged; the branch is on current feat-cmux-next. The four commits are 447ddfe0945 (test), 3493030775b, b6c45a343eb (test) and dc50b230def. It doesn't need #21662 (the Settings row).
No new strings: the tooltip reuses the existing STATE_LABEL keys.
Testing
-
webviews/test/static-status-loops.test.tsloads the real stylesheets in Chromium. It turns the look on the app's way: it runsWebTheme.bootstrapScript, read from the Swift source as the gallery does, then pushes a theme carryingstatusIndicators. It lists running infinite animations (document.getAnimations()) and checks the following:- The loops run by default.
- Static stops every pane and Home loop.
- Reduce Motion stops every loop, including the diff viewer's.
- Thinking stays readable.
- Each color-only mark gets its own shape.
- The theme push sets the attribute.
- The static triangle keeps the dot's box, so its neighbour's position is unchanged.
It's a browser-lane test, and it skipped locally because Chromium isn't installed on this host.
-
webviews/test/status-indicators-theme.test.tschecks that the agent theme's look reaches the root. It passes locally (bun test). -
WebThemeStatusIndicatorsTests(CmuxNextDesignTests) checks that the payload carriesstaticunder the setting or Reduce Motion, and that the bootstrap sets the attribute. This host is Linux, so it hasn't run yet. -
CI's first run (on that commit's pre-rebase copy, 2dc90cca633):
react-apps-checkfailed atcheck:text-focusonDaemonRecoveryControls.swift. That's base-red from #20765, so the test step never ran. -
Local checks:
bun testofgallery-web-theme-bootstrap.test.tspasses, so the bootstrap still parses.check:layers,check:browser-lanes,check-crash-safety.shandlint-swift-post-edit.shpass.tsc --noEmitreports only a missingweb/datasnapshot, which isn't in this sparse checkout.
Changelog
Fixed: in cmux NEXT, Reduce Motion stops every web page's status loops, including the diff viewer's base-picker spinner.
๐ค Generated with Claude Code