47 lines
4.5 KiB
Markdown
47 lines
4.5 KiB
Markdown
# 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).
|