fix(session-window): stop the startup flash in detached windows - #1236
Merged
Conversation
A detached session window opened transparent, flashed an opaque plate, then settled back to its vibrancy. Two separate layers painted that plate and neither of them was the app's own surface. macOS: apply_window_background_color enabled WKWebView background drawing without pinning underPageBackgroundColor, so the webview fell back to its white default for the whole bundle boot, and index.html's --splash-bg plate (#ffffff on a light theme) painted over the vibrancy on top of that. The window now mounts its material, clears the backdrop, and pins the webview's own background; index.html skips the plate for macOS secondary windows, which settle on vibrancy anyway. Windows and Linux: the opaque startup backdrop was a hardcoded #0d0d0d, so a light-theme window opened dark, then white, then the app. It now follows general.theme and matches --splash-bg exactly. The window is also built hidden and shown once its chrome is applied, so the pre-chrome frames never reach the screen. The show stays synchronous with creation rather than deferred to first paint.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Opening a detached session window showed three states in a row: the window
appeared transparent, flashed an opaque plate, then settled back to its
vibrancy. Two independent layers painted that plate and neither of them was
the app's own surface.
On macOS the window is built transparent with an
NSVisualEffectViewbehindits webview and settles on that material (
html[data-host-desktop="macos"]insrc/index.scsspaints only a 15% tint). Two things covered it during boot:apply_window_background_colortoggled_setDrawsBackground:on theWKWebView but never pinned
underPageBackgroundColor. WebKit derives thatcolour from the document, and before the first document has painted there
is nothing to derive from, so it falls back to white — for the entire
cold boot of that window's webview, since each Tauri window re-parses and
re-executes the bundle.
public/index.html's splash plate,html, body, #root { background: var(--splash-bg) }. On a light theme that resolves to#ffffff, andsecondary windows suppress the splash mark, so it was a bare white
rectangle over the vibrancy.
On Windows and Linux the secondary window is opaque (
transparent(true)inopen_session_windowis macOS-only), and its startup backdrop was a hardcoded#0d0d0d. On a light theme that opened the window dark, then the splash platerepainted it white, then the app painted — two flashes, neither the app's
colour.
Separately, the window was built
visible(true), so the frames betweenbuild()and the post-build chrome reached the screen as the leadingtransparent state.
Solution
The pre-paint surface should be whatever the window settles on, so there is no
seam to see.
set_webview_background_recursive(wasset_draws_background_recursive) nowpins
underPageBackgroundColoralongside_setDrawsBackground:, so thewebview paints the intended colour instead of its white default, and the
setting survives the navigation that re-derives it. Public API from macOS 12
and the bundle targets 10.15, so it is probed with
respondsToSelector:.It also returns whether a WKWebView was actually found, and both callers warn
when it was not — the previous version failed silently, which is exactly the
case that is indistinguishable from a working fix.
open_session_windowno longer callsapply_window_background_color(rightfor the main window, which settles opaque; wrong here). It mounts the
vibrancy material and clears the builder backdrop, so the webview composites
onto the material from its first frame.
public/index.htmlskips the splashplate for macOS secondary windows to match, scoped to
[data-host-desktop="macos"][data-orgii-secondary-window]so opaque hostsand the main window keep it.
New
startup_backdrop.rsresolves the opaque backdrop fromgeneral.themeand matches
--splash-bgexactly (#ffffff/#141414), mirroringnormalizeGlobalThemePreference+LEGACY_THEME_ALIASESfromglobalThemes.tsand falling back to the OS theme forsystem, absent, andunrecognised values.
The window is built hidden and shown once its chrome is applied. The
show()stays synchronous with creation, not deferred to the frontend's first
paint — deferring it would make the click that opens the window feel dead.
Updated the Team Inbox test harness to preserve the real Git-remotes module exports while overriding only
getGitRemotes; this prevents the PR import graph from exposing a stale full-module mock during full-suite collection.Potential risks
The macOS half is diagnosed by elimination, not yet observed working. An
earlier iteration of this change (the CSS plate plus dropping
apply_window_background_color) shipped to a local dev build and the flashpersisted, which is what identified
underPageBackgroundColoras theremaining white source: the NSWindow was
clearColor, the vibrancy is darkon a dark system appearance, and the page was proven transparent. The
underPageBackgroundColorfix itself has not been run — see Verification.underPageBackgroundColoris macOS 12+. On 10.15/11 therespondsToSelector:probe skips it and those hosts keep the old behaviour, including the white
base. No crash, no regression, but no fix there either.
If
apply_macos_window_materialever fails, the boot window is nowsee-through to the desktop where it previously showed a plate. The same
failure already shows through after first paint, since the macOS rule paints
only a 15% tint, so this widens an existing failure mode rather than adding
one.
app_windownow depends on thesettingscrate: one JSONC read per detachedwindow open (a user gesture, not a hot path).
read_settings()creates thesettings file with
{}when absent, so a window open can now create it. Thedependency is acyclic —
settingspulls onlyapp_paths+tauri.A non-baseline skin overrides
--splash-bgfromlocalStorage["orgii_skin_surface"], derived byderiveSkinTokensin TS.Nothing derives those tokens outside the bundle, so a skinned app gets
ORGII's base surface as its backdrop. Light/dark polarity is still correct,
which is what removes the flash; matching the exact skin surface would mean
duplicating the skin registry in Rust.
The Windows/Linux backdrop change is reasoned from the shared code path and
covered by unit tests, but has not been run on either platform.
The main window is untouched.
apply_window_background_colorstill uses afixed
#0d0d0dforrecreate_main_window, andtauri.conf.json'sbackgroundColoris static, so a light-theme macOS cold start still opens ona dark frame. Same defect class, different window, left for its own change.
The CI repair changes only a Vitest mock boundary; production code and runtime behavior are unaffected.
Verification
GitHub Actions CI run 33753170543 → frontend, Rust clippy/workspace tests, and cargo audit passed
../../../node_modules/.bin/vitest run --config config/vitest.config.ts src/modules/MainApp/TeamInbox/__tests__/AssignedWorkItemDetail.test.ts --reporter=verbose→ 9/9 passed, 0 failed../../../node_modules/.bin/eslint src/modules/MainApp/TeamInbox/__tests__/AssignedWorkItemDetail.test.ts --max-warnings 0 --report-unused-disable-directives→ clean../../../node_modules/.bin/tsgo --noEmit --pretty false→ cleannode scripts/quality/check-test-placement.mjs→ consistent across 457 directoriesRan:
cargo test -p app_window— 6 passed (3 pre-existing + 3 new theme-resolutiontests covering current ids, every legacy alias, and the follow-the-OS
fallbacks).
cargo check -p app_window— clean.cargo fmt -p app_window -- --check— clean.npx vitest run src/app/root/__tests__/secondaryWindowStartupSurface.test.ts— 8 passed. Mutation-checked: removing the CSS override fails 4 of the 8, so
the guard is not vacuous.
pnpm typecheck:fast(tsgo) — clean.pnpm run check:test-placement— clean across 458 directories.prettier --check,oxlint,eslint --max-warnings 0on the changed TS —clean.
served
index.html, dropped the bundle scripts, setdata-host-desktop="macos"+data-orgii-secondary-window, and read computedstyles.
--splash-bgresolves to#ffffffwhilehtml,body,#rootand#splashare allrgba(0, 0, 0, 0)— the override wins and the page paintsnothing.
Did not run:
tauri devstack was stopped before theunderPageBackgroundColorchange was built, so the macOS fix has never beenexercised at runtime. The prior iteration was confirmed live (dev binary
rebuilt before the retest) and did not fix the flash; this one is untested.
Needs a run on macOS with a light app theme, opening a detached session
window, before it can be called fixed.
git commit-treefrom atemp index because the checkout holds a concurrent session's unrelated work,
so no hook ran and there is no
Pre-commit hook ran.trailer. The checks itwould have run (typecheck, oxlint, eslint, prettier) were run manually and
are listed above.
No screenshots: the change is a sub-second pre-paint transient, and since the
fix is not yet confirmed working there is no correct-state frame to capture.
🤖 Generated with Claude Code