Files
dsa-ranger/AGENTS.md
T
2026-05-16 18:59:34 +02:00

7.1 KiB
Raw Blame History

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.