22 Commits

Author SHA1 Message Date
b15ee3dd7f Shiny hunt tracker (#/shiny)
New store + view (linked from Settings > Your data): one card per active
hunt with a big +1 counter, the method's odds, and the running cumulative
chance (1 - (1-p)^count). Nine methods with shiny-charm variants
(Full odds, Masuda, SOS, Radar, DexNav, Catch Combo, Dynamax Adventure,
Mass/Massive Outbreak). "Found it" marks the Pokémon caught and clears
the hunt; per-hunt notes field.

Also: JSON export/import now covers team, formTracking and shinyHunts
alongside settings/selection; openPokemonPicker gains a `closeAfterPick`
option (used by the shiny + breeding single-pick flows).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-09 19:06:46 -04:00
48cb471489 Breeding helper (#/breeding)
Two modes, linked from the Team header:
- Egg groups — browse every species in each of the 14 breedable egg
  groups (offline, from the snapshot's eggGroups).
- Can breed with — pick a Pokémon and get its compatible partners
  (shared egg group; Ditto pairs with everything; genderless pairs only
  with Ditto; Undiscovered can't breed), plus its family's egg moves
  (walks evolves-from to the base stage — Pikachu shows Pichu's), each
  linking to the move page (which already lists who can learn it).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-09 19:01:24 -04:00
5f6414528e Compare any two Pokémon — standalone #/compare view
Extracted the Team Compare table into components/CompareTable.js and
reused it for a new #/compare route: its own picker (up to 4 Pokémon,
persisted in ui.compareIds), gen-aware types, per-stat max highlight.
Linked from the Team header alongside Natures / Type chart. TeamView's
Compare tab now just calls CompareTable too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-09 18:48:27 -04:00
fa302af7f1 Search moves: sort by TM/HM number; add an "HMs only" filter
TM/HM numbers are now baked into the snapshot (build-snapshot resolves
every machine id -> "TM25" etc. in a post-pass, ~2400 lookups), so the
Search moves list no longer lazily fetches /machine per row — it shows
numbers synchronously and can sort by them.

- New "TM / HM number" sort option, shown only while a machine filter is
  on, and dropped back to A–Z when neither is.
- "TMs only" now means strictly TMs; added a parallel "HMs only". Either
  or both. In "All games" mode a move can be a TM in one game and an HM
  in another, so machineFor picks the newest entry of a requested kind
  rather than just the newest entry (fixes "HMs only" showing 0).

Removes the getMachine/mapLimit lazy-resolution path (and its now-unused
stale-token guard) from SearchView.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-08 10:44:14 -04:00
4b9bc5c0ab Settings: text size, reduce motion, landing screen, haptics
Four new preferences, all in settings.js / applied via applyTheme() so
boot and live changes go through one path:

- fontScale (small/default/large): scales root font-size (92/100/115%);
  the whole stylesheet is already rem-based so this alone rescales
  everything.
- reduceMotion: an explicit in-app override alongside the existing
  `prefers-reduced-motion` OS check, via a new
  :root[data-reduce-motion="true"] rule in tokens.css mirroring the
  existing media-query kill-switch. New prefersReducedMotion() helper
  (checks both) replaces the three hand-rolled matchMedia checks in
  router.js/Card.js/PokemonDetail.js.
- defaultRoute (dex/team/search): redirects on a genuinely hash-less
  launch only (bookmark, home-screen icon, bare URL) — explicit nav
  (e.g. tapping "Dex") is never touched, since it's applied once in
  main.js before initRouter runs.
- haptics: a short navigator.vibrate() pulse on the same catch/seen/
  favorite toggles that already play the pop animation, via a new
  lib/haptics.js buzz() (no-ops without Vibration API support, e.g. iOS
  Safari).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-04 12:35:26 -04:00
c9807127d6 Dex grid: ability, egg group, min BST and fully-evolved filters
Extends the existing filter drawer (type/gen) with four more:

- Ability — snapshot abilities already carry a reverse pokemon[] index,
  so this is a plain lookup, no new data needed.
- Egg group — options derived from the species list's own eggGroups.
- Min BST — a number field; hard filter, distinct from sorting by BST.
- Fully evolved only — new species.evolvesFromId field (from
  pokemon-species' evolves_from_species, already fetched during the
  snapshot build, so no extra requests). "Fully evolved" is computed
  client-side as "no other species points here via evolvesFromId" —
  correctly handles branching lines (Eevee's evolutions all count as
  fully evolved; Eevee itself doesn't).

All four persist via the ui store and count toward the filter badge, same
as the existing filters.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-04 12:14:36 -04:00
1ed8fcb709 Add a per-species form dex (Unown letters, Vivillon patterns, ...)
New tab on the detail page — "<Species> Dex" — for any species with more
than one cosmetic form: a checklist grid (sprite + label + tap-to-toggle)
tracking which appearances you've caught, separate from the species' own
caught flag. Persisted in a new pdx.formTracking store keyed by form slug.

Only offered when the species is actually in the currently selected
game's dex (reuses the page's existing prev/next row lookup), so Unown
gets its dex in HeartGold/SoulSilver but not in Sword/Shield, where it
was never released.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-04 11:35:03 -04:00
415cf3edec Abilities lookup + detail; Natures reference
- Snapshot bakes an abilities index (373: name, generation, effect, and the
  species that have it). Snapshot ~872 KB / 133 KB gzip.
- Search gains an 'Abilities' tab — browse all 373 offline, filter/search by
  name or effect, sort A–Z / most-Pokemon / newest
- #/ability/:id detail: effect + a grid of every Pokemon with the ability
  (all from the snapshot, no fetch)
- Pokemon detail: the Abilities line is now tappable, linking to each ability
- #/natures: the full 25-nature +10%/-10% table; linked from the Team view

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-28 11:00:14 -04:00
79a5efaf11 Browsable moves & items lists (offline)
- Snapshot now bakes a moves index (937: type, damage class, power,
  accuracy, pp, priority, generation, machine ids per version group) and an
  items index (2223: id, name, category — resolved via the 54 item
  categories). ~806 KB / 117 KB gzip.
- Search Moves/Items tabs show the FULL list when the query is empty:
  - Moves: filter by type / damage class / 'TMs only' (for the selected
    game), sort by A–Z / power / accuracy / newest; TM numbers resolve
    lazily via /machine. Rich rows (type + class + power) with no fetch.
  - Items: filter by category, sort A–Z / dex order; sprite + category tag.
  - Result count shown; capped at 400 with a 'refine to see more' note.
- Both tabs are now fully offline (dropped the online name-index calls).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-28 10:42:03 -04:00
ddc84c2a48 Team Builder + Compare views
- New #/team view: a persisted lineup of up to 6 Pokémon (pdx.team store)
  with a search-picker overlay, plus a Coverage/Compare toggle
  - Coverage: 18x6 weakness table (colour-coded multipliers + per-type weak
    count), offensive STAB gaps, team at-a-glance (avg BST, fastest, bulkiest)
  - Compare: per-member column table of types + 6 stats + BST with mini bars
    and row-max highlighting; scrolls horizontally past 4 members
- '+ Team' / '✓ In team' toggle on the Pokémon detail page (disabled when full)
- Nav gains a Team item; a Settings toggle ('Show Team in the navigation
  bar', on by default) hides it from the bar without removing the route
- type-chart.js: defenseVector() helper

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-28 10:33:52 -04:00
2e4572428a Dense-data pass: training/breeding facts, STAB coverage, filters, cries
- Detail About tab: EV yield, base EXP, catch rate + ~%, base friendship,
  growth rate + total EXP, held items; Breeding block with a gender-ratio
  bar, egg groups, egg cycles/steps
- Stats tab: 'STAB coverage (attacking)' — types the Pokemon's STAB hits
  hard / is walled by (data/type-chart.js offensiveSummary)
- Feed: Type and Generation filter dropdowns + a Random button; cards now
  resolve typings for the selected game's generation via snapshot pastTypes
- Recently-viewed strip on the feed (ui.recent, capped at 12)
- Play-cry button on the detail hero; service worker caches PokeAPI cries

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-28 10:06:36 -04:00
491d1102cc Center card sprite; ghost number to top:2px; scroll-position restore
- Card sprite sits centred in the upper area (flex:1 + place-items:center)
  instead of a forced margin; sprite-style / boxed sizing moved onto the
  img so it stays centred
- .card__ghost number nudged to top: 2px
- Feed Back-navigation restores the raw scroll offset again (dropped the
  card-anchor approach); keeps manual scrollRestoration + retry-on-reflow

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-28 08:25:23 -04:00
23272b99a7 Land Back on the opened card (clear of header/nav); card spacing
- Feed remembers the opened card (ui.feedAnchor) and, on Back, scrolls that
  exact card just below the sticky header via scrollIntoView + a computed
  scroll-margin-top; re-corrects on webfont load and as off-screen cards
  render their real height, but yields once the user scrolls
- history.scrollRestoration = 'manual' so the browser doesn't fight it;
  per-session scroll memory cleared on cold launch
- Cards: ghost number nudged off the top edge; sprite dropped 10px (flex
  column grows the card, so nothing overlaps); intrinsic size bumped to match

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 17:49:23 -04:00
b0e3655dbf Restore feed scroll position on Back; enlarge the detail back button
- The dex feed remembers scrollY on teardown (ui.feedScroll) and restores
  it on re-mount, so viewing a Pokémon and going back lands where you were.
  Reset to top when the filter, sort, direction or game changes.
- Router no longer force-scrolls after mount; it scrolls to top on the
  loading placeholder and each view manages its own position (detail pages
  land at top, feed and search restore).
- .phero__back is now a rounded pill with a real 40px tap target.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 17:40:13 -04:00
0d95f9c93a TM/HM numbers; default to the National Dex
- Learnset 'By TM / HM' rows show the machine number for the selected game
  (TM25 / HM05 / TR10), resolved from /machine when the group is expanded
- Move detail page gains a 'TM / HM' fact (marked '(latest)' when the move
  isn't a machine in the currently-selected game)
- machineNumber() exported from MovesList and reused by MoveDetail
- Fresh installs now open on the National Dex (versionGroup 'all') instead
  of Scarlet/Violet

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 13:56:53 -04:00
0f00b50198 Move & item lookup: tabbed Search + detail pages
- Search becomes a tabbed lookup: Pokémon (offline snapshot) / Moves /
  Items. Moves + Items lazy-load a name index from PokéAPI (SW-cached) and
  filter client-side; short move result sets get type/class/power chips
- MoveDetail (#/move/:id): type-themed header, power/accuracy/PP/priority,
  effect text with %-substitution, target, ailment/crit/drain/stat-change
  summary, learned-by count
- ItemDetail (#/item/:id): item sprite, category, cost, fling power,
  attributes, held-by count, effect text
- Loose name matching (hyphens vs spaces); run-token guards stale async
  renders when the query or tab changes mid-fetch

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 13:51:51 -04:00
61ceb6abf3 Declutter feed header; add theme + accent options
- Feed header: the game pill is gone (the nav Games button opens the sheet);
  the active game is now a quiet text label under the title
- Settings > Theme: add Black (OLED) and Sepia alongside System/Light/Dark
- Settings > Accent colour: six swatches (red default, blue, green, amber,
  violet, rose) layered over any theme via [data-accent]; persisted
- applyTheme() takes the settings object; system theme now keys off the
  absence of [data-theme] so explicit light/sepia don't fight the media query

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 13:24:48 -04:00
fa6df9d60b Sorting + richer snapshot; Legendary filter; shiny toggle to hero top
- Snapshot now carries per-species base stats + BST, height, weight, base
  EXP, capture rate, growth rate, colour, egg groups, gender rate,
  legendary/mythical/baby flags, and past typings (~72 KB gzip)
- Dex feed: Sort control (dex / name / BST / each stat / height / weight /
  base EXP / catch rate / recently caught) with a direction toggle;
  sort + filter persisted in the ui store; cards show the sorted metric
- New 'Legendary' filter chip (legendary or mythical) with a live count
- Detail hero: shiny toggle moved up beside the favourite, top of the hero

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 13:20:19 -04:00
01269fd35a All-games mode, full flavour list, persistent search
- FlavorText: 'All Pokédex entries' disclosure listing every distinct
  English entry across all games (newest first, labelled by game) — not
  just the selected game's one line
- Search remembers its query and scroll position in the ui store, so Back
  or re-opening the tab restores the results; header explains the scope
  (matches all species; opens for the selected game / all games)
- GameSheet 'All games' option: National Dex, newest data, no generation
  limits — abilities/shiny ungated, types untrimmed, evolution unpruned;
  Moves/Locations prompt to pick a game

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 13:06:56 -04:00
5144f760f5 Games as an overlay sheet; remember the detail tab
- New GameSheet: bottom drop-up overlay (backdrop / grab handle / Esc to
  dismiss) summoned from the nav 'Games' button or the feed's game pill;
  picking a game/sub-dex writes settings and the feed updates in place
- Removed the #/games route and GamePicker view
- Detail page remembers the last-opened tab in a new pdx.ui store and
  restores it on return; selectTab guards unknown ids

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 12:37:16 -04:00
b4f2460341 Apply type-themed styling to grid, games, search
- Cards: primary-type gradient tint, radial spotlight behind the sprite,
  ghost dex number, official artwork by default, spring hover lift
- Game picker cards + search rows: rounder, soft shadows, hover motion
- Progress bar gradient; pill-shaped search inputs
- Shared typeHex() helper (src/lib/type-color.js), reused by detail + cards

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 12:04:21 -04:00
cd2655011f Scaffold Pokedex PWA (Vite + Workbox)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 10:54:36 -04:00