AptlyDigital commited on
Commit
f8f1363
·
verified ·
1 Parent(s): 4855d76

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +703 -908
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>AI Tutor 3D Interface</title>
7
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
8
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
9
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
@@ -20,132 +20,208 @@
20
  font-family: 'Segoe UI', system-ui, sans-serif;
21
  overflow: hidden;
22
  height: 100vh;
 
23
  }
24
 
 
25
  #canvasContainer {
26
- width: 100%;
27
- height: 100%;
28
  position: relative;
 
29
  }
30
 
31
  canvas {
32
  display: block;
33
- outline: none;
34
  width: 100%;
35
  height: 100%;
36
  }
37
 
38
- .ui-overlay {
39
- position: absolute;
40
- top: 0;
41
- left: 0;
42
- width: 100%;
43
- height: 100%;
44
- pointer-events: none;
45
- z-index: 100;
 
 
 
 
46
  }
47
 
48
- /* === CHAT INTERFACE === */
49
- .chat-interface {
50
- position: absolute;
51
- top: 30px;
52
- right: 30px;
53
- width: 420px;
54
- height: calc(100vh - 100px);
 
 
 
 
 
 
55
  display: flex;
56
- flex-direction: column;
57
- pointer-events: all;
58
- z-index: 101;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  opacity: 0;
60
- transform: translateY(20px);
61
- animation: slideIn 0.5s ease 1s forwards;
 
 
62
  }
63
 
64
- @keyframes slideIn {
65
- to {
66
- opacity: 1;
67
- transform: translateY(0);
68
- }
 
69
  }
70
 
71
- .chat-header {
72
- background: rgba(20, 20, 30, 0.9);
73
- backdrop-filter: blur(10px);
74
- border-radius: 20px 20px 0 0;
75
- padding: 20px;
76
- border: 1px solid rgba(255, 255, 255, 0.1);
77
- border-bottom: none;
78
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
79
  display: flex;
80
  align-items: center;
81
  justify-content: space-between;
 
82
  }
83
 
84
- .chat-title {
85
- font-size: 1.2em;
86
- font-weight: 300;
 
 
87
  color: #a0b0ff;
 
 
88
  display: flex;
89
  align-items: center;
90
  gap: 10px;
91
  }
92
 
93
- .chat-status {
94
- display: flex;
95
- align-items: center;
96
- gap: 8px;
97
- font-size: 0.85em;
98
- color: #8892b0;
99
  }
100
 
101
- .status-indicator {
102
- width: 8px;
103
- height: 8px;
104
- border-radius: 50%;
105
- background: #00ff9d;
106
- animation: pulse 2s infinite;
107
  }
108
 
109
- .chat-container {
110
- flex: 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  background: rgba(20, 20, 30, 0.85);
112
- backdrop-filter: blur(10px);
 
113
  border: 1px solid rgba(255, 255, 255, 0.1);
114
- border-top: none;
115
- overflow: hidden;
116
  display: flex;
117
  flex-direction: column;
118
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
 
 
119
  }
120
 
121
- .chat-messages {
122
- flex: 1;
123
- overflow-y: auto;
124
- padding: 20px;
 
 
 
 
 
 
 
 
 
125
  display: flex;
126
- flex-direction: column;
127
- gap: 20px;
128
- scrollbar-width: thin;
129
- scrollbar-color: #5a6cff rgba(255, 255, 255, 0.1);
130
  }
131
 
132
- .chat-messages::-webkit-scrollbar {
133
- width: 6px;
 
 
134
  }
135
 
136
- .chat-messages::-webkit-scrollbar-track {
137
- background: rgba(255, 255, 255, 0.05);
138
- border-radius: 3px;
 
 
 
 
 
 
139
  }
140
 
141
- .chat-messages::-webkit-scrollbar-thumb {
142
- background: #5a6cff;
143
- border-radius: 3px;
 
 
 
 
 
 
 
 
 
 
 
144
  }
145
 
146
  .message {
147
  max-width: 85%;
148
- padding: 15px;
149
  border-radius: 18px;
150
  line-height: 1.5;
151
  position: relative;
@@ -172,16 +248,16 @@
172
 
173
  .message-ai {
174
  align-self: flex-start;
175
- background: rgba(255, 255, 255, 0.1);
176
  color: #e0e0ff;
177
  border-bottom-left-radius: 5px;
178
  border: 1px solid rgba(255, 255, 255, 0.05);
179
  }
180
 
181
  .message-time {
182
- font-size: 0.7em;
183
  opacity: 0.7;
184
- margin-top: 5px;
185
  text-align: right;
186
  }
187
 
@@ -214,14 +290,14 @@
214
  }
215
 
216
  .chat-input-container {
217
- padding: 20px;
218
  background: rgba(15, 15, 25, 0.9);
219
  border-top: 1px solid rgba(255, 255, 255, 0.05);
220
  }
221
 
222
  .input-wrapper {
223
  display: flex;
224
- gap: 10px;
225
  align-items: flex-end;
226
  }
227
 
@@ -230,7 +306,7 @@
230
  background: rgba(255, 255, 255, 0.07);
231
  border: 1px solid rgba(255, 255, 255, 0.1);
232
  border-radius: 15px;
233
- padding: 15px 20px;
234
  color: white;
235
  font-family: 'Segoe UI', system-ui, sans-serif;
236
  font-size: 1em;
@@ -251,7 +327,14 @@
251
  color: rgba(255, 255, 255, 0.4);
252
  }
253
 
254
- .voice-input-btn {
 
 
 
 
 
 
 
255
  width: 56px;
256
  height: 56px;
257
  border-radius: 15px;
@@ -263,10 +346,11 @@
263
  align-items: center;
264
  justify-content: center;
265
  transition: all 0.3s ease;
266
- flex-shrink: 0;
267
  }
268
 
269
- .voice-input-btn:hover {
 
270
  transform: translateY(-2px);
271
  box-shadow: 0 5px 15px rgba(90, 108, 255, 0.4);
272
  }
@@ -282,94 +366,100 @@
282
  }
283
 
284
  .send-btn {
285
- width: 56px;
286
- height: 56px;
287
- border-radius: 15px;
288
- background: rgba(255, 255, 255, 0.1);
289
- border: 1px solid rgba(255, 255, 255, 0.1);
290
- color: #a0b0ff;
291
- cursor: pointer;
292
- display: flex;
293
- align-items: center;
294
- justify-content: center;
295
- transition: all 0.3s ease;
296
- flex-shrink: 0;
297
  }
298
 
299
  .send-btn:hover {
300
- background: rgba(90, 108, 255, 0.2);
301
- color: white;
302
- transform: translateY(-2px);
 
 
 
303
  }
304
 
305
- .voice-visualizer {
306
- height: 40px;
307
  display: flex;
308
  align-items: center;
309
- justify-content: center;
310
- gap: 3px;
311
- margin-top: 10px;
312
- opacity: 0;
313
- transition: opacity 0.3s ease;
314
  }
315
 
316
- .voice-visualizer.active {
317
- opacity: 1;
 
 
318
  }
319
 
320
- .voice-bar {
321
- width: 4px;
322
- height: 10px;
 
 
 
 
 
 
 
 
 
 
323
  background: #5a6cff;
324
- border-radius: 2px;
325
- transition: height 0.1s ease;
 
 
 
 
 
 
326
  }
327
 
328
- .voice-bar.listening {
329
- background: #ff5a5a;
 
 
 
 
 
330
  }
331
 
332
- /* === VOICE CONTROLS PANEL === */
333
- .voice-controls {
334
- position: absolute;
335
- bottom: 30px;
336
- right: 470px;
337
- background: rgba(20, 20, 30, 0.9);
338
- backdrop-filter: blur(10px);
339
- border-radius: 20px;
340
- padding: 25px;
341
- width: 280px;
342
- pointer-events: all;
343
- border: 1px solid rgba(255, 255, 255, 0.1);
344
- box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
345
- z-index: 102;
346
- opacity: 0;
347
- transform: translateY(20px);
348
- animation: slideIn 0.5s ease 1.2s forwards;
349
  }
350
 
351
- .voice-header {
352
- display: flex;
353
- align-items: center;
354
- gap: 10px;
355
- margin-bottom: 20px;
356
  color: #a0b0ff;
357
- font-size: 1.1em;
358
- font-weight: 300;
 
 
 
359
  }
360
 
361
- .voice-control-group {
362
- margin-bottom: 20px;
 
363
  }
364
 
365
- .voice-label {
366
- display: block;
367
- margin-bottom: 8px;
368
- font-size: 0.9em;
369
- color: #8892b0;
370
- display: flex;
371
- align-items: center;
372
- gap: 8px;
373
  }
374
 
375
  .voice-select {
@@ -398,50 +488,11 @@
398
  padding: 10px;
399
  }
400
 
401
- .voice-slider-container {
402
- display: flex;
403
- align-items: center;
404
- gap: 15px;
405
- }
406
-
407
- .voice-slider {
408
- flex: 1;
409
- height: 6px;
410
- background: rgba(255, 255, 255, 0.1);
411
- border-radius: 3px;
412
- outline: none;
413
- -webkit-appearance: none;
414
- }
415
-
416
- .voice-slider::-webkit-slider-thumb {
417
- -webkit-appearance: none;
418
- width: 20px;
419
- height: 20px;
420
- background: #5a6cff;
421
- border-radius: 50%;
422
- cursor: pointer;
423
- transition: all 0.2s;
424
- }
425
-
426
- .voice-slider::-webkit-slider-thumb:hover {
427
- background: #7a8aff;
428
- transform: scale(1.1);
429
- }
430
-
431
- .voice-value {
432
- min-width: 40px;
433
- text-align: center;
434
- font-family: 'Courier New', monospace;
435
- color: #5a6cff;
436
- font-weight: 500;
437
- font-size: 0.9em;
438
- }
439
-
440
  .voice-control-buttons {
441
  display: grid;
442
  grid-template-columns: 1fr 1fr;
443
  gap: 10px;
444
- margin-top: 25px;
445
  }
446
 
447
  .voice-btn {
@@ -486,160 +537,60 @@
486
  .voice-preview-btn {
487
  width: 100%;
488
  padding: 12px;
489
- background: rgba(255, 255, 255, 0.07);
490
- border: 1px solid rgba(255, 255, 255, 0.1);
491
- border-radius: 10px;
492
- color: #a0b0ff;
493
- cursor: pointer;
494
- transition: all 0.3s ease;
495
- display: flex;
496
- align-items: center;
497
- justify-content: center;
498
- gap: 8px;
499
- margin-top: 10px;
500
- font-size: 0.9em;
501
- }
502
-
503
- .voice-preview-btn:hover {
504
- background: rgba(255, 255, 255, 0.1);
505
- transform: translateY(-2px);
506
- }
507
-
508
- .voice-status {
509
- display: flex;
510
- align-items: center;
511
- gap: 8px;
512
- margin-top: 15px;
513
- padding: 10px;
514
  background: rgba(0, 255, 157, 0.1);
 
515
  border-radius: 10px;
516
- font-size: 0.85em;
517
- color: #00ff9d;
518
- border: 1px solid rgba(0, 255, 157, 0.2);
519
- }
520
-
521
- .voice-status i {
522
- animation: pulse 2s infinite;
523
- }
524
-
525
- /* === EXISTING STYLES (PRESERVED) === */
526
- .control-panel {
527
- position: absolute;
528
- bottom: 30px;
529
- left: 30px;
530
- background: rgba(20, 20, 30, 0.8);
531
- backdrop-filter: blur(10px);
532
- border-radius: 20px;
533
- padding: 25px;
534
- width: 300px;
535
- pointer-events: all;
536
- border: 1px solid rgba(255, 255, 255, 0.1);
537
- box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
538
- }
539
-
540
- .control-title {
541
- font-size: 1.2em;
542
- margin-bottom: 20px;
543
- font-weight: 300;
544
- color: #a0b0ff;
545
- display: flex;
546
- align-items: center;
547
- gap: 10px;
548
- }
549
-
550
- .control-group {
551
- margin-bottom: 20px;
552
- }
553
-
554
- label {
555
- display: block;
556
- margin-bottom: 8px;
557
- font-size: 0.9em;
558
- color: #8892b0;
559
- }
560
-
561
- .slider-container {
562
- display: flex;
563
- align-items: center;
564
- gap: 15px;
565
- }
566
-
567
- input[type="range"] {
568
- flex: 1;
569
- height: 6px;
570
- background: rgba(255, 255, 255, 0.1);
571
- border-radius: 3px;
572
- outline: none;
573
- -webkit-appearance: none;
574
- }
575
-
576
- input[type="range"]::-webkit-slider-thumb {
577
- -webkit-appearance: none;
578
- width: 20px;
579
- height: 20px;
580
- background: #5a6cff;
581
- border-radius: 50%;
582
- cursor: pointer;
583
- transition: all 0.2s;
584
- }
585
-
586
- input[type="range"]::-webkit-slider-thumb:hover {
587
- background: #7a8aff;
588
- transform: scale(1.1);
589
- }
590
-
591
- .value-display {
592
- min-width: 40px;
593
- text-align: center;
594
- font-family: 'Courier New', monospace;
595
- color: #5a6cff;
596
- font-weight: 500;
597
- }
598
-
599
- .preset-buttons {
600
- display: grid;
601
- grid-template-columns: repeat(3, 1fr);
602
- gap: 10px;
603
- margin-top: 20px;
604
- }
605
-
606
- .preset-btn {
607
- padding: 10px;
608
- background: rgba(90, 108, 255, 0.1);
609
- border: 1px solid rgba(90, 108, 255, 0.3);
610
- color: #a0b0ff;
611
- border-radius: 10px;
612
  cursor: pointer;
613
- transition: all 0.2s;
 
 
 
 
 
614
  font-size: 0.9em;
615
- text-align: center;
616
  }
617
 
618
- .preset-btn:hover {
619
- background: rgba(90, 108, 255, 0.2);
620
  transform: translateY(-2px);
621
  }
622
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
623
  .status-bar {
624
  position: absolute;
625
- top: 30px;
626
- left: 30px;
627
  background: rgba(20, 20, 30, 0.8);
628
  backdrop-filter: blur(10px);
629
- padding: 15px 25px;
630
- border-radius: 15px;
631
- font-size: 0.9em;
632
  color: #8892b0;
633
  border: 1px solid rgba(255, 255, 255, 0.1);
 
 
 
634
  }
635
 
636
  .pulse-indicator {
637
- display: inline-block;
638
  width: 12px;
639
  height: 12px;
640
  background: #00ff9d;
641
  border-radius: 50%;
642
- margin-right: 10px;
643
  animation: pulse 2s infinite;
644
  }
645
 
@@ -648,6 +599,7 @@
648
  50% { opacity: 0.3; }
649
  }
