What it is

The profile screen is the account center reached from the metagame bottom navigation. It surfaces the player’s identity, the path to convert a guest session into a permanent claimed account, and a row of one-tap developer convenience tools used during testing. There is no separate cosmetic or trophy collection page wired up yet — the /collection route redirects to the unified ships screen, and the collection CSS scaffolding (tabs, filter pills, ship grid, captain grid, achievement progress, detail panel) ships in the bundle but no React component renders it. The claim account modal is a fullscreen overlay launched from the profile screen that sends a passwordless email magic link to upgrade a guest account into a claimed account.

Stats / variables tables

Profile screen sections (top to bottom)

SectionVisibilityPurpose
Player cardAlwaysAvatar, display name, account-state badge, admin badge, player ID, email
Claim account buttonGuest accounts onlyOpens the claim modal
Unlock all + Reset all rowAlwaysTwo paired developer buttons with confirm step
Grant gems buttonAlwaysOne-shot gem injection developer button
Admin tools buttonAdmin role onlyNavigates to the admin screen
Sign out buttonAlwaysBottom of page, ghost styling

Player card fields

FieldSourceNotes
AvatarStatic rocket glyphFixed for all players; no upload yet
Display namePlayer profileTap to edit inline; 1-24 characters
Account-state badgePlayer profileReads “GUEST” or “CLAIMED”
Admin badgePlayer profileShown only when role is admin
Player IDPlayer profileFirst 12 characters shown; tap copies full ID to clipboard; copy confirmation lasts 2 seconds
EmailPlayer profileShown only when an email is on file

Display name rules

RuleValue
Minimum length1 character
Maximum length24 characters
TrimmingLeading and trailing whitespace stripped before validation
Error on invalid length”1-24 characters”
Save targetPlayers table, display_name column

Account states

StateEmailPersistenceHow to enter
GuestNoneAnonymous session, device-local risk if signed out without claimDefault on first launch
ClaimedVerified emailCross-device, recoverable via magic linkClick magic link sent by claim flow

Player roles

RoleEffect
PlayerDefault; admin tools button hidden
AdminAdmin badge shown; admin tools button visible; navigates to admin screen

Developer tool buttons

ButtonConfirm stepActionServer effect
Unlock allTwo-tap with amber warning panelCalls the dev unlock RPC, re-runs bootstrapMax wallet, max pull tickets, one of every ship hull at five-star, one legendary of every mod template, every mod-grid cell purchased
Reset allTwo-tap with red warning panelCalls the dev reset RPC, re-runs bootstrapWipes inventory, wallet, save to day-one defaults; match history preserved
Grant gemsNoneCalls the grant dev currency RPC, replaces wallet from snapshotAdds 50,000 gems
Admin toolsNoneNavigates to the admin screenNone directly; admin screen has its own RPCs
Sign outNoneClears auth session, clears all stores, immediately starts a fresh anonymous sessionServer retains the prior player’s data; client moves to a new guest account

Claim account modal flow

StepWhat the player seesWhat the system does
OpenHeading “CLAIM YOUR ACCOUNT”, email input, send button, cancel buttonModal scrim is dismissible by tapping outside
ValidateInline error if invalidEmail must contain @ after trim
SubmitSend button reads “SENDING…”Calls the player store claim action which sends a Supabase magic link
SentHeading “CHECK YOUR EMAIL” with the entered email, “GOT IT” close buttonModal stays open until the player closes it; the actual claim completes when the player clicks the emailed link from any device
Link clickedAuth state changes on next app load, welcome modal triggers so the player can set their callsignSame anonymous player ID is upgraded server-side; existing progress is preserved

Collection CSS scaffolding (present in the bundle, no rendered component)

The collection.css file is imported by the profile screen and defines styling for an unbuilt collection grid. None of these UI elements render in the live profile screen today; they are reserved for a future collection page.

