Files

47 lines
4.5 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.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Overview
This renders printable D&D 5e spell reference cards for a specific character ("Oswin Eisenbach", a Forest Gnome Artificer). `index.html` is the static page (Tailwind CSS, Flowbite, and Google Fonts from CDNs, no build step), but spell data lives in JSON files under `characters/`, loaded at runtime via `fetch()`.
## Running / Previewing
`index.html` fetches JSON files, which browsers block on `file://` URLs (CORS). You must serve the directory:
```
python3 -m http.server
```
then open `http://localhost:8000/`. Opening `index.html` directly will not load any spells.
## Architecture
### `index.html`
1. **`<style>` block** — card visual design (`.spell-card`, `.card-header`, `.stat-row`, `.card-body`, `.card-footer`, `.level-flag`, etc.) plus per-school color theming via classes like `.school-conjuration`, `.school-evocation`, etc. (each sets `--school-col` / `--school-bg` CSS custom properties consumed by the card components). Also defines `@media print` rules and an `@page` rule (A4 portrait, 12mm margin, 3-column grid) so the page can be printed directly to physical cards sized at 2.5×3.5 in (240×336px at 96dpi, set via `--card-w`/`--card-h`).
2. **UI chrome** (`.ui-panel`) — toggle buttons to filter cards by spell level (`#type-filters`) and school (`#school-filters`), built dynamically from the loaded data, plus a "Print Cards" button that calls `window.print()`. Elements marked `.no-print` are hidden when printing. The card grid (`#card-grid`, also `.print-area`) is the same element in both screen and print view — print CSS just swaps it from a flex-wrap layout to a 3-column grid.
3. **Data + render logic** (final `<script>`):
- `CHARACTER_DIR` — path to the active character's data folder (currently `characters/oswin-eisenbach`).
- `loadSpells()` — fetches `manifest.json` for the character, then fetches every spell JSON file it lists, populates `SPELLS`, builds the filter buttons, and renders.
- `SPELLS` — array of spell objects, populated at runtime from JSON. Each spell has: `name`, `level` (`"cantrip"` or a numeric string like `"1"`), `levelDisplay`, `school`, `castingTime`, `range`, `components`, `duration`, optional `damage`/`saveDC`/`material`, `source` (book/page citation), `uses` (e.g. `"At Will"`, `"Spell Slot"`, `"2× / Long Rest"`), `tags` (array of short labels), and `desc` (array of HTML-containing paragraph strings — inline `<b>`/`<em>` tags are used for emphasis directly in the data).
- `SCHOOL_ABBR` — maps school name to a 2-letter abbreviation shown in the circular "pip" badge on each card.
- `buildCard(spell)` — returns the HTML string for one card, assembling stat chips, description paragraphs, tags, footer, and a corner `.level-flag` (grey "Cantrip" vs. gold "Lvl N Spell") from a spell object.
- `buildFilters(typeLabels)` — generates the type and school filter buttons after data loads, based on what's actually present.
- `renderCards()` — filters `SPELLS` by the current `activeType`/`activeSchool` globals and re-renders the `#card-grid` container.
- `filterType(btn, val)` / `filterSchool(btn, val)` — button click handlers that update filter state, toggle the `.active` class on buttons, and call `renderCards()`.
### `characters/<character-folder>/`
- `manifest.json``{ character, subtitle, types: [{ level, label, files: [...] }] }`. `level` is the folder name and matches the spell's `level` field (`"cantrip"`, `"1"`, `"2"`, ...); `files` lists the JSON filenames inside that level's folder, in display order.
- `<level>/<spell-slug>.json` — one spell per file, same shape as the spell objects described above (no `level`/`levelDisplay` redundancy issue — both are still included in the file since the card needs them).
## Adding/editing spells
To add a new spell, create a JSON file in the right `characters/<character>/<level>/` folder (create the folder if it's a new level) and add its filename to that level's `files` array in `manifest.json`. To add a new school, add both a `.school-<name>` CSS rule (lowercase school name) and an entry in `SCHOOL_ABBR` in `index.html` — filter buttons for schools and levels are generated automatically from whatever data loads.
To add a second character, create a new `characters/<folder>/` with its own `manifest.json` and level folders, then point `CHARACTER_DIR` in `index.html` at it (there is currently no in-page character switcher).