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/playerStorefor bootstrap status, loading flag, bootstrap error, welcome-modal visibility, recovery-toast state, and theinit/enterOfflineMode/dismissRecoveryToastactions.metagame/stores/sessionStorefor selected ship and run-def state (beta entry, dev-keys quick-launch).metagame/services/assembleRunServiceto build a run-def from current selections.metagame/services/featureFlagsfor kill-switch hydration.metagame/services/analyticsfor the event tracker and the sync-flush used at unload.metagame/components/RewardOrchestrator,RewardPopup,WelcomeModal,FeedbackFAB,UpdateBannerfor shell-level UI fixtures.engine/telemetryfor session start/end, queue flush, partial-run-on-unload, and the sampler session setter.engine/core/remote-errorsto wire crash reporting to the analytics tracker.engine/core/preloadfor asset preload with a progress callback.engine/core/configfor build version display and the perftest flag.engine/core/statefor the debug-overlay setter / getter consumed by the dev-keys toggle.- All metagame screen components mounted as route elements.
react-router-domforBrowserRouter, route primitives, redirects, and the navigation hooks consumed by the perftest redirect and dev-keys.window.location.pathnamefor the pre-router nebula-viewer bypass check.- DOM queries (
data-testidselectors 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-domhistory (navigatefor perftest redirect and dev-keys chords).windowevent listeners (beforeunload/pagehidefor the unload handler,keydownfor 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
assembleRunDefwith 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 globalkeydownlistener 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 bydata-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
loadingor!bootstrappedor 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 againstwindow.locationbefore 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.