650
 
 
651
  .loading-screen {
652
  position: absolute;
653
  top: 0;
@@ -659,7 +611,7 @@
659
  flex-direction: column;
660
  justify-content: center;
661
  align-items: center;
662
- z-index: 1000;
663
  }
664
 
665
  .spinner {
@@ -687,7 +639,7 @@
687
  flex-direction: column;
688
  justify-content: center;
689
  align-items: center;
690
- z-index: 1001;
691
  text-align: center;
692
  padding: 20px;
693
  }
@@ -719,241 +671,334 @@
719
  transform: translateY(-2px);
720
  }
721
 
722
- /* Responsive adjustments */
723
- @media (max-width: 1400px) {
724
- .voice-controls {
725
- right: 30px;
726
- bottom: 400px;
727
- }
728
-
729
- .chat-interface {
730
- width: 400px;
731
  }
732
  }
733
 
734
- @media (max-height: 800px) {
735
- .chat-interface {
736
- height: calc(100vh - 80px);
 
 
 
 
 
 
 
737
  }
738
 
739
- .voice-controls {
 
 
 
 
 
 
 
 
 
 
 
740
  padding: 20px;
741
- width: 260px;
742
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
743
  }
744
  </style>
745
  </head>
746
  <body>
747
- <div id="canvasContainer">
748
- <canvas id="mainCanvas"></canvas>
749
-
750
- <!-- Existing UI Overlay -->
751
- <div class="ui-overlay">
752
- <div class="status-bar">
753
- <span class="pulse-indicator"></span>
754
- <span id="statusText">AI Tutor System Ready</span>
755
- </div>
756
  </div>
757
 
758
- <!-- Voice Controls Panel -->
759
- <div class="voice-controls">
760
- <div class="voice-header">
761
- <i class="fas fa-robot"></i>
762
- <span>Voice Synthesis</span>
763
- </div>
764
-
765
- <div class="voice-control-group">
766
- <label class="voice-label">
767
- <i class="fas fa-user-circle"></i>
768
- Voice Selection
769
- </label>
770
- <select class="voice-select" id="voiceSelect">
771
- <option value="">Loading voices...</option>
772
- </select>
773
- </div>
774
-
775
- <div class="voice-control-group">
776
- <label class="voice-label">
777
- <i class="fas fa-tachometer-alt"></i>
778
- Speech Rate
779
- </label>
780
- <div class="voice-slider-container">
781
- <input type="range" class="voice-slider" id="rateSlider" min="0.5" max="2" step="0.1" value="1">
782
- <span class="voice-value" id="rateValue">1.0x</span>
783
  </div>
784
- </div>
785
-
786
- <div class="voice-control-group">
787
- <label class="voice-label">
788
- <i class="fas fa-wave-square"></i>
789
- Pitch Variation
790
- </label>
791
- <div class="voice-slider-container">
792
- <input type="range" class="voice-slider" id="pitchSlider" min="0.5" max="2" step="0.1" value="1">
793
- <span class="voice-value" id="pitchValue">1.0</span>
794
- </div>
795
- </div>
796
-
797
- <div class="voice-control-group">
798
- <label class="voice-label">
799
- <i class="fas fa-volume-up"></i>
800
- Volume Level
801
- </label>
802
- <div class="voice-slider-container">
803
- <input type="range" class="voice-slider" id="volumeSlider" min="0.1" max="1" step="0.1" value="0.8">
804
- <span class="voice-value" id="volumeValue">80%</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
805
  </div>
806
  </div>
807
 
808
- <div class="voice-control-buttons">
809
- <button class="voice-btn" id="autoSpeakBtn" data-enabled="true">
810
- <i class="fas fa-bullhorn"></i>
811
- Auto-Speak
812
- </button>
813
- <button class="voice-btn stop" id="stopBtn">
814
- <i class="fas fa-stop"></i>
815
- Stop
816
- </button>
817
- </div>
818
-
819
- <button class="voice-preview-btn" id="previewBtn">
820
- <i class="fas fa-play"></i>
821
- Preview Voice
822
- </button>
823
-
824
- <div class="voice-status" id="voiceStatus" style="display: none;">
825
- <i class="fas fa-comment-dots"></i>
826
- <span id="statusMessage">Speaking...</span>
827
- </div>
828
- </div>
829
-
830
- <!-- Chat Interface -->
831
- <div class="chat-interface">
832
- <div class="chat-header">
833
- <div class="chat-title">
834
- <i class="fas fa-robot"></i>
835
- AI Tutor Assistant
836
  </div>
837
- <div class="chat-status">
838
- <span class="status-indicator"></span>
839
- <span id="chatStatusText">Online</span>
840
- </div>
841
- </div>
842
-
843
- <div class="chat-container">
844
- <div class="chat-messages" id="chatMessages">
845
- <!-- Messages will be dynamically added here -->
846
- <div class="message message-ai">
847
- <div class="message-content">
848
- Hello! I'm your AI Tutor. I can help explain concepts, answer questions, and guide your learning. How can I assist you today?
849
  </div>
850
- <div class="message-time">Just now</div>
 
 
851
  </div>
852
 
853
- <div class="message message-ai">
854
- <div class="message-content">
855
- You can type your questions or click the microphone icon to speak. I'll respond with explanations, examples, and follow-up questions to enhance your understanding.
 
 
 
 
 
856
  </div>
857
- <div class="message-time">Just now</div>
858
  </div>
859
 
860
- <!-- Typing indicator (hidden by default) -->
861
- <div class="message-typing" id="typingIndicator" style="display: none;">
862
- <div class="typing-dot"></div>
863
- <div class="typing-dot"></div>
864
- <div class="typing-dot"></div>
 
 
 
 
865
  </div>
866
- </div>
867
-
868
- <div class="chat-input-container">
869
- <div class="input-wrapper">
870
- <textarea
871
- class="chat-input"
872
- id="chatInput"
873
- placeholder="Type your question or click the microphone to speak..."
874
- rows="1"
875
- ></textarea>
876
-
877
- <button class="voice-input-btn" id="voiceBtn" title="Start voice input">
878
- <i class="fas fa-microphone"></i>
 
 
 
879
  </button>
880
-
881
- <button class="send-btn" id="sendBtn" title="Send message">
882
- <i class="fas fa-paper-plane"></i>
883
  </button>
884
  </div>
885
 
886
- <div class="voice-visualizer" id="voiceVisualizer">
887
- <div class="voice-bar"></div>
888
- <div class="voice-bar"></div>
889
- <div class="voice-bar"></div>
890
- <div class="voice-bar"></div>
891
- <div class="voice-bar"></div>
892
- <div class="voice-bar"></div>
893
- <div class="voice-bar"></div>
894
- <div class="voice-bar"></div>
895
- <div class="voice-bar"></div>
896
- <div class="voice-bar"></div>
897
  </div>
898
  </div>
899
  </div>
900
- </div>
901
-
902
- <!-- Existing Control Panel -->
903
- <div class="control-panel">
904
- <div class="control-title">
905
- <span>🧠 AI Tutor Interface</span>
906
- </div>
907
 
908
- <div class="control-group">
909
- <label>Animation Intensity</label>
910
- <div class="slider-container">
911
- <input type="range" id="intensity" min="0" max="100" value="50">
912
- <span class="value-display" id="intensityValue">50</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
913
  </div>
914
  </div>
915
-
916
- <div class="control-group">
917
- <label>Particle Count</label>
918
- <div class="slider-container">
919
- <input type="range" id="particleCount" min="100" max="5000" value="2000" step="100">
920
- <span class="value-display" id="particleCountValue">2000</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
921
  </div>
922
  </div>
923
 
924
- <div class="control-group">
925
- <label>Energy Level</label>
926
- <div class="slider-container">
927
- <input type="range" id="energy" min="0" max="100" value="30">
928
- <span class="value-display" id="energyValue">30</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
929
  </div>
930
  </div>
931
 
932
- <div class="preset-buttons">
933
- <button class="preset-btn" data-preset="listening">🎤 Listening</button>
934
- <button class="preset-btn" data-preset="processing">⚡ Processing</button>
935
- <button class="preset-btn" data-preset="responding">💬 Responding</button>
936
- <button class="preset-btn" data-preset="exploring">🔍 Exploring</button>
937
- <button class="preset-btn" data-preset="teaching">📚 Teaching</button>
938
- <button class="preset-btn" data-preset="idle">🌀 Idle</button>
 
 
 
 
 
 
 
 
 
 
 
 
939
  </div>
940
  </div>
941
 
942
- <!-- Existing Loading Screen -->
943
  <div class="loading-screen" id="loadingScreen">
944
  <div class="spinner"></div>
945
- <div id="loadingText">Initializing AI Interface...</div>
946
  </div>
947
 
948
- <!-- Existing Error Screen -->
949
  <div class="error-screen" id="errorScreen">
950
- <h2>⚠️ Initialization Failed</h2>
951
- <p id="errorMessage">Three.js library failed to load. Please check your internet connection or try again.</p>
952
- <button class="retry-btn" id="retryBtn">Retry</button>
953
  </div>
954
  </div>
955
 
956
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
957
  // Check if Three.js loaded properly
958
  function checkThreeJS() {
959
  if (typeof THREE === 'undefined') {
@@ -1003,8 +1048,30 @@
1003
  volume: 0.8
1004
  };
1005
 
1006
- // Hardcoded longer, simpler test script for voice testing
1007
- this.testScript = "Hello there! This is a test to see how natural and fluid my voice sounds. I'm going to tell you a little story about learning and discovery. Imagine you're walking through a beautiful forest on a sunny day. The light filters through the leaves, creating patterns on the ground. Birds are singing in the trees, and there's a gentle breeze carrying the scent of flowers. You come across a small stream, and you sit on a rock to listen to the water flowing. It's in moments like these that we often have our best ideas and clearest thoughts. Learning is like this forest walk - it's a journey of discovery where each step reveals something new and wonderful. The key is to stay curious, keep exploring, and enjoy the process. Now, how does my voice sound to you? Is it clear, natural, and pleasant to listen to?";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1008
 
1009
  this.initVoices();
1010
  this.setupEventListeners();
@@ -1041,7 +1108,7 @@
1041
  return;
1042
  }
1043
 
1044
- // Prioritize natural-sounding voices (Google, Microsoft, Apple premium voices)
1045
  const preferredVoices = [
1046
  'Google UK English Male',
1047
  'Google US English',
@@ -1052,9 +1119,7 @@
1052
  'Daniel',
1053
  'Karen',
1054
  'Moira',
1055
- 'Tessa',
1056
- 'Fred',
1057
- 'Victoria'
1058
  ];
1059
 
1060
  // Try to find a preferred voice
@@ -1187,12 +1252,12 @@
1187
  this.showStatus(this.isAutoSpeak ? 'Auto-speak enabled' : 'Auto-speak disabled', 2000);
1188
  });
