---
phase: 05-multi-wald-system
plan: 02
type: execute
wave: 2
depends_on:
  - 05-01
files_modified:
  - src/forest/scene.ts
  - src/forest/reward.ts
  - src/app.ts
autonomous: false
requirements:
  - MWLD-05
  - MWLD-06
  - MWLD-07

must_haves:
  truths:
    - "Kind kann mit Pfeiltasten zwischen Waldseiten navigieren"
    - "Aktuelle Waldseite wird in Progress gespeichert und nach Reload wiederhergestellt"
    - "Nach Lesson-Abschluss zeigt der Wald automatisch die Seite mit dem neuen Element"
    - "Seitenwechsel hat sanfte Fade-Animation"
  artifacts:
    - path: "src/forest/scene.ts"
      provides: "Navigation event handlers, page persistence"
      contains: "forest-nav-prev"
    - path: "src/forest/reward.ts"
      provides: "Correct slot index for paginated forest"
      contains: "SLOTS_PER_PAGE"
    - path: "src/app.ts"
      provides: "Forest init with correct page, post-reward navigation"
      contains: "currentForestPage"
  key_links:
    - from: "src/forest/scene.ts"
      to: "src/storage/db.ts"
      via: "saveProgress for page persistence"
      pattern: "saveProgress"
    - from: "src/forest/reward.ts"
      to: "src/forest/scene.ts"
      via: "SLOTS_PER_PAGE import for slot calculation"
      pattern: "SLOTS_PER_PAGE"
    - from: "src/app.ts"
      to: "src/forest/scene.ts"
      via: "renderForestScene with page parameter"
      pattern: "renderForestScene.*db.*page"
---

<objective>
Wire navigation interactions, persist current page, and fix reward flow for paginated forest.

Purpose: Plan 01 added the data model and rendering. This plan makes it interactive: clicking arrows changes pages, the page persists across sessions, and completing a lesson navigates to the correct page.

Output: Working multi-forest navigation, persisted page state, correct reward-to-forest flow.
</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/05-multi-wald-system-wald-pagination-und-navigation-zwischen-w-ldern/05-CONTEXT.md
@.planning/phases/05-multi-wald-system-wald-pagination-und-navigation-zwischen-w-ldern/05-01-SUMMARY.md

<interfaces>
<!-- From Plan 01 outputs -->

From src/types.ts (after Plan 01):
```typescript
export interface Progress {
  // ... existing fields ...
  currentForestPage: number; // 0-indexed, default 0
}
```

From src/forest/scene.ts (after Plan 01):
```typescript
export const SLOTS_PER_PAGE = 12;
export async function renderForestScene(db: IDBDatabase, page: number, newElementId?: number): Promise<void>;
export async function initForestScreen(db: IDBDatabase, onStartLesson: (level: number) => void): Promise<void>;
```

From src/storage/db.ts (unchanged):
```typescript
export function getProgress(db: IDBDatabase): Promise<Progress | null>;
export function saveProgress(db: IDBDatabase, progress: Progress): Promise<void>;
export function getForestElements(db: IDBDatabase): Promise<ForestElement[]>;
```

From src/app.ts:
```typescript
function migrateProgress(progress): void; // adds currentForestPage if missing
async function handleLessonComplete(completedLevel, stats): Promise<void>;
// calls initRewardScreen which returns elementId
// "Zurueck zum Wald" callback: initForestScreen + renderForestScene + showScreen
```
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Wire navigation handlers and page persistence in initForestScreen</name>
  <files>src/forest/scene.ts</files>
  <read_first>
    - src/forest/scene.ts (current initForestScreen — must add nav button handlers)
    - src/storage/db.ts (saveProgress pattern)
    - src/types.ts (Progress with currentForestPage)
  </read_first>
  <action>
**src/forest/scene.ts** — Modify `initForestScreen` to:

1. Import `saveProgress` from `../storage/db` (add to existing import).

2. Read `progress.currentForestPage` (with fallback to 0) and use it as the initial page for rendering:
```typescript
const page = progress.currentForestPage ?? 0;
await renderForestScene(db, page);
```

