Dev Keyboard Shortcuts

Global keyboard shortcuts for dev and automation navigation, defined in src/metagame/app/DevKeys.tsx. All shortcuts use the Ctrl+Shift+<key> chord to avoid collision with in-game input. Every match calls preventDefault() on the keydown event.

DevKeys is a side-effect-only React component — it renders null. It must be mounted inside the BrowserRouter because it depends on useNavigate and useLocation from react-router-dom. A single window keydown listener is registered on mount and removed on unmount.

Shortcut catalog

17 active shortcuts across three groups.

Always-on. Fired regardless of which route is currently active.

ChordAction
Ctrl+Shift+HNavigate to hub (/)
Ctrl+Shift+LQuick-launch: assemble a RunDef from the current selectedShipId in sessionStore, set it, then navigate to /games/starship-survivors/play
Ctrl+Shift+SNavigate to shop (/shop)
Ctrl+Shift+CNavigate to collection (/collection)
Ctrl+Shift+PNavigate to profile (/profile)
Ctrl+Shift+ANavigate to admin (/admin)
Ctrl+Shift+VNavigate to level select (/games/starship-survivors/levels)
Ctrl+Shift+TNavigate to weapon test playground (/ship-playground)
Ctrl+Shift+RNavigate to reward reveal (/games/starship-survivors/reveal)
Ctrl+Shift+DToggle the debug overlay flag in engine/core/state

Shop pulls (4)

Only active when location.pathname === '/shop'. Each tries a data-testid selector first and falls back to scanning all <button> elements for matching text content.

ChordAction
Ctrl+Shift+1Solar Legion x1 pull (selector [data-testid="pull-1-solar"], text fallback x1, index 0)
Ctrl+Shift+2Solar Legion x10 pull (selector [data-testid="pull-10-solar"], text fallback x10, index 0)
Ctrl+Shift+3Freebooters x1 pull (selector [data-testid="pull-1-free"], text fallback x1, index 1)
Ctrl+Shift+4Freebooters x10 pull (selector [data-testid="pull-10-free"], text fallback x10, index 1)

Collection tabs (2)

Only active when location.pathname starts with /collection.

ChordAction
Ctrl+Shift+5Navigate to /collection?tab=ships
Ctrl+Shift+6Navigate to /collection (default tab)

Implementation notes

  • e.key.toUpperCase() is matched, so both unshifted digits (1-6) and their shifted symbol counterparts (!, @, #, $, %, ^) hit the same case branches.
  • The handler short-circuits at the top if either ctrlKey or shiftKey is not held. Everything else falls through switch (key) without a default, so non-bound chords pass through untouched.
  • Ctrl+Shift+E is intentionally removed — the dedicated settings screen was deleted and settings now live in the in-game cog menu. A comment in the source records the deprecation.
  • Ctrl+Shift+7 is documented in the file header for an achievements tab, but no case '7' exists in the switch — it is a header-only entry.
  • The _clickButton helper takes (selector, textMatch, nthMatch). CSS selector is tried first via querySelectorAll; if there are not enough matches, it scans every <button> on the page and clicks the nthMatch-th element whose textContent (lower-cased) contains textMatch (lower-cased).
  • The useEffect dependency array is [navigate, location.pathname], so the listener re-binds on every route change. Context-sensitive shortcuts always see a fresh path.

Intended use

These chords let Claude or any developer drive the full game UI from the browser console or automation tooling without clicking through menus. The data-testid selectors are the stable contract; the text-content fallbacks exist so the helper still works on buttons that have not yet been tagged.