1189
 
1190
- // Stop button
1191
  document.getElementById('stopBtn').addEventListener('click', () => {
1192
- this.stopSpeaking();
1193
  });
1194
 
1195
- // Preview button - uses the hardcoded test script
1196
  document.getElementById('previewBtn').addEventListener('click', () => {
1197
  this.previewCurrentVoice();
1198
  });
@@ -1226,7 +1291,7 @@
1226
  speak(text) {
1227
  if (!this.isAutoSpeak || !text || this.isSpeaking) return;
1228
 
1229
- this.stopSpeaking();
1230
 
1231
  const utterance = new SpeechSynthesisUtterance(text);
1232
 
@@ -1238,9 +1303,6 @@
1238
  utterance.pitch = this.settings.pitch;
1239
  utterance.volume = this.settings.volume;
1240
 
1241
- // Add natural pauses for better cadence
1242
- utterance.text = this.addNaturalPauses(text);
1243
-
1244
  // Event listeners for this utterance
1245
  utterance.onerror = (event) => {
1246
  console.error('Speech synthesis error:', event);
@@ -1251,18 +1313,10 @@
1251
  this.synth.speak(utterance);
1252
  }
1253
 
1254
- addNaturalPauses(text) {
1255
- // Add slight pauses for commas and periods for more natural speech
1256
- return text
1257
- .replace(/,/g, ',<break time="200ms"/>')
1258
- .replace(/\./g, '.<break time="300ms"/>')
1259
- .replace(/\?/g, '?<break time="400ms"/>')
1260
- .replace(/\!/g, '!<break time="400ms"/>');
1261
- }
1262
-
1263
- stopSpeaking() {
1264
- if (this.isSpeaking) {
1265
- this.synth.cancel();
1266
  this.isSpeaking = false;
1267
  this.currentUtterance = null;
1268
  document.getElementById('stopBtn').classList.remove('active');
@@ -1271,9 +1325,9 @@
1271
  }
1272
 
1273
  previewCurrentVoice() {
1274
- // Always use the hardcoded test script for voice testing
1275
  this.speak(this.testScript);
1276
- this.showStatus('Testing voice with story script...', 3000);
1277
  }
1278
 
1279
  showStatus(message, duration = null) {
@@ -1306,7 +1360,6 @@
1306
  class ChatInterface {
1307
  constructor() {
1308
  this.isListening = false;
1309
- this.voiceAnimationInterval = null;
1310
  this.initChat();
1311
  }
1312
 
@@ -1315,9 +1368,7 @@
1315
  this.chatMessages = document.getElementById('chatMessages');
1316
  this.voiceBtn = document.getElementById('voiceBtn');
1317
  this.sendBtn = document.getElementById('sendBtn');
1318
- this.voiceVisualizer = document.getElementById('voiceVisualizer');
1319
  this.typingIndicator = document.getElementById('typingIndicator');
1320
- this.chatStatusText = document.getElementById('chatStatusText');
1321
 
1322
  this.setupEventListeners();
1323
  this.autoResizeTextarea();
@@ -1356,9 +1407,6 @@
1356
  // Start "listening" state
1357
  this.voiceBtn.classList.add('listening');
1358
  this.voiceBtn.innerHTML = '<i class="fas fa-stop"></i>';
1359
- this.voiceVisualizer.classList.add('active');
1360
- this.chatStatusText.textContent = 'Listening...';
1361
- this.startVoiceAnimation();
1362
 
1363
  // Update 3D visualization to listening mode
1364
  if (window.visualization) {
@@ -1373,9 +1421,6 @@
1373
  // Stop "listening" state
1374
  this.voiceBtn.classList.remove('listening');
1375
  this.voiceBtn.innerHTML = '<i class="fas fa-microphone"></i>';
1376
- this.voiceVisualizer.classList.remove('active');
1377
- this.chatStatusText.textContent = 'Online';
1378
- this.stopVoiceAnimation();
1379
 
1380
  // Update 3D visualization to processing mode
1381
  if (window.visualization) {
@@ -1384,41 +1429,16 @@
1384
  }
1385
  }
1386
 
1387
- startVoiceAnimation() {
1388
- const bars = this.voiceVisualizer.querySelectorAll('.voice-bar');
1389
- bars.forEach(bar => bar.classList.add('listening'));
1390
-
1391
- this.voiceAnimationInterval = setInterval(() => {
1392
- bars.forEach(bar => {
1393
- const randomHeight = 10 + Math.random() * 30;
1394
- bar.style.height = `${randomHeight}px`;
1395
- });
1396
- }, 100);
1397
- }
1398
-
1399
- stopVoiceAnimation() {
1400
- if (this.voiceAnimationInterval) {
1401
- clearInterval(this.voiceAnimationInterval);
1402
- this.voiceAnimationInterval = null;
1403
-
1404
- const bars = this.voiceVisualizer.querySelectorAll('.voice-bar');
1405
- bars.forEach(bar => {
1406
- bar.classList.remove('listening');
1407
- bar.style.height = '10px';
1408
- });
1409
- }
1410
- }
1411
-
1412
  simulateVoiceInput() {
1413
  if (!this.isListening) return;
1414
 
1415
  // Simulate capturing voice input
1416
  const simulatedQuestions = [
1417
- "Can you explain quantum computing?",
1418
- "How do neural networks learn?",
1419
- "What's the difference between AI and machine learning?",
1420
- "Help me understand blockchain technology",
1421
- "Explain the concept of derivatives in calculus"
1422
  ];
1423
 
1424
  const randomQuestion = simulatedQuestions[Math.floor(Math.random() * simulatedQuestions.length)];
@@ -1434,9 +1454,6 @@
1434
  this.isListening = false;
1435
  this.voiceBtn.classList.remove('listening');
1436
  this.voiceBtn.innerHTML = '<i class="fas fa-microphone"></i>';
1437
- this.voiceVisualizer.classList.remove('active');
1438
- this.stopVoiceAnimation();
1439
- this.chatStatusText.textContent = 'Online';
1440
  }, 500);
1441
  }
1442
 
@@ -1507,7 +1524,7 @@
1507
  this.addMessage(response, 'ai');
1508
 
1509
  // Speak the response if voice synthesis is available
1510
- if (window.voiceSynthesis) {
1511
  setTimeout(() => {
1512
  window.voiceSynthesis.speak(response);
1513
  }, 300);
@@ -1537,27 +1554,29 @@
1537
  }
1538
 
1539
  generateAIResponse(userMessage) {
1540
- // Simple AI response generator
1541
  const responses = {
1542
- quantum: "Quantum computing leverages quantum mechanics to process information. Unlike classical bits (0 or 1), quantum bits (qubits) can exist in superposition, enabling parallel computation. Key concepts include superposition, entanglement, and quantum interference.",
1543
- neural: "Neural networks learn through backpropagation and gradient descent. They adjust weights based on prediction errors, minimizing loss functions. Deep learning uses multiple layers to extract hierarchical features from data.",
1544
- blockchain: "Blockchain is a decentralized, distributed ledger technology. Each block contains cryptographic hashes linking to previous blocks, ensuring immutability. Smart contracts enable self-executing agreements on blockchain networks.",
1545
- calculus: "Derivatives measure instantaneous rate of change. The derivative of f(x) at point a is the slope of the tangent line. Differentiation rules include power, product, quotient, and chain rules for various functions.",
1546
- default: "I understand you're asking about " + userMessage.substring(0, 30) + "... This is a complex topic that requires careful explanation. Could you specify which aspect you'd like me to focus on? I can provide examples, applications, or fundamental principles."
 
1547
  };
1548
 
1549
  const lowerMessage = userMessage.toLowerCase();
1550
 
1551
  if (lowerMessage.includes('quantum')) return responses.quantum;
1552
  if (lowerMessage.includes('neural') || lowerMessage.includes('network')) return responses.neural;
 
1553
  if (lowerMessage.includes('blockchain')) return responses.blockchain;
1554
- if (lowerMessage.includes('calculus') || lowerMessage.includes('derivative')) return responses.calculus;
1555
 
1556
  return responses.default;
1557
  }
1558
  }
1559
 
1560
- // Main application - Merged Visualization
1561
  class AITutorVisualization {
1562
  constructor() {
1563
  if (!checkThreeJS()) return;
@@ -1565,16 +1584,7 @@
1565
  this.scene = null;
1566
  this.camera = null;
1567
  this.renderer = null;
1568
-
1569
- // Outer layer particles (original)
1570
- this.outerParticles = null;
1571
-
1572
- // Inner neural web components
1573
- this.neuralParticles = null;
1574
- this.neuralLines = null;
1575
- this.neuralCore = null;
1576
- this.particlePositions = [];
1577
-
1578
  this.controls = null;
1579
 
1580
  this.params = {
@@ -1590,20 +1600,19 @@
1590
 
1591
  try {
1592
  this.init();
1593
- this.createOuterParticles();
1594
- this.createNeuralWeb();
1595
  this.setupControls();
1596
  this.animate();
1597
- updateStatus('AI Interface Ready');
1598
  setTimeout(hideLoading, 500);
1599
  } catch (error) {
1600
  console.error('Initialization error:', error);
1601
- showError('Failed to initialize 3D scene: ' + error.message);
1602
  }
1603
  }
1604
 
1605
  init() {
1606
- updateStatus('Creating 3D scene...');
1607
 
1608
  // Scene
1609
  this.scene = new THREE.Scene();
@@ -1616,8 +1625,7 @@
1616
  0.1,
1617
  1000
1618
  );
1619
- this.camera.position.z = 8;
1620
- this.camera.position.y = 2;
1621
 
1622
  // Renderer
1623
  const canvas = document.getElementById('mainCanvas');
@@ -1633,203 +1641,72 @@
1633
  this.scene.fog = new THREE.Fog(0x0a0a0f, 10, 25);
1634
 
1635
  // Add lights
1636
- const ambientLight = new THREE.AmbientLight(0x222244, 0.6);
1637
  this.scene.add(ambientLight);
1638
 
1639
  const directionalLight = new THREE.DirectionalLight(0x5a6cff, 1);
1640
  directionalLight.position.set(5, 3, 5);
1641
  this.scene.add(directionalLight);
1642
 
1643
- const pointLight = new THREE.PointLight(0x00ff9d, 0.4, 10);
1644
- pointLight.position.set(-2, -1, 2);
1645
- this.scene.add(pointLight);
1646
-
1647
  // Orbit controls
1648
- updateStatus('Setting up controls...');
1649
  this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
1650
  this.controls.enableDamping = true;
1651
  this.controls.dampingFactor = 0.05;
1652
- this.controls.maxDistance = 15;
1653
- this.controls.minDistance = 3;
1654
  }
1655
 
1656
- createOuterParticles() {
1657
- updateStatus('Creating outer particles...');
1658
 
1659
  const geometry = new THREE.BufferGeometry();
1660
  const positions = new Float32Array(this.params.particleCount * 3);
1661
  const colors = new Float32Array(this.params.particleCount * 3);
1662
 
1663
- // Create outer shell particles (larger radius)
1664
  for (let i = 0; i < this.params.particleCount; i++) {
1665
  const i3 = i * 3;
1666
 
1667
- // Fibonacci sphere distribution for outer shell
1668
  const phi = Math.acos(-1 + (2 * i) / this.params.particleCount);
1669
  const theta = Math.sqrt(this.params.particleCount * Math.PI) * phi;
1670
 
1671
- // Outer particles have larger radius (4-6)
1672
- const radius = 4 + Math.random() * 2;
1673
-
1674
- const x = Math.cos(theta) * Math.sin(phi) * radius;
1675
- const y = Math.sin(theta) * Math.sin(phi) * radius;
1676
- const z = Math.cos(phi) * radius;
1677
 
1678
  positions[i3] = x;
1679
  positions[i3 + 1] = y;
1680
  positions[i3 + 2] = z;
1681
 
1682
- // Bluer colors for outer layer
1683
- colors[i3] = 0.2 + x * 0.3; // Red
1684
- colors[i3 + 1] = 0.3 + y * 0.4; // Green
1685
- colors[i3 + 2] = 0.9 + z * 0.1; // Blue
1686
  }
1687
 
1688
  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
1689
  geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
1690
 
1691
  const material = new THREE.PointsMaterial({
1692
- size: 0.04,
1693
- vertexColors: true,
1694
- transparent: true,
1695
- opacity: 0.6,
1696
- blending: THREE.AdditiveBlending,
1697
- sizeAttenuation: true
1698
- });
1699
-
1700
- this.outerParticles = new THREE.Points(geometry, material);
1701
- this.scene.add(this.outerParticles);
1702
- }
1703
-
1704
- createNeuralWeb() {
1705
- updateStatus('Creating neural web...');
1706
-
1707
- // Remove existing neural web if recreating
1708
- if (this.neuralParticles) this.scene.remove(this.neuralParticles);
1709
- if (this.neuralLines) this.scene.remove(this.neuralLines);
1710
- if (this.neuralCore) this.scene.remove(this.neuralCore);
1711
-
1712
- // Create neural particles (inner layer)
1713
- const neuralParticleCount = Math.min(800, this.params.particleCount / 3);
1714
- const particleGeometry = new THREE.BufferGeometry();
1715
- const positions = new Float32Array(neuralParticleCount * 3);
1716
- const colors = new Float32Array(neuralParticleCount * 3);
1717
-
1718
- this.particlePositions = [];
1719
-
1720
- // Create an organic neural network structure (smaller radius)
1721
- const layers = 5;
1722
- const particlesPerLayer = neuralParticleCount / layers;
1723
-
1724
- for (let i = 0; i < neuralParticleCount; i++) {
1725
- const i3 = i * 3;
1726
- const layer = Math.floor(i / particlesPerLayer);
1727
- const layerProgress = layer / layers;
1728
-
1729
- // Spherical coordinates with some noise (inner radius 1.0-2.0)
1730
- const radius = 1.0 + layerProgress * 1.0;
1731
- const theta = Math.random() * Math.PI * 2;
1732
- const phi = Math.acos(2 * Math.random() - 1);
1733
-
1734
- // Add organic noise
1735
- const noise = 0.2;
1736
- const x = radius * Math.sin(phi) * Math.cos(theta) + (Math.random() - 0.5) * noise;
1737
- const y = radius * Math.sin(phi) * Math.sin(theta) + (Math.random() - 0.5) * noise;
1738
- const z = radius * Math.cos(phi) + (Math.random() - 0.5) * noise;
1739
-
1740
- positions[i3] = x;
1741
- positions[i3 + 1] = y;
1742
- positions[i3 + 2] = z;
1743
-
1744
- this.particlePositions.push(new THREE.Vector3(x, y, z));
1745
-
1746
- // Warmer colors for neural web
1747
- const hue = 0.7 + (layer / layers) * 0.2; // Purple to pink gradient
1748
- const saturation = 0.9 - layerProgress * 0.3;
1749
- const brightness = 0.8 + (y / 2) * 0.2;
1750
-
1751
- colors[i3] = hue;
1752
- colors[i3 + 1] = saturation;
1753
- colors[i3 + 2] = brightness;
1754
- }
1755
-
1756
- particleGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
1757
- particleGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
1758
-
1759
- const particleMaterial = new THREE.PointsMaterial({
1760
- size: 0.02,
1761
  vertexColors: true,
1762
  transparent: true,
1763
- opacity: 0.9,
1764
- blending: THREE.AdditiveBlending,
1765
- sizeAttenuation: true
1766
  });
1767
 
1768
- this.neuralParticles = new THREE.Points(particleGeometry, particleMaterial);
1769
- this.scene.add(this.neuralParticles);
1770
-
1771
- // Create neural connections
1772
- this.createNeuralConnections();
1773
 
1774
- // Add central core (smaller for inner layer)
1775
- const coreGeometry = new THREE.IcosahedronGeometry(0.3, 2);
1776
- const coreMaterial = new THREE.MeshBasicMaterial({
1777
  color: 0x5a6cff,
1778
  wireframe: true,
1779
  transparent: true,
1780
- opacity: 0.4
1781
  });
1782
- this.neuralCore = new THREE.Mesh(coreGeometry, coreMaterial);
1783
- this.scene.add(this.neuralCore);
1784
- }
1785
-
1786
- createNeuralConnections() {
1787
- const lineGeometry = new THREE.BufferGeometry();
1788
- const linePositions = [];
1789
- const lineColors = [];
1790
-
1791
- // Connect nearby particles in neural web
1792
- const connectionDistance = 1.2;
1793
- const maxConnections = 3;
1794
-
1795
- for (let i = 0; i < this.particlePositions.length; i++) {
1796
- const source = this.particlePositions[i];
1797
- let connections = 0;
1798
-
1799
- for (let j = i + 1; j < this.particlePositions.length && connections < maxConnections; j++) {
1800
- const target = this.particlePositions[j];
1801
- const distance = source.distanceTo(target);
1802
-
1803
- if (distance < connectionDistance) {
1804
- // Add line from source to target
1805
- linePositions.push(source.x, source.y, source.z);
1806
- linePositions.push(target.x, target.y, target.z);
1807
-
1808
- // Line colors with gradient
1809
- const intensity = 1 - (distance / connectionDistance);
1810
- const color1 = new THREE.Color(0x5a6cff);
1811
- const color2 = new THREE.Color(0x00ff9d);
1812
-
1813
- lineColors.push(color1.r, color1.g, color1.b, intensity * 0.8);
1814
- lineColors.push(color2.r, color2.g, color2.b, intensity * 0.8);
1815
-
1816
- connections++;
1817
- }
1818
- }
1819
- }
1820
-
1821
- lineGeometry.setAttribute('position', new THREE.Float32BufferAttribute(linePositions, 3));
1822
- lineGeometry.setAttribute('color', new THREE.Float32BufferAttribute(lineColors, 4));
1823
-
1824
- const lineMaterial = new THREE.LineBasicMaterial({
1825
- vertexColors: true,
1826
- transparent: true,
1827
- opacity: 0.4,
1828
- linewidth: 1
1829
- });
1830
-
1831
- this.neuralLines = new THREE.LineSegments(lineGeometry, lineMaterial);
1832
- this.scene.add(this.neuralLines);
1833
  }
1834
 
1835
  setupControls() {
@@ -1877,9 +1754,7 @@
1877
 
1878
  // Update UI to show active preset
1879
  document.querySelectorAll('.preset-btn').forEach(btn => {
1880
- btn.style.background = btn.dataset.preset === preset
1881
- ? 'rgba(90, 108, 255, 0.4)'
1882
- : 'rgba(90, 108, 255, 0.1)';
1883
  });
1884
 
1885
  // Update status
@@ -1889,7 +1764,7 @@
1889
  'responding': '💬 Formulating response...',
1890
  'exploring': '🔍 Exploring concepts...',
1891
  'teaching': '📚 Teaching mode active',
1892
- 'idle': '🌀 AI Tutor Idle'
1893
  };
1894
 
1895
  if (statusMap[preset]) {
@@ -1898,13 +1773,10 @@
1898
  }
1899
 
1900
  updateParticleCount() {
1901
- if (this.outerParticles) {
1902
- this.scene.remove(this.outerParticles);
1903
  }
1904
- this.createOuterParticles();
1905
-
1906
- // Also recreate neural web with proportional size
1907
- this.createNeuralWeb();
1908
  }
1909
 
1910
  simulateAudioData() {
@@ -1919,172 +1791,77 @@
1919
  }
1920
  }
1921
 
1922
- updateOuterParticles() {
1923
- if (!this.outerParticles) return;
 
 
 
 
 
 
 
 
 
 
 
1924
 
1925
- const positions = this.outerParticles.geometry.attributes.position.array;
1926
- const colors = this.outerParticles.geometry.attributes.color.array;
1927
  const time = this.time;
1928
 
1929
  for (let i = 0; i < this.params.particleCount; i++) {
1930
  const i3 = i * 3;
 
 
 
1931
 
1932
- let wave = 0;
1933
- let pulse = 0;
1934
-
1935
- // Outer layer responds differently based on mode
1936
- switch(this.params.mode) {
1937
- case 'listening':
1938
- wave = Math.sin(time * 2 + i * 0.005) * 0.3;
1939
- pulse = Math.sin(time * 5) * 0.2;
1940
- break;
1941
- case 'processing':
1942
- wave = Math.sin(time * 3 + i * 0.01) * 0.4;
1943
- pulse = Math.sin(time * 7) * 0.25;
1944
- break;
1945
- case 'responding':
1946
- wave = (Math.sin(time * 1.5 + i * 0.003) + 1) * 0.25;
1947
- pulse = Math.sin(time * 4) * 0.3;
1948
- break;
1949
- case 'exploring':
1950
- wave = Math.sin(time * 1.2 + i * 0.008) * 0.35;
1951
- pulse = Math.sin(time * 3) * 0.2;
1952
- break;
1953
- case 'teaching':
1954
- wave = Math.sin(time * 2.5 + i * 0.006) * 0.3;
1955
- pulse = Math.sin(time * 6) * 0.25;
1956
- break;
1957
- default: // idle
1958
- wave = Math.sin(time * 0.5 + i * 0.002) * 0.15;
1959
- pulse = Math.sin(time * 2) * 0.1;
1960
- }
1961
-
1962
- // Original radius calculation (4-6)
1963
- const baseRadius = 4 + (i % 3) * 0.5;
1964
- const radius = baseRadius + wave * this.params.intensity + pulse * this.params.energy;
1965
-
1966
- // Get original spherical coordinates
1967
- const x0 = positions[i3];
1968
- const y0 = positions[i3 + 1];
1969
- const z0 = positions[i3 + 2];
1970
-
1971
- const originalRadius = Math.sqrt(x0*x0 + y0*y0 + z0*z0);
1972
- const scale = radius / originalRadius;
1973
 
1974
- // Update position
1975
- positions[i3] = x0 * scale;
1976
- positions[i3 + 1] = y0 * scale;
1977
- positions[i3 + 2] = z0 * scale;
1978
-
1979
- // Update color based on activity
1980
- const activity = Math.abs(wave) * this.params.intensity;
1981
- colors[i3] = 0.2 + activity * 0.3; // Red
1982
- colors[i3 + 1] = 0.3 + Math.sin(time * 2 + i * 0.01) * 0.2; // Green pulse
1983
- colors[i3 + 2] = 0.9 - activity * 0.2; // Blue
1984
- }
1985
-
1986
- this.outerParticles.geometry.attributes.position.needsUpdate = true;
1987
- this.outerParticles.geometry.attributes.color.needsUpdate = true;
1988
-
1989
- // Rotate outer particles slowly
1990
- this.outerParticles.rotation.y = time * 0.05;
1991
- this.outerParticles.rotation.x = Math.sin(time * 0.03) * 0.05;
1992
- }
1993
-
1994
- updateNeuralWeb() {
1995
- if (!this.neuralParticles || !this.particlePositions.length) return;
1996
-
1997
- const time = this.time;
1998
- const positions = this.neuralParticles.geometry.attributes.position.array;
1999
- const colors = this.neuralParticles.geometry.attributes.color.array;
2000
- const particleCount = this.particlePositions.length;
2001
-
2002
- // Update neural particles
2003
- for (let i = 0; i < particleCount; i++) {
2004
- const i3 = i * 3;
2005
-
2006
- let neuralWave = 0;
2007
  switch(this.params.mode) {
2008
  case 'listening':
2009
- neuralWave = Math.sin(time * 3 + i * 0.02) * 0.15;
2010
  break;
2011
  case 'processing':
2012
- neuralWave = Math.sin(time * 4 + i * 0.03) * 0.2;
2013
  break;
2014
  case 'responding':
2015
- neuralWave = (Math.sin(time * 2 + i * 0.015) + 1) * 0.12;
2016
  break;
2017
  case 'exploring':
2018
- neuralWave = Math.sin(time * 1.8 + i * 0.025) * 0.18;
2019
  break;
2020
  case 'teaching':
2021
- neuralWave = Math.sin(time * 3.5 + i * 0.02) * 0.16;
2022
  break;
2023
  default: // idle
2024
- neuralWave = Math.sin(time * 0.8 + i * 0.01) * 0.08;
2025
  }
2026
 
2027
- // Apply movement with intensity and energy (more subtle for inner layer)
2028
- const movement = neuralWave * this.params.intensity * this.params.energy * 0.5;
2029
-
2030
- // Update position with organic movement
2031
- positions[i3] += Math.sin(time * 1.2 + i) * 0.003 * movement;
2032
- positions[i3 + 1] += Math.cos(time * 0.8 + i) * 0.003 * movement;
2033
- positions[i3 + 2] += Math.sin(time * 0.5 + i) * 0.003 * movement;
2034
 
2035
- // Update stored positions
2036
- if (this.particlePositions[i]) {
2037
- this.particlePositions[i].set(positions[i3], positions[i3 + 1], positions[i3 + 2]);
2038
- }
2039
-
2040
- // Update color based on neural activity
2041
- const neuralActivity = Math.abs(neuralWave) * this.params.intensity;
2042
- colors[i3] = 0.7 + neuralActivity * 0.3; // Hue shift to warmer colors
2043
- colors[i3 + 1] = 0.9 - neuralActivity * 0.2; // Saturation
2044
- colors[i3 + 2] = 0.8 + Math.sin(time * 3 + i * 0.02) * 0.15; // Brightness pulse
2045
- }
2046
-
2047
- this.neuralParticles.geometry.attributes.position.needsUpdate = true;
2048
- this.neuralParticles.geometry.attributes.color.needsUpdate = true;
2049
-
2050
- // Update neural connections
2051
- if (this.neuralLines) {
2052
- const lineColors = this.neuralLines.geometry.attributes.color.array;
2053
 
2054
- for (let i = 0; i < lineColors.length; i += 8) {
2055
- const pulse = Math.sin(time * 3 + i * 0.02) * 0.3 + 0.5;
2056
- lineColors[i + 3] = pulse * this.params.intensity * 0.8;
2057
- lineColors[i + 7] = pulse * this.params.intensity * 0.8;
2058
- }
2059
 
2060
- this.neuralLines.geometry.attributes.color.needsUpdate = true;
 
 
 
 
2061
  }
2062
 
2063
- // Update core
2064
- if (this.neuralCore) {
2065
- this.neuralCore.rotation.y = time * 0.3;
2066
- this.neuralCore.rotation.x = time * 0.15;
2067
-
2068
- // Pulsing core based on mode
2069
- let corePulse = 0;
2070
- switch(this.params.mode) {
2071
- case 'processing':
2072
- corePulse = Math.sin(time * 8) * 0.2;
2073
- break;
2074
- case 'responding':
2075
- corePulse = (Math.sin(time * 6) + 1) * 0.15;
2076
- break;
2077
- default:
2078
- corePulse = Math.sin(time * 4) * 0.1;
2079
- }
2080
-
2081
- const scale = 1 + corePulse * this.params.energy;
2082
- this.neuralCore.scale.setScalar(scale);
2083
- }
2084
 
2085
- // Gentle rotation of neural web (different speed than outer layer)
2086
- this.neuralParticles.rotation.y = time * 0.08;
2087
- this.neuralParticles.rotation.x = Math.sin(time * 0.04) * 0.03;
2088
  }
2089
 
2090
  animate() {
@@ -2093,8 +1870,7 @@
2093
  this.time += 0.016;
2094
 
2095
  this.simulateAudioData();
2096
- this.updateNeuralWeb(); // Update inner neural web
2097
- this.updateOuterParticles(); // Update outer particle layer
2098
 
2099
  this.controls.update();
2100
  this.renderer.render(this.scene, this.camera);
@@ -2121,7 +1897,17 @@
2121
 
2122
  // Initialize when page loads
2123
  window.addEventListener('load', () => {
2124
- updateStatus('Loading AI Interface...');
 
 
 
 
 
 
 
 
 
 
2125
 
2126
  // Wait a moment for libraries to load
2127
  setTimeout(() => {
@@ -2155,12 +1941,21 @@
2155
  }
2156
  // Ctrl+Space to stop speech
2157
  if (e.code === 'Space' && e.ctrlKey && window.voiceSynthesis) {
2158
- window.voiceSynthesis.stopSpeaking();
 
 
 
 
2159
  }
2160
  });
2161
 
2162
  // Set initial preset
2163
  window.visualization.setPreset('idle');
 
 
 
 
 
2164
  }
2165
  }, 100);
