Files
2026-05-16 18:59:34 +02:00

119 lines
7.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md
Guidance for AI agents working in this repo. Read this before making changes.
## Project at a Glance
- **What it is:** An offline-first PWA helper for the German tabletop RPG _Das Schwarze Auge 4.1_ (DSA 4.1). Covers character sheet, melee/ranged combat, spells, and import/export.
- **Stack:** SvelteKit 2 (SPA via `adapter-static`) + Svelte 5 + TypeScript (strict) + Vite 6.
- **Persistence:** IndexedDB via Dexie (`src/lib/storage/db.ts`); meta key/value table tracks the active character.
- **Validation:** Zod schemas in `src/lib/schema/`.
- **PWA:** `@vite-pwa/sveltekit` with autoUpdate; manifest in `vite.config.ts`.
- **Language:** UI, copy, identifiers, and most code comments are **German**. Preserve German wording (`Eigenschaften`, `Talente`, `Sonderfertigkeiten`, `Vorteile`, `Nachteile`, attribute keys like `MU/KL/IN/CH/FF/GE/KO/KK`, …) don't translate domain terms.
## Commands
| Task | Command |
| ----------------- | ---------------- |
| Install deps | `npm install` |
| Dev server | `npm run dev` |
| Production build | `npm run build` |
| Preview build | `npm run preview`|
| Type / svelte check | `npm run check` |
| Lint | `npm run lint` |
| Format | `npm run format` |
| Run tests (CI) | `npm test` |
| Watch tests | `npm run test:watch` |
| Regenerate icons | `npm run icons` |
After substantive edits, run `npm run check` and `npm test` before declaring done.
## Repository Layout
```
src/
app.css, app.html, app.d.ts
lib/
characters/ # Character defaults / factories (newCharacter)
components/ # Shared Svelte components (e.g. DiceRoller)
engine/ # Pure derivation: AT/PA/FK basis, LeP, melee, ranged, probe, talent-check, spell
import/ # Helden-Software importer (placeholder)
rules/ # DSA 4.1 rule tables: attributes, races, talents, weapons, SFs, Vor-/Nachteile
schema/ # Zod schemas + schema version / migration
storage/ # Dexie DB, repo (CRUD), io (JSON/YAML export/import)
routes/
+layout.{svelte,ts}, +page.svelte
characters/[id]/{sheet,combat/melee,combat/ranged,spells}/+page.svelte
settings/+page.svelte
tests/
setup.ts # vitest setup (uses fake-indexeddb)
engine/ # Unit tests for derivation, ranged, io
scripts/
write-placeholder-icons.mjs # runs on postinstall + `npm run icons`
static/
favicon.svg, icons/
```
Use SvelteKit aliases: `$lib/...` (resolves to `src/lib`) and `$app/...` for kit internals. Don't introduce relative `../../lib` imports.
## Conventions
### Formatting & Linting
- Prettier: **tabs**, single quotes, no trailing commas, `printWidth: 100`. `*.svelte` uses the Svelte parser via `prettier-plugin-svelte`.
- ESLint flat config (`eslint.config.js`) extends `@eslint/js`, `typescript-eslint`, and `eslint-plugin-svelte`. `build/`, `.svelte-kit/`, and `node_modules/` are ignored.
- Run `npm run format` and `npm run lint` before finishing a change.
### TypeScript
- `strict: true` in `tsconfig.json` (extends `.svelte-kit/tsconfig.json`). `allowJs` and `checkJs` are on stray `.js` files are type-checked too.
- Prefer `import type { ... }` for type-only imports.
- No `any`. Use Zod inference (`z.infer<typeof schema>`) for domain types; the canonical `Character` type lives in `src/lib/schema/character.ts`.
### Svelte 5
- Components are Svelte 5. Use the new runes where appropriate (`$state`, `$derived`, `$effect`, `$props`); don't reintroduce legacy `export let` style for new code.
- `svelte.config.js` filters the `a11y_label_has_associated_control` warning and the ESLint config relaxes it because fields use visual labels. Keep that pattern don't add `for`/`id` plumbing just to silence warnings.
### Domain Rules (read carefully before touching `engine/` or `rules/`)
- Derived values follow DSA 4.1 formulas in `src/lib/engine/derived.ts`. They are pure functions of `Character`; don't mutate the input.
- Attribute access goes through `effectiveAttr(char, key)` (= `startwert + mod`). Don't read raw values directly when computing derived stats.
- Race modifiers come from `getRaceDef(char.meta.rasse)` (`src/lib/rules/races.ts`). New races must provide `lep_mod`, `asp_mod`, `aup_mod`, `mr_mod` so the engine keeps working.
- Sonderfertigkeiten / Vor- / Nachteile each have a typed table in `src/lib/rules/*.ts` and a getter (`getSonderfertigkeit`, …). Add new entries to the table; don't hard-code IDs in engine code.
### Schema & Migrations
- `CURRENT_SCHEMA_VERSION` lives in `src/lib/schema/version.ts`. Every persisted `Character` carries `schemaVersion` (a `z.literal`).
- When you change the character schema in a breaking way:
1. Bump `CURRENT_SCHEMA_VERSION`.
2. Update `migrateCharacter` in `src/lib/schema/version.ts` to migrate old payloads forward.
3. Update / add tests in `tests/engine/io.test.ts` (or a new test) covering the migration path.
- Importers (`src/lib/storage/io.ts`, `src/lib/import/helden.ts`) must run input through `migrateCharacter` before `parseCharacter`.
### Storage
- All DB access goes through `src/lib/storage/repo.ts`. Don't `import { db }` from components use `listCharacters`, `getCharacter`, `saveCharacter`, `deleteCharacter`, and the active-character helpers.
- The Dexie schema is in `src/lib/storage/db.ts`. Adding a new store or index requires bumping the Dexie `version(N)` and providing an upgrade function.
## Testing
- Test runner: Vitest (`npm test` / `npm run test:watch`). Config lives in `vite.config.ts` (`test.include` + `tests/setup.ts`).
- `tests/setup.ts` wires up `fake-indexeddb` so Dexie works in Node. Don't import real browser globals in tests.
- Add tests next to existing ones under `tests/engine/` for any new derivation, rules logic, or schema migration. Keep them deterministic (no real time/random unless seeded).
- When changing `engine/derived.ts`, re-check `tests/engine/derived.test.ts` because it pins the exact DSA 4.1 rounding (`Math.round` for AT/PA/FK/INI/MR, `Math.floor` for LeP base).
## Build & PWA Notes
- SPA mode: `adapter-static` with `fallback: 'index.html'` and `strict: false`. Don't introduce server-only endpoints (`+server.ts`, `+page.server.ts`) the app must build as a static bundle.
- Workbox precaches `client/**/*.{js,css,ico,png,svg,webp,woff,woff2}`. If you add new asset types that should be cached offline, extend `workbox.globPatterns` in `vite.config.ts`.
- `postinstall` runs `scripts/write-placeholder-icons.mjs` to generate placeholder PNGs. Real production icons should replace `static/icons/icon-192.png`, `icon-512.png`, and `maskable-512.png`.
## Things to Avoid
- Don't add server-rendered routes, server hooks, or anything that breaks `adapter-static`.
- Don't bypass Zod every external payload (import, future API) must go through `parseCharacter` (after migration).
- Don't hardcode rule data inside components; put it in `src/lib/rules/` so it can be reused and tested.
- Don't switch indentation, quote style, or trailing-comma policy Prettier owns formatting.
- Don't translate German domain vocabulary or rename attribute keys; existing data and tests depend on them.