// === LETTER DISCOVERY GAME === // Discover letters first, then explore words that start with each letter class LetterDiscovery { constructor({ container, content, onScoreUpdate, onGameEnd }) { this.container = container; this.content = content; this.onScoreUpdate = onScoreUpdate; this.onGameEnd = onGameEnd; // Game state this.currentPhase = 'letter-discovery'; // letter-discovery, word-exploration, practice this.currentLetterIndex = 0; this.discoveredLetters = []; this.currentLetter = null; this.currentWordIndex = 0; this.discoveredWords = []; this.score = 0; this.lives = 3; // Content processing this.letters = []; this.letterWords = {}; // Map letter -> words starting with that letter // Practice system this.practiceLevel = 1; this.practiceRound = 0; this.maxPracticeRounds = 8; this.practiceCorrectAnswers = 0; this.practiceErrors = 0; this.currentPracticeItems = []; this.injectCSS(); this.extractContent(); this.init(); } injectCSS() { if (document.getElementById('letter-discovery-styles')) return; const styleSheet = document.createElement('style'); styleSheet.id = 'letter-discovery-styles'; styleSheet.textContent = ` .letter-discovery-wrapper { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; padding: 20px; position: relative; overflow-y: auto; } .letter-discovery-hud { display: flex; justify-content: space-between; align-items: center; background: rgba(255,255,255,0.1); padding: 15px 20px; border-radius: 15px; backdrop-filter: blur(10px); margin-bottom: 20px; flex-wrap: wrap; gap: 10px; } .hud-group { display: flex; align-items: center; gap: 15px; } .hud-item { color: white; font-weight: bold; font-size: 1.1em; } .phase-indicator { background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; font-size: 0.9em; color: white; backdrop-filter: blur(5px); } .letter-discovery-main { background: rgba(255,255,255,0.1); border-radius: 20px; padding: 30px; backdrop-filter: blur(10px); min-height: 70vh; display: flex; flex-direction: column; align-items: center; justify-content: center; } .game-content { width: 100%; max-width: 900px; text-align: center; } /* Letter Display Styles */ .letter-card { background: rgba(255,255,255,0.95); border-radius: 25px; padding: 60px 40px; margin: 30px auto; max-width: 400px; box-shadow: 0 20px 40px rgba(0,0,0,0.1); transform: scale(0.8); animation: letterAppear 0.8s ease-out forwards; } @keyframes letterAppear { to { transform: scale(1); } } .letter-display { font-size: 8em; font-weight: bold; color: #667eea; margin-bottom: 20px; text-shadow: 0 4px 8px rgba(0,0,0,0.1); font-family: 'Arial Black', Arial, sans-serif; } .letter-info { font-size: 1.5em; color: #333; margin-bottom: 15px; } .letter-pronunciation { font-size: 1.2em; color: #666; font-style: italic; margin-bottom: 25px; } .letter-controls { display: flex; gap: 15px; justify-content: center; margin-top: 30px; } /* Word Exploration Styles */ .word-exploration-header { background: rgba(255,255,255,0.1); padding: 20px; border-radius: 15px; margin-bottom: 30px; backdrop-filter: blur(5px); } .exploring-letter { font-size: 3em; color: white; margin-bottom: 10px; font-weight: bold; } .word-progress { color: rgba(255,255,255,0.8); font-size: 1.1em; } .word-card { background: rgba(255,255,255,0.95); border-radius: 20px; padding: 40px 30px; margin: 25px auto; max-width: 500px; box-shadow: 0 15px 30px rgba(0,0,0,0.1); transform: translateY(20px); animation: wordSlideIn 0.6s ease-out forwards; } @keyframes wordSlideIn { to { transform: translateY(0); } } .word-text { font-size: 2.5em; color: #667eea; margin-bottom: 15px; font-weight: bold; } .word-translation { font-size: 1.3em; color: #333; margin-bottom: 10px; } .word-pronunciation { font-size: 1.1em; color: #666; font-style: italic; margin-bottom: 10px; } .word-type { font-size: 0.9em; color: #667eea; background: rgba(102, 126, 234, 0.1); padding: 4px 12px; border-radius: 15px; display: inline-block; margin-bottom: 15px; font-weight: 500; } .word-example { font-size: 1em; color: #555; font-style: italic; padding: 10px 15px; background: rgba(0, 0, 0, 0.05); border-left: 3px solid #667eea; border-radius: 0 8px 8px 0; margin-bottom: 15px; } /* Practice Challenge Styles */ .practice-challenge { text-align: center; margin-bottom: 30px; } .challenge-text { font-size: 1.8em; color: white; margin-bottom: 25px; text-shadow: 0 2px 4px rgba(0,0,0,0.3); } .practice-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; max-width: 800px; margin: 0 auto; } .practice-option { background: rgba(255,255,255,0.9); border: none; border-radius: 15px; padding: 20px; font-size: 1.2em; cursor: pointer; transition: all 0.3s ease; color: #333; font-weight: 500; } .practice-option:hover { background: rgba(255,255,255,1); transform: translateY(-3px); box-shadow: 0 8px 20px rgba(0,0,0,0.2); } .practice-option.correct { background: #4CAF50; color: white; animation: correctPulse 0.6s ease; } .practice-option.incorrect { background: #F44336; color: white; animation: incorrectShake 0.6s ease; } @keyframes correctPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } } @keyframes incorrectShake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } .practice-stats { display: flex; justify-content: space-around; margin-top: 20px; color: white; font-size: 1.1em; } .stat-item { text-align: center; padding: 10px; background: rgba(255,255,255,0.1); border-radius: 10px; backdrop-filter: blur(5px); } /* Control Buttons */ .discovery-btn { background: linear-gradient(45deg, #667eea, #764ba2); color: white; border: none; padding: 15px 30px; border-radius: 25px; font-size: 1.1em; font-weight: bold; cursor: pointer; transition: all 0.3s ease; margin: 0 10px; } .discovery-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(0,0,0,0.3); } .discovery-btn:active { transform: translateY(0); } .audio-btn { background: none; border: none; font-size: 2em; cursor: pointer; color: #667eea; margin-left: 15px; transition: all 0.3s ease; } .audio-btn:hover { transform: scale(1.2); color: #764ba2; } /* Completion Message */ .completion-message { text-align: center; padding: 40px; background: rgba(255,255,255,0.1); border-radius: 20px; backdrop-filter: blur(10px); color: white; } .completion-title { font-size: 2.5em; margin-bottom: 20px; color: #00ff88; text-shadow: 0 2px 10px rgba(0,255,136,0.3); } .completion-stats { font-size: 1.3em; margin-bottom: 30px; line-height: 1.6; } /* Responsive Design */ @media (max-width: 768px) { .letter-discovery-wrapper { padding: 15px; } .letter-display { font-size: 6em; } .word-text { font-size: 2em; } .challenge-text { font-size: 1.5em; } .practice-grid { grid-template-columns: 1fr; } } `; document.head.appendChild(styleSheet); } extractContent() { logSh('🔍 Letter Discovery - Extracting content...', 'INFO'); // Check for letters in content or rawContent const letters = this.content.letters || this.content.rawContent?.letters; if (letters && Object.keys(letters).length > 0) { this.letters = Object.keys(letters).sort(); this.letterWords = letters; logSh(`📝 Found ${this.letters.length} letters with words`, 'INFO'); } else { this.showNoLettersMessage(); return; } logSh(`🎯 Letter Discovery ready: ${this.letters.length} letters`, 'INFO'); } showNoLettersMessage() { this.container.innerHTML = `