2166
  });
@@ -2171,7 +1966,7 @@
2171
  window.visualization.destroy();
2172
  }
2173
  if (window.voiceSynthesis) {
2174
- window.voiceSynthesis.stopSpeaking();
2175
  }
2176
  });
2177
  </script>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Neural AI Tutor | Interactive Learning Platform</title>
7
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
8
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
9
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
 
20
  font-family: 'Segoe UI', system-ui, sans-serif;
21
  overflow: hidden;
22
  height: 100vh;
23
+ display: flex;
24
  }
25
 
26
+ /* Main Canvas - Prominently Displayed */
27
  #canvasContainer {
28
+ flex: 1;
 
29
  position: relative;
30
+ background: linear-gradient(135deg, #0a0a0f 0%, #0f0f1a 100%);
31
  }
32
 
33
  canvas {
34
  display: block;
 
35
  width: 100%;
36
  height: 100%;
37
  }
38
 
39
+ /* Left Sidebar - Hidden Panels */
40
+ .sidebar {
41
+ width: 80px;
42
+ background: rgba(15, 15, 25, 0.9);
43
+ backdrop-filter: blur(10px);
44
+ border-right: 1px solid rgba(255, 255, 255, 0.05);
45
+ display: flex;
46
+ flex-direction: column;
47
+ align-items: center;
48
+ padding: 20px 10px;
49
+ z-index: 1000;
50
+ transition: width 0.3s ease;
51
  }
