# Quickstart: Roll Initiative ## Overview This feature adds dice-rolling to the encounter tracker. The initiative column uses a click-to-edit pattern: bestiary combatants without initiative show a d20 icon that rolls 1d20 + modifier on click; once set, the value displays as plain text (click to edit/clear). Manual combatants show "--" (click to type). A "Roll All" button in the top bar batch-rolls for all bestiary combatants that don't yet have initiative. ## Key Files to Touch ### Domain Layer (`packages/domain/src/`) 1. **`roll-initiative.ts`** (NEW) — Pure function: `rollInitiative(diceRoll: number, modifier: number) → number`. Validates dice roll range [1,20], returns `diceRoll + modifier`. 2. **`__tests__/roll-initiative.test.ts`** (NEW) — Tests for the pure function covering normal, boundary (1, 20), and negative modifier cases. ### Application Layer (`packages/application/src/`) 3. **`roll-initiative-use-case.ts`** (NEW) — Single combatant roll. Receives `(store, combatantId, diceRoll, getCreature)`. Looks up creature via `creatureId`, computes modifier via `calculateInitiative`, computes final value via `rollInitiative`, delegates to `setInitiative` domain function. 4. **`roll-all-initiative-use-case.ts`** (NEW) — Batch roll. Receives `(store, diceRolls: Map, getCreature)`. Iterates eligible combatants, applies `setInitiative` in sequence on evolving encounter state, saves once. ### Web Adapter (`apps/web/src/`) 5. **`components/d20-icon.tsx`** (NEW) — React component rendering the d20.svg inline. Accepts className for sizing. 6. **`components/combatant-row.tsx`** (MODIFY) — Add d20 button next to initiative input. Only shown when `combatant.creatureId` is defined. New prop: `onRollInitiative: (id: CombatantId) => void`. 7. **`components/turn-navigation.tsx`** (MODIFY) — Add "Roll All Initiative" d20 button in right section. New prop: `onRollAllInitiative: () => void`. 8. **`hooks/use-encounter.ts`** (MODIFY) — Add `rollInitiative(id)` and `rollAllInitiative()` callbacks that generate dice rolls via `Math.floor(Math.random() * 20) + 1` and call the respective use cases. 9. **`App.tsx`** (MODIFY) — Wire new callbacks to components. ## Architecture Pattern ``` [Browser Math.random()] → diceRoll (number 1-20) ↓ [Application Use Case] → looks up creature, computes modifier, calls domain ↓ [Domain rollInitiative()] → diceRoll + modifier = initiative value ↓ [Domain setInitiative()] → updates combatant, re-sorts encounter ↓ [Store.save()] → persists to localStorage ``` ## Running ```bash pnpm --filter web dev # Dev server at localhost:5173 pnpm test # Run all tests pnpm vitest run packages/domain/src/__tests__/roll-initiative.test.ts # Single test pnpm check # Full merge gate ```