CategorySubcategories defined in stylesheet
Sub-tab selectorGeneric tabbed bar with active highlighting
Captain filter pillsHorizontal scrollable pill row with magenta active state
Section header and subtitleCal Sans heading, Space Grotesk subtitle
Toast messagesTwo variants: merge (cyan) and starup (magenta)
Item cardsShips, captains, achievements share a single card layout
Star displayAmber filled stars, recessed empty stars
Action buttonsThree variants: merge (cyan), starup (magenta), claim (amber)
Ship gridFive squares per row (one per rarity tier), grouped by hull class, with a small count badge in the top-right
Hull rarity cardsFour cards per row, taller aspect ratio, rarity initial label, gray question mark for unowned slots
Captain gridFive squares per row, wrapping, with a star count badge in the bottom-right
Detail panelExpanding panel under the grid when a square is tapped
Undiscovered listGreyed list of locked entries
Achievement progressTrack plus fill plus claimed badge; complete fills with a cyan gradient

Collection CSS rarity-tier count

| Rarity tiers expected by the grid | 5 |

Sign-out behavior

StepEffect
Tap sign outPlayer store clears user, profile, save, pity; bootstrapped flag flips off
NavigationPage navigates to the hub route
Auto re-initPlayer store immediately starts a fresh anonymous session so the next screen has a valid guest account; without this the app would otherwise hang on the loading splash

How it works

The profile screen reads its data from the player store, which is the client-side projection of the bootstrap player RPC response. The profile object contains the player ID, display name, email, account state, role, analytics opt-in flag, and creation timestamp. The screen renders nothing until the profile is loaded; while bootstrap is pending it shows a “Loading profile…” placeholder. Display name edits are validated locally, written through the profile service to the players table, and reflected back into the store on success. Player ID copies use the system clipboard and flash a “Copied!” label for 2 seconds.

The two destructive developer buttons (unlock all and reset all) each have their own confirm panel. Tapping the button replaces it with a yellow or red warning panel and a yes/no pair; tapping yes runs the corresponding RPC and re-bootstraps every store from the canonical server response, so the on-screen wallet, inventory, ships, mods, and grid all swap in atomically. The grant gems button has no confirm step and grants 50,000 gems by calling the grant dev currency RPC then replacing the wallet from the returned snapshot.

The claim account flow runs entirely client-initiated up to send time, then becomes asynchronous: the magic link is consumed on whichever device the player clicks it on, the anonymous Supabase user is upgraded in place (same player ID, new email attached), and the auth state change listener in the player store re-runs bootstrap to refresh the profile to the claimed state. A welcome modal then fires once per claim so the player can set their callsign. The “welcome shown” guard lives in localStorage.

The sign-out flow is intentionally seamless. Signing out does not leave the player on a dead screen — it clears all state then immediately calls init again to mint a new anonymous session, so the hub re-renders for a fresh guest. The original account is not deleted; it remains on the server and can be reattached by signing into its claimed email if it had been claimed.

Interactions

InteractionResult
Tap display nameInline edit field replaces the name; autofocused; save button writes to the server then exits edit mode
Tap save with invalid lengthInline error appears, name not changed
Tap player IDFull ID copied to clipboard, label reads “Copied!” for 2 seconds
Tap claim accountClaim modal opens fullscreen
Tap unlock allConfirm panel replaces the button; second tap on yes runs the RPC
Tap reset allConfirm panel replaces the button; second tap on yes runs the RPC
Tap +50K gemsWallet store is replaced from the RPC response; no confirm
Tap admin toolsNavigates to the admin screen route
Tap sign outAuth cleared, navigation to hub, new guest session started immediately
Magic link clicked on any deviceAuth state change re-bootstraps the profile, welcome modal opens

What it does NOT do

  • It does not let the player change their avatar; the rocket glyph is fixed.
  • It does not show a cosmetic, ship, captain, or achievement collection — that screen is not yet wired up, only its stylesheet exists.
  • It does not show wallet balances directly; those live in the top bar.
  • It does not delete an account; sign-out only ends the local session.
  • It does not change the player ID when a guest claims; the same ID is upgraded.
  • It does not require a password at any step; the only sign-in path is the email magic link.
  • It does not gate the developer buttons by role; unlock all, reset all, and the gem grant are visible to every player. Only the admin tools button is role-gated.
  • It does not block the destructive buttons against a double-tap; both protect with a single confirm step but no rate limit.
  • It does not retry a failed unlock, reset, or gem grant automatically; failures only log to the developer console and the user must tap again.
  • It does not toggle the analytics opt-in from this screen, even though the profile service exposes that mutation.
  • It does not handle a paid-account or subscription state; only guest and claimed exist.