52
 
53
+ .sidebar:hover,
54
+ .sidebar.expanded {
55
+ width: 380px;
56
+ }
57
+
58
+ .sidebar:hover .panel-content,
59
+ .sidebar.expanded .panel-content {
60
+ opacity: 1;
61
+ visibility: visible;
62
+ }
63
+
64
+ .panel-toggle {
65
+ width: 100%;
66
  display: flex;
67
+ align-items: center;
68
+ justify-content: center;
69
+ margin-bottom: 30px;
70
+ padding: 15px 0;
71
+ cursor: pointer;
72
+ border-radius: 12px;
73
+ transition: all 0.3s ease;
74
+ background: rgba(90, 108, 255, 0.1);
75
+ border: 1px solid rgba(90, 108, 255, 0.2);
76
+ }
77
+
78
+ .panel-toggle:hover {
79
+ background: rgba(90, 108, 255, 0.2);
80
+ transform: translateY(-2px);
81
+ }
82
+
83
+ .toggle-icon {
84
+ font-size: 1.5em;
85
+ color: #a0b0ff;
86
+ }
87
+
88
+ .panel-content {
89
+ width: 100%;
90
  opacity: 0;
91
+ visibility: hidden;
92
+ transition: all 0.3s ease;
93
+ overflow-y: auto;
94
+ max-height: calc(100vh - 120px);
95
  }
96
 
97
+ .panel-section {
98
+ margin-bottom: 25px;
99
+ background: rgba(20, 20, 30, 0.7);
100
+ border-radius: 15px;
101
+ border: 1px solid rgba(255, 255, 255, 0.05);
102
+ overflow: hidden;
103
  }
104
 
105
+ .panel-header {
106
+ padding: 15px;
107
+ background: rgba(30, 30, 45, 0.8);
108
+ cursor: pointer;
 
 
 
 
109
  display: flex;
110
  align-items: center;
111
  justify-content: space-between;
112
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
113
  }
114
 
115
+ .panel-header:hover {
116
+ background: rgba(40, 40, 60, 0.8);
117
+ }
118
+
119
+ .panel-header h3 {
120
  color: #a0b0ff;
121
+ font-size: 1em;
122
+ font-weight: 500;
123
  display: flex;
124
  align-items: center;
125
  gap: 10px;
126
  }
127
 
128
+ .panel-header i {
129
+ font-size: 1.2em;
 
 
 
 
130
  }
131
 
132
+ .panel-body {
133
+ padding: 20px;
134
+ display: none;
 
 
 
135
  }
136
 
137
+ .panel-body.active {
138
+ display: block;
139
+ }
140
+
141
+ .chevron {
142
+ transition: transform 0.3s ease;
143
+ }
144
+
145
+ .chevron.rotated {
146
+ transform: rotate(90deg);
147
+ }
148
+
149
+ /* Chat Interface - Centered on Page */
150
+ .chat-overlay {
151
+ position: absolute;
152
+ top: 50%;
153
+ left: 50%;
154
+ transform: translate(-50%, -50%);
155
+ width: 500px;
156
+ max-width: 90vw;
157
  background: rgba(20, 20, 30, 0.85);
158
+ backdrop-filter: blur(20px);
159
+ border-radius: 20px;
160
  border: 1px solid rgba(255, 255, 255, 0.1);
161
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3);
162
+ z-index: 100;
163
  display: flex;
164
  flex-direction: column;
165
+ overflow: hidden;
166
+ opacity: 0;
167
+ animation: fadeIn 0.5s ease 1s forwards;
168
  }
169
 
170
+ @keyframes fadeIn {
171
+ to {
172
+ opacity: 1;
173
+ }
174
+ }
175
+
176
+ .chat-header {
177
+ padding: 25px;
178
+ background: rgba(25, 25, 40, 0.9);
179
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
180
+ }
181
+
182
+ .chat-title {
183
  display: flex;
184
+ align-items: center;
185
+ gap: 15px;
186
+ margin-bottom: 10px;
 
187
  }
188
 
189
+ .chat-title h2 {
190
+ color: #a0b0ff;
191
+ font-weight: 400;
192
+ font-size: 1.5em;
193
  }
194
 
195
+ .ai-avatar {
196
+ width: 50px;
197
+ height: 50px;
198
+ background: linear-gradient(135deg, #5a6cff, #00ff9d);
199
+ border-radius: 50%;
200
+ display: flex;
201
+ align-items: center;
202
+ justify-content: center;
203
+ font-size: 1.5em;
204
  }
205
 
206
+ .chat-subtitle {
207
+ color: #8892b0;
208
+ font-size: 0.9em;
209
+ line-height: 1.5;
210
+ }
211
+
212
+ .chat-messages {
213
+ flex: 1;
214
+ padding: 25px;
215
+ overflow-y: auto;
216
+ max-height: 400px;
217
+ display: flex;
218
+ flex-direction: column;
219
+ gap: 20px;
220
  }
221
 
222
  .message {
223
  max-width: 85%;
224
+ padding: 18px;
225
  border-radius: 18px;
226
  line-height: 1.5;
227
  position: relative;
 
248
 
249
  .message-ai {
250
  align-self: flex-start;
251
+ background: rgba(255, 255, 255, 0.08);
252
  color: #e0e0ff;
253
  border-bottom-left-radius: 5px;
254
  border: 1px solid rgba(255, 255, 255, 0.05);
255
  }
256
 
257
  .message-time {
258
+ font-size: 0.75em;
259
  opacity: 0.7;
260
+ margin-top: 8px;
261
  text-align: right;
262
  }
263
 
 
290
  }
291
 
292
  .chat-input-container {
293
+ padding: 25px;
294
  background: rgba(15, 15, 25, 0.9);
295
  border-top: 1px solid rgba(255, 255, 255, 0.05);
296
  }
297
 
298
  .input-wrapper {
299
  display: flex;
300
+ gap: 12px;
301
  align-items: flex-end;
302
  }
303
 
 
306
  background: rgba(255, 255, 255, 0.07);
307
  border: 1px solid rgba(255, 255, 255, 0.1);
308
  border-radius: 15px;
309
+ padding: 18px 20px;
310
  color: white;
311
  font-family: 'Segoe UI', system-ui, sans-serif;
312
  font-size: 1em;
 
327
  color: rgba(255, 255, 255, 0.4);
328
  }
329
 
330
+ .input-buttons {
331
+ display: flex;
332
+ flex-direction: column;
333
+ gap: 8px;
334
+ }
335
+
336
+ .voice-input-btn,
337
+ .send-btn {
338
  width: 56px;
339
  height: 56px;
340
  border-radius: 15px;
 
346
  align-items: center;
347
  justify-content: center;
348
  transition: all 0.3s ease;
349
+ font-size: 1.2em;
350
  }
351
 
352
+ .voice-input-btn:hover,
353
+ .send-btn:hover {
354
  transform: translateY(-2px);
355
  box-shadow: 0 5px 15px rgba(90, 108, 255, 0.4);
356
  }
 
366
  }
367
 
368
  .send-btn {
369
+ background: rgba(0, 255, 157, 0.2);
370
+ border: 1px solid rgba(0, 255, 157, 0.3);
371
+ color: #00ff9d;
 
 
 
 
 
 
 
 
 
372
  }
373
 
374
  .send-btn:hover {
375
+ background: rgba(0, 255, 157, 0.3);
376
+ }
377
+
378
+ /* Control Elements in Sidebar */
379
+ .control-group {
380
+ margin-bottom: 20px;
381
  }
382
 
383
+ .control-label {
 
384
  display: flex;
385
  align-items: center;
386
+ gap: 10px;
387
+ margin-bottom: 10px;
388
+ color: #a0b0ff;
389
+ font-size: 0.9em;
390
+ font-weight: 500;
391
  }
392
 
393
+ .slider-container {
394
+ display: flex;
395
+ align-items: center;
396
+ gap: 15px;
397
  }
398
 
399
+ input[type="range"] {
400
+ flex: 1;
401
+ height: 6px;
402
+ background: rgba(255, 255, 255, 0.1);
403
+ border-radius: 3px;
404
+ outline: none;
405
+ -webkit-appearance: none;
406
+ }
407
+
408
+ input[type="range"]::-webkit-slider-thumb {
409
+ -webkit-appearance: none;
410
+ width: 20px;
411
+ height: 20px;
412
  background: #5a6cff;
413
+ border-radius: 50%;
414
+ cursor: pointer;
415
+ transition: all 0.2s;
416
+ }
417
+
418
+ input[type="range"]::-webkit-slider-thumb:hover {
419
+ background: #7a8aff;
420
+ transform: scale(1.1);
421
  }
422
 
423
+ .value-display {
424
+ min-width: 40px;
425
+ text-align: center;
426
+ font-family: 'Courier New', monospace;
427
+ color: #5a6cff;
428
+ font-weight: 500;
429
+ font-size: 0.9em;
430
  }
431
 
432
+ .preset-buttons {
433
+ display: grid;
434
+ grid-template-columns: repeat(2, 1fr);
435
+ gap: 8px;
436
+ margin-top: 15px;
 
 
 
 
 
 
 
 
 
 
 
 
437
  }
438
 
439
+ .preset-btn {
440
+ padding: 10px;
441
+ background: rgba(90, 108, 255, 0.1);
442
+ border: 1px solid rgba(90, 108, 255, 0.3);
 
443
  color: #a0b0ff;
444
+ border-radius: 10px;
445
+ cursor: pointer;
446
+ transition: all 0.2s;
447
+ font-size: 0.85em;
448
+ text-align: center;
449
  }
450
 
451
+ .preset-btn:hover {
452
+ background: rgba(90, 108, 255, 0.2);
453
+ transform: translateY(-2px);
454
  }
455
 
456
+ .preset-btn.active {
457
+ background: rgba(90, 108, 255, 0.4);
458
+ color: white;
459
+ }
460
+
461
+ .voice-control-group {
462
+ margin-bottom: 20px;
 
463
  }
464
 
465
  .voice-select {
 
488
  padding: 10px;
489
  }
490
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  .voice-control-buttons {
492
  display: grid;
493
  grid-template-columns: 1fr 1fr;
494
  gap: 10px;
495
+ margin-top: 15px;
496
  }
497
 
498
  .voice-btn {
 
537
  .voice-preview-btn {
538
  width: 100%;
539
  padding: 12px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
540
  background: rgba(0, 255, 157, 0.1);
541
+ border: 1px solid rgba(0, 255, 157, 0.3);
542
  border-radius: 10px;
543
+ color: #00ff9d;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
544
  cursor: pointer;
545
+ transition: all 0.3s ease;
546
+ display: flex;
547
+ align-items: center;
548
+ justify-content: center;
549
+ gap: 8px;
550
+ margin-top: 10px;
551
  font-size: 0.9em;
 
552
  }
553
 
554
+ .voice-preview-btn:hover {
555
+ background: rgba(0, 255, 157, 0.2);
556
  transform: translateY(-2px);
557
  }
558
 
559
+ .voice-status {
560
+ display: flex;
561
+ align-items: center;
562
+ gap: 8px;
563
+ margin-top: 15px;
564
+ padding: 10px;
565
+ background: rgba(0, 255, 157, 0.1);
566
+ border-radius: 10px;
567
+ font-size: 0.85em;
568
+ color: #00ff9d;
569
+ border: 1px solid rgba(0, 255, 157, 0.2);
570
+ }
571
+
572
+ /* System Status Bar */
573
  .status-bar {
574
  position: absolute;
575
+ top: 20px;
576
+ right: 20px;
577
  background: rgba(20, 20, 30, 0.8);
578
  backdrop-filter: blur(10px);
579
+ padding: 12px 20px;
580
+ border-radius: 12px;
581
+ font-size: 0.85em;
582
  color: #8892b0;
583
  border: 1px solid rgba(255, 255, 255, 0.1);
584
+ display: flex;
585
+ align-items: center;
586
+ gap: 10px;
587
  }
588
 
589
  .pulse-indicator {
 
590
  width: 12px;
591
  height: 12px;
592
  background: #00ff9d;
593
  border-radius: 50%;
 
594
  animation: pulse 2s infinite;
595
  }
596
 
 
599
  50% { opacity: 0.3; }
600
  }
601
 
602
+ /* Loading and Error Screens */
603
  .loading-screen {
604
  position: absolute;
605
  top: 0;
 
611
  flex-direction: column;
612
  justify-content: center;
613
  align-items: center;
614
+ z-index: 2000;
615
  }
616
 
617
  .spinner {
 
639
  flex-direction: column;
640
  justify-content: center;
641
  align-items: center;
642
+ z-index: 2001;
643
  text-align: center;
644
  padding: 20px;
645
  }
 
671
  transform: translateY(-2px);
672
  }
673
 
674
+ /* Responsive Design */
675
+ @media (max-width: 1200px) {
676
+ .chat-overlay {
677
+ width: 450px;
 
 
 
 
 
678
  }
679
  }
680
 
681
+ @media (max-width: 768px) {
682
+ body {
683
+ flex-direction: column;
684
+ }
685
+
686
+ .sidebar {
687
+ width: 100%;
688
+ height: 60px;
689
+ flex-direction: row;
690
+ padding: 10px;
691
  }
692
 
693
+ .sidebar:hover,
694
+ .sidebar.expanded {
695
+ height: auto;
696
+ min-height: 300px;
697
+ }
698
+
699
+ .panel-content {
700
+ position: absolute;
701
+ top: 60px;
702
+ left: 0;
703
+ width: 100%;
704
+ background: rgba(15, 15, 25, 0.95);
705
  padding: 20px;
 
706
  }
707
+
708
+ .chat-overlay {
709
+ width: 95%;
710
+ top: 40%;
711
+ }
712
+ }
713
+
714
+ /* Scrollbar Styling */
715
+ ::-webkit-scrollbar {
716
+ width: 8px;
717
+ }
718
+
719
+ ::-webkit-scrollbar-track {
720
+ background: rgba(255, 255, 255, 0.05);
721
+ border-radius: 4px;
722
+ }
723
+
724
+ ::-webkit-scrollbar-thumb {
725
+ background: #5a6cff;
726
+ border-radius: 4px;
727
+ }
728
+
729
+ ::-webkit-scrollbar-thumb:hover {
730
+ background: #7a8aff;
731
  }
732
  </style>
733
  </head>
734
  <body>
735
+ <!-- Left Sidebar with Collapsible Panels -->
736
+ <div class="sidebar" id="sidebar">
737
+ <div class="panel-toggle" onclick="toggleSidebar()">
738
+ <i class="fas fa-bars toggle-icon"></i>
 
 
 
 
 
739
  </div>
740
 
741
+ <div class="panel-content">
742
+ <!-- Visualization Controls -->
743
+ <div class="panel-section">
744
+ <div class="panel-header" onclick="togglePanel('visualizationPanel')">
745
+ <h3><i class="fas fa-brain"></i> Visualization Controls</h3>
746
+ <i class="fas fa-chevron-right chevron" id="visualizationChevron"></i>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
747
  </div>
748
+ <div class="panel-body" id="visualizationPanel">
749
+ <div class="control-group">
750
+ <div class="control-label">
751
+ <i class="fas fa-wave-square"></i>
752
+ <span>Animation Intensity</span>
753
+ </div>
754
+ <div class="slider-container">
755
+ <input type="range" id="intensity" min="0" max="100" value="50">
756
+ <span class="value-display" id="intensityValue">50</span>
757
+ </div>
758
+ </div>
759
+
760
+ <div class="control-group">
761
+ <div class="control-label">
762
+ <i class="fas fa-atom"></i>
763
+ <span>Particle Count</span>
764
+ </div>
765
+ <div class="slider-container">
766
+ <input type="range" id="particleCount" min="100" max="5000" value="2000" step="100">
767
+ <span class="value-display" id="particleCountValue">2000</span>
768
+ </div>
769
+ </div>
770
+
771
+ <div class="control-group">
772
+ <div class="control-label">
773
+ <i class="fas fa-bolt"></i>
774
+ <span>Energy Level</span>
775
+ </div>
776
+ <div class="slider-container">
777
+ <input type="range" id="energy" min="0" max="100" value="30">
778
+ <span class="value-display" id="energyValue">30</span>
779
+ </div>
780
+ </div>
781
+
782
+ <div class="preset-buttons">
783
+ <button class="preset-btn" data-preset="listening">🎤 Listening</button>
784
+ <button class="preset-btn" data-preset="processing">⚡ Processing</button>
785
+ <button class="preset-btn" data-preset="responding">💬 Responding</button>
786
+ <button class="preset-btn" data-preset="exploring">🔍 Exploring</button>
787
+ <button class="preset-btn" data-preset="teaching">📚 Teaching</button>
788
+ <button class="preset-btn" data-preset="idle">🌀 Idle</button>
789
+ </div>
790
  </div>
791
  </div>
792
 
793
+ <!-- Voice Controls -->
794
+ <div class="panel-section">
795
+ <div class="panel-header" onclick="togglePanel('voicePanel')">
796
+ <h3><i class="fas fa-robot"></i> Voice Synthesis</h3>
797
+ <i class="fas fa-chevron-right chevron" id="voiceChevron"></i>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
798
  </div>
799
+ <div class="panel-body" id="voicePanel">
800
+ <div class="voice-control-group">
801
+ <div class="control-label">
802
+ <i class="fas fa-user-circle"></i>
803
+ <span>Voice Selection</span>
 
 
 
 
 
 
 
804
  </div>
805
+ <select class="voice-select" id="voiceSelect">
806
+ <option value="">Loading voices...</option>
807
+ </select>
808
  </div>
809
 
810
+ <div class="voice-control-group">
811
+ <div class="control-label">
812
+ <i class="fas fa-tachometer-alt"></i>
813
+ <span>Speech Rate</span>
814
+ </div>
815
+ <div class="slider-container">
816
+ <input type="range" class="voice-slider" id="rateSlider" min="0.5" max="2" step="0.1" value="1">
817
+ <span class="value-display" id="rateValue">1.0x</span>
818
  </div>
 
819
  </div>
820
 
821
+ <div class="voice-control-group">
822
+ <div class="control-label">
823
+ <i class="fas fa-wave-square"></i>
824
+ <span>Pitch Variation</span>
825
+ </div>
826
+ <div class="slider-container">
827
+ <input type="range" class="voice-slider" id="pitchSlider" min="0.5" max="2" step="0.1" value="1">
828
+ <span class="value-display" id="pitchValue">1.0</span>
829
+ </div>
830
  </div>
831
+
832
+ <div class="voice-control-group">
833
+ <div class="control-label">
834
+ <i class="fas fa-volume-up"></i>
835
+ <span>Volume Level</span>
836
+ </div>
837
+ <div class="slider-container">
838
+ <input type="range" class="voice-slider" id="volumeSlider" min="0.1" max="1" step="0.1" value="0.8">
839
+ <span class="value-display" id="volumeValue">80%</span>
840
+ </div>
841
+ </div>
842
+
843
+ <div class="voice-control-buttons">
844
+ <button class="voice-btn" id="autoSpeakBtn" data-enabled="true">
845
+ <i class="fas fa-bullhorn"></i>
846
+ Auto-Speak
847
  </button>
848
+ <button class="voice-btn stop" id="stopBtn">
849
+ <i class="fas fa-stop"></i>
850
+ Stop
851
  </button>
852
  </div>
853
 
854
+ <button class="voice-preview-btn" id="previewBtn">
855
+ <i class="fas fa-play"></i>
856
+ Preview Voice (Little Red Riding Hood)
857
+ </button>
858
+
859
+ <div class="voice-status" id="voiceStatus" style="display: none;">
860
+ <i class="fas fa-comment-dots"></i>
861
+ <span id="statusMessage">Speaking...</span>
 
 
 
862
  </div>
863
  </div>
864
  </div>
 
 
 
 
 
 
 
865
 
866
+ <!-- System Info -->
867
+ <div class="panel-section">
868
+ <div class="panel-header" onclick="togglePanel('systemPanel')">
869
+ <h3><i class="fas fa-info-circle"></i> System Info</h3>
870
+ <i class="fas fa-chevron-right chevron" id="systemChevron"></i>
871
+ </div>
872
+ <div class="panel-body" id="systemPanel">
873
+ <div class="control-group">
874
+ <div class="control-label">
875
+ <i class="fas fa-cube"></i>
876
+ <span>3D Renderer</span>
877
+ </div>
878
+ <div style="color: #8892b0; font-size: 0.9em; padding: 10px 0;">
879
+ Three.js v128<br>
880
+ WebGL 2.0 Enabled
881
+ </div>
882
+ </div>
883
+
884
+ <div class="control-group">
885
+ <div class="control-label">
886
+ <i class="fas fa-microchip"></i>
887
+ <span>Performance</span>
888
+ </div>
889
+ <div style="color: #8892b0; font-size: 0.9em; padding: 10px 0;">
890
+ <div id="fpsCounter">FPS: 60</div>
891
+ <div id="particleCounter">Particles: 2000</div>
892
+ </div>
893
+ </div>
894
  </div>
