--- phase: 01-grundger-st-tippmechanik plan: 05 type: execute wave: 4 depends_on: ["01-02", "01-04"] files_modified: - src/ui/screens.ts - src/forest/scene.ts - index.html - src/styles/main.css - src/app.ts autonomous: false requirements: - FRST-04 - FRST-05 must_haves: truths: - "Wald-Uebersicht zeigt Stufenkarte mit Status locked/current/completed" - "Weiter-ueben-Button startet die naechste offene Stufe" - "Nach Lesson-Abschluss kehrt die App zur Wald-Uebersicht zurueck und zeigt aktualisierten Status" - "Gesamter Flow funktioniert: Welcome -> Forest -> Lesson -> Forest (mit Fortschritt)" artifacts: - path: "src/forest/scene.ts" provides: "Forest overview with level map" exports: ["initForestScreen", "renderLevelMap"] key_links: - from: "src/forest/scene.ts" to: "src/storage/db.ts" via: "loads progress to determine level statuses" pattern: "getProgress" - from: "src/forest/scene.ts" to: "src/game/levels.ts" via: "reads level definitions for the map" pattern: "import.*levels" - from: "src/forest/scene.ts" to: "src/app.ts" via: "calls startLesson when user clicks a level or continue button" pattern: "startLesson|navigateTo" --- Build the forest overview screen with the level map (Stufenkarte) showing locked/current/completed states, and wire together the complete app flow: welcome -> forest -> lesson -> forest. Purpose: This is the final integration plan that connects all pieces into a playable app. The user can see their progress and start lessons from the forest screen. Output: Complete playable Phase 1 app with the core loop working end-to-end. @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/phases/01-grundger-st-tippmechanik/01-CONTEXT.md @.planning/phases/01-grundger-st-tippmechanik/01-01-SUMMARY.md @.planning/phases/01-grundger-st-tippmechanik/01-02-SUMMARY.md @.planning/phases/01-grundger-st-tippmechanik/01-03-SUMMARY.md @.planning/phases/01-grundger-st-tippmechanik/01-04-SUMMARY.md @SPEC.md (section 7.1 for screen structure) From src/types.ts: ```typescript export type LevelStatus = 'locked' | 'current' | 'completed'; export type ScreenName = 'welcome' | 'forest' | 'lesson' | 'reward' | 'parent'; export interface Progress { id: 1; currentLevel: number; completedLevels: number[]; totalSessions: number; sessionDates: string[]; selectedCharacter: CompanionType; selectedLayout: KeyboardLayout; } ``` From src/game/levels.ts: ```typescript export const levels: Level[]; ``` From src/app.ts: ```typescript export function showScreen(name: ScreenName): void; export function getDB(): IDBDatabase; ``` From src/storage/db.ts: ```typescript export async function getProgress(db: IDBDatabase): Promise; ``` Task 1: Forest screen with level map and continue button src/forest/scene.ts, index.html, src/styles/main.css src/types.ts src/game/levels.ts src/storage/db.ts src/app.ts src/ui/screens.ts index.html src/styles/main.css 1. Update index.html — populate forest screen: ```html

Dein Zauberwald

``` 2. Create src/forest/scene.ts: ```typescript import type { Progress, LevelStatus, ScreenName } from '../types'; import { levels } from '../game/levels'; import { getProgress } from '../storage/db'; export function getLevelStatus(levelNum: number, progress: Progress): LevelStatus { if (progress.completedLevels.includes(levelNum)) return 'completed'; if (levelNum === progress.currentLevel) return 'current'; return 'locked'; } export function renderLevelMap( container: HTMLElement, progress: Progress, onLevelClick: (level: number) => void ): void { container.innerHTML = ''; levels.forEach(level => { const status = getLevelStatus(level.level, progress); const card = document.createElement('button'); card.className = `level-card level-card--${status}`; card.dataset.level = String(level.level); const statusEmoji = status === 'completed' ? '✓' : status === 'current' ? '→' : '🔒'; const keysDisplay = level.newKeys .filter(k => k !== ' ') .map(k => k.toUpperCase()) .join(' '); card.innerHTML = ` Stufe ${level.level} ${keysDisplay}${level.newKeys.includes(' ') ? ' + Leertaste' : ''} ${statusEmoji} `; // Only current and completed levels are clickable if (status !== 'locked') { card.addEventListener('click', () => onLevelClick(level.level)); } else { card.disabled = true; } container.appendChild(card); }); } export async function initForestScreen( db: IDBDatabase, onStartLesson: (level: number) => void ): Promise { const mapContainer = document.getElementById('level-map')!; const continueBtn = document.getElementById('continue-btn') as HTMLButtonElement; const progress = await getProgress(db); if (!progress) return; renderLevelMap(mapContainer, progress, onStartLesson); // Continue button starts the current level continueBtn.onclick = () => onStartLesson(progress.currentLevel); } ``` 3. Update src/app.ts to wire the complete flow: - Import `initForestScreen` from `./forest/scene` - Import `initLessonScreen` from `./ui/screens` - In `initApp()`: after checking progress, if user exists, call `initForestScreen(db, startLesson)` before showing forest screen - `startLesson(level)` function: show lesson screen, call initLessonScreen with onComplete callback - `onComplete` callback: update progress (add to completedLevels, increment currentLevel if applicable, increment totalSessions, add today's date), save to DB, re-init forest screen, show forest screen - After welcome screen's "Los geht's" navigates to forest: also call initForestScreen The full flow is: - First visit: Welcome -> select companion/layout -> "Los geht's" -> Forest (level 1 = current) - Click "Weiter ueben" or level 1 card -> Lesson screen (type letters) - Complete lesson -> Forest (level 1 = completed, level 2 = current) - Reload -> Forest (skips welcome, shows current state) 4. Add CSS for forest and level map to src/styles/main.css: ```css .forest { display: flex; flex-direction: column; align-items: center; padding: 2rem; min-height: 100vh; background: var(--bg-forest); } .forest__title { font-family: 'Quicksand', sans-serif; font-size: 2rem; color: var(--text-dark); margin-bottom: 1.5rem; } .forest__level-map { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; max-width: 500px; width: 100%; margin-bottom: 2rem; } .level-card { display: flex; flex-direction: column; align-items: center; gap: 0.3rem; padding: 1rem; border-radius: 12px; border: 2px solid transparent; font-family: 'Nunito', sans-serif; cursor: pointer; transition: transform 0.2s ease, border-color 0.2s ease; background: white; } .level-card:hover:not(:disabled) { transform: scale(1.05); } .level-card--current { border-color: var(--accent-gold); background: #FFF8E0; box-shadow: 0 2px 8px rgba(232, 184, 75, 0.3); } .level-card--completed { border-color: var(--accent-green); background: #E8F5E4; } .level-card--locked { opacity: 0.5; cursor: not-allowed; background: #f0f0f0; } .level-card__number { font-weight: 700; font-size: 0.9rem; color: var(--text-dark); } .level-card__keys { font-family: 'Quicksand', sans-serif; font-weight: 600; font-size: 1.1rem; color: var(--accent-purple); } .level-card__status { font-size: 1.2rem; } .forest__continue-btn { padding: 1rem 3rem; border-radius: 12px; background: var(--accent-green); color: white; border: none; font-family: 'Quicksand', sans-serif; font-weight: 700; font-size: 1.3rem; cursor: pointer; transition: transform 0.2s ease; } .forest__continue-btn:hover { transform: scale(1.05); } ```
cd /home/dev/workspace/zauberwald && npx tsc --noEmit && npx vitest run - src/forest/scene.ts exports `initForestScreen`, `renderLevelMap`, `getLevelStatus` - src/forest/scene.ts contains `getLevelStatus` returning 'completed', 'current', or 'locked' - src/forest/scene.ts creates 6 level cards with class `level-card` - src/forest/scene.ts contains `level-card--${status}` for dynamic CSS class - index.html contains `id="level-map"` and `id="continue-btn"` - src/app.ts calls `initForestScreen` and `initLessonScreen` in the correct flow - src/app.ts has lesson completion handler that calls `saveProgress` with updated `completedLevels` and `currentLevel` - src/styles/main.css contains `.level-card--current`, `.level-card--completed`, `.level-card--locked` - src/styles/main.css contains `.forest__continue-btn` - `npx tsc --noEmit` exits 0 - `npx vitest run` exits 0 Forest screen shows 6-level map with correct statuses, continue button starts current level, level cards are clickable for completed/current levels, complete app flow works end-to-end
Task 2: Verify complete Phase 1 app flow no files modified (verification only) Human verifies the complete Phase 1 app flow in the browser. No code changes in this task. Open the app at http://vps-ip:5173 and verify these 7 steps: 1. Welcome screen: 4 companion cards with emojis and DE/CH toggle visible. Select a companion, click "Los geht's". 2. Forest overview: Level map shows Stufe 1 as current (gold border), Stufen 2-6 as locked (grayed). "Weiter ueben" button visible. 3. Click "Weiter ueben": Lesson screen appears with a large letter (F, J, or space symbol) and QWERTZ keyboard below. Target key pulses on keyboard. 4. Type the shown letter: Letter dissolves, next letter appears. Type all 8-12 letters correctly. 5. After completion: Returns to forest. Stufe 1 now shows checkmark, Stufe 2 is current (gold). 6. Reload the page: Skips welcome, goes directly to forest with preserved state. 7. Wrong key test: During a lesson, press a wrong key — nothing happens to the letter, correct key continues pulsing. cd /home/dev/workspace/zauberwald && npx tsc --noEmit && npx vitest run && echo "ALL AUTOMATED CHECKS PASS" - All 7 manual verification steps pass in browser - `npx tsc --noEmit` exits 0 - `npx vitest run` exits 0 Human confirmed all 7 verification steps pass: welcome flow, forest map, lesson typing, level progression, persistence across reload, correct error handling
- Complete flow: Welcome -> Forest -> Lesson -> Forest works - Level map shows correct statuses after completing a level - Typing exercise handles correct/wrong input per spec - Progress persists across page reloads - Keyboard shows finger colors for learned keys, gray for unlearned - All tests pass: `npx vitest run` - TypeScript compiles: `npx tsc --noEmit` - Forest overview shows 6 levels with locked/current/completed states - "Weiter ueben" button starts the current level's typing exercise - After completing a lesson, level status updates correctly - Full app loop is playable from fresh start through at least level 1 completion - Progress survives browser reload After completion, create `.planning/phases/01-grundger-st-tippmechanik/01-05-SUMMARY.md`