mlmihjaz commited on
Commit
3071b2e
·
verified ·
1 Parent(s): 9c109bf

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +774 -470
index.html CHANGED
@@ -4,12 +4,12 @@
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>AlphaPop & Chat - Interactive Learning</title>
8
 
9
  <!-- Import Google Fonts -->
10
  <link rel="preconnect" href="https://fonts.googleapis.com">
11
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12
- <link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;600;700&family=Nunito:wght@400;700&display=swap"
13
  rel="stylesheet">
14
 
15
  <!-- FontAwesome for Icons -->
@@ -17,21 +17,39 @@
17
 
18
  <style>
19
  :root {
20
- --primary-color: #6C63FF;
21
- --secondary-color: #FF6584;
22
- --accent-color: #43D9AD;
23
- --bg-gradient: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
24
- --glass-bg: rgba(255, 255, 255, 0.9);
25
- --glass-border: rgba(255, 255, 255, 0.5);
26
- --text-dark: #2D3436;
27
- --shadow-lg: 0 10px 30px rgba(0, 0, 0, 0.15);
28
- --chat-bg: #ffffff;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  }
30
 
31
  * {
32
  box-sizing: border-box;
33
  margin: 0;
34
  padding: 0;
 
35
  }
36
 
37
  body {
@@ -41,28 +59,36 @@
41
  display: flex;
42
  flex-direction: column;
43
  overflow: hidden;
44
- color: var(--text-dark);
45
  }
46
 
47
- /* Header Section */
48
  header {
49
- padding: 1rem 2rem;
50
  display: flex;
51
  justify-content: space-between;
52
  align-items: center;
53
- background: rgba(255, 255, 255, 0.95);
54
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
55
  z-index: 100;
 
56
  }
57
 
58
  .logo {
59
  font-family: 'Fredoka', sans-serif;
60
- font-size: 1.5rem;
61
  font-weight: 700;
62
- color: var(--primary-color);
63
  display: flex;
64
  align-items: center;
65
- gap: 10px;
 
 
 
 
 
 
 
66
  }
67
 
68
  .header-actions {
@@ -71,191 +97,310 @@
71
  align-items: center;
72
  }
73
 
74
- .chat-trigger {
75
- background: var(--primary-color);
76
- color: white;
77
  border: none;
78
- width: 40px;
79
- height: 40px;
80
  border-radius: 50%;
81
  cursor: pointer;
82
  display: flex;
83
  justify-content: center;
84
  align-items: center;
85
- transition: transform 0.2s;
86
- box-shadow: 0 4px 10px rgba(108, 99, 255, 0.3);
 
87
  }
88
 
89
- .chat-trigger:hover {
90
- transform: scale(1.1);
 
 
 
91
  }
92
 
93
- .anycoder-link {
94
- font-size: 0.9rem;
95
- font-weight: 600;
96
- color: var(--text-dark);
97
  text-decoration: none;
98
- padding: 0.5rem 1rem;
99
- background: #f0f0f0;
100
- border-radius: 20px;
101
- transition: all 0.3s ease;
 
 
 
 
102
  }
103
 
104
- .anycoder-link:hover {
105
- background: var(--primary-color);
106
- color: white;
107
  transform: translateY(-2px);
108
  }
109
 
110
- /* Main Game Area */
111
  main {
112
  flex: 1;
113
  display: flex;
114
- flex-direction: column;
115
  justify-content: center;
116
  align-items: center;
117
  position: relative;
118
  padding: 1rem;
119
  }
120
 
121
- /* Game Container */
122
  .game-board {
123
- background: var(--glass-bg);
124
- backdrop-filter: blur(12px);
125
- -webkit-backdrop-filter: blur(12px);
126
- border: 1px solid var(--glass-border);
127
- border-radius: 30px;
128
- padding: 2rem;
129
- width: 90%;
130
- max-width: 600px;
131
  box-shadow: var(--shadow-lg);
132
  text-align: center;
133
- display: flex;
134
- flex-direction: column;
135
- align-items: center;
136
- min-height: 500px;
137
- justify-content: space-between;
138
  transition: transform 0.3s ease, filter 0.3s ease;
139
  }
140
 
141
  .game-board.blurred {
142
- filter: blur(5px);
143
  pointer-events: none;
144
  }
145
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  /* Progress Bar */
147
- .progress-container {
148
  width: 100%;
149
- height: 10px;
150
- background: #e0e0e0;
151
- border-radius: 10px;
152
  margin-bottom: 2rem;
 
 
 
 
 
 
 
153
  overflow: hidden;
154
  }
155
 
156
- .progress-bar {
157
  height: 100%;
158
  width: 0%;
159
- background: linear-gradient(90deg, var(--secondary-color), var(--primary-color));
160
  border-radius: 10px;
161
- transition: width 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
162
  }
163
 
164
- /* Letter Display */
165
- .letter-display {
 
 
 
 
 
 
 
 
 
 
166
  font-family: 'Fredoka', sans-serif;
167
- font-size: 10rem;
168
  font-weight: 700;
169
- color: var(--primary-color);
170
- text-shadow: 4px 4px 0px rgba(0, 0, 0, 0.1);
171
- cursor: default;
172
- user-select: none;
173
- position: relative;
174
- z-index: 2;
175
  transition: color 0.3s;
176
  }
177
 
178
- /* Image Container */
179
- .image-container {
180
- width: 180px;
181
- height: 180px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  border-radius: 20px;
183
  overflow: hidden;
184
  background: #fff;
185
- box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.05);
186
  border: 4px solid white;
187
- display: flex;
188
- justify-content: center;
189
- align-items: center;
190
  opacity: 0;
191
- transform: scale(0.8);
192
- transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
193
- margin-top: 1rem;
194
  }
195
 
196
- .image-container.visible {
197
  opacity: 1;
198
  transform: scale(1);
199
  }
200
 
201
- .image-container img {
202
  width: 100%;
203
  height: 100%;
204
  object-fit: cover;
205
  }
206
 
207
- /* Status Text */
208
- .status-text {
209
- font-size: 1.2rem;
210
- color: #636e72;
211
- margin-top: 1rem;
212
- font-weight: 600;
 
213
  }
214
 
215
- .hint-text {
216
- font-size: 0.9rem;
217
- color: #b2bec3;
218
- margin-top: 0.5rem;
219
  }
220
 
221
  /* Buttons */
222
- .controls {
223
- margin-top: 2rem;
224
- }
225
-
226
- .btn {
227
- background: var(--primary-color);
228
  color: white;
229
  border: none;
230
- padding: 1rem 2.5rem;
231
- font-size: 1.2rem;
232
- border-radius: 50px;
233
  cursor: pointer;
234
  font-family: 'Fredoka', sans-serif;
235
- box-shadow: 0 5px 15px rgba(108, 99, 255, 0.4);
236
- transition: all 0.2s ease;
 
237
  display: inline-flex;
238
  align-items: center;
239
  gap: 10px;
240
  }
241
 
242
- .btn:hover {
 
243
  transform: translateY(-3px);
244
- box-shadow: 0 8px 20px rgba(108, 99, 255, 0.5);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  }
246
 
247
- .btn:active {
248
- transform: translateY(1px);
 
 
 
 
 
 
249
  }
250
 
251
- /* --- CHAT UI STYLES --- */
252
- .chat-overlay {
 
 
 
 
253
  position: fixed;
254
  top: 0;
255
  left: 0;
256
  width: 100%;
257
  height: 100%;
258
- background: rgba(0, 0, 0, 0.4);
259
  z-index: 200;
260
  display: flex;
261
  justify-content: center;
@@ -265,39 +410,39 @@
265
  transition: all 0.3s ease;
266
  }
267
 
268
- .chat-overlay.active {
269
  opacity: 1;
270
  visibility: visible;
271
  }
272
 
273
- .chat-window {
274
  width: 90%;
275
  max-width: 500px;
276
- height: 70vh;
277
  background: white;
278
- border-radius: 20px;
279
- box-shadow: 0 20px 50px rgba(0, 0, 0, 0.2);
280
  display: flex;
281
  flex-direction: column;
282
  overflow: hidden;
283
- transform: translateY(50px);
284
- transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
285
  }
286
 