895
  </div>
896
+ </div>
897
+ </div>
898
+
899
+ <!-- Main Visualization Canvas -->
900
+ <div id="canvasContainer">
901
+ <canvas id="mainCanvas"></canvas>
902
+
903
+ <!-- Status Bar -->
904
+ <div class="status-bar">
905
+ <span class="pulse-indicator"></span>
906
+ <span id="statusText">Neural AI Tutor Ready</span>
907
+ </div>
908
+
909
+ <!-- Centered Chat Interface -->
910
+ <div class="chat-overlay">
911
+ <div class="chat-header">
912
+ <div class="chat-title">
913
+ <div class="ai-avatar">
914
+ <i class="fas fa-brain"></i>
915
+ </div>
916
+ <div>
917
+ <h2>Neural AI Tutor</h2>
918
+ <div class="chat-subtitle">
919
+ Interactive learning assistant with neural visualization
920
+ </div>
921
+ </div>
922
  </div>
923
  </div>
924
 
925
+ <div class="chat-messages" id="chatMessages">
926
+ <div class="message message-ai">
927
+ <div class="message-content">
928
+ Welcome to the Neural AI Tutor! I'm your interactive learning assistant.
929
+ I can help explain complex concepts, answer questions, and guide your learning journey.
930
+ What would you like to learn about today?
931
+ </div>
932
+ <div class="message-time">Just now</div>
933
+ </div>
934
+
935
+ <div class="message message-ai">
936
+ <div class="message-content">
937
+ You can type your questions or use voice input. The neural visualization
938
+ responds to our conversation, showing how knowledge connects in real-time.
939
+ </div>
940
+ <div class="message-time">Just now</div>
941
+ </div>
942
+
943
+ <!-- Typing indicator (hidden by default) -->
944
+ <div class="message-typing" id="typingIndicator" style="display: none;">
945
+ <div class="typing-dot"></div>
946
+ <div class="typing-dot"></div>
947
+ <div class="typing-dot"></div>
948
  </div>
949
  </div>
950
 
951
+ <div class="chat-input-container">
952
+ <div class="input-wrapper">
953
+ <textarea
954
+ class="chat-input"
955
+ id="chatInput"
956
+ placeholder="Ask me anything about science, math, technology, or any subject..."
957
+ rows="1"
958
+ ></textarea>
959
+
960
+ <div class="input-buttons">
961
+ <button class="voice-input-btn" id="voiceBtn" title="Start voice input">
962
+ <i class="fas fa-microphone"></i>
963
+ </button>
964
+
965
+ <button class="send-btn" id="sendBtn" title="Send message">
966
+ <i class="fas fa-paper-plane"></i>
967
+ </button>
968
+ </div>
969
+ </div>
970
  </div>
971
  </div>
972
 
973
+ <!-- Loading Screen -->
974
  <div class="loading-screen" id="loadingScreen">
975
  <div class="spinner"></div>
976
+ <div id="loadingText">Initializing Neural AI Tutor...</div>
977
  </div>
978
 
979
+ <!-- Error Screen -->
980
  <div class="error-screen" id="errorScreen">
981
+ <h2>⚠️ System Initialization Failed</h2>
982
+ <p id="errorMessage">Unable to load 3D visualization engine. Please check your browser compatibility or try again.</p>
983
+ <button class="retry-btn" id="retryBtn">Retry Initialization</button>
984
  </div>
985
  </div>
986
 
987
  <script>
988
+ // Sidebar and Panel Management
989
+ function toggleSidebar() {
990
+ const sidebar = document.getElementById('sidebar');
991
+ sidebar.classList.toggle('expanded');
992
+ }
993
+
994
+ function togglePanel(panelId) {
995
+ const panel = document.getElementById(panelId);
996
+ const chevron = document.getElementById(panelId.replace('Panel', 'Chevron'));
997
+
998
+ panel.classList.toggle('active');
999
+ chevron.classList.toggle('rotated');
1000
+ }
1001
+
1002
  // Check if Three.js loaded properly
1003
  function checkThreeJS() {
1004
  if (typeof THREE === 'undefined') {
 
1048
  volume: 0.8
1049
  };
1050
 
1051
+ // Little Red Riding Hood story for voice preview
1052
+ this.testScript = "Once upon a time, there was a little girl who lived in a village near the forest. " +
1053
+ "Whenever she went out, the little girl wore a red riding cloak, so everyone in the village called her Little Red Riding Hood. " +
1054
+ "One morning, Little Red Riding Hood asked her mother if she could go to visit her grandmother as it had been awhile since they'd seen each other. " +
1055
+ "That's a wonderful idea, her mother said. So they packed a nice basket for Little Red Riding Hood to take to her grandmother. " +
1056
+ "When the basket was ready, the little girl put on her red cloak and kissed her mother goodbye. " +
1057
+ "Remember, go straight to Grandma's house, her mother cautioned. Don't dawdle along the way and please don't talk to strangers! " +
1058
+ "The woods are dangerous. I will be careful, Little Red Riding Hood promised her mother. " +
1059
+ "The grandmother lived out in the woods, a half hour from the village. When Little Red Riding Hood entered the woods a wolf came up to her. " +
1060
+ "She did not know what a wicked animal he was, and was not afraid of him. Good day, Little Red Riding Hood, said the wolf. " +
1061
+ "Thank you kindly, wolf, she replied. Where are you going so early, Little Red Riding Hood? " +
1062
+ "To my grandmother's house. What do you have there in your basket? " +
1063
+ "Cake and wine. Yesterday was baking day, so poor sick grandmother is to have something good, to make her stronger. " +
1064
+ "Where does your grandmother live, Little Red Riding Hood? A good quarter of an hour farther in the woods. " +
1065
+ "Her house is under the three large oak trees. You can tell by the nut trees which are below. " +
1066
+ "The wolf thought to himself, What a tender young creature! What a nice plump mouthful! She will be better to eat than the old woman. " +
1067
+ "I must act craftily, so as to catch both. So he walked for a short time by Little Red Riding Hood's side, and then he said, " +
1068
+ "See, Little Red Riding Hood, how pretty the flowers are about here! Why do you not look around? " +
1069
+ "I believe, too, that you do not hear how sweetly the little birds are singing. " +
1070
+ "You walk gravely along as if you were going to school, while everything else out here in the wood is merry. " +
1071
+ "Little Red Riding Hood raised her eyes, and when she saw the sunbeams dancing here and there through the trees, and pretty flowers growing everywhere, " +
1072
+ "she thought, Suppose I take grandmother a fresh nosegay. That would please her too. It is so early in the day that I shall still get there in good time. " +
1073
+ "And so she ran from the path into the woods to look for flowers. And whenever she had picked one, she fancied that she saw a still prettier one farther on, " +
1074
+ "and ran after it, and so got deeper and deeper into the woods.";
1075
 
1076
  this.initVoices();
1077
  this.setupEventListeners();
 
1108
  return;
1109
  }
1110
 
1111
+ // Prioritize natural-sounding voices
1112
  const preferredVoices = [
1113
  'Google UK English Male',
1114
  'Google US English',
 
1119
  'Daniel',
1120
  'Karen',
1121
  'Moira',
1122
+ 'Tessa'
 
 
1123
  ];
1124
 
1125
  // Try to find a preferred voice
 
1252
  this.showStatus(this.isAutoSpeak ? 'Auto-speak enabled' : 'Auto-speak disabled', 2000);
1253
  });
1254
 
1255
+ // Stop button - immediately stops all speech
1256
  document.getElementById('stopBtn').addEventListener('click', () => {
1257
+ this.stopAllSpeech();
1258
  });
1259
 
1260
+ // Preview button - reads Little Red Riding Hood
1261
  document.getElementById('previewBtn').addEventListener('click', () => {
1262
  this.previewCurrentVoice();
1263
  });
 
