/** * Text-to-Speech Handler for AI Interactive Fiction * Uses Web Speech API for text-to-speech */ class TTSHandler { constructor() { this.enabled = false; this.speaking = false; this.queue = []; this.synthesis = window.speechSynthesis; this.utterance = null; // Check if browser supports speech synthesis if (this.synthesis) { console.log('Speech synthesis is supported in this browser'); this.browserSupport = true; } else { console.warn('Speech synthesis is not supported in this browser'); this.browserSupport = false; } } /** * Toggle TTS on/off */ toggle() { this.enabled = !this.enabled; if (!this.enabled && this.speaking) { this.stop(); } return this.enabled; } /** * Speak the given text */ speak(text) { if (!this.enabled || !this.browserSupport) return; // Add to queue this.queue.push(text); // If not already speaking, start processing queue if (!this.speaking) { this.processQueue(); } } /** * Process the speech queue */ processQueue() { if (this.queue.length === 0 || this.speaking) return; this.speaking = true; const text = this.queue.shift(); try { this.utterance = new SpeechSynthesisUtterance(text); // Configure speech options this.utterance.rate = 1.0; // Speech rate (0.1 to 10) this.utterance.pitch = 1.0; // Speech pitch (0 to 2) // When speech ends, process the next item this.utterance.onend = () => { this.speaking = false; this.processQueue(); }; // If speech is interrupted or errors this.utterance.onerror = (event) => { console.error('TTS error:', event.error); this.speaking = false; this.processQueue(); }; this.synthesis.speak(this.utterance); } catch (error) { console.error('TTS error:', error); this.speaking = false; this.processQueue(); } } /** * Stop current speech */ stop() { if (this.synthesis && this.speaking) { this.synthesis.cancel(); } this.queue = []; this.speaking = false; } /** * Check if TTS is ready */ isReady() { return this.browserSupport; } } // Create a global instance const tts = new TTSHandler();