31 tests in test/, run in a plain Node env with a tiny localStorage shim (no jsdom — its Node-22.4 transitive-dep breakage isn't worth working around for logic tests): - type-chart: modern effectiveness, dual-type stacking, and the era rules (no Fairy pre-6, Steel resists Ghost/Dark pre-6, the Gen 1 Ghost→Psychic and Bug↔Poison quirks). - damage-calc: nature multipliers, the Gen 3+ stat formula (Garchomp reference values), STAB/effectiveness/immunity, pre/post-Gen-6 crit. - savedex: a synthetic Gen 1 SRAM (bitfields + checksum) round-trips; checksum-mismatch and size guards. - selection: normalizeSelection v2→v3 migration, per-game isolation, global favourite, stats vs statsNational. - pokedex-resolver: prettify, dex resolution against a mini snapshot. `npm test` wired into CI after format:check. Also: docker-compose host port 8080 → 4753 (README updated). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
105 lines
5.4 KiB
Markdown
105 lines
5.4 KiB
Markdown
# AGENTS.md
|
|
|
|
Guidance for AI coding agents working in this repo. Humans: see
|
|
[CONTRIBUTING.md](CONTRIBUTING.md) — this file is the short, machine-facing
|
|
version of the same rules.
|
|
|
|
## What this is
|
|
|
|
Pocketdex — an offline-first Pokédex / team builder / save-file tracker.
|
|
**Vanilla JS, no UI framework.** Vite 6 + `vite-plugin-pwa` (Workbox,
|
|
injectManifest). All data comes from [PokéAPI](https://pokeapi.co/).
|
|
|
|
## Setup & commands
|
|
|
|
```bash
|
|
npm install
|
|
npm run snapshot # build src/data/snapshot.json from PokéAPI (git-ignored; required before first build/dev)
|
|
npm run dev # dev server, http://localhost:5173
|
|
npm run build # runs `snapshot` (prebuild) then builds to dist/
|
|
npm run preview # serve the production build — REQUIRED to test the service worker / offline / install
|
|
npm test # Vitest (pure-logic unit tests in test/)
|
|
npm run format # Prettier, write
|
|
```
|
|
|
|
- Node **20+**.
|
|
- CI runs three checks, all must pass: `npm run format:check` (Prettier),
|
|
`npm test` (Vitest — pure-logic unit tests in `test/`), and
|
|
`npm run build` (esbuild transforms every module, catching syntax and
|
|
import errors). Run `npm run format` before finishing. No ESLint.
|
|
- If you change type-chart / damage-calc / savedex / selection logic,
|
|
update or add a test in `test/`.
|
|
- `npm run snapshot -- --force` rebuilds the snapshot even if it's fresh.
|
|
|
|
## Project structure
|
|
|
|
| Path | What |
|
|
| ---------------------------- | --------------------------------------------------------------------------- |
|
|
| `src/main.js` | boot: theme, nav, router, SW registration, install prompt |
|
|
| `src/router.js` | hash router; `routes` array; each view is `() => Promise<Node>` |
|
|
| `src/views/*.js` | one file per route (`DexGrid`, `PokemonDetail`, `TeamView`, …) |
|
|
| `src/components/*.js` | reusable DOM pieces (`Card`, `Sprite`, `TypeChip`, `CompareTable`, …) |
|
|
| `src/store/*.js` | `createStore()` state, persisted to `localStorage` under `pdx.*` |
|
|
| `src/data/*.js` | snapshot loader, pokedex resolver, lazy PokéAPI client, type chart, natures |
|
|
| `src/lib/*.js` | app-agnostic helpers (`dom`, `anim`, `damage-calc`, `savedex`, `swipe`, …) |
|
|
| `scripts/build-snapshot.mjs` | the only thing that calls PokéAPI at build time |
|
|
| `test/*.test.js` | Vitest unit tests (pure logic only) |
|
|
| `src/styles/tokens.css` | palette, type colours, the five themes |
|
|
| `src/styles/layout.css` | everything else |
|
|
|
|
## Conventions
|
|
|
|
- **Build DOM with `el()`** from `src/lib/dom.js` — `el(tag, props, ...children)`.
|
|
No template-string HTML, no `innerHTML`, except the deliberate `html:` prop
|
|
for trusted inline SVG.
|
|
- **Stores**: `createStore(key, initial)` → `{ get, set, subscribe, replace }`.
|
|
`set(fn)` **replaces** state (it does not merge) — spread `...s` yourself.
|
|
In views, `subscribe()` and call the returned unsub in
|
|
`onTeardown(viewNode, off)`.
|
|
- **Everything is game-aware.** The selected game lives in
|
|
`settings.get().versionGroup`. If you touch typings, effectiveness,
|
|
learnsets or evolution, honour that game's generation: `typesForGen()`,
|
|
`multiplier(atk, def, gen)`, PokéAPI `past_values`.
|
|
- **Tracking is per game.** `src/store/selection.js`: `entry(id)` /
|
|
`toggle(id, field)` / `stats(ids)` default to the selected game;
|
|
`favorite` and `note` are global. Don't reintroduce a single global
|
|
caught set.
|
|
- Respect `prefersReducedMotion()` (from `src/store/settings.js`) for any
|
|
animation.
|
|
- Formatting is Prettier (`npm run format`). Otherwise match the
|
|
surrounding file; keep comments about _why_.
|
|
- No new runtime dependencies. Prefer adding to the snapshot over a new
|
|
runtime fetch.
|
|
|
|
## Adding things
|
|
|
|
- **Route** — new `src/views/Foo.js` exporting `async function Foo()`
|
|
returning a node; add one entry to `routes` in `src/router.js`. Add a
|
|
`skeleton` if it does async work before first paint.
|
|
- **Setting** — key + default in `src/store/settings.js` (and `applyTheme()`
|
|
if it affects the document), a field in `src/views/SettingsView.js`, and
|
|
add it to the export payload in `exportData()` if it should survive a
|
|
backup.
|
|
- **Snapshot field** — add it in `scripts/build-snapshot.mjs`, run
|
|
`npm run snapshot -- --force`, read it via `loadSnapshot()`. Keep the
|
|
snapshot small; it's precached on every install.
|
|
|
|
## Do not
|
|
|
|
- Commit `dist/` or `src/data/snapshot.json` (both git-ignored).
|
|
- Commit Pokémon sprites, artwork, audio, ROMs or save files. All imagery
|
|
is fetched at runtime from PokéAPI.
|
|
- Add analytics, telemetry, ads, tracking, or "sign in" flows.
|
|
- Add a framework or a build step that isn't Vite.
|
|
- Break offline-first: the grid, search, filters and game switching must
|
|
work with no network.
|
|
|
|
## Verifying a change
|
|
|
|
`npm run format`, `npm test`, `npm run build` — all must pass. Then
|
|
sanity-check by hand: the dex grid (filters, sort, catching from a card),
|
|
switching games (numbers + typings update), a detail page (all tabs, form
|
|
switch), and `npm run preview` offline (DevTools → Network → Offline →
|
|
reload). Check light and dark
|
|
theme and a mobile-width viewport.
|