Files
Zauberwald/.planning/phases/03-komplettes-spielerlebnis/03-03-PLAN.md
T
gurixandClaude Opus 4.6 5819ade457 docs(03): create phase plan — komplettes spielerlebnis
5 plans across 3 waves covering all 17 requirements:
- Plan 01 (W1): Word lists, Progress extension, rate limits
- Plan 02 (W2): Lesson 3-phase state machine, review/repeat
- Plan 03 (W1): Forest visual scene with SVG + grid
- Plan 04 (W3): Reward screen, pre-generation, full flow wiring
- Plan 05 (W2): Parent area with stats and settings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:37:08 +02:00

9.4 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
03-komplettes-spielerlebnis 03 execute 1
src/forest/scene.ts
index.html
src/styles/main.css
true
FRST-01
FRST-02
FRST-03
truths artifacts key_links
Forest screen shows SVG woodland background
A 4x3 grid overlays the SVG for placing forest element images
New elements appear with fade-in + scale-up animation
All previously earned elements load from IndexedDB on screen init
path provides exports
src/forest/scene.ts renderForestScene() that loads elements from IDB and renders in grid
renderForestScene
path provides contains
index.html Forest scene container with SVG background and grid overlay forest-scene
from to via pattern
src/forest/scene.ts src/storage/db.ts getForestElements() to load persisted elements getForestElements
Build the visual forest scene: SVG background with a 4x3 grid overlay where generated forest element images are placed. Elements load from IndexedDB and new ones animate in.

Purpose: The growing forest IS the reward system — the child sees their world fill up with each session. Output: Visual forest scene in forest screen with grid, animations, and IndexedDB loading.

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

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @src/forest/scene.ts @src/storage/db.ts @src/types.ts @index.html @src/styles/main.css export function getForestElements(db: IDBDatabase): Promise; export function saveForestElement(db: IDBDatabase, element: ForestElement): Promise;

export interface ForestElement { id?: number; levelCompleted: number; imageBlob: Blob; imagePrompt: string; description: string; companionText: string; position: { x: number; y: number }; createdAt: string; }

Task 1: SVG forest background and grid HTML structure index.html, src/styles/main.css index.html, src/styles/main.css, src/forest/scene.ts **Update index.html** `#screen-forest .forest` section (per D-07, D-09):
Add a forest scene container ABOVE the level-map but BELOW the greeting:
```html
<div class="forest__scene" id="forest-scene">
  <svg class="forest__bg" viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg">
    <!-- Ground -->
    <rect x="0" y="300" width="800" height="100" fill="#C8E6C0" rx="0"/>
    <!-- Hills -->
    <ellipse cx="200" cy="320" rx="250" ry="80" fill="#A8D8A8"/>
    <ellipse cx="650" cy="330" rx="200" ry="60" fill="#B8E0B0"/>
    <!-- Trees (background) -->
    <g opacity="0.3">
      <ellipse cx="80" cy="240" rx="40" ry="60" fill="#7DB87D"/>
      <ellipse cx="720" cy="250" rx="35" ry="55" fill="#6DA86D"/>
      <ellipse cx="400" cy="230" rx="45" ry="70" fill="#8DC88D"/>
    </g>
    <!-- Sky gradient -->
    <defs>
      <linearGradient id="sky-grad" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stop-color="#E8F4FD"/>
        <stop offset="100%" stop-color="#F0F8E8"/>
      </linearGradient>
    </defs>
    <rect x="0" y="0" width="800" height="300" fill="url(#sky-grad)"/>
    <!-- Clouds -->
    <ellipse cx="150" cy="60" rx="60" ry="25" fill="white" opacity="0.5"/>
    <ellipse cx="550" cy="80" rx="70" ry="20" fill="white" opacity="0.4"/>
    <!-- Sun -->
    <circle cx="700" cy="50" r="30" fill="#F8E8A0" opacity="0.6"/>
  </svg>
  <div class="forest__grid" id="forest-grid">
    <!-- 12 slots for forest elements, filled dynamically -->
  </div>
</div>
```

NOTE: The SVG layers must be ordered so sky-rect is FIRST (painted first, at back), then hills/ground on top. Adjust SVG element order: sky rect first, then clouds/sun, then background trees, then hills, then ground.

