75 lines
3.1 KiB
Markdown
75 lines
3.1 KiB
Markdown
# Quickstart: Bestiary Search & Stat Block Display
|
|
|
|
**Branch**: `021-bestiary-statblock` | **Date**: 2026-03-06
|
|
|
|
## What This Feature Does
|
|
|
|
Adds a searchable creature library (D&D 2024 Monster Manual) to the initiative tracker. Users can search for creatures by name, view their full stat block in a side panel, and add them as combatants with stats pre-filled (name, HP, AC). Multiple instances of the same creature are auto-numbered.
|
|
|
|
## Key Files to Touch
|
|
|
|
### New Files (Domain)
|
|
- `packages/domain/src/creature-types.ts` — Creature, CreatureId, TraitBlock, etc.
|
|
- `packages/domain/src/auto-number.ts` — Auto-numbering logic for duplicate creature names
|
|
|
|
### New Files (Web)
|
|
- `data/bestiary/xmm.json` — Raw 5etools bestiary data (bundled at build time)
|
|
- `apps/web/src/adapters/bestiary-adapter.ts` — Normalizes raw JSON to Creature[]
|
|
- `apps/web/src/adapters/strip-tags.ts` — Strips {@tag} markup to plain text
|
|
- `apps/web/src/hooks/use-bestiary.ts` — Provides search + creature lookup
|
|
- `apps/web/src/components/bestiary-search.tsx` — Search input with autocomplete dropdown
|
|
- `apps/web/src/components/stat-block.tsx` — Full creature stat block display
|
|
- `apps/web/src/components/stat-block-panel.tsx` — Side panel / drawer wrapper
|
|
|
|
### Modified Files
|
|
- `packages/domain/src/types.ts` — Add optional `creatureId` to Combatant
|
|
- `packages/domain/src/index.ts` — Export new creature types
|
|
- `apps/web/src/App.tsx` — Two-column layout + stat block panel state
|
|
- `apps/web/src/components/action-bar.tsx` — Add search icon + bestiary search integration
|
|
- `apps/web/src/hooks/use-encounter.ts` — Handle creatureId on add, auto-numbering
|
|
- `apps/web/src/persistence/encounter-storage.ts` — Persist/rehydrate creatureId
|
|
|
|
## Architecture Fit
|
|
|
|
```
|
|
data/bestiary/xmm.json (static asset)
|
|
|
|
|
v
|
|
bestiary-adapter.ts (web adapter) --normalizes--> Creature[] (domain types)
|
|
|
|
|
v
|
|
use-bestiary.ts (hook) --provides--> search + lookup
|
|
|
|
|
v
|
|
bestiary-search.tsx --selects creature--> use-encounter.ts --calls--> addCombatant (domain)
|
|
| |
|
|
v v
|
|
stat-block-panel.tsx <--reads creature data-- creatureId on Combatant
|
|
```
|
|
|
|
The domain layer gets the `Creature` type definitions and auto-numbering logic (pure functions). The web adapter handles the raw-to-domain transformation and tag stripping. The hook layer orchestrates search and state.
|
|
|
|
## Running & Testing
|
|
|
|
```bash
|
|
# Dev server
|
|
pnpm --filter web dev
|
|
|
|
# Run all tests
|
|
pnpm test
|
|
|
|
# Typecheck
|
|
pnpm typecheck
|
|
|
|
# Full merge gate
|
|
pnpm check
|
|
```
|
|
|
|
## Key Design Decisions
|
|
|
|
1. **Bundled JSON** — No runtime fetching, no database. JSON imported at build time.
|
|
2. **Pre-rendered text** — Tags stripped during normalization, not at render time.
|
|
3. **Creature type in domain** — Type definitions live in domain, normalization adapter lives in web.
|
|
4. **creatureId on Combatant** — Lightweight reference, not embedded creature data.
|
|
5. **Auto-numbering in domain** — Pure function that takes existing names and base name, returns resolved name.
|