Files
T

307 lines
12 KiB
Markdown
Raw Normal View History

---
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>