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-codedRecord<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 inSCENARIO_META.DevHomepagedefault-exported React component.- Computes
scenariosvialistScenarios(). - Buckets scenarios into
groupskeyed bymeta.group. - Applies a fixed display order
['Artifacts', 'Combat', 'Misc', 'Other'], appending any unrecognized groups at the end. launch(name, tier?)inner function that setswindow.location.hrefto the play URL withdevand optionaltierquery params.
- Computes
- 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). LEGENDARYbutton on Artifacts cards that callslaunch(name, 3)withstopPropagation.
READS FROM
../testing/dev-scenarios— importslistScenarios()to enumerate registered scenarios at render time.window.location— read/write for navigation (launchsetshref).
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.locationassignment. - 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=3is 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=3appended;e.stopPropagation()prevents the parent card click from also firing. onMouseEnter/onMouseLeaveon each card → direct style mutation oncurrentTarget(border color promotes to fullmeta.color, background to#1a2540; reverts on leave).- Click on
Performance Dashboardanchor → browser navigates to/dev/analytics. - Click on
Weapon Workbenchanchor → browser navigates to/weapon-workbench.
Entry points
- Default export
DevHomepage— React component, no props. Mounted at the/devroute by the metagame shell. - Module side effects: none; only the
SCENARIO_METAconstant andgetFallbackMetafunction 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 fromSCENARIO_METArenders withgetFallbackMetadefaults rather than throwing. - Group labels are prefixed with literal emoji characters in the rendered heading (Artifacts, Combat, and the default
Misc/Otherfallback) — 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.hrefassignment 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.