Implement the 029-on-demand-bestiary feature that replaces the bundled XMM bestiary JSON with a compact search index (~350KB) and on-demand source loading, where users explicitly provide a URL or upload a JSON file to fetch full stat block data per source, which is then normalized and cached in IndexedDB (with in-memory fallback) so creature stat blocks load instantly on subsequent visits while keeping the app bundle small and never auto-fetching copyrighted content
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
76
specs/029-on-demand-bestiary/quickstart.md
Normal file
76
specs/029-on-demand-bestiary/quickstart.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Quickstart: On-Demand Bestiary with Pre-Indexed Search
|
||||
|
||||
**Feature**: 029-on-demand-bestiary
|
||||
**Date**: 2026-03-10
|
||||
|
||||
## What This Feature Does
|
||||
|
||||
Replaces the bundled full bestiary file (one source, ~1.3 MB of copyrighted content) with:
|
||||
1. A pre-shipped lightweight index (102 sources, 3,312 creatures, ~52 KB gzipped) for instant search and combatant creation
|
||||
2. On-demand fetching of full stat block data per source, cached in IndexedDB
|
||||
|
||||
## Key Changes
|
||||
|
||||
### Removed
|
||||
- `data/bestiary/xmm.json` — no longer shipped with the app
|
||||
|
||||
### New Files
|
||||
- `apps/web/src/adapters/bestiary-index-adapter.ts` — loads and parses the shipped index, converts compact format to domain types
|
||||
- `apps/web/src/adapters/bestiary-cache.ts` — IndexedDB cache adapter for fetched source data
|
||||
- `apps/web/src/components/source-fetch-prompt.tsx` — dialog prompting user to fetch/upload source data
|
||||
- `apps/web/src/components/source-manager.tsx` — UI for viewing and clearing cached sources
|
||||
|
||||
### Modified Files
|
||||
- `apps/web/src/hooks/use-bestiary.ts` — rewritten to search from index and look up creatures from cache
|
||||
- `apps/web/src/hooks/use-encounter.ts` — `addFromBestiary` accepts index entries (no fetch needed to add)
|
||||
- `apps/web/src/components/bestiary-search.tsx` — shows source display name in results
|
||||
- `apps/web/src/components/stat-block-panel.tsx` — triggers source fetch prompt when creature not cached
|
||||
- `packages/domain/src/creature-types.ts` — new `BestiaryIndexEntry` and `BestiaryIndex` types
|
||||
|
||||
### Unchanged
|
||||
- `apps/web/src/adapters/bestiary-adapter.ts` — normalization pipeline processes fetched data exactly as before
|
||||
- `apps/web/src/adapters/strip-tags.ts` — tag stripping unchanged
|
||||
- `apps/web/src/components/stat-block.tsx` — stat block rendering unchanged
|
||||
- `apps/web/src/persistence/encounter-storage.ts` — encounter persistence unchanged
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
index.json (shipped, static)
|
||||
↓ Vite JSON import
|
||||
bestiary-index-adapter.ts
|
||||
↓ BestiaryIndexEntry[]
|
||||
use-bestiary.ts (search, add)
|
||||
↓
|
||||
bestiary-search.tsx → use-encounter.ts (addFromBestiary)
|
||||
↓
|
||||
stat-block-panel.tsx
|
||||
↓ creatureId → source not cached?
|
||||
source-fetch-prompt.tsx
|
||||
↓ fetch URL or upload file
|
||||
bestiary-adapter.ts (normalizeBestiary — unchanged)
|
||||
↓ Creature[]
|
||||
bestiary-cache.ts (IndexedDB)
|
||||
↓
|
||||
stat-block.tsx (renders full stat block)
|
||||
```
|
||||
|
||||
## Development Commands
|
||||
|
||||
```bash
|
||||
pnpm check # Must pass before every commit
|
||||
pnpm test # Run all tests
|
||||
pnpm typecheck # TypeScript type checking
|
||||
pnpm --filter web dev # Dev server at localhost:5173
|
||||
```
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
- **Domain tests**: Pure function tests for new `BestiaryIndexEntry` type and any utility functions
|
||||
- **Adapter tests**: Test index parsing (compact → readable format), test IndexedDB cache operations (mock IndexedDB via fake-indexeddb)
|
||||
- **Component tests**: Not in scope (existing pattern — components tested via manual verification)
|
||||
- **Integration**: Verify search returns multi-source results, verify add-from-index flow, verify fetch→cache→display flow
|
||||
|
||||
## New Dependency
|
||||
|
||||
- `idb` — Promise-based IndexedDB wrapper (~1.5 KB gzipped). Used only in `bestiary-cache.ts`.
|
||||
Reference in New Issue
Block a user