Collection Screen (Ships Gallery)
The Ships screen is the player’s hull collection UI. It is the SHIPS sub-tab of ShipsScreen (screens/ShipsScreen.tsx); the ARTIFACTS sub-tab is a sibling surface, not part of this page.
Route: /games/starship-survivors/ships?tab=select (default tab). Deep-linked; URL stays in sync with the active sub-tab.
Layout
Two stacked regions inside screens/ships/SelectTab.tsx:
- Top — hero card (340px tall) showing the currently
selectedShipId. Live ship preview as full-bleed background, name, star bar, big-number stats (HP / SHIELD / SPEED), specialty slot, and weapon-slot circles glued to the bottom.(i)button in the top-right opensShipInfoPopoverwith the full stat sheet. - Bottom — inventory grid.
INVENTORYheader strip with aFILTERtoggle, followed by a scrollable grid ofCollectibleCardtiles, one per owned hull. Grid usesrepeat(auto-fill, minmax(108px, 1fr)).
Bottom-bar OverlayBottomBar carries BACK + SHIPS/ARTIFACTS sub-tabs.
Data source
The grid renders the player’s owned hulls only — no locked silhouettes are shown.
useInventoryStore(stores/inventoryStore.ts) holdsships: Record<string, ShipInstance>, keyed byhull_class. Each instance has{ shipId, xp }. Starter hulls (Industria_Towncar,Junkrats_Tank,Solaris_Cargo) are granted on fresh accounts viaresetToStarter.HULL_CLASSES.filter(h => !!ships[h])produces the visible list. Locked hulls do not appear; the inventory grid is owned-only.- Each card always passes
locked={false}. (TheCollectibleCardcomponent supports a locked silhouette state, butSelectTabnever invokes it — locked-state rendering lives in other surfaces such as the gacha-reveal flow.)
Grouping and sort
Hulls are NOT grouped by faction. The actual sort is a three-key descending order applied to all owned hulls:
- Rarity descending —
legendary → epic → rare → uncommon → common(rank map inSelectTab.tsx). - Star tier descending.
- XP descending (tiebreak within same rarity + star).
Effect: highest-rarity, highest-star hulls bubble to the top of the grid.
Star tier (1-5)
Per-hull star is derived from cumulative XP via starFromXp (data/ship-progression.ts). XP increments by 1 each duplicate pull through grantShipPull. First pull unlocks the hull at XP 0 (star 1). xpToNextStar drives the XP-bar fill on both the hero card and each CollectibleCard. Max star is 5; at 5 the bar pegs at 100%.
HullStarBar (components/HullStarBar.tsx) draws the gold star + slanted XP bar shared by the hero card and the inventory tiles.
Rarity badge
Each CollectibleCard shows a RarityBadge letter (legendary / epic / rare / uncommon / common) plus a colored frame. Rarity is the ship’s static def.rarity from getShipDef(hull, 1) — it does not change with star tier. The same rarity color drives the hero-card frame and glow, and is preserved per the ADR 20260513-001 exception inside the otherwise medical-token UI.
Filter
Press FILTER to open a panel above the grid with two filter rows:
- BY RARITY — multi-select pills for
LEGENDARY / EPIC / RARE / UNCOMMON / COMMON. - BY STAR — multi-select pills for
1★through5★.
Filter state lives in local React state (rarityFilter: Set<ShipRarity>, starFilter: Set<number>) inside SelectTab. Empty sets = no filter applied. A green count badge on the FILTER button shows the total number of active pills.
Empty result renders No ships match the current filter.
Selection — writes to sessionStore
Tapping a card calls setShip(hull) on useSessionStore (stores/sessionStore.ts):
- Writes
selectedShipIdin the session store. - Fires
update_player_saveRPC viapersistSelectionto cloud-save the choice (fire-and-forget; errors logged, not surfaced).
selectedShipId is consumed by:
- The hero card on the same screen (re-renders with new hull’s stats / preview / weapon slots).
LevelSelectand run-assembly screens, which readselectedShipIdwhen building theRunDefinition.- The in-run game loop via the run bridge, which uses the session’s ship choice as the player hull.
- The Hub at session reset.
Relation to the gacha screen
The gacha screen (chest opens, single/10-pulls) is the producer side of the same inventory store. Its grantShipPull(hull_class) call either:
- Unlocks a new hull (
unlocked: true, xpGained: 0) — first appearance in the Ships gallery. - Or grants 1 XP toward the existing hull (
xpGained: 1) — bumps the star bar when viewed on this screen.
The Ships gallery is the readback: the player opens it after a chest pull to confirm the unlock or star-up.
Files
src/starship-survivors/screens/ShipsScreen.tsx— sub-tab shell + currency strip.src/starship-survivors/screens/ships/SelectTab.tsx— hero card + filter panel + inventory grid.src/starship-survivors/screens/ships/ShipInfoPopover.tsx— stat-sheet popover from(i)button.src/starship-survivors/screens/ships/ShipLivePreview.tsx— full-bleed live ship preview on hero card.src/metagame/components/CollectibleCard.tsx— per-hull grid tile.src/starship-survivors/components/HullStarBar.tsx— gold-star + XP-bar unit.src/starship-survivors/stores/inventoryStore.ts— owned hulls + XP + star derivation.src/starship-survivors/stores/sessionStore.ts—selectedShipId+ cloud persist.src/starship-survivors/data/ship-progression.ts—starFromXp,xpToNextStar.