3. After the `renderLevelMap` call, wire up navigation buttons per D-05:
```typescript
const prevBtn = document.getElementById('forest-nav-prev') as HTMLButtonElement;
const nextBtn = document.getElementById('forest-nav-next') as HTMLButtonElement;

let currentPage = progress.currentForestPage ?? 0;

const navigateToPage = async (newPage: number) => {
  currentPage = newPage;
  await renderForestScene(db, currentPage);
  // Persist page in progress per D-05
  const freshProgress = await getProgress(db);
  if (freshProgress) {
    freshProgress.currentForestPage = currentPage;
    await saveProgress(db, freshProgress);
  }
};

if (prevBtn) {
  prevBtn.onclick = () => {
    if (currentPage > 0) navigateToPage(currentPage - 1);
  };
}

if (nextBtn) {
  nextBtn.onclick = async () => {
    const elements = await getForestElements(db);
    const totalPages = Math.max(1, Math.ceil(elements.length / SLOTS_PER_PAGE));
    if (currentPage < totalPages - 1) navigateToPage(currentPage + 1);
  };
}
```

4. Update all existing calls to `renderForestScene` within this file to pass the page parameter. The `initForestScreen` call becomes `renderForestScene(db, page)` (already done above).

5. Add a CSS transition for the grid on page change. In `renderForestScene`, before clearing `grid.innerHTML`, add:
```typescript
grid.style.opacity = '0';
grid.style.transition = 'opacity 0.3s ease';
```
And after the rendering loop completes:
```typescript
// Trigger fade-in after a frame
requestAnimationFrame(() => {
  grid.style.opacity = '1';
});
```
  </action>
  <verify>
    <automated>cd /home/dev/workspace/zauberwald && npx tsc --noEmit 2>&1 | head -20</automated>
  </verify>
  <acceptance_criteria>
    - src/forest/scene.ts contains `saveProgress` in import statement
    - src/forest/scene.ts contains `currentForestPage`
    - src/forest/scene.ts contains `prevBtn.onclick`
    - src/forest/scene.ts contains `nextBtn.onclick`
    - src/forest/scene.ts contains `navigateToPage`
    - src/forest/scene.ts contains `grid.style.opacity`
    - TypeScript compiles without errors
  </acceptance_criteria>
  <done>Arrow buttons navigate between forest pages, current page saved to Progress on every navigation, fade animation on page transitions</done>
</task>

<task type="auto">
  <name>Task 2: Fix reward flow and all renderForestScene call sites for pagination</name>
  <files>src/forest/reward.ts, src/app.ts</files>
  <read_first>
    - src/forest/reward.ts (slotIndex calculation at line 179 — must account for pagination)
    - src/app.ts (all renderForestScene calls — must pass page parameter; handleLessonComplete "Zurueck zum Wald" callback)
    - src/forest/scene.ts (new renderForestScene signature with page parameter)
  </read_first>
  <action>
**src/forest/reward.ts** — Per D-01, fix the slotIndex calculation to work with pagination:

1. Import `SLOTS_PER_PAGE` from `./scene`:
```typescript
import { SLOTS_PER_PAGE } from "./scene";
```

2. Replace the slotIndex calculation (currently `const slotIndex = existing.length % 12`):
```typescript
const slotIndex = existing.length % SLOTS_PER_PAGE;
```
This ensures the element is placed in the correct grid position on its page.

**src/app.ts** — Update ALL `renderForestScene` and `initForestScreen` call sites per D-06:

1. In `handleLessonComplete`, the "Zurueck zum Wald" callback (the `onBackToForest` lambda around line 122-125):
```typescript
async () => {
  // Per D-06: navigate to page containing the new element
  const elements = await getForestElements(db);
  const newPage = Math.max(0, Math.ceil(elements.length / SLOTS_PER_PAGE) - 1);

  // Update progress with new page
  const latestProgress = await getProgress(db);
  if (latestProgress) {
    latestProgress.currentForestPage = newPage;
    await saveProgress(db, latestProgress);
  }

  await initForestScreen(db, startLessonFromForest);
  await renderForestScene(db, newPage, elementId);
  showScreen("forest");
}
```

