Files

385 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 01-grundger-st-tippmechanik
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- package.json
- tsconfig.json
- vite.config.ts
- biome.json
- index.html
- .gitignore
- src/main.ts
- src/types.ts
- src/storage/db.ts
- src/styles/main.css
- public/config.example.json
autonomous: true
requirements:
- FNDN-01
- FNDN-02
- FNDN-03
- FNDN-04
- PLSH-06
must_haves:
truths:
- "npm run dev startet Vite auf 0.0.0.0:5173 ohne Fehler"
- "Alle Verzeichnisse aus Spec Abschnitt 13 existieren"
- "TypeScript-Interfaces sind exportiert und typisiert"
- "IndexedDB oeffnet mit 5 Stores und schliesst nicht bei reload"
- "CSS Custom Properties fuer alle Farben und Fonts sind definiert"
artifacts:
- path: "package.json"
provides: "Project dependencies and scripts"
contains: "vite"
- path: "src/types.ts"
provides: "All shared TypeScript interfaces"
exports: ["Progress", "ForestElement", "CompanionAssets", "Level", "Settings", "StyleReference"]
- path: "src/storage/db.ts"
provides: "IndexedDB wrapper with 5 stores"
exports: ["openDB", "getProgress", "saveProgress", "getSettings", "saveSettings"]
- path: "src/styles/main.css"
provides: "CSS palette and typography"
contains: "--bg-cream"
key_links:
- from: "src/storage/db.ts"
to: "src/types.ts"
via: "imports Progress, Settings, ForestElement etc."
pattern: "import.*from.*types"
- from: "src/main.ts"
to: "src/storage/db.ts"
via: "initializes DB on app start"
pattern: "openDB"
---
<objective>
Scaffold the complete Vite project, define all TypeScript interfaces, create the IndexedDB wrapper, and establish the CSS design system.
Purpose: Every subsequent plan depends on the project existing, types being defined, storage being available, and styles being set.
Output: A runnable Vite dev server with types, IndexedDB, and CSS custom properties — no visible UI yet beyond a blank styled page.
</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/01-grundger-st-tippmechanik/01-CONTEXT.md
@SPEC.md (sections 6.2, 6.3, 7.2, 13)
</context>
<tasks>
<task type="auto">
<name>Task 1: Vite project scaffold + project structure + CSS design system</name>
<files>
package.json, tsconfig.json, vite.config.ts, biome.json, index.html,
.gitignore, src/main.ts, src/styles/main.css, public/config.example.json
</files>
<read_first>
SPEC.md (section 13 for project structure, section 6.2 for tech stack, section 7.2 for CSS palette)
.planning/phases/01-grundger-st-tippmechanik/01-CONTEXT.md
</read_first>
<action>
1. Initialize Vite project with vanilla-ts template:
`npm create vite@latest . -- --template vanilla-ts` (or manually create files if directory not empty).
2. Install dependencies:
- `npm install` (vite, typescript)
- `npm install -D vitest @biomejs/biome`
3. Configure vite.config.ts (per D-01, spec section 0):
```typescript
import { defineConfig } from 'vite'
export default defineConfig({
server: { host: '0.0.0.0', port: 5173 },
preview: { host: '0.0.0.0', port: 4173 }
})
```
4. Configure tsconfig.json: `"strict": true`, target ES2020, module ESNext, moduleResolution bundler.
5. Configure biome.json: enable formatter and linter, indent with tabs, line width 100.
6. Configure package.json scripts:
```json
{
"dev": "vite --host",
"build": "tsc && vite build",
"preview": "vite preview --host --port 4173",
"test": "vitest run",
"test:watch": "vitest",
"lint": "biome check .",
"lint:fix": "biome check --write ."
}
```
7. Create .gitignore with: node_modules, dist, public/config.json, *.local
8. Create ALL directories from spec section 13:
- src/game/, src/forest/, src/companion/, src/api/, src/storage/, src/ui/, src/styles/
- src/assets/companions/fee-lila/, src/assets/companions/einhorn-stella/,
src/assets/companions/fuchs-finn/, src/assets/companions/eule-elsa/
- src/assets/style-reference/, src/assets/fallback-images/
- scripts/
- public/
Place empty .gitkeep in asset directories that have no files yet.
9. Create public/config.example.json:
```json
{
"geminiApiKey": "YOUR_API_KEY_HERE",
"geminiModel": "gemini-2.5-flash",
"imageModel": "gemini-3.1-flash-image-preview"
}
```
10. Create index.html with:
- DOCTYPE html, lang="de"
- Google Fonts link: Quicksand (400, 600, 700) + Nunito (400, 600)
- Link to src/styles/main.css (via Vite)
- 5 screen sections per D-01: `<section id="screen-welcome" class="screen">`,
`<section id="screen-forest" class="screen">`,
`<section id="screen-lesson" class="screen">`,
`<section id="screen-reward" class="screen">`,
`<section id="screen-parent" class="screen">`
- Only screen-welcome gets class `screen--active` initially
- `<script type="module" src="/src/main.ts"></script>`
11. Create src/styles/main.css with ALL CSS custom properties from spec section 7.2:
```css
:root {
--bg-cream: #FFF8F0;
--bg-forest: #E8F5E4;
--text-dark: #3D3225;
--text-warm: #5C4A3A;
--text-light: #8B7D6B;
--accent-green: #6DB87D;
--accent-gold: #E8B84B;
--accent-pink: #E88BAE;
--accent-purple: #9B7DC4;
--accent-blue: #7DB8D4;
--finger-l-pinky: #E8B4C8;
--finger-l-ring: #C4A8D4;
--finger-l-mid: #A8C4E0;
--finger-l-index: #A8D8B8;
--finger-r-index: #D4D8A8;
--finger-r-mid: #E0C4A8;
--finger-r-ring: #D4A8A8;
--finger-r-pinky: #C8B4E8;
--finger-thumb: #D4CFC8;
}
```
Body: font-family 'Nunito', sans-serif; background var(--bg-cream); color var(--text-dark); min font-size 16px; margin 0; padding 0.
Headings (h1h3): font-family 'Quicksand', sans-serif.
Screen base: `.screen { display: none; opacity: 0; transition: opacity 0.3s ease; }` and `.screen--active { display: flex; flex-direction: column; align-items: center; opacity: 1; min-height: 100vh; }`.
12. Create src/main.ts as minimal entry: import './styles/main.css', console.log('Zauberwald loaded').
</action>
<verify>
<automated>cd /home/dev/workspace/zauberwald && npm run dev -- --strictPort 2>&1 &amp; sleep 3 && curl -s http://localhost:5173 | grep -q "Zauberwald" || curl -s http://localhost:5173 | grep -q "screen-welcome" && kill %1 && echo "PASS"</automated>
</verify>
<acceptance_criteria>
- package.json contains "vite" in devDependencies and scripts "dev", "build", "preview", "test", "lint"
- vite.config.ts contains `host: '0.0.0.0'` and `port: 5173`
- tsconfig.json contains `"strict": true`
- biome.json exists and contains `"formatter"` and `"linter"`
- .gitignore contains `public/config.json` and `node_modules`
- index.html contains 5 `<section` tags with ids screen-welcome, screen-forest, screen-lesson, screen-reward, screen-parent
- index.html contains `class="screen screen--active"` on screen-welcome
- src/styles/main.css contains `--bg-cream: #FFF8F0` and `--finger-l-pinky: #E8B4C8` and `--finger-thumb: #D4CFC8`
- src/styles/main.css contains `font-family:` with `Quicksand` and `Nunito`
- Directories exist: src/game, src/forest, src/companion, src/api, src/storage, src/ui, src/assets/companions
- public/config.example.json contains `geminiApiKey` and `geminiModel`
- `npm run dev` starts without errors
</acceptance_criteria>
<done>Vite project runs, all directories exist per spec section 13, CSS custom properties match spec section 7.2, index.html has 5 screen sections</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: TypeScript interfaces + IndexedDB wrapper</name>
<files>
src/types.ts, src/storage/db.ts, src/storage/db.test.ts
</files>
<read_first>
SPEC.md (section 6.3 for IndexedDB stores, section 4.1 for level structure, section 5.2 for companion types)
src/types.ts (after Task 1 creates it — may be empty placeholder)
</read_first>
<behavior>
- Test: openDB() resolves to an IDBDatabase with 5 object store names
- Test: saveProgress({ currentLevel: 1, ... }) then getProgress() returns same data
- Test: saveSettings({ audioEnabled: true, ... }) then getSettings() returns same data
- Test: getProgress() on empty DB returns null (not crash)
- Test: getSettings() on empty DB returns null (not crash)
</behavior>
<action>
1. Create src/types.ts with ALL interfaces per spec section 6.3 (per FNDN-03):
```typescript
// Companion types
export type CompanionType = 'fee' | 'einhorn' | 'fuchs' | 'eule';
export type KeyboardLayout = 'de' | 'ch';
// Level status for the forest map
export type LevelStatus = 'locked' | 'current' | 'completed';
// Progress store
export interface Progress {
id: 1; // singleton row
currentLevel: number;
completedLevels: number[];
totalSessions: number;
sessionDates: string[]; // ISO date strings (days only)
selectedCharacter: CompanionType;
selectedLayout: KeyboardLayout;
}
// Companion assets store
export interface CompanionAssets {
characterType: CompanionType;
characterSheet: Blob;
avatarImage: Blob;
generatedAt: string; // ISO date
}
// Style reference store
export interface StyleReference {
id: 1; // singleton
imageBlob: Blob;
generatedAt: string;
}
// Forest element store
export interface ForestElement {
id?: number; // auto-increment
levelCompleted: number;
imageBlob: Blob;
imagePrompt: string;
description: string;
companionText: string;
position: { x: number; y: number };
createdAt: string;
}
// Settings store
export interface Settings {
id: 1; // singleton
audioEnabled: boolean;
apiKey: string;
}
// Level definition (used in game/levels.ts)
export interface Level {
level: number;
newKeys: string[];
allKeys: string[]; // cumulative keys up to this level
fingerMap: Record<string, string>; // key -> CSS variable name for finger color
}
// Typing exercise state
export interface TypingExerciseState {
currentLetterIndex: number;
letters: string[];
intervalMs: number;
correctStreak: number;
totalCorrect: number;
totalErrors: number;
}
// Screen names
export type ScreenName = 'welcome' | 'forest' | 'lesson' | 'reward' | 'parent';
```
2. Create src/storage/db.ts — IndexedDB wrapper (per D-02, all 5 stores created, only progress + settings fully used):
```typescript
import type { Progress, Settings, ForestElement, CompanionAssets, StyleReference } from '../types';
const DB_NAME = 'zauberwald';
const DB_VERSION = 1;
export function openDB(): Promise<IDBDatabase> {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
if (!db.objectStoreNames.contains('progress')) {
db.createObjectStore('progress', { keyPath: 'id' });
}
if (!db.objectStoreNames.contains('companionAssets')) {
db.createObjectStore('companionAssets', { keyPath: 'characterType' });
}
if (!db.objectStoreNames.contains('styleReference')) {
db.createObjectStore('styleReference', { keyPath: 'id' });
}
if (!db.objectStoreNames.contains('forestElements')) {
db.createObjectStore('forestElements', { keyPath: 'id', autoIncrement: true });
}
if (!db.objectStoreNames.contains('settings')) {
db.createObjectStore('settings', { keyPath: 'id' });
}
};
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
export async function getProgress(db: IDBDatabase): Promise<Progress | null> { ... }
export async function saveProgress(db: IDBDatabase, progress: Progress): Promise<void> { ... }
export async function getSettings(db: IDBDatabase): Promise<Settings | null> { ... }
export async function saveSettings(db: IDBDatabase, settings: Settings): Promise<void> { ... }
```
Each get/save function wraps IDB transaction in a Promise. Use 'readonly' for gets, 'readwrite' for saves. Store name matches interface.
3. Create src/storage/db.test.ts using vitest with fake-indexeddb:
- `npm install -D fake-indexeddb`
- Import `import 'fake-indexeddb/auto'` at top of test
- Test all behaviors listed above
</action>
<verify>
<automated>cd /home/dev/workspace/zauberwald && npx vitest run src/storage/db.test.ts</automated>
</verify>
<acceptance_criteria>
- src/types.ts exports: Progress, ForestElement, CompanionAssets, Settings, StyleReference, Level, CompanionType, KeyboardLayout, LevelStatus, ScreenName, TypingExerciseState
- src/types.ts contains `type CompanionType = 'fee' | 'einhorn' | 'fuchs' | 'eule'`
- src/types.ts contains `type KeyboardLayout = 'de' | 'ch'`
- src/storage/db.ts exports: openDB, getProgress, saveProgress, getSettings, saveSettings
- src/storage/db.ts contains `const DB_NAME = 'zauberwald'`
- src/storage/db.ts contains all 5 store names: 'progress', 'companionAssets', 'styleReference', 'forestElements', 'settings'
- src/storage/db.test.ts exists and `npx vitest run src/storage/db.test.ts` exits 0
- package.json contains `fake-indexeddb` in devDependencies
</acceptance_criteria>
<done>All TypeScript interfaces exported, IndexedDB wrapper creates 5 stores, read/write for progress and settings works, all tests pass</done>
</task>
</tasks>
<verification>
- `npm run dev` starts without errors on port 5173
- `npx vitest run` passes all DB tests
- `npx biome check .` shows no errors (or only warnings)
- All directories from spec section 13 exist
- index.html has 5 screen sections
- CSS custom properties match spec section 7.2 exactly
</verification>
<success_criteria>
- Vite dev server accessible at 0.0.0.0:5173
- TypeScript compiles without errors in strict mode
- IndexedDB wrapper tested and working with 5 stores
- CSS design system complete with all palette colors and typography
- Project structure matches spec section 13
</success_criteria>
<output>
After completion, create `.planning/phases/01-grundger-st-tippmechanik/01-01-SUMMARY.md`
</output>