// Application Data const appData = { modes: [ { id: "conversation", name: "المحادثة الحرة", icon: "💬", description: "دردشة مفتوحة مع Echo Light لممارسة المهارات اللغوية" }, { id: "vocabulary", name: "بناء المفردات", icon: "📚", description: "نظام بطاقات تعليمية ذكي مع تكرار مباعد" }, { id: "pronunciation", name: "تدريب النطق", icon: "🎤", description: "تقييم النطق الفوري مع تعليقات مفصلة" }, { id: "grammar", name: "ألعاب القواعد", icon: "🎯", description: "تمارين تفاعلية لتعلم القواعد بطريقة ممتعة" }, { id: "scenarios", name: "سيناريوهات واقعية", icon: "🌍", description: "محاكاة مواقف حياتية مثل المطاعم والمقابلات" }, { id: "daily", name: "التحدي اليومي", icon: "⭐", description: "تمارين يومية قصيرة للحفاظ على استمرارية التعلم" } ], achievements: [ { id: "first_conversation", name: "المحادثة الأولى", description: "أكمل أول محادثة مع Echo Light", icon: "🎉" }, { id: "vocabulary_master", name: "خبير المفردات", description: "تعلم 50 كلمة جديدة", icon: "🏆" }, { id: "pronunciation_expert", name: "خبير النطق", description: "احصل على تقييم ممتاز في النطق 10 مرات", icon: "🎯" }, { id: "grammar_guru", name: "معلم القواعد", description: "أكمل جميع تمارين القواعد بنجاح", icon: "📖" }, { id: "daily_streak", name: "المواظبة", description: "أكمل التحدي اليومي لمدة 7 أيام متتالية", icon: "🔥" } ], vocabulary_cards: [ { word: "Hello", translation: "مرحبا", pronunciation: "/həˈloʊ/", example: "Hello, how are you?" }, { word: "Thank you", translation: "شكراً لك", pronunciation: "/θæŋk juː/", example: "Thank you for your help." }, { word: "Beautiful", translation: "جميل", pronunciation: "/ˈbjuːtɪfəl/", example: "The sunset is beautiful." }, { word: "Important", translation: "مهم", pronunciation: "/ɪmˈpɔːrtənt/", example: "This is very important." }, { word: "Learning", translation: "تعلم", pronunciation: "/ˈlɜːrnɪŋ/", example: "Learning English is fun." } ], grammar_exercises: [ { question: "Choose the correct form: I ___ to school every day.", options: ["go", "goes", "going", "went"], correct: 0, explanation: "نستخدم 'go' مع الضمير 'I' في المضارع البسيط" }, { question: "Complete: She ___ reading a book now.", options: ["is", "are", "was", "were"], correct: 0, explanation: "نستخدم 'is' مع الضمير 'She' في المضارع المستمر" } ], scenarios: [ { title: "في المطعم", description: "تعلم كيفية طلب الطعام في المطعم", dialogue: [ { speaker: "waiter", text: "Good evening! Welcome to our restaurant. How can I help you?" }, { speaker: "customer", text: "Good evening! I'd like to see the menu, please." } ] }, { title: "مقابلة عمل", description: "تدرب على أسئلة مقابلة العمل الشائعة", dialogue: [ { speaker: "interviewer", text: "Tell me about yourself." }, { speaker: "candidate", text: "I'm a motivated professional with experience in..." } ] } ], echoResponses: [ "That's wonderful! Your English is getting better every day.", "Great job! Can you tell me more about that topic?", "Excellent! I love how you expressed that idea.", "Perfect! Let's try using some advanced vocabulary now.", "Amazing progress! What would you like to talk about next?", "Fantastic! Your grammar is really improving.", "Well done! That was a complete and clear sentence.", "Impressive! You're becoming more confident in English.", "Brilliant! Let's explore this topic further.", "Outstanding! Keep up the great work!" ] }; // Application State const appState = { currentScreen: 'homeScreen', userProgress: { streak: 5, totalPoints: 125, wordsLearned: 12, conversationsCompleted: 3, pronunciationAccuracy: 78, grammarScore: 85, unlockedAchievements: ['first_conversation'] }, currentVocabIndex: 0, currentGrammarIndex: 0, currentScenario: null, isRecording: false, soundEnabled: true, dailyProgress: 1, selectedChallengeWords: [], recordingTimer: null }; // Character Animation Controller class CharacterController { constructor() { this.character = document.getElementById('echoCharacter'); this.mouth = document.getElementById('characterMouth'); this.soundWaves = document.getElementById('soundWaves'); this.isAnimating = false; this.mouthStates = ['happy', 'speaking', 'surprised', 'neutral']; this.currentMoodIndex = 0; this.startIdleAnimation(); } startIdleAnimation() { // Eye blinking animation setInterval(() => { this.blink(); }, 3000 + Math.random() * 2000); // Mood changes setInterval(() => { this.changeMood(); }, 10000); } blink() { const eyes = document.querySelectorAll('.eye'); eyes.forEach(eye => { eye.style.transform = 'scaleY(0.1)'; setTimeout(() => { eye.style.transform = 'scaleY(1)'; }, 150); }); } changeMood() { if (this.isAnimating) return; const moods = ['happy', 'excited', 'thinking', 'encouraging']; const randomMood = moods[Math.floor(Math.random() * moods.length)]; this.setMood(randomMood); } setMood(mood) { const character = this.character; const mouth = this.mouth; // Remove existing mood classes character.classList.remove('happy', 'excited', 'thinking', 'encouraging'); character.classList.add(mood); switch(mood) { case 'happy': mouth.style.borderRadius = '0 0 40px 40px'; mouth.style.width = '40px'; mouth.style.background = '#ff6b9d'; break; case 'excited': mouth.style.borderRadius = '50%'; mouth.style.width = '30px'; mouth.style.background = '#32b8c6'; break; case 'thinking': mouth.style.borderRadius = '40px 40px 0 0'; mouth.style.width = '20px'; mouth.style.background = '#8a2be2'; break; case 'encouraging': mouth.style.borderRadius = '0 0 50px 50px'; mouth.style.width = '50px'; mouth.style.background = '#ff6b9d'; break; } } speak(text) { this.isAnimating = true; this.setMood('happy'); // Animate sound waves if (this.soundWaves) { this.soundWaves.style.display = 'block'; } // Simulate mouth movement let speakingInterval = setInterval(() => { const randomWidth = 20 + Math.random() * 30; if (this.mouth) { this.mouth.style.width = randomWidth + 'px'; } }, 150); // Use Web Speech API if available and enabled if ('speechSynthesis' in window && appState.soundEnabled) { const utterance = new SpeechSynthesisUtterance(text); utterance.lang = 'en-US'; utterance.rate = 0.9; utterance.pitch = 1.1; utterance.onend = () => { clearInterval(speakingInterval); this.stopSpeaking(); }; utterance.onerror = () => { clearInterval(speakingInterval); this.stopSpeaking(); }; speechSynthesis.speak(utterance); } else { // Fallback animation setTimeout(() => { clearInterval(speakingInterval); this.stopSpeaking(); }, Math.min(text.length * 50, 3000)); } } stopSpeaking() { this.isAnimating = false; if (this.soundWaves) { this.soundWaves.style.display = 'none'; } if (this.mouth) { this.mouth.style.width = '40px'; } this.setMood('happy'); } celebrate() { this.setMood('excited'); if (this.character) { this.character.style.animation = 'float 0.5s ease-in-out 3'; setTimeout(() => { this.character.style.animation = 'float 3s ease-in-out infinite'; this.setMood('happy'); }, 1500); } } encourage() { this.setMood('encouraging'); setTimeout(() => { this.setMood('happy'); }, 2000); } } // Initialize character controller let characterController; // Screen Management function showScreen(screenId) { // Hide all screens document.querySelectorAll('.screen').forEach(screen => { screen.classList.remove('active'); }); // Show target screen const targetScreen = document.getElementById(screenId); if (targetScreen) { targetScreen.classList.add('active'); appState.currentScreen = screenId; // Update character mood based on screen if (characterController) { switch(screenId) { case 'homeScreen': characterController.setMood('happy'); break; case 'conversationScreen': characterController.setMood('encouraging'); break; case 'vocabularyScreen': case 'grammarScreen': characterController.setMood('thinking'); break; case 'pronunciationScreen': characterController.setMood('excited'); break; case 'progressScreen': initializeAchievements(); break; } } } } // Mode Management function initializeModes() { const modesGrid = document.getElementById('modesGrid'); if (!modesGrid) return; modesGrid.innerHTML = ''; appData.modes.forEach(mode => { const modeCard = document.createElement('div'); modeCard.className = 'mode-card'; modeCard.onclick = () => openMode(mode.id); modeCard.innerHTML = `
${mode.description}
`; modesGrid.appendChild(modeCard); }); } function openMode(modeId) { const screenMap = { 'conversation': 'conversationScreen', 'vocabulary': 'vocabularyScreen', 'pronunciation': 'pronunciationScreen', 'grammar': 'grammarScreen', 'scenarios': 'scenariosScreen', 'daily': 'dailyScreen' }; const screenId = screenMap[modeId]; if (screenId) { showScreen(screenId); // Initialize mode-specific content switch(modeId) { case 'vocabulary': initializeVocabulary(); break; case 'grammar': initializeGrammar(); break; case 'scenarios': initializeScenarios(); break; case 'daily': initializeDailyChallenge(); break; case 'pronunciation': initializePronunciation(); break; } } } // Conversation Mode function sendMessage() { const input = document.getElementById('messageInput'); if (!input) return; const message = input.value.trim(); if (!message) return; addMessage(message, 'user'); input.value = ''; // استدعاء الذكاء الاصطناعي عبر الخادم fetch('/chat', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({message}) }) .then(res => res.json()) .then(data => { addMessage(data.reply, 'echo'); if (characterController) characterController.speak(data.reply); }) .catch(() => { addMessage("Sorry, I couldn't connect to the AI server.", 'echo'); }); // تحديث النقاط كما هو appState.userProgress.conversationsCompleted++; appState.userProgress.totalPoints += 25; updateProgressDisplay(); } function addMessage(text, sender) { const messagesContainer = document.getElementById('chatMessages'); if (!messagesContainer) return; const messageDiv = document.createElement('div'); messageDiv.className = `message ${sender}`; messageDiv.textContent = text; messagesContainer.appendChild(messageDiv); messagesContainer.scrollTop = messagesContainer.scrollHeight; } function startVoiceInput() { if ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window) { const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; const recognition = new SpeechRecognition(); recognition.lang = 'en-US'; recognition.continuous = false; recognition.interimResults = false; recognition.onresult = function(event) { const transcript = event.results[0][0].transcript; const input = document.getElementById('messageInput'); if (input) { input.value = transcript; } }; recognition.onerror = function(event) { console.log('Speech recognition error:', event.error); alert('حدث خطأ في التعرف على الصوت. تأكد من السماح بالوصول للميكروفون.'); }; recognition.start(); } else { alert('متصفحك لا يدعم تقنية التعرف على الصوت.'); } } // Vocabulary Mode function initializeVocabulary() { appState.currentVocabIndex = 0; updateVocabularyCard(); updateVocabularyProgress(); } function updateVocabularyCard() { const card = appData.vocabulary_cards[appState.currentVocabIndex]; const elements = { 'cardWord': card.word, 'cardPronunciation': card.pronunciation, 'cardTranslation': card.translation, 'cardExample': card.example }; Object.entries(elements).forEach(([id, value]) => { const element = document.getElementById(id); if (element) { element.textContent = value; } }); // Reset card flip const flashcard = document.getElementById('flashcard'); if (flashcard) { flashcard.classList.remove('flipped'); } } function updateVocabularyProgress() { const progress = ((appState.currentVocabIndex + 1) / appData.vocabulary_cards.length) * 100; const progressFill = document.getElementById('vocabProgress'); const progressText = document.getElementById('vocabProgressText'); if (progressFill) { progressFill.style.width = progress + '%'; } if (progressText) { progressText.textContent = `${appState.currentVocabIndex + 1}/${appData.vocabulary_cards.length}`; } } function flipCard() { const flashcard = document.getElementById('flashcard'); if (flashcard) { flashcard.classList.toggle('flipped'); } } function nextCard() { appState.currentVocabIndex = (appState.currentVocabIndex + 1) % appData.vocabulary_cards.length; updateVocabularyCard(); updateVocabularyProgress(); // Update progress appState.userProgress.wordsLearned++; appState.userProgress.totalPoints += 10; updateProgressDisplay(); if (characterController) { characterController.encourage(); } } function playPronunciation() { const card = appData.vocabulary_cards[appState.currentVocabIndex]; if (characterController && appState.soundEnabled) { characterController.speak(card.word); } } // Pronunciation Mode function initializePronunciation() { const words = appData.vocabulary_cards; const randomWord = words[Math.floor(Math.random() * words.length)]; const practiceWord = document.getElementById('practiceWord'); const practicePronunciation = document.getElementById('practicePronunciation'); if (practiceWord) practiceWord.textContent = randomWord.word; if (practicePronunciation) practicePronunciation.textContent = randomWord.pronunciation; // Clear previous feedback const feedback = document.getElementById('pronunciationFeedback'); if (feedback) { feedback.innerHTML = ''; } } function playTargetPronunciation() { const word = document.getElementById('practiceWord'); if (word && characterController && appState.soundEnabled) { characterController.speak(word.textContent); } } function toggleRecording() { const recordBtn = document.getElementById('recordBtn'); const visualizer = document.getElementById('recordVisualizer'); if (!recordBtn || !visualizer) return; if (!appState.isRecording) { // Start recording appState.isRecording = true; recordBtn.textContent = '⏹️ إيقاف التسجيل'; recordBtn.classList.add('recording'); // Clear previous content visualizer.innerHTML = ''; // Create recording visualization const bars = []; for (let i = 0; i < 10; i++) { const bar = document.createElement('div'); bar.style.cssText = ` width: 15px; background: #32b8c6; margin: 2px; border-radius: 2px; display: inline-block; height: 20px; animation: record-bar 0.8s infinite alternate; animation-delay: ${i * 0.1}s; `; bars.push(bar); visualizer.appendChild(bar); } // Add CSS for bars animation if not exists if (!document.getElementById('recordBarStyles')) { const style = document.createElement('style'); style.id = 'recordBarStyles'; style.textContent = ` @keyframes record-bar { 0% { height: 10px; opacity: 0.5; } 100% { height: 50px; opacity: 1; } } `; document.head.appendChild(style); } // Auto-stop after 5 seconds appState.recordingTimer = setTimeout(() => { if (appState.isRecording) { toggleRecording(); } }, 5000); } else { // Stop recording appState.isRecording = false; recordBtn.textContent = '🎤 ابدأ التسجيل'; recordBtn.classList.remove('recording'); // Clear timer if (appState.recordingTimer) { clearTimeout(appState.recordingTimer); appState.recordingTimer = null; } // Clear visualizer visualizer.innerHTML = ''; // Show processing message then feedback const feedback = document.getElementById('pronunciationFeedback'); if (feedback) { feedback.innerHTML = 'جاري تحليل النطق...
'; setTimeout(() => { showPronunciationFeedback(); }, 1500); } } } function showPronunciationFeedback() { const feedback = document.getElementById('pronunciationFeedback'); if (!feedback) return; const accuracy = 65 + Math.random() * 30; // Simulate accuracy between 65-95% const roundedAccuracy = Math.round(accuracy); let message, color; if (roundedAccuracy >= 85) { message = 'ممتاز! نطقك رائع 🎉'; color = '#32b8c6'; } else if (roundedAccuracy >= 70) { message = 'جيد جداً! يمكنك تحسينه أكثر 👍'; color = '#8a2be2'; } else { message = 'يحتاج تحسين، استمع للنطق الصحيح 🎯'; color = '#ff6b9d'; } feedback.innerHTML = `${message}
`; // Update progress appState.userProgress.pronunciationAccuracy = Math.round( (appState.userProgress.pronunciationAccuracy + accuracy) / 2 ); appState.userProgress.totalPoints += Math.round(accuracy / 10); updateProgressDisplay(); if (characterController) { if (roundedAccuracy >= 85) { characterController.celebrate(); } else { characterController.encourage(); } } } // Grammar Mode function initializeGrammar() { appState.currentGrammarIndex = 0; showGrammarQuestion(); } function showGrammarQuestion() { const exercise = appData.grammar_exercises[appState.currentGrammarIndex]; const questionElement = document.getElementById('grammarQuestion'); if (questionElement) { questionElement.textContent = exercise.question; } const optionsContainer = document.getElementById('grammarOptions'); if (optionsContainer) { optionsContainer.innerHTML = ''; exercise.options.forEach((option, index) => { const optionBtn = document.createElement('button'); optionBtn.className = 'option-btn'; optionBtn.textContent = option; optionBtn.onclick = () => selectGrammarOption(index); optionsContainer.appendChild(optionBtn); }); } // Clear previous feedback const feedback = document.getElementById('grammarFeedback'); if (feedback) { feedback.innerHTML = ''; } } function selectGrammarOption(selectedIndex) { const exercise = appData.grammar_exercises[appState.currentGrammarIndex]; const options = document.querySelectorAll('.option-btn'); const feedback = document.getElementById('grammarFeedback'); if (!feedback) return; // Disable all options options.forEach((btn, index) => { btn.disabled = true; if (index === exercise.correct) { btn.classList.add('correct'); } else if (index === selectedIndex && index !== exercise.correct) { btn.classList.add('incorrect'); } }); // Show feedback const isCorrect = selectedIndex === exercise.correct; feedback.innerHTML = `${exercise.explanation}
`; // Update progress if (isCorrect) { appState.userProgress.grammarScore += 10; appState.userProgress.totalPoints += 15; updateProgressDisplay(); if (characterController) { characterController.celebrate(); } } else { if (characterController) { characterController.encourage(); } } } function nextGrammarQuestion() { appState.currentGrammarIndex = (appState.currentGrammarIndex + 1) % appData.grammar_exercises.length; showGrammarQuestion(); } // Scenarios Mode function initializeScenarios() { const buttonsContainer = document.getElementById('scenarioButtons'); if (!buttonsContainer) return; buttonsContainer.innerHTML = ''; appData.scenarios.forEach((scenario, index) => { const btn = document.createElement('button'); btn.className = 'scenario-btn'; btn.textContent = scenario.title; btn.onclick = () => showScenario(index); buttonsContainer.appendChild(btn); }); // Show first scenario by default if (appData.scenarios.length > 0) { showScenario(0); } } function showScenario(scenarioIndex) { const scenario = appData.scenarios[scenarioIndex]; appState.currentScenario = scenarioIndex; // Update button states document.querySelectorAll('.scenario-btn').forEach((btn, index) => { btn.classList.toggle('active', index === scenarioIndex); }); // Show dialogue const dialogueContainer = document.getElementById('scenarioDialogue'); if (dialogueContainer) { dialogueContainer.innerHTML = `${scenario.description}
${line.text}
🎤 الآن دورك! تدرب على الرد باللغة الإنجليزية
'; dialogueContainer.appendChild(practiceDiv); } } // Daily Challenge Mode function initializeDailyChallenge() { appState.dailyProgress = 1; appState.selectedChallengeWords = []; updateDailyProgress(); startChallengeTimer(); } function updateDailyProgress() { const progress = (appState.dailyProgress / 3) * 100; const progressFill = document.getElementById('dailyProgress'); const progressText = document.getElementById('dailyProgressText'); if (progressFill) { progressFill.style.width = progress + '%'; } if (progressText) { progressText.textContent = `${appState.dailyProgress}/3`; } } function selectWord(wordElement) { const word = wordElement.textContent; // Toggle selection if (wordElement.classList.contains('selected')) { wordElement.classList.remove('selected'); appState.selectedChallengeWords = appState.selectedChallengeWords.filter(w => w !== word); } else { // Limit to 2 selections if (appState.selectedChallengeWords.length < 2) { wordElement.classList.add('selected'); appState.selectedChallengeWords.push(word); } } // Check if challenge is complete if (appState.selectedChallengeWords.length === 2) { setTimeout(() => { checkChallengeAnswer(); }, 500); } } function checkChallengeAnswer() { const correctWords = ['study', 'important']; const isCorrect = correctWords.every(word => appState.selectedChallengeWords.includes(word)); if (isCorrect) { appState.dailyProgress++; updateDailyProgress(); if (characterController) { characterController.celebrate(); } // Update streak and points appState.userProgress.streak++; appState.userProgress.totalPoints += 20; updateProgressDisplay(); if (appState.dailyProgress >= 3) { setTimeout(() => { alert('🎉 أكملت التحدي اليومي! أحسنت!'); checkAchievements(); }, 1000); } else { setTimeout(() => { alert('✅ إجابة صحيحة! استمر...'); }, 500); } } else { if (characterController) { characterController.encourage(); } setTimeout(() => { alert('❌ حاول مرة أخرى!'); }, 500); } // Reset selections document.querySelectorAll('.word-option').forEach(option => { option.classList.remove('selected'); }); appState.selectedChallengeWords = []; } function startChallengeTimer() { let timeLeft = 300; // 5 minutes in seconds const timerElement = document.getElementById('challengeTimer'); if (!timerElement) return; const timer = setInterval(() => { const minutes = Math.floor(timeLeft / 60); const seconds = timeLeft % 60; timerElement.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timeLeft--; if (timeLeft < 0) { clearInterval(timer); alert('⏰ انتهى الوقت! حاول مرة أخرى غداً.'); } }, 1000); } // Progress Tracking function updateProgressDisplay() { const elements = { 'streakCount': appState.userProgress.streak, 'totalPoints': appState.userProgress.totalPoints, 'wordsLearned': appState.userProgress.wordsLearned, 'conversationsCompleted': appState.userProgress.conversationsCompleted, 'pronunciationAccuracy': appState.userProgress.pronunciationAccuracy + '%', 'grammarScore': appState.userProgress.grammarScore }; Object.entries(elements).forEach(([id, value]) => { const element = document.getElementById(id); if (element) { element.textContent = value; } }); } // Achievements System function checkAchievements() { const progress = appState.userProgress; const achievements = [ { id: 'first_conversation', condition: progress.conversationsCompleted >= 1 }, { id: 'vocabulary_master', condition: progress.wordsLearned >= 50 }, { id: 'pronunciation_expert', condition: progress.pronunciationAccuracy >= 85 }, { id: 'grammar_guru', condition: progress.grammarScore >= 100 }, { id: 'daily_streak', condition: progress.streak >= 7 } ]; achievements.forEach(achievement => { if (achievement.condition && !progress.unlockedAchievements.includes(achievement.id)) { unlockAchievement(achievement.id); } }); } function unlockAchievement(achievementId) { const achievement = appData.achievements.find(a => a.id === achievementId); if (!achievement) return; appState.userProgress.unlockedAchievements.push(achievementId); appState.userProgress.totalPoints += 50; updateProgressDisplay(); // Show achievement notification showAchievementNotification(achievement); if (characterController) { characterController.celebrate(); } } function showAchievementNotification(achievement) { const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background: linear-gradient(135deg, #32b8c6, #8a2be2); color: white; padding: 20px; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.3); z-index: 1000; animation: slideIn 0.5s ease-out; max-width: 300px; `; notification.innerHTML = `${achievement.name}
`; document.body.appendChild(notification); setTimeout(() => { notification.remove(); }, 5000); } function initializeAchievements() { const achievementsGrid = document.getElementById('achievementsGrid'); if (!achievementsGrid) return; achievementsGrid.innerHTML = ''; appData.achievements.forEach(achievement => { const isUnlocked = appState.userProgress.unlockedAchievements.includes(achievement.id); const achievementCard = document.createElement('div'); achievementCard.className = `achievement-card ${isUnlocked ? 'unlocked' : ''}`; achievementCard.innerHTML = `