Skip to content

fix(ui): delay-gate the startup splash so it never flashes on fast cached boots - #11885

Merged
lalalune merged 1 commit into
elizaOS:developfrom
roninjin10:fix/startup-splash-flash-delay
Jul 3, 2026
Merged

fix(ui): delay-gate the startup splash so it never flashes on fast cached boots#11885
lalalune merged 1 commit into
elizaOS:developfrom
roninjin10:fix/startup-splash-flash-delay

Conversation

@roninjin10

Copy link
Copy Markdown
Contributor

Problem

Closes #11883.

On a warm/cached load — where the app boots almost instantly — the full-screen elizaOS booting/splash screen flashes for a fraction of a second and is immediately ripped away. It's a jarring flash on every fast (2nd) load. The splash should only appear when the app does not load right away.

Root cause

packages/ui/src/components/shell/StartupShell.tsx returned the full-screen orange StartupLoading splash immediately whenever view.kind === "loading" (the fall-through after the error / pairing / bootstrap / none branches). A fast cached boot transitions loading → none within a few milliseconds, so the splash painted for those few ms and then unmounted → flash.

Fix

Gate only the loading splash behind a short delay, STARTUP_SPLASH_DELAY_MS = 220:

  • useDelayElapsed(active, delayMs) returns true only after the loading state has persisted continuously for the threshold, and resets to false the instant loading ends. The timer lives in a useEffect (setTimeout, cleared on unmount / when the view kind changes) — no render-time clock/timer, so audit:ui-determinism stays green.
  • If the view becomes ready (transitions away from loading) before the threshold, the splash never renders — the flash is eliminated.
  • error, pairing, and bootstrap views still render immediately (they are terminal/interactive, not fast-flash cases).
  • The startup-shell:first-paint telemetry mark now fires when visible startup UI actually paints — the immediate views, or the splash once its gate opens — and never on a null-rendering mount. Existing dedupe-by-name behavior is preserved.
  • StartupLoading's markup, data-testid="startup-shell-loading", data-startup-phase, and roles are unchanged — only when it appears changed.

Evidence

Primary proof is a new co-located unit test (StartupShell.test.tsx, vitest + jsdom, fake timers), 8 cases:

  • splash is absent before the threshold (and no first-paint mark);
  • splash appears exactly once the threshold is crossed (markup/role/phase preserved; first-paint mark fires);
  • splash never renders when the view flips to none before the threshold (fast cached boot — no mark);
  • a fast flicker loading → none → loading restarts the timer and only paints after a fresh full threshold;
  • error / pairing / bootstrap render immediately and mark first-paint; none renders nothing and marks nothing.

Verification run in this branch:

  • bun run --cwd packages/ui typecheck — pass
  • bunx @biomejs/biome check on both changed files — pass (clean)
  • bunx vitest run src/components/shell/StartupShell.test.tsx — 8/8 pass
  • bunx vitest run src/components/shell/ — 36 files, 624 pass / 7 skipped (no regressions in the shell suite, incl. the existing StartupFailureView test)
  • bun run audit:ui-determinism — StartupShell is not flagged (0 occurrences); this change adds no render-time nondeterminism. (The audit's pre-existing failures are all in unrelated cloud/ files with a stale baseline on develop.)

Timing behavior, before → after: on a fast cached boot the splash used to paint for a few ms then vanish (flash); now it never mounts. On a genuinely slow boot the splash still appears (220ms later) and stays until the app is ready, exactly as before.

N/A rows: real-LLM trajectories, backend logs, audio — N/A (pure client-side render-timing change; no agent/model/prompt/voice behavior touched). Screenshots/video — the flash is a sub-frame timing artifact best proven by the fake-timer unit test above; there is no steady-state visual change to the splash itself.

🤖 Generated with Claude Code

…ched boots

On a warm/cached load the app boots almost instantly, so the view transitions
loading -> none within a few milliseconds. StartupShell returned the full-screen
orange StartupLoading splash immediately for the "loading" kind, so those few ms
painted the splash and then ripped it away — a jarring flash.

Gate the loading splash behind STARTUP_SPLASH_DELAY_MS (220ms): render it only
once the loading state has persisted past the threshold. A boot that becomes
ready first never paints it. Error / pairing / bootstrap views stay immediate.

The delay uses an effect-based timer (useState + useEffect + setTimeout, cleared
on unmount / view-kind change) so no render-time clock/timer is introduced and
the audit:ui-determinism gate stays green. The startup-shell:first-paint mark now
fires only when visible startup UI actually paints (immediate views, or the
splash once its gate opens) — never on a null-rendering mount — preserving the
dedupe-by-name behavior. StartupLoading markup/roles/test ids are unchanged.

Closes elizaOS#11883

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

An error occurred during the review process. Please try again later.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@lalalune
lalalune merged commit 65e3f41 into elizaOS:develop Jul 3, 2026
3 checks passed
lalalune pushed a commit that referenced this pull request Jul 3, 2026
lalalune pushed a commit that referenced this pull request Jul 3, 2026
…tartup-shell:mounted mark keeps boot-trace harness reachable (#11885 review fixes)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the ui label Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Startup splash flashes on fast (cached) boots

2 participants