Files
Lukas 91703ddebc
All checks were successful
CI / check (push) Successful in 45s
CI / build-image (push) Successful in 18s
Add player character management feature
Persistent player character templates (name, AC, HP, color, icon) with
full CRUD, bestiary-style search to add PCs to encounters with pre-filled
stats, and color/icon visual distinction in combatant rows. Also stops
the stat block panel from auto-opening when adding a creature.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 18:11:08 +01:00

5.2 KiB

Implementation Plan: Player Character Management

Branch: 005-player-characters | Date: 2026-03-12 | Spec: spec.md Input: Feature specification from /specs/005-player-characters/spec.md

Summary

Add persistent player character templates with name, AC, max HP, color, and icon. Player characters are stored independently from encounters and appear in the combatant search dropdown. When added to an encounter, a combatant is created as an independent snapshot with the player character's stats, color, and icon. A management view allows editing and deleting saved characters.

Technical Context

Language/Version: TypeScript 5.8 (strict mode, verbatimModuleSyntax) Primary Dependencies: React 19, Vite 6, Tailwind CSS v4, Lucide React Storage: localStorage (new key "initiative:player-characters") Testing: Vitest (unit tests for domain, persistence rehydration) Target Platform: Web browser (single-page app, no routing) Project Type: Web application (monorepo: domain → application → web adapter) Performance Goals: Instant load (synchronous localStorage), <16ms search on small list Constraints: Local-first, single-user, offline-capable Scale/Scope: Typical party size 3-8 player characters

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

Principle Status Notes
I. Deterministic Domain Core PASS All PC operations are pure functions, no I/O
II. Layered Architecture PASS Domain types/functions → Application use cases/ports → Web adapters/hooks/components
III. Clarification-First PASS No non-trivial assumptions; all decisions documented in research.md
IV. Escalation Gates PASS Feature has its own spec; cross-feature impacts (Combatant type extension) are documented
V. MVP Baseline Language PASS Exclusions use "MVP baseline does not include" language
VI. No Gameplay Rules PASS No game mechanics in spec or plan

Post-Phase 1 re-check: PASS. Data model uses pure domain types. Color/icon are constrained string sets validated in domain. Storage adapter follows existing localStorage pattern.

Project Structure

Documentation (this feature)

specs/005-player-characters/
├── plan.md              # This file
├── spec.md              # Feature specification
├── research.md          # Phase 0: technical decisions
├── data-model.md        # Phase 1: entity definitions
├── quickstart.md        # Phase 1: implementation guide
├── contracts/
│   └── ui-contracts.md  # Phase 1: UI component contracts
├── checklists/
│   └── requirements.md  # Spec quality checklist
└── tasks.md             # Phase 2 output (/speckit.tasks)

Source Code (repository root)

packages/domain/src/
├── player-character-types.ts    # NEW: PlayerCharacterId, PlayerCharacter, PlayerColor, PlayerIcon
├── create-player-character.ts   # NEW: Pure create function
├── edit-player-character.ts     # NEW: Pure edit function
├── delete-player-character.ts   # NEW: Pure delete function
├── types.ts                     # MODIFIED: Add color?, icon?, playerCharacterId? to Combatant
├── events.ts                    # MODIFIED: Add PC domain events to union
├── index.ts                     # MODIFIED: Re-export new types/functions
└── __tests__/
    ├── create-player-character.test.ts  # NEW
    ├── edit-player-character.test.ts    # NEW
    └── delete-player-character.test.ts  # NEW

packages/application/src/
├── ports.ts                              # MODIFIED: Add PlayerCharacterStore
├── create-player-character-use-case.ts   # NEW
├── edit-player-character-use-case.ts     # NEW
├── delete-player-character-use-case.ts   # NEW
└── index.ts                              # MODIFIED: Re-export

apps/web/src/
├── persistence/
│   ├── player-character-storage.ts       # NEW: localStorage adapter
│   ├── encounter-storage.ts              # MODIFIED: Handle new Combatant fields
│   └── __tests__/
│       └── player-character-storage.test.ts  # NEW
├── hooks/
│   └── use-player-characters.ts          # NEW: React state + persistence
├── components/
│   ├── create-player-modal.tsx           # NEW: Create/edit modal
│   ├── player-management.tsx             # NEW: List/edit/delete view
│   ├── color-palette.tsx                 # NEW: Color selection grid
│   ├── icon-grid.tsx                     # NEW: Icon selection grid
│   ├── action-bar.tsx                    # MODIFIED: Add "Players" section to dropdown
│   └── combatant-row.tsx                 # MODIFIED: Render color/icon
└── App.tsx                               # MODIFIED: Wire usePlayerCharacters

Structure Decision: Follows existing monorepo layered architecture. New domain files for player character operations, new application use cases, new web adapter/hook/components. Modified files extend existing types and UI.

Complexity Tracking

No constitution violations. No complexity justification needed.