Skip to content

Add transparent background support - #198

Open
statik wants to merge 19 commits into
kenn-io:mainfrom
statik:transparent-background
Open

Add transparent background support#198
statik wants to merge 19 commits into
kenn-io:mainfrom
statik:transparent-background

Conversation

@statik

@statik statik commented Aug 26, 2026

Copy link
Copy Markdown
  • Ghosthub windows now honor background-opacity and background-blur from the terminal config. When opacity is below 1, the window, titlebar, sidebar, and empty states become translucent at one consistent level, and the layers behind the terminal render clear so the desktop shows through — matching how Ghostty.app treats the same settings.
  • The appearance derives from the loaded libghostty config graph at startup and on every reload, so edits to ghostty.conf apply live without a restart. libghostty remains authoritative for parsing; there is no separate Ghosthub setting.
  • Blur is applied through ghostty_set_window_background_blur, the same entry point Ghostty.app uses. macOS 26 glass-style values skip the radius call, matching upstream behavior.
  • Accessibility increased contrast forces opaque. Native fullscreen stays opaque, with chrome re-applied on fullscreen enter and exit.
  • tmux, Herdr, and Zellij session views previously painted an opaque fill behind the terminal surface; that fill now clears under transparency so the surface's own alpha is visible.
  • Sidebar preview thumbnails flatten over an opaque background so cards stay legible regardless of terminal transparency.
  • Existing users keep today's look unless they lower background-opacity; the default config's 0.95 now has a subtle visible effect, and 1 restores a fully opaque window.
  • Docs: an architecture note on the appearance derivation and a website Guide section for the two config keys. No screenshot refresh: the Guide addition documents config keys rather than UI operation, and the existing screenshot set's visuals are not materially altered at default opacity.

https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW

statik added 16 commits August 26, 2026 14:07
Route the libghostty background appearance into GhosthubUI via a new
terminalBackgroundAppearance environment key, injected from the App
module where LibghosttyRuntime lives. Surfaces directly behind the
terminal go fully clear when transparent (the surface paints its own
background at the configured opacity); chrome surfaces use the new
WorkspaceSurfaceColor opacity variants so the window shows one
consistent translucency. Opaque config renders exactly as before.

Sweep of WorkspaceSurfaceColor/paneFill call sites:
- RootView.swift workspaceContent (workspaceColumns background):
  behind sidebar and terminal -> clear when transparent.
- RootView.swift workspaceSidebarColumn background: sidebar chrome
  surface -> tinted at appearance opacity.
- RootView.swift terminalWorkspaceWithPreviewParking: cover layer ->
  clear when transparent; parked preview surfaces drop to 0.001
  opacity so they keep rendering without showing through.
- WorkspaceSidebarView.swift host header hierarchy-row background:
  chrome surface -> tinted; Color.primary overlay unchanged.
- WorkspaceWindow.swift root background: behind everything -> clear
  when transparent.
- WorkspaceWindow.swift WorkspaceWindowChrome.apply (nsColor sites):
  already appearance-aware from the window chrome change; unchanged.
- SettingsView.swift .background(paneFill): settings sheet with its
  own backing -> stays opaque; out of scope.
- PaneColors.swift paneFill definition: definition only.

Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
The sidebar column already paints the tinted surface, so repainting it
on the host-header row multiplied the alphas (~0.96 effective at 0.8)
and made the header visibly more opaque than the rest of the sidebar.
Inherit the column surface when transparent, keeping only the
Color.primary overlay for header differentiation; opaque rendering is
unchanged.

Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
The clear-when-transparent ternary was duplicated across four call
sites (and its tinted sibling at a fifth), which already caused one
alpha-compounding bug. Replace them with two helpers on
WorkspaceSurfaceColor: behindTerminal(_:) for layers the terminal
surface (or an already-tinted surface) draws over, chrome(_:) for
chrome surfaces tinted at the configured opacity.

Also from review follow-ups:
- Clamp nsColor(opacity:) to 0...1 before withAlphaComponent;
  out-of-range alpha is unspecified on the public API.
- Justify the 0.001 parking opacity from verified behavior: terminal
  occlusion pausing is window-scoped (TerminalSurfaceView reads only
  window.occlusionState/isVisible/isKeyWindow), so 0 would not pause
  the surfaces, but SwiftUI may skip compositing at exactly zero;
  0.001 avoids that and matches the near-clear window background in
  WorkspaceWindowChrome.apply.
