Skip to content

feat(identity): prototype car identity catalog + manual picker#40

Merged
burkben merged 2 commits into
mainfrom
burkben-car-identity-catalog
Jul 1, 2026
Merged

feat(identity): prototype car identity catalog + manual picker#40
burkben merged 2 commits into
mainfrom
burkben-car-identity-catalog

Conversation

@burkben

@burkben burkben commented Jun 26, 2026

Copy link
Copy Markdown
Owner

What this does

Revives real Hot Wheels car identity in the garage — castings get their real names + photos, and you can manually identify a car with a tap. Identity is keyed off the stable Mattel id the app already decodes, so identifying one copy names every copy of that casting you scan.

Crucially, this is an isolated module — the shipped cars SQLite table is untouched. Two small maps live in a new append-only v6 migration (car_links, car_identifications), so it's safe to iterate on or rip out.

What you'll see

  • Garage list & detail show each car's real name + photo once identified (bundled 146-car catalog, 136 with art, scraped from the Hot Wheels Fandom wiki).
  • Tap "Identify" / "Change" → modal with a searchable 2-column photo grid picker.
  • Identifying one copy of a casting names all copies.

How it works

uid ──(learned on detection)──▶ castingKey ──(user pick)──▶ catalogId ──▶ name + photo
  • Protocol: decode the NFC NDEF mattelId on the modern MPID path, surface it on CarDetectedEventportalStore's CurrentCar. New castingKeyFromMattelId() (model-id bytes [2..6), base64url-aware, defensive raw-id fallback) + KAT tests.
  • Identity store: uid → castingKey links (learned automatically) and castingKey → catalogId identifications (user pick); catalogIdForUid selector. Repository interface + in-memory + sqlite impls; bootstrap hydrate + write-through sink + learnIdentity() in seed and subscribe paths.
  • Catalog + UI: catalog.json via a stdlib-only Fandom scraper; typed catalog.ts surface + ranked searchCatalog; useCarIdentity hook; shared CarPhoto component; app/identify.tsx modal picker.

Caveats (tracked in ADR-0013)

  1. Images hot-link the CC-BY-SA wiki CDN. Fine for a prototype, but mirroring/relicensing + attribution is a pre-release follow-up. Also means art only renders on a real device/simulator, not in the test env.
  2. The model-id byte offset is reverse-engineered. There's a raw-id fallback so a wrong guess can't mis-identify, but a wrong-but-decodable offset could mis-group castings — worth validating against real cars.

Testing

  • npm run typecheck clean.
  • 261 tests pass (207 mobile + 54 protocol), including new casting, catalog, identityStore, and identityRepository suites.
  • On-device UI not yet exercised (no simulator run); images load from the wiki CDN at runtime.

🤖 Generated with GitHub Copilot CLI

burkben and others added 2 commits June 26, 2026 15:02
Revive real Hot Wheels car identity in the garage without touching the
shipped `cars` table. A bundled, wiki-sourced catalog gives castings real
names + photos, and a manual picker lets the user identify a car keyed off
the stable Mattel id the app already decodes.

Protocol:
- Decode the NFC NDEF `mattelId` on the modern MPID path and surface it on
  CarDetectedEvent; thread it into portalStore's CurrentCar.
- Add castingKeyFromMattelId() (model-id bytes [2..6), base64url-aware,
  defensive raw-id fallback) + KAT tests.

Identity (isolated module, append-only v6 migration: car_links,
car_identifications):
- identityStore: uid->castingKey links (learned on detection) and
  castingKey->catalogId identifications (user pick); catalogIdForUid
  selector. Identifying one copy names every copy of a casting.
- Repository interface + in-memory + sqlite impls; bootstrap hydrate +
  write-through sink + learnIdentity() in seed and subscribe paths.

Catalog + UI:
- catalog.json (146 cars, 136 with art) via stdlib-only Fandom scraper.
- catalog.ts typed surface + searchCatalog ranking; useCarIdentity hook.
- Shared CarPhoto component; garage rows + detail show catalog name/photo;
  Identify/Change modal grid picker (app/identify.tsx).

Docs: ADR-0013 + ROADMAP Phase 5 status.

Caveats (see ADR-0013): catalog images hot-link the CC-BY-SA wiki CDN
(licensing/attribution is a pre-release follow-up); the model-id byte
offset is reverse-engineered, with raw-id fallback to keep grouping safe.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Make the Car Identity & Collection surfaces feel less utilitarian while
staying inside the documented design language (night-track dark, flame
accent, soft accent glow for "alive" states over heavy shadows).

- tokens: add surfaceRaised + accentSoft/accentBlueSoft washes and a
  reusable `elevation` preset (card ambient lift, accentGlow, blueGlow).
- CarPhoto: move to expo-image (fade transition, disk cache), flexible
  sizing (size | width/height/aspectRatio) and an optional accent ring.
- garage list: summary line (N identified · on portal), richer rows with
  56px photo, identified ring, on-portal accent glow, card depth.
- garage detail: imagery-forward hero photo banner with Change badge when
  identified; identity-prompt card only when unidentified; accent glow on
  the best-speed hero; depth on stat cards.
- identify: search row with leading magnify glyph; casting cards become
  square photo tiles with a selected check-badge + ring.
- home: subtle card depth on the speed stat tiles for cohesion.
- docs: document the new elevation/glow + raised-surface tokens in the
  design language (§4).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@burkben burkben merged commit 4ebc85c into main Jul 1, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant