Created: 2026-05-24 | Updated: 2026-06-09 | Author: Senior Voice Architect | Status: Phase 1 Complete (v1.17.0) + Phase 2 WASM Scaffold + KokoroTTS + Async Engine Refactor Complete (2026-05-31) + Phase 3 Model Download UI Complete (v1.21, 2026-06-09)
WorldScript Studio receives a complete, opt-in Voice Full Support as a premium add-on feature. The app remains primarily mouse and keyboard driven. When activated, users can control nearly all features (navigation, writing, Plot Board, AI features, settings, export, collaboration) by voice.
Vision: Voice as an equal input medium alongside mouse/keyboard β with maximum privacy (local-first), offline capability, and WCAG 2.2 AAA-compliant accessibility. Voice Mode is a force multiplier for power users and a gateway for accessibility users.
Status v1.0 Foundation: All abstract engine interfaces, Web Speech API fallback implementations, Redux state, UI components, intent engine, command mappings, and 83 unit tests are implemented and green.
Status v1.19.0 WASM Scaffold (B-2): WasmSttEngine (Whisper.cpp WASM STT scaffold) und SileroVadEngine (Silero VAD v4 via ONNX Runtime Web) implementiert in services/voice/wasmSttEngine.ts + sileroVadEngine.ts. Beide implementieren die abstrakten Interfaces aus voiceTypes.ts. Aktivierung via enableVoiceWasm flag (off by default). Model-Download-UI ist Phase 3.
Status 2026-05-31 (Local AI Perfection β Phase 1.2):
KokoroTtsEngine(services/voice/kokoroTtsEngine.ts) β full ONNX TTS implementation; text β PCM Float32Array; lazy ONNX session; phoneme-pad preprocessing;dispose()releases session. Gated byenableVoiceWasm.SileroVadEngineβ upgraded to full LSTM implementation with hidden-state threading;processChunk(Float32Array)β{ isSpeech: boolean, probability: number }.- All engine interfaces (
SttEngine,TtsEngine,VadEngine,WakeWordEngine,IntentEngine) refactored toasync processChunk()β enables non-blocking pipeline usage. - TTS factory updated to prefer
KokoroTtsEnginewhenenableVoiceWasmis on; falls back toWebSpeechTtsEngine. - Eco-mode subscriber: when battery level < 30%,
voiceCommandServiceswitches to Web Speech API fallback to save battery.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β UI Layer (React 19) β
β VoiceControlPanel VoiceIndicator VoiceFeedbackToast β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββ
β Voice Orchestration Layer β
β useVoice() hook useVoiceAccessibility() hook β
β VoiceContext (React Context) β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββ
β Voice Service Layer β
β βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββββββ β
β β STT Engine β β TTS Engine β β Intent / NLU Engine β β
β β (abstract) β β (abstract) β β (context-aware) β β
β ββββββββ¬βββββββ ββββββββ¬βββββββ βββββββββββββ¬ββββββββββββββ β
β β β β β
β ββββββββΌβββββββ ββββββββΌβββββββ ββββββββββΌβββββββββ β
β βLocal (Whisp.β βLocal (Kokor.β βCommand Registry β β
β β+Sherpa-ONNX)β β+Piper) β β+Template Parser β β
β ββββββββ¬βββββββ ββββββββ¬βββββββ ββββββββββ¬βββββββββ β
β β β β β
β ββββββββΌβββββββ ββββββββΌβββββββ ββββββββββΌβββββββββ β
β βWeb Speech β βWeb Speech β βLocal MiniLM β β
β βAPI Fallback β βAPI Fallback β βIntent Classifierβ β
β βββββββββββββββ βββββββββββββββ βββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββ
β Microphone / Audio Layer β
β VAD Engine (Silero/WebRTC) Wake-Word Engine AudioWorklet β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Abstract engine pattern:
SttEngine,TtsEngine,VadEngine,WakeWordEngineas TypeScript interfaces with multiple implementations - Capability detection: Runtime check which engines are available (WASM support, WebGPU, model download status)
- Graceful degradation: Automatic fallback from local β Web Speech API β visual-only
- Worker isolation: Audio processing (VAD, STT chunking) in
workers/voiceAudio.worker.ts(v1.1) - Redux state:
features/voice/voiceSlice.tsfor persistent voice preferences (stored in Settings) - Zustand state:
app/transientUiStore.tsfor ephemeral UI (listening indicator, active mode)
- Default: "Hey WorldScript" or "OK WorldScript"
- Engine:
EnergyThresholdWakeWordEngineβ energy threshold + phrase-matching fallback - Future: Sherpa-ONNX wake-word (WASM) with small ONNX model (~50KB)
- Privacy: Wake-word runs entirely locally; no audio upload
- Primary:
WebRtcVadEngineβ energy-based VAD in pure JavaScript (immediately available) - Future: Silero VAD v4 via ONNX Runtime Web (~2MB model, lazy-loaded)
- Configuration:
threshold(0.01),minSilenceFrames(5),minSpeechFrames(3)
- Push-to-Talk (PTT): hold key (configurable, default:
Ctrl+Shift+V) β recommended for privacy - Wake-Word Mode: continuous VAD/wake-word hybrid; active listening after wake-word
- Manual Mode: click the voice button in the toolbar
- AudioWorklet: custom
voice-processor.jsfor 16kHz/16bit mono stream with minimal latency (v1.1)
- Permission: Explicit request on first activation with an explanation of its purpose
- Indicator: Permanent microphone status in status bar (only when voice is active)
- Muting: Fast mute via keyboard or click; audio stream is actually stopped
| Engine | Type | Size | Quality | Offline | Privacy | Languages | Status 2026 |
|---|---|---|---|---|---|---|---|
| Web Speech API | Browser-native | 0KB | Medium | No | Poor | Browser-dependent | β v1.0 fallback |
| Whisper.cpp WASM | Local WASM | ~30-80MB | Very high | Yes | Excellent | 99+ | v1.1 planned |
| Faster-Whisper (ONNX) | Local WASM | ~50MB | Very high | Yes | Excellent | 99+ | v1.1 planned |
| Sherpa-ONNX | Local WASM | ~5-20MB | High | Yes | Excellent | 10+ | v1.1 planned |
| Transformers.js Whisper | Web Transformer | ~30MB | High | Yes | Excellent | 99+ | v1.1 planned |
| Parakeet (NVIDIA) | Cloud/API | 0KB | Extremely high | No | Poor | En+ | Optional |
| Kokoro (ONNX) | Local TTS | ~15MB | Very high | Yes | Excellent | En+ | v1.1 planned |
| Piper | Local TTS | ~5-20MB | High | Yes | Excellent | 20+ | v1.1 planned |
| Coqui XTTS | Local TTS | ~400MB | Extremely high | Yes | Excellent | Multi | Heavyweight |
STT:
- Primary (v1.1): Whisper.cpp WASM (tiny/base model, ~30-80MB)
- Secondary (v1.1): Sherpa-ONNX (faster streaming, lower latency)
- Fallback β v1.0: Web Speech API (immediately available, no downloads)
TTS:
- Primary (v1.1): Kokoro (ONNX, ~15MB)
- Secondary (v1.1): Piper (~5MB)
- Fallback β
v1.0: Web Speech API
speechSynthesis
VAD:
- Primary (v1.1): Silero VAD v4 via ONNX Runtime Web
- Fallback β v1.0: WebRTC native VAD (energy-based)
Wake-Word:
- Primary (v1.1): Sherpa-ONNX wake-word
- Fallback β v1.0: Energy threshold + phrase matching
- Whisper.cpp WASM with streaming support (chunk-based) β v1.1
- Model tiers:
tiny(~30MB): For fast devices, very good qualitybase(~80MB): For desktop/high-end, best quality- Model download on-demand with progress indicator
- Language detection: Automatic language recognition (Whisper supports 99+ languages)
- Prompting: Context prompt with current project content for better proper-noun recognition
- Cloud fallback: When local is unavailable AND user has explicitly consented, optional cloud STT (Gemini STT API)
- Toggle: Setting "Allow cloud speech processing" (default: false)
Microphone (16kHz/16bit Mono)
β AudioWorklet (voice-processor)
β VAD (Silero) β splits in speech chunks
β STT Engine (Whisper.cpp / Sherpa-ONNX)
β Intent Engine
β Command Execution
- Command registry reuse: Existing
services/commands/commandBuilder.tsis extended withvoiceKeywordsper command - Intent templates: Natural language templates can be assigned to each command definition
- Example:
"navigate to {view}","open {view}","show {view}"βglobal-dashboard
- Example:
- Slot extraction:
{view},{characterName},{sectionTitle}are extracted from the transcript
- Current view: "next scene" means something different in the manuscript vs. on the Plot Board
- Selection: "delete this" deletes the current selection
- Last actions: "do that again" repeats the last command
- Project context: Character names, scene titles, and locations are known and recognized as slots
- Rule-based (fast) β v1.0: 80% of commands via template matching and keyword scoring (Jaccard similarity)
- Semantic (precise): Local embedding similarity (MiniLM via ONNX) for similar commands β v1.2
- LLM fallback (complex): For complex multi-part commands a small local LLM (Phi-3.5 mini / Qwen 2.5 0.5B) is used via WebLLM β v1.2
- "Create a new scene after the current one titled 'The Forest' and link the protagonist"
- "Change the font size to 18, activate Zen Mode, and jump to the manuscript"
- "Export the current project as PDF with the default template"
- WCAG 2.2 AA/AAA: All voice interactions are fully keyboard-operable
- 2.1.1 Keyboard: Voice activation possible via keyboard (PTT key)
- 2.1.4 Character Key Shortcuts: No single-character shortcuts for voice
- 2.2.1 Timing Adjustable: Voice listening timeout configurable (5-30s)
- 2.2.2 Pause, Stop, Hide: TTS can be stopped at any time
- 2.4.3 Focus Order: After a voice command focus remains logically positioned
- 2.5.5 Target Size: Voice buttons at least 44Γ44px
aria-live="polite"regions for voice feedbackaria-atomic="true"for complete announcements- Distinction: system feedback vs. user transcription
- Voice panel as
role="region"witharia-label="Voice Control" - Voice button as
role="button"witharia-pressedfor listening status - Transcription display as
role="log"witharia-live="polite"
- On command execution:
aria-liveannouncement of the result - On errors:
aria-live="assertive"for immediate attention - On mode change: status change communicated via
aria-live
- After a voice command focus is moved to the affected element
- On navigation: focus on the main content of the new view
- On dictation: focus in the editor, cursor at the insertion position
- Confirmation level configurable:
minimal: Errors and ambiguities onlystandard: Confirmation on every actionverbose: Detailed descriptions and help
- Context-dependent:
- Navigation: brief confirmation ("Dashboard")
- Destructive actions: explicit confirmation ("Delete scenes β are you sure?")
- AI generation: progress announcements ("Generating ideas... Done")
- Visual indicators take precedence over audio
- Audio feedback only when app is in the background or explicitly requested
- Silent mode: TTS completely disableable
- Night mode: reduced volume, no wake-word audio
- Kokoro (v1.1): ONNX-based, ~15MB, extremely natural, good for longer texts
- Piper (v1.1): Fast, small (~5MB), good for short feedback announcements
- Web Speech API β v1.0: Immediately available but lower quality
- Lazy-load: Download TTS model only on first use
- Streaming: For longer texts (reading the manuscript aloud)
- Voice selection: Available per language
- Parameters: Rate (0.5-2.0), pitch, volume
- All 18 views reachable
- "Back", "Forward" in browser history
- "Help for [view]"
- Dictation: Continuous insertion of transcription
- Formatting: "Bold", "Italic", "Heading", etc.
- Cursor: "Beginning", "End", "forward three words", "delete sentence"
- Scenes: "New scene", "next scene", "delete scene"
- "New scene here", "move scene to the left"
- "Connect scene one with scene two"
- "Zoom out", "center board"
- "Generate plot ideas", "write dialog for [character]"
- "Check consistency", "start character interview"
- "Change theme to dark", "font size 18"
- "Activate Zen Mode"
services/voice/
voiceCommandService.ts (orchestrator β 162 lines)
voiceTypes.ts (shared interfaces β 198 lines)
sttEngine.ts (Web Speech API STT β 149 lines)
ttsEngine.ts (Web Speech API TTS β 125 lines)
vadEngine.ts (energy-based VAD β 90 lines)
wakeWordEngine.ts (energy-threshold wake-word β 67 lines)
intentEngine.ts (hybrid template + fuzzy β 104 lines)
feedbackService.ts (TTS feedback orchestration β 130 lines)
audioNavigator.ts (ARIA focus management β 136 lines)
commandVoiceMappings.ts (25 static voice commands β 203 lines)
wasmSttEngine.ts (Whisper.cpp WASM STT scaffold β v1.19.0 B-2)
sileroVadEngine.ts (Silero VAD v4 / ONNX scaffold β v1.19.0 B-2)
features/voice/
voiceSlice.ts (Redux state β 199 lines)
hooks/
useVoice.ts (React bridge β 187 lines)
usePushToTalk.ts (Ctrl+Shift+V handler β 89 lines)
useVoiceDictation.ts (editor dictation β 134 lines)
useVoiceAccessibility.ts (ARIA integration β 112 lines)
components/voice/
VoiceControlPanel.tsx (voice UI panel β 278 lines)
VoiceIndicator.tsx (status indicator β 156 lines)
VoiceSettingsSection.tsx (settings UI β 312 lines)
tests/unit/voice/
voiceSlice.test.ts (10 tests)
feedbackService.test.ts (4 tests)
intentEngine.test.ts (7 tests)
sttEngine.test.ts (9 tests)
ttsEngine.test.ts (10 tests)
vadEngine.test.ts (7 tests)
wakeWordEngine.test.ts (11 tests)
audioNavigator.test.ts (13 tests)
commandVoiceMappings.test.ts (12 tests)
βββββββββββββββββββββββββββββββββββββββββ
Total: 83 tests / 9 files
types.ts β VoiceSettings, Voice* enums
features/settings/settingsSlice.ts β VoiceSettings reducer
features/voice/voiceSlice.ts β Extended state (mode, engine status, dictation)
features/featureFlags/featureFlagsSlice.ts β enableVoiceSupport flag
app/store.ts β voiceSlice registration
components/App.tsx β Voice event listeners, PTT hook, conditional UI
components/Header.tsx β useVoice integration
components/manuscript/ManuscriptEditor.tsx β dictation support
components/settings/SettingsView.tsx β VoiceSettingsSection tab
locales/*/settings.json β 2025 keys Γ 5 locales (voice keys added)
- Local-first: All voice engines run locally in the browser
- No audio upload: Microphone audio never leaves the device (except on explicit cloud opt-in)
- Cloud opt-in separate: Extra toggle for cloud STT, default: off
- WASM sandbox: All local models run in WASM sandbox
- CSP-compatible: No
eval(), no inline scripts - No API keys in voice: Voice needs no cloud keys
- Service Worker: Voice models cached after first download
- Progressive download: Models are downloaded when activated
- Offline indicator: Clear display when voice is available offline
- Lazy loading: Voice modules loaded only on activation
- Worker isolation: Audio processing not on the main thread
- Model caching: IndexedDB for downloaded models
- Chunk sizes: STT in 5-10s chunks for low latency
| Situation | Fallback | UX |
|---|---|---|
| WASM not supported | Web Speech API | Info toast |
| Model download failed | Web Speech API | Retry button |
| Microphone unavailable | Visual mode (typing) | Explanatory dialog |
| STT engine crashed | Auto-restart once, then fallback | Silent fallback |
| Intent not recognized | "I didn't understand that" + suggestions | Polite announcement |
| TTS unavailable | Visual feedback only | No error |
- Voice feature always works in some form
- Minimum feature set: Web Speech API + visual feedback
- No hard error on unavailability
voiceSlice.test.tsβ Redux state transitions (10 tests)intentEngine.test.tsβ Template-Matching, Slot-Extraction, View-Filtering (7 tests)feedbackService.test.tsβ Feedback-Level-Logik, Queue, Cancel (4 tests)sttEngine.test.tsβ Web Speech API abstraction, fallback logic (9 tests)ttsEngine.test.tsβ TTS abstraction, error handling (10 tests)vadEngine.test.tsβ Energy-threshold VAD, speech/silence detection (7 tests)wakeWordEngine.test.tsβ Phrase matching, custom phrases, history (11 tests)audioNavigator.test.tsβ ARIA landmark scanning, focus management, live regions (13 tests)commandVoiceMappings.test.tsβ Command definitions, map building (12 tests)
Total: 83 tests / 9 test files β all passing
voiceCommandService.test.tsβ end-to-end command executionuseVoice.test.tsβ hook behavior
- axe-core on voice panel
- Keyboard navigation voice UI
- Screen reader compatibility
- Voice activation flow
- Command execution via simulated transcript
- Graceful degradation without microphone
- β
VoiceSettings in
types.ts - β
featureFlags.enableVoiceSupport - β Extend voice slice (mode, engine status, feedback level)
- β
Abstract engine interfaces (
voiceTypes.ts) - β Web Speech API implementations (immediately usable)
- β Intent engine (template + fuzzy Jaccard)
- β Command voice mappings (25 commands)
- β Feedback service (3 verbosity levels)
- β Audio navigator (ARIA landmarks + focus)
- β UI components (VoiceControlPanel, VoiceIndicator, VoiceSettingsSection)
- β React hooks (useVoice, usePushToTalk, useVoiceDictation, useVoiceAccessibility)
- β App integration (App.tsx, Header.tsx, ManuscriptEditor.tsx)
- β i18n for all 5 languages (2025 keys)
- β 83 unit tests (9 files)
- β Quality gate: lint β Β· i18n:check β Β· typecheck β
- β
VAD Engine (Silero via ONNX) β full LSTM implementation;
processChunkasync; model download UI Phase 3 - β¬ Wake-Word Engine (Sherpa-ONNX) β Phase 4
- β
STT engine (Whisper.cpp WASM) β
wasmSttEngine.tsscaffold; chunked inference; model download UI delivered Phase 3 - β
TTS engine (Kokoro ONNX) β
kokoroTtsEngine.tsfull implementation; PCM Float32Array output;enableVoiceWasmgated - β
Async engine refactor β all
processChunk()methods async; eco-mode battery subscriber - β¬ AudioWorklet for microphone processing β Phase 4
- β
VoiceModelDownloadModal(components/voice/) β progress bar, cancel (AbortController), retry; handles both STT (Whisper Q8, ~42 MB) and TTS (Kokoro, ~15 MB) model types - β
VoiceSettingsSectionβ separate "Download STT Model" + "Download TTS Model" buttons;downloadModelTypestate threads choice into modal - β
VoiceCommandService.downloadVoiceModels(modelType, signal?)β AbortSignal-aware download pipeline; all await checkpoints respect cancellation - β CodeAnt fixes: modal cancel now truly aborts in-flight fetch; TTS path fully reachable from Settings UI
- β
settings.voice.wasmModelsReadyflipped totrueon successful download (persisted) - β
i18n keys:
voice.modelDownload.*added to all 11 locales (2348 keys total)
- Semantic intent matching (MiniLM embeddings)
- Local LLM fallback (WebLLM Phi-3.5 mini)
- Complex multi-slot commands
- Plot Board voice control (canvas mode)
- AI feature voice integration
- Settings voice shortcuts
- Collaboration voice commands
- Integration tests (voiceCommandService, useVoice)
- E2E tests (Playwright)
- Accessibility audit (axe-core)
- Performance optimization
- Documentation finalization
{
"dependencies": {
"onnxruntime-web": "^1.20.0",
"@xenova/transformers": "^3.0.0",
"whisper-web": "^1.0.0"
},
"optionalDependencies": {
"sherpa-onnx-wasm": "^1.10.0"
}
}Note: Since WorldScript Studio strictly prioritizes privacy and offline-first, all voice engines are loaded as WASM/ONNX and executed locally. No cloud dependency for the base mode.