Skip to content

perf(research): orbit ring repaints the whole pane every frame, forever (perpetual conic-gradient + mask raster) #115

Description

@jdmanring

Problem

The Research pane's animated accent ring is a perpetual per-frame paint producer.

static/js/research/panel.js:_ensureOrbit() runs a requestAnimationFrame loop that rewrites the --research-orbit-angle CSS variable every frame while the panel is open — by design even when idle with no research job running (ambient mode, _orbitSpeedDegPerSec = running > 0 ? 60 : 22). The loop only stops when the pane is removed.

That variable feeds static/style.css .research-pane::after:

.research-pane::after {
  position: absolute; inset: 0;                 /* full pane area */
  background: conic-gradient(from var(--research-orbit-angle), …);
  mask: …; mask-composite: exclude;             /* dual-mask to a 2px ring */
}

Every frame the browser recomputes a conic-gradient over the entire pane box and re-applies an exclude mask-composite, then re-rasterizes — 60 fps, forever. This is the worst-case 'paint, not compositor' pattern (large area + mask), and it is invisible work when idle (no job, user not looking).

Impact

Discovered via CDP (tooling/mem-probe.py raf flagged _ensureOrbit <- _syncResearchRail). On hardware GPU it's a steady background cost; under software rendering (llvmpipe) it is catastrophic. Same family as the spinner (#107) and brain-panel (#108) perpetual-animation fixes, but worse (full-area + mask).

Proposed fix

  • Freeze the orbit when no job is running (the ambient idle spin is pure decoration burning frames) — leave a static ring; only drive the rAF while running > 0. Eliminates the idle case entirely.
  • When it does run, prefer a compositor approach (static gradient + transform: rotate()) or throttle below 60 fps. Note: a traveling arc around a rounded-rect can't be fully compositor-free, so freezing-when-idle is the high-value win.
  • Honor prefers-reduced-motion (already partially done — the ::after has a reduce rule, but the JS rAF ignores it; gate the JS too).

Evidence: this session's CPU investigation; static/js/research/panel.js:160-183, static/style.css:35927.

Metadata

Metadata

Assignees

No one assigned

    Labels

    upstream-candidateBug or feature suitable for contributing to upstream

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions