DevHomepage

PURPOSE

Dev-playground landing page rendered at /dev. Displays a grouped grid of all registered dev scenarios with launch buttons, plus shortcut links to the Performance Dashboard and Weapon Workbench. Navigates the browser to /games/starship-survivors/play?dev=<scenario> (optionally &tier=<n>) on click.

OWNS

  • SCENARIO_META: a hard-coded Record<string, { group, label, desc, color }> mapping scenario names to display metadata (group bucket, display label, short description, accent color).
  • getFallbackMeta(name): builds a default metadata record (group: 'Other', label = name, empty desc, neutral color) for scenarios not listed in SCENARIO_META.
  • DevHomepage default-exported React component.
    • Computes scenarios via listScenarios().
    • Buckets scenarios into groups keyed by meta.group.
    • Applies a fixed display order ['Artifacts', 'Combat', 'Misc', 'Other'], appending any unrecognized groups at the end.
    • launch(name, tier?) inner function that sets window.location.href to the play URL with dev and optional tier query params.
  • Inline-styled DOM tree: header, dev-tool link row (Performance Dashboard, Weapon Workbench), and per-group sections each containing a CSS-grid of scenario cards.
  • Per-card hover behavior (border + background swap via onMouseEnter / onMouseLeave).
  • Per-card click dispatch to launch(name).
  • LEGENDARY button on Artifacts cards that calls launch(name, 3) with stopPropagation.

READS FROM

  • ../testing/dev-scenarios — imports listScenarios() to enumerate registered scenarios at render time.
  • window.location — read/write for navigation (launch sets href).

PUSHES TO

  • Browser navigation (window.location.href) — sends the user to /games/starship-survivors/play?dev=<name>[&tier=<n>].
  • DOM event handlers mutate e.currentTarget.style (borderColor, background) for hover feedback.

DOES NOT

  • Does not import or touch the engine, game loop, ECS, or any gameplay state.
  • Does not call into Zustand stores or any global app state.
  • Does not register, define, or modify scenarios — only consumes listScenarios().
  • Does not route via a React router; navigation is a hard window.location assignment.
  • Does not perform network requests, persistence, telemetry, or Supabase/Sentry calls.
  • Does not read URL query params or persist user selections.
  • Does not validate that tier=3 is meaningful for the target scenario — it is appended unconditionally on the LEGENDARY button.
  • Has no props, no internal React state, and no effects.

Signals

  • Click on a scenario card launch(name) full-page navigation to /games/starship-survivors/play?dev=<name>.
  • Click on the LEGENDARY button (Artifacts group only) launch(name, 3) navigation with &tier=3 appended; e.stopPropagation() prevents the parent card click from also firing.
  • onMouseEnter / onMouseLeave on each card direct style mutation on currentTarget (border color promotes to full meta.color, background to #1a2540; reverts on leave).
  • Click on Performance Dashboard anchor browser navigates to /dev/analytics.
  • Click on Weapon Workbench anchor browser navigates to /weapon-workbench.

Entry points

  • Default export DevHomepage — React component, no props. Mounted at the /dev route by the metagame shell.
  • Module side effects: none; only the SCENARIO_META constant and getFallbackMeta function are evaluated at import time.

Pattern notes

  • All styling is inline; no CSS modules, Tailwind classes, or external stylesheet usage.
  • Group order is a hard-coded array (groupOrder); unrecognized groups fall through to a tail append loop so new buckets show up without crashing.
  • Scenario metadata is decoupled from scenario registration: a scenario registered via listScenarios() but missing from SCENARIO_META renders with getFallbackMeta defaults rather than throwing.
  • Group labels are prefixed with literal emoji characters in the rendered heading (Artifacts, Combat, and the default Misc/Other fallback) — these are inline JSX string literals, not from data.
  • The ?dev=<name> token is also rendered on each card as a monospace footer string, doubling as a copy-paste reference for manual URL construction.
  • Navigation is intentionally a window.location.href assignment rather than a router-managed transition — this guarantees a full reload into the game shell with the dev scenario query param parsed by the play route.
  • The component re-buckets and re-sorts groups on every render; cheap given the small fixed scenario count, no memoization applied.