# Speed Reading Mode - Implementation Plan ## 📋 Overview Implement a speed reading mode using RSVP (Rapid Serial Visual Presentation) technique, allowing users to consume Bible content at accelerated rates while maintaining comprehension through guided visual training. **Status:** Planning Phase **Priority:** 🟡 Medium **Estimated Time:** 2 weeks (80 hours) **Target Completion:** TBD --- ## 🎯 Goals & Objectives ### Primary Goals 1. Enable users to read at 200-1000+ words per minute 2. Reduce eye movement and increase focus 3. Track reading speed progress over time 4. Provide comprehension exercises 5. Offer customizable display modes ### User Value Proposition - **For busy professionals**: Read more in less time - **For students**: Cover more material quickly - **For speed reading enthusiasts**: Practice technique - **For information seekers**: Rapid content consumption - **For skill builders**: Measurable improvement tracking --- ## ✨ Feature Specifications ### 1. RSVP Configuration ```typescript interface RSVPConfig { // Speed wordsPerMinute: number // 200-1000+ autoAdjust: boolean // Automatically adjust based on comprehension // Display displayMode: 'single' | 'dual' | 'triple' // Words shown at once chunkSize: number // 1-3 words fontSize: number // 16-48px fontFamily: string backgroundColor: string textColor: string highlightColor: string // Timing pauseOnPunctuation: boolean pauseDuration: { comma: number; period: number; question: number } // ms pauseBetweenVerses: number // ms // Focus showFixationPoint: boolean fixationStyle: 'center' | 'orpAlgorithm' | 'custom' showWordPosition: boolean // Current word out of total showProgress: boolean // Comprehension enableQuizzes: boolean quizFrequency: number // Every N verses requirePassToContinue: boolean } ``` ### 2. RSVP Display Component ```typescript const RSVPReader: React.FC<{ content: string[] config: RSVPConfig onComplete: () => void onPause: () => void }> = ({ content, config, onComplete, onPause }) => { const [isPlaying, setIsPlaying] = useState(false) const [currentIndex, setCurrentIndex] = useState(0) const [words, setWords] = useState([]) useEffect(() => { // Parse content into words const allWords = content.join(' ').split(/\s+/) setWords(allWords) }, [content]) // Main playback logic useEffect(() => { if (!isPlaying || currentIndex >= words.length) return const currentWord = words[currentIndex] const delay = calculateDelay(currentWord, config) const timer = setTimeout(() => { setCurrentIndex(prev => prev + 1) // Check if completed if (currentIndex + 1 >= words.length) { setIsPlaying(false) onComplete() } }, delay) return () => clearTimeout(timer) }, [isPlaying, currentIndex, words, config]) const calculateDelay = (word: string, config: RSVPConfig): number => { const baseDelay = (60 / config.wordsPerMinute) * 1000 // Adjust for punctuation if (config.pauseOnPunctuation) { if (word.endsWith(',')) return baseDelay + config.pauseDuration.comma if (word.endsWith('.') || word.endsWith('!')) return baseDelay + config.pauseDuration.period if (word.endsWith('?')) return baseDelay + config.pauseDuration.question } // Adjust for word length (longer words take slightly longer) const lengthMultiplier = 1 + (Math.max(0, word.length - 6) * 0.02) return baseDelay * lengthMultiplier } const getDisplayWords = (): string[] => { if (config.displayMode === 'single') { return [words[currentIndex]] } else if (config.displayMode === 'dual') { return [words[currentIndex], words[currentIndex + 1]].filter(Boolean) } else { return [words[currentIndex], words[currentIndex + 1], words[currentIndex + 2]].filter(Boolean) } } const displayWords = getDisplayWords() const progress = (currentIndex / words.length) * 100 return ( {/* Header - Controls */} setIsPlaying(true)} onPause={() => { setIsPlaying(false) onPause() }} onRestart={() => setCurrentIndex(0)} config={config} /> {/* Main Display Area */} {/* Fixation Point Guide */} {config.showFixationPoint && ( )} {/* Word Display */} {displayWords.map((word, index) => { const isActive = index === 0 const fixationIndex = calculateFixationPoint(word) return ( {word.split('').map((char, charIndex) => ( {char} ))} ) })} {/* Word Position Indicator */} {config.showWordPosition && ( Word {currentIndex + 1} of {words.length} )} {/* Footer - Progress */} {config.showProgress && ( {Math.round(progress)}% Complete {config.wordsPerMinute} WPM )} ) } // ORP (Optimal Recognition Point) Algorithm const calculateFixationPoint = (word: string): number => { const length = word.length if (length <= 1) return 0 if (length <= 5) return 1 if (length <= 9) return 2 if (length <= 13) return 3 return Math.floor(length * 0.3) } ``` ### 3. Speed Reading Controls ```typescript const SpeedReadingControls: React.FC<{ isPlaying: boolean onPlay: () => void onPause: () => void onRestart: () => void config: RSVPConfig }> = ({ isPlaying, onPlay, onPause, onRestart, config }) => { const [showSettings, setShowSettings] = useState(false) return ( {/* Playback Controls */} {isPlaying ? : } {/* Speed Adjustment */} adjustSpeed(-25)}> {config.wordsPerMinute} WPM updateSpeed(value as number)} min={100} max={1000} step={25} size="small" /> adjustSpeed(25)}> {/* Quick Speed Presets */} {/* Settings */} setShowSettings(true)}> {/* Settings Dialog */} setShowSettings(false)} config={config} /> ) } ``` ### 4. Fixation Guide ```typescript const FixationGuide: React.FC<{ style: string }> = ({ style }) => { if (style === 'center') { return ( ) } if (style === 'orpAlgorithm') { return ( ) } return null } ``` ### 5. Comprehension Quiz ```typescript interface ComprehensionQuiz { id: string verseReference: string question: string options: string[] correctAnswer: number explanation?: string } const ComprehensionQuiz: React.FC<{ quiz: ComprehensionQuiz onAnswer: (correct: boolean) => void }> = ({ quiz, onAnswer }) => { const [selectedAnswer, setSelectedAnswer] = useState(null) const [showResult, setShowResult] = useState(false) const handleSubmit = () => { const isCorrect = selectedAnswer === quiz.correctAnswer setShowResult(true) setTimeout(() => { onAnswer(isCorrect) }, 2000) } return ( Comprehension Check {quiz.verseReference} {quiz.question} setSelectedAnswer(Number(e.target.value))}> {quiz.options.map((option, index) => ( } label={option} disabled={showResult} sx={{ p: 1, borderRadius: 1, bgcolor: showResult ? index === quiz.correctAnswer ? 'success.light' : index === selectedAnswer ? 'error.light' : 'transparent' : 'transparent' }} /> ))} {showResult && quiz.explanation && ( {quiz.explanation} )} ) } ``` ### 6. Progress Tracking ```typescript interface ReadingSession { id: string userId: string startTime: Date endTime: Date wordsRead: number averageWPM: number peakWPM: number comprehensionScore: number // 0-100% book: string chapter: number } const ProgressTracker: React.FC = () => { const [sessions, setSessions] = useState([]) const [stats, setStats] = useState(null) useEffect(() => { loadSessions() loadStats() }, []) return ( Speed Reading Progress {/* Summary Stats */} } /> } /> } /> } /> {/* Progress Chart */} Reading Speed Over Time {/* Session History */} Recent Sessions Date Passage Words Avg WPM Comprehension {sessions.map(session => ( {formatDate(session.startTime)} {session.book} {session.chapter} {session.wordsRead} {session.averageWPM} = 80 ? 'success' : 'warning'} size="small" /> ))}
) } ``` ### 7. Training Exercises ```typescript const SpeedReadingTraining: React.FC = () => { const [currentExercise, setCurrentExercise] = useState(0) const exercises = [ { name: 'Word Recognition', description: 'Practice recognizing words at increasing speeds', component: }, { name: 'Peripheral Vision', description: 'Expand your field of vision', component: }, { name: 'Chunking Practice', description: 'Read multiple words at once', component: }, { name: 'Speed Progression', description: 'Gradually increase reading speed', component: } ] return ( Speed Reading Training {exercises.map((exercise, index) => ( {exercise.name} ))} {exercises[currentExercise].component} ) } ``` --- ## 🗄️ Database Schema ```prisma model SpeedReadingSession { id String @id @default(cuid()) userId String user User @relation(fields: [userId], references: [id]) startTime DateTime endTime DateTime wordsRead Int averageWPM Int peakWPM Int lowestWPM Int book String chapter Int startVerse Int endVerse Int comprehensionScore Float? // 0-100 quizzesTaken Int @default(0) quizzesCorrect Int @default(0) config Json // RSVPConfig snapshot createdAt DateTime @default(now()) @@index([userId, createdAt]) } model SpeedReadingStats { id String @id @default(cuid()) userId String @unique user User @relation(fields: [userId], references: [id]) totalSessions Int @default(0) totalWords BigInt @default(0) totalMinutes Int @default(0) currentWPM Int @default(200) startingWPM Int @default(200) peakWPM Int @default(200) avgComprehension Float @default(0) lastSessionAt DateTime? updatedAt DateTime @updatedAt } ``` --- ## 📅 Implementation Timeline ### Week 1: Core RSVP **Day 1-2:** Foundation - [ ] RSVP display component - [ ] Word timing logic - [ ] Basic controls **Day 3-4:** Features - [ ] Fixation point - [ ] Speed adjustment - [ ] Multiple display modes **Day 5:** Testing - [ ] Performance optimization - [ ] User testing - [ ] Bug fixes ### Week 2: Advanced **Day 1-2:** Comprehension - [ ] Quiz system - [ ] Auto-adjustment - [ ] Results tracking **Day 3-4:** Analytics - [ ] Progress tracking - [ ] Statistics dashboard - [ ] Training exercises **Day 5:** Launch - [ ] Final polish - [ ] Documentation - [ ] Deployment --- **Document Version:** 1.0 **Last Updated:** 2025-10-13 **Status:** Ready for Implementation