Skip to content

fix(linux): zoom ghost-pixel fix via CSS transition#228

Open
AgentU-asaf wants to merge 1 commit intomainfrom
agentx/zoom-ghost-fix-linux
Open

fix(linux): zoom ghost-pixel fix via CSS transition#228
AgentU-asaf wants to merge 1 commit intomainfrom
agentx/zoom-ghost-fix-linux

Conversation

@AgentU-asaf
Copy link
Copy Markdown
Collaborator

Summary

  • Sets --zoom-transition-dur: 80ms in initChromeZoom() so WebKitGTK's animation engine invalidates ghost pixels left behind when zoom: var(--zoomfactor) elements shrink on zoom-out
  • Adds transition: zoom var(--zoom-transition-dur, 0ms) ease-out to block headers, statusbar, and window drag header (the three elements carrying the CSS zoom)
  • Adds opacity/transparency retro doc (docs/retro-opacity-transparency-2026-03-25.md) covering the full investigation and recommended path forward

Known issue (not fixed in this PR)

The always-on transition creates GPU compositing layers in WebKitGTK that temporarily drop alpha during scroll, causing the window to flash opaque. The ghost fix needs to be gated to fire only during actual zoom operations (not permanently). This is documented in the retro and should be addressed separately.

Test plan

  • Zoom in/out on Linux — no ghost pixels left behind
  • Window opacity still works as expected (CSS approach)
  • Scroll in terminal — note if opacity flash occurs (known regression, tracked)

🤖 Generated with Claude Code

WebKitGTK leaves ghost pixels in the area vacated when a zoomed
element shrinks (zoom: var(--zoomfactor) going from e.g. 1.2 → 1.0).
WebKit does not repaint the vacated region because it considers only
the new (smaller) bounding box dirty.

Fix: set --zoom-transition-dur: 80ms on <html> in initChromeZoom() and
add `transition: zoom var(--zoom-transition-dur, 0ms) ease-out` to every
element that carries zoom: var(--zoomfactor):
  - .block-frame-default-header (block.scss)
  - .statusbar (StatusBar.scss)
  - .window-drag-header (window-header.linux.scss)

The 80 ms transition forces WebKitGTK's animation engine to invalidate
and repaint the full pre-transition bounding box on each zoom change,
clearing the ghosts. The variable defaults to 0ms so non-Linux builds
and any element that doesn't set the var are unaffected.

NOTE: this approach introduces a scroll-opacity regression on Linux
(transparent window flashes opaque during scroll because the always-on
transition creates GPU compositing layers that temporarily drop alpha).
The fix needs to be gated to fire only during actual zoom changes, not
permanently. See docs/retro-opacity-transparency-2026-03-25.md.

Also adds retro document covering the full opacity/transparency
investigation and recommended path forward.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@reagentx-workflow reagentx-workflow Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReAgent Diagnostics
Field Value
ReAgent Version 5.12.4
Project Context CLAUDE.md loaded
Model claude-opus-4-6
Effort high
Ref Repos Disabled
Merge Analysis Clean
Review Time 30.3s
Timestamp 2026-03-25T12:03:06Z
Repository agentmuxai/agentmux
PR #228

Issues:

  • package.json:3 - Version downgrade detected: 0.32.83 → 0.32.82. Versions must increase; rebase on main and bump to 0.32.84+
  • frontend/app/window/window-header.linux.scss:33 - Hardcodes 80ms instead of using var(--zoom-transition-dur, 0ms) like block.scss and StatusBar.scss. If the duration changes, this file will be out of sync

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant