Implement the 018-combatant-concentration feature that adds a per-combatant concentration toggle with Brain icon, purple border accent, and damage pulse animation in the encounter tracker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-06 14:34:28 +01:00
parent febe892e15
commit e59fd83292
19 changed files with 779 additions and 7 deletions

View File

@@ -0,0 +1,45 @@
# Data Model: Combatant Concentration
**Feature**: 018-combatant-concentration | **Date**: 2026-03-06
## Entity Changes
### Combatant (modified)
| Field | Type | Required | Default | Notes |
|-------|------|----------|---------|-------|
| id | CombatantId | yes | - | Existing, unchanged |
| name | string | yes | - | Existing, unchanged |
| initiative | number | no | undefined | Existing, unchanged |
| maxHp | number | no | undefined | Existing, unchanged |
| currentHp | number | no | undefined | Existing, unchanged |
| ac | number | no | undefined | Existing, unchanged |
| conditions | ConditionId[] | no | undefined | Existing, unchanged |
| **isConcentrating** | **boolean** | **no** | **undefined (falsy)** | **New field. Independent of conditions.** |
### Domain Events (new)
| Event | Fields | Emitted When |
|-------|--------|-------------|
| ConcentrationStarted | `type`, `combatantId` | Concentration toggled from off to on |
| ConcentrationEnded | `type`, `combatantId` | Concentration toggled from on to off |
## State Transitions
```
toggleConcentration(encounter, combatantId)
├── combatant not found → DomainError("combatant-not-found")
├── isConcentrating is falsy → set to true, emit ConcentrationStarted
└── isConcentrating is true → set to undefined, emit ConcentrationEnded
```
## Validation Rules
- `combatantId` must reference an existing combatant in the encounter.
- No other validation needed (boolean toggle has no invalid input beyond missing combatant).
## Storage Impact
- **Format**: JSON via localStorage (existing adapter).
- **Migration**: None. Field is optional; absent field is treated as `false`.
- **Backward compatibility**: Old data loads without `isConcentrating`; new data with the field serializes/deserializes transparently.