Starting an encounter meant searching for each party member by name, one at a time. The management view now carries an "Add party to encounter" button that puts all of them on the board in one click and closes, so the initiative list is what you see next. Members already in the encounter are skipped. Matching is on playerCharacterId, not on name — otherwise a second click would hand you "Thorin 2" via the auto-numbering, and renaming a combatant to match a mini (the reason the rename feature exists) would break the check. Rows for those members show a muted swords icon, and the button disables once nothing is left to add, so the greyed-out state has a visible cause. The whole batch pushes a single undo entry rather than one per combatant: undoing a four-person party should not take four keystrokes. That is why the reducer loops internally instead of the UI dispatching N times, and why addOneFromPlayerCharacter is now split out of the single-add handler for both paths to share. Spec 005 gains story PC-8, FR-020..FR-023, SC-010/SC-011 and the edge cases around partial parties, renamed combatants and orphaned ones. The existing "multiple copies of the same PC are allowed" edge case is marked as still true for individual adds — the party button is the deliberate exception. Key Entities now documents the combatant/PC link the dedup relies on, which had never been written down. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
305 lines
20 KiB
Markdown
305 lines
20 KiB
Markdown
# Feature Specification: Player Character Management
|
|
|
|
**Feature Branch**: `005-player-characters`
|
|
**Created**: 2026-03-12
|
|
**Status**: Draft
|
|
**Input**: User description: "Allow users to create and manage Player characters via the bottom bar. Each player character has a name, AC, max HP, a chosen color, and a preset icon. Player characters persist across sessions and are searchable when adding combatants to an encounter. A dedicated management view lets users edit and delete existing player characters."
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### Creating Player Characters
|
|
|
|
**Story PC-1 — Create a new player character (Priority: P1)**
|
|
|
|
A game master opens a "Create Player" modal from the bottom bar and fills in the character's name, AC, max HP, selects a color from a palette, and picks an icon from a preset grid. On saving, the player character is persisted and available for future encounters.
|
|
|
|
**Why this priority**: Creating player characters is the foundational action — nothing else in this feature works without it.
|
|
|
|
**Independent Test**: Can be fully tested by creating a player character and verifying it appears in the saved player list.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the bottom bar is visible, **When** the user clicks the "Create Player" icon button, **Then** a modal opens with fields for Name, AC, Max HP, a color palette, and an icon selection grid.
|
|
|
|
2. **Given** the create player modal is open, **When** the user fills in Name "Aragorn", AC 16, Max HP 120, selects the color green, and selects the shield icon, **Then** clicking save creates a player character with those attributes and closes the modal.
|
|
|
|
3. **Given** no player characters exist, **When** the user creates their first player character, **Then** it is persisted and appears in the player character list.
|
|
|
|
4. **Given** the create player modal is open, **When** the user submits with an empty name, **Then** a validation error is shown and the player character is not created.
|
|
|
|
5. **Given** the create player modal is open, **When** the user submits with a whitespace-only name, **Then** a validation error is shown and the player character is not created.
|
|
|
|
6. **Given** the create player modal is open, **When** the user clicks cancel or closes the modal, **Then** no player character is created and any entered data is discarded.
|
|
|
|
---
|
|
|
|
### Player Character Persistence
|
|
|
|
**Story PC-2 — Player characters survive page reload (Priority: P1)**
|
|
|
|
Player characters are long-lived entities that persist across browser sessions. Unlike encounter combatants which belong to a single encounter, player characters represent recurring party members that the GM reuses across many encounters.
|
|
|
|
**Why this priority**: Without persistence, users would need to recreate their party every session, defeating the purpose.
|
|
|
|
**Independent Test**: Can be tested by creating a player character, reloading the page, and verifying it still exists.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the user has created player characters, **When** the page is reloaded, **Then** all player characters are restored with their name, AC, max HP, color, and icon intact.
|
|
|
|
2. **Given** saved player character data is corrupt or malformed, **When** the page loads, **Then** the application starts with an empty player character list without crashing.
|
|
|
|
3. **Given** no saved player character data exists, **When** the page loads, **Then** the application starts with an empty player character list.
|
|
|
|
---
|
|
|
|
### Adding Player Characters to Encounters
|
|
|
|
**Story PC-3 — Search and add player characters as combatants (Priority: P1)**
|
|
|
|
When adding combatants to an encounter, the GM can search for their saved player characters by name. Selecting a player character adds it as a combatant with its saved stats (AC, max HP) pre-filled, along with its color and icon for visual identification.
|
|
|
|
**Why this priority**: This is the core value proposition — reusing pre-configured characters instead of re-entering stats every encounter.
|
|
|
|
**Independent Test**: Can be tested by creating a player character, then adding it to an encounter via the combatant search.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** player characters "Aragorn" and "Legolas" exist, **When** the user types "Ara" in the combatant search field, **Then** "Aragorn" appears in the search results alongside bestiary creatures.
|
|
|
|
2. **Given** player character "Aragorn" (AC 16, Max HP 120) exists, **When** the user selects "Aragorn" from search results, **Then** a combatant is added to the encounter with name "Aragorn", AC 16, max HP 120, current HP 120, and the player character's color and icon.
|
|
|
|
3. **Given** player character "Gandalf" exists, **When** the user adds "Gandalf" to two separate encounters (or the same encounter twice), **Then** each combatant is an independent copy — modifying one combatant's HP does not affect the other or the saved player character.
|
|
|
|
4. **Given** no player characters exist, **When** the user searches in the combatant search field, **Then** only bestiary creatures appear in results (no empty "Players" section is shown).
|
|
|
|
---
|
|
|
|
**Story PC-8 — Add the whole party to an encounter (Priority: P1)**
|
|
|
|
At the start of a session the GM wants the entire party in the initiative tracker. Instead of searching for each character by name, they open the player character management view and add every saved character to the encounter in one action.
|
|
|
|
**Why this priority**: Putting the party on the board is how nearly every encounter starts. Doing it one character at a time is the main friction in the setup flow.
|
|
|
|
**Independent Test**: Can be tested by creating several player characters, triggering the add-party action, and verifying every character is present as a combatant.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** player characters "Aragorn", "Legolas", and "Gimli" exist and none are in the encounter, **When** the user triggers the add-party action from the management view, **Then** a combatant is created for each of them, with the same stats, color, and icon an individual add would produce.
|
|
|
|
2. **Given** "Aragorn" is already a combatant in the encounter and "Legolas" is not, **When** the user triggers the add-party action, **Then** only "Legolas" is added — "Aragorn" gets no second copy and is not renamed.
|
|
|
|
3. **Given** the user has just added the party, **When** the user undoes once, **Then** every combatant created by that action is removed together.
|
|
|
|
4. **Given** every saved player character is already in the encounter, **When** the user opens the management view, **Then** the add-party action is unavailable and communicates why.
|
|
|
|
5. **Given** some player characters are already in the encounter, **When** the user opens the management view, **Then** those characters are marked as already present and the add-party action remains available for the rest.
|
|
|
|
6. **Given** no player characters exist, **When** the user opens the management view, **Then** the empty state is shown without an add-party action.
|
|
|
|
---
|
|
|
|
### Displaying Player Characters in Encounters
|
|
|
|
**Story PC-4 — Visual distinction for player character combatants (Priority: P2)**
|
|
|
|
Combatants originating from player characters display their chosen color and icon next to their name in the combatant row, making it easy to visually distinguish PCs from monsters at a glance.
|
|
|
|
**Why this priority**: Color and icon display enhances usability but the feature is functional without it.
|
|
|
|
**Independent Test**: Can be tested by adding a player character to an encounter and verifying the color and icon render in the combatant row.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a combatant was added from a player character with color green and the shield icon, **When** the combatant row is rendered, **Then** the player character's icon is displayed next to the name and the color is applied as a visual accent (e.g., colored border, background tint, or icon tint).
|
|
|
|
2. **Given** a combatant was added from the bestiary (not a player character), **When** the combatant row is rendered, **Then** no player character icon or color accent is shown.
|
|
|
|
---
|
|
|
|
### Managing Player Characters
|
|
|
|
**Story PC-5 — View all saved player characters (Priority: P2)**
|
|
|
|
The GM can access a dedicated management view to see all their saved player characters at a glance, with each character's name, AC, max HP, color, and icon displayed.
|
|
|
|
**Why this priority**: Management view is needed for editing and deleting, but basic create/add flow works without it.
|
|
|
|
**Independent Test**: Can be tested by creating several player characters and opening the management view to verify all are listed.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** player characters exist, **When** the user opens the player character management view, **Then** all saved player characters are listed showing their name, AC, max HP, color, and icon.
|
|
|
|
2. **Given** no player characters exist, **When** the user opens the management view, **Then** an empty state message is shown encouraging the user to create their first player character.
|
|
|
|
---
|
|
|
|
**Story PC-6 — Edit an existing player character (Priority: P2)**
|
|
|
|
The GM realizes a player character's stats have changed (e.g., level up) or wants to fix a typo. They open the management view and edit the character's attributes.
|
|
|
|
**Why this priority**: Editing is important for ongoing campaigns but the feature delivers value without it initially.
|
|
|
|
**Independent Test**: Can be tested by editing a player character's name and stats and verifying the changes persist.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** player character "Aragorn" exists, **When** the user edits "Aragorn" to change the name to "Strider" and AC to 18, **Then** the changes are saved and reflected in the player character list.
|
|
|
|
2. **Given** a player character is being edited, **When** the user submits with an empty name, **Then** a validation error is shown and the changes are not saved.
|
|
|
|
3. **Given** a player character is being edited, **When** the user cancels the edit, **Then** the original values are preserved.
|
|
|
|
4. **Given** a player character was previously added to an encounter as a combatant, **When** the player character is edited, **Then** existing combatants in the current encounter are not affected (they are independent copies).
|
|
|
|
---
|
|
|
|
**Story PC-7 — Delete a player character (Priority: P2)**
|
|
|
|
The GM no longer needs a player character and wants to remove it from their saved list.
|
|
|
|
**Why this priority**: Deletion keeps the list manageable but is not needed for core functionality.
|
|
|
|
**Independent Test**: Can be tested by deleting a player character and verifying it no longer appears in the list or search results.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** player character "Boromir" exists, **When** the user deletes "Boromir" with confirmation, **Then** the player character is removed from the saved list.
|
|
|
|
2. **Given** player character "Boromir" was previously added to the current encounter as a combatant, **When** the player character is deleted, **Then** the combatant in the encounter is not affected (it is an independent copy).
|
|
|
|
3. **Given** the delete action is initiated, **When** the user is asked to confirm, **Then** the confirmation follows the existing ConfirmButton two-step pattern (as defined in spec 001).
|
|
|
|
---
|
|
|
|
### Edge Cases
|
|
|
|
- **Duplicate player character names**: Permitted. Player characters are identified by a unique internal ID, not by name.
|
|
- **Adding the same player character to an encounter multiple times**: Each addition creates an independent combatant copy. Multiple copies of the same PC in one encounter are allowed. The add-party action is the deliberate exception — it skips characters that are already present (see PC-8).
|
|
- **Adding the party when part of it is already present**: Only the missing characters are added. Membership is determined by player character identity, not by name.
|
|
- **Adding the party after a PC-derived combatant was renamed**: The combatant is still recognised as that player character, so the party add does not produce a duplicate.
|
|
- **Adding the party after the source player character was deleted**: The orphaned combatant matches no saved character; it is left alone and the remaining party members add normally.
|
|
- **Editing a player character while it is also a combatant in the active encounter**: The active combatant is not affected; only future additions use the updated stats.
|
|
- **Deleting a player character while it is a combatant in the active encounter**: The combatant remains in the encounter unchanged.
|
|
- **Very long player character names**: The UI should truncate or ellipsize names that exceed the available space.
|
|
- **Browser storage quota exceeded**: Player character persistence silently fails; the current in-memory session continues.
|
|
- **Corrupt player character data on load**: The application discards corrupt data and starts with an empty player character list.
|
|
- **Color/icon rendering on different screen sizes**: Color and icon must remain visible and distinguishable at all supported viewport sizes.
|
|
- **Search ranking**: When searching, player characters should appear in a distinct group (e.g., "Players" section) above or alongside bestiary results to make them easy to find.
|
|
|
|
---
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
### Functional Requirements
|
|
|
|
#### FR-001 — Create: Modal via bottom bar
|
|
The system MUST provide an icon button in the bottom bar that opens a "Create Player" modal.
|
|
|
|
#### FR-002 — Create: Required fields
|
|
The create modal MUST include fields for Name (text), AC (number), and Max HP (number).
|
|
|
|
#### FR-003 — Create: Color selection
|
|
The create modal MUST include a color palette allowing the user to select one color from a predefined set of distinguishable colors.
|
|
|
|
#### FR-004 — Create: Icon selection
|
|
The create modal MUST include a grid of ~10-20 preset icons (e.g., sword, shield, skull, heart, wand) from which the user selects one.
|
|
|
|
#### FR-005 — Create: Name validation
|
|
Creating a player character MUST reject empty or whitespace-only names, showing a validation error.
|
|
|
|
#### FR-006 — Create: Unique identity
|
|
Each player character MUST be assigned a unique internal identifier on creation.
|
|
|
|
#### FR-007 — Persistence: Cross-session storage
|
|
Player characters MUST be persisted to browser storage and restored on page load.
|
|
|
|
#### FR-008 — Persistence: Independent from encounter storage
|
|
Player character storage MUST be separate from encounter storage — clearing an encounter does not affect saved player characters.
|
|
|
|
#### FR-009 — Persistence: Graceful degradation
|
|
The system MUST NOT crash when player character data is missing, corrupt, or storage is unavailable. It MUST fall back to an empty player character list.
|
|
|
|
#### FR-010 — Search: Player characters in combatant search
|
|
Player characters MUST appear in the combatant search results when the user searches for combatants to add to an encounter. Matching is by name substring.
|
|
|
|
#### FR-011 — Search: Distinct grouping
|
|
Player character results MUST be visually distinguishable from bestiary creature results in the search dropdown.
|
|
|
|
#### FR-012 — Add to encounter: Pre-filled stats
|
|
When a player character is added to an encounter as a combatant, the combatant MUST be created with the player character's name, AC, max HP, and current HP set to max HP.
|
|
|
|
#### FR-013 — Add to encounter: Color and icon association
|
|
When a combatant is created from a player character, the combatant MUST carry the player character's color and icon for display purposes.
|
|
|
|
#### FR-014 — Add to encounter: Independent copy
|
|
Combatants created from player characters MUST be independent copies. Changes to the combatant's stats during an encounter do not modify the saved player character, and vice versa.
|
|
|
|
#### FR-015 — Display: Color and icon in combatant row
|
|
Combatant rows for player-character-originating combatants MUST display the chosen icon and color accent.
|
|
|
|
#### FR-016 — Management: View all player characters
|
|
The system MUST provide a view listing all saved player characters with their name, AC, max HP, color, and icon.
|
|
|
|
#### FR-017 — Management: Edit player character
|
|
The system MUST allow editing a player character's name, AC, max HP, color, and icon. Edits MUST be persisted.
|
|
|
|
#### FR-018 — Management: Delete player character
|
|
The system MUST allow deleting a player character with two-step confirmation (ConfirmButton pattern from spec 001).
|
|
|
|
#### FR-019 — Management: Delete does not affect active combatants
|
|
Deleting a player character MUST NOT remove or modify any combatants currently in an encounter.
|
|
|
|
#### FR-020 — Add to encounter: Add the whole party
|
|
The management view MUST provide an action that adds all saved player characters to the current encounter in a single interaction.
|
|
|
|
#### FR-021 — Add to encounter: Party add skips present members
|
|
Adding the party MUST skip player characters that already have a combatant in the current encounter. Membership MUST be determined by player character identity, not by combatant name.
|
|
|
|
#### FR-022 — Add to encounter: Party add is one undo step
|
|
Adding the party MUST be reversible as a single undo step, regardless of how many combatants it created.
|
|
|
|
#### FR-023 — Management: Indicate encounter membership
|
|
The management view MUST indicate which saved player characters are already in the current encounter, and MUST disable the add-party action when none remain to be added.
|
|
|
|
### Key Entities
|
|
|
|
- **PlayerCharacter**: A persistent, reusable character template with a unique `PlayerCharacterId` (branded string), required `name`, `ac` (number), `maxHp` (number), `color` (string from predefined set), `icon` (string identifier from preset icon set), and optional `level` (integer 1-20, added by spec 008 for encounter difficulty calculation).
|
|
- **PlayerCharacterStore** (port): Interface for loading, saving, and deleting player characters. Implemented as a browser storage adapter.
|
|
- **Combatant → PlayerCharacter link**: A combatant created from a player character retains that character's `PlayerCharacterId`. The link drives display (color, icon) and encounter-membership detection (FR-021). It does not make the combatant a live view of the character — the combatant remains an independent copy (FR-014).
|
|
|
|
---
|
|
|
|
## Success Criteria *(mandatory)*
|
|
|
|
### Measurable Outcomes
|
|
|
|
- **SC-001**: Users can create a player character with name, AC, max HP, color, and icon in under 30 seconds.
|
|
- **SC-002**: Player characters persist across page reloads with all attributes intact.
|
|
- **SC-003**: Player characters appear in combatant search results and can be added to an encounter in a single selection.
|
|
- **SC-004**: Combatants created from player characters display their color and icon in the initiative tracker.
|
|
- **SC-005**: Users can edit any attribute of a saved player character and see the change persisted immediately.
|
|
- **SC-006**: Deleting a player character requires two deliberate user interactions (ConfirmButton pattern) and does not affect active encounter combatants.
|
|
- **SC-007**: All player character domain operations (create, edit, delete) are pure functions with no I/O, consistent with the project's deterministic domain core.
|
|
- **SC-008**: The player character domain module has zero imports from application, adapter, or UI layers.
|
|
- **SC-009**: Corrupt or missing player character data never causes a crash — the application gracefully falls back to an empty player character list.
|
|
- **SC-010**: Users can put their entire party into an encounter with one interaction, and reverse it with one undo — no matter how large the party is.
|
|
- **SC-011**: Repeating the add-party action never produces duplicate or auto-renamed copies of a player character already in the encounter.
|
|
|
|
---
|
|
|
|
## Assumptions
|
|
|
|
- Player character IDs are generated by the caller (application layer), keeping domain functions pure.
|
|
- The predefined color palette contains 8-12 visually distinct colors suitable for both light and dark backgrounds.
|
|
- The preset icon set uses Lucide React icons already available in the project, requiring no additional icon dependencies.
|
|
- Player characters are stored in a separate `localStorage` key from encounter data.
|
|
- Name validation trims whitespace; a name that is empty after trimming is invalid.
|
|
- Duplicate player character names are permitted — characters are distinguished by their unique ID.
|
|
- MVP baseline does not include importing/exporting player characters.
|
|
- MVP baseline does not include player-character-specific fields beyond name, AC, max HP, color, and icon (e.g., no class, level, or ability scores).
|
|
- MVP baseline does not include reordering player characters in the management view.
|
|
- The management view is accessible from the bottom bar or a dedicated UI affordance, separate from the encounter view.
|
|
- When a player character is added to an encounter, a snapshot of its current stats is copied — future edits to the player character do not retroactively update existing combatants.
|