287
- .chat-overlay.active .chat-window {
288
  transform: translateY(0);
289
  }
290
 
291
- .chat-header {
292
- background: var(--primary-color);
293
- color: white;
294
- padding: 1rem;
295
  display: flex;
296
- align-items: center;
297
  justify-content: space-between;
 
 
298
  }
299
 
300
- .chat-header h3 {
301
  font-family: 'Fredoka', sans-serif;
302
  display: flex;
303
  align-items: center;
@@ -308,57 +453,53 @@
308
  background: none;
309
  border: none;
310
  color: white;
311
- font-size: 1.2rem;
312
  cursor: pointer;
313
  opacity: 0.8;
314
  }
315
 
316
- .close-chat:hover {
317
- opacity: 1;
318
- }
319
-
320
- .chat-messages {
321
  flex: 1;
322
- padding: 1rem;
323
  overflow-y: auto;
324
- background: #f9f9f9;
325
  display: flex;
326
  flex-direction: column;
327
- gap: 10px;
328
  }
329
 
330
- .message {
331
- max-width: 80%;
332
- padding: 10px 15px;
333
- border-radius: 15px;
334
  font-size: 0.95rem;
335
- line-height: 1.4;
336
  position: relative;
337
- animation: slideUp 0.3s ease;
338
  }
339
 
340
- @keyframes slideUp {
341
- from { transform: translateY(10px); opacity: 0; }
342
- to { transform: translateY(0); opacity: 1; }
343
  }
344
 
345
- .message.bot {
346
  background: white;
347
- color: var(--text-dark);
348
- border-bottom-left-radius: 2px;
349
  align-self: flex-start;
350
  box-shadow: 0 2px 5px rgba(0,0,0,0.05);
351
  }
352
 
353
- .message.user {
354
- background: var(--primary-color);
355
  color: white;
356
- border-bottom-right-radius: 2px;
357
  align-self: flex-end;
358
  box-shadow: 0 2px 5px rgba(108, 99, 255, 0.2);
359
  }
360
 
361
- .chat-input-area {
362
  padding: 1rem;
363
  background: white;
364
  border-top: 1px solid #eee;
@@ -366,27 +507,27 @@
366
  gap: 10px;
367
  }
368
 
369
- .chat-input-area input {
370
  flex: 1;
371
- padding: 10px 15px;
372
  border: 2px solid #eee;
373
- border-radius: 25px;
374
  outline: none;
375
  font-family: 'Nunito', sans-serif;
376
  transition: border-color 0.2s;
377
  }
378
 
379
- .chat-input-area input:focus {
380
- border-color: var(--primary-color);
381
  }
382
 
383
  .send-btn {
384
- background: var(--primary-color);
385
- color: white;
386
- border: none;
387
- width: 40px;
388
- height: 40px;
389
  border-radius: 50%;
 
 
 
390
  cursor: pointer;
391
  display: flex;
392
  justify-content: center;
@@ -395,33 +536,11 @@
395
  }
396
 
397
  .send-btn:hover {
398
- background: var(--secondary-color);
399
- }
400
-
401
- /* Animations */
402
- @keyframes popIn {
403
- 0% { transform: scale(0); opacity: 0; }
404
- 60% { transform: scale(1.2); opacity: 1; }
405
- 100% { transform: scale(1); opacity: 1; }
406
- }
407
-
408
- @keyframes shake {
409
- 0%, 100% { transform: translateX(0); }
410
- 25% { transform: translateX(-10px) rotate(-5deg); color: var(--secondary-color); }
411
- 75% { transform: translateX(10px) rotate(5deg); color: var(--secondary-color); }
412
- }
413
-
414
- @keyframes float {
415
- 0%, 100% { transform: translateY(0px); }
416
- 50% { transform: translateY(-10px); }
417
  }
418
 
419
- .anim-pop { animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; }
420
- .anim-shake { animation: shake 0.4s ease-in-out; }
421
- .anim-float { animation: float 3s ease-in-out infinite; }
422
-
423
- /* Confetti Canvas */
424
- #confetti-canvas {
425
  position: absolute;
426
  top: 0;
427
  left: 0;
@@ -431,17 +550,30 @@
431
  z-index: 50;
432
  }
433
 
434
- /* Responsive */
435
- @media (max-width: 768px) {
436
- .letter-display { font-size: 7rem; }
437
- .game-board { width: 95%; padding: 1.5rem; }
438
- .image-container { width: 140px; height: 140px; }
 
 
 
 
439
  }
440
 
441
- @media (max-width: 480px) {
442
- .letter-display { font-size: 5rem; }
443
- .header-actions .anycoder-link span { display: none; }
444
- .header-actions .anycoder-link { padding: 0.5rem; }
 
 
 
 
 
 
 
 
 
445
  }
446
  </style>
447
  </head>
@@ -449,350 +581,522 @@
449
  <body>
450
 
451
  <header>
452
- <div class="logo">
453
- <i class="fa-solid fa-shapes"></i>
454
  <span>AlphaPop</span>
455
- </div>
456
  <div class="header-actions">
457
- <button class="chat-trigger" onclick="toggleChat()" title="Talk to me">
458
  <i class="fa-solid fa-comment-dots"></i>
459
  </button>
460
- <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
461
- <span>Built with anycoder</span>
462
  </a>
463
  </div>
464
  </header>
465
 
466
  <main>
467
- <canvas id="confetti-canvas"></canvas>
468
 
469
  <div class="game-board" id="gameBoard">
470
- <!-- Progress -->
471
- <div class="progress-container">
472
- <div class="progress-bar" id="progressBar"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
  </div>
474
 
475
- <!-- Game Area -->
476
- <div id="gameArea" style="display: none; flex-direction: column; align-items: center; width: 100%;">
477
- <div class="letter-display anim-pop" id="letterDisplay">A</div>
478
- <div class="image-container" id="imageContainer">
479
- <img id="letterImage" src="" alt="Letter Image">
 
 
 
480
  </div>
481
- <div class="status-text" id="statusText">Press the 'A' key!</div>
482
- <div class="hint-text"><i class="fa-solid fa-volume-high"></i> Sound On</div>
483
- </div>
484
 
485
- <!-- Start Screen -->
486
- <div id="startScreen" style="text-align: center;">
487
- <div class="logo" style="justify-content: center; font-size: 3rem; margin-bottom: 1rem; color: var(--primary-color);">
488
- <i class="fa-solid fa-keyboard"></i>
489
  </div>
490
- <h2 style="margin-bottom: 1rem; font-size: 1.8rem;">Ready to type?</h2>
491
- <p style="margin-bottom: 2rem; color: #636e72;">Press the matching key to hear the sound and see the picture!</p>
492
- <button class="btn" onclick="startGame()">Start Game <i class="fa-solid fa-play"></i></button>
493
- <div style="margin-top: 10px;">
494
- <button class="btn" style="background: transparent; color: var(--primary-color); box-shadow: none; border: 2px solid var(--primary-color); font-size: 1rem; padding: 0.8rem 1.5rem;" onclick="toggleChat()">
495
- <i class="fa-solid fa-comments"></i> Talk to Me First
496
- </button>
 
 
 
 
 
 
 
 
 
 
 
497
  </div>
 
 
 
498
  </div>
499
 
500
  <!-- End Screen -->
501
- <div id="endScreen" style="display: none; text-align: center;">
502
- <i class="fa-solid fa-trophy" style="font-size: 4rem; color: #f1c40f; margin-bottom: 1rem; animation: float 2s infinite;"></i>
503
- <h2 style="margin-bottom: 1rem; font-size: 2rem;">Great Job!</h2>
504
- <p style="margin-bottom: 2rem; color: #636e72;">You completed the alphabet.</p>
505
- <button class="btn" onclick="startGame()">Play Again <i class="fa-solid fa-rotate-right"></i></button>
 
 
 
506
  </div>
 
507
  </div>
508
  </main>
509
 
510
- <!-- Chat Interface Overlay -->
511
- <div class="chat-overlay" id="chatOverlay">
512
- <div class="chat-window">
513
- <div class="chat-header">
514
  <h3><i class="fa-solid fa-robot"></i> AlphaBot</h3>
515
- <button class="close-chat" onclick="toggleChat()"><i class="fa-solid fa-xmark"></i></button>
516
  </div>
