metagame/app

PURPOSE — The React app shell: boots the player session (telemetry, remote errors, feature flags, asset preload, auth + bootstrap RPC + store hydration), gates rendering on bootstrap completion, mounts the router and route table, wraps every screen in a fixed-height layout with FX overlay stack, and installs the global dev-keys keyboard navigator.

OWNS

  • The boot lifecycle: telemetry session start, queued-run flush, sampler session-id forwarding, remote-error init, feature-flag hydrate, player-store init, asset preload progress, unload-time partial-run flush.
  • Bootstrap render-gate state: a loading-screen branch (animated spinner, progress bar, build version stamp) and an error branch (retry / play-offline buttons, error message).
  • The nebula-viewer bypass (server-free entry that skips bootstrap entirely).
  • The post-bootstrap shell: BrowserRouter, perftest-redirect mount, Layout, route table, welcome modal gate, feedback FAB, update banner, and a transient “connected” toast for offline-recovery.
  • The FX overlay stack mounted above all app content (dim, flash, particle canvas, floating clones, milestone chips), with fixed inset and ascending z-indices, pointer-events disabled by default.
  • Dev-route overflow toggle for the main content area (scrollable for dev dashboards, hidden for game/metagame).
  • The route table: hub, shop, profile, admin, unified ships screen, level select, mission board, gameplay screen, beta auto-launch entry, reveal, ship pull, run stats, prologue, dev tools (homepage, boss test, perf dashboard, perf benchmark, nebula viewer, backgrounds viewer, ship playground, weapon workbench), and legacy-path redirects.
  • The beta entry wrapper that lazily assembles a default run-def before mounting the gameplay screen.
  • The global dev-keys keyboard handler: navigation chords (hub / shop / collection / profile / admin / levels / ship playground / reveal), quick-launch run assembly, debug overlay toggle, and context-sensitive shop-pull / collection-tab actions resolved via DOM lookup.

READS FROM

  • metagame/stores/playerStore for bootstrap status, loading flag, bootstrap error, welcome-modal visibility, recovery-toast state, and the init / enterOfflineMode / dismissRecoveryToast actions.
  • metagame/stores/sessionStore for selected ship and run-def state (beta entry, dev-keys quick-launch).
  • metagame/services/assembleRunService to build a run-def from current selections.
  • metagame/services/featureFlags for kill-switch hydration.
  • metagame/services/analytics for the event tracker and the sync-flush used at unload.
  • metagame/components/RewardOrchestrator, RewardPopup, WelcomeModal, FeedbackFAB, UpdateBanner for shell-level UI fixtures.
  • engine/telemetry for session start/end, queue flush, partial-run-on-unload, and the sampler session setter.
  • engine/core/remote-errors to wire crash reporting to the analytics tracker.
  • engine/core/preload for asset preload with a progress callback.
  • engine/core/config for build version display and the perftest flag.
  • engine/core/state for the debug-overlay setter / getter consumed by the dev-keys toggle.
  • All metagame screen components mounted as route elements.
  • react-router-dom for BrowserRouter, route primitives, redirects, and the navigation hooks consumed by the perftest redirect and dev-keys.
  • window.location.pathname for the pre-router nebula-viewer bypass check.
  • DOM queries (data-testid selectors and button text content) for the context-sensitive shop-pull shortcuts.

PUSHES TO

  • engine/telemetry (session start / end, queue flush, partial-run on unload, sampler session id).
  • engine/core/remote-errors (init with the analytics tracker as the sink).
  • engine/core/preload (kicks off asset preload, receives progress).
  • engine/core/state (debug-overlay toggle).
  • metagame/stores/playerStore (init, enterOfflineMode, dismissRecoveryToast).
  • metagame/stores/sessionStore (setRunDef).
  • metagame/services/analytics (sync-flush on unload).
  • metagame/services/featureFlags (hydrate at boot).
  • react-router-dom history (navigate for perftest redirect and dev-keys chords).
  • window event listeners (beforeunload / pagehide for the unload handler, keydown for dev-keys).
  • DOM (click dispatched on resolved shop-pull buttons).