**Add CSS to `src/styles/main.css`:**

```css
/* Forest Scene */
.forest__scene {
  position: relative;
  width: 100%;
  max-width: 800px;
  margin: 0 auto 1.5rem;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.forest__bg {
  display: block;
  width: 100%;
  height: auto;
}

.forest__grid {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, 1fr);
  padding: 1rem;
  gap: 0.5rem;
}

.forest__element {
  display: flex;
  align-items: center;
  justify-content: center;
}

.forest__element img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 8px;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.15));
}

/* New element animation (per D-08, FRST-02) */
.forest__element--new {
  animation: forest-element-appear 1.2s ease-out forwards;
}

@keyframes forest-element-appear {
  0% {
    opacity: 0;
    transform: scale(0.3);
  }
  60% {
    opacity: 1;
    transform: scale(1.05);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}
```
grep -c "forest-scene" index.html && grep -c "forest__grid" index.html && grep -c "forest__element--new" src/styles/main.css - grep "forest-scene" index.html returns match - grep "forest__grid" index.html returns match - grep "forest-element-appear" src/styles/main.css returns match (animation keyframes) - grep "grid-template-columns.*repeat(4" src/styles/main.css returns match (4x3 grid) - grep "grid-template-rows.*repeat(3" src/styles/main.css returns match - SVG viewBox="0 0 800 400" present in index.html Forest scene has SVG background with woodland scenery, 4x3 CSS grid overlay, and fade-in+scale-up animation keyframes for new elements. Task 2: Render forest elements from IndexedDB src/forest/scene.ts src/forest/scene.ts, src/storage/db.ts, src/types.ts, index.html Extend `src/forest/scene.ts` (per D-07, D-08, FRST-03):
Add a new exported function `renderForestScene(db: IDBDatabase, newElementId?: number): Promise<void>`:

1. Get `#forest-grid` element
2. Call `getForestElements(db)` to load all persisted elements
3. Clear grid contents
4. For each element (up to 12 — the grid has 12 slots):
   - Create a `<div class="forest__element">`
   - Create an `<img>` with `src` = `URL.createObjectURL(element.imageBlob)`
   - Set `alt` = `element.description`
   - Apply random offset per D-07: `style="transform: translate(${randomOffset}px, ${randomOffset}px)"` where offset is +-10-20px random
   - If `element.id === newElementId`, add class `forest__element--new` for animation
   - Append to grid

5. Store created Object URLs in a module-level array so they can be revoked on next call (prevent memory leak):
   ```typescript
   let activeObjectUrls: string[] = [];
   ```
   At start of function, revoke all old URLs via `URL.revokeObjectURL()`, then clear array.

Update `initForestScreen` to call `renderForestScene(db)` alongside existing `renderLevelMap`.

The `newElementId` parameter will be used by Plan 04 (reward flow) to trigger animation on the just-added element.
npx tsc --noEmit && npx vitest run - grep "renderForestScene" src/forest/scene.ts returns export - grep "getForestElements" src/forest/scene.ts returns match (loads from IDB) - grep "createObjectURL" src/forest/scene.ts returns match (blob->URL conversion) - grep "revokeObjectURL" src/forest/scene.ts returns match (memory cleanup) - grep "forest__element--new" src/forest/scene.ts returns match (animation class) - grep "renderForestScene" src/forest/scene.ts shows it's called from initForestScreen - npx tsc --noEmit exits 0 Forest scene renders all stored elements from IndexedDB as images in the 4x3 grid. New elements get animation class. Object URLs cleaned up on re-render. Level map preserved alongside scene. - `npx tsc --noEmit` — no type errors - `npx vitest run` — all tests pass - Forest screen has SVG background visible with grid overlay - Elements from IndexedDB render as images with random offset

<success_criteria>

  1. Forest screen shows SVG woodland background (sky, hills, trees, clouds)
  2. 4x3 CSS grid overlays the SVG for element placement
  3. All stored ForestElements load from IndexedDB and display as images
  4. New elements animate with fade-in + scale-up (1.2s ease-out)
  5. Object URLs properly managed (revoked on re-render)
  6. Level map still visible below/alongside the scene </success_criteria>
After completion, create `.planning/phases/03-komplettes-spielerlebnis/03-03-SUMMARY.md`