By the end of this lesson, you will be able to:
ℹ️ Info Definition: Gamified language learning combines educational content with game mechanics to make language acquisition engaging and effective. Apps like Duolingo, Babbel, and Memrise have revolutionized how people learn languages through interactive gameplay.
Language learning apps have transformed education:
Mechanic | Example | Learning Benefit |
---|---|---|
Streaks | Daily lesson completion | Builds consistent study habits |
XP Points | Experience for correct answers | Motivates continuous engagement |
Leagues | Weekly competitions | Social motivation and benchmarking |
Hearts/Lives | Limited mistakes allowed | Encourages careful attention |
Achievements | Unlock badges for milestones | Long-term goal setting |
💡 Success Insight: Duolingo users spend an average of 34 minutes per day in the app, compared to 19 minutes for traditional learning apps!
// components/VocabularyGame.tsx
import React, { useState, useEffect, useCallback } from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Animated,
Alert,
Dimensions,
} from 'react-native';
import { Audio } from 'expo-av';
import { LinearGradient } from 'expo-linear-gradient';
interface Word {
id: string;
word: string;
translation: string;
pronunciation: string;
audioUrl?: string;
difficulty: 'beginner' | 'intermediate' | 'advanced';
category: string;
}
interface GameStats {
score: number;
streak: number;
correctAnswers: number;
totalQuestions: number;
xp: number;
}
const sampleWords: Word[] = [
{
id: '1',
word: 'Hola',
translation: 'Hello',
pronunciation: 'OH-lah',
difficulty: 'beginner',
category: 'greetings',
},
{
id: '2',
word: 'Gracias',
translation: 'Thank you',
pronunciation: 'GRAH-see-ahs',
difficulty: 'beginner',
category: 'courtesy',
},
{
id: '3',
word: 'Comida',
translation: 'Food',
pronunciation: 'koh-MEE-dah',
difficulty: 'intermediate',
category: 'food',
},
{
id: '4',
word: 'Biblioteca',
translation: 'Library',
pronunciation: 'bee-blee-oh-TEH-kah',
difficulty: 'advanced',
category: 'places',
},
];
export const VocabularyGame: React.FC = () => {
const [currentWord, setCurrentWord] = useState<Word | null>(null);
const [options, setOptions] = useState<string[]>([]);
const [selectedAnswer, setSelectedAnswer] = useState<string>('');
const [isAnswerCorrect, setIsAnswerCorrect] = useState<boolean | null>(null);
const [gameStats, setGameStats] = useState<GameStats>({
score: 0,
streak: 0,
correctAnswers: 0,
totalQuestions: 0,
xp: 0,
});\n const [gameMode, setGameMode] = useState<'translation' | 'listening' | 'pronunciation'>('translation');\n const [showResult, setShowResult] = useState(false);\n const [sound, setSound] = useState<Audio.Sound | null>(null);\n const [animationValue] = useState(new Animated.Value(0));\n\n useEffect(() => {\n generateNewQuestion();\n }, []);\n\n useEffect(() => {\n if (isAnswerCorrect !== null) {\n animateResult();\n }\n }, [isAnswerCorrect]);\n\n const generateNewQuestion = useCallback(() => {\n // Select a random word based on spaced repetition algorithm\n const selectedWord = selectWordBySpacedRepetition();\n setCurrentWord(selectedWord);\n \n // Generate multiple choice options\n const correctAnswer = selectedWord.translation;\n const wrongAnswers = sampleWords\n .filter(w => w.id !== selectedWord.id)\n .map(w => w.translation)\n .sort(() => Math.random() - 0.5)\n .slice(0, 3);\n \n const allOptions = [correctAnswer, ...wrongAnswers].sort(() => Math.random() - 0.5);\n setOptions(allOptions);\n \n // Reset state\n setSelectedAnswer('');\n setIsAnswerCorrect(null);\n setShowResult(false);\n }, []);\n\n const selectWordBySpacedRepetition = (): Word => {\n // Implement spaced repetition algorithm\n // For now, random selection with difficulty weighting\n const difficultyWeights = {\n beginner: 0.5,\n intermediate: 0.3,\n advanced: 0.2,\n };\n \n const totalWeight = Object.values(difficultyWeights).reduce((sum, weight) => sum + weight, 0);\n let randomValue = Math.random() * totalWeight;\n \n for (const [difficulty, weight] of Object.entries(difficultyWeights)) {\n randomValue -= weight;\n if (randomValue <= 0) {\n const wordsInDifficulty = sampleWords.filter(w => w.difficulty === difficulty);\n return wordsInDifficulty[Math.floor(Math.random() * wordsInDifficulty.length)];\n }\n }\n \n return sampleWords[0]; // Fallback\n };\n\n const handleAnswer = useCallback((answer: string) => {\n if (selectedAnswer || !currentWord) return;\n \n setSelectedAnswer(answer);\n const isCorrect = answer === currentWord.translation;\n setIsAnswerCorrect(isCorrect);\n \n // Update statistics\n setGameStats(prev => {\n const newStats = {\n totalQuestions: prev.totalQuestions + 1,\n correctAnswers: prev.correctAnswers + (isCorrect ? 1 : 0),\n streak: isCorrect ? prev.streak + 1 : 0,\n score: prev.score + (isCorrect ? calculateScore(currentWord, prev.streak) : 0),\n xp: prev.xp + (isCorrect ? 10 + prev.streak * 2 : 5),\n };\n \n // Check for achievements\n checkAchievements(newStats);\n \n return newStats;\n });\n \n setShowResult(true);\n \n // Play sound feedback\n playFeedbackSound(isCorrect);\n \n // Auto-proceed to next question\n setTimeout(() => {\n generateNewQuestion();\n }, 2000);\n }, [selectedAnswer, currentWord]);\n\n const calculateScore = (word: Word, streak: number): number => {\n const baseScore = {\n beginner: 10,\n intermediate: 15,\n advanced: 20,\n }[word.difficulty];\n \n const streakMultiplier = Math.min(1 + (streak * 0.1), 2.0);\n return Math.floor(baseScore * streakMultiplier);\n };\n\n const checkAchievements = (stats: GameStats) => {\n if (stats.streak === 5) {\n showAchievement('🔥 Hot Streak!', 'Answer 5 questions correctly in a row');\n }\n if (stats.correctAnswers === 10) {\n showAchievement('📚 Scholar!', 'Answer 10 questions correctly');\n }\n if (stats.xp >= 100) {\n showAchievement('⭐ XP Master!', 'Earn 100 XP points');\n }\n };\n\n const showAchievement = (title: string, description: string) => {\n Alert.alert('Achievement Unlocked!', `${title}\\n${description}`);\n };\n\n const playFeedbackSound = async (isCorrect: boolean) => {\n try {\n if (sound) {\n await sound.unloadAsync();\n }\n \n // In a real app, you'd have actual sound files\n const soundFile = isCorrect ? 'correct.mp3' : 'incorrect.mp3';\n console.log(`Playing ${soundFile}`);\n \n } catch (error) {\n console.error('Error playing sound:', error);\n }\n };\n\n const playPronunciation = async () => {\n if (!currentWord) return;\n \n try {\n // In a real app, you'd use text-to-speech or audio files\n console.log(`Playing pronunciation: ${currentWord.pronunciation}`);\n \n } catch (error) {\n console.error('Error playing pronunciation:', error);\n }\n };\n\n const animateResult = () => {\n Animated.sequence([\n Animated.timing(animationValue, {\n toValue: 1,\n duration: 300,\n useNativeDriver: true,\n }),\n Animated.timing(animationValue, {\n toValue: 0,\n duration: 300,\n useNativeDriver: true,\n }),\n ]).start();\n };\n\n if (!currentWord) {\n return (\n <View style={styles.loadingContainer}>\n <Text style={styles.loadingText}>Loading...</Text>\n </View>\n );\n }\n\n return (\n <LinearGradient\n colors={['#667eea', '#764ba2']}\n style={styles.container}\n >\n {/* Header with Stats */}\n <View style={styles.header}>\n <View style={styles.statItem}>\n <Text style={styles.statValue}>{gameStats.score}</Text>\n <Text style={styles.statLabel}>Score</Text>\n </View>\n <View style={styles.statItem}>\n <Text style={styles.statValue}>{gameStats.streak}</Text>\n <Text style={styles.statLabel}>Streak</Text>\n </View>\n <View style={styles.statItem}>\n <Text style={styles.statValue}>{gameStats.xp}</Text>\n <Text style={styles.statLabel}>XP</Text>\n </View>\n </View>\n\n {/* Progress Bar */}\n <View style={styles.progressContainer}>\n <View style={styles.progressBarBackground}>\n <View \n style={[\n styles.progressBarFill,\n { width: `${(gameStats.correctAnswers / gameStats.totalQuestions) * 100 || 0}%` }\n ]}\n />\n </View>\n <Text style={styles.progressText}>\n {gameStats.correctAnswers}/{gameStats.totalQuestions} Correct\n </Text>\n </View>\n\n {/* Question Card */}\n <View style={styles.questionCard}>\n <Text style={styles.questionCategory}>{currentWord.category.toUpperCase()}</Text>\n <Text style={styles.questionWord}>{currentWord.word}</Text>\n <Text style={styles.questionPronunciation}>/{currentWord.pronunciation}/</Text>\n \n <TouchableOpacity \n style={styles.pronunciationButton}\n onPress={playPronunciation}\n >\n <Text style={styles.pronunciationButtonText}>🔊 Listen</Text>\n </TouchableOpacity>\n </View>\n\n {/* Answer Options */}\n <View style={styles.optionsContainer}>\n {options.map((option, index) => {\n let buttonStyle = styles.optionButton;\n let textStyle = styles.optionText;\n \n if (selectedAnswer && option === currentWord.translation) {\n buttonStyle = [styles.optionButton, styles.correctOption];\n textStyle = [styles.optionText, styles.correctOptionText];\n } else if (selectedAnswer === option && !isAnswerCorrect) {\n buttonStyle = [styles.optionButton, styles.incorrectOption];\n textStyle = [styles.optionText, styles.incorrectOptionText];\n }\n \n return (\n <TouchableOpacity\n key={index}\n style={buttonStyle}\n onPress={() => handleAnswer(option)}\n disabled={!!selectedAnswer}\n >\n <Text style={textStyle}>{option}</Text>\n </TouchableOpacity>\n );\n })}\n </View>\n\n {/* Result Feedback */}\n {showResult && (\n <Animated.View \n style={[\n styles.resultContainer,\n {\n opacity: animationValue.interpolate({\n inputRange: [0, 1],\n outputRange: [0.7, 1],\n }),\n transform: [{\n scale: animationValue.interpolate({\n inputRange: [0, 1],\n outputRange: [0.8, 1],\n })\n }]\n }\n ]}\n >\n <Text style={[\n styles.resultText,\n { color: isAnswerCorrect ? '#4CAF50' : '#FF5722' }\n ]}>\n {isAnswerCorrect ? '✅ Correct!' : '❌ Incorrect!'}\n </Text>\n {isAnswerCorrect && (\n <Text style={styles.resultExplanation}>\n +{calculateScore(currentWord, gameStats.streak - 1)} points!\n </Text>\n )}\n {!isAnswerCorrect && (\n <Text style={styles.resultExplanation}>\n The correct answer was: {currentWord.translation}\n </Text>\n )}\n </Animated.View>\n )}\n </LinearGradient>\n );\n};\n\nconst { width } = Dimensions.get('window');\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n padding: 20,\n },\n loadingContainer: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n },\n loadingText: {\n fontSize: 18,\n color: 'white',\n },\n header: {\n flexDirection: 'row',\n justifyContent: 'space-around',\n marginTop: 40,\n marginBottom: 20,\n },\n statItem: {\n alignItems: 'center',\n },\n statValue: {\n fontSize: 24,\n fontWeight: 'bold',\n color: 'white',\n },\n statLabel: {\n fontSize: 14,\n color: 'rgba(255, 255, 255, 0.8)',\n },\n progressContainer: {\n marginBottom: 30,\n },\n progressBarBackground: {\n height: 8,\n backgroundColor: 'rgba(255, 255, 255, 0.3)',\n borderRadius: 4,\n overflow: 'hidden',\n },\n progressBarFill: {\n height: '100%',\n backgroundColor: '#4CAF50',\n borderRadius: 4,\n },\n progressText: {\n color: 'white',\n textAlign: 'center',\n marginTop: 8,\n fontSize: 14,\n },\n questionCard: {\n backgroundColor: 'white',\n borderRadius: 20,\n padding: 30,\n alignItems: 'center',\n marginBottom: 30,\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 4 },\n shadowOpacity: 0.3,\n shadowRadius: 8,\n elevation: 8,\n },\n questionCategory: {\n fontSize: 12,\n color: '#666',\n marginBottom: 10,\n letterSpacing: 2,\n },\n questionWord: {\n fontSize: 36,\n fontWeight: 'bold',\n color: '#2C3E50',\n marginBottom: 10,\n },\n questionPronunciation: {\n fontSize: 18,\n color: '#7F8C8D',\n fontStyle: 'italic',\n marginBottom: 15,\n },\n pronunciationButton: {\n backgroundColor: '#3498DB',\n paddingHorizontal: 20,\n paddingVertical: 10,\n borderRadius: 20,\n },\n pronunciationButtonText: {\n color: 'white',\n fontSize: 16,\n fontWeight: '600',\n },\n optionsContainer: {\n flex: 1,\n },\n optionButton: {\n backgroundColor: 'white',\n padding: 18,\n borderRadius: 15,\n marginBottom: 15,\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 2 },\n shadowOpacity: 0.1,\n shadowRadius: 4,\n elevation: 3,\n },\n correctOption: {\n backgroundColor: '#4CAF50',\n },\n incorrectOption: {\n backgroundColor: '#FF5722',\n },\n optionText: {\n fontSize: 18,\n textAlign: 'center',\n color: '#2C3E50',\n fontWeight: '600',\n },\n correctOptionText: {\n color: 'white',\n },\n incorrectOptionText: {\n color: 'white',\n },\n resultContainer: {\n position: 'absolute',\n bottom: 100,\n left: 20,\n right: 20,\n backgroundColor: 'white',\n padding: 20,\n borderRadius: 15,\n alignItems: 'center',\n },\n resultText: {\n fontSize: 20,\n fontWeight: 'bold',\n marginBottom: 5,\n },\n resultExplanation: {\n fontSize: 14,\n color: '#666',\n textAlign: 'center',\n },\n});\n\nexport default VocabularyGame;\n```\n\n## 🧠 Spaced Repetition Algorithm\n\n### Intelligent Review System\n\n```typescript\n// services/SpacedRepetitionService.ts\nimport AsyncStorage from '@react-native-async-storage/async-storage';\n\ninterface ReviewItem {\n wordId: string;\n lastReviewed: Date;\n reviewCount: number;\n easiness: number; // 1.3 to 2.5\n interval: number; // Days until next review\n nextReview: Date;\n}\n\nclass SpacedRepetitionService {\n private static readonly STORAGE_KEY = 'spaced_repetition_data';\n private reviewData: Map<string, ReviewItem> = new Map();\n\n async initialize() {\n try {\n const stored = await AsyncStorage.getItem(SpacedRepetitionService.STORAGE_KEY);\n if (stored) {\n const data = JSON.parse(stored);\n this.reviewData = new Map(Object.entries(data));\n }\n } catch (error) {\n console.error('Error loading spaced repetition data:', error);\n }\n }\n\n async save() {\n try {\n const data = Object.fromEntries(this.reviewData);\n await AsyncStorage.setItem(\n SpacedRepetitionService.STORAGE_KEY, \n JSON.stringify(data)\n );\n } catch (error) {\n console.error('Error saving spaced repetition data:', error);\n }\n }\n\n getWordsToReview(): string[] {\n const now = new Date();\n const wordsToReview: string[] = [];\n\n this.reviewData.forEach((item, wordId) => {\n if (item.nextReview <= now) {\n wordsToReview.push(wordId);\n }\n });\n\n // Sort by priority (overdue items first)\n return wordsToReview.sort((a, b) => {\n const itemA = this.reviewData.get(a)!;\n const itemB = this.reviewData.get(b)!;\n return itemA.nextReview.getTime() - itemB.nextReview.getTime();\n });\n }\n\n recordReview(\n wordId: string, \n quality: number // 0-5 (0 = complete blackout, 5 = perfect)\n ) {\n let item = this.reviewData.get(wordId);\n \n if (!item) {\n // New word\n item = {\n wordId,\n lastReviewed: new Date(),\n reviewCount: 0,\n easiness: 2.5,\n interval: 1,\n nextReview: new Date(),\n };\n }\n\n // SuperMemo-2 algorithm\n item.reviewCount++;\n item.lastReviewed = new Date();\n\n if (quality >= 3) {\n // Correct answer\n if (item.reviewCount === 1) {\n item.interval = 1;\n } else if (item.reviewCount === 2) {\n item.interval = 6;\n } else {\n item.interval = Math.round(item.interval * item.easiness);\n }\n } else {\n // Incorrect answer - reset interval\n item.interval = 1;\n item.reviewCount = 0;\n }\n\n // Update easiness factor\n item.easiness = Math.max(\n 1.3,\n item.easiness + (0.1 - (5 - quality) * (0.08 + (5 - quality) * 0.02))\n );\n\n // Set next review date\n item.nextReview = new Date();\n item.nextReview.setDate(item.nextReview.getDate() + item.interval);\n\n this.reviewData.set(wordId, item);\n this.save();\n }\n\n getStudyStats(): {\n totalWords: number;\n dueToday: number;\n reviewedToday: number;\n averageEasiness: number;\n } {\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const tomorrow = new Date(today);\n tomorrow.setDate(tomorrow.getDate() + 1);\n\n let dueToday = 0;\n let reviewedToday = 0;\n let totalEasiness = 0;\n\n this.reviewData.forEach(item => {\n if (item.nextReview <= tomorrow) {\n dueToday++;\n }\n \n if (item.lastReviewed >= today) {\n reviewedToday++;\n }\n \n totalEasiness += item.easiness;\n });\n\n return {\n totalWords: this.reviewData.size,\n dueToday,\n reviewedToday,\n averageEasiness: totalEasiness / this.reviewData.size || 2.5,\n };\n }\n}\n\nexport default SpacedRepetitionService;\n```\n\n## 🎤 Speech Recognition for Pronunciation\n\n### Voice Practice Component\n\n```typescript\n// components/PronunciationPractice.tsx\nimport React, { useState, useEffect } from 'react';\nimport {\n View,\n Text,\n TouchableOpacity,\n StyleSheet,\n Alert,\n Animated,\n} from 'react-native';\nimport { Audio } from 'expo-av';\nimport * as Speech from 'expo-speech';\n\ninterface PronunciationResult {\n accuracy: number; // 0-100\n feedback: string;\n phonemes: Array<{\n phoneme: string;\n accuracy: number;\n }>;\n}\n\nexport const PronunciationPractice: React.FC<{\n word: string;\n targetPronunciation: string;\n onComplete: (result: PronunciationResult) => void;\n}> = ({ word, targetPronunciation, onComplete }) => {\n const [isRecording, setIsRecording] = useState(false);\n const [recording, setRecording] = useState<Audio.Recording | null>(null);\n const [isAnalyzing, setIsAnalyzing] = useState(false);\n const [waveAnimation] = useState(new Animated.Value(0));\n\n useEffect(() => {\n return () => {\n if (recording) {\n recording.stopAndUnloadAsync();\n }\n };\n }, [recording]);\n\n const startRecording = async () => {\n try {\n const { status } = await Audio.requestPermissionsAsync();\n if (status !== 'granted') {\n Alert.alert('Permission required', 'Microphone access needed for pronunciation practice');\n return;\n }\n\n await Audio.setAudioModeAsync({\n allowsRecordingIOS: true,\n playsInSilentModeIOS: true,\n });\n\n const { recording } = await Audio.Recording.createAsync(\n Audio.RecordingOptionsPresets.HIGH_QUALITY\n );\n \n setRecording(recording);\n setIsRecording(true);\n \n // Start wave animation\n Animated.loop(\n Animated.sequence([\n Animated.timing(waveAnimation, {\n toValue: 1,\n duration: 500,\n useNativeDriver: true,\n }),\n Animated.timing(waveAnimation, {\n toValue: 0,\n duration: 500,\n useNativeDriver: true,\n }),\n ])\n ).start();\n \n } catch (error) {\n console.error('Error starting recording:', error);\n Alert.alert('Error', 'Could not start recording');\n }\n };\n\n const stopRecording = async () => {\n if (!recording) return;\n\n setIsRecording(false);\n waveAnimation.stopAnimation();\n waveAnimation.setValue(0);\n setIsAnalyzing(true);\n\n try {\n await recording.stopAndUnloadAsync();\n const uri = recording.getURI();\n \n if (uri) {\n const result = await analyzePronunciation(uri, targetPronunciation);\n onComplete(result);\n }\n } catch (error) {\n console.error('Error stopping recording:', error);\n Alert.alert('Error', 'Could not analyze pronunciation');\n } finally {\n setIsAnalyzing(false);\n setRecording(null);\n }\n };\n\n const analyzePronunciation = async (\n audioUri: string, \n target: string\n ): Promise<PronunciationResult> => {\n // In a real app, you'd use services like:\n // - Google Speech-to-Text API\n // - Azure Cognitive Services Speech\n // - Amazon Transcribe\n // - Custom ML models\n \n console.log(`Analyzing pronunciation of \"${target}\" from ${audioUri}`);\n \n // Mock analysis for demo\n const accuracy = 70 + Math.random() * 30;\n \n return {\n accuracy: Math.round(accuracy),\n feedback: accuracy > 80 \n ? 'Excellent pronunciation!' \n : accuracy > 60 \n ? 'Good, but try to emphasize the syllables more.'\n : 'Keep practicing! Focus on the vowel sounds.',\n phonemes: target.split(' ').map(phoneme => ({\n phoneme,\n accuracy: 60 + Math.random() * 40,\n })),\n };\n };\n\n const playTargetPronunciation = () => {\n Speech.speak(word, {\n language: 'es-ES', // Spanish\n pitch: 1.0,\n rate: 0.8,\n });\n };\n\n return (\n <View style={styles.container}>\n <Text style={styles.title}>Practice Pronunciation</Text>\n <Text style={styles.word}>{word}</Text>\n <Text style={styles.pronunciation}>/{targetPronunciation}/</Text>\n \n <TouchableOpacity \n style={styles.playButton}\n onPress={playTargetPronunciation}\n >\n <Text style={styles.playButtonText}>🔊 Play Target</Text>\n </TouchableOpacity>\n\n {/* Recording Visualizer */}\n <View style={styles.visualizerContainer}>\n {Array.from({ length: 5 }).map((_, index) => (\n <Animated.View\n key={index}\n style={[\n styles.waveBar,\n {\n opacity: waveAnimation.interpolate({\n inputRange: [0, 1],\n outputRange: [0.3, 1],\n }),\n transform: [{\n scaleY: waveAnimation.interpolate({\n inputRange: [0, 1],\n outputRange: [0.5, 1 + index * 0.2],\n }),\n }],\n },\n ]}\n />\n ))}\n </View>\n\n {/* Record Button */}\n <TouchableOpacity\n style={[\n styles.recordButton,\n isRecording && styles.recordingButton,\n isAnalyzing && styles.analyzingButton,\n ]}\n onPress={isRecording ? stopRecording : startRecording}\n disabled={isAnalyzing}\n >\n <Text style={styles.recordButtonText}>\n {isAnalyzing \n ? '🔍 Analyzing...' \n : isRecording \n ? '⏹️ Stop Recording'\n : '🎤 Start Recording'\n }\n </Text>\n </TouchableOpacity>\n\n <Text style={styles.instruction}>\n {isRecording \n ? 'Say the word clearly'\n : 'Tap to record your pronunciation'\n }\n </Text>\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n padding: 20,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: '#F8F9FA',\n },\n title: {\n fontSize: 24,\n fontWeight: 'bold',\n color: '#2C3E50',\n marginBottom: 20,\n },\n word: {\n fontSize: 48,\n fontWeight: 'bold',\n color: '#3498DB',\n marginBottom: 10,\n },\n pronunciation: {\n fontSize: 20,\n color: '#7F8C8D',\n fontStyle: 'italic',\n marginBottom: 20,\n },\n playButton: {\n backgroundColor: '#2ECC71',\n paddingHorizontal: 30,\n paddingVertical: 15,\n borderRadius: 25,\n marginBottom: 40,\n },\n playButtonText: {\n color: 'white',\n fontSize: 18,\n fontWeight: '600',\n },\n visualizerContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n height: 60,\n marginBottom: 40,\n },\n waveBar: {\n width: 6,\n height: 40,\n backgroundColor: '#3498DB',\n borderRadius: 3,\n marginHorizontal: 2,\n },\n recordButton: {\n backgroundColor: '#E74C3C',\n paddingHorizontal: 40,\n paddingVertical: 20,\n borderRadius: 30,\n marginBottom: 20,\n },\n recordingButton: {\n backgroundColor: '#FF6B6B',\n },\n analyzingButton: {\n backgroundColor: '#95A5A6',\n },\n recordButtonText: {\n color: 'white',\n fontSize: 18,\n fontWeight: 'bold',\n },\n instruction: {\n fontSize: 16,\n color: '#666',\n textAlign: 'center',\n },\n});\n\nexport default PronunciationPractice;\n```\n\n## 🤖 AI-Powered Content Generation\n\n### Personalized Learning Content\n\n```typescript\n// services/LanguageLearningAI.ts\nimport OpenAI from 'openai';\n\ninterface LearnerProfile {\n level: 'beginner' | 'intermediate' | 'advanced';\n nativeLanguage: string;\n targetLanguage: string;\n interests: string[];\n weakAreas: string[];\n learningStyle: 'visual' | 'auditory' | 'kinesthetic';\n}\n\nclass LanguageLearningAI {\n private openai: OpenAI;\n\n constructor(apiKey: string) {\n this.openai = new OpenAI({ apiKey });\n }\n\n async generatePersonalizedLesson(\n profile: LearnerProfile,\n topic: string\n ): Promise<{\n vocabulary: Array<{ word: string; translation: string; example: string }>;\n exercises: Array<{ type: string; question: string; options: string[]; answer: string }>;\n culturalNotes: string[];\n }> {\n const prompt = `\n Create a ${profile.targetLanguage} lesson for a ${profile.level} learner.\n Native language: ${profile.nativeLanguage}\n Topic: ${topic}\n Interests: ${profile.interests.join(', ')}\n Weak areas: ${profile.weakAreas.join(', ')}\n Learning style: ${profile.learningStyle}\n \n Generate:\n 1. 10 relevant vocabulary words with translations and example sentences\n 2. 5 varied exercises (multiple choice, fill-in-blank, etc.)\n 3. 3 cultural notes related to the topic\n \n Return as JSON with vocabulary, exercises, and culturalNotes arrays.\n `;\n\n try {\n const response = await this.openai.chat.completions.create({\n model: 'gpt-4',\n messages: [{ role: 'user', content: prompt }],\n temperature: 0.7,\n });\n\n return JSON.parse(response.choices[0].message.content || '{}');\n } catch (error) {\n console.error('Lesson generation error:', error);\n return { vocabulary: [], exercises: [], culturalNotes: [] };\n }\n }\n\n async generateStory(\n profile: LearnerProfile,\n theme: string,\n targetWords: string[]\n ): Promise<{\n story: string;\n comprehensionQuestions: Array<{ question: string; answer: string }>;\n vocabulary: Array<{ word: string; definition: string; context: string }>;\n }> {\n const prompt = `\n Write a short story in ${profile.targetLanguage} for a ${profile.level} learner.\n Theme: ${theme}\n Must include these words: ${targetWords.join(', ')}\n Interests: ${profile.interests.join(', ')}\n \n The story should be:\n - Appropriate for ${profile.level} level\n - Engaging and culturally relevant\n - 200-300 words long\n \n Include:\n 1. The story text\n 2. 5 comprehension questions with answers\n 3. Vocabulary explanations for difficult words\n \n Return as JSON.\n `;\n\n try {\n const response = await this.openai.chat.completions.create({\n model: 'gpt-4',\n messages: [{ role: 'user', content: prompt }],\n temperature: 0.8,\n });\n\n return JSON.parse(response.choices[0].message.content || '{}');\n } catch (error) {\n console.error('Story generation error:', error);\n return { story: '', comprehensionQuestions: [], vocabulary: [] };\n }\n }\n\n async analyzeLearningProgress(\n profile: LearnerProfile,\n recentSessions: Array<{\n topic: string;\n accuracy: number;\n timeSpent: number;\n mistakes: string[];\n }>\n ): Promise<{\n strengths: string[];\n weaknesses: string[];\n recommendations: string[];\n nextTopics: string[];\n }> {\n const prompt = `\n Analyze language learning progress:\n \n Learner profile:\n - Level: ${profile.level}\n - Target language: ${profile.targetLanguage}\n - Weak areas: ${profile.weakAreas.join(', ')}\n \n Recent performance:\n ${recentSessions.map(session => \n `- ${session.topic}: ${session.accuracy}% accuracy, ${session.timeSpent}min, mistakes: ${session.mistakes.join(', ')}`\n ).join('\\n')}\n \n Provide:\n 1. Learning strengths identified\n 2. Areas needing improvement\n 3. Specific study recommendations\n 4. Suggested next topics to study\n \n Return as JSON.\n `;\n\n try {\n const response = await this.openai.chat.completions.create({\n model: 'gpt-3.5-turbo',\n messages: [{ role: 'user', content: prompt }],\n temperature: 0.3,\n });\n\n return JSON.parse(response.choices[0].message.content || '{}');\n } catch (error) {\n console.error('Progress analysis error:', error);\n return { strengths: [], weaknesses: [], recommendations: [], nextTopics: [] };\n }\n }\n}\n\nexport default LanguageLearningAI;\n```\n\n## 📝 Summary\n\nIn this lesson, you learned:\n- How to create engaging language learning games with gamification\n- Implementing spaced repetition algorithms for effective memorization\n- Building pronunciation practice with speech recognition\n- Using AI to generate personalized learning content and assessments\n- Creating progress tracking systems and achievement mechanics\n- Understanding the psychology of language learning through games\n\n## 🤖 Practice with AI\n\nCode with AI: Try building these language learning features.\n\n**Prompts to try:**\n- *\"Create a grammar quiz game that adapts difficulty based on user performance\"*\n- *\"Build a chatbot conversation simulator for language practice with contextual responses\"*\n- *\"Design a cultural trivia game that teaches language through cultural context\"*\n- *\"Implement a story builder where users create stories using new vocabulary words\"*\n- *\"Create a multiplayer language competition with real-time challenges\"*\n\nLanguage learning apps have incredible user retention and monetization potential - combine education with entertainment to create the next Duolingo!