From 31cc076c0cc920a115ba83f321f475baf6e89798 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 10 Sep 2026 11:03:23 -0400 Subject: [PATCH] Name the project Pocketdex; full README, CONTRIBUTING, LICENSE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the app from the working-title "Pokédex" to Pocketdex across the nav brand, install toast, PWA manifest, index.html title/meta, and package.json. Generic in-universe uses of "Pokédex" (sub-dex label, "all Pokédex entries", save-import messages) are left as-is. Docs for going public: - README.md rewritten: quick start, full feature list, how-it-works (data/storage split, per-game tracking, routing), deployment, legal disclaimer, contributing pointer. - CONTRIBUTING.md: ground rules (no copyrighted assets, framework-free, offline-first), setup, project map, code style, common tasks, manual test checklist, PR conventions. - LICENSE: MIT (+ note that it covers source only, not Pokémon data). - .editorconfig, .github/PULL_REQUEST_TEMPLATE.md. - package.json: add "engines": node >=20. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu --- .editorconfig | 12 + .github/PULL_REQUEST_TEMPLATE.md | 25 ++ CONTRIBUTING.md | 123 ++++++++++ LICENSE | 28 +++ README.md | 387 ++++++++++++++++++++----------- docker-compose.yml | 2 +- index.html | 8 +- package.json | 7 +- src/components/Nav.js | 2 +- src/main.js | 2 +- vite.config.js | 6 +- 11 files changed, 458 insertions(+), 144 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f15441a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..9e78131 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,25 @@ + + +## What & why + + + +## How I tested + + + +- [ ] `npm run build` succeeds +- [ ] Checked light and dark theme +- [ ] Checked a narrow (mobile) viewport +- [ ] Switched games and confirmed game-aware data still updates (if relevant) + +## Screenshots / clip + + + +## Checklist + +- [ ] No copyrighted assets committed (sprites, artwork, ROMs, save files) +- [ ] No new runtime dependencies (or discussed in an issue first) +- [ ] `dist/` and `src/data/snapshot.json` are not in the diff +- [ ] Matches the surrounding code style diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c9d03aa --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,123 @@ +# Contributing to Pocketdex + +Thanks for taking the time. This is a small, framework-free codebase and +easy to get into. + +## Ground rules + +- **No copyrighted assets.** Don't commit Pokémon sprites, artwork, audio, + ROMs or save files. Everything visual is fetched at runtime from PokéAPI. + PRs that add such files will be asked to remove them. +- **Non-commercial.** No ads, analytics, telemetry, paid tiers, affiliate + links or "sign in" flows. +- **Stay framework-free.** No React/Vue/Svelte/etc., and no new runtime + dependencies without discussing it in an issue first. Build-time dev + dependencies are a lower bar but still worth raising. +- **Offline-first stays true.** The list, search, sort, filters and game + switching must keep working with no network. New always-needed data goes + in the snapshot, not a runtime fetch. +- **Be kind.** Assume good faith in issues and reviews. + +## Getting set up + +Requires **Node 20+**. + +```bash +npm install +npm run snapshot # build src/data/snapshot.json from PokéAPI (git-ignored) +npm run dev # http://localhost:5173 +``` + +To exercise the service worker, offline behaviour or the install prompt, +you need a real build: + +```bash +npm run build && npm run preview +``` + +## Where things live + +See the **Project layout** and **How it works** sections in +[README.md](README.md). In short: + +- `src/views/.js` — one file per route, an `async` function returning + a DOM node. Register it in `src/router.js`. +- `src/components/` — reusable pieces (`Card`, `Sprite`, `TypeChip`, …). +- `src/store/` — `createStore()`-backed reactive state, persisted to + `localStorage` under `pdx.*`. +- `src/lib/` — framework-y helpers with no app knowledge (`dom`, `anim`, + `damage-calc`, `savedex`, …). +- `src/data/` — the snapshot loader, the Pokédex resolver, the lazy PokéAPI + client, the type chart, natures. +- `scripts/build-snapshot.mjs` — the only thing that talks to PokéAPI at + build time. + +## Code style + +There's no linter or formatter config yet — **match the surrounding +code**: + +- 2-space indent, semicolons, single quotes, trailing commas in + multi-line literals (an `.editorconfig` covers whitespace). +- Build DOM with the `el()` helper from `src/lib/dom.js`, not template + strings or `innerHTML` (except the deliberate `html:` prop for trusted + inline SVG). +- Stores: `set(fn)` **replaces** state — spread `...s` yourself. Read with + `get()`, react with `subscribe()`, and unsubscribe in the view's + teardown (`onTeardown(view, off)`). +- Keep comments about *why*, not *what*. Match the existing density. +- Respect `prefersReducedMotion()` for any new animation. +- Keep everything game-aware: if you touch typings, type effectiveness, + learnsets or evolution, honour the selected game's generation + (`typesForGen`, `multiplier(atk, def, gen)`, `past_values`, …). + +## Common tasks + +**Add a setting** — add the key + default to `src/store/settings.js` +(and `applyTheme()` if it affects the document), then a field in +`src/views/SettingsView.js`. Add it to the export payload if it should +survive a backup. + +**Add a snapshot field** — add it in `scripts/build-snapshot.mjs`, run +`npm run snapshot -- --force`, and consume it via `loadSnapshot()`. Keep +the snapshot small; it's precached on every install. + +**Add a route** — new file in `src/views/`, one entry in the `routes` +array in `src/router.js`. Add a skeleton if the view does async work +before it can render. + +## Testing your change + +There's no automated suite. Before opening a PR, manually check: + +- The **dex grid** — filters, sort, the progress ring, catching from a + card. +- **Switching games** (the Games sheet) — regional numbers, era typings, + and per-game seen/caught all update. +- A **detail page** — every tab, form switching, the track buttons. +- **`npm run build`** succeeds, and `npm run preview` still works offline + (DevTools → Network → Offline, then reload). +- Light **and** dark theme, and a narrow (mobile) viewport. + +Describe what you tested in the PR. + +## Commits & pull requests + +- Branch off `main`. One focused change per PR. +- Imperative commit subjects ("Add …", "Fix …"), with a body explaining + the *why* when it isn't obvious. +- Don't commit `dist/` or `src/data/snapshot.json` (both git-ignored). +- Fill in the PR template. Screenshots or a short clip for anything + visual. +- It's fine to open a draft PR early to discuss direction. + +## Reporting bugs + +Open an issue with: what you did, what you expected, what happened, the +browser/OS, and the selected game if it's relevant. A screenshot or the +console output helps a lot. + +## License + +By contributing you agree that your contributions are licensed under the +[MIT License](LICENSE). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c2f47a8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +MIT License + +Copyright (c) 2026 Pocketdex contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +This license applies to the Pocketdex source code only. Pokémon and all +related names, imagery and data are the property of Nintendo, Game Freak and +The Pokémon Company, and are served at runtime via PokéAPI +(https://pokeapi.co/). No such assets are included in this repository. diff --git a/README.md b/README.md index d029d3a..419fd40 100644 --- a/README.md +++ b/README.md @@ -1,157 +1,280 @@ -# Pokédex PWA +# Pocketdex -A responsive, offline-capable Pokédex reference built on -[PokéAPI](https://pokeapi.co/). Vanilla JS + Vite + Workbox — no UI -framework. +An offline-first **Pokédex, team builder and save-file tracker**, built on +[PokéAPI](https://pokeapi.co/). Vanilla JS + [Vite](https://vitejs.dev/) + +[Workbox](https://developer.chrome.com/docs/workbox) — no UI framework, no +runtime dependencies in the app bundle. -## Two headline features +- **Pick a game** and everything reshapes to it — regional numbering, + era-accurate typings, that generation's type chart and move data, the + right flavour text. +- **Track seen/caught per game.** Catching Pikachu in Blue says nothing + about your Gold save. `#/progress` shows each game's own tally. +- **Import a real save file** (`.sav` / `.srm` / `.dsv`), Gen 1–5, and read + the Pokédex straight out of it. +- **Works offline** after the first load, and installs as a PWA. -| 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`. | -| **Per-game Pokémon tracking** | Seen / caught are stored **per game** (version-group key) — catching Pikachu in Blue says nothing about your Gold save. `favorite` and `note` are global (they describe the Pokémon, keyed by National Dex id). The `all` bucket ("All games" mode) reads as the union — "caught anywhere" — and is where a pre-per-game save or an older backup migrates to. `#/progress` shows each game's own tally (National = the union), leading with the games you've played and tucking the rest behind a toggle. The active Pokémon is also a single deep-linkable route (`#/pokemon/25`). | +> **Not affiliated with Nintendo, Game Freak or The Pokémon Company.** This +> is a non-commercial fan reference tool. See [Legal](#legal). -## 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. +## Quick start -Export / import of all local state (settings, tracking, team, form -tracking, shiny hunts) as JSON lives in **Settings**, which also imports -the Pokédex straight out of a **game save file** (`.sav` / `.srm` / -`.dsv`): Gen 1 (R/B/Y), Gen 2 (G/S/C), Gen 3 (R/S/E, FR/LG), Gen 4 -(D/P/Pt, HG/SS) and Gen 5 (B/W, B2/W2). It reads the game's own -seen/owned bitfields — checksum-picking Gold/Silver vs Crystal, Gen 3's -newer slot and rotated sections, Gen 4/5's active NDS slot (DeSmuME -footer stripped) and OR-ing their per-form "seen" copies — then a -dialog offers to merge or replace. - -## Scripts +Requires **Node 20+**. ```bash +git clone https://github.com/OWNER/pocketdex.git +cd pocketdex 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) +npm run snapshot # fetch the data snapshot from PokéAPI (one time) +npm run dev # http://localhost:5173 ``` -Deploying under a sub-path (e.g. GitHub Pages project site): `BASE_PATH=/repo-name/ npm run build`. +| Script | What it does | +| --- | --- | +| `npm run snapshot` | Build `src/data/snapshot.json` from PokéAPI. Skips if the file is under 30 days old; `npm run snapshot -- --force` to rebuild anyway. | +| `npm run dev` | Vite dev server with HMR. | +| `npm run build` | Runs `snapshot` (as `prebuild`), then builds to `dist/`. | +| `npm run preview` | Serve the production build. **Use this to test the service worker / offline / install** — none of that runs under `npm run dev`. | -## Docker +The snapshot is **git-ignored** — it's a build artifact. `npm install` +doesn't create it; run `npm run snapshot` (or `npm run build`) first, or +the app has no data to show. -Multi-stage build (Node → nginx) that serves the static `dist/`: +--- + +## Features + +### Dex grid +Type-tinted cards — official artwork over a type-coloured spotlight, ghost +number, per-dex progress ring. Filter by name/number; chips for +caught / missing / favourites / legendary / has-a-note; a filter drawer for +type, generation, ability, egg group, minimum BST and "fully evolved only" +(all derived client-side from the snapshot — no extra fetches). Sort by dex +number, name, any base stat, BST, height, weight, base EXP, catch rate or +"recently caught". When a specific game is selected, cards show a +version-exclusive badge ("Ruby only"), derived from baked wild-encounter +data (so gift/trade-only exclusives are missed). + +### Detail page +Type-gradient hero with a shared-element morph from the tapped card, then a +tabbed sheet: + +- **About** — flavour text for the selected game (with an "all entries" + disclosure), physical data, abilities (each linking to its own page), + held items, egg groups, gender rate, catch rate, growth rate. +- **Stats** — colour-coded animated bars with an animated total. +- **Evolution** — the chain re-parented to the selected game's generation. +- **Moves** — the full learnset with per-move power / type / damage class / + accuracy / PP / effect, **era-accurate** via PokéAPI `past_values` + (including pre-Gen-4 physical/special-by-type). The TM/HM group is ordered + by machine number for the selected game. +- **Locations** — wild encounter locations for the selected game. + +Forms (Mega, Gigantamax, regional, alternate formes) get a pill switcher +that rebuilds types / stats / matchups / abilities / learnset / artwork. +Purely cosmetic variants — Unown's letters, Vivillon's patterns, Alcremie's +decorations, Pikachu caps, seasonal Deerling, and so on — get a separate +compact **Appearance** dropdown, plus a per-species "form dex" checklist +tracked independently of the main caught flag. + +### Team builder (`#/team`) +A lineup of up to 6 (specific forms included). Three modes: + +- **Coverage** — leads with a *weak spots* summary (types that hit 2+ + members, or that someone's weak to and nobody resists), then a full + defensive matchup grid with a diverging resist ◀│▶ weak bar per type, + offensive STAB gaps, and at-a-glance stats. +- **Compare** — the six stacked side by side. (The same table is also a + standalone `#/compare` view with its own picker, up to 4 Pokémon.) +- **Calc** — a damage calculator. Attacker + move + defender → 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. Links out to a **Natures** table, an interactive **Type chart** +(`#/types` — tap a type for its offensive + defensive breakdown, gen-aware) +and a **Breeding** helper (`#/breeding` — egg-group browser, compatibility +check, and egg moves resolved to the base breeding stage). + +### Search (`#/search`) +Tabbed lookup — Pokémon, Moves, Items, 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 +by TM/HM number when a machine filter is on. Items filter by category. The +move, ability and item detail pages each list the Pokémon connected to them +(learners / users / wild holders) as a filterable grid, narrowed to the +selected game. Query, scroll, tab and filters persist. + +### Progress by game (`#/progress`) +Every game's seen/caught tally against its own dex, from its own per-game +bucket. Leads with the games you've played (selected at least once, or +imported a save for); the rest sit behind a toggle. The National Dex row is +the union across all games. + +### Shiny hunt tracker (`#/shiny`) +Per-hunt counters with method-aware odds (full odds, Masuda, SOS, chain +fishing, DexNav, radar, dynamax adventures, outbreaks, mass outbreaks) and +Shiny Charm, cumulative-probability readout, notes, and a "found it" that +marks the Pokémon caught. + +### Save-file import +**Settings → Import from a game save.** Reads the game's own seen/owned +bitfields — not an approximation — from: + +| Gen | Games | Format | +| --- | --- | --- | +| 1 | Red / Blue / Yellow | 32 KB SRAM (`.sav` / `.srm`) | +| 2 | Gold / Silver / Crystal | 32 KB SRAM — checksum picks G/S vs Crystal | +| 3 | Ruby / Sapphire / Emerald, FireRed / LeafGreen | 128 KB — newer slot, rotated sections | +| 4 | Diamond / Pearl / Platinum, HeartGold / SoulSilver | 512 KB NDS — active slot, DeSmuME `.dsv` footer stripped | +| 5 | Black / White, Black 2 / White 2 | 512 KB NDS — per-form "seen" copies OR'd | + +Gen 1–3 are checksum-verified; Gen 4–5 offsets come from PKHeX and are +validated structurally (nothing set past the last species; every caught +species is also seen). A dialog then offers **merge** or **replace** into +one game's bucket — the selected game if the save could be it, otherwise +the parser's best guess. + +Full local state (settings, per-game tracking, team, form tracking, shiny +hunts, played games) also exports / imports as a single JSON file. + +### Settings +Theme (System / Light / Dark / Black OLED / Sepia) + accent colour; text +size; an in-app reduce-motion override (the OS preference is always +respected too); sprite style (modern pixel / game-era pixel / official +artwork / HOME); haptic feedback on catch (Vibration API); which screen to +land on at launch; JSON export / import; cache and tracking resets. + +### PWA +Workbox service worker: precache the app shell + snapshot; stale-while- +revalidate for PokéAPI JSON (30-day TTL); cache-first LRU for sprites; +in-app update toast. Installable with maskable icons, `beforeinstallprompt` +captured for an in-app offer, and manifest shortcuts to Team / Search / +Type chart. + +--- + +## How it works + +### Data & storage + +| Layer | Where | Notes | +| --- | --- | --- | +| Preferences + tracking | `localStorage` (`pdx.*` keys) | Tiny, synchronous, restored on reload. | +| Build-time snapshot | `src/data/snapshot.json` (~150 KB) | Every species (id, name, generation, current + past typings, base stats, height/weight, species flags), every regional Pokédex, every version group, plus move / item / ability name indexes and baked TM numbers and version-exclusivity. Precached by the SW. | +| Detail data | `pokeapi.co`, fetched lazily per page | Stats, abilities, flavour text, evolution, encounters. Cached by the SW (stale-while-revalidate). | +| Sprites | PokéAPI sprites repo, cache-first | Capped LRU. | + +The list, search, sort, filters and game switching run **entirely off the +snapshot** — no network until you open a detail page. + +### Per-game tracking + +`src/store/selection.js`: + +``` +pokemon: { [id]: { favorite, note } } // global — describe the Pokémon +games: { [vgKey]: { [id]: { seen, caught } } } // per game +``` + +`entry(id)` / `toggle(id, field)` / `stats(ids)` default to the selected +game; `favorite` and `note` are always global. The `all` key ("All games" +mode) reads as the **union** of every game — and is where an older +single-record store or JSON backup migrates to (`normalizeSelection`), so +nothing is falsely attributed to a game you never played. + +### Routing & rendering + +Hash router (`src/router.js`) over a small route table. Each view is an +`async` function that returns a DOM node; the router swaps it into `#view` +using the View Transitions API when available (and when the user hasn't +asked for reduced motion). Detail routes get a shaped skeleton first so the +tapped card's sprite can morph into the hero. + +No framework. DOM is built with a ~30-line `el()` helper +(`src/lib/dom.js`). State is a handful of `localStorage`-backed reactive +stores from `createStore()` — `get()`, `set(patch | fn)`, +`subscribe(fn) → unsub`, `replace(next)`. + +### Project layout + +``` +scripts/build-snapshot.mjs PokéAPI → snapshot.json +src/ + main.js boot: theme, nav, router, SW registration, install prompt + router.js hash router + View Transitions + sw.js Workbox service worker (injectManifest) + store/ createStore + settings / selection / team / ui / … + data/ snapshot loader, pokedex resolver, lazy API client, + type chart, natures, game colours + lib/ dom, anim, damage-calc, savedex, swipe, dialog, haptics, … + components/ Card, Sprite, TypeChip, StatBar, CompareTable, Nav, … + views/ one file per route (DexGrid, PokemonDetail, TeamView, …) + styles/ tokens.css (palette, type colours, themes), layout.css +``` + +--- + +## Deployment + +Static output — host `dist/` anywhere. + +**Sub-path** (e.g. a GitHub Pages project site at `/pocketdex/`): ```bash -docker compose up --build # → http://localhost:8080 -# or without compose: -docker build -t pokedex-pwa . -docker run --rm -p 8080:80 pokedex-pwa +BASE_PATH=/pocketdex/ npm run build ``` -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. +**Docker** (multi-stage Node → nginx): -## 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 +```bash +docker compose up --build # → http://localhost:8080 +# or +docker build -t pocketdex . +docker run --rm -p 8080:80 pocketdex ``` -## Status +The build stage's `prebuild` fetches the snapshot, so `docker build` needs +network access to `pokeapi.co` unless a fresh `src/data/snapshot.json` is +already present (it's copied in and reused). Sub-path: +`docker build --build-arg BASE_PATH=/pocketdex/ .`. `nginx.conf` sets the +SPA fallback and long-cache headers for `/assets/*` while keeping +`index.html` / `sw.js` uncached. -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. When a specific game is selected, - cards show a version-exclusive badge ("Ruby only") — derived from the - snapshot's baked wild-encounter data, so gift/trade-only exclusives are - missed. -- **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 colors, 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); colored 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-color 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; the move, ability and item pages list the - Pokémon connected to them (learners / users / wild holders) as a - filterable grid, narrowed to the selected game (by generation, or - exactly by version for held items). 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 (the same table is also a standalone - `#/compare` view with its own picker — up to 4 Pokémon, persisted). - 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. Links out to a Natures table and an interactive Type - chart (tap a type for its offensive + defensive breakdown; both - gen-aware). -- **Settings** — theme (System / Light / Dark / Black / Sepia) + accent - color, 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. Installable: PNG + - maskable icons, `beforeinstallprompt` captured for an in-app "Install" - offer (toast + Settings button), manifest shortcuts to Team / Search / - Type chart. +## Contributing -Not yet done: an interactive region map (PokéAPI has no map imagery or -coordinates), and a formal Lighthouse pass. +Issues and pull requests are welcome — see +**[CONTRIBUTING.md](CONTRIBUTING.md)** for setup, project conventions, and +what's in and out of scope. -## Notes +Known gaps: no interactive region map (PokéAPI has no map imagery or +coordinates), no automated test suite yet, and no formal Lighthouse pass. -- `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. +--- + +## Legal + +Pocketdex is an unofficial, non-commercial fan project. It is **not +affiliated with, endorsed by, or sponsored by** Nintendo, Game Freak, The +Pokémon Company, or PokéAPI. + +- Pokémon and all related names, sprites and artwork are **© Nintendo / + Game Freak / The Pokémon Company**. They are served at runtime from + PokéAPI and its sprite repository; **none are committed to this + repository**, and none should be added in a pull request. +- Game data is provided by [PokéAPI](https://pokeapi.co/) under its terms. +- The build-time snapshot (`snapshot.json`) is generated locally from + PokéAPI and is git-ignored. + +If you represent a rights holder and have a concern, please open an issue. + +## License + +[MIT](LICENSE) — applies to the Pocketdex source code only, not to any +Pokémon data or assets it displays. diff --git a/docker-compose.yml b/docker-compose.yml index 2b664d9..aa769aa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: context: . args: BASE_PATH: / - image: pokedex-pwa + image: pocketdex ports: - "8080:80" restart: unless-stopped diff --git a/index.html b/index.html index 539d267..1ef8e60 100644 --- a/index.html +++ b/index.html @@ -9,18 +9,18 @@ - - Pokédex + + Pocketdex
- +
diff --git a/package.json b/package.json index 5034d0a..cde859f 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { - "name": "pokedex-pwa", + "name": "pocketdex", "version": "0.1.0", "private": true, "type": "module", - "description": "A responsive, offline-capable Pokédex reference PWA powered by PokéAPI.", + "description": "An offline-first Pokédex, team builder and save-file tracker powered by PokéAPI. Vanilla JS + Vite + Workbox.", "scripts": { "snapshot": "node scripts/build-snapshot.mjs", "prebuild": "node scripts/build-snapshot.mjs", @@ -11,6 +11,9 @@ "build": "vite build", "preview": "vite preview" }, + "engines": { + "node": ">=20" + }, "license": "MIT", "devDependencies": { "vite": "^5.4.21", diff --git a/src/components/Nav.js b/src/components/Nav.js index c6dcce4..5cb2636 100644 --- a/src/components/Nav.js +++ b/src/components/Nav.js @@ -31,7 +31,7 @@ export function Nav() { ? el('button', { class: 'nav__link', type: 'button', onclick: () => item.action() }, ...inner) : el('a', { class: 'nav__link', href: item.href }, ...inner); }); - nav.replaceChildren(el('span', { class: 'nav__brand' }, 'Pokédex'), ...links); + nav.replaceChildren(el('span', { class: 'nav__brand' }, 'Pocketdex'), ...links); nav._items = items; sync(); } diff --git a/src/main.js b/src/main.js index 373ef14..7f3dd36 100644 --- a/src/main.js +++ b/src/main.js @@ -68,7 +68,7 @@ let installOffered = false; onInstallChange((can) => { if (!can || installOffered) return; installOffered = true; - showToast('Install this Pokédex for offline, full-screen use?', 'Install', () => { + showToast('Install Pocketdex for offline, full-screen use?', 'Install', () => { promptInstall(); }); }); diff --git a/vite.config.js b/vite.config.js index 7b3d5a9..053fc5b 100644 --- a/vite.config.js +++ b/vite.config.js @@ -27,10 +27,10 @@ export default defineConfig({ 'apple-touch-icon.png', ], manifest: { - name: 'Pokédex', - short_name: 'Pokédex', + name: 'Pocketdex', + short_name: 'Pocketdex', description: - 'A responsive, offline-capable Pokédex reference powered by PokéAPI.', + 'An offline-first Pokédex, team builder and save-file tracker powered by PokéAPI.', start_url: './', scope: './', display: 'standalone',