PURPOSE
Shared metagame chrome for the React shell. Wraps a child stage with a fixed 70px top bar (account pill + build-version stamp + live currency display) and an 80px bottom tab nav, on a medical-UI panel-recessed background. Every metagame screen renders fullscreen inside this shell; the shell provides the 70/80px chrome and a scrollable main stage flexed between them.
OWNS
V32Shell— named-export functional component rendering the shell layout.V32ShellProps— internal props interface (children: ReactNode, optionalhideChrome: boolean).- The
WARP_SVG_PATHconstant — inline path data for the warp-crystal currency icon. - The two inline SVG icon strings injected into the currency pills (warp crystal with
var(--warp-core)fill plus#fdf4ffstroke; credits coin as a layered yellow disc with#fbbf24outer ring,#78350fstroke,#fde68ainner disc). - The top-bar layout: account pill on the left, build-version stamp centered, currency pills on the right.
- The main-stage container with vh-clamped padding/gap (
clamp(8px, 1.8vh, 15px)/clamp(6px, 1.8vh, 15px)), vertical scrolling, hidden horizontal overflow, and momentum scrolling on iOS viaWebkitOverflowScrolling: 'touch'. - The chrome-hide behavior: top bar fades to
opacity: 0with pointer events disabled; bottom nav is unmounted entirely. - The wallet display-override resolution (frozen before-values during reward presentation take precedence over live store values).
- Anchor registration of the currency pills for fly-to animations.
READS FROM
react—ReactNodetype for children.react-router-dom—useNavigatefor the account-pill route push.@starship-survivors/engine/core/config—BUILD_VERSIONfor the centered version stamp.@starship-survivors/stores/walletStore— livegemsandcreditsselectors.@starship-survivors/stores/displayOverrideStore—walletOverridesmap selector (keyed by'gems'/'credits').@starship-survivors/services/anchor-registry—useAnchorfor thewallet-gemsandwallet-creditsanchor refs../BottomNav— the defaultBottomNavexport for the bottom tabs.../screens/shop/shop.css— imported for side-effect to apply the.sig-shopscoped styles, medical-UI overrides, top-bar styling, account-pill styling, currency-pill styling.- CSS custom properties consumed by the imported stylesheet:
--med-panel-raised,--med-panel-recessed,--med-border,--warp-core.
PUSHES TO
- React Router via
navigate('/profile')when the account pill is clicked. - The anchor registry, which receives DOM refs for the credits and gems currency pills under the keys
wallet-creditsandwallet-gems. - The DOM via
dangerouslySetInnerHTML— the currency pills are injected with a concatenation of the inline SVG icon string and the localized currency value.
DOES NOT
- Manage any component-local state — all dynamic values come from store selectors and prop input.
- Persist anything to stores, Supabase, or localStorage.
- Compute or mutate wallet values; only reads
walletStoreand the display-override layer. - Define the bottom tabs or their active-state logic — that belongs to
BottomNav. - Apply a separate fade animation to the bottom nav; the hide is a hard unmount of
BottomNavrather than an opacity transition. - Render the onboarding chrome-free layout —
OnboardingShellis a separate component. - Re-emit window events, signals, or telemetry.
- Re-implement the canvas/HUD or any in-game UI — purely React metagame chrome.
- Polyfill or guard against SVG injection beyond the trusted constant strings it constructs.
Signals
- Wallet selector reads cause re-renders on every
walletStoregems/credits change. - Display-override selector reads cause re-renders when
walletOverridesis set or cleared (used by reward presentation to freeze the before-value during the fly-to animation). - Anchor registry mount/unmount cycle registers and unregisters
wallet-gemsandwallet-creditsautomatically with theuseAnchorhook. - No window events, post-FX subscriptions, or signal-bus traffic.
Entry points
- Named export
V32Shellis consumed by the main metagame screens (hub, shop, ships, profile, collection, etc.) to wrap their content with the standard chrome. - The
hideChromeprop is used by callers mounting fullscreen overlays that need the chrome out of the way without unmounting the shell.
Pattern notes
- The CSS scope class is still named
.sig-shopeven though the component is shared across all metagame screens; the name is preserved per the file header to keep the scope key stable for ported V32 child markup. - The main stage is a
<div className="v32-main">rather than a<main>element, deliberately avoiding nested<main>elements when the shell is mounted insideLayout.tsx. - The display-override layer takes precedence with
walletOverrides?.get('gems') ?? liveGemsso reward-presentation flows can freeze the pre-reward value on screen while the gain animates. - Styling tokens follow ADR 20260513-001 (medical UI): top bar uses
var(--med-panel-raised)with a hairline border-bottom; currency pills usevar(--med-panel-recessed)plusvar(--med-border). - The build-version stamp is rendered inline-styled (not in shop.css) at 10px, 40% white opacity, 1px letter-spacing, centered between the account pill and the currencies.
- Currency icons are inlined via
dangerouslySetInnerHTMLrather than imported as React SVG components so the icon and the formatted number share the same flow inside the pill without extra wrapper nodes. hideChromeis asymmetric: the top bar stays mounted but invisible (so the anchor refs and CSS layout do not shift), while the bottom nav is fully unmounted.- The shell relies on its parent flex container providing height; the main stage uses
flex: 1withminHeight: 0to make the inner overflow scroll correctly under a Flexbox parent.