# Pokédex PWA A responsive, offline-capable Pokédex reference built on [PokéAPI](https://pokeapi.co/). Vanilla JS + Vite + Workbox — no UI framework. ## Two headline features | Feature | How it works | | --- | --- | | **Game series selection** | Pick a *game* (PokéAPI version group, e.g. Scarlet & Violet). If it has more than one regional dex (Paldea / Kitakami / Blueberry) a sub-dex switcher appears. The choice drives which species show, their regional numbering, and which version's flavor text the detail page uses. Stored in `localStorage`. | | **Unified Pokémon selection** | One tracking record per Pokémon, keyed by **National Dex id**. Mark Pikachu once and every game's view reflects it — each dex computes its own "Seen / Caught" totals by intersecting its species list with that single map. The active Pokémon is also a single deep-linkable route (`#/pokemon/25`). | ## Data & storage split - **Preferences + tracking state** → `localStorage` (`pdx.settings`, `pdx.selection`). Tiny, synchronous, restored on reload. - **Build-time snapshot** (`src/data/snapshot.json`, ~150 KB) → generated by `npm run snapshot` from PokéAPI: every species (id, name, generation, types), all regional Pokédex lists, and all version groups. Precached by the service worker, so the list / search / game switching work on the first offline launch. - **Detail data** (stats, abilities, flavor text, evolution) → fetched lazily from `pokeapi.co` per Pokémon, then cached by the service worker (stale-while-revalidate, 30-day TTL). - **Sprites** → cache-first with a capped LRU. Export / import of `settings` + `selection` as JSON lives in **Settings**. ## Scripts ```bash npm install npm run snapshot # fetch data from PokéAPI -> src/data/snapshot.json (run once; refreshes if >30 days old) npm run dev # vite dev server npm run build # runs snapshot (prebuild) then vite build npm run preview # serve the production build (needed to exercise the service worker) ``` Deploying under a sub-path (e.g. GitHub Pages project site): `BASE_PATH=/repo-name/ npm run build`. ## Docker Multi-stage build (Node → nginx) that serves the static `dist/`: ```bash docker compose up --build # → http://localhost:8080 # or without compose: docker build -t pokedex-pwa . docker run --rm -p 8080:80 pokedex-pwa ``` The build stage runs `npm run build`, whose `prebuild` step fetches the PokéAPI snapshot — so `docker build` needs network access to `pokeapi.co` unless a fresh `src/data/snapshot.json` is already present (it gets copied in and reused). Serving under a sub-path: `docker build --build-arg BASE_PATH=/dex/ .`. `nginx.conf` sets the SPA fallback and long-cache headers for `/assets/*` while keeping `index.html` / `sw.js` uncached. ## Project layout ``` scripts/build-snapshot.mjs PokéAPI -> snapshot.json src/ main.js boot: theme, nav, router, SW registration router.js hash router (#/, #/pokemon/:id, #/games, #/search, #/settings) sw.js Workbox service worker (injectManifest) store/ createStore + settings + selection (localStorage) data/ snapshot loader, pokedex resolver, lazy API client components/ Card, Sprite, TypeChip, StatBar, ProgressHeader, Nav views/ DexGrid, PokemonDetail, GamePicker, SearchView, SettingsView styles/ tokens.css (palette, type colors, light/dark), layout.css ``` ## Status Working app with a type-themed UI: - **Dex grid** — type-tinted cards (official artwork, spotlight, ghost number), per-dex progress, name/number filter, caught/favorite filters, plus a filter drawer: type, generation, ability, egg group, minimum BST, and "fully evolved only" (derived client-side from each species' evolves-from link — no extra fetches). A "Notes" chip filters to Pokémon with a note; cards with one get a small 📝 mark. - **Notes** — a free-text note per Pokémon on its detail page (trade plans, where you caught it, anything), autosaving as you type and flushing immediately on blur or navigation so a quick tab-away never drops a keystroke. Rides along in the existing JSON export/import. - **Forms** — Megas, Gigantamax, regional forms and alternate formes in the snapshot; a pill switcher on the detail page rebuilds types / stats / matchups / abilities / learnset / artwork for the chosen form. Purely cosmetic variants (Unown's 27 letters, Vivillon's 19 patterns, Furfrou trims, seasonal Deerling/Sawsbuck, Flabébé line colours, Alcremie's 62 decorations, Pikachu caps — 278 across 50 species) get a separate compact "Appearance" dropdown that only swaps the sprite. Cards show a "+N forms" badge. - **Detail** — type-gradient hero + tabbed sheet (About / Stats / Evolution / Moves / Locations); coloured animated stat bars; defensive type matchups; evolution chain re-parented to the selected game's generation; learnset with per-move power/type/accuracy/PP/effect (era-accurate via `past_values`, incl. pre-Gen-4 physical/special-by-type), the TM/HM group ordered by TM number for the selected game; wild encounter locations. - **Game-aware** — abilities gated to Gen 3+ (hidden to Gen 5+); type chart applies Gen 1 / pre-Gen 6 rules. - **Games** — overlay picker with stylised version-colour cover tiles, sub-dex switch, and an "All games" (National, no gen limits) option. - **Search** — tabbed lookup: Pokémon, Moves, Items and Abilities, all browsable offline from the snapshot. Moves filter by type / damage class / "TMs only" / "HMs only" for the selected game and sort by power / accuracy / recency — or, with a machine filter on, by TM/HM number (numbers are baked into the snapshot). Items filter by category. Each has its own detail page. Query, scroll, tab and filters persist. - **Team** — a lineup of up to 6. Coverage leads with a "weak spots" summary (types that hit 2+ members, or that someone's weak to and nobody resists), then a full matchup grid with a diverging resist◀│▶weak bar per type; plus offensive STAB gaps and at-a-glance stats. A Compare table stacks the six side by side. A third Calc mode is a damage calculator — pick (or quick-pick from your team) an attacker + move + defender, and get a damage range, % of HP, hits-to-KO, STAB/effectiveness badges, with level/nature/EV controls; it's a base-stats estimate (31 IVs assumed, no items/abilities/weather/terrain). All three follow the selected game — its generation's type chart, era-accurate typings (pre-Gen-6 Clefairy is Normal, etc.), and era move data. Toggleable in the nav from Settings. - **Settings** — theme (System / Light / Dark / Black / Sepia) + accent colour, text size, an in-app reduce-motion override (on top of the OS preference, which is always respected too), sprite style, haptic feedback on catch (Vibration API), which screen to land on at launch, JSON export/import. - **PWA** — Workbox SW: precache shell + snapshot, SWR for API JSON, cache-first LRU for sprites, in-app update toast. Not yet done: version-exclusive badges, type/generation filters on the grid, an interactive region map (PokéAPI has no map imagery or coordinates), skeleton loaders, install-prompt handling, PNG/maskable raster icons (currently SVG only), and a Lighthouse PWA pass. ## Notes - `npm audit` reports the known esbuild dev-server advisory via Vite 5. It affects the local dev server only, not the production build. Vite 8 (which fixes it) requires a newer Node than this environment has. - Data and images © Nintendo / Game Freak / The Pokémon Company, served via PokéAPI. This project is a non-commercial reference tool.