Add "splash screen" to hide the slow loading of the app - #631
Add "splash screen" to hide the slow loading of the app#631Juanpe Bolívar (arximboldi) wants to merge 3 commits into
Conversation
The window is shown as soon as it is built, so the seconds spent hydrating the ViewModel and running the launch probes read as an empty pane. SplashScreen fills it with the mascot, the wordmark, and a label naming the probe in flight. Deliberately the CSS-3D cube rather than <NixmacMascot3D>: three.js must stay out of the main bundle, since it would add to the very startup cost this screen exists to cover. Its styling lives in a plain-CSS splash.css rather than Tailwind utilities so that the pre-React boot splash can share it verbatim.
Replaces the neutral empty container the widget held before hydration, and reports which launch probe is running as the mount effect walks them.
SplashScreen can only paint once the bundle has loaded and parsed, which is itself part of the wait. index.html now carries the same markup inside #root, styled by the same splash.css and gated on the same 400ms delay, with icon.svg standing in for the animated mascot. React clears #root on its first commit, so the handover costs nothing: the mark simply starts hopping.
🎨 Storybook previewUpdated for e1a4c1c 🧭 Story changesCompared to 🆕 New stories (2)
|
📋 PR Overview
🔬 Coverage
|
| Storybook stories need. | ||
| */ | ||
|
|
||
| .nixmac-splash { |
There was a problem hiding this comment.
I would consider just leaving all these nixmac- prefixes out, they add a bit of verbosity for probably not a lot of gain when we already have the splash part.
darkmatteragent
left a comment
There was a problem hiding this comment.
Review — COMMENT
e1a4c1ca3449 · 3 findings
Comment: the React handoff restarts the splash fade on normal slow boots, while the new CSS also degrades on the declared macOS floor.
Findings
Warning
major · correctness — Clamping elapsed delay resets the splash at handoff
apps/native/src/components/widget/layout/splash-screen.tsx:60
The static copy in index.html starts nixmac-splash-in after 400ms and fades for 500ms. When React replaces it after that threshold, this Math.max(0, ...) clamp forces the replacement animation to start at opacity 0. For example, a handoff at 600ms replaces a partially visible splash with a transparent element and replays the full fade; after 900ms it blanks an already opaque splash for anoth
Warning
major · compatibility — Splash layout breaks on the declared macOS minimum
apps/native/src/components/widget/layout/splash.css:23
The app declares macOS 10.13 as its minimum, whose Safari-era WKWebView predates the inset shorthand, so this is ignored and the absolutely positioned splash has no full-window offsets. The same new stylesheet's only backdrop, background: color-mix(in oklch, ...) at line 31, is also unsupported there. During the pre-bundle interval this can leave the splash content-sized with no backdrop; its
Important
minor · correctness — Stage-label fade animation is a no-op
apps/native/src/components/widget/layout/splash.css:103
.nixmac-splash__stage has no opacity declaration, so its underlying opacity is 1. The applied animation ends at opacity: 1 (line 108), and nixmac-splash-in has no explicit from keyframe; each keyed remount therefore animates 1→1 instead of fading in as the component comment claims. Add opacity: 0 to the stage rule or an explicit from { opacity: 0; } keyframe.
| // in, this one must appear at once rather than restart the countdown. Frozen | ||
| // on first render — re-resolving `animation-delay` restarts the fade, and this | ||
| // component re-renders on every stage change. | ||
| const [delayMs] = useState(() => Math.max(0, appearDelayMs - performance.now())); |
There was a problem hiding this comment.
[major] Clamping elapsed delay resets the splash at handoff
The static copy in index.html starts nixmac-splash-in after 400ms and fades for 500ms. When React replaces it after that threshold, this Math.max(0, ...) clamp forces the replacement animation to start at opacity 0. For example, a handoff at 600ms replaces a partially visible splash with a transparent element and replays the full fade; after 900ms it blanks an already opaque splash for another 500ms. Preserve the negative delay (appearDelayMs - performance.now()) so CSS starts the replacement at the elapsed animation progress.
|
|
||
| .nixmac-splash { | ||
| position: absolute; | ||
| inset: 0; |
There was a problem hiding this comment.
[major] Splash layout breaks on the declared macOS minimum
The app declares macOS 10.13 as its minimum, whose Safari-era WKWebView predates the inset shorthand, so this is ignored and the absolutely positioned splash has no full-window offsets. The same new stylesheet's only backdrop, background: color-mix(in oklch, ...) at line 31, is also unsupported there. During the pre-bundle interval this can leave the splash content-sized with no backdrop; its #fafafa text fallback then renders against the default white page. Add top/right/bottom/left and broadly supported background fallbacks, or raise the platform floor.
| text-transform: uppercase; | ||
| letter-spacing: -0.01em; | ||
| color: var(--muted-foreground, #a1a1aa); | ||
| animation: nixmac-splash-in 300ms ease-out both; |
There was a problem hiding this comment.
[minor] Stage-label fade animation is a no-op
.nixmac-splash__stage has no opacity declaration, so its underlying opacity is 1. The applied animation ends at opacity: 1 (line 108), and nixmac-splash-in has no explicit from keyframe; each keyed remount therefore animates 1→1 instead of fading in as the component comment claims. Add opacity: 0 to the stage rule or an explicit from { opacity: 0; } keyframe.
Warning major · correctness — Clamping elapsed delay resets the splash at handoff The static copy in Warning major · compatibility — Splash layout breaks on the declared macOS minimum The app declares macOS 10.13 as its minimum, whose Safari-era WKWebView predates the Important minor · correctness — Stage-label fade animation is a no-op
reviewed: e1a4c1c — 2026-08-29T07:57Z verdict: comment findings: 3
Run details
|
||||||||||||||||||||||||||||

Summary
The app has grown a bit slow to load. Nothing too terrible but it freezes blank for a couple of seconds. This hides this with some nice animation to increase the subjective perception of fluidity.
Test Plan
Docs