🔤 Letter Discovery

❌ No letter structure found in this content.

This game requires content with a predefined letters system.

Try with content that includes letter-based learning material.

`; } init() { this.container.innerHTML = `
Score: ${this.score}
Lives: ${this.lives}
Letter Discovery
Progress: 0/${this.letters.length}
`; this.updateHUD(); } start() { this.showLetterCard(); } updateHUD() { const scoreDisplay = document.getElementById('score-display'); const livesDisplay = document.getElementById('lives-display'); const progressDisplay = document.getElementById('progress-display'); const phaseIndicator = document.getElementById('phase-indicator'); if (scoreDisplay) scoreDisplay.textContent = this.score; if (livesDisplay) livesDisplay.textContent = this.lives; if (this.currentPhase === 'letter-discovery') { if (progressDisplay) progressDisplay.textContent = `${this.currentLetterIndex}/${this.letters.length}`; if (phaseIndicator) phaseIndicator.textContent = 'Letter Discovery'; } else if (this.currentPhase === 'word-exploration') { if (progressDisplay) progressDisplay.textContent = `${this.currentWordIndex}/${this.letterWords[this.currentLetter].length}`; if (phaseIndicator) phaseIndicator.textContent = `Exploring Letter "${this.currentLetter}"`; } else if (this.currentPhase === 'practice') { if (progressDisplay) progressDisplay.textContent = `Round ${this.practiceRound + 1}/${this.maxPracticeRounds}`; if (phaseIndicator) phaseIndicator.textContent = `Practice - Level ${this.practiceLevel}`; } } showLetterCard() { if (this.currentLetterIndex >= this.letters.length) { this.showCompletion(); return; } const letter = this.letters[this.currentLetterIndex]; const gameContent = document.getElementById('game-content'); gameContent.innerHTML = `
${letter}
Letter "${letter}"
${this.getLetterPronunciation(letter)}
`; // Store reference for button callbacks window.currentLetterGame = this; // Auto-play letter sound setTimeout(() => this.playLetterSound(letter), 500); } getLetterPronunciation(letter) { // Basic letter pronunciation guide const pronunciations = { 'A': 'ay', 'B': 'bee', 'C': 'see', 'D': 'dee', 'E': 'ee', 'F': 'ef', 'G': 'gee', 'H': 'aych', 'I': 'eye', 'J': 'jay', 'K': 'kay', 'L': 'el', 'M': 'em', 'N': 'en', 'O': 'oh', 'P': 'pee', 'Q': 'cue', 'R': 'ar', 'S': 'ess', 'T': 'tee', 'U': 'you', 'V': 'vee', 'W': 'double-you', 'X': 'ex', 'Y': 'why', 'Z': 'zee' }; return pronunciations[letter] || letter.toLowerCase(); } playLetterSound(letter) { if (window.SettingsManager && window.SettingsManager.speak) { const speed = 0.8; // Slower for letters window.SettingsManager.speak(letter, { lang: this.content.language || 'en-US', rate: speed }).catch(error => { console.warn('🔊 TTS failed for letter:', error); }); } } discoverLetter() { const letter = this.letters[this.currentLetterIndex]; this.discoveredLetters.push(letter); this.score += 10; this.onScoreUpdate(this.score); // Start word exploration for this letter this.currentLetter = letter; this.currentPhase = 'word-exploration'; this.currentWordIndex = 0; this.updateHUD(); this.showWordExploration(); } showWordExploration() { const words = this.letterWords[this.currentLetter]; if (!words || this.currentWordIndex >= words.length) { // Finished exploring words for this letter this.currentPhase = 'letter-discovery'; this.currentLetterIndex++; this.updateHUD(); this.showLetterCard(); return; } const word = words[this.currentWordIndex]; const gameContent = document.getElementById('game-content'); gameContent.innerHTML = `
Letter "${this.currentLetter}"
Word ${this.currentWordIndex + 1} of ${words.length}
${word.word}
${word.translation}
${word.pronunciation ? `
[${word.pronunciation}]
` : ''} ${word.type ? `
${word.type}
` : ''} ${word.example ? `
"${word.example}"
` : ''}
`; // Add word to discovered list this.discoveredWords.push(word); // Auto-play word sound setTimeout(() => this.playWordSound(word.word), 500); } playWordSound(word) { if (window.SettingsManager && window.SettingsManager.speak) { const speed = 0.9; window.SettingsManager.speak(word, { lang: this.content.language || 'en-US', rate: speed }).catch(error => { console.warn('🔊 TTS failed for word:', error); }); } } nextWord() { this.currentWordIndex++; this.score += 5; this.onScoreUpdate(this.score); this.updateHUD(); this.showWordExploration(); } showCompletion() { const gameContent = document.getElementById('game-content'); const totalWords = Object.values(this.letterWords).reduce((sum, words) => sum + words.length, 0); gameContent.innerHTML = `
🎉 All Letters Discovered!
Letters Discovered: ${this.discoveredLetters.length}
Words Learned: ${this.discoveredWords.length}
Final Score: ${this.score}
`; } startPractice() { this.currentPhase = 'practice'; this.practiceLevel = 1; this.practiceRound = 0; this.practiceCorrectAnswers = 0; this.practiceErrors = 0; // Create mixed practice from all discovered words this.currentPracticeItems = this.shuffleArray([...this.discoveredWords]); this.updateHUD(); this.showPracticeChallenge(); } showPracticeChallenge() { if (this.practiceRound >= this.maxPracticeRounds) { this.endPractice(); return; } const currentItem = this.currentPracticeItems[this.practiceRound % this.currentPracticeItems.length]; const gameContent = document.getElementById('game-content'); // Generate options (correct + 3 random) const allWords = this.discoveredWords.filter(w => w.word !== currentItem.word); const randomOptions = this.shuffleArray([...allWords]).slice(0, 3); const options = this.shuffleArray([currentItem, ...randomOptions]); gameContent.innerHTML = `
What does "${currentItem.word}" mean?
${options.map((option, index) => ` `).join('')}
Correct: ${this.practiceCorrectAnswers}
Errors: ${this.practiceErrors}
Round: ${this.practiceRound + 1}/${this.maxPracticeRounds}
`; // Store correct answer for checking this.currentCorrectAnswer = currentItem.word; // Auto-play word setTimeout(() => this.playWordSound(currentItem.word), 500); } selectPracticeAnswer(selectedIndex, selectedWord) { const buttons = document.querySelectorAll('.practice-option'); const isCorrect = selectedWord === this.currentCorrectAnswer; if (isCorrect) { buttons[selectedIndex].classList.add('correct'); this.practiceCorrectAnswers++; this.score += 10; this.onScoreUpdate(this.score); } else { buttons[selectedIndex].classList.add('incorrect'); this.practiceErrors++; // Show correct answer buttons.forEach((btn, index) => { if (btn.textContent.trim() === this.discoveredWords.find(w => w.word === this.currentCorrectAnswer)?.translation) { btn.classList.add('correct'); } }); } setTimeout(() => { this.practiceRound++; this.updateHUD(); this.showPracticeChallenge(); }, 1500); } endPractice() { const accuracy = Math.round((this.practiceCorrectAnswers / this.maxPracticeRounds) * 100); const gameContent = document.getElementById('game-content'); gameContent.innerHTML = `
🏆 Practice Complete!
Accuracy: ${accuracy}%
Correct Answers: ${this.practiceCorrectAnswers}/${this.maxPracticeRounds}
Final Score: ${this.score}
`; // End game setTimeout(() => { this.onGameEnd(this.score); }, 3000); } shuffleArray(array) { const shuffled = [...array]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled; } restart() { this.currentPhase = 'letter-discovery'; this.currentLetterIndex = 0; this.discoveredLetters = []; this.currentLetter = null; this.currentWordIndex = 0; this.discoveredWords = []; this.score = 0; this.lives = 3; this.practiceLevel = 1; this.practiceRound = 0; this.practiceCorrectAnswers = 0; this.practiceErrors = 0; this.currentPracticeItems = []; this.updateHUD(); this.start(); } destroy() { // Cleanup if (window.currentLetterGame === this) { delete window.currentLetterGame; } const styleSheet = document.getElementById('letter-discovery-styles'); if (styleSheet) { styleSheet.remove(); } } } // Register the game module window.GameModules = window.GameModules || {}; window.GameModules.LetterDiscovery = LetterDiscovery;