Spaces:
Running
Running
Update index.html
Browse files- 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
|
| 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 |
-
|
| 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 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
}
|
| 47 |
|
| 48 |
-
|
| 49 |
-
.
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
display: flex;
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
opacity: 0;
|
| 60 |
-
|
| 61 |
-
|
|
|
|
|
|
|
| 62 |
}
|
| 63 |
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
|
|
|
| 69 |
}
|
| 70 |
|
| 71 |
-
.
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 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 |
-
.
|
| 85 |
-
|
| 86 |
-
|
|
|
|
|
|
|
| 87 |
color: #a0b0ff;
|
|
|
|
|
|
|
| 88 |
display: flex;
|
| 89 |
align-items: center;
|
| 90 |
gap: 10px;
|
| 91 |
}
|
| 92 |
|
| 93 |
-
.
|
| 94 |
-
|
| 95 |
-
align-items: center;
|
| 96 |
-
gap: 8px;
|
| 97 |
-
font-size: 0.85em;
|
| 98 |
-
color: #8892b0;
|
| 99 |
}
|
| 100 |
|
| 101 |
-
.
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
border-radius: 50%;
|
| 105 |
-
background: #00ff9d;
|
| 106 |
-
animation: pulse 2s infinite;
|
| 107 |
}
|
| 108 |
|
| 109 |
-
.
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
background: rgba(20, 20, 30, 0.85);
|
| 112 |
-
backdrop-filter: blur(
|
|
|
|
| 113 |
border: 1px solid rgba(255, 255, 255, 0.1);
|
| 114 |
-
|
| 115 |
-
|
| 116 |
display: flex;
|
| 117 |
flex-direction: column;
|
| 118 |
-
|
|
|
|
|
|
|
| 119 |
}
|
| 120 |
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
display: flex;
|
| 126 |
-
|
| 127 |
-
gap:
|
| 128 |
-
|
| 129 |
-
scrollbar-color: #5a6cff rgba(255, 255, 255, 0.1);
|
| 130 |
}
|
| 131 |
|
| 132 |
-
.chat-
|
| 133 |
-
|
|
|
|
|
|
|
| 134 |
}
|
| 135 |
|
| 136 |
-
.
|
| 137 |
-
|
| 138 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
}
|
| 140 |
|
| 141 |
-
.chat-
|
| 142 |
-
|
| 143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
}
|
| 145 |
|
| 146 |
.message {
|
| 147 |
max-width: 85%;
|
| 148 |
-
padding:
|
| 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.
|
| 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.
|
| 183 |
opacity: 0.7;
|
| 184 |
-
margin-top:
|
| 185 |
text-align: right;
|
| 186 |
}
|
| 187 |
|
|
@@ -214,14 +290,14 @@
|
|
| 214 |
}
|
| 215 |
|
| 216 |
.chat-input-container {
|
| 217 |
-
padding:
|
| 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:
|
| 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:
|
| 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 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 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 |
-
|
| 286 |
-
|
| 287 |
-
|
| 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(
|
| 301 |
-
|
| 302 |
-
|
|
|
|
|
|
|
|
|
|
| 303 |
}
|
| 304 |
|
| 305 |
-
.
|
| 306 |
-
height: 40px;
|
| 307 |
display: flex;
|
| 308 |
align-items: center;
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
}
|
| 315 |
|
| 316 |
-
.
|
| 317 |
-
|
|
|
|
|
|
|
| 318 |
}
|
| 319 |
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
height:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 323 |
background: #5a6cff;
|
| 324 |
-
border-radius:
|
| 325 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
}
|
| 327 |
|
| 328 |
-
.
|
| 329 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 330 |
}
|
| 331 |
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 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 |
-
.
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
margin-bottom: 20px;
|
| 356 |
color: #a0b0ff;
|
| 357 |
-
|
| 358 |
-
|
|
|
|
|
|
|
|
|
|
| 359 |
}
|
| 360 |
|
| 361 |
-
.
|
| 362 |
-
|
|
|
|
| 363 |
}
|
| 364 |
|
| 365 |
-
.
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 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:
|
| 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 |
-
|
| 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 614 |
font-size: 0.9em;
|
| 615 |
-
text-align: center;
|
| 616 |
}
|
| 617 |
|
| 618 |
-
.
|
| 619 |
-
background: rgba(
|
| 620 |
transform: translateY(-2px);
|
| 621 |
}
|
| 622 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 623 |
.status-bar {
|
| 624 |
position: absolute;
|
| 625 |
-
top:
|
| 626 |
-
|
| 627 |
background: rgba(20, 20, 30, 0.8);
|
| 628 |
backdrop-filter: blur(10px);
|
| 629 |
-
padding:
|
| 630 |
-
border-radius:
|
| 631 |
-
font-size: 0.
|
| 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:
|
| 663 |
}
|
| 664 |
|
| 665 |
.spinner {
|
|
@@ -687,7 +639,7 @@
|
|
| 687 |
flex-direction: column;
|
| 688 |
justify-content: center;
|
| 689 |
align-items: center;
|
| 690 |
-
z-index:
|
| 691 |
text-align: center;
|
| 692 |
padding: 20px;
|
| 693 |
}
|
|
@@ -719,241 +671,334 @@
|
|
| 719 |
transform: translateY(-2px);
|
| 720 |
}
|
| 721 |
|
| 722 |
-
/* Responsive
|
| 723 |
-
@media (max-width:
|
| 724 |
-
.
|
| 725 |
-
|
| 726 |
-
bottom: 400px;
|
| 727 |
-
}
|
| 728 |
-
|
| 729 |
-
.chat-interface {
|
| 730 |
-
width: 400px;
|
| 731 |
}
|
| 732 |
}
|
| 733 |
|
| 734 |
-
@media (max-
|
| 735 |
-
|
| 736 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 737 |
}
|
| 738 |
|
| 739 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 740 |
padding: 20px;
|
| 741 |
-
width: 260px;
|
| 742 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 743 |
}
|
| 744 |
</style>
|
| 745 |
</head>
|
| 746 |
<body>
|
| 747 |
-
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
| 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 |
-
|
| 759 |
-
|
| 760 |
-
<div class="
|
| 761 |
-
<
|
| 762 |
-
|
| 763 |
-
|
| 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 |
-
|
| 785 |
-
|
| 786 |
-
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
| 791 |
-
|
| 792 |
-
|
| 793 |
-
|
| 794 |
-
|
| 795 |
-
|
| 796 |
-
|
| 797 |
-
|
| 798 |
-
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
|
| 802 |
-
|
| 803 |
-
|
| 804 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 805 |
</div>
|
| 806 |
</div>
|
| 807 |
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 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="
|
| 838 |
-
<
|
| 839 |
-
|
| 840 |
-
|
| 841 |
-
|
| 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 |
-
<
|
|
|
|
|
|
|
| 851 |
</div>
|
| 852 |
|
| 853 |
-
<div class="
|
| 854 |
-
<div class="
|
| 855 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 856 |
</div>
|
| 857 |
-
<div class="message-time">Just now</div>
|
| 858 |
</div>
|
| 859 |
|
| 860 |
-
|
| 861 |
-
|
| 862 |
-
|
| 863 |
-
|
| 864 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 865 |
</div>
|
| 866 |
-
|
| 867 |
-
|
| 868 |
-
|
| 869 |
-
|
| 870 |
-
|
| 871 |
-
|
| 872 |
-
|
| 873 |
-
|
| 874 |
-
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
|
| 878 |
-
|
|
|
|
|
|
|
|
|
|
| 879 |
</button>
|
| 880 |
-
|
| 881 |
-
|
| 882 |
-
|
| 883 |
</button>
|
| 884 |
</div>
|
| 885 |
|
| 886 |
-
<
|
| 887 |
-
<
|
| 888 |
-
|
| 889 |
-
|
| 890 |
-
|
| 891 |
-
|
| 892 |
-
<
|
| 893 |
-
<
|
| 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 |
-
|
| 909 |
-
|
| 910 |
-
<div class="
|
| 911 |
-
<
|
| 912 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 913 |
</div>
|
| 914 |
</div>
|
| 915 |
-
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
|
| 920 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 921 |
</div>
|
| 922 |
</div>
|
| 923 |
|
| 924 |
-
<div class="
|
| 925 |
-
<
|
| 926 |
-
|
| 927 |
-
|
| 928 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 929 |
</div>
|
| 930 |
</div>
|
| 931 |
|
| 932 |
-
<div class="
|
| 933 |
-
<
|
| 934 |
-
|
| 935 |
-
|
| 936 |
-
|
| 937 |
-
|
| 938 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 939 |
</div>
|
| 940 |
</div>
|
| 941 |
|
| 942 |
-
<!--
|
| 943 |
<div class="loading-screen" id="loadingScreen">
|
| 944 |
<div class="spinner"></div>
|
| 945 |
-
<div id="loadingText">Initializing AI
|
| 946 |
</div>
|
| 947 |
|
| 948 |
-
<!--
|
| 949 |
<div class="error-screen" id="errorScreen">
|
| 950 |
-
<h2>⚠️ Initialization Failed</h2>
|
| 951 |
-
<p id="errorMessage">
|
| 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 |
-
//
|
| 1007 |
-
this.testScript = "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1008 |
|
| 1009 |
this.initVoices();
|
| 1010 |
this.setupEventListeners();
|
|
@@ -1041,7 +1108,7 @@
|
|
| 1041 |
return;
|
| 1042 |
}
|
| 1043 |
|
| 1044 |
-
// Prioritize natural-sounding 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.
|
| 1193 |
});
|
| 1194 |
|
| 1195 |
-
// Preview button -
|
| 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.
|
| 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 |
-
|
| 1255 |
-
|
| 1256 |
-
|
| 1257 |
-
.
|
| 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 |
-
|
| 1275 |
this.speak(this.testScript);
|
| 1276 |
-
this.showStatus('
|
| 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
|
| 1420 |
-
"
|
| 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 |
-
//
|
| 1541 |
const responses = {
|
| 1542 |
-
quantum: "Quantum computing
|
| 1543 |
-
neural: "Neural networks learn through backpropagation
|
| 1544 |
-
|
| 1545 |
-
|
| 1546 |
-
|
|
|
|
| 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
|
| 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.
|
| 1594 |
-
this.createNeuralWeb();
|
| 1595 |
this.setupControls();
|
| 1596 |
this.animate();
|
| 1597 |
-
updateStatus('AI
|
| 1598 |
setTimeout(hideLoading, 500);
|
| 1599 |
} catch (error) {
|
| 1600 |
console.error('Initialization error:', error);
|
| 1601 |
-
showError('Failed to initialize 3D
|
| 1602 |
}
|
| 1603 |
}
|
| 1604 |
|
| 1605 |
init() {
|
| 1606 |
-
updateStatus('
|
| 1607 |
|
| 1608 |
// Scene
|
| 1609 |
this.scene = new THREE.Scene();
|
|
@@ -1616,8 +1625,7 @@
|
|
| 1616 |
0.1,
|
| 1617 |
1000
|
| 1618 |
);
|
| 1619 |
-
this.camera.position.z =
|
| 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.
|
| 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('
|
| 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 |
-
|
| 1657 |
-
updateStatus('
|
| 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
|
| 1668 |
const phi = Math.acos(-1 + (2 * i) / this.params.particleCount);
|
| 1669 |
const theta = Math.sqrt(this.params.particleCount * Math.PI) * phi;
|
| 1670 |
|
| 1671 |
-
|
| 1672 |
-
const
|
| 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 |
-
//
|
| 1683 |
-
colors[i3] = 0.
|
| 1684 |
-
colors[i3 + 1] = 0.3 + y * 0.
|
| 1685 |
-
colors[i3 + 2] = 0.
|
| 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.
|
| 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.
|
| 1764 |
-
blending: THREE.AdditiveBlending
|
| 1765 |
-
sizeAttenuation: true
|
| 1766 |
});
|
| 1767 |
|
| 1768 |
-
this.
|
| 1769 |
-
this.scene.add(this.
|
| 1770 |
-
|
| 1771 |
-
// Create neural connections
|
| 1772 |
-
this.createNeuralConnections();
|
| 1773 |
|
| 1774 |
-
// Add central core
|
| 1775 |
-
const coreGeometry = new THREE.
|
| 1776 |
-
const coreMaterial = new THREE.MeshBasicMaterial({
|
| 1777 |
color: 0x5a6cff,
|
| 1778 |
wireframe: true,
|
| 1779 |
transparent: true,
|
| 1780 |
-
opacity: 0.
|
| 1781 |
});
|
| 1782 |
-
|
| 1783 |
-
this.scene.add(
|
| 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.
|
| 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': '🌀
|
| 1893 |
};
|
| 1894 |
|
| 1895 |
if (statusMap[preset]) {
|
|
@@ -1898,13 +1773,10 @@
|
|
| 1898 |
}
|
| 1899 |
|
| 1900 |
updateParticleCount() {
|
| 1901 |
-
if (this.
|
| 1902 |
-
this.scene.remove(this.
|
| 1903 |
}
|
| 1904 |
-
this.
|
| 1905 |
-
|
| 1906 |
-
// Also recreate neural web with proportional size
|
| 1907 |
-
this.createNeuralWeb();
|
| 1908 |
}
|
| 1909 |
|
| 1910 |
simulateAudioData() {
|
|
@@ -1919,172 +1791,77 @@
|
|
| 1919 |
}
|
| 1920 |
}
|
| 1921 |
|
| 1922 |
-
|
| 1923 |
-
if (!this.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1924 |
|
| 1925 |
-
const
|
| 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
|
| 1933 |
-
let
|
| 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 |
-
//
|
| 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 |
-
|
| 2010 |
break;
|
| 2011 |
case 'processing':
|
| 2012 |
-
|
| 2013 |
break;
|
| 2014 |
case 'responding':
|
| 2015 |
-
|
| 2016 |
break;
|
| 2017 |
case 'exploring':
|
| 2018 |
-
|
| 2019 |
break;
|
| 2020 |
case 'teaching':
|
| 2021 |
-
|
| 2022 |
break;
|
| 2023 |
default: // idle
|
| 2024 |
-
|
| 2025 |
}
|
| 2026 |
|
| 2027 |
-
//
|
| 2028 |
-
|
| 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 |
-
//
|
| 2036 |
-
|
| 2037 |
-
|
| 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 |
-
|
| 2055 |
-
|
| 2056 |
-
|
| 2057 |
-
lineColors[i + 7] = pulse * this.params.intensity * 0.8;
|
| 2058 |
-
}
|
| 2059 |
|
| 2060 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2061 |
}
|
| 2062 |
|
| 2063 |
-
|
| 2064 |
-
|
| 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 |
-
//
|
| 2086 |
-
this.
|
| 2087 |
-
this.
|
| 2088 |
}
|
| 2089 |
|
| 2090 |
animate() {
|
|
@@ -2093,8 +1870,7 @@
|
|
| 2093 |
this.time += 0.016;
|
| 2094 |
|
| 2095 |
this.simulateAudioData();
|
| 2096 |
-
this.
|
| 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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.
|
| 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>
|