---
phase: 03-komplettes-spielerlebnis
plan: 02
type: execute
wave: 2
depends_on: [03-01]
files_modified:
  - src/game/typing.ts
  - src/game/typing.test.ts
  - src/ui/screens.ts
  - index.html
autonomous: true
requirements: [TYPE-05, TYPE-06, TYPE-07, LEVL-05, LEVL-06]
must_haves:
  truths:
    - "Entdecken phase shows companion text and highlights the new key on keyboard"
    - "Woerter phase displays whole words with active letter highlighted"
    - "Lesson flows through discover -> practice -> words automatically"
    - "Every 3rd session is a review mixing letters from last 2-3 levels"
    - "After 2x same level, companion shows encouragement with curiosity trigger"
  artifacts:
    - path: "src/game/typing.ts"
      provides: "Extended createExerciseState with mode='letters'|'words', generateWordLetters()"
      exports: ["createExerciseState", "generateWordLetters"]
    - path: "src/ui/screens.ts"
      provides: "Lesson sub-phase state machine: discover -> practice -> words"
      contains: "LessonPhase"
  key_links:
    - from: "src/ui/screens.ts"
      to: "src/game/typing.ts"
      via: "createExerciseState for practice and word phases"
      pattern: "createExerciseState"
    - from: "src/ui/screens.ts"
      to: "src/companion/companion.ts"
      via: "getLetterIntro for discover phase"
      pattern: "getLetterIntro"
    - from: "src/ui/screens.ts"
      to: "src/game/words.ts"
      via: "getWordsForLevel for word phase"
      pattern: "getWordsForLevel"
---

<objective>
Build the complete lesson flow with 3 sub-phases (Entdecken -> Ueben -> Woerter) as an internal state machine, plus review mechanic and repetition protection.

Purpose: This is the core game loop — the child experiences discover, practice, then words in one fluid session.
Output: Extended typing engine with word mode, lesson screen with 3-phase state machine, review and repetition logic.
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/03-komplettes-spielerlebnis/03-01-SUMMARY.md
@src/game/typing.ts
@src/ui/screens.ts
@src/companion/companion.ts
@src/game/words.ts
@src/game/levels.ts
@src/types.ts
@index.html

<interfaces>
<!-- From src/types.ts (after Plan 01): -->
export type LessonPhase = 'discover' | 'practice' | 'words';
export interface Progress {
  id: 1;
  currentLevel: number;
  completedLevels: number[];
  totalSessions: number;
  sessionDates: string[];
  selectedCharacter: CompanionType;
  selectedLayout: KeyboardLayout;
  totalCorrect: number;
  totalErrors: number;
  errorKeyCounts: Record<string, number>;
  lastPlayedLevels: number[];
}

<!-- From src/game/words.ts (after Plan 01): -->
export const wordsByLevel: Record<number, string[]>;
export function getWordsForLevel(level: number, count: number): string[];

<!-- From src/companion/companion.ts (existing): -->
export async function getLetterIntro(characterType: CompanionType, letter: string, fingerDescription: string, db: IDBDatabase): Promise<string>;

<!-- From src/game/typing.ts (existing): -->
export function createExerciseState(level: number): TypingExerciseState;
export function handleKeyPress(state: TypingExerciseState, pressedKey: string): KeyPressResult;
export function getCurrentLetter(state: TypingExerciseState): string | null;

<!-- From src/game/levels.ts (existing): -->
export function getLevelByNumber(n: number): Level | undefined;
export function getKeysUpToLevel(n: number): string[];
</interfaces>
</context>

<tasks>

