- .github/workflows/ci.yml — npm ci + npm run build on push/PR, with the PokéAPI snapshot cached so only the first run pays the fetch cost. - .github/dependabot.yml — weekly npm, monthly actions, grouped. - .github/ISSUE_TEMPLATE/ — bug report, feature request, config with discussion / upstream-data links. - CODE_OF_CONDUCT.md — Contributor Covenant 2.1 (contact method is a placeholder to fill in). - SECURITY.md — private reporting + the known dev-only Vite/esbuild advisory. - AGENTS.md — machine-facing version of CONTRIBUTING for AI coding agents. - docs/screenshots/ + a strip in the README (resized + pngquant'd, ~240 KB). - public/og.png + Open Graph / Twitter card meta in index.html. - .nvmrc (20); gitignore .claude/ .idea/ .vscode/. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
4.6 KiB
4.6 KiB
AGENTS.md
Guidance for AI coding agents working in this repo. Humans: see 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 5 + vite-plugin-pwa (Workbox,
injectManifest). All data comes from PokéAPI.
Setup & commands
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 -- --forcerebuilds 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()fromsrc/lib/dom.js—el(tag, props, ...children). No template-string HTML, noinnerHTML, except the deliberatehtml:prop for trusted inline SVG. - Stores:
createStore(key, initial)→{ get, set, subscribe, replace }.set(fn)replaces state (it does not merge) — spread...syourself. In views,subscribe()and call the returned unsub inonTeardown(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éAPIpast_values. - Tracking is per game.
src/store/selection.js:entry(id)/toggle(id, field)/stats(ids)default to the selected game;favoriteandnoteare global. Don't reintroduce a single global caught set. - Respect
prefersReducedMotion()(fromsrc/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.jsexportingasync function Foo()returning a node; add one entry toroutesinsrc/router.js. Add askeletonif it does async work before first paint. - Setting — key + default in
src/store/settings.js(andapplyTheme()if it affects the document), a field insrc/views/SettingsView.js, and add it to the export payload inexportData()if it should survive a backup. - Snapshot field — add it in
scripts/build-snapshot.mjs, runnpm run snapshot -- --force, read it vialoadSnapshot(). Keep the snapshot small; it's precached on every install.
Do not
- Commit
dist/orsrc/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.