2. Import `SLOTS_PER_PAGE` from `./forest/scene` and `getForestElements` from `./storage/db` (add to existing imports if not already there).

3. In the "Weiter ueben" callback from reward (the `onContinue` lambda), no forest rendering happens so no change needed.

4. In `handleLessonCancel` (line 129-132), `initForestScreen` already reads `currentForestPage` from progress internally, so no change needed here.

5. In `initApp` returning user flow (line 208), `initForestScreen` already handles page from progress, but the subsequent `renderForestScene` call does not exist separately — `initForestScreen` calls it. No change needed.

6. In the "Zurueck zum Wald" from parent area (line 182-183), same — `initForestScreen` handles it.

7. BUT: There is an explicit `renderForestScene(db, elementId)` call on line 123. This must become `renderForestScene(db, newPage, elementId)` as described in step 1 above.
  </action>
  <verify>
    <automated>cd /home/dev/workspace/zauberwald && npx tsc --noEmit 2>&1 | head -20 && grep -n "SLOTS_PER_PAGE" src/forest/reward.ts src/app.ts</automated>
  </verify>
  <acceptance_criteria>
    - src/forest/reward.ts contains `import { SLOTS_PER_PAGE } from "./scene"`
    - src/forest/reward.ts contains `existing.length % SLOTS_PER_PAGE`
    - src/app.ts contains `SLOTS_PER_PAGE` import
    - src/app.ts contains `currentForestPage = newPage`
    - src/app.ts does NOT contain `renderForestScene(db, elementId)` (old 2-arg call with elementId)
    - TypeScript compiles without errors
  </acceptance_criteria>
  <done>Reward flow correctly calculates slot position for paginated grid, "Zurueck zum Wald" navigates to the page containing the new element, all renderForestScene calls pass page parameter</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 3: Verify multi-forest navigation works end-to-end</name>
  <files>n/a</files>
  <action>
Human verification checkpoint for the multi-forest pagination system.

What was built: Arrow navigation between forest pages, page persistence in Progress, correct page navigation after lesson completion, fade animation on page transitions.

How to verify:
1. Open http://localhost:5173 in browser
2. If fresh install: complete onboarding, play through at least 1 lesson to get forest elements
3. On the forest screen: if you have fewer than 13 elements, the navigation arrows should be HIDDEN
4. To test pagination with many elements: Use browser DevTools console to add fake elements to IndexedDB, OR play through enough lessons to fill 12+ slots
5. With 13+ elements: navigation arrows ("Wald 1 von 2") should appear between the forest scene and level map
6. Click right arrow — should fade to page 2 showing element 13+
7. Click left arrow — should fade back to page 1
8. Left arrow should be disabled on page 1, right arrow disabled on last page
9. Reload browser — same page should be shown (persistence)
10. Complete a lesson — after clicking "Zurueck zum Wald", should show the page with the new element (last page)

Resume signal: Type "approved" or describe issues.
  </action>
  <verify>User confirms visual and functional correctness of multi-forest navigation</verify>
  <done>User approves that forest pagination, navigation arrows, page persistence, and post-lesson page selection all work correctly</done>
</task>

</tasks>

<verification>
- `npx tsc --noEmit` passes
- `npm run dev` starts without errors
- Navigation arrows hidden when <= 12 elements
- Navigation arrows visible when > 12 elements
- Page persists in IndexedDB across reloads
- New element after lesson appears on correct page
</verification>

<success_criteria>
- Clicking prev/next arrows changes forest page with fade animation
- "Wald X von Y" text updates correctly
- Arrows disabled at boundaries (prev on page 1, next on last page)
- currentForestPage persisted in Progress and restored on reload
- After lesson completion, forest shows the page containing the new element
- No console errors during normal navigation
</success_criteria>

<output>
After completion, create `.planning/phases/05-multi-wald-system-wald-pagination-und-navigation-zwischen-w-ldern/05-02-SUMMARY.md`
</output>