- Test tinted alpha under both light and dark appearances, assert the
  base colors differ across appearances (dynamic resolution survives
  the alpha wrap), compare all RGB channels against the canonical
  color, and cover the new clamp.

Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
The non-terminal branches of terminalWorkspaceContent (session
detached, opening/loading progress, no-session and error states, the
welcome screen) sat over the behindTerminal cover, which goes clear
under a transparent config — they floated over the bare desktop at
full transparency, breaking the uniform chrome translucency and
hurting readability over busy wallpaper.

Extract those branches into emptyWorkspaceState — they are the entire
tail of the if/else chain after the three terminal branches, so one
shared container covers all seven uniformly — and give it a single
chrome(_:) background. The shared full-size frame replaces the
per-branch max frames, keeping each state centered in the same slot.

Opaque rendering is unchanged: these views previously had no
background of their own and were drawn over the opaque cover;
chrome(.opaque) paints the same canonical surface color over that
identical opaque cover, which is visually indistinguishable.

Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
The borrowed tmux, Herdr, and Zellij session views painted an opaque
textBackgroundColor directly behind the libghostty surface, defeating
the surface's configured alpha in the terminal content area. The
backdrop is now clear whenever the terminal background appearance is
transparent, and unchanged when opaque.

Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
@statik
statik deployed to sandbox-image-promotion-status August 26, 2026 18:08 — with GitHub Actions Active
@statik
statik deployed to sandbox-image-promotion-status August 26, 2026 18:08 — with GitHub Actions Active
@statik
statik deployed to sandbox-image-promotion-status August 26, 2026 18:08 — with GitHub Actions Active
@roborev-ci

roborev-ci Bot commented Aug 26, 2026

Copy link
Copy Markdown

roborev: Combined Review (6b48ca5)

No issues found.


Reviewers: 2 done | Synthesis: codex | Total: 10m13s

Ports the snapshot opaque-flatten fix onto the always-live preview
rework: the CGContext thumbnail path was replaced upstream by a
CoreImage composite, which now flattens over opaqueFill so preview
frames stay opaque under a transparent terminal background. The
CGImage composite test is superseded by the opaqueFill seam tests;
the live-surface smoke tests cover the GPU render.

Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
@statik
statik deployed to sandbox-image-promotion-status August 26, 2026 18:24 — with GitHub Actions Active
@statik
statik deployed to sandbox-image-promotion-status August 26, 2026 18:24 — with GitHub Actions Active
@statik
statik deployed to sandbox-image-promotion-status August 26, 2026 18:24 — with GitHub Actions Active
@roborev-ci

roborev-ci Bot commented Aug 26, 2026

Copy link
Copy Markdown

roborev: Combined Review (e8eb500)

Verdict: One medium-severity UI issue was identified.

Medium

  • Sources/UI/RootView.swift:1720-1722 — Recovery/no-surface views for active tmux, Herdr, or Zellij sessions use a clear background, exposing the desktop instead of the configured workspace tint. Apply WorkspaceSurfaceColor.chrome(backgroundAppearance) to these branches.

Reviewers: 2 done | Synthesis: codex, 6s | Total: 12m19s

statik added 2 commits August 26, 2026 17:10
The recovery, disconnection, and opening fallback branches of the
borrowed tmux, Herdr, and Zellij session views sat over a cover that
goes clear under a transparent terminal background, so they floated
over the bare desktop instead of the workspace chrome tint; each view
now collapses those branches into one sessionFallback container with a
shared chrome(_:) background. When opaque, chrome(.opaque) paints the
canonical surface color over what was previously the opaque cover
behind these views, so opaque rendering is visually unchanged.

Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
@statik

statik commented Aug 26, 2026

Copy link
Copy Markdown
Author

Addressed in c156256: the recovery, disconnection, and opening fallback branches of the tmux, Herdr, and Zellij session views now share a single WorkspaceSurfaceColor.chrome(backgroundAppearance) container (same pattern as the empty-workspace states in 0af0f68), so they render over the workspace tint instead of the bare desktop under transparency. Live-surface branches are untouched, and opaque rendering is unchanged since the chrome color matches the previously opaque cover.

https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW

@statik
statik deployed to sandbox-image-promotion-status August 26, 2026 21:22 — with GitHub Actions Active
@statik
statik deployed to sandbox-image-promotion-status August 26, 2026 21:22 — with GitHub Actions Active
@statik
statik deployed to sandbox-image-promotion-status August 26, 2026 21:23 — with GitHub Actions Active
@roborev-ci

roborev-ci Bot commented Aug 26, 2026

Copy link
Copy Markdown

roborev: Combined Review (26f07d4)

No issues found.


Reviewers: 2 done | Synthesis: codex | Total: 13m44s

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant