# Text-to-Speech (TTS) - Implementation Plan ## ๐Ÿ“‹ Overview Implement a full-featured Text-to-Speech system for the Bible reader, allowing users to listen to Scripture while reading, driving, exercising, or multitasking. **Status:** Planning Phase **Priority:** ๐Ÿ”ด High **Estimated Time:** 2-3 weeks (80-120 hours) **Target Completion:** TBD --- ## ๐ŸŽฏ Goals & Objectives ### Primary Goals 1. Provide accessible audio playback of Bible content 2. Support multiple voices and languages 3. Enable hands-free Bible reading 4. Improve accessibility for visually impaired users 5. Allow multitasking while consuming Scripture ### User Value Proposition - **For visually impaired users**: Full accessibility to Bible content - **For commuters**: Listen during driving/transit - **For learners**: Audio reinforcement of reading - **For multitaskers**: Listen while doing other activities - **For language learners**: Hear correct pronunciation --- ## โœจ Feature Specifications ### 1. Core TTS Functionality #### Web Speech API (Free Tier) - Uses browser's built-in speech synthesis - No API costs - Works offline after initial load - Variable quality depending on OS/browser #### Premium Voices (Optional - Phase 2) - Amazon Polly integration - Google Cloud Text-to-Speech - Higher quality, more natural voices - Multiple accents and styles - Costs: ~$4 per 1 million characters ### 2. Voice Selection ```typescript interface Voice { id: string name: string language: string gender: 'male' | 'female' | 'neutral' quality: 'standard' | 'premium' provider: 'browser' | 'polly' | 'google' isDefault: boolean localeName: string // e.g., "en-US", "es-ES" } interface TTSConfig { // Voice selectedVoiceId: string // Playback rate: number // 0.5 - 2.0 (speed) pitch: number // 0.5 - 2.0 (pitch) volume: number // 0 - 1 // Behavior autoAdvanceChapter: boolean highlightCurrentVerse: boolean pauseBetweenVerses: number // 0-2000ms pauseBetweenChapters: number // 0-5000ms // Display showFloatingPlayer: boolean showProgress: boolean minimizeWhenPlaying: boolean } ``` ### 3. Playback Controls #### Player UI Components ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๐Ÿ”Š Genesis 1:1-31 โš™๏ธ ๐Ÿ“ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โฎ โช โ–ถ๏ธ โฉ โญ 1.0x ๐Ÿ”ˆโ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ—โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” 65% โ”‚ โ”‚ Verse 15 of 31 โ€ข 2:34 / 6:12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` **Controls:** - Play/Pause - Previous/Next Verse - Previous/Next Chapter - Skip Backward 10s / Forward 10s - Speed Control (0.5x, 0.75x, 1.0x, 1.25x, 1.5x, 2.0x) - Volume Control - Settings Menu - Pin/Unpin Player #### Keyboard Shortcuts ```typescript const shortcuts = { 'Space': 'Play/Pause', 'ArrowLeft': 'Previous verse', 'ArrowRight': 'Next verse', 'Shift+ArrowLeft': 'Previous chapter', 'Shift+ArrowRight': 'Next chapter', 'ArrowUp': 'Increase speed by 0.25x', 'ArrowDown': 'Decrease speed by 0.25x', '[': 'Skip backward 10s', ']': 'Skip forward 10s', 'M': 'Mute/Unmute', 'Escape': 'Stop playback' } ``` ### 4. Visual Feedback #### Active Verse Highlighting ```typescript interface HighlightConfig { enabled: boolean style: 'background' | 'border' | 'underline' | 'bold' color: string scrollToVerse: boolean scrollBehavior: 'auto' | 'smooth' centerVerse: boolean } // CSS Example .verse-playing { background-color: rgba(var(--primary-rgb), 0.1); border-left: 4px solid var(--primary-color); padding-left: 12px; margin-left: -16px; scroll-margin-top: 100px; /* For scroll-into-view */ transition: all 0.3s ease; } ``` #### Progress Visualization - Linear progress bar - Circular progress (for floating player) - Time elapsed / total time - Verse counter (current / total) - Visual waveform (optional, premium) ### 5. Verse-Level Navigation ```typescript interface VersePosition { book: string chapter: number verse: number verseText: string startTime: number // ms from chapter start duration: number // ms for this verse } class VerseNavigator { private verses: VersePosition[] private currentIndex: number getCurrentVerse(): VersePosition nextVerse(): VersePosition previousVerse(): VersePosition jumpToVerse(verseNum: number): void getProgress(): number // 0-100% } ``` ### 6. Background Playback #### Service Worker Integration ```typescript // Support for background playback on mobile // Uses Media Session API if ('mediaSession' in navigator) { navigator.mediaSession.metadata = new MediaMetadata({ title: 'Genesis 1:1-31', artist: 'Bible Reader', album: 'Old Testament', artwork: [ { src: '/icons/bible-96.png', sizes: '96x96', type: 'image/png' }, { src: '/icons/bible-256.png', sizes: '256x256', type: 'image/png' } ] }) navigator.mediaSession.setActionHandler('play', handlePlay) navigator.mediaSession.setActionHandler('pause', handlePause) navigator.mediaSession.setActionHandler('previoustrack', handlePreviousVerse) navigator.mediaSession.setActionHandler('nexttrack', handleNextVerse) navigator.mediaSession.setActionHandler('seekbackward', () => seek(-10)) navigator.mediaSession.setActionHandler('seekforward', () => seek(10)) } ``` ### 7. Persistent Player Bar #### Floating Player States 1. **Full Player** - All controls visible 2. **Mini Player** - Compact view with play/pause and progress 3. **Hidden** - Only show icon in corner 4. **Minimized to Tab** - Shows in browser tab title ```typescript type PlayerSize = 'full' | 'mini' | 'icon' | 'hidden' interface PlayerPosition { size: PlayerSize position: 'top' | 'bottom' sticky: boolean // Stays visible when scrolling docked: 'left' | 'center' | 'right' } ``` --- ## ๐Ÿ—๏ธ Technical Implementation ### File Structure ``` /components/bible-reader/ โ”œโ”€โ”€ tts/ โ”‚ โ”œโ”€โ”€ TTSProvider.tsx # Context provider โ”‚ โ”œโ”€โ”€ TTSPlayer.tsx # Main player component โ”‚ โ”œโ”€โ”€ TTSControls.tsx # Playback controls โ”‚ โ”œโ”€โ”€ TTSSettings.tsx # Settings panel โ”‚ โ”œโ”€โ”€ VoiceSelector.tsx # Voice selection UI โ”‚ โ”œโ”€โ”€ FloatingPlayer.tsx # Floating/sticky player โ”‚ โ”œโ”€โ”€ VerseHighlighter.tsx # Active verse highlighting โ”‚ โ”œโ”€โ”€ PlaybackProgress.tsx # Progress bar/circle โ”‚ โ”œโ”€โ”€ engines/ โ”‚ โ”‚ โ”œโ”€โ”€ WebSpeechEngine.ts # Browser TTS โ”‚ โ”‚ โ”œโ”€โ”€ PollyEngine.ts # Amazon Polly (Phase 2) โ”‚ โ”‚ โ””โ”€โ”€ GoogleTTSEngine.ts # Google TTS (Phase 2) โ”‚ โ””โ”€โ”€ hooks/ โ”‚ โ”œโ”€โ”€ useTTS.ts # Main TTS hook โ”‚ โ”œโ”€โ”€ useVoices.ts # Voice management โ”‚ โ”œโ”€โ”€ usePlayback.ts # Playback state โ”‚ โ”œโ”€โ”€ useVerseTracking.ts # Track current verse โ”‚ โ””โ”€โ”€ useMediaSession.ts # Background playback โ””โ”€โ”€ reader.tsx # Updated main reader ``` ### Core TTS Engine (Web Speech API) ```typescript // engines/WebSpeechEngine.ts export class WebSpeechEngine { private synth: SpeechSynthesis private utterance: SpeechSynthesisUtterance | null = null private currentVerseIndex: number = 0 private verses: string[] = [] private isPaused: boolean = false constructor() { this.synth = window.speechSynthesis } async getVoices(): Promise { return new Promise((resolve) => { const voices = this.synth.getVoices() if (voices.length > 0) { resolve(this.mapVoices(voices)) } else { // Some browsers load voices asynchronously this.synth.onvoiceschanged = () => { resolve(this.mapVoices(this.synth.getVoices())) } } }) } private mapVoices(synthVoices: SpeechSynthesisVoice[]): Voice[] { return synthVoices.map(v => ({ id: v.voiceURI, name: v.name, language: v.lang, gender: this.detectGender(v.name), quality: 'standard', provider: 'browser', isDefault: v.default, localeName: v.lang })) } private detectGender(name: string): 'male' | 'female' | 'neutral' { const lower = name.toLowerCase() if (lower.includes('female') || lower.includes('woman')) return 'female' if (lower.includes('male') || lower.includes('man')) return 'male' return 'neutral' } async speak( text: string, config: TTSConfig, onBoundary?: (charIndex: number) => void, onEnd?: () => void ): Promise { return new Promise((resolve, reject) => { // Cancel any existing speech this.synth.cancel() this.utterance = new SpeechSynthesisUtterance(text) // Find selected voice const voices = this.synth.getVoices() const voice = voices.find(v => v.voiceURI === config.selectedVoiceId) if (voice) { this.utterance.voice = voice } // Apply settings this.utterance.rate = config.rate this.utterance.pitch = config.pitch this.utterance.volume = config.volume // Event handlers this.utterance.onboundary = (event) => { if (onBoundary) onBoundary(event.charIndex) } this.utterance.onend = () => { if (onEnd) onEnd() resolve() } this.utterance.onerror = (event) => { console.error('Speech error:', event) reject(event) } // Start speaking this.synth.speak(this.utterance) }) } pause(): void { if (this.synth.speaking && !this.synth.paused) { this.synth.pause() this.isPaused = true } } resume(): void { if (this.synth.paused) { this.synth.resume() this.isPaused = false } } stop(): void { this.synth.cancel() this.isPaused = false } isSpeaking(): boolean { return this.synth.speaking && !this.synth.paused } isPausedState(): boolean { return this.isPaused } } ``` ### TTS Context Provider ```typescript // TTSProvider.tsx interface TTSContextType { // State isPlaying: boolean isPaused: boolean currentVerse: VersePosition | null config: TTSConfig voices: Voice[] progress: number // 0-100 // Actions play(): Promise pause(): void resume(): void stop(): void nextVerse(): void previousVerse(): void nextChapter(): void previousChapter(): void jumpToVerse(verseNum: number): void setSpeed(rate: number): void setVoice(voiceId: string): void setVolume(volume: number): void updateConfig(config: Partial): void } export const TTSProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [engine] = useState(() => new WebSpeechEngine()) const [isPlaying, setIsPlaying] = useState(false) const [isPaused, setIsPaused] = useState(false) const [config, setConfig] = useState(loadConfig()) const [voices, setVoices] = useState([]) const [currentVerse, setCurrentVerse] = useState(null) const [verses, setVerses] = useState([]) const [progress, setProgress] = useState(0) // Load voices on mount useEffect(() => { engine.getVoices().then(setVoices) }, [engine]) // Save config to localStorage useEffect(() => { localStorage.setItem('tts-config', JSON.stringify(config)) }, [config]) const play = async () => { if (verses.length === 0) return setIsPlaying(true) setIsPaused(false) const playVerse = async (index: number) => { if (index >= verses.length) { if (config.autoAdvanceChapter) { // Load next chapter await loadNextChapter() } else { stop() } return } const verse = verses[index] setCurrentVerse(verse) setProgress((index / verses.length) * 100) try { await engine.speak( verse.verseText, config, undefined, () => { // Verse completed if (config.pauseBetweenVerses > 0) { setTimeout(() => { playVerse(index + 1) }, config.pauseBetweenVerses) } else { playVerse(index + 1) } } ) } catch (error) { console.error('TTS error:', error) stop() } } playVerse(currentVerse ? verses.indexOf(currentVerse) : 0) } const pause = () => { engine.pause() setIsPaused(true) } const resume = () => { engine.resume() setIsPaused(false) } const stop = () => { engine.stop() setIsPlaying(false) setIsPaused(false) setCurrentVerse(null) setProgress(0) } const nextVerse = () => { if (!currentVerse) return const currentIndex = verses.indexOf(currentVerse) if (currentIndex < verses.length - 1) { const wasPlaying = isPlaying stop() setCurrentVerse(verses[currentIndex + 1]) if (wasPlaying) play() } } const previousVerse = () => { if (!currentVerse) return const currentIndex = verses.indexOf(currentVerse) if (currentIndex > 0) { const wasPlaying = isPlaying stop() setCurrentVerse(verses[currentIndex - 1]) if (wasPlaying) play() } } // ... more methods return ( {children} ) } ``` ### TTS Player UI Component ```typescript // TTSPlayer.tsx export const TTSPlayer: React.FC = () => { const { isPlaying, isPaused, currentVerse, config, progress, play, pause, resume, stop, nextVerse, previousVerse, setSpeed } = useTTS() const [playerSize, setPlayerSize] = useState('full') const [isVisible, setIsVisible] = useState(false) // Show player when playback starts useEffect(() => { if (isPlaying) { setIsVisible(true) } }, [isPlaying]) if (!isVisible) return null const handlePlayPause = () => { if (isPlaying && !isPaused) { pause() } else if (isPaused) { resume() } else { play() } } const speeds = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0] const currentSpeedIndex = speeds.indexOf(config.rate) const cycleSpeed = () => { const nextIndex = (currentSpeedIndex + 1) % speeds.length setSpeed(speeds[nextIndex]) } if (playerSize === 'mini') { return ( {isPlaying && !isPaused ? : } {currentVerse?.book} {currentVerse?.chapter}:{currentVerse?.verse} setPlayerSize('full')}> ) } return ( {/* Header */} {currentVerse?.book} {currentVerse?.chapter}:1-{verses.length} setPlayerSize('mini')}> {/* Main Controls */} {isPlaying && !isPaused ? : } {/* Progress Bar */} Verse {currentVerse?.verse} of {verses.length} {Math.round(progress)}% {/* Secondary Controls */} setVolume(value as number)} min={0} max={1} step={0.1} sx={{ width: 100 }} /> ) } ``` ### Verse Highlighting ```typescript // VerseHighlighter.tsx export const VerseHighlighter: React.FC = () => { const { currentVerse, config } = useTTS() useEffect(() => { if (!currentVerse || !config.highlightCurrentVerse) return const verseElement = document.querySelector( `[data-verse="${currentVerse.verse}"]` ) if (verseElement) { // Add playing class verseElement.classList.add('verse-playing') // Scroll into view if (config.scrollToVerse) { verseElement.scrollIntoView({ behavior: 'smooth', block: 'center' }) } // Cleanup return () => { verseElement.classList.remove('verse-playing') } } }, [currentVerse, config]) return null // Pure effect component } ``` ### Media Session API (Background Playback) ```typescript // hooks/useMediaSession.ts export const useMediaSession = () => { const { currentVerse, isPlaying, play, pause, nextVerse, previousVerse } = useTTS() useEffect(() => { if (!('mediaSession' in navigator)) return if (currentVerse) { navigator.mediaSession.metadata = new MediaMetadata({ title: `${currentVerse.book} ${currentVerse.chapter}:${currentVerse.verse}`, artist: 'Bible Reader', album: currentVerse.book, artwork: [ { src: '/icons/bible-96.png', sizes: '96x96', type: 'image/png' }, { src: '/icons/bible-192.png', sizes: '192x192', type: 'image/png' }, { src: '/icons/bible-512.png', sizes: '512x512', type: 'image/png' } ] }) } // Set up action handlers navigator.mediaSession.setActionHandler('play', () => play()) navigator.mediaSession.setActionHandler('pause', () => pause()) navigator.mediaSession.setActionHandler('previoustrack', () => previousVerse()) navigator.mediaSession.setActionHandler('nexttrack', () => nextVerse()) // Update playback state navigator.mediaSession.playbackState = isPlaying ? 'playing' : 'paused' return () => { navigator.mediaSession.setActionHandler('play', null) navigator.mediaSession.setActionHandler('pause', null) navigator.mediaSession.setActionHandler('previoustrack', null) navigator.mediaSession.setActionHandler('nexttrack', null) } }, [currentVerse, isPlaying, play, pause, nextVerse, previousVerse]) } ``` --- ## ๐Ÿ’พ Data Persistence ### LocalStorage Schema ```typescript interface TTSStorage { version: number config: TTSConfig recentVoices: string[] // Voice IDs lastPlayedVerse: { book: string chapter: number verse: number } | null stats: { totalListeningTime: number // seconds chaptersCompleted: number favoriteVoice: string } } // Key: 'bible-reader:tts' ``` ### User Preferences API ```typescript // Add to UserPreference model model UserPreference { // ... existing fields ttsConfig Json? ttsVoiceId String? ttsRate Float? @default(1.0) } // Sync endpoint POST /api/user/preferences/tts Body: Partial ``` --- ## ๐Ÿ“Š API Endpoints ### For Premium Voices (Phase 2) ```typescript // /api/tts/voices GET /api/tts/voices Response: { voices: Voice[] providers: { browser: Voice[] polly: Voice[] google: Voice[] } } // /api/tts/synthesize POST /api/tts/synthesize Body: { text: string voiceId: string provider: 'polly' | 'google' config: TTSConfig } Response: { audioUrl: string // Signed URL to audio file duration: number // seconds } ``` --- ## ๐Ÿงช Testing Strategy ### Unit Tests ```typescript // __tests__/tts/web-speech-engine.test.ts describe('WebSpeechEngine', () => { it('should load available voices', async () => { const engine = new WebSpeechEngine() const voices = await engine.getVoices() expect(voices.length).toBeGreaterThan(0) }) it('should speak text with config', async () => { const engine = new WebSpeechEngine() const mockSynth = jest.spyOn(window.speechSynthesis, 'speak') await engine.speak('Test', defaultConfig) expect(mockSynth).toHaveBeenCalled() }) it('should pause and resume correctly', () => { const engine = new WebSpeechEngine() engine.pause() expect(engine.isPausedState()).toBe(true) engine.resume() expect(engine.isPausedState()).toBe(false) }) }) ``` ### Integration Tests ```typescript // __tests__/tts/integration.test.tsx describe('TTS Integration', () => { it('should play verse and highlight it', async () => { render( ) const playButton = screen.getByRole('button', { name: /play/i }) fireEvent.click(playButton) await waitFor(() => { expect(screen.getByText(/Genesis 1:1/)).toHaveClass('verse-playing') }) }) }) ``` ### Manual Testing Checklist - [ ] All voices load correctly - [ ] Playback works across browsers (Chrome, Firefox, Safari) - [ ] Speed adjustment works (0.5x - 2.0x) - [ ] Volume control works - [ ] Verse highlighting syncs with audio - [ ] Auto-advance to next verse works - [ ] Auto-advance to next chapter works - [ ] Background playback works on mobile - [ ] Media controls in notification shade work - [ ] Settings persist across sessions - [ ] Player UI is responsive on mobile - [ ] Keyboard shortcuts work correctly - [ ] No memory leaks during long playback --- ## ๐Ÿ“… Implementation Timeline ### Phase 1: Core TTS (Week 1) **Day 1-2: Foundation** - [ ] Create TTS context provider - [ ] Implement Web Speech API engine - [ ] Build voice selector component - [ ] Add basic play/pause controls **Day 3-4: Player UI** - [ ] Design and build full player UI - [ ] Implement mini player mode - [ ] Add progress bar and tracking - [ ] Create settings panel **Day 5: Verse Navigation** - [ ] Implement verse-by-verse playback - [ ] Add next/previous verse controls - [ ] Build verse position tracking - [ ] Test chapter boundaries **Deliverable:** Working TTS with basic controls ### Phase 2: Enhanced Features (Week 2) **Day 1-2: Visual Feedback** - [ ] Implement verse highlighting - [ ] Add scroll-to-verse - [ ] Create speed controls - [ ] Build volume controls **Day 3-4: Advanced Controls** - [ ] Add keyboard shortcuts - [ ] Implement skip forward/backward - [ ] Create chapter navigation - [ ] Add auto-advance features **Day 5: Mobile & Background** - [ ] Implement Media Session API - [ ] Test background playback - [ ] Optimize for mobile - [ ] Add floating player **Deliverable:** Full-featured TTS system ### Phase 3: Premium Voices (Week 3 - Optional) **Day 1-2: Backend Integration** - [ ] Set up Amazon Polly API - [ ] Create synthesis endpoint - [ ] Implement audio caching - [ ] Build voice preview **Day 3-4: Frontend Integration** - [ ] Add premium voice selector - [ ] Implement streaming playback - [ ] Handle API errors gracefully - [ ] Add loading states **Day 5: Polish & Testing** - [ ] Test premium voices - [ ] Optimize API usage - [ ] Add cost monitoring - [ ] Documentation **Deliverable:** Premium TTS with high-quality voices --- ## ๐Ÿš€ Deployment Plan ### Pre-Launch Checklist - [ ] All unit tests passing - [ ] Integration tests passing - [ ] Cross-browser testing complete - [ ] Mobile testing complete (iOS + Android) - [ ] Accessibility audit passed - [ ] Performance benchmarks met - [ ] User documentation created - [ ] Analytics events configured ### Rollout Strategy 1. **Beta (Week 1)**: 10% of users, Web Speech API only 2. **Staged (Week 2)**: 50% of users, collect feedback 3. **Full (Week 3)**: 100% of users 4. **Premium (Week 4)**: Launch premium voices for subscribers ### Browser Support - โœ… Chrome 33+ (excellent support) - โœ… Edge 14+ (excellent support) - โœ… Safari 7+ (good support) - โš ๏ธ Firefox 49+ (limited voices) - โŒ IE 11 (not supported) --- ## ๐Ÿ’ฐ Cost Analysis (Premium Voices) ### Amazon Polly Pricing - Standard voices: $4.00 per 1 million characters - Neural voices: $16.00 per 1 million characters - Average Bible: ~4 million characters - Cost to read entire Bible: ~$16-64 ### Optimization Strategies 1. **Caching**: Cache synthesized audio (reduce repeat costs) 2. **Compression**: Use MP3 (smaller file sizes) 3. **Lazy Loading**: Only synthesize on-demand 4. **Rate Limiting**: Prevent abuse 5. **Subscription Gating**: Premium voices for paid users only ### Expected Monthly Costs - 1,000 users ร— 10 chapters/month ร— 5,000 chars = 50M chars - Cost: $200-800/month (depending on voice quality) --- ## ๐Ÿ“š Documentation ### User Documentation - "Getting Started with Text-to-Speech" - "Choosing the Right Voice" - "Keyboard Shortcuts Guide" - "Background Playback on Mobile" - "Premium Voices: What's the Difference?" ### Developer Documentation - TTS Engine Architecture - Adding New Voice Providers - Custom Voice Integration Guide - Performance Optimization Tips --- ## ๐Ÿ”„ Future Enhancements ### Phase 3+ Features - [ ] Offline audio download (pre-synthesize chapters) - [ ] Playlist creation (custom reading lists) - [ ] Sleep timer - [ ] Bookmarks/favorites for audio - [ ] Sharing audio clips - [ ] Customizable voice profiles (pitch + rate presets) - [ ] Synchronized multi-device playback - [ ] Audio effects (reverb, echo) - [ ] Speed training (gradually increase WPM) - [ ] Comprehension quizzes after listening --- ## ๐Ÿ“ Notes & Considerations ### Performance - Keep player UI lightweight (<50ms render time) - Use Web Workers for audio processing (Phase 2) - Implement audio buffering for smooth playback - Monitor memory usage during long sessions ### Accessibility - Ensure screen reader compatibility - Provide text alternatives for all controls - Maintain keyboard accessibility - Test with assistive technologies ### Legal Considerations - Bible text copyright (check version licenses) - Voice cloning regulations (only use licensed voices) - COPPA compliance (children under 13) - GDPR compliance (store user preferences correctly) --- **Document Version:** 1.0 **Last Updated:** 2025-10-13 **Owner:** Development Team **Status:** Ready for Implementation