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>
178 lines
7.4 KiB
Markdown
178 lines
7.4 KiB
Markdown
---
|
|
phase: 03-komplettes-spielerlebnis
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- src/types.ts
|
|
- src/game/words.ts
|
|
- src/game/words.test.ts
|
|
- src/api/gemini.ts
|
|
autonomous: true
|
|
requirements: [LEVL-04, TYPE-06]
|
|
must_haves:
|
|
truths:
|
|
- "Word lists exist for levels 1-6 using only learned letters"
|
|
- "Every word in a level's list uses only letters from allKeys of that level"
|
|
- "Progress interface has stats fields for accuracy tracking"
|
|
- "Rate limits allow 10 text + 5 image calls per day"
|
|
artifacts:
|
|
- path: "src/game/words.ts"
|
|
provides: "Static word lists per level, getWordsForLevel() function"
|
|
exports: ["wordsByLevel", "getWordsForLevel"]
|
|
- path: "src/game/words.test.ts"
|
|
provides: "Tests validating word lists only use learned letters"
|
|
- path: "src/types.ts"
|
|
provides: "Extended Progress with totalCorrect, totalErrors, errorKeyCounts, lastPlayedLevels"
|
|
contains: "totalCorrect"
|
|
- path: "src/api/gemini.ts"
|
|
provides: "Updated rate limits: 10 text, 5 image per day"
|
|
key_links:
|
|
- from: "src/game/words.ts"
|
|
to: "src/game/levels.ts"
|
|
via: "imports getKeysUpToLevel for validation"
|
|
pattern: "getKeysUpToLevel"
|
|
---
|
|
|
|
<objective>
|
|
Foundation data layer for Phase 3: word lists per level, extended Progress type with stats fields, updated rate limits.
|
|
|
|
Purpose: All subsequent plans (lesson flow, reward, parent area) depend on these types and data structures.
|
|
Output: `src/game/words.ts` with tested word lists, extended `Progress` interface, updated rate limits in gemini.ts.
|
|
</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
|
|
@src/types.ts
|
|
@src/game/levels.ts
|
|
@src/api/gemini.ts
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 1: Word lists per level with validation tests</name>
|
|
<files>src/game/words.ts, src/game/words.test.ts</files>
|
|
<read_first>src/game/levels.ts, src/types.ts</read_first>
|
|
<behavior>
|
|
- Test: wordsByLevel has entries for levels 1-6
|
|
- Test: Each level has at least 8 words (per D-04: 8-10 minimum)
|
|
- Test: Every word in level N uses only characters from levels[N].allKeys (no spaces)
|
|
- Test: No word exceeds 5 characters (per D-04)
|
|
- Test: getWordsForLevel(level, count) returns `count` random words from that level
|
|
- Test: getWordsForLevel returns empty array for non-existent level
|
|
</behavior>
|
|
<action>
|
|
Create `src/game/words.ts` (per D-04):
|
|
|
|
```typescript
|
|
import { getKeysUpToLevel } from './levels';
|
|
|
|
export const wordsByLevel: Record<number, string[]> = {
|
|
1: [], // Level 1 has only F, J, space — no real words possible, use letter combos: "ff", "jj", "fj", "jf", "fjf", "jfj", "ff", "jj", "fjfj", "jfjf"
|
|
2: ['fdk', 'kdf', 'djf', 'fkd', 'dkf', 'jdk', 'kfj', 'fdkj', 'kjdf', 'dfjk'], // F,J,D,K — no real German words, use combos
|
|
3: ['falls', 'lass', 'das', 'sdf', 'sdk', 'lsd', 'flsk', 'sldf', 'dsl', 'kls'], // adds S, L — "falls", "lass" are real words
|
|
4: ['als', 'da', 'das', 'dafö', 'salad', 'lass', 'falls', 'aas', 'sa', 'ask'], // adds A, OE
|
|
5: ['glas', 'halb', 'jagd', 'gash', 'hagl', 'gah', 'hag', 'lag', 'gal', 'sah'], // adds G, H
|
|
6: ['eis', 'idee', 'kleid', 'lied', 'lief', 'fies', 'dies', 'die', 'sie', 'sei'], // adds E, I
|
|
};
|
|
```
|
|
|
|
IMPORTANT: For levels 1-2, real German words are impossible with only F/J/D/K + space. Use letter combination patterns instead (the Spec acknowledges this implicitly — words only become meaningful at level 3+). Each word MUST only use characters from that level's `allKeys` (excluding space). Validate at test time by cross-referencing `getKeysUpToLevel()`.
|
|
|
|
Export `getWordsForLevel(level: number, count: number): string[]` that returns `count` random words from the level's list (sampling without replacement if count <= list length, with replacement otherwise).
|
|
|
|
Create `src/game/words.test.ts` with vitest tests covering all behaviors above.
|
|
</action>
|
|
<verify>
|
|
<automated>npx vitest run src/game/words.test.ts</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- grep "wordsByLevel" src/game/words.ts returns matches
|
|
- grep "getWordsForLevel" src/game/words.ts returns export
|
|
- grep "getKeysUpToLevel" src/game/words.test.ts shows validation against level keys
|
|
- npx vitest run src/game/words.test.ts exits 0
|
|
</acceptance_criteria>
|
|
<done>Word lists for levels 1-6 exist, each with 8+ words using only learned letters, max 5 chars. Tests pass.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Extend Progress type and update rate limits</name>
|
|
<files>src/types.ts, src/api/gemini.ts</files>
|
|
<read_first>src/types.ts, src/api/gemini.ts</read_first>
|
|
<action>
|
|
**Progress type extension (per D-15):**
|
|
Add these fields to the `Progress` interface in `src/types.ts`:
|
|
```typescript
|
|
totalCorrect: number;
|
|
totalErrors: number;
|
|
errorKeyCounts: Record<string, number>;
|
|
lastPlayedLevels: number[]; // last 3 played levels for D-06
|
|
```
|
|
|
|
Also add a `LessonPhase` type:
|
|
```typescript
|
|
export type LessonPhase = 'discover' | 'practice' | 'words';
|
|
```
|
|
|
|
**Update rate limits (per D-13):**
|
|
In `src/api/gemini.ts`, change `checkRateLimit` function:
|
|
- Current: `settings.apiCallsToday[type] < 1` (allows 1 each)
|
|
- New: text limit = 10, image limit = 5
|
|
- Add constants: `const TEXT_RATE_LIMIT = 10;` and `const IMAGE_RATE_LIMIT = 5;`
|
|
- Change comparison: `type === 'text' ? settings.apiCallsToday.text < TEXT_RATE_LIMIT : settings.apiCallsToday.image < IMAGE_RATE_LIMIT`
|
|
|
|
**Update initWelcomeScreen in screens.ts** to include new Progress fields with defaults:
|
|
In `src/ui/screens.ts`, find the `Progress` object creation in `startBtn` click handler and add:
|
|
```typescript
|
|
totalCorrect: 0,
|
|
totalErrors: 0,
|
|
errorKeyCounts: {},
|
|
lastPlayedLevels: [],
|
|
```
|
|
</action>
|
|
<verify>
|
|
<automated>npx vitest run && npx tsc --noEmit</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- grep "totalCorrect" src/types.ts returns a match
|
|
- grep "totalErrors" src/types.ts returns a match
|
|
- grep "errorKeyCounts" src/types.ts returns a match
|
|
- grep "lastPlayedLevels" src/types.ts returns a match
|
|
- grep "LessonPhase" src/types.ts returns a match
|
|
- grep "TEXT_RATE_LIMIT = 10" src/api/gemini.ts returns a match
|
|
- grep "IMAGE_RATE_LIMIT = 5" src/api/gemini.ts returns a match
|
|
- npx tsc --noEmit exits 0
|
|
</acceptance_criteria>
|
|
<done>Progress has stats fields, LessonPhase type exists, rate limits updated to 10 text / 5 image per day. TypeScript compiles clean.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `npx vitest run` — all tests pass
|
|
- `npx tsc --noEmit` — no type errors
|
|
- Word lists validated: every word uses only learned letters for its level
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
1. `src/game/words.ts` exports wordsByLevel (levels 1-6, 8+ words each) and getWordsForLevel()
|
|
2. All words validated: only use allKeys from their level, max 5 chars
|
|
3. Progress interface extended with totalCorrect, totalErrors, errorKeyCounts, lastPlayedLevels
|
|
4. LessonPhase type exported from types.ts
|
|
5. Rate limits updated to 10 text / 5 image per day
|
|
6. All tests pass, TypeScript compiles clean
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/03-komplettes-spielerlebnis/03-01-SUMMARY.md`
|
|
</output>
|