From 843c3abcc7f27f8942864db4519bcdfdf4ea5495 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Sat, 8 Aug 2026 12:31:52 -0500 Subject: [PATCH] fix(desktop): an empty HUD thread shouldn't paint a blank panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A fresh thread has nothing to show, but the HUD showed a slab of frosted glass above the bar anyway. Vibrancy is the window's whole content view, so it frosts the full rectangle — fine while the band always filled the window, wrong the moment there is no transcript to fill it. It stays off until there is something to back. The sheet had a 12px floor for the same reason: the breathing room above the first row was added in CSS, so a zero-row transcript still measured 12. It is folded into the measured height now and only applies when there are rows. --- apps/desktop/src/app/hud/hud-shell.tsx | 22 +++++++++++++--------- apps/desktop/src/styles.css | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/desktop/src/app/hud/hud-shell.tsx b/apps/desktop/src/app/hud/hud-shell.tsx index dee6a30af7..348f3af3a4 100644 --- a/apps/desktop/src/app/hud/hud-shell.tsx +++ b/apps/desktop/src/app/hud/hud-shell.tsx @@ -9,7 +9,7 @@ import { useI18n } from '@/i18n' import { chatMessageText } from '@/lib/chat-messages' import { closeHud } from '@/store/hud' import { $activeSessionAwaitingInput } from '@/store/prompts' -import { $busy, $messages } from '@/store/session' +import { $busy, $messages, $messagesEmpty } from '@/store/session' import { WiredPane } from '../contrib/wiring' import { titlebarButtonClass } from '../shell/titlebar' @@ -41,8 +41,8 @@ const HUD_DIM_MS = Math.round(HUD_FADE_MS * 1.5) const HUD_COLLAPSE_MS = Math.round(HUD_FADE_MS * 0.66) /** Breathing room the sheet keeps above the first row, so the fade has - * somewhere to land. Published to CSS, and used here to work out how much of - * the window the HUD actually occupies. */ + * somewhere to land. Folded into the measured height rather than added in CSS, + * so an empty transcript measures a true zero instead of a 12px strip. */ const HUD_SHEET_OVERHANG_PX = 12 /** Composer on top, transcript always hanging below it — Spotlight's shape, @@ -156,6 +156,10 @@ export function HudShell() { const { t } = useI18n() const [recent, holdBand] = useRecentActivity() const held = useHudHeld() + // Nothing to back yet. Vibrancy is the window's whole content view, so on a + // fresh thread it frosts the empty space above the bar into a blank slab — + // the transcript's backing showing up before the transcript does. + const empty = useStore($messagesEmpty) // Main holds the session id on this window's behalf, so leaving HUD mode can // hand the app window back whatever conversation ended up here. @@ -264,9 +268,10 @@ export function HudShell() { const span = !rows?.length || !box ? 0 - : root.dataset.hudEdge === 'top' - ? rows[rows.length - 1].getBoundingClientRect().bottom - box.top - : box.bottom - rows[0].getBoundingClientRect().top + : HUD_SHEET_OVERHANG_PX + + (root.dataset.hudEdge === 'top' + ? rows[rows.length - 1].getBoundingClientRect().bottom - box.top + : box.bottom - rows[0].getBoundingClientRect().top) root.style.setProperty('--hud-band-height', `${Math.max(0, Math.round(span))}px`) @@ -297,7 +302,7 @@ export function HudShell() { } }, []) - useHudGlass(rootRef, recent || held) + useHudGlass(rootRef, (recent || held) && !empty) useHudClickThrough(rootRef) // Force the HOST layers transparent. index.html's pre-paint script writes an @@ -332,8 +337,7 @@ export function HudShell() { '--hud-fade': `${HUD_FADE_MS}ms`, '--hud-collapse': `${HUD_COLLAPSE_MS}ms`, '--hud-dim': `${HUD_DIM_MS}ms`, - '--hud-reveal': `${HUD_REVEAL_MS}ms`, - '--hud-sheet-overhang': `${HUD_SHEET_OVERHANG_PX}px` + '--hud-reveal': `${HUD_REVEAL_MS}ms` } as CSSProperties } > diff --git a/apps/desktop/src/styles.css b/apps/desktop/src/styles.css index 10b01d848b..c593456ca7 100644 --- a/apps/desktop/src/styles.css +++ b/apps/desktop/src/styles.css @@ -2393,7 +2393,7 @@ button[data-slot='aui_msg-reactions'] svg { The height below still tracks the transcript; only the offset animates on exit, and it finishes ahead of the fade so the panel has left while the last of the text is still going. */ - height: min(100%, calc(var(--hud-band-height, 0px) + var(--hud-sheet-overhang, 0.75rem))); + height: min(100%, var(--hud-band-height, 0px)); translate: 0 var(--hud-exit-shift, 2.5rem); opacity: 0; transition: