dex/AGENTS.md
chris 671e72972a Apply Prettier to the whole tree
Pure formatting — no behaviour change. Verified: build passes, all 14
routes render, service worker active, no console errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-10 11:24:31 -04:00

98 lines
5.0 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
```
- Node **20+**.
- There is **no lint or test command** and **no test suite**. The build
(`npm run build`) is the only automated check — it must pass. It runs
esbuild over every module, so it catches syntax and import errors.
- `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 |
| `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.
- 2-space indent, semicolons, single quotes, trailing commas in multi-line
literals. 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 build` 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.