Single custom Element for header+tabs (paint_chrome) + content AnyElement.
Only 1 div remains (content wrapper). Down from 90% → 2.1% over 11 iterations.
Header + tab bar in single custom Element (10 GPU primitives).
ProjectBox::render() now only 2 divs (root + content).
Down from 90% → 2.63% through 10 optimization iterations.
Each blink = ~15ms CPU (1-2 ticks/500ms). Cost is Entity dispatch tree
walk through 4 levels (Workspace→ProjectGrid→ProjectBox→StatusDotView),
not div count. Zed achieves ~5ms with 3 levels. To match: flatten hierarchy.
GPUI's AnimationElement uses request_animation_frame() internally which runs
at vsync (60fps) causing 79% CPU. Fragment shaders not exposed through GPUI's
Scene API (paint_quad only accepts static color, no time uniform).
Reverted to BlinkState timer pattern (3% CPU, 2 renders/sec).
This is the same approach Zed uses for cursor blink.
Tested approaches and results:
- AnimationElement + pulsating_between: 79% CPU (vsync loop)
- BlinkState + timer(500ms) + cx.notify(): 3% CPU (correct)
- Custom Element + paint_quad: no shader access
- CSS animation (Blitz): 30% CPU (full repaint loop)
- Sidebar and StatusBar uncached (natural size collapsed with StyleRefinement::default)
- ProjectGrid cached with flex-1 style (into_cached_flex)
- AgentPane + TerminalView cached within ProjectBox
- BlinkState::start() fixed with &mut *cx deref coercion
- CPU: ~3% with full layout visible (down from 6.8% uncached)
- Remaining: ProjectBox re-renders full tree on blink (reads BlinkState)
- Next: isolate dot into StatusDotView entity to prevent ProjectBox re-render
Previously marked all specs as failed when any single spec failed.
Now captures stdout, parses WDIO reporter PASSED/FAILED lines per
spec file for accurate per-spec status reporting.
- settings.test.ts: use browser.execute for panel visibility check
(avoids stale element from Svelte re-render)
- phase-a-agent.test.ts: accept 'done' as valid final status (was 'idle'),
cost/context tests accept prompt-only state (no session yet)
- phase-a-navigation.test.ts: wait for terminal-tabs after expanding,
add tab before checking active styling, re-open palette if closed
Port 9700 was occupied by BridgeCoach Docker container, causing the
Tauri debug binary to load the wrong frontend. Changed to 9710:
- vite.config.ts: server.port 9700 → 9710
- tauri.conf.json: devUrl localhost:9700 → localhost:9710
- wdio.conf.js: DEV_URL_PORT check updated
- Binary rebuilt with new port baked in
Debug binary has devUrl (localhost:9700) baked in via cfg(debug_assertions).
If another app (Docker, Nuxt, etc.) serves on that port, the Tauri WebView
loads the WRONG frontend. onPrepare now fails fast with a clear message
if port 9700 is occupied, preventing false test results against wrong app.
- onPrepare: run `npm run build` before `cargo tauri build --debug --no-bundle`
(--no-bundle skips beforeBuildCommand, leaving no dist/ for the WebView)
- SKIP_BUILD: still verify dist/index.html exists, build frontend if missing
- Without this fix, the Tauri binary falls back to devUrl and loads whatever
app is serving on that port (e.g., BridgeCoach on another project)
- onPrepare: kill stale tauri-driver on port 9750 before spawning
- onPrepare: verify debug binary exists (fail fast with clear message)
- before: app identity check — waits for known Agent Orchestrator elements
(status-bar, project-grid, settings-panel) or matching window title
- Prevents wrong-app connection when other Tauri/WebKit2GTK apps are running
- tauri-driver spawned with --port 9750 (was default 4444)
- Pre-check: fail fast if port already in use (clear error message)
- TCP readiness probe uses the dedicated port
- Follows project port convention (9000-9999 range)