From f9601cb271982944b5c07a8d00f7e323b2c078b8 Mon Sep 17 00:00:00 2001 From: Markus Graf Date: Sun, 29 Mar 2026 18:12:06 +0200 Subject: [PATCH] docs(04-polish-audio): create phase plan --- .planning/ROADMAP.md | 17 +- .../phases/04-polish-audio/04-01-PLAN.md | 165 +++++++++++ .../phases/04-polish-audio/04-02-PLAN.md | 278 ++++++++++++++++++ .../phases/04-polish-audio/04-03-PLAN.md | 231 +++++++++++++++ .../phases/04-polish-audio/04-04-PLAN.md | 190 ++++++++++++ 5 files changed, 876 insertions(+), 5 deletions(-) create mode 100644 .planning/phases/04-polish-audio/04-01-PLAN.md create mode 100644 .planning/phases/04-polish-audio/04-02-PLAN.md create mode 100644 .planning/phases/04-polish-audio/04-03-PLAN.md create mode 100644 .planning/phases/04-polish-audio/04-04-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 8874c97..dc70ae7 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -89,7 +89,14 @@ Plans: 3. Sprachausgabe liest Companion-Text vor wenn aktiviert (Web Speech API, Deutsch) 4. Export und Import funktionieren: Exportieren → Browser-Daten loeschen → Importieren → Fortschritt wiederhergestellt 5. Keine unbehandelten Exceptions in der Browser-Konsole bei normalem Gebrauch -**Plans**: TBD +**Plans:** 4 plans + +Plans: +- [ ] 04-01-PLAN.md — Audio system (Web Audio API sounds, Web Speech API speech, mute button) +- [ ] 04-02-PLAN.md — Animation polish (leaf-fall, stardust, companion float), responsive, error handler +- [ ] 04-03-PLAN.md — Export/Import/Reset in parent area +- [ ] 04-04-PLAN.md — Wire audio into all screens, end-to-end human verification + **UI hint**: yes ## Progress @@ -99,7 +106,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| -| 1. Grundgerüst + Tippmechanik | 0/5 | Planning complete | - | -| 2. Gemini-Integration + Asset-Pipeline | 0/5 | Planning complete | - | -| 3. Komplettes Spielerlebnis | 0/5 | Planning complete | - | -| 4. Polish + Audio | 0/? | Not started | - | +| 1. Grundgerüst + Tippmechanik | 5/5 | Complete | - | +| 2. Gemini-Integration + Asset-Pipeline | 5/5 | Complete | - | +| 3. Komplettes Spielerlebnis | 5/5 | Complete | - | +| 4. Polish + Audio | 0/4 | Planning complete | - | diff --git a/.planning/phases/04-polish-audio/04-01-PLAN.md b/.planning/phases/04-polish-audio/04-01-PLAN.md new file mode 100644 index 0000000..2caafd3 --- /dev/null +++ b/.planning/phases/04-polish-audio/04-01-PLAN.md @@ -0,0 +1,165 @@ +--- +phase: 04-polish-audio +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - src/audio/sounds.ts + - src/audio/speech.ts + - src/types.ts + - index.html + - src/styles/main.css + - src/main.ts +autonomous: true +requirements: [AUDI-01, AUDI-02, AUDI-03, AUDI-04, AUDI-05] + +must_haves: + truths: + - "playCorrectSound() erzeugt 800Hz Sinus-Ton fuer 0.1s bei audioEnabled=true" + - "playRewardSound() erzeugt aufsteigende Tonfolge fuer 0.8s" + - "playForestElementSound() erzeugt gefiltertes weisses Rauschen fuer 0.5s" + - "Mute-Button im DOM sichtbar, toggle aendert audioEnabled in Settings und persistiert" + - "speakText() liest deutschen Text via Web Speech API vor wenn speechEnabled=true" + - "AudioContext wird lazy bei erster User-Interaktion erstellt (Autoplay Policy)" + artifacts: + - path: "src/audio/sounds.ts" + provides: "Web Audio API sound effects" + exports: ["playCorrectSound", "playRewardSound", "playForestElementSound", "initAudioOnInteraction"] + - path: "src/audio/speech.ts" + provides: "Web Speech API text-to-speech" + exports: ["speakText"] + - path: "index.html" + provides: "Mute button element outside screens" + contains: "mute-btn" + key_links: + - from: "src/audio/sounds.ts" + to: "src/storage/db.ts" + via: "getSettings() check for audioEnabled" + pattern: "getSettings.*audioEnabled" + - from: "src/audio/speech.ts" + to: "src/storage/db.ts" + via: "getSettings() check for speechEnabled" + pattern: "getSettings.*speechEnabled" +--- + + +Audio-System fuer Zauberwald: Web Audio API Sound-Effekte (3 Sounds), Mute-Button, optionale Sprachausgabe via Web Speech API. + +Purpose: Auditives Feedback macht das Tipperlebnis lebendig und belohnend -- per D-01 bis D-05 aus CONTEXT.md. +Output: Zwei neue Module (sounds.ts, speech.ts), Mute-Button in index.html, speechEnabled Feld in Settings. + + + +@$HOME/.claude/get-shit-done/workflows/execute-plan.md +@$HOME/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/04-polish-audio/04-CONTEXT.md + +@src/types.ts +@src/storage/db.ts +@src/main.ts +@index.html +@src/styles/main.css + + + + + + Task 1: Audio module + Speech module + Settings extension + src/audio/sounds.ts, src/audio/speech.ts, src/types.ts + src/types.ts, src/storage/db.ts, .planning/phases/04-polish-audio/04-CONTEXT.md + +1. In `src/types.ts`: Add `speechEnabled: boolean` to the `Settings` interface (per D-05). Keep existing fields unchanged. + +2. Create `src/audio/sounds.ts` (per D-01, D-02): + - Module-level `let audioCtx: AudioContext | null = null` + - `initAudioOnInteraction()`: Creates/resumes AudioContext on first call. Intended to be called from a user-interaction event handler. Export this. + - Helper `isAudioEnabled()`: async, calls `getSettings(db)` from db.ts (needs db reference -- use a module-level `let db: IDBDatabase | null` set via an `setAudioDB(d)` function, or import `getDB()` from app.ts). Check `settings?.audioEnabled !== false`. Return boolean. + - `playCorrectSound()`: async. Check `isAudioEnabled()`. If false, return. Ensure audioCtx exists (call initAudioOnInteraction if needed). Create OscillatorNode: type sine, frequency 800Hz, connect to gain (0.15), start, stop after 0.1s. Ramp gain to 0 over last 0.02s for click-free cutoff. + - `playRewardSound()`: async. Check enabled. Ascending tone sequence: play 3-4 notes (e.g. C5=523, E5=659, G5=784, C6=1047) each ~0.2s apart, each 0.15s duration, sine wave, gain 0.12. Total ~0.8s. + - `playForestElementSound()`: async. Check enabled. Create white noise buffer (AudioBuffer, fill with Math.random()*2-1), play through BiquadFilterNode (bandpass, frequency 3000Hz, Q 0.5), gain 0.1, duration 0.5s with gain ramp-down. + - All functions: wrap in try/catch (never throw to caller). + +3. Create `src/audio/speech.ts` (per D-04, D-05): + - `speakText(text: string)`: async. Check `speechEnabled` from Settings via getSettings. If not enabled, return. Check `window.speechSynthesis` exists. Create `SpeechSynthesisUtterance(text)`, set `lang='de-DE'`, `rate=0.9`, `pitch=1.1`. Try to find a German voice (`getVoices().find(v => v.lang.startsWith('de'))`), set if found. Call `speechSynthesis.speak(utterance)`. Wrap in try/catch, silent fallback. + - Handle voice loading: voices may load async. Use `speechSynthesis.onvoiceschanged` if `getVoices()` returns empty initially. + + + cd /home/dev/workspace/zauberwald && npx tsc --noEmit 2>&1 | head -20 + + + - src/audio/sounds.ts exports playCorrectSound, playRewardSound, playForestElementSound, initAudioOnInteraction + - src/audio/speech.ts exports speakText + - Settings interface in types.ts includes speechEnabled: boolean + - All three sound functions check audioEnabled before playing + - speakText checks speechEnabled before speaking + - TypeScript compiles without errors + + Three sound functions and speakText function exist, all check Settings before executing, TypeScript compiles clean + + + + Task 2: Mute button in HTML + CSS + wiring in main.ts + index.html, src/styles/main.css, src/main.ts + index.html, src/main.ts, src/styles/main.css, src/storage/db.ts + +1. In `index.html` (per D-03): Add a mute button BEFORE the `