# Quickstart: Combatant Concentration **Feature**: 018-combatant-concentration | **Date**: 2026-03-06 ## Overview This feature adds a per-combatant boolean `isConcentrating` state with a Brain icon toggle, a colored left border accent for visual identification, and a pulse animation when a concentrating combatant takes damage. ## Key Files to Modify ### Domain Layer 1. **`packages/domain/src/types.ts`** — Add `isConcentrating?: boolean` to `Combatant` interface. 2. **`packages/domain/src/events.ts`** — Add `ConcentrationStarted` and `ConcentrationEnded` event types to the `DomainEvent` union. 3. **`packages/domain/src/toggle-concentration.ts`** (new) — Pure function mirroring `toggle-condition.ts` pattern. 4. **`packages/domain/src/index.ts`** — Re-export new function and event types. ### Application Layer 5. **`packages/application/src/toggle-concentration-use-case.ts`** (new) — Thin orchestration following `toggle-condition-use-case.ts` pattern. 6. **`packages/application/src/index.ts`** — Re-export new use case. ### Web Adapter 7. **`apps/web/src/persistence/encounter-storage.ts`** — Add `isConcentrating` to combatant rehydration. 8. **`apps/web/src/hooks/use-encounter.ts`** — Add `toggleConcentration` callback. 9. **`apps/web/src/components/combatant-row.tsx`** — Add Brain icon toggle, left border accent, and pulse animation. 10. **`apps/web/src/App.tsx`** — Wire `onToggleConcentration` prop through to `CombatantRow`. ## Implementation Pattern Follow the existing `toggleCondition` pattern end-to-end: ``` Domain: toggleConcentration(encounter, combatantId) → { encounter, events } | DomainError App: toggleConcentrationUseCase(store, combatantId) → events | DomainError Hook: toggleConcentration = useCallback((id) => { ... toggleConcentrationUseCase(makeStore(), id) ... }) Component: onToggleConcentration(id)} /> ``` ## Testing Strategy - **Domain tests**: `toggle-concentration.test.ts` — toggle on/off, combatant not found, immutability, correct events emitted. - **UI behavior**: Manual verification of hover show/hide, tooltip, left border accent, pulse animation on damage. ## Key Decisions - Concentration is **not** a condition — it has its own boolean field and separate UI treatment. - Pulse animation uses **CSS keyframes** triggered by transient React state, not a domain event. - Damage detection for pulse uses **HP comparison** in the component (prevHp vs currentHp), not domain events. - No localStorage migration needed — optional boolean field is backward-compatible.