Skip to content

Native browser view obscures canvas overlays and widgets #14

Description

@cododel

Problem

The built-in Browser combines React UI with a native Electron WebContentsView. The native page does not participate in the renderer DOM stacking context, so it can paint above canvas UI even when that UI has a higher CSS z-index.

Two cases were observed on macOS:

  1. When the Browser approaches the top of the application, the native page surface and its scrollbar can extend into UI outside the expected page viewport.
  2. When the Browser overlaps the bottom-right keyboard shortcut overlay, the page covers the overlay background and part of its text despite .shortcut-hints using z-index: 300.

The same problem can affect other DOM-backed canvas widgets that should appear above the Browser.

Image Image

Root cause

BrowserService.syncViews mounts the active page as a native WebContentsView under BrowserWindow.contentView.

Other canvas widgets and overlays are rendered inside the React renderer. CSS z-index cannot change stacking order across the native/DOM boundary.

The existing clipping logic constrains the Browser to a rectangular viewport and application bounds, but it does not account for higher DOM overlays or overlapping widgets.

Relevant code:

  • src/main/services/BrowserService.ts: syncViews, mountClipTab, clipView
  • src/main/services/browser/BrowserCanvasGestureController.ts: surfaceDecision, activateFreezeFrame, refreshFrame
  • src/renderer/src/features/browser/BrowserCard.tsx: reportViewport, freezeFrameVisible, nativeViewVisible
  • src/renderer/src/features/workspace/WorkspaceCanvas.tsx: shortcut-hints
  • src/renderer/src/styles/app.css: .shortcut-hints, .canvas-controls

Expected behavior

  • Application chrome and persistent overlays remain visible above the Browser.
  • Canvas widget ordering remains visually consistent when widgets overlap.
  • The live Browser remains interactive when unobscured.
  • Restoring the live native view does not cause a geometry jump or show a stale frame.

Proposed direction

Introduce an occlusion-aware composition policy instead of relying on CSS z-index:

  1. Treat fixed application chrome as explicit safe areas and keep the native viewport outside them.
  2. Render suitable persistent overlays in a trusted native overlay, or relocate them when they intersect the Browser.
  3. For arbitrary overlaps with higher DOM widgets, extend the existing freeze-frame mechanism:
    • capture the current page;
    • hide the native WebContentsView;
    • display the snapshot inside BrowserCard;
    • restore the live view when the Browser is selected or brought to the front.
  4. Invalidate captured frames after navigation, tab changes, resize, canvas zoom, and live/snapshot transitions.

Rectangular insets can solve fixed safe areas, but they cannot represent arbitrary overlap between multiple widgets and should not be the only mechanism.

Reproduction

  1. Start CanvasTTY on macOS and open the built-in Browser.
  2. Move or resize the Browser near the top application UI.
  3. Inspect the native page and scrollbar at the upper boundary.
  4. Move or resize the Browser so it intersects the bottom-right keyboard shortcut overlay.
  5. Observe that the native page paints above the overlay despite its higher DOM z-index.
  6. Repeat with another DOM widget positioned visually above the Browser.

Environment

  • macOS
  • Electron 43.2.0
  • Observed on feat/canvas-trackpad-navigation

Acceptance criteria

  • The native page and scrollbar do not paint into reserved application chrome.
  • shortcut-hints and other persistent overlays remain visible above the Browser.
  • Higher DOM widgets render above the Browser without relying only on CSS z-index.
  • An occluded Browser snapshot does not receive hidden pointer or keyboard input.
  • Selecting the Browser restores the live WebContentsView without a geometry jump.
  • Navigation, tab changes, resize, and canvas zoom cannot display a stale freeze-frame.
  • Unit tests cover occlusion geometry and live/snapshot/live transitions.
  • An Electron smoke test covers native/DOM layering on macOS.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions