PURPOSE
Ships-screen tab where the player picks the starting alien artifact for the next run. Renders a hero card for the currently selected artifact plus a scrollable grid of every artifact in the game, each card showing one of four collection states (selected / unlocked / seen / hidden). Built on the medical-UI design system with the artifact’s “alien aqua” identity folded into the medical cyan tech accent. Card layout mirrors the SHIPS tab.
OWNS
ArtifactsTabexported tab component.ArtifactCardinternal card component with four visual states (selected, unlocked, seen, hidden) keyed off theCardStateunion.ArtifactGlyphinternal circular monogram glyph (cyan-tech accent when unlocked, recessed-well surface when locked).CardStatelocal type ('selected' | 'unlocked' | 'seen' | 'hidden').ARTIFACT_ACTIVEpalette object — hex literals mirroring--med-accent-bright/--med-accent/--med-accent-deepso JS-sidergba()/box-shadowstrings can stay literal without runtime CSS reads.headerStripStylemodule-level CSS object for the inventory header strip.popoverIdlocal state — id of the artifact whose info popover is open, ornullwhen closed.- Sort policy: selected first, then unlocked alphabetical, then seen-but-locked alphabetical, then hidden alphabetical.
- Card-click routing:
unlockedselects,seenopens popover,hiddenandselectedno-op (the hero (i) button reaches the popover for the selected artifact).
READS FROM
@starship-survivors/data/artifacts—ARTIFACT_DEFS,ArtifactDeftype,ARTIFACT_TIER_COLOR_BY_IDX,ARTIFACT_TIER_NAMES.@starship-survivors/stores/artifactUnlocksStoreviauseArtifactUnlocksStore— selectorsunlockedIds,selectedId,bestTier, and theselectaction../ArtifactInfoPopover— sibling component rendered whenpopoverIdis non-null.useMemo,useStatefrom React.
PUSHES TO
useArtifactUnlocksStore.select(id)when anunlockedcard is tapped — sets the starting artifact for the next run.- Internal
setPopoverIdstate setter — opens the popover for the hero card’s (i) button or for any seen-but-not-unlocked card. ArtifactInfoPopoverviaartifactId+onCloseprops.
DOES NOT
- Does not fetch, persist, or unlock artifacts. Unlock state is owned by
artifactUnlocksStoreand seeded / updated elsewhere (default starters seeded as legendary best-tier, others promoted to unlocked when brought to legendary in a run). - Does not render the tier ladder, ability text, or flat-stat bonus details — those live in
ArtifactInfoPopover. - Does not own the artifact catalog.
ARTIFACT_DEFSis a read-only import. - Does not handle the tab-bar chrome that hosts this tab; the parent ships screen owns tab switching.
- Does not read CSS variables at runtime; uses literal hex values in
ARTIFACT_ACTIVEthat intentionally mirror the medical accent tokens. - Does not animate beyond a hover/active
translateY(-2px)lift and a box-shadow transition on the selected card.
Signals
select(id)— store action fired on tap of anunlockedcard.popoverIdstate transitions —null → idopens popover (hero (i) button or seen card),id → nullonArtifactInfoPopover.onClose.- Derived
stateper card (selected | unlocked | seen | hidden) computed fromselectedId,unlockedIds, andbestTier[def.id].
Entry points
ArtifactsTab()— named export, mounted as one tab inside the ships screen.ArtifactCard({ def, state, bestTier, onClick })— internal, one per artifact in the grid.ArtifactGlyph({ icon, size, unlocked })— internal, used by both the hero card (size 84) and each grid card (size 56).
Pattern notes
- Four-state card model: state is derived once per render from store selectors (
isSelected,isUnlocked,best >= 0) — no separate flag flow. - Sorting is memoized on
[unlockedIds, bestTier]; the selected artifact is hoisted to the hero card and remains in the grid (its grid card shows theselectedchip and lifted glow). - Surface palette splits between visible and hidden: visible cards use a
linear-gradientover--med-panel-raisedwith the cyan accent fill; hidden cards use--med-panel-recessed. Selected/unlocked share the cyan border; seen and hidden share the muted--med-border. - Tier-color badges on each card pull from
ARTIFACT_TIER_COLOR_BY_IDX/ARTIFACT_TIER_NAMES. Tier colors are preserved as semantic identity per ADR 20260513-001 exception (they bypass the otherwise-strict medical palette). - “Alien aqua” identity is implemented as the cyan tech accent —
ARTIFACT_ACTIVE.edge/.edgeDim/.fillTop/.fill/.glow. Hero card layers a soft radial cyan wash over the white medical panel. - Hidden cards are
disabledwithcursor: 'not-allowed', a padlock glyph, and an “NEVER SEEN / UNLOCK BY RUNNING” caption — no name shown (renders???). - Accessibility: per-card
aria-labelreflects state (“Select X” / “View X details” / “X (locked)”); selected card setsaria-pressed; hero (i) button carries an explicitaria-label. - Grid uses CSS
repeat(auto-fill, minmax(108px, 1fr))for responsive sizing on phone widths. - Layout matches the SHIPS tab (hero card → INVENTORY header → grid) to keep the two collection tabs visually parallel.
- Tick 99 medical-UI rollout, ship tabs PR 2/4.