PURPOSE

Root React component for the metagame shell. Boots telemetry, remote error reporting, feature flags, player auth/bootstrap, and asset preload before rendering the app under BrowserRouter. Renders a themed loading screen with progress bar and a connection-error retry/offline-mode panel until bootstrap and asset preload complete.

OWNS

  • App — root component, runs boot orchestration in a single useEffect keyed on init.
  • PerfTestRedirect — internal component mounted inside BrowserRouter that navigates to /games/starship-survivors/play when PERF_FLAGS.perftest is set.
  • ConnectedToast — internal floating toast shown when the offline-mode recovery loop re-establishes the Supabase connection. Auto-dismisses after 3 seconds.
  • Local UI state: assetsReady (boolean), preloadPct (0..1), preloadStarted (ref guard preventing double-preload).
  • Loading-screen markup, error/offline panel, version stamp (BUILD_VERSION), and spinner/progress-bar CSS keyframes (sp-spin, sp-pulse).
  • beforeunload / pagehide window listeners and their cleanup.

READS FROM

  • usePlayerStore selectors: bootstrapped, loading, bootstrapError, showWelcome, init, enterOfflineMode, recoveryToast, dismissRecoveryToast.
  • @starship-survivors/engine/core/configBUILD_VERSION, PERF_FLAGS.
  • window.location.pathname for the nebula-viewer bypass (/nebula-viewer).
  • useNavigate / useLocation from react-router-dom (used inside PerfTestRedirect).

PUSHES TO

  • startTelemetrySession, flushTelemetryQueue, endTelemetrySession, sendPartialRunOnUnload, Sampler.setSession (from @starship-survivors/engine/telemetry).
  • initRemoteErrors(trackEvent) (from @starship-survivors/engine/core/remote-errors).
  • hydrateFeatureFlags (from ../services/featureFlags).
  • preloadAllAssets with a progress callback (from @starship-survivors/engine/core/preload).
  • init() / enterOfflineMode() / dismissRecoveryToast() on usePlayerStore.
  • flushAnalyticsSync on the unload handler.
  • DOM: registers beforeunload and pagehide listeners on window.

DOES NOT

  • Does not implement auth, bootstrap RPC, store hydration, or wallet/inventory logic — that lives in playerStore.init.
  • Does not define routes — that is delegated to Routes from ./routes wrapped in Layout from ./Layout.
  • Does not render any in-game canvas or HUD; only the metagame shell, modals (WelcomeModal), FAB (FeedbackFAB), banner (UpdateBanner), and recovery toast.
  • Does not block the nebula viewer route on bootstrap — /nebula-viewer bypasses the loading gate.
  • Does not retry telemetry or feature-flag hydration on failure (fire-and-forget).
  • Does not amend or persist user state on unload — only flushes telemetry/analytics and ends the telemetry session.

Signals

  • loading || !bootstrapped || !assetsReady (with !isNebulaViewer) → renders the loading screen with spinner + progress bar.
  • bootstrapError truthy → swaps spinner for a CONNECTION ERROR panel with RETRY and PLAY OFFLINE buttons.
  • showWelcome true → renders <WelcomeModal /> inside the router.
  • recoveryToast true → renders <ConnectedToast onDone={dismissRecoveryToast} />.
  • PERF_FLAGS.perftest true → mounts <PerfTestRedirect />, which calls navigate('/games/starship-survivors/play', { replace: true }) if not already there.
  • preloadAllAssets progress callback drives the loading-screen progress bar via setPreloadPct.

Entry points

  • Default export: none. Named export App is the metagame entry consumed by the metagame bundle entry point.
  • PerfTestRedirect and ConnectedToast are file-local and not exported.

Pattern notes

  • Single boot useEffect with init in the dependency array; preloadStarted ref prevents the asset preload from running twice on effect re-run.
  • Telemetry, remote errors, feature flags, and player init are kicked off in parallel; only player bootstrap (init) and asset preload gate the render. Telemetry/remote-errors/feature-flags are fire-and-forget.
  • BrowserRouter is mounted only after bootstrap and asset preload succeed, so routing hooks are never invoked during the loading state.
  • Unload handler uses sendPartialRunOnUnload, flushAnalyticsSync, and endTelemetrySession — the sync variants — so the browser does not cancel the requests during teardown. Registered on both beforeunload and pagehide.
  • Nebula viewer (/nebula-viewer) is a deliberate bypass: it reads archetype data only and does not require an authenticated player or hydrated stores.
  • Error panel offers two recovery paths: init() retry and enterOfflineMode(). Offline mode is documented inline as “skips cloud save.”
  • Provider topology is minimal: BrowserRouter wraps Layout wraps Routes. There is no Context provider tree above the router; global state is Zustand stores accessed directly.
  • Inline CSS keyframes are injected via a <style> tag inside the loading subtree rather than a global stylesheet.
  • ConnectedToast uses a fixed-position floating div with pointerEvents: 'none' and zIndex: 9999; auto-dismiss is a single setTimeout(onDone, 3000) with cleanup.