SEA / index.html
AptlyDigital's picture
Rename deepseek_html_20260108_c1212a.html to index.html
7104bdf verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI-Powered Spelling Tutor</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: linear-gradient(135deg, #0a0a0f 0%, #1a1a2e 100%);
color: #fff;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
overflow: hidden;
height: 100vh;
}
#canvasContainer {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 1;
}
canvas {
display: block;
outline: none;
width: 100%;
height: 100%;
}
/* === MAIN INTERFACE === */
.main-interface {
position: fixed;
top: 20px;
left: 20px;
right: 20px;
bottom: 20px;
background: rgba(20, 20, 35, 0.7);
backdrop-filter: blur(10px);
border-radius: 24px;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
display: flex;
overflow: hidden;
z-index: 2;
}
/* === SIDEBAR === */
.sidebar {
width: 320px;
background: rgba(15, 15, 25, 0.9);
border-right: 1px solid rgba(255, 255, 255, 0.05);
padding: 25px;
display: flex;
flex-direction: column;
overflow-y: auto;
}
.sidebar-header {
margin-bottom: 30px;
}
.sidebar-title {
font-size: 1.5em;
font-weight: 600;
color: #5a6cff;
margin-bottom: 5px;
display: flex;
align-items: center;
gap: 10px;
}
.sidebar-subtitle {
color: #8892b0;
font-size: 0.9em;
}
.section {
margin-bottom: 30px;
}
.section-title {
font-size: 1em;
font-weight: 600;
color: #a0b0ff;
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 8px;
}
.btn-group {
display: flex;
flex-direction: column;
gap: 10px;
}
.btn {
padding: 12px 20px;
background: rgba(255, 255, 255, 0.07);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
color: #e0e0ff;
font-family: inherit;
font-size: 0.95em;
cursor: pointer;
transition: all 0.3s ease;
text-align: left;
display: flex;
align-items: center;
gap: 10px;
}
.btn:hover {
background: rgba(255, 255, 255, 0.12);
transform: translateX(5px);
}
.btn.active {
background: linear-gradient(135deg, #5a6cff, #7a8aff);
color: white;
border-color: #5a6cff;
}
.btn-primary {
background: linear-gradient(135deg, #5a6cff, #7a8aff);
color: white;
border: none;
font-weight: 500;
justify-content: center;
}
.btn-primary:hover {
background: linear-gradient(135deg, #7a8aff, #5a6cff);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(90, 108, 255, 0.4);
}
.btn-danger {
background: linear-gradient(135deg, #ff5a5a, #ff7a7a);
color: white;
border: none;
font-weight: 500;
justify-content: center;
}
.btn-danger:hover {
background: linear-gradient(135deg, #ff7a7a, #ff5a5a);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(255, 90, 90, 0.4);
}
.progress-container {
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
padding: 15px;
margin-top: 15px;
}
.progress-bar {
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
overflow: hidden;
margin: 8px 0;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #5a6cff, #34d399);
border-radius: 3px;
transition: width 0.5s ease;
}
.progress-stats {
display: flex;
justify-content: space-between;
font-size: 0.9em;
color: #8892b0;
}
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-top: 15px;
}
.stat-card {
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
padding: 12px;
text-align: center;
}
.stat-value {
font-size: 1.3em;
font-weight: 600;
color: #5a6cff;
margin-bottom: 5px;
}
.stat-label {
font-size: 0.8em;
color: #8892b0;
}
/* === MAIN CONTENT === */
.main-content {
flex: 1;
padding: 30px;
display: flex;
flex-direction: column;
overflow-y: auto;
}
.word-display-container {
background: rgba(15, 15, 25, 0.8);
border-radius: 20px;
padding: 40px;
text-align: center;
margin-bottom: 30px;
border: 2px solid rgba(90, 108, 255, 0.3);
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.word-display {
font-family: 'Courier New', monospace;
font-size: 4em;
font-weight: 800;
letter-spacing: 8px;
margin: 20px 0;
color: white;
text-shadow: 0 0 20px rgba(90, 108, 255, 0.3);
}
.word-display.correct {
color: #34d399;
text-shadow: 0 0 20px rgba(52, 211, 153, 0.3);
}
.word-display.incorrect {
color: #ff5a5a;
text-shadow: 0 0 20px rgba(255, 90, 90, 0.3);
}
.word-hint {
color: #a0b0ff;
font-size: 1.2em;
margin-top: 15px;
font-style: italic;
}
.controls-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 30px;
}
.input-container {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
padding: 25px;
margin-bottom: 25px;
}
.input-label {
display: block;
margin-bottom: 15px;
color: #a0b0ff;
font-weight: 500;
}
.answer-input {
width: 100%;
background: rgba(255, 255, 255, 0.07);
border: 2px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 18px;
font-size: 1.3em;
color: white;
font-family: inherit;
transition: all 0.3s ease;
}
.answer-input:focus {
outline: none;
border-color: #5a6cff;
background: rgba(255, 255, 255, 0.1);
box-shadow: 0 0 0 3px rgba(90, 108, 255, 0.2);
}
.action-buttons {
display: flex;
gap: 15px;
margin-top: 20px;
}
.action-btn {
flex: 1;
padding: 16px;
border-radius: 12px;
border: none;
font-size: 1.1em;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.action-btn.check {
background: linear-gradient(135deg, #34d399, #10b981);
color: white;
}
.action-btn.check:hover {
background: linear-gradient(135deg, #10b981, #34d399);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(16, 185, 129, 0.4);
}
.action-btn.next {
background: linear-gradient(135deg, #5a6cff, #7a8aff);
color: white;
}
.action-btn.next:hover {
background: linear-gradient(135deg, #7a8aff, #5a6cff);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(90, 108, 255, 0.4);
}
.action-btn.hint {
background: linear-gradient(135deg, #fbbf24, #f59e0b);
color: white;
}
.action-btn.hint:hover {
background: linear-gradient(135deg, #f59e0b, #fbbf24);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(251, 191, 36, 0.4);
}
.feedback-container {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
padding: 25px;
margin-top: 25px;
}
.feedback-title {
color: #a0b0ff;
margin-bottom: 15px;
font-weight: 500;
}
.feedback-content {
color: #e0e0ff;
line-height: 1.6;
font-size: 1.1em;
}
.feedback-content.correct {
color: #34d399;
}
.feedback-content.incorrect {
color: #ff5a5a;
}
/* === AI CHAT === */
.ai-chat {
width: 350px;
background: rgba(15, 15, 25, 0.9);
border-left: 1px solid rgba(255, 255, 255, 0.05);
display: flex;
flex-direction: column;
}
.chat-header {
padding: 25px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.chat-title {
font-size: 1.2em;
font-weight: 600;
color: #5a6cff;
display: flex;
align-items: center;
gap: 10px;
}
.chat-status {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.9em;
color: #8892b0;
margin-top: 5px;
}
.status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background: #00ff9d;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 15px;
}
.message {
max-width: 85%;
padding: 12px 16px;
border-radius: 18px;
line-height: 1.4;
animation: messageAppear 0.3s ease;
}
@keyframes messageAppear {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.message-ai {
align-self: flex-start;
background: rgba(90, 108, 255, 0.2);
color: #e0e0ff;
border: 1px solid rgba(90, 108, 255, 0.3);
}
.message-user {
align-self: flex-end;
background: rgba(52, 211, 153, 0.2);
color: #e0e0ff;
border: 1px solid rgba(52, 211, 153, 0.3);
}
.typing-indicator {
display: flex;
align-items: center;
gap: 5px;
padding: 12px 16px;
background: rgba(255, 255, 255, 0.05);
border-radius: 18px;
align-self: flex-start;
width: 70px;
}
.typing-dot {
width: 8px;
height: 8px;
background: #a0b0ff;
border-radius: 50%;
animation: typing 1.4s infinite ease-in-out;
}
.typing-dot:nth-child(1) { animation-delay: -0.32s; }
.typing-dot:nth-child(2) { animation-delay: -0.16s; }
@keyframes typing {
0%, 80%, 100% { transform: translateY(0); }
40% { transform: translateY(-10px); }
}
.chat-input-container {
padding: 20px;
border-top: 1px solid rgba(255, 255, 255, 0.05);
}
.chat-input-wrapper {
display: flex;
gap: 10px;
}
.chat-input {
flex: 1;
background: rgba(255, 255, 255, 0.07);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 12px 16px;
color: white;
font-family: inherit;
resize: none;
min-height: 50px;
max-height: 100px;
}
.chat-input:focus {
outline: none;
border-color: #5a6cff;
}
.voice-input-btn {
width: 50px;
border-radius: 12px;
background: linear-gradient(135deg, #5a6cff, #7a8aff);
border: none;
color: white;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.voice-input-btn:hover {
background: linear-gradient(135deg, #7a8aff, #5a6cff);
transform: translateY(-2px);
}
.voice-input-btn.listening {
background: linear-gradient(135deg, #ff5a5a, #ff7a7a);
animation: pulse 1.5s infinite;
}
/* === LOADING SCREEN === */
.loading-screen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #0a0a0f 0%, #1a1a2e 100%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 1000;
}
.spinner {
width: 60px;
height: 60px;
border: 3px solid rgba(90, 108, 255, 0.3);
border-top-color: #5a6cff;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* === RESPONSIVE === */
@media (max-width: 1200px) {
.ai-chat {
display: none;
}
}
@media (max-width: 900px) {
.sidebar {
width: 280px;
}
.word-display {
font-size: 3em;
letter-spacing: 6px;
}
}
@media (max-width: 768px) {
.main-interface {
flex-direction: column;
}
.sidebar {
width: 100%;
border-right: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
max-height: 200px;
}
.controls-grid {
grid-template-columns: 1fr;
}
.action-buttons {
flex-direction: column;
}
}
</style>
</head>
<body>
<!-- 3D Visualization Canvas -->
<div id="canvasContainer">
<canvas id="mainCanvas"></canvas>
</div>
<!-- Main Interface -->
<div class="main-interface">
<!-- Sidebar -->
<div class="sidebar">
<div class="sidebar-header">
<div class="sidebar-title">
<i class="fas fa-brain"></i>
AI Spelling Tutor
</div>
<div class="sidebar-subtitle">Adaptive Learning System</div>
</div>
<div class="section">
<div class="section-title">
<i class="fas fa-book"></i>
Difficulty Level
</div>
<div class="btn-group">
<button class="btn active" data-level="beginner">
<i class="fas fa-seedling"></i>
Beginner
</button>
<button class="btn" data-level="intermediate">
<i class="fas fa-leaf"></i>
Intermediate
</button>
<button class="btn" data-level="advanced">
<i class="fas fa-tree"></i>
Advanced
</button>
<button class="btn" data-level="expert">
<i class="fas fa-mountain"></i>
Expert
</button>
</div>
</div>
<div class="section">
<div class="section-title">
<i class="fas fa-gamepad"></i>
Training Mode
</div>
<div class="btn-group">
<button class="btn active" data-mode="adaptive">
<i class="fas fa-robot"></i>
Adaptive AI
</button>
<button class="btn" data-mode="practice">
<i class="fas fa-dumbbell"></i>
Practice Mode
</button>
<button class="btn" data-mode="challenge">
<i class="fas fa-trophy"></i>
Challenge Mode
</button>
<button class="btn" data-mode="time-trial">
<i class="fas fa-clock"></i>
Time Trial
</button>
</div>
</div>
<div class="section">
<div class="section-title">
<i class="fas fa-chart-line"></i>
Progress
</div>
<div class="progress-container">
<div class="progress-stats">
<span>Level 2</span>
<span>65%</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill" style="width: 65%"></div>
</div>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-value" id="wordsMastered">24</div>
<div class="stat-label">Words Mastered</div>
</div>
<div class="stat-card">
<div class="stat-value" id="streakCount">5</div>
<div class="stat-label">Day Streak</div>
</div>
</div>
</div>
</div>
<div class="section">
<div class="section-title">
<i class="fas fa-volume-up"></i>
Voice Settings
</div>
<div class="btn-group">
<button class="btn active" data-voice="en-US-GuyNeural">
<i class="fas fa-user"></i>
US Male
</button>
<button class="btn" data-voice="en-US-AriaNeural">
<i class="fas fa-user"></i>
US Female
</button>
<button class="btn" data-voice="en-GB-SoniaNeural">
<i class="fas fa-user"></i>
UK Female
</button>
</div>
</div>
<button class="btn btn-primary" id="startSession">
<i class="fas fa-play"></i>
Start Training Session
</button>
<button class="btn btn-danger" id="resetSession" style="margin-top: 15px;">
<i class="fas fa-redo"></i>
Reset Session
</button>
</div>
<!-- Main Content -->
<div class="main-content">
<div class="word-display-container">
<div class="word-display" id="currentWord">Ready to begin?</div>
<div class="word-hint" id="wordHint"></div>
</div>
<div class="input-container">
<label class="input-label">
<i class="fas fa-keyboard"></i>
Type your spelling here:
</label>
<input type="text" class="answer-input" id="answerInput" placeholder="Type the word you hear...">
<div class="action-buttons">
<button class="action-btn check" id="checkButton">
<i class="fas fa-check"></i>
Check Answer
</button>
<button class="action-btn hint" id="hintButton">
<i class="fas fa-lightbulb"></i>
Get Hint
</button>
<button class="action-btn next" id="nextButton" style="display: none;">
<i class="fas fa-arrow-right"></i>
Next Word
</button>
</div>
</div>
<div class="controls-grid">
<button class="btn" id="hearButton">
<i class="fas fa-volume-up"></i>
Hear Word
</button>
<button class="btn" id="spellButton">
<i class="fas fa-spell-check"></i>
Spell Out
</button>
<button class="btn" id="contextButton">
<i class="fas fa-comment-alt"></i>
Context Sentence
</button>
<button class="btn" id="repeatButton">
<i class="fas fa-redo"></i>
Repeat
</button>
</div>
<div class="feedback-container">
<div class="feedback-title">
<i class="fas fa-comment-dots"></i>
AI Tutor Feedback
</div>
<div class="feedback-content" id="aiFeedback">
Welcome to AI Spelling Tutor! I'll help you improve your spelling skills through personalized training. Click "Start Training Session" to begin!
</div>
</div>
</div>
<!-- AI Chat -->
<div class="ai-chat">
<div class="chat-header">
<div class="chat-title">
<i class="fas fa-robot"></i>
AI Tutor
</div>
<div class="chat-status">
<span class="status-indicator"></span>
<span>Adaptive Learning Active</span>
</div>
</div>
<div class="chat-messages" id="chatMessages">
<div class="message message-ai">
Hello! I'm your AI spelling tutor. I'll adapt to your skill level and help you master spelling through personalized exercises.
</div>
<div class="message message-ai">
Click "Start Training Session" to begin. I'll track your progress and adjust difficulty based on your performance.
</div>
<div class="typing-indicator" id="typingIndicator" style="display: none;">
<div class="typing-dot"></div>
<div class="typing-dot"></div>
<div class="typing-dot"></div>
</div>
</div>
<div class="chat-input-container">
<div class="chat-input-wrapper">
<textarea class="chat-input" id="chatInput" placeholder="Ask your AI tutor a question..."></textarea>
<button class="voice-input-btn" id="voiceButton">
<i class="fas fa-microphone"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Loading Screen -->
<div class="loading-screen" id="loadingScreen">
<div class="spinner"></div>
<div id="loadingText">Initializing AI Tutor System...</div>
</div>
<script>
// ============================================================================
// CORE AI SPELLING TUTOR SYSTEM
// ============================================================================
class AISpellingTutor {
constructor() {
this.initializeState();
this.initialize3D();
this.setupEventListeners();
this.hideLoading();
}
initializeState() {
// Core training state
this.state = {
sessionActive: false,
currentWord: null,
currentWordIndex: 0,
attempts: 0,
hintsUsed: 0,
isCorrect: false,
showNextButton: false,
// Adaptive learning metrics
difficulty: 'beginner',
trainingMode: 'adaptive',
currentVoice: 'en-US-GuyNeural',
// Progress tracking
wordsMastered: 24,
currentStreak: 5,
accuracy: 85,
levelProgress: 65,
// Word banks by difficulty
wordLists: {
beginner: [
{ word: "cat", context: "The small ___ purred softly.", phonetic: "/kæt/" },
{ word: "dog", context: "The loyal ___ wagged its tail.", phonetic: "/dɒɡ/" },
{ word: "house", context: "We live in a big red ___.", phonetic: "/haʊs/" },
{ word: "book", context: "She read an interesting ___.", phonetic: "/bʊk/" },
{ word: "friend", context: "My best ___ is coming over.", phonetic: "/frɛnd/" },
{ word: "water", context: "I drink eight glasses of ___ daily.", phonetic: "/ˈwɔːtər/" },
{ word: "happy", context: "She felt very ___ today.", phonetic: "/ˈhæpi/" },
{ word: "school", context: "Children learn at ___.", phonetic: "/skuːl/" }
],
intermediate: [
{ word: "beautiful", context: "The sunset was incredibly ___.", phonetic: "/ˈbjuːtɪfʊl/" },
{ word: "chocolate", context: "She loves dark ___.", phonetic: "/ˈtʃɒklət/" },
{ word: "mountain", context: "We climbed the high ___.", phonetic: "/ˈmaʊntɪn/" },
{ word: "language", context: "English is a global ___.", phonetic: "/ˈlæŋɡwɪdʒ/" },
{ word: "calendar", context: "Check the ___ for dates.", phonetic: "/ˈkælɪndər/" },
{ word: "restaurant", context: "We dined at a fancy ___.", phonetic: "/ˈrɛstrɒnt/" },
{ word: "environment", context: "Protect the natural ___.", phonetic: "/ɪnˈvaɪrənmənt/" },
{ word: "temperature", context: "The ___ is rising today.", phonetic: "/ˈtɛmprətʃər/" }
],
advanced: [
{ word: "pneumonia", context: "He was hospitalized with ___.", phonetic: "/njuːˈmoʊniə/" },
{ word: "xylophone", context: "She played the ___ beautifully.", phonetic: "/ˈzaɪləfoʊn/" },
{ word: "bouquet", context: "He brought her a ___ of roses.", phonetic: "/buːˈkeɪ/" },
{ word: "mnemonic", context: "A ___ helps with memory.", phonetic: "/nɪˈmɒnɪk/" },
{ word: "chrysanthemum", context: "The ___ bloomed in autumn.", phonetic: "/krɪˈsænθəməm/" },
{ word: "psychology", context: "She studies ___.", phonetic: "/saɪˈkɒlədʒi/" },
{ word: "rendezvous", context: "Their ___ was at sunset.", phonetic: "/ˈrɒndeɪvuː/" },
{ word: "entrepreneur", context: "The ___ started a business.", phonetic: "/ˌɒntrəprəˈnɜːr/" }
],
expert: [
{ word: "onomatopoeia", context: "Buzz is an example of ___.", phonetic: "/ˌɒnəˌmætəˈpiːə/" },
{ word: "synecdoche", context: "All hands on deck is a ___.", phonetic: "/sɪˈnɛkdəki/" },
{ word: "antediluvian", context: "The artifact was ___.", phonetic: "/ˌæntɪdɪˈluːviən/" },
{ word: "sesquipedalian", context: "He used ___ words.", phonetic: "/ˌsɛskwɪpɪˈdeɪliən/" },
{ word: "perspicacious", context: "Her insights were ___.", phonetic: "/ˌpɜːspɪˈkeɪʃəs/" },
{ word: "serendipity", context: "Finding the book was pure ___.", phonetic: "/ˌsɛrənˈdɪpɪti/" },
{ word: "philanthropist", context: "The ___ donated millions.", phonetic: "/fɪˈlænθrəpɪst/" },
{ word: "antidisestablishmentarianism", context: "He studied ___ movements.", phonetic: "/ˌæntidɪsəˌstæblɪʃmənˈtɛəriənɪzəm/" }
]
},
// Current word list based on difficulty
currentList: [],
// Performance tracking
sessionStats: {
correct: 0,
incorrect: 0,
totalAttempts: 0,
totalHints: 0,
startTime: null,
sessionDuration: 0
}
};
// Speech synthesis
this.synth = window.speechSynthesis;
this.voices = [];
this.currentUtterance = null;
// Initialize voices
this.initializeVoices();
}
initializeVoices() {
const loadVoices = () => {
this.voices = this.synth.getVoices();
console.log('Voices loaded:', this.voices.length);
};
if (this.synth.onvoiceschanged !== undefined) {
this.synth.onvoiceschanged = loadVoices;
}
if (this.synth.getVoices().length > 0) {
loadVoices();
}
}
async initialize3D() {
try {
// Check if Three.js is available
if (typeof THREE === 'undefined') {
console.log('Three.js not available, skipping 3D');
return;
}
// Create scene
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0x0a0a0f);
// Create camera
this.camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
this.camera.position.z = 5;
// Create renderer
const canvas = document.getElementById('mainCanvas');
this.renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
alpha: true
});
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// Add lights
const ambientLight = new THREE.AmbientLight(0x222244, 0.5);
this.scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0x5a6cff, 1);
directionalLight.position.set(5, 3, 5);
this.scene.add(directionalLight);
// Add particles
this.createParticles();
// Start animation loop
this.animate();
// Handle window resize
window.addEventListener('resize', () => this.onWindowResize());
console.log('3D scene initialized');
} catch (error) {
console.error('3D initialization error:', error);
}
}
createParticles() {
const particleCount = 1000;
const geometry = new THREE.BufferGeometry();
const positions = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount; i++) {
const i3 = i * 3;
positions[i3] = (Math.random() - 0.5) * 10;
positions[i3 + 1] = (Math.random() - 0.5) * 10;
positions[i3 + 2] = (Math.random() - 0.5) * 10;
}
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
const material = new THREE.PointsMaterial({
size: 0.05,
color: 0x5a6cff,
transparent: true,
opacity: 0.6,
blending: THREE.AdditiveBlending
});
this.particles = new THREE.Points(geometry, material);
this.scene.add(this.particles);
// Add central sphere
const sphereGeometry = new THREE.SphereGeometry(1, 32, 32);
const sphereMaterial = new THREE.MeshBasicMaterial({
color: 0x5a6cff,
wireframe: true,
transparent: true,
opacity: 0.1
});
this.sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
this.scene.add(this.sphere);
}
animate() {
requestAnimationFrame(() => this.animate());
if (this.particles) {
this.particles.rotation.y += 0.001;
this.particles.rotation.x += 0.0005;
// Pulsing effect
const time = Date.now() * 0.001;
const scale = 1 + Math.sin(time) * 0.1;
this.particles.scale.set(scale, scale, scale);
}
if (this.sphere) {
this.sphere.rotation.y += 0.002;
}
if (this.renderer && this.scene && this.camera) {
this.renderer.render(this.scene, this.camera);
}
}
onWindowResize() {
if (this.camera && this.renderer) {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
}
setupEventListeners() {
// Start session button
document.getElementById('startSession').addEventListener('click', () => this.startSession());
// Reset session button
document.getElementById('resetSession').addEventListener('click', () => this.resetSession());
// Check answer button
document.getElementById('checkButton').addEventListener('click', () => this.checkAnswer());
// Next word button
document.getElementById('nextButton').addEventListener('click', () => this.nextWord());
// Hint button
document.getElementById('hintButton').addEventListener('click', () => this.giveHint());
// Audio buttons
document.getElementById('hearButton').addEventListener('click', () => this.speakWord());
document.getElementById('spellButton').addEventListener('click', () => this.spellWord());
document.getElementById('contextButton').addEventListener('click', () => this.speakContext());
document.getElementById('repeatButton').addEventListener('click', () => this.repeatWord());
// Answer input - handle Enter key
document.getElementById('answerInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
this.checkAnswer();
}
});
// Difficulty buttons
document.querySelectorAll('[data-level]').forEach(btn => {
btn.addEventListener('click', (e) => {
this.setDifficulty(e.target.dataset.level);
});
});
// Training mode buttons
document.querySelectorAll('[data-mode]').forEach(btn => {
btn.addEventListener('click', (e) => {
this.setTrainingMode(e.target.dataset.mode);
});
});
// Voice buttons
document.querySelectorAll('[data-voice]').forEach(btn => {
btn.addEventListener('click', (e) => {
this.setVoice(e.target.dataset.voice);
});
});
// Chat input
document.getElementById('chatInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.sendChatMessage();
}
});
// Voice input button
document.getElementById('voiceButton').addEventListener('click', () => this.toggleVoiceInput());
}
hideLoading() {
setTimeout(() => {
document.getElementById('loadingScreen').style.opacity = '0';
setTimeout(() => {
document.getElementById('loadingScreen').style.display = 'none';
}, 500);
}, 1500);
}
// ============================================================================
// SESSION MANAGEMENT
// ============================================================================
startSession() {
this.state.sessionActive = true;
this.state.sessionStats.startTime = Date.now();
this.state.currentWordIndex = 0;
this.state.currentList = [...this.state.wordLists[this.state.difficulty]];
// Shuffle the list for practice
if (this.state.trainingMode === 'practice' || this.state.trainingMode === 'challenge') {
this.shuffleArray(this.state.currentList);
}
// Reset session stats
this.state.sessionStats = {
correct: 0,
incorrect: 0,
totalAttempts: 0,
totalHints: 0,
startTime: Date.now(),
sessionDuration: 0
};
// Update UI
document.getElementById('startSession').disabled = true;
document.getElementById('startSession').innerHTML = '<i class="fas fa-spinner fa-spin"></i> Session Active';
// Get first word
this.getNewWord();
// Add AI chat message
this.addAIMessage(`Starting ${this.state.difficulty} level spelling session! I'll adapt to your performance.`);
this.showTypingIndicator();
setTimeout(() => {
this.hideTypingIndicator();
this.addAIMessage(`First word: "${this.state.currentWord.word}". Listen carefully and type what you hear.`);
}, 1500);
}
resetSession() {
if (confirm('Are you sure you want to reset the current session?')) {
this.state.sessionActive = false;
this.state.currentWord = null;
this.state.currentWordIndex = 0;
this.state.attempts = 0;
this.state.hintsUsed = 0;
this.state.isCorrect = false;
this.state.showNextButton = false;
// Reset UI
document.getElementById('currentWord').textContent = 'Ready to begin?';
document.getElementById('currentWord').className = 'word-display';
document.getElementById('wordHint').textContent = '';
document.getElementById('answerInput').value = '';
document.getElementById('aiFeedback').textContent = 'Session reset. Click "Start Training Session" to begin!';
document.getElementById('aiFeedback').className = 'feedback-content';
document.getElementById('nextButton').style.display = 'none';
document.getElementById('checkButton').style.display = 'flex';
document.getElementById('hintButton').style.display = 'flex';
document.getElementById('startSession').disabled = false;
document.getElementById('startSession').innerHTML = '<i class="fas fa-play"></i> Start Training Session';
// Clear chat messages
document.getElementById('chatMessages').innerHTML = `
<div class="message message-ai">
Hello! I'm your AI spelling tutor. I'll adapt to your skill level and help you master spelling through personalized exercises.
</div>
<div class="message message-ai">
Click "Start Training Session" to begin. I'll track your progress and adjust difficulty based on your performance.
</div>
<div class="typing-indicator" id="typingIndicator" style="display: none;">
<div class="typing-dot"></div>
<div class="typing-dot"></div>
<div class="typing-dot"></div>
</div>
`;
this.addAIMessage('Session reset. Ready for a new challenge?');
}
}
getNewWord() {
if (this.state.currentWordIndex < this.state.currentList.length) {
this.state.currentWord = this.state.currentList[this.state.currentWordIndex];
this.state.attempts = 0;
this.state.hintsUsed = 0;
this.state.isCorrect = false;
this.state.showNextButton = false;
// Update UI
document.getElementById('currentWord').textContent = '_'.repeat(this.state.currentWord.word.length);
document.getElementById('currentWord').className = 'word-display';
document.getElementById('wordHint').textContent = '';
document.getElementById('answerInput').value = '';
document.getElementById('answerInput').focus();
document.getElementById('nextButton').style.display = 'none';
document.getElementById('checkButton').style.display = 'flex';
document.getElementById('hintButton').style.display = 'flex';
// Speak the word
setTimeout(() => this.speakWord(), 500);
// Update feedback
document.getElementById('aiFeedback').textContent = `New word! Listen carefully and spell it correctly. Difficulty: ${this.state.difficulty}`;
return true;
} else {
this.endSession();
return false;
}
}
nextWord() {
this.state.currentWordIndex++;
this.getNewWord();
}
endSession() {
this.state.sessionActive = false;
this.state.sessionStats.sessionDuration = Date.now() - this.state.sessionStats.startTime;
const accuracy = this.state.sessionStats.totalAttempts > 0
? Math.round((this.state.sessionStats.correct / this.state.sessionStats.totalAttempts) * 100)
: 0;
// Update progress
if (accuracy > 80) {
this.state.levelProgress = Math.min(100, this.state.levelProgress + 10);
document.getElementById('progressFill').style.width = `${this.state.levelProgress}%`;
}
// Update UI
document.getElementById('currentWord').textContent = 'Session Complete!';
document.getElementById('wordHint').textContent = `Accuracy: ${accuracy}% | Words: ${this.state.sessionStats.correct}`;
document.getElementById('answerInput').value = '';
document.getElementById('aiFeedback').textContent = `Great job! You completed the session with ${accuracy}% accuracy. Ready for another challenge?`;
document.getElementById('nextButton').style.display = 'none';
document.getElementById('startSession').disabled = false;
document.getElementById('startSession').innerHTML = '<i class="fas fa-play"></i> Start Training Session';
// Add AI message
this.addAIMessage(`Session completed! You got ${this.state.sessionStats.correct} words correct with ${accuracy}% accuracy.`);
// Update stats
this.updateStats();
}
// ============================================================================
// SPELLING LOGIC
// ============================================================================
checkAnswer() {
const userInput = document.getElementById('answerInput').value.trim();
if (!userInput) return;
this.state.attempts++;
this.state.sessionStats.totalAttempts++;
const isCorrect = userInput.toLowerCase() === this.state.currentWord.word.toLowerCase();
if (isCorrect) {
this.handleCorrectAnswer();
} else {
this.handleIncorrectAnswer(userInput);
}
}
handleCorrectAnswer() {
this.state.isCorrect = true;
this.state.showNextButton = true;
this.state.sessionStats.correct++;
this.state.wordsMastered++;
// Update UI
document.getElementById('currentWord').textContent = this.state.currentWord.word;
document.getElementById('currentWord').className = 'word-display correct';
document.getElementById('answerInput').value = '';
document.getElementById('nextButton').style.display = 'flex';
document.getElementById('checkButton').style.display = 'none';
document.getElementById('hintButton').style.display = 'none';
// Calculate points
const basePoints = 10;
const hintPenalty = this.state.hintsUsed * 2;
const attemptPenalty = Math.max(0, this.state.attempts - 1) * 3;
const pointsEarned = Math.max(1, basePoints - hintPenalty - attemptPenalty);
// Update feedback
document.getElementById('aiFeedback').textContent = `✅ Excellent! "${this.state.currentWord.word}" is correct! `;
document.getElementById('aiFeedback').className = 'feedback-content correct';
if (this.state.attempts === 1 && this.state.hintsUsed === 0) {
document.getElementById('aiFeedback').textContent += `Perfect first try! +${pointsEarned} points!`;
} else {
document.getElementById('aiFeedback').textContent += `You used ${this.state.hintsUsed} hint(s) and ${this.state.attempts} attempt(s). +${pointsEarned} points!`;
}
// Add AI chat message
this.addAIMessage(`Correct! "${this.state.currentWord.word}" is spelled correctly. Great job!`);
// Play success sound
this.playSuccessSound();
// Update stats
this.updateStats();
// Adaptive learning: adjust difficulty based on performance
if (this.state.attempts === 1 && this.state.hintsUsed === 0) {
this.considerDifficultyIncrease();
}
}
handleIncorrectAnswer(userInput) {
this.state.sessionStats.incorrect++;
// Show incorrect feedback
document.getElementById('currentWord').className = 'word-display incorrect';
document.getElementById('aiFeedback').textContent = `❌ Not quite. "${userInput}" is incorrect. Try again!`;
document.getElementById('aiFeedback').className = 'feedback-content incorrect';
// Add AI chat message
this.addAIMessage(`Incorrect attempt for "${this.state.currentWord.word}". Try again or ask for a hint!`);
// Give progressive hints
if (this.state.attempts === 2) {
this.giveHint();
} else if (this.state.attempts === 3) {
this.revealFirstLetter();
}
// Adaptive learning: consider difficulty decrease if struggling
if (this.state.attempts >= 3) {
this.considerDifficultyDecrease();
}
}
giveHint() {
if (!this.state.currentWord || this.state.isCorrect) return;
this.state.hintsUsed++;
this.state.sessionStats.totalHints++;
// Show phonetic hint
if (this.state.hintsUsed === 1) {
document.getElementById('wordHint').textContent = `Phonetic: ${this.state.currentWord.phonetic}`;
this.addAIMessage(`Hint: The word sounds like "${this.state.currentWord.phonetic}"`);
}
// Show context hint
else if (this.state.hintsUsed === 2) {
document.getElementById('wordHint').textContent += ` | Context: ${this.state.currentWord.context}`;
this.addAIMessage(`Context: ${this.state.currentWord.context}`);
}
// Show first letter
else if (this.state.hintsUsed === 3) {
this.revealFirstLetter();
}
}
revealFirstLetter() {
if (!this.state.currentWord) return;
const word = this.state.currentWord.word;
const displayed = document.getElementById('currentWord').textContent;
const firstLetter = word[0];
// Update display to show first letter
let newDisplay = firstLetter;
for (let i = 1; i < word.length; i++) {
newDisplay += displayed[i] === '_' ? '_' : displayed[i];
}
document.getElementById('currentWord').textContent = newDisplay;
this.addAIMessage(`First letter revealed: "${firstLetter}"`);
}
// ============================================================================
// SPEECH SYNTHESIS
// ============================================================================
speakText(text, rate = 1.0, pitch = 1.0) {
if (!this.synth) return;
// Stop any current speech
this.synth.cancel();
const utterance = new SpeechSynthesisUtterance(text);
// Try to find the selected voice
if (this.voices.length > 0) {
const selectedVoice = this.voices.find(voice =>
voice.name.includes(this.state.currentVoice) ||
voice.lang.includes(this.state.currentVoice.split('-').slice(0, 2).join('-'))
);
if (selectedVoice) {
utterance.voice = selectedVoice;
}
}
utterance.rate = rate;
utterance.pitch = pitch;
utterance.volume = 1.0;
this.currentUtterance = utterance;
this.synth.speak(utterance);
}
speakWord() {
if (!this.state.currentWord) return;
this.speakText(this.state.currentWord.word, 0.8, 1.0);
// Add visual feedback
const wordDisplay = document.getElementById('currentWord');
const originalText = wordDisplay.textContent;
wordDisplay.style.color = '#5a6cff';
setTimeout(() => {
wordDisplay.style.color = '';
}, 1000);
}
spellWord() {
if (!this.state.currentWord) return;
const word = this.state.currentWord.word.toUpperCase();
const letters = word.split('');
const spelled = letters.join('. ') + '.';
this.speakText(spelled, 0.5, 1.1);
// Visual spelling display
let display = '';
let i = 0;
const spellInterval = setInterval(() => {
if (i < word.length) {
display = word.substring(0, i + 1) + '_'.repeat(word.length - i - 1);
document.getElementById('currentWord').textContent = display;
i++;
} else {
clearInterval(spellInterval);
setTimeout(() => {
document.getElementById('currentWord').textContent = '_'.repeat(word.length);
}, 1000);
}
}, 500);
}
speakContext() {
if (!this.state.currentWord || !this.state.currentWord.context) return;
this.speakText(this.state.currentWord.context, 0.9, 1.0);
// Highlight context in feedback
document.getElementById('aiFeedback').textContent = `Context: ${this.state.currentWord.context}`;
setTimeout(() => {
if (!this.state.isCorrect) {
document.getElementById('aiFeedback').textContent = 'Try spelling the word from the context clue!';
}
}, 3000);
}
repeatWord() {
this.speakWord();
}
playSuccessSound() {
// Create a simple success tone using Web Audio API
try {
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.setValueAtTime(523.25, audioContext.currentTime); // C5
oscillator.frequency.setValueAtTime(659.25, audioContext.currentTime + 0.1); // E5
oscillator.frequency.setValueAtTime(783.99, audioContext.currentTime + 0.2); // G5
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.5);
} catch (e) {
console.log('Web Audio API not supported');
}
}
// ============================================================================
// ADAPTIVE LEARNING AI
// ============================================================================
considerDifficultyIncrease() {
// Check if user has perfect streak
const perfectStreak = this.getPerfectStreak();
if (perfectStreak >= 3) {
const currentLevel = this.state.difficulty;
const nextLevel = this.getNextDifficultyLevel(currentLevel);
if (nextLevel) {
this.addAIMessage(`🎯 Perfect streak detected! Advancing to ${nextLevel} level for next session.`);
this.state.difficulty = nextLevel;
// Update UI
document.querySelectorAll('[data-level]').forEach(btn => {
btn.classList.toggle('active', btn.dataset.level === nextLevel);
});
}
}
}
considerDifficultyDecrease() {
// Check if user is struggling
const recentAccuracy = this.getRecentAccuracy();
if (recentAccuracy < 50) {
const currentLevel = this.state.difficulty;
const prevLevel = this.getPreviousDifficultyLevel(currentLevel);
if (prevLevel) {
this.addAIMessage(`I notice you're finding this challenging. Let's try ${prevLevel} level for better learning.`);
this.state.difficulty = prevLevel;
// Update UI
document.querySelectorAll('[data-level]').forEach(btn => {
btn.classList.toggle('active', btn.dataset.level === prevLevel);
});
}
}
}
getPerfectStreak() {
// Simplified - in real implementation, track actual streak
return this.state.sessionStats.correct;
}
getRecentAccuracy() {
if (this.state.sessionStats.totalAttempts === 0) return 100;
return (this.state.sessionStats.correct / this.state.sessionStats.totalAttempts) * 100;
}
getNextDifficultyLevel(current) {
const levels = ['beginner', 'intermediate', 'advanced', 'expert'];
const currentIndex = levels.indexOf(current);
return currentIndex < levels.length - 1 ? levels[currentIndex + 1] : null;
}
getPreviousDifficultyLevel(current) {
const levels = ['beginner', 'intermediate', 'advanced', 'expert'];
const currentIndex = levels.indexOf(current);
return currentIndex > 0 ? levels[currentIndex - 1] : null;
}
// ============================================================================
// CHAT AI FUNCTIONALITY
// ============================================================================
addAIMessage(text) {
const chatMessages = document.getElementById('chatMessages');
const typingIndicator = document.getElementById('typingIndicator');
if (typingIndicator.style.display !== 'none') {
typingIndicator.style.display = 'none';
}
const messageDiv = document.createElement('div');
messageDiv.className = 'message message-ai';
messageDiv.textContent = text;
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
addUserMessage(text) {
const chatMessages = document.getElementById('chatMessages');
const typingIndicator = document.getElementById('typingIndicator');
if (typingIndicator.style.display !== 'none') {
typingIndicator.style.display = 'none';
}
const messageDiv = document.createElement('div');
messageDiv.className = 'message message-user';
messageDiv.textContent = text;
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
showTypingIndicator() {
const typingIndicator = document.getElementById('typingIndicator');
typingIndicator.style.display = 'flex';
const chatMessages = document.getElementById('chatMessages');
chatMessages.scrollTop = chatMessages.scrollHeight;
}
hideTypingIndicator() {
const typingIndicator = document.getElementById('typingIndicator');
typingIndicator.style.display = 'none';
}
sendChatMessage() {
const chatInput = document.getElementById('chatInput');
const message = chatInput.value.trim();
if (!message) return;
// Add user message
this.addUserMessage(message);
// Clear input
chatInput.value = '';
// Show typing indicator
this.showTypingIndicator();
// AI response with delay
setTimeout(() => {
this.hideTypingIndicator();
this.generateAIResponse(message);
}, 1000 + Math.random() * 1000);
}
generateAIResponse(userMessage) {
const lowerMessage = userMessage.toLowerCase();
let response = '';
// Simple AI response logic - in production, connect to actual AI API
if (lowerMessage.includes('help') || lowerMessage.includes('how')) {
response = "I'm here to help you improve your spelling! Listen to the word, type it correctly, and I'll give you feedback. Use hints if you need help!";
} else if (lowerMessage.includes('difficulty') || lowerMessage.includes('hard') || lowerMessage.includes('easy')) {
response = "I automatically adjust difficulty based on your performance. Get words correct on the first try to advance levels!";
} else if (lowerMessage.includes('score') || lowerMessage.includes('points')) {
response = `Your current stats: ${this.state.wordsMastered} words mastered, ${this.state.currentStreak} day streak, Level ${Math.floor(this.state.levelProgress/25)+1}.`;
} else if (lowerMessage.includes('hint') || lowerMessage.includes('clue')) {
response = "Click the 'Get Hint' button for phonetic clues, context sentences, or letter reveals. Don't overuse hints for maximum points!";
} else if (lowerMessage.includes('current word') || lowerMessage.includes('what word')) {
if (this.state.currentWord) {
response = `The current word is "${this.state.currentWord.word}". Listen carefully and try to spell it!`;
} else {
response = "Start a training session to get your first word!";
}
} else if (lowerMessage.includes('thank')) {
response = "You're welcome! Keep practicing to become a spelling champion! 🏆";
} else {
response = this.getRandomAIResponse();
}
this.addAIMessage(response);
// Optional: Speak the response
if (this.state.sessionActive) {
this.speakText(response, 0.9, 1.0);
}
}
getRandomAIResponse() {
const responses = [
"Great question! Focus on listening carefully to each word. The phonetic clues can help if you're stuck.",
"Remember, spelling improves with practice. Each word you master builds your vocabulary!",
"I'm tracking your progress and will adjust the difficulty to match your skill level.",
"Try to spell words without hints for maximum points. But don't hesitate to use hints if you need them!",
"Pay attention to vowel sounds and silent letters - they're often the trickiest parts of spelling.",
"Consistent practice is key to spelling mastery. Even 10 minutes a day makes a big difference!"
];
return responses[Math.floor(Math.random() * responses.length)];
}
toggleVoiceInput() {
const voiceBtn = document.getElementById('voiceButton');
const isListening = voiceBtn.classList.contains('listening');
if (!isListening) {
// Start listening
voiceBtn.classList.add('listening');
voiceBtn.innerHTML = '<i class="fas fa-stop"></i>';
this.startVoiceRecognition();
} else {
// Stop listening
voiceBtn.classList.remove('listening');
voiceBtn.innerHTML = '<i class="fas fa-microphone"></i>';
this.stopVoiceRecognition();
}
}
startVoiceRecognition() {
if ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window) {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
this.recognition = new SpeechRecognition();
this.recognition.continuous = false;
this.recognition.interimResults = false;
this.recognition.lang = 'en-US';
this.recognition.onresult = (event) => {
const transcript = event.results[0][0].transcript;
document.getElementById('answerInput').value = transcript;
// Auto-check if in spelling mode
if (this.state.sessionActive && !this.state.isCorrect) {
setTimeout(() => this.checkAnswer(), 500);
}
};
this.recognition.onerror = (event) => {
console.log('Speech recognition error:', event.error);
};
this.recognition.start();
} else {
alert('Speech recognition not supported in this browser. Try Chrome or Edge.');
}
}
stopVoiceRecognition() {
if (this.recognition) {
this.recognition.stop();
}
}
// ============================================================================
// UI SETTINGS
// ============================================================================
setDifficulty(level) {
this.state.difficulty = level;
// Update UI
document.querySelectorAll('[data-level]').forEach(btn => {
btn.classList.toggle('active', btn.dataset.level === level);
});
this.addAIMessage(`Difficulty set to ${level} level. Words will match this skill level.`);
}
setTrainingMode(mode) {
this.state.trainingMode = mode;
// Update UI
document.querySelectorAll('[data-mode]').forEach(btn => {
btn.classList.toggle('active', btn.dataset.mode === mode);
});
const modeDescriptions = {
'adaptive': 'AI adapts difficulty in real-time',
'practice': 'Random words for general practice',
'challenge': 'Time-limited spelling challenges',
'time-trial': 'Race against the clock'
};
this.addAIMessage(`Training mode set to ${mode}. ${modeDescriptions[mode]}`);
}
setVoice(voice) {
this.state.currentVoice = voice;
// Update UI
document.querySelectorAll('[data-voice]').forEach(btn => {
btn.classList.toggle('active', btn.dataset.voice === voice);
});
// Test the voice
this.speakText('Voice updated', 0.9, 1.0);
}
updateStats() {
document.getElementById('wordsMastered').textContent = this.state.wordsMastered;
document.getElementById('streakCount').textContent = this.state.currentStreak;
// Update progress bar
document.getElementById('progressFill').style.width = `${this.state.levelProgress}%`;
// Update sidebar progress
const progressContainer = document.querySelector('.progress-stats');
const level = Math.floor(this.state.levelProgress / 25) + 1;
progressContainer.innerHTML = `<span>Level ${level}</span><span>${this.state.levelProgress}%</span>`;
}
// ============================================================================
// UTILITY FUNCTIONS
// ============================================================================
shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
}
// ============================================================================
// INITIALIZE APPLICATION
// ============================================================================
// Start the AI Spelling Tutor when page loads
document.addEventListener('DOMContentLoaded', () => {
window.spellingTutor = new AISpellingTutor();
// Add keyboard shortcuts
document.addEventListener('keydown', (e) => {
// Ctrl + Space to hear word
if (e.ctrlKey && e.code === 'Space') {
e.preventDefault();
window.spellingTutor.speakWord();
}
// Ctrl + Enter to check answer
if (e.ctrlKey && e.key === 'Enter') {
e.preventDefault();
window.spellingTutor.checkAnswer();
}
// Ctrl + H for hint
if (e.ctrlKey && e.key === 'h') {
e.preventDefault();
window.spellingTutor.giveHint();
}
// Ctrl + N for next word (when available)
if (e.ctrlKey && e.key === 'n') {
e.preventDefault();
if (window.spellingTutor.state.showNextButton) {
window.spellingTutor.nextWord();
}
}
});
// Instructions tooltip
setTimeout(() => {
if (window.spellingTutor) {
window.spellingTutor.addAIMessage('💡 Tip: Use Ctrl+Space to hear the word, Ctrl+Enter to check your answer!');
}
}, 3000);
});
// Handle window resize
window.addEventListener('resize', () => {
if (window.spellingTutor && window.spellingTutor.onWindowResize) {
window.spellingTutor.onWindowResize();
}
});
</script>
</body>
</html>