<task type="auto" tdd="true">
  <name>Task 1: Extend typing engine with word mode</name>
  <files>src/game/typing.ts, src/game/typing.test.ts</files>
  <read_first>src/game/typing.ts, src/game/words.ts, src/types.ts</read_first>
  <behavior>
    - Test: createExerciseState(level) still works as before (letters mode, backwards compatible)
    - Test: createWordExerciseState(level, words) creates state with letters from the words joined, e.g. words=["eis","die"] -> letters=["e","i","s","d","i","e"]
    - Test: createWordExerciseState stores words and wordBoundaries in state for UI rendering
    - Test: handleKeyPress works the same way for word-mode state
    - Test: getWordAtIndex(state, letterIndex) returns which word the letter belongs to
  </behavior>
  <action>
    Extend `src/game/typing.ts` (per D-03):

    1. Add `ExerciseMode` type: `'letters' | 'words'`

    2. Extend `TypingExerciseState` interface (in types.ts) with optional word fields:
       ```typescript
       export interface TypingExerciseState {
         currentLetterIndex: number;
         letters: string[];
         intervalMs: number;
         correctStreak: number;
         totalCorrect: number;
         totalErrors: number;
         mode: 'letters' | 'words';
         words?: string[];           // original words for display
         wordBoundaries?: number[];  // indices where each word starts in letters[]
       }
       ```

    3. Keep existing `createExerciseState(level)` unchanged but set `mode: 'letters'`, `words: undefined`, `wordBoundaries: undefined`.

    4. Add new function:
       ```typescript
       export function createWordExerciseState(words: string[]): TypingExerciseState {
         const letters: string[] = [];
         const wordBoundaries: number[] = [];
         for (const word of words) {
           wordBoundaries.push(letters.length);
           for (const ch of word) {
             letters.push(ch);
           }
         }
         return {
           currentLetterIndex: 0,
           letters,
           intervalMs: 0, // no falling in word mode
           correctStreak: 0,
           totalCorrect: 0,
           totalErrors: 0,
           mode: 'words',
           words,
           wordBoundaries,
         };
       }
       ```

    5. Add helper: `getCurrentWordIndex(state: TypingExerciseState): number` — returns which word index (0-based) the currentLetterIndex is in, using wordBoundaries.

    6. `handleKeyPress` already works generically — no changes needed.

    Create `src/game/typing.test.ts` (or extend if exists) with vitest tests for the new functions plus backwards compatibility.
  </action>
  <verify>
    <automated>npx vitest run src/game/typing.test.ts</automated>
  </verify>
  <acceptance_criteria>
    - grep "createWordExerciseState" src/game/typing.ts returns export
    - grep "getCurrentWordIndex" src/game/typing.ts returns export
    - grep "mode.*letters.*words" src/types.ts returns match showing mode field
    - npx vitest run src/game/typing.test.ts exits 0
  </acceptance_criteria>
  <done>Typing engine supports word mode with word boundaries tracking. Backwards compatible with letter mode. Tests pass.</done>
</task>