DOES NOT

  • Authenticate, talk to Supabase, or run the bootstrap RPC directly — it only calls the store action and renders against the resulting flags.
  • Decide what loads during asset preload, what counts as a remote error, or what events the analytics tracker forwards — those policies live in their owning modules.
  • Render the hub, shop, ships, gameplay, reveal, run-stats, profile, admin, or any other route content — only mounts the route table and the shell chrome around it.
  • Run the game loop, draw the canvas, tick the engine clock, or touch any per-frame engine state.
  • Implement the reward pipeline, welcome flow, feedback capture, or update-banner logic — only mounts those components into the shell.
  • Define routes’ per-screen chrome (V32 shell, bottom bars, etc.) — every screen renders its own.
  • Compose the run-def: dev-keys and the beta entry only call assembleRunDef with current selections and write the result to the session store.
  • Filter or rebind dev-keys per route beyond a pathname check on the shop and collection action shortcuts — the keydown handler is global once mounted.
  • Persist any state on its own — all durable state lives in the player / session stores it consumes.

Signals fired / Signals watched — none. The shell talks to other systems by direct calls (stores, services, engine telemetry / preload / remote errors) and DOM events (beforeunload, pagehide, keydown); it does not emit or subscribe to engine signals.

Entry points

  • App — root component; runs the boot effect, renders the bootstrap render-gate (loading / error) or the routed shell.
  • PerfTestRedirect — mounted under the router when the perftest config flag is set; navigates to the gameplay route once on mount and renders nothing.
  • ConnectedToast — transient overlay shown when offline-recovery reconnects; auto-dismisses after a fixed delay.
  • Layout — shell wrapper for every routed screen; mounts dev-keys, the FX overlay stack, the reward orchestrator, the main content area (with dev-route overflow toggle), and the reward popup.
  • FxLayers — internal helper that paints the five fixed-position FX layers (dim, flash, particle canvas, floating clones, chips) in ascending z-order.
  • Routes — the route table; binds every public, internal, and dev path to its screen component and installs legacy-path redirects + a catch-all to home.
  • BetaGameScreen — internal route element that ensures a run-def exists (assembling a default one if absent) before rendering the gameplay screen.
  • DevKeys — side-effect-only component that installs the global keydown listener for Ctrl+Shift navigation and action chords; renders nothing.
  • _clickButton — internal helper used by the dev-keys action chords to resolve a target button (first by data-testid / selector, then by text content) and dispatch a click.

Pattern notes

  • The shell is a flat composition rather than a registry: routes, FX layers, shell fixtures (welcome / feedback / update banner / recovery toast), and dev-keys chords are listed inline. Adding a route or a chord is a direct edit to the corresponding component.
  • Bootstrap is a render-gate: the same component renders a loading / error screen while the player store reports loading or !bootstrapped or assets are still preloading, then swaps to the routed shell once all three conditions clear. The nebula-viewer pathname is the only bypass and is checked against window.location before the router mounts.
  • Unload teardown runs the partial-run flush, the sync analytics flush, and the telemetry session end together so the browser’s pre-teardown beacons are not cancelled.
  • The perftest redirect is mounted inside the router (it needs the routing hooks) and gated by a config flag rather than a URL query inspection.
  • The FX layers are a fixed stack with hardcoded ascending z-indices and disabled pointer events by default; the reward orchestrator is responsible for selectively re-enabling them.
  • Dev-keys are a single switch statement keyed on the uppercased key with a Ctrl+Shift guard; number-key action shortcuts gate themselves on the current pathname and resolve their target via a DOM lookup helper rather than wiring directly to store actions.
  • The beta route is the only entry that mutates the session store inside a route element’s render path; every other dev or play entry expects the run-def to be set upstream.