517
- <div class="chat-messages" id="chatMessages">
518
- <div class="message bot">Hello! I'm AlphaBot. I can talk to you! Try saying "Hello" or ask me about the game.</div>
519
  </div>
520
- <div class="chat-input-area">
521
- <input type="text" id="chatInput" placeholder="Type a message..." onkeypress="handleChatEnter(event)">
522
- <button class="send-btn" onclick="sendMessage()"><i class="fa-solid fa-paper-plane"></i></button>
523
  </div>
524
  </div>
525
  </div>
526
 
527
  <script>
528
- // --- Game Configuration & State ---
529
- const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('');
530
- let currentIndex = 0;
531
- let isGameActive = false;
532
- let isChatOpen = false;
533
-
534
- // DOM Elements
535
- const startScreen = document.getElementById('startScreen');
536
- const endScreen = document.getElementById('endScreen');
537
- const gameArea = document.getElementById('gameArea');
538
- const gameBoard = document.getElementById('gameBoard');
539
- const letterDisplay = document.getElementById('letterDisplay');
540
- const statusText = document.getElementById('statusText');
541
- const imageContainer = document.getElementById('imageContainer');
542
- const letterImage = document.getElementById('letterImage');
543
- const progressBar = document.getElementById('progressBar');
544
-
545
- // Chat Elements
546
- const chatOverlay = document.getElementById('chatOverlay');
547
- const chatMessages = document.getElementById('chatMessages');
548
- const chatInput = document.getElementById('chatInput');
549
-
550
- // --- Chat Logic ---
551
- function toggleChat() {
552
- isChatOpen = !isChatOpen;
553
- if (isChatOpen) {
554
- chatOverlay.classList.add('active');
555
- gameBoard.classList.add('blurred');
556
- chatInput.focus();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
557
  } else {
558
- chatOverlay.classList.remove('active');
559
- gameBoard.classList.remove('blurred');
560
- // Return focus to game if active
561
- if(isGameActive) gameBoard.focus();
562
  }
563
- }
564
-
565
- function handleChatEnter(e) {
566
- if (e.key === 'Enter') sendMessage();
567
- }
568
 