1291
  speak(text) {
1292
  if (!this.isAutoSpeak || !text || this.isSpeaking) return;
1293
 
1294
+ this.stopAllSpeech();
1295
 
1296
  const utterance = new SpeechSynthesisUtterance(text);
1297
 
 
1303
  utterance.pitch = this.settings.pitch;
1304
  utterance.volume = this.settings.volume;
1305
 
 
 
 
1306
  // Event listeners for this utterance
1307
  utterance.onerror = (event) => {
1308
  console.error('Speech synthesis error:', event);
 
1313
  this.synth.speak(utterance);
1314
  }
1315
 
1316
+ // Stops ALL speech immediately
1317
+ stopAllSpeech() {
1318
+ if (this.synth.speaking) {
1319
+ this.synth.cancel(); // This stops ALL utterances immediately
 
 
 
 
 
 
 
 
1320
  this.isSpeaking = false;
1321
  this.currentUtterance = null;
1322
  document.getElementById('stopBtn').classList.remove('active');
 
1325
  }
1326
 
1327
  previewCurrentVoice() {
1328
+ this.stopAllSpeech();
1329
  this.speak(this.testScript);
1330
+ this.showStatus('Reading: Little Red Riding Hood', 3000);
1331
  }
1332
 
1333
  showStatus(message, duration = null) {
 
1360
  class ChatInterface {
1361
  constructor() {
1362
  this.isListening = false;
 
1363
  this.initChat();
1364
  }
1365
 
 
1368
  this.chatMessages = document.getElementById('chatMessages');
1369
  this.voiceBtn = document.getElementById('voiceBtn');
1370
  this.sendBtn = document.getElementById('sendBtn');
 
1371
  this.typingIndicator = document.getElementById('typingIndicator');
 
1372
 
1373
  this.setupEventListeners();
1374
  this.autoResizeTextarea();
 
1407
  // Start "listening" state
1408
  this.voiceBtn.classList.add('listening');
1409
  this.voiceBtn.innerHTML = '<i class="fas fa-stop"></i>';
 
 
 
1410
 
1411
  // Update 3D visualization to listening mode
1412
  if (window.visualization) {
 
1421
  // Stop "listening" state
1422
  this.voiceBtn.classList.remove('listening');
1423
  this.voiceBtn.innerHTML = '<i class="fas fa-microphone"></i>';
 
 
 
1424
 
1425
  // Update 3D visualization to processing mode
1426
  if (window.visualization) {
 
1429
  }
1430
  }
1431
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1432
  simulateVoiceInput() {
1433
  if (!this.isListening) return;
1434
 
1435
  // Simulate capturing voice input
1436
  const simulatedQuestions = [
1437
+ "Can you explain quantum computing in simple terms?",
1438
+ "How do neural networks actually learn from data?",
1439
+ "What's the difference between artificial intelligence and machine learning?",
1440
+ "Could you help me understand how blockchain technology works?",
1441
+ "Explain the concept of derivatives in calculus for beginners"
1442
  ];
1443
 
1444
  const randomQuestion = simulatedQuestions[Math.floor(Math.random() * simulatedQuestions.length)];
 
1454
  this.isListening = false;
1455
  this.voiceBtn.classList.remove('listening');
1456
  this.voiceBtn.innerHTML = '<i class="fas fa-microphone"></i>';
 
 
 
1457
  }, 500);
1458
  }
1459
 
 
1524
  this.addMessage(response, 'ai');
1525
 
1526
  // Speak the response if voice synthesis is available
1527
+ if (window.voiceSynthesis && window.voiceSynthesis.isAutoSpeak) {
1528
  setTimeout(() => {
1529
  window.voiceSynthesis.speak(response);
1530
  }, 300);
 
1554
  }
1555
 
1556
  generateAIResponse(userMessage) {
1557
+ // Enhanced AI response generator with educational content
1558
  const responses = {
1559
+ quantum: "Quantum computing uses quantum bits or 'qubits' that can exist in multiple states simultaneously (superposition). This allows quantum computers to process vast amounts of data in parallel. Unlike classical bits (0 or 1), qubits can be 0, 1, or both at the same time. Key principles include superposition, entanglement (where qubits affect each other instantly regardless of distance), and quantum interference. Current applications include cryptography, drug discovery, and complex system simulations.",
1560
+ neural: "Neural networks learn through a process called backpropagation with gradient descent. They consist of layers of interconnected 'neurons' that process information. During training, the network makes predictions, calculates errors, and adjusts connection weights to minimize those errors. Deep learning uses multiple hidden layers to extract hierarchical features - early layers detect simple patterns (edges, colors), while deeper layers recognize complex structures (faces, objects).",
1561
+ ai: "Artificial Intelligence (AI) is the broader concept of machines being able to carry out tasks in a way we would consider 'smart'. Machine Learning (ML) is a subset of AI where machines learn from data without explicit programming. Deep Learning (DL) is a subset of ML using neural networks with multiple layers. Think of it as: AI > ML > DL. AI encompasses everything, ML is the method, and DL is the specific technique.",
1562
+ blockchain: "Blockchain is a distributed, decentralized digital ledger that records transactions across many computers. Each 'block' contains a cryptographic hash of the previous block, a timestamp, and transaction data, creating an immutable chain. Key features include transparency (all participants can see transactions), security (extremely difficult to alter past records), and decentralization (no single point of control). Beyond cryptocurrency, it's used for smart contracts, supply chain tracking, and secure voting systems.",
1563
+ calculus: "Derivatives measure instantaneous rate of change - essentially the slope of a curve at a specific point. If f(x) is your function, the derivative f'(x) tells you how fast f(x) is changing at any x. Think of driving: your speedometer shows your instantaneous speed (derivative of position). Important rules include: Power rule (d/dx[xⁿ] = nxⁿ⁻¹), Product rule (d/dx[uv] = u'v + uv'), Quotient rule, and Chain rule for composite functions.",
1564
+ default: "I understand you're asking about " + userMessage.substring(0, 50) + "... This is an interesting topic in modern education. Let me provide a structured explanation with key concepts, real-world applications, and learning pathways. Would you like me to start with fundamentals, practical examples, or career applications?"
1565
  };
1566
 
1567
  const lowerMessage = userMessage.toLowerCase();
1568
 
1569
  if (lowerMessage.includes('quantum')) return responses.quantum;
1570
  if (lowerMessage.includes('neural') || lowerMessage.includes('network')) return responses.neural;
1571
+ if (lowerMessage.includes('artificial intelligence') || lowerMessage.includes(' ai ') || lowerMessage.includes('machine learning')) return responses.ai;
1572
  if (lowerMessage.includes('blockchain')) return responses.blockchain;
1573
+ if (lowerMessage.includes('calculus') || lowerMessage.includes('derivative') || lowerMessage.includes('differentiation')) return responses.calculus;
1574
 
1575
  return responses.default;
1576
  }
1577
  }
1578
 
1579
+ // Main Visualization Class (Unchanged from previous version)
1580
  class AITutorVisualization {
1581
  constructor() {
1582
  if (!checkThreeJS()) return;
 
1584
  this.scene = null;
1585
  this.camera = null;
1586
  this.renderer = null;
1587
+ this.particles = null;
 
 
 
 
 
 
 
 
 
1588
  this.controls = null;
1589
 
1590
  this.params = {
 
1600
 
1601
  try {
1602
  this.init();
1603
+ this.createParticles();
 
1604
  this.setupControls();
1605
  this.animate();
1606
+ updateStatus('Neural AI System Ready');
1607
  setTimeout(hideLoading, 500);
1608
  } catch (error) {
1609
  console.error('Initialization error:', error);
1610
+ showError('Failed to initialize 3D visualization: ' + error.message);
1611
  }
1612
  }
1613
 
1614
  init() {
1615
+ updateStatus('Initializing neural network visualization...');
1616
 
1617
  // Scene
1618
  this.scene = new THREE.Scene();
 
1625
  0.1,
1626
  1000
1627
  );
1628
+ this.camera.position.z = 5;
 
1629
 
1630
  // Renderer
1631
  const canvas = document.getElementById('mainCanvas');
 
1641
  this.scene.fog = new THREE.Fog(0x0a0a0f, 10, 25);
1642
 
1643
  // Add lights
1644
+ const ambientLight = new THREE.AmbientLight(0x222244, 0.5);
1645
  this.scene.add(ambientLight);
1646
 
1647
  const directionalLight = new THREE.DirectionalLight(0x5a6cff, 1);
1648
  directionalLight.position.set(5, 3, 5);
1649
  this.scene.add(directionalLight);
1650
 
 
 
 
 
1651
  // Orbit controls
1652
+ updateStatus('Configuring interaction controls...');
1653
  this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
1654
  this.controls.enableDamping = true;
1655
  this.controls.dampingFactor = 0.05;
 
 
1656
  }
1657
 
1658
+ createParticles() {
1659
+ updateStatus('Generating neural particles...');
1660
 
1661
  const geometry = new THREE.BufferGeometry();
1662
  const positions = new Float32Array(this.params.particleCount * 3);
1663
  const colors = new Float32Array(this.params.particleCount * 3);
1664
 
 
1665
  for (let i = 0; i < this.params.particleCount; i++) {
1666
  const i3 = i * 3;
1667
 
1668
+ // Fibonacci sphere distribution
1669
  const phi = Math.acos(-1 + (2 * i) / this.params.particleCount);
1670
  const theta = Math.sqrt(this.params.particleCount * Math.PI) * phi;
1671
 
1672
+ const x = Math.cos(theta) * Math.sin(phi);
1673
+ const y = Math.sin(theta) * Math.sin(phi);
1674
+ const z = Math.cos(phi);
 
 
 
1675
 
1676
  positions[i3] = x;
1677
  positions[i3 + 1] = y;
1678
  positions[i3 + 2] = z;
1679
 
1680
+ // Color gradient based on position
1681
+ colors[i3] = 0.5 + x * 0.5;
1682
+ colors[i3 + 1] = 0.3 + y * 0.7;
1683
+ colors[i3 + 2] = 0.8 + z * 0.2;
1684
  }
1685
 
1686
  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
1687
  geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
1688
 
1689
  const material = new THREE.PointsMaterial({
1690
+ size: 0.03,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1691
  vertexColors: true,
1692
  transparent: true,
1693
+ opacity: 0.8,
1694
+ blending: THREE.AdditiveBlending
 
1695
  });
1696
 
1697
+ this.particles = new THREE.Points(geometry, material);
1698
+ this.scene.add(this.particles);
 
 
 
1699
 
1700
+ // Add central neural core
1701
+ const coreGeometry = new THREE.SphereGeometry(0.5, 32, 32);
1702
+ const coreMaterial = new THREE.MeshBasicMaterial({
1703
  color: 0x5a6cff,
1704
  wireframe: true,
1705
  transparent: true,
1706
+ opacity: 0.1
1707
  });
1708
+ const core = new THREE.Mesh(coreGeometry, coreMaterial);
1709
+ this.scene.add(core);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1710
  }
1711
 
1712
  setupControls() {
 
1754
 
1755
  // Update UI to show active preset
1756
  document.querySelectorAll('.preset-btn').forEach(btn => {
1757
+ btn.classList.toggle('active', btn.dataset.preset === preset);
 
 
1758
  });
1759
 
1760
  // Update status
 
1764
  'responding': '💬 Formulating response...',
1765
  'exploring': '🔍 Exploring concepts...',
1766
  'teaching': '📚 Teaching mode active',
1767
+ 'idle': '🌀 Neural system idle'
1768
  };
1769
 
1770
  if (statusMap[preset]) {
 
1773
  }
1774
 
1775
  updateParticleCount() {
1776
+ if (this.particles) {
1777
+ this.scene.remove(this.particles);
1778
  }
1779
+ this.createParticles();
 
 
 
1780
  }
1781
 
1782
  simulateAudioData() {
 
1791
  }
1792
  }
1793
 
1794
+ updateParticles() {
1795
+ if (!this.particles) return;
1796
+
1797
+ const positions = this.particles.geometry.attributes.position.array;
1798
+ const originalPositions = this.particles.geometry.attributes.originalPosition;
1799
+ const colors = this.particles.geometry.attributes.color.array;
1800
+
1801
+ // Store original positions if not already stored
1802
+ if (!originalPositions) {
1803
+ const origPos = new Float32Array(positions.length);
1804
+ origPos.set(positions);
1805
+ this.particles.geometry.setAttribute('originalPosition', new THREE.BufferAttribute(origPos, 3));
1806
+ }
1807
 
1808
+ const origPositions = this.particles.geometry.attributes.originalPosition.array;
 
1809
  const time = this.time;
1810
 
1811
  for (let i = 0; i < this.params.particleCount; i++) {
1812
  const i3 = i * 3;
1813
+ const x = origPositions[i3];
1814
+ const y = origPositions[i3 + 1];
1815
+ const z = origPositions[i3 + 2];
1816
 
1817
+ let radius = 2.0;
1818
+ let intensity = this.params.intensity;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1819
 
1820
+ // Apply different behaviors based on mode
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1821
  switch(this.params.mode) {
1822
  case 'listening':
1823
+ radius += Math.sin(time * 3 + i * 0.01) * 0.5 * intensity;
1824
  break;
1825
  case 'processing':
1826
+ radius += Math.sin(time * 5 + i * 0.02) * 0.6 * intensity;
1827
  break;
1828
  case 'responding':
1829
+ radius += (Math.sin(time * 2 + i * 0.005) + 1) * 0.4 * intensity;
1830
  break;
1831
  case 'exploring':
1832
+ radius += Math.sin(time * 1.5 + i * 0.015) * 0.7 * intensity;
1833
  break;
1834
  case 'teaching':
1835
+ radius += Math.sin(time * 4 + i * 0.008) * 0.55 * intensity;
1836
  break;
1837
  default: // idle
1838
+ radius += Math.sin(time * 0.5 + i * 0.01) * 0.2 * intensity;
1839
  }
1840
 
1841
+ // Add energy-based pulsation
1842
+ radius += Math.sin(time * 8) * 0.2 * this.params.energy;
 
 
 
 
 
1843
 
1844
+ // Add audio data influence
1845
+ const audioIndex = Math.floor((i / this.params.particleCount) * this.audioData.length);
1846
+ radius += this.audioData[audioIndex] * 0.5 * intensity;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1847
 
1848
+ positions[i3] = x * radius;
1849
+ positions[i3 + 1] = y * radius;
1850
+ positions[i3 + 2] = z * radius;
 
 
1851
 
1852
+ // Update colors based on mode
1853
+ const colorShift = Math.sin(time * 0.5 + i * 0.001) * 0.1;
1854
+ colors[i3] = 0.5 + x * 0.5 + colorShift;
1855
+ colors[i3 + 1] = 0.3 + y * 0.7 + colorShift;
1856
+ colors[i3 + 2] = 0.8 + z * 0.2 + colorShift;
1857
  }
1858
 
1859
+ this.particles.geometry.attributes.position.needsUpdate = true;
1860
+ this.particles.geometry.attributes.color.needsUpdate = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1861
 
1862
+ // Rotate particles slowly
1863
+ this.particles.rotation.y = time * 0.1;
1864
+ this.particles.rotation.x = Math.sin(time * 0.05) * 0.1;
1865
  }
1866
 
1867
  animate() {
 
1870
  this.time += 0.016;
1871
 
1872
  this.simulateAudioData();
1873
+ this.updateParticles();
 
1874
 
1875
  this.controls.update();
1876
  this.renderer.render(this.scene, this.camera);
 
1897
 
1898
  // Initialize when page loads
1899
  window.addEventListener('load', () => {
1900
+ updateStatus('Loading Neural AI Tutor...');
1901
+
1902
+ // Auto-expand sidebar on hover
1903
+ const sidebar = document.getElementById('sidebar');
1904
+ sidebar.addEventListener('mouseenter', () => {
1905
+ sidebar.classList.add('expanded');
1906
+ });
1907
+
1908
+ sidebar.addEventListener('mouseleave', () => {
1909
+ sidebar.classList.remove('expanded');
1910
+ });
1911
 
1912
  // Wait a moment for libraries to load
1913
  setTimeout(() => {
 
1941
  }
1942
  // Ctrl+Space to stop speech
1943
  if (e.code === 'Space' && e.ctrlKey && window.voiceSynthesis) {
1944
+ window.voiceSynthesis.stopAllSpeech();
1945
+ }
1946
+ // Escape key closes all panels
1947
+ if (e.code === 'Escape') {
1948
+ sidebar.classList.remove('expanded');
1949
  }
1950
  });
1951
 
1952
  // Set initial preset
1953
  window.visualization.setPreset('idle');
1954
+
1955
+ // Auto-open visualization panel
1956
+ setTimeout(() => {
1957
+ togglePanel('visualizationPanel');
1958
+ }, 1000);
1959
  }
1960
  }, 100);
1961
  });
 
1966
  window.visualization.destroy();
1967
  }
1968
  if (window.voiceSynthesis) {
1969
+ window.voiceSynthesis.stopAllSpeech();
1970
  }
1971
  });
1972
  </script>