<task type="auto">
  <name>Task 2: Lesson screen 3-phase state machine with review and repetition</name>
  <files>src/ui/screens.ts, index.html</files>
  <read_first>src/ui/screens.ts, src/game/typing.ts, src/companion/companion.ts, src/game/words.ts, src/game/levels.ts, src/types.ts, index.html</read_first>
  <action>
    Rewrite `initLessonScreen` in `src/ui/screens.ts` as a 3-phase state machine (per D-01, D-02, D-03):

    **Add to index.html** inside `#screen-lesson .lesson`:
    ```html
    <div class="lesson__phase-indicator" id="lesson-phase-indicator"></div>
    ```
    This shows which phase is active (Entdecken / Ueben / Woerter). Add above the letter-area.

    **Signature change:**
    ```typescript
    export function initLessonScreen(
      db: IDBDatabase,
      level: number,
      layout: KeyboardLayout,
      onComplete: (level: number, stats: { totalCorrect: number; totalErrors: number; errorKeys: Record<string, number> }) => void,
      onCancel?: () => void,
    ): () => void
    ```
    The `onComplete` callback now receives exercise stats (per D-16).

    **State machine flow:**

    1. **DISCOVER phase** (per D-02, TYPE-05):
       - Show phase indicator: "Entdecken"
       - Get the first new key of this level via `getLevelByNumber(level).newKeys[0]`
       - Fetch companion letter intro via `getLetterIntro(characterType, letter, fingerDescription, db)`
       - Display intro text in `#lesson-companion-text`
       - Highlight the target key on keyboard (already have `highlightKey()`)
       - Make key pulse (add class `keyboard__key--discover-pulse` to the key)
       - Wait for child to press the correct key ONCE to proceed
       - If level has a second newKey, repeat discover for that key too
       - Then transition to PRACTICE

    2. **PRACTICE phase** (existing behavior, TYPE-01-04):
       - Show phase indicator: "Ueben"
       - Run existing letter exercise with `createExerciseState(level)`
       - On complete, accumulate stats, transition to WORDS

    3. **WORDS phase** (per D-03, TYPE-06):
       - Show phase indicator: "Woerter"
       - Get 3-4 random words via `getWordsForLevel(level, 4)` (fallback to 3 if < 4 available)
       - Create word exercise via `createWordExerciseState(words)`
       - Display current word fully, highlight active letter:
         ```html
         <div class="word-display">
           <span class="word-display__letter word-display__letter--done">e</span>
           <span class="word-display__letter word-display__letter--active">i</span>
           <span class="word-display__letter">s</span>
         </div>
         ```
       - When word complete, show next word. After all words done, call `onComplete(level, stats)`.

    **Review mechanic (per D-05, LEVL-05):**
    Add `isReviewSession` parameter to `initLessonScreen`. When `true`:
    - Discover phase: skip (reviews don't introduce new letters)
    - Practice phase: use mixed letters from last 2-3 levels (combine allKeys from current and previous 1-2 levels)
    - Words phase: pick words from last 2-3 levels randomly

    The review trigger logic (`totalSessions % 3 === 0`) is handled in `app.ts` (Plan 04), not here. This function just needs to accept the `isReview: boolean` flag.

    **Repetition protection (per D-06, LEVL-06):**
    Add `showEncouragement` parameter. When `true`:
    - Before discover phase, show companion encouragement text: a hardcoded array of 3-4 messages like "Magst du sehen, was als Naechstes kommt? Im Wald gibt es noch so viel zu entdecken!"
    - Show for 3 seconds, then proceed to discover (or practice if review).

    The trigger logic (checking `lastPlayedLevels` for 2x same) is handled in `app.ts` (Plan 04).

    **Cumulative stats across phases:**
    Track `totalCorrect`, `totalErrors`, `errorKeys: Record<string, number>` across all 3 phases. In handleKeyPress wrapper, if `!result.correct`, increment `errorKeys[expectedKey]`. Pass accumulated stats to `onComplete`.

    **CSS for phase indicator** — add styles in action:
    ```css
    .lesson__phase-indicator {
      text-align: center;
      font-family: var(--font-heading);
      font-size: 1rem;
      color: var(--text-warm);
      margin-bottom: 0.5rem;
      opacity: 0.7;
    }
    ```

    **CSS for word display:**
    ```css
    .word-display {
      display: flex;
      justify-content: center;
      gap: 0.25rem;
      font-family: var(--font-heading);
      font-size: 2.5rem;
      margin: 2rem 0;
    }
    .word-display__letter {
      color: var(--text-light);
      transition: color 0.3s;
    }
    .word-display__letter--active {
      color: var(--accent-gold);
      font-weight: 700;
    }
    .word-display__letter--done {
      color: var(--accent-green);
    }
    ```

    Add CSS for discover pulse:
    ```css
    .keyboard__key--discover-pulse {
      animation: discover-pulse 1.5s ease-in-out infinite;
    }
    @keyframes discover-pulse {
      0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 var(--accent-gold); }
      50% { transform: scale(1.1); box-shadow: 0 0 12px 4px var(--accent-gold); }
    }
    ```
  </action>
  <verify>
    <automated>npx tsc --noEmit && npx vitest run</automated>
  </verify>
  <acceptance_criteria>
    - grep "lesson-phase-indicator" index.html returns a match
    - grep "discover.*practice.*words" src/ui/screens.ts shows state machine phases
    - grep "getLetterIntro" src/ui/screens.ts shows companion integration in discover
    - grep "createWordExerciseState" src/ui/screens.ts shows word mode usage
    - grep "getWordsForLevel" src/ui/screens.ts shows word list integration
    - grep "isReview" src/ui/screens.ts shows review parameter
    - grep "showEncouragement" src/ui/screens.ts shows repetition protection parameter
    - grep "word-display" src/styles/main.css returns CSS matches
    - grep "discover-pulse" src/styles/main.css returns CSS matches
    - npx tsc --noEmit exits 0
  </acceptance_criteria>
  <done>Lesson screen runs 3 phases (discover->practice->words) with companion letter intro, word display UI, review flag support, and repetition encouragement. Stats accumulated across phases and passed to onComplete callback.</done>
</task>

</tasks>

<verification>
- `npx tsc --noEmit` — no type errors
- `npx vitest run` — all tests pass
- Manual: lesson screen shows phase indicator, discover phase displays companion text and highlights key, words phase shows word with active letter
</verification>

<success_criteria>
1. Typing engine has createWordExerciseState() and getCurrentWordIndex()
2. Lesson screen flows: discover -> practice -> words -> onComplete(level, stats)
3. Discover phase: companion introduces letter, key pulses, child presses once to proceed
4. Words phase: 3-4 words displayed with active letter highlighted, typed letter by letter
5. Review flag skips discover and mixes letters/words from recent levels
6. Encouragement shown when showEncouragement=true
7. Stats (correct, errors, errorKeys) accumulated and passed to onComplete
</success_criteria>

<output>
After completion, create `.planning/phases/03-komplettes-spielerlebnis/03-02-SUMMARY.md`
</output>