569
- function sendMessage() {
570
- const text = chatInput.value.trim();
571
- if (!text) return;
572
-
573
- // Add User Message
574
- addMessage(text, 'user');
575
- chatInput.value = '';
576
-
577
- // Generate Bot Response
578
- const reply = getBotResponse(text);
579
 
580
- // Simulate typing delay
581
- setTimeout(() => {
582
- addMessage(reply, 'bot');
583
- speakText(reply); // Speak the reply
584
- }, 600);
585
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
586
 
587
- function addMessage(text, sender) {
588
- const div = document.createElement('div');
589
- div.className = `message ${sender}`;
590
- div.textContent = text;
591
- chatMessages.appendChild(div);
592
- chatMessages.scrollTop = chatMessages.scrollHeight;
593
- }
594
 
595
- function getBotResponse(input) {
596
- const lower = input.toLowerCase();
 
597
 
598
- if (lower.includes('hello') || lower.includes('hi')) {
599
- return "Hi there! Are you ready to learn the alphabet?";
600
- } else if (lower.includes('play') || lower.includes('game')) {
601
- return "Close this chat and click 'Start Game' to begin! You can also type letters like 'A' or 'B' here to hear them.";
602
- } else if (lower.includes('name')) {
603
- return "I am AlphaBot, your friendly coding assistant.";
604
- } else if (lower.includes('help')) {
605
- return "I can help you practice letters. Just type a letter, or close the chat to play the typing game.";
606
- } else if (/^[a-z]$/.test(lower)) {
607
- // If user types a single letter
608
- return `You typed ${input.toUpperCase()}. Good job!`;
609
- } else {
610
- const randomReplies = [
611
- "That's interesting!",
612
- "Tell me more!",
613
- "I'm listening.",
614
- "Can you teach me a new word?",
615
- "Let's get back to learning soon!"
616
- ];
617
- return randomReplies[Math.floor(Math.random() * randomReplies.length)];
618
  }
619
- }
620
 
621
- // --- Speech Synthesis (Shared) ---
622
- function speakText(text) {
623
- if ('speechSynthesis' in window) {
624
- window.speechSynthesis.cancel();
625
- const utterance = new SpeechSynthesisUtterance(text);
626
- utterance.lang = 'en-US';
627
- utterance.rate = 1.0;
628
- utterance.pitch = 1.0;
629
- window.speechSynthesis.speak(utterance);
630
  }
631
- }
632
 
633
- function speakLetter(letter) {
634
- speakText(letter); // Reuse the main speak function
635
- }
 
 
636
 
637
- // --- Game Logic ---
638
- function startGame() {
639
- currentIndex = 0;
640
- isGameActive = true;
641
-
642
- startScreen.style.display = 'none';
643
- endScreen.style.display = 'none';
644
- gameArea.style.display = 'flex';
645
 
646
- // Close chat if open
647
- if(isChatOpen) toggleChat();
648
 
649
- updateLevel();
650
- }
 
 
 
651
 
652
- function updateLevel() {
653
- if (currentIndex >= alphabet.length) {
654
- endGame();
655
- return;
656
  }
 
657
 
658
- const currentLetter = alphabet[currentIndex];
 
 
659
 
660
- // Reset Animations
661
- letterDisplay.classList.remove('anim-pop', 'anim-shake');
662
- void letterDisplay.offsetWidth;
663
- letterDisplay.classList.add('anim-pop');
664
-
665
- letterDisplay.textContent = currentLetter;
666
- statusText.textContent = `Press the '${currentLetter}' key!`;
667
- imageContainer.classList.remove('visible');
668
 
669
- const progress = (currentIndex / alphabet.length) * 100;
670
- progressBar.style.width = `${progress}%`;
 
 
 
 
 
 
 
 
 
 
 
 
 
671
 
672
- speakLetter(currentLetter);
673
- }
674
 
675
- function handleInput(e) {
676
- // If chat is open, don't process game keys
677
- if (isChatOpen) return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
678
 
679
- if (!isGameActive) return;
 
 
680
 
681
- const key = e.key.toUpperCase();
682
- const targetLetter = alphabet[currentIndex];
 
 
 
 
 
 
683
 
684
- if (!/^[A-Z]$/.test(key)) return;
 
 
 
685
 
686
- if (key === targetLetter) {
687
- onCorrectPress(targetLetter);
688
  } else {
689
- onWrongPress();
690
  }
691
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
692
 
693
- function onCorrectPress(letter) {
694
- speakLetter(letter);
695
-
696
- // Random Image Placeholder
697
- const randomId = Math.floor(Math.random() * 1000);
698
- const imgUrl = `https://picsum.photos/seed/${letter}${randomId}/300/300`;
699
- letterImage.src = imgUrl;
700
-
701
- letterImage.onload = () => {
702
- imageContainer.classList.add('visible');
703
- };
704
- if(letterImage.complete) imageContainer.classList.add('visible');
705
 
706
- letterDisplay.style.color = "var(--accent-color)";
707
- statusText.textContent = "Great!";
708
- statusText.style.color = "var(--accent-color)";
709
 
710
- fireConfetti(0.5);
 
 
711
 
 
712
  setTimeout(() => {
713
- currentIndex++;
714
- letterDisplay.style.color = "var(--primary-color)";
715
- statusText.style.color = "#636e72";
716
- updateLevel();
717
- }, 1500);
718
- }
719
-
720
- function onWrongPress() {
721
- letterDisplay.classList.remove('anim-shake');
722
- void letterDisplay.offsetWidth;
723
- letterDisplay.classList.add('anim-shake');
724
-
725
- statusText.textContent = "Oops, try again!";
726
- statusText.style.color = "var(--secondary-color)";
727
- speakLetter(alphabet[currentIndex]);
728
- }
729
-
730
- function endGame() {
731
- isGameActive = false;
732
- gameArea.style.display = 'none';
733
- endScreen.style.display = 'block';
734
- progressBar.style.width = '100%';
735
- fireConfetti(1.0);
736
- speakText("Great job! You finished the game!");
737
- }
738
-
739
- // Event Listeners
740
- window.addEventListener('keydown', handleInput);
741
-
742
- // --- Confetti Logic ---
743
- const canvas = document.getElementById('confetti-canvas');
744
- const ctx = canvas.getContext('2d');
745
- let particles = [];
746
 
747
- function resizeCanvas() {
748
- canvas.width = window.innerWidth;
749
- canvas.height = window.innerHeight;
750
- }
751
- window.addEventListener('resize', resizeCanvas);
752
- resizeCanvas();
 
753
 
754
- function fireConfetti(intensity = 1.0) {
755
- const particleCount = 100 * intensity;
756
- const colors = ['#FF6584', '#6C63FF', '#43D9AD', '#FFD93D', '#FF8C00'];
 
 
 
 
 
 
757
 
758
- for (let i = 0; i < particleCount; i++) {
759
- particles.push({
760
- x: canvas.width / 2,
761
- y: canvas.height / 2 + 50,
762
- vx: (Math.random() - 0.5) * 20 * intensity,
763
- vy: (Math.random() - 1) * 20 * intensity,
764
- size: Math.random() * 8 + 4,
765
- color: colors[Math.floor(Math.random() * colors.length)],
766
- life: 100,
767
- gravity: 0.5
768
- });
769
  }
770
- if(particles.length <= particleCount) requestAnimationFrame(updateConfetti);
771
- }
772
 
773
- function updateConfetti() {
774
- ctx.clearRect(0, 0, canvas.width, canvas.height);
775
-
776
- for (let i = 0; i < particles.length; i++) {
777
- let p = particles[i];
778
- p.x += p.vx;
779
- p.y += p.vy;
780
- p.vy += p.gravity;
781
- p.life--;
782
-
783
- ctx.fillStyle = p.color;
784
- ctx.beginPath();
785
- ctx.rect(p.x, p.y, p.size, p.size);
786
- ctx.fill();
 
 
 
 
 
 
 
 
787
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
788
 
789
- particles = particles.filter(p => p.life > 0);
790
-
791
- if (particles.length > 0) {
792
- requestAnimationFrame(updateConfetti);
 
 
 
 
 
 
 
793
  }
794
- }
795
- </script>
796
- </body>
797
 
798
- </html>
 
 
 
 
 
 
 
 
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>AlphaPop Adventure - Typing & Spelling</title>
8
 
9
  <!-- Import Google Fonts -->
10
  <link rel="preconnect" href="https://fonts.googleapis.com">
11
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12
+ <link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;600;700&family=Nunito:wght@400;600;800&display=swap"
13
  rel="stylesheet">
14
 
15
  <!-- FontAwesome for Icons -->
 
17
 
18
  <style>
19
  :root {
20
+ /* Palette */
21
+ --primary: #6C63FF;
22
+ --primary-dark: #5a52d5;
23
+ --secondary: #FF6584;
24
+ --accent: #43D9AD;
25
+ --accent-dark: #32b08b;
26
+ --warning: #FFD93D;
27
+ --dark: #2D3436;
28
+ --light: #f5f7fa;
29
+
30
+ /* Gradients & Backgrounds */
31
+ --bg-gradient: linear-gradient(135deg, #fdfbfb 0%, #ebedee 100%);
32
+ --header-gradient: linear-gradient(90deg, #ffffff 0%, #f0f2f5 100%);
33
+ --card-bg: rgba(255, 255, 255, 0.95);
34
+
35
+ /* Effects */
36
+ --shadow-sm: 0 4px 6px rgba(0, 0, 0, 0.05);
37
+ --shadow-lg: 0 15px 35px rgba(108, 99, 255, 0.15);
38
+ --glass-border: 1px solid rgba(255, 255, 255, 0.6);
39
+ --blur: blur(12px);
40
+ --radius-lg: 24px;
41
+ --radius-btn: 50px;
42
+
43
+ /* Transitions */
44
+ --trans-fast: 0.2s ease;
45
+ --trans-bounce: 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
46
  }
47
 
48
  * {
49
  box-sizing: border-box;
50
  margin: 0;
51
  padding: 0;
52
+ -webkit-tap-highlight-color: transparent;
53
  }
54
 
55
  body {
 
59
  display: flex;
60
  flex-direction: column;
61
  overflow: hidden;
62
+ color: var(--dark);
63
  }
64
 
65
+ /* --- Header --- */
66
  header {
67
+ padding: 0.8rem 2rem;
68
  display: flex;
69
  justify-content: space-between;
70
  align-items: center;
71
+ background: var(--header-gradient);
72
+ box-shadow: var(--shadow-sm);
73
  z-index: 100;
74
+ backdrop-filter: blur(5px);
75
  }
76
 
77
  .logo {
78
  font-family: 'Fredoka', sans-serif;
79
+ font-size: 1.6rem;
80
  font-weight: 700;
81
+ color: var(--primary);
82
  display: flex;
83
  align-items: center;
84
+ gap: 12px;
85
+ text-decoration: none;
86
+ }
87
+
88
+ .logo i {
89
+ background: rgba(108, 99, 255, 0.1);
90
+ padding: 10px;
91
+ border-radius: 12px;
92
  }
93
 
94
  .header-actions {
 
97
  align-items: center;
98
  }
99
 
100
+ .icon-btn {
101
+ background: white;
102
+ color: var(--primary);
103
  border: none;
104
+ width: 44px;
105
+ height: 44px;
106
  border-radius: 50%;
107
  cursor: pointer;
108
  display: flex;
109
  justify-content: center;
110
  align-items: center;
111
+ font-size: 1.1rem;
112
+ transition: var(--trans-fast);
113
+ box-shadow: var(--shadow-sm);
114
  }
115
 
116
+ .icon-btn:hover {
117
+ transform: translateY(-2px);
118
+ background: var(--primary);
119
+ color: white;
120
+ box-shadow: 0 5px 15px rgba(108, 99, 255, 0.3);
121
  }
122
 
123
+ .anycoder-badge {
124
+ font-size: 0.85rem;
125
+ font-weight: 700;
126
+ color: var(--dark);
127
  text-decoration: none;
128
+ padding: 0.5rem 1.2rem;
129
+ background: white;
130
+ border-radius: var(--radius-btn);
131
+ border: 2px solid #eee;
132
+ transition: var(--trans-fast);
133
+ display: flex;
134
+ align-items: center;
135
+ gap: 8px;
136
  }
137
 
138
+ .anycoder-badge:hover {
139
+ border-color: var(--primary);
140
+ color: var(--primary);
141
  transform: translateY(-2px);
142
  }
143
 
144
+ /* --- Main Layout --- */
145
  main {
146
  flex: 1;
147
  display: flex;
 
148
  justify-content: center;
149
  align-items: center;
150
  position: relative;
151
  padding: 1rem;
152
  }
153
 
154
+ /* --- Game Board --- */
155
  .game-board {
156
+ background: var(--card-bg);
157
+ backdrop-filter: var(--blur);
158
+ -webkit-backdrop-filter: var(--blur);
159
+ border: var(--glass-border);
160
+ border-radius: var(--radius-lg);
161
+ padding: 2.5rem;
162
+ width: 95%;
163
+ max-width: 700px;
164
  box-shadow: var(--shadow-lg);
165
  text-align: center;
166
+ position: relative;
167
+ overflow: hidden;
 
 
 
168
  transition: transform 0.3s ease, filter 0.3s ease;
169
  }
170
 
171
  .game-board.blurred {
172
+ filter: blur(8px);
173
  pointer-events: none;
174
  }
175
 
176
+ /* Mode Switcher */
177
+ .mode-switch {
178
+ display: flex;
179
+ background: #f0f0f5;
180
+ padding: 5px;
181
+ border-radius: var(--radius-btn);
182
+ margin: 0 auto 2rem auto;
183
+ width: fit-content;
184
+ position: relative;
185
+ }
186
+
187
+ .mode-btn {
188
+ background: transparent;
189
+ border: none;
190
+ padding: 10px 25px;
191
+ border-radius: var(--radius-btn);
192
+ font-family: 'Nunito', sans-serif;
193
+ font-weight: 700;
194
+ color: #888;
195
+ cursor: pointer;
196
+ z-index: 2;
197
+ transition: color 0.3s ease;
198
+ font-size: 1rem;
199
+ }
200
+
201
+ .mode-btn.active {
202
+ color: white;
203
+ }
204
+
205
+ .switch-bg {
206
+ position: absolute;
207
+ top: 5px;
208
+ left: 5px;
209
+ width: calc(50% - 5px);
210
+ height: calc(100% - 10px);
211
+ background: var(--primary);
212
+ border-radius: var(--radius-btn);
213
+ transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
214
+ z-index: 1;
215
+ }
216
+
217
  /* Progress Bar */
218
+ .progress-wrapper {
219
  width: 100%;
 
 
 
220
  margin-bottom: 2rem;
221
+ }
222
+
223
+ .progress-track {
224
+ width: 100%;
225
+ height: 12px;
226
+ background: #eee;
227
+ border-radius: 10px;
228
  overflow: hidden;
229
  }
230
 
231
+ .progress-fill {
232
  height: 100%;
233
  width: 0%;
234
+ background: linear-gradient(90deg, var(--secondary), var(--primary));
235
  border-radius: 10px;
236
+ transition: width 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
237
  }
238
 
239
+ /* Game Display Area */
240
+ .display-area {
241
+ min-height: 250px;
242
+ display: flex;
243
+ flex-direction: column;
244
+ justify-content: center;
245
+ align-items: center;
246
+ margin-bottom: 1rem;
247
+ }
248
+
249
+ /* Letter Mode Styles */
250
+ .big-letter {
251
  font-family: 'Fredoka', sans-serif;
252
+ font-size: 9rem;
253
  font-weight: 700;
254
+ color: var(--primary);
255
+ text-shadow: 4px 4px 0px rgba(108, 99, 255, 0.1);
256
+ line-height: 1;
 
 
 
257
  transition: color 0.3s;
258
  }
259
 
260
+ /* Word Mode Styles */
261
+ .word-container {
262
+ display: flex;
263
+ gap: 10px;
264
+ margin-bottom: 20px;
265
+ }
266
+
267
+ .letter-box {
268
+ font-family: 'Fredoka', sans-serif;
269
+ font-size: 3.5rem;
270
+ font-weight: 700;
271
+ width: 60px;
272
+ height: 80px;
273
+ border-bottom: 4px solid #ddd;
274
+ display: flex;
275
+ justify-content: center;
276
+ align-items: center;
277
+ color: #ccc;
278
+ transition: all 0.3s;
279
+ text-transform: uppercase;
280
+ }
281
+
282
+ .letter-box.active {
283
+ border-bottom-color: var(--primary);
284
+ color: var(--primary);
285
+ transform: translateY(-5px);
286
+ animation: bounce 1s infinite;
287
+ }
288
+
289
+ .letter-box.completed {
290
+ color: var(--accent-dark);
291
+ border-bottom-color: var(--accent);
292
+ }
293
+
294
+ @keyframes bounce {
295
+ 0%, 100% { transform: translateY(-5px); }
296
+ 50% { transform: translateY(0); }
297
+ }
298
+
299
+ /* Image Display */
300
+ .image-wrapper {
301
+ width: 200px;
302
+ height: 200px;
303
  border-radius: 20px;
304
  overflow: hidden;
305
  background: #fff;
306
+ box-shadow: inset 0 0 20px rgba(0,0,0,0.05);
307
  border: 4px solid white;
308
+ margin: 0 auto;
 
 
309
  opacity: 0;
310
+ transform: scale(0.9);
311
+ transition: all 0.5s var(--trans-bounce);
 
312
  }
313
 
314
+ .image-wrapper.visible {
315
  opacity: 1;
316
  transform: scale(1);
317
  }
318
 
319
+ .image-wrapper img {
320
  width: 100%;
321
  height: 100%;
322
  object-fit: cover;
323
  }
324
 
325
+ /* Feedback Text */
326
+ .status-msg {
327
+ font-size: 1.4rem;
328
+ font-weight: 700;
329
+ color: var(--dark);
330
+ margin-top: 1.5rem;
331
+ min-height: 2rem;
332
  }
333
 
334
+ .sub-status {
335
+ font-size: 1rem;
336
+ color: #888;
337
+ font-weight: 600;
338
  }
339
 
340
  /* Buttons */
341
+ .btn-main {
342
+ background: var(--primary);
 
 
 
 
343
  color: white;
344
  border: none;
345
+ padding: 1rem 3rem;
346
+ font-size: 1.3rem;
347
+ border-radius: var(--radius-btn);
348
  cursor: pointer;
349
  font-family: 'Fredoka', sans-serif;
350
+ box-shadow: 0 8px 20px rgba(108, 99, 255, 0.3);
351
+ transition: var(--trans-fast);
352
+ margin-top: 1rem;
353
  display: inline-flex;
354
  align-items: center;
355
  gap: 10px;
356
  }
357
 
358
+ .btn-main:hover {
359
+ background: var(--primary-dark);
360
  transform: translateY(-3px);
361
+ box-shadow: 0 12px 25px rgba(108, 99, 255, 0.4);
362
+ }
363
+
364
+ .btn-secondary {
365
+ background: transparent;
366
+ color: var(--primary);
367
+ border: 2px solid var(--primary);
368
+ padding: 0.8rem 2rem;
369
+ font-size: 1rem;
370
+ border-radius: var(--radius-btn);
371
+ cursor: pointer;
372
+ font-family: 'Fredoka', sans-serif;
373
+ font-weight: 600;
374
+ margin-top: 10px;
375
+ transition: var(--trans-fast);
376
+ }
377
+
378
+ .btn-secondary:hover {
379
+ background: rgba(108, 99, 255, 0.05);
380
  }
381
 
382
+ /* Screens */
383
+ .screen {
384
+ display: none;
385
+ width: 100%;
386
+ height: 100%;
387
+ flex-direction: column;
388
+ align-items: center;
389
+ justify-content: center;
390
  }
391
 
392
+ .screen.active {
393
+ display: flex;
394
+ }
395
+
396
+ /* Chat Overlay */
397
+ .chat-modal {
398
  position: fixed;
399
  top: 0;
400
  left: 0;
401
  width: 100%;
402
  height: 100%;
403
+ background: rgba(0, 0, 0, 0.5);
404
  z-index: 200;
405
  display: flex;
406
  justify-content: center;
 
410
  transition: all 0.3s ease;
411
  }
412
 
413
+ .chat-modal.open {
414
  opacity: 1;
415
  visibility: visible;
416
  }
417
 
418
+ .chat-box {
419
  width: 90%;
420
  max-width: 500px;
421
+ height: 75vh;
422
  background: white;
423
+ border-radius: 24px;
424
+ box-shadow: 0 25px 50px rgba(0,0,0,0.25);
425
  display: flex;
426
  flex-direction: column;
427
  overflow: hidden;
428
+ transform: translateY(30px);
429
+ transition: transform 0.3s var(--trans-bounce);
430
  }
431
 
432
+ .chat-modal.open .chat-box {
433
  transform: translateY(0);
434
  }
435
 
436
+ .chat-top {
437
+ background: var(--primary);
438
+ padding: 1rem 1.5rem;
 
439
  display: flex;
 
440
  justify-content: space-between;
441
+ align-items: center;
442
+ color: white;
443
  }
444
 
445
+ .chat-top h3 {
446
  font-family: 'Fredoka', sans-serif;
447
  display: flex;
448
  align-items: center;
 
453
  background: none;
454
  border: none;
455
  color: white;
456
+ font-size: 1.4rem;
457
  cursor: pointer;
458
  opacity: 0.8;
459
  }
460
 
461
+ .chat-body {
 
 
 
 
462
  flex: 1;
463
+ padding: 1.5rem;
464
  overflow-y: auto;
465
+ background: #f8f9fa;
466
  display: flex;
467
  flex-direction: column;
468
+ gap: 12px;
469
  }
470
 
471
+ .msg {
472
+ max-width: 85%;
473
+ padding: 12px 18px;
474
+ border-radius: 18px;
475
  font-size: 0.95rem;
476
+ line-height: 1.5;
477
  position: relative;
478
+ animation: slideIn 0.3s ease;
479
  }
480
 
481
+ @keyframes slideIn {
482
+ from { opacity: 0; transform: translateY(10px); }
483
+ to { opacity: 1; transform: translateY(0); }
484
  }
485
 
486
+ .msg.bot {
487
  background: white;
488
+ color: var(--dark);
489
+ border-bottom-left-radius: 4px;
490
  align-self: flex-start;
491
  box-shadow: 0 2px 5px rgba(0,0,0,0.05);
492
  }
493
 
494
+ .msg.user {
495
+ background: var(--primary);
496
  color: white;
497
+ border-bottom-right-radius: 4px;
498
  align-self: flex-end;
499
  box-shadow: 0 2px 5px rgba(108, 99, 255, 0.2);
500
  }
501
 
502
+ .chat-footer {
503
  padding: 1rem;
504
  background: white;
505
  border-top: 1px solid #eee;
 
507
  gap: 10px;
508
  }
509
 
510
+ .chat-footer input {
511
  flex: 1;
512
+ padding: 12px 20px;
513
  border: 2px solid #eee;
514
+ border-radius: 30px;
515
  outline: none;
516
  font-family: 'Nunito', sans-serif;
517
  transition: border-color 0.2s;
518
  }
519
 
520
+ .chat-footer input:focus {
521
+ border-color: var(--primary);
522
  }
523
 
524
  .send-btn {
525
+ width: 45px;
526
+ height: 45px;
 
 
 
527
  border-radius: 50%;
528
+ border: none;
529
+ background: var(--primary);
530
+ color: white;
531
  cursor: pointer;
532
  display: flex;
533
  justify-content: center;
 
536
  }
537
 
538
  .send-btn:hover {
539
+ background: var(--secondary);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
540
  }
541
 
542
+ /* Canvas */
543
+ #confetti {
 
 
 
 
544
  position: absolute;
545
  top: 0;
546
  left: 0;
 
550
  z-index: 50;
551
  }
552
 
553
+ /* Animations */
554
+ .shake {
555
+ animation: shake 0.4s ease;
556
+ }
557
+
558
+ @keyframes shake {
559
+ 0%, 100% { transform: translateX(0); }
560
+ 25% { transform: translateX(-10px); color: var(--secondary); }
561
+ 75% { transform: translateX(10px); color: var(--secondary); }
562
  }
563
 
564
+ /* Responsive */
565
+ @media (max-width: 600px) {
566
+ .game-board {
567
+ width: 100%;
568
+ height: 100%;
569
+ border-radius: 0;
570
+ border: none;
571
+ }
572
+ .big-letter { font-size: 6rem; }
573
+ .letter-box { width: 40px; height: 60px; font-size: 2rem; }
574
+ .logo span { display: none; }
575
+ header { padding: 0.8rem 1rem; }
576
+ .mode-btn { padding: 8px 16px; font-size: 0.9rem; }
577
  }
578
  </style>
579
  </head>
 
581
  <body>
582
 
583
  <header>
584
+ <a href="#" class="logo">
585
+ <i class="fa-solid fa-rocket"></i>
586
  <span>AlphaPop</span>
587
+ </a>
588
  <div class="header-actions">
589
+ <button class="icon-btn" onclick="app.toggleChat()" title="Talk to AlphaBot">
590
  <i class="fa-solid fa-comment-dots"></i>
591
  </button>
592
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-badge">
593
+ <i class="fa-solid fa-code"></i> Built with anycoder
594
  </a>
595
  </div>
596
  </header>
597
 
598
  <main>
599
+ <canvas id="confetti"></canvas>
600
 
601
  <div class="game-board" id="gameBoard">
602
+
603
+ <!-- Start Screen -->
604
+ <div id="startScreen" class="screen active">
605
+ <div style="font-size: 4rem; color: var(--primary); margin-bottom: 1rem;">
606
+ <i class="fa-solid fa-gamepad"></i>
607
+ </div>
608
+ <h1 style="font-family: 'Fredoka'; font-size: 2.5rem; margin-bottom: 0.5rem; color: var(--dark);">Ready to Play?</h1>
609
+ <p style="color: #666; font-size: 1.1rem; margin-bottom: 2rem;">Choose a mode to start learning!</p>
610
+
611
+ <div style="display: flex; flex-direction: column; gap: 15px; width: 100%; max-width: 300px;">
612
+ <button class="btn-main" onclick="app.startGame('letter')">
613
+ <i class="fa-solid fa-a"></i> Letter Mode
614
+ </button>
615
+ <button class="btn-secondary" onclick="app.startGame('word')">
616
+ <i class="fa-solid fa-spell-check"></i> Word Mode
617
+ </button>
618
+ <button class="btn-secondary" style="border: none; color: #666;" onclick="app.toggleChat()">
619
+ <i class="fa-solid fa-robot"></i> Talk to AlphaBot first
620
+ </button>
621
+ </div>
622
  </div>
623
 
624
+ <!-- Play Screen -->
625
+ <div id="playScreen" class="screen">
626
+
627
+ <!-- Mode Switcher (Visible during gameplay) -->
628
+ <div class="mode-switch">
629
+ <div class="switch-bg" id="switchBg"></div>
630
+ <button class="mode-btn active" id="btnModeLetter" onclick="app.switchMode('letter')">Letters</button>
631
+ <button class="mode-btn" id="btnModeWord" onclick="app.switchMode('word')">Words</button>
632
  </div>
 
 
 
633
 
634
+ <div class="progress-wrapper">
635
+ <div class="progress-track">
636
+ <div class="progress-fill" id="progressBar"></div>
637
+ </div>
638
  </div>
639
+
640
+ <div class="display-area">
641
+ <!-- Letter Mode Elements -->
642
+ <div id="letterModeUI" style="display: flex; flex-direction: column; align-items: center;">
643
+ <div class="big-letter" id="bigLetter">A</div>
644
+ </div>
645
+
646
+ <!-- Word Mode Elements -->
647
+ <div id="wordModeUI" style="display: none; flex-direction: column; align-items: center;">
648
+ <div class="word-container" id="wordContainer">
649
+ <!-- Letter boxes injected here -->
650
+ </div>
651
+ </div>
652
+
653
+ <!-- Shared Image -->
654
+ <div class="image-wrapper" id="imageWrapper">
655
+ <img id="gameImage" src="" alt="Success Image">
656
+ </div>
657
  </div>
658
+
659
+ <div class="status-msg" id="statusMsg">Press 'A'</div>
660
+ <div class="sub-status"><i class="fa-solid fa-volume-high"></i> Sound Enabled</div>
661
  </div>
662
 
663
  <!-- End Screen -->
664
+ <div id="endScreen" class="screen">
665
+ <i class="fa-solid fa-trophy" style="font-size: 5rem; color: var(--warning); margin-bottom: 1rem; animation: bounce 2s infinite;"></i>
666
+ <h2 style="font-family: 'Fredoka'; font-size: 2.5rem; margin-bottom: 0.5rem; color: var(--dark);">Awesome!</h2>
667
+ <p style="color: #666; margin-bottom: 2rem;">You completed the level.</p>
668
+ <button class="btn-main" onclick="app.startGame(app.currentMode)">
669
+ Play Again <i class="fa-solid fa-rotate-right"></i>
670
+ </button>
671
+ <button class="btn-secondary" onclick="app.showStartScreen()">Main Menu</button>
672
  </div>
673
+
674
  </div>
675
  </main>
676
 
677
+ <!-- Chat Modal -->
678
+ <div class="chat-modal" id="chatModal">
679
+ <div class="chat-box">
680
+ <div class="chat-top">
681
  <h3><i class="fa-solid fa-robot"></i> AlphaBot</h3>
682
+ <button class="close-chat" onclick="app.toggleChat()"><i class="fa-solid fa-xmark"></i></button>
683
  </div>
684
+ <div class="chat-body" id="chatBody">
685
+ <div class="msg bot">Hello! I'm AlphaBot. I can help you learn! Try typing "Hello" or ask me how to play.</div>
686
  </div>
687
+ <div class="chat-footer">
688
+ <input type="text" id="chatInput" placeholder="Type a message..." onkeypress="app.handleChatKey(event)">
689
+ <button class="send-btn" onclick="app.sendChatMessage()"><i class="fa-solid fa-paper-plane"></i></button>
690
  </div>
691
  </div>
692
  </div>
693
 
694
  <script>
695
+ /**
696
+ * AlphaPop Application Logic
697
+ * Handles Game State, UI Updates, Speech, and Chat
698
+ */
699
+ const app = {
700
+ // State
701
+ alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(''),
702
+ words: ["CAT", "DOG", "SUN", "CAR", "BEE", "FOX", "OWL", "PIG", "COW", "BAT", "HAT", "MAP", "JAM", "PAN", "VAN"],
703
+ currentMode: 'letter', // 'letter' || 'word'
704
+ currentIndex: 0,
705
+ letterIndex: 0, // For word mode tracking
706
+ isPlaying: false,
707
+ isChatOpen: false,
708
+ isProcessingInput: false, // Debounce visual feedback
709
+
710
+ // DOM Elements
711
+ ui: {
712
+ startScreen: document.getElementById('startScreen'),
713
+ playScreen: document.getElementById('playScreen'),
714
+ endScreen: document.getElementById('endScreen'),
715
+ gameBoard: document.getElementById('gameBoard'),
716
+
717
+ // Game UI
718
+ letterModeUI: document.getElementById('letterModeUI'),
719
+ wordModeUI: document.getElementById('wordModeUI'),
720
+ bigLetter: document.getElementById('bigLetter'),
721
+ wordContainer: document.getElementById('wordContainer'),
722
+ imageWrapper: document.getElementById('imageWrapper'),
723
+ gameImage: document.getElementById('gameImage'),
724
+ statusMsg: document.getElementById('statusMsg'),
725
+ progressBar: document.getElementById('progressBar'),
726
+
727
+ // Mode Switcher
728
+ switchBg: document.getElementById('switchBg'),
729
+ btnModeLetter: document.getElementById('btnModeLetter'),
730
+ btnModeWord: document.getElementById('btnModeWord'),
731
+
732
+ // Chat
733
+ chatModal: document.getElementById('chatModal'),
734
+ chatBody: document.getElementById('chatBody'),
735
+ chatInput: document.getElementById('chatInput')
736
+ },
737
+
738
+ init() {
739
+ // Global Key Listener
740
+ window.addEventListener('keydown', (e) => this.handleGlobalKey(e));
741
+
742
+ // Resize Canvas
743
+ window.addEventListener('resize', () => this.resizeCanvas());
744
+ this.resizeCanvas();
745
+
746
+ // Setup Speech Synthesis (preload voices)
747
+ window.speechSynthesis.getVoices();
748
+ },
749
+
750
+ /* --- Navigation --- */
751
+ showStartScreen() {
752
+ this.isPlaying = false;
753
+ this.ui.startScreen.classList.add('active');
754
+ this.ui.playScreen.classList.remove('active');
755
+ this.ui.endScreen.classList.remove('active');
756
+ this.closeChat();
757
+ },
758
+
759
+ startGame(mode) {
760
+ this.currentMode = mode;
761
+ this.currentIndex = 0;
762
+ this.isPlaying = true;
763
+ this.isProcessingInput = false;
764
+
765
+ // UI Reset
766
+ this.ui.startScreen.classList.remove('active');
767
+ this.ui.endScreen.classList.remove('active');
768
+ this.ui.playScreen.classList.add('active');
769
+
770
+ this.updateModeSwitcherUI();
771
+ this.loadLevel();
772
+ },
773
+
774
+ switchMode(mode) {
775
+ if (this.currentMode === mode) return;
776
+ this.startGame(mode); // Restart with new mode
777
+ },
778
+
779
+ /* --- Game Logic --- */
780
+ loadLevel() {
781
+ // Reset Visuals
782
+ this.ui.imageWrapper.classList.remove('visible');
783
+ this.ui.statusMsg.style.color = 'var(--dark)';
784
+ this.ui.statusMsg.textContent = "...";
785
+
786
+ // Update Progress
787
+ const total = this.currentMode === 'letter' ? this.alphabet.length : this.words.length;
788
+ const progress = (this.currentIndex / total) * 100;
789
+ this.ui.progressBar.style.width = `${progress}%`;
790
+
791
+ // Setup specific mode UI
792
+ if (this.currentMode === 'letter') {
793
+ this.setupLetterLevel();
794
  } else {
795
+ this.setupWordLevel();
 
 
 
796
  }
797
+ },
 
 
 
 
798
 
799
+ setupLetterLevel() {
800
+ this.ui.letterModeUI.style.display = 'flex';
801
+ this.ui.wordModeUI.style.display = 'none';
 
 
 
 
 
 
 
802
 
803
+ const letter = this.alphabet[this.currentIndex];
804
+ this.ui.bigLetter.textContent = letter;
805
+ this.ui.statusMsg.textContent = `Press the '${letter}' key!`;
806
+
807
+ this.speak(`Find the letter ${letter}`);
808
+ },
809
+
810
+ setupWordLevel() {
811
+ this.ui.letterModeUI.style.display = 'none';
812
+ this.ui.wordModeUI.style.display = 'flex';
813
+ this.letterIndex = 0;
814
+
815
+ const word = this.words[this.currentIndex];
816
+ this.ui.wordContainer.innerHTML = ''; // Clear previous
817
+
818
+ // Create letter boxes
819
+ for (let i = 0; i < word.length; i++) {
820
+ const box = document.createElement('div');
821
+ box.className = 'letter-box';
822
+ box.textContent = word[i];
823
+ box.id = `box-${i}`;
824
+ this.ui.wordContainer.appendChild(box);
825
+ }
826
 
827
+ this.updateWordHighlight();
828
+ this.speak(`Let's spell ${word}`);
829
+ },
 
 
 
 
830
 
831
+ updateWordHighlight() {
832
+ const word = this.words[this.currentIndex];
833
+ const boxes = this.ui.wordContainer.children;
834
 
835
+ // Reset all
836
+ for (let box of boxes) {
837
+ box.className = 'letter-box';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
838
  }
 
839
 
840
+ // Highlight current
841
+ const currentBox = document.getElementById(`box-${this.letterIndex}`);
842
+ if (currentBox) {
843
+ currentBox.classList.add('active');
 
 
 
 
 
844
  }
 
845
 
846
+ // Mark completed
847
+ for(let i=0; i<this.letterIndex; i++) {
848
+ const completedBox = document.getElementById(`box-${i}`);
849
+ if(completedBox) completedBox.classList.add('completed');
850
+ }
851
 
852
+ this.ui.statusMsg.textContent = `Type '${word[this.letterIndex]}'`;
853
+ },
854
+
855
+ handleInput(key) {
856
+ if (!this.isPlaying || this.isProcessingInput || this.isChatOpen) return;
 
 
 
857
 
858
+ const upperKey = key.toUpperCase();
859
+ let target = '';
860
 
861
+ if (this.currentMode === 'letter') {
862
+ target = this.alphabet[this.currentIndex];
863
+ } else {
864
+ target = this.words[this.currentIndex][this.letterIndex];
865
+ }
866
 
867
+ if (upperKey === target) {
868
+ this.handleCorrect(target);
869
+ } else {
870
+ this.handleWrong();
871
  }
872
+ },
873
 
874
+ handleCorrect(char) {
875
+ this.isProcessingInput = true;
876
+ this.speak(char);
877
 
878
+ const isLetterMode = this.currentMode === 'letter';
879
+ const isWordComplete = !isLetterMode && (this.letterIndex === this.words[this.currentIndex].length - 1);
880
+
881
+ // Visual Feedback
882
+ this.ui.statusMsg.textContent = "Correct!";
883
+ this.ui.statusMsg.style.color = "var(--accent-dark)";
 
 
884
 
885
+ if (isLetterMode) {
886
+ this.ui.bigLetter.style.color = "var(--accent-dark)";
887
+ this.showImage(char);
888
+ } else {
889
+ // Update Word UI
890
+ const box = document.getElementById(`box-${this.letterIndex}`);
891
+ if(box) {
892
+ box.classList.remove('active');
893
+ box.classList.add('completed');
894
+ }
895
+
896
+ if (isWordComplete) {
897
+ this.showImage(this.words[this.currentIndex]);
898
+ }
899
+ }
900
 
901
+ // Fire Particles
902
+ this.fireConfetti(isWordComplete || isLetterMode ? 1.5 : 0.5);
903
 
904
+ setTimeout(() => {
905
+ if (isLetterMode) {
906
+ this.ui.bigLetter.style.color = "var(--primary)";
907
+ this.nextLevel();
908
+ } else {
909
+ if (isWordComplete) {
910
+ this.nextLevel();
911
+ } else {
912
+ this.letterIndex++;
913
+ this.updateWordHighlight();
914
+ this.isProcessingInput = false;
915
+ }
916
+ }
917
+ }, 1200);
918
+ },
919
+
920
+ handleWrong() {
921
+ this.speak("Try again");
922
+
923
+ if (this.currentMode === 'letter') {
924
+ this.ui.bigLetter.classList.remove('shake');
925
+ void this.ui.bigLetter.offsetWidth; // trigger reflow
926
+ this.ui.bigLetter.classList.add('shake');
927
+ } else {
928
+ const box = document.getElementById(`box-${this.letterIndex}`);
929
+ if(box) {
930
+ box.classList.remove('shake');
931
+ void box.offsetWidth;
932
+ box.classList.add('shake');
933
+ }
934
+ }
935
 
936
+ this.ui.statusMsg.textContent = "Oops, try again!";
937
+ this.ui.statusMsg.style.color = "var(--secondary)";
938
+ },
939
 
940
+ showImage(seed) {
941
+ // Use Picsum with seed to get consistent random images
942
+ const url = `https://picsum.photos/seed/${seed}/400/400`;
943
+ this.ui.gameImage.src = url;
944
+ this.ui.gameImage.onload = () => {
945
+ this.ui.imageWrapper.classList.add('visible');
946
+ };
947
+ },
948
 
949
+ nextLevel() {
950
+ const total = this.currentMode === 'letter' ? this.alphabet.length : this.words.length;
951
+ this.currentIndex++;
952
+ this.isProcessingInput = false;
953
 
954
+ if (this.currentIndex >= total) {
955
+ this.gameOver();
956
  } else {
957
+ this.loadLevel();
958
  }
959
+ },
960
+
961
+ gameOver() {
962
+ this.isPlaying = false;
963
+ this.ui.playScreen.classList.remove('active');
964
+ this.ui.endScreen.classList.add('active');
965
+ this.ui.progressBar.style.width = '100%';
966
+ this.fireConfetti(3.0);
967
+ this.speak("Amazing work! You finished the game!");
968
+ },
969
+
970
+ updateModeSwitcherUI() {
971
+ if (this.currentMode === 'letter') {
972
+ this.ui.switchBg.style.transform = 'translateX(0)';
973
+ this.ui.btnModeLetter.classList.add('active');
974
+ this.ui.btnModeWord.classList.remove('active');
975
+ } else {
976
+ this.ui.switchBg.style.transform = 'translateX(100%)';
977
+ this.ui.btnModeLetter.classList.remove('active');
978
+ this.ui.btnModeWord.classList.add('active');
979
+ }
980
+ },
981
+
982
+ /* --- Chat System --- */
983
+ toggleChat() {
984
+ this.isChatOpen = !this.isChatOpen;
985
+ if (this.isChatOpen) {
986
+ this.ui.chatModal.classList.add('open');
987
+ this.ui.gameBoard.classList.add('blurred');
988
+ this.ui.chatInput.focus();
989
+ } else {
990
+ this.ui.chatModal.classList.remove('open');
991
+ this.ui.gameBoard.classList.remove('blurred');
992
+ }
993
+ },
994
 
995
+ handleChatKey(e) {
996
+ if (e.key === 'Enter') this.sendChatMessage();
997
+ },
 
 
 
 
 
 
 
 
 
998
 
999
+ sendChatMessage() {
1000
+ const text = this.ui.chatInput.value.trim();
1001
+ if (!text) return;
1002
 
1003
+ // User Msg
1004
+ this.addMsg(text, 'user');
1005
+ this.ui.chatInput.value = '';
1006
 
1007
+ // Bot Response
1008
  setTimeout(() => {
1009
+ const reply = this.getBotResponse(text);
1010
+ this.addMsg(reply, 'bot');
1011
+ this.speak(reply);
1012
+ }, 600);
1013
+ },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1014
 
1015
+ addMsg(text, type) {
1016
+ const div = document.createElement('div');
1017
+ div.className = `msg ${type}`;
1018
+ div.textContent = text;
1019
+ this.ui.chatBody.appendChild(div);
1020
+ this.ui.chatBody.scrollTop = this.ui.chatBody.scrollHeight;
1021
+ },
1022
 
1023
+ getBotResponse(input) {
1024
+ const lower = input.toLowerCase();
1025
+
1026
+ if (lower.includes('hello') || lower.includes('hi')) return "Hi there! Ready to learn some letters and words?";
1027
+ if (lower.includes('how are you')) return "I'm a robot, so I'm always functioning at 100%!";
1028
+ if (lower.includes('play') || lower.includes('game')) return "If you are in Letter Mode, press the key you see. In Word Mode, type the whole word!";
1029
+ if (lower.includes('letter')) return "Letter Mode helps you learn individual keys A through Z.";
1030
+ if (lower.includes('word')) return "Word Mode is harder. You have to spell words like 'CAT' or 'DOG'.";
1031
+ if (lower.includes('help')) return "Just type the letters on your keyboard that match the screen!";
1032
 
1033
+ // Check for single letters
1034
+ if (/^[a-z]$/.test(lower)) {
1035
+ return `You typed ${input.toUpperCase()}! That is correct.`;
 
 
 
 
 
 
 
 
1036
  }
 
 
1037
 
1038
+ const jokes = [
1039
+ "Why did the computer go to the doctor? Because it had a virus!",
1040
+ "I love teaching you, you are a fast typer!",
1041
+ "Keep going, you are doing great!",
1042
+ "Did you know? The alphabet has 26 letters!"
1043
+ ];
1044
+ return jokes[Math.floor(Math.random() * jokes.length)];
1045
+ },
1046
+
1047
+ /* --- Utilities --- */
1048
+ handleGlobalKey(e) {
1049
+ // Input handling is routed here
1050
+ this.handleInput(e.key);
1051
+ },
1052
+
1053
+ speak(text) {
1054
+ if ('speechSynthesis' in window) {
1055
+ window.speechSynthesis.cancel(); // Stop previous
1056
+ const utterance = new SpeechSynthesisUtterance(text);
1057
+ utterance.rate = 1.0;
1058
+ utterance.pitch = 1.1; // Slightly higher pitch for "kid friendly" vibe
1059
+ window.speechSynthesis.speak(utterance);
1060
  }
1061
+ },
1062
+
1063
+ /* --- Confetti System --- */
1064
+ canvas: null,
1065
+ ctx: null,
1066
+ particles: [],
1067
+
1068
+ resizeCanvas() {
1069
+ this.canvas = document.getElementById('confetti');
1070
+ this.ctx = this.canvas.getContext('2d');
1071
+ this.canvas.width = window.innerWidth;
1072
+ this.canvas.height = window.innerHeight;
1073
+ },
1074
+
1075
+ fireConfetti(intensity = 1.0) {
1076
+ const count = 100 * intensity;
1077
+ const colors = ['#FF6584', '#6C63FF', '#43D9AD', '#FFD93D', '#FF8C00'];
1078
 
1079
+ for (let i = 0; i < count; i++) {
1080
+ this.particles.push({
1081
+ x: window.innerWidth / 2,
1082
+ y: window.innerHeight / 2,
1083
+ vx: (Math.random() - 0.5) * 20 * intensity,
1084
+ vy: (Math.random() - 1) * 20 * intensity,
1085
+ size: Math.random() * 8 + 4,
1086
+ color: colors[Math.floor(Math.random() * colors.length)],
1087
+ life: 100,
1088
+ gravity: 0.5
1089
+ });
1090
  }
1091
+
1092
+ if (this.particles.length <= count) requestAnimationFrame(() => this.updateConfetti());
1093
+ },
1094
 
1095
+ updateConfetti() {
1096
+ if (!this.ctx) return;
1097
+
1098
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
1099
+
1100
+ for (let i = 0; i < this.particles.length; i++) {
1101
+ let p = this.particles[i];
1102
+ p.x += p.vx;