Update index.html
Browse files- index.html +29 -427
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>Interactive 3D GPU Threading
|
| 7 |
<style>
|
| 8 |
body {
|
| 9 |
font-family: 'Consolas', 'Courier New', monospace;
|
|
@@ -131,6 +131,27 @@
|
|
| 131 |
padding-bottom: 10px;
|
| 132 |
}
|
| 133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
.cube-container {
|
| 135 |
height: 500px;
|
| 136 |
perspective: 1200px;
|
|
@@ -298,364 +319,6 @@
|
|
| 298 |
background: #f8f8f8;
|
| 299 |
}
|
| 300 |
|
| 301 |
-
.interaction-guide {
|
| 302 |
-
display: flex;
|
| 303 |
-
justify-content: space-around;
|
| 304 |
-
margin-bottom: 20px;
|
| 305 |
-
padding: 15px;
|
| 306 |
-
background: #f8f8f8;
|
| 307 |
-
border: 1px solid #cccccc;
|
| 308 |
-
font-size: 12px;
|
| 309 |
-
}
|
| 310 |
-
|
| 311 |
-
.interaction-item {
|
| 312 |
-
text-align: center;
|
| 313 |
-
color: #333333;
|
| 314 |
-
}
|
| 315 |
-
|
| 316 |
-
.interaction-item .icon {
|
| 317 |
-
font-size: 18px;
|
| 318 |
-
margin-bottom: 5px;
|
| 319 |
-
display: block;
|
| 320 |
-
}
|
| 321 |
-
|
| 322 |
-
.spatial-explanation {
|
| 323 |
-
background: #f8f8f8;
|
| 324 |
-
padding: 25px;
|
| 325 |
-
border: 2px solid #000000;
|
| 326 |
-
margin-bottom: 30px;
|
| 327 |
-
}
|
| 328 |
-
|
| 329 |
-
.spatial-explanation h3 {
|
| 330 |
-
color: #000000;
|
| 331 |
-
margin-bottom: 20px;
|
| 332 |
-
border-bottom: 1px solid #000000;
|
| 333 |
-
padding-bottom: 10px;
|
| 334 |
-
}
|
| 335 |
-
|
| 336 |
-
.warp-visualization {
|
| 337 |
-
background: #ffffff;
|
| 338 |
-
border: 1px solid #000000;
|
| 339 |
-
padding: 20px;
|
| 340 |
-
margin: 20px 0;
|
| 341 |
-
display: flex;
|
| 342 |
-
flex-direction: column;
|
| 343 |
-
align-items: center;
|
| 344 |
-
}
|
| 345 |
-
|
| 346 |
-
.sm-representation {
|
| 347 |
-
background: #f0f0f0;
|
| 348 |
-
border: 2px solid #000000;
|
| 349 |
-
padding: 15px;
|
| 350 |
-
margin: 10px 0;
|
| 351 |
-
width: 100%;
|
| 352 |
-
max-width: 600px;
|
| 353 |
-
}
|
| 354 |
-
|
| 355 |
-
.sm-title {
|
| 356 |
-
font-weight: bold;
|
| 357 |
-
text-align: center;
|
| 358 |
-
margin-bottom: 15px;
|
| 359 |
-
font-size: 14px;
|
| 360 |
-
border-bottom: 1px solid #000000;
|
| 361 |
-
padding-bottom: 5px;
|
| 362 |
-
}
|
| 363 |
-
|
| 364 |
-
.warp-grid {
|
| 365 |
-
display: grid;
|
| 366 |
-
grid-template-columns: repeat(8, 1fr);
|
| 367 |
-
gap: 2px;
|
| 368 |
-
margin-bottom: 15px;
|
| 369 |
-
}
|
| 370 |
-
|
| 371 |
-
.warp-thread {
|
| 372 |
-
width: 20px;
|
| 373 |
-
height: 20px;
|
| 374 |
-
background: #ffffff;
|
| 375 |
-
border: 1px solid #000000;
|
| 376 |
-
display: flex;
|
| 377 |
-
align-items: center;
|
| 378 |
-
justify-content: center;
|
| 379 |
-
font-size: 8px;
|
| 380 |
-
font-weight: bold;
|
| 381 |
-
}
|
| 382 |
-
|
| 383 |
-
.warp-0 { background: #e0e0e0; }
|
| 384 |
-
.warp-1 { background: #d0d0d0; }
|
| 385 |
-
.warp-2 { background: #c0c0c0; }
|
| 386 |
-
.warp-3 { background: #b0b0b0; }
|
| 387 |
-
|
| 388 |
-
.warp-label {
|
| 389 |
-
font-size: 12px;
|
| 390 |
-
font-weight: bold;
|
| 391 |
-
margin-bottom: 5px;
|
| 392 |
-
text-align: center;
|
| 393 |
-
}
|
| 394 |
-
|
| 395 |
-
.code-example {
|
| 396 |
-
background: #f0f0f0;
|
| 397 |
-
padding: 20px;
|
| 398 |
-
border: 1px solid #cccccc;
|
| 399 |
-
font-family: 'Consolas', 'Courier New', monospace;
|
| 400 |
-
font-size: 13px;
|
| 401 |
-
line-height: 1.6;
|
| 402 |
-
border-left: 4px solid #000000;
|
| 403 |
-
margin: 15px 0;
|
| 404 |
-
color: #000000;
|
| 405 |
-
}
|
| 406 |
-
|
| 407 |
-
.highlight {
|
| 408 |
-
background: #e0e0e0;
|
| 409 |
-
padding: 2px 4px;
|
| 410 |
-
border: 1px solid #000000;
|
| 411 |
-
}
|
| 412 |
-
|
| 413 |
-
.hardware-pipeline {
|
| 414 |
-
background: #ffffff;
|
| 415 |
-
border: 2px solid #000000;
|
| 416 |
-
padding: 20px;
|
| 417 |
-
margin: 20px 0;
|
| 418 |
-
}
|
| 419 |
-
|
| 420 |
-
.pipeline-stage {
|
| 421 |
-
margin-bottom: 30px;
|
| 422 |
-
border-bottom: 1px solid #cccccc;
|
| 423 |
-
padding-bottom: 20px;
|
| 424 |
-
}
|
| 425 |
-
|
| 426 |
-
.pipeline-stage h4 {
|
| 427 |
-
font-size: 16px;
|
| 428 |
-
font-weight: bold;
|
| 429 |
-
margin-bottom: 15px;
|
| 430 |
-
color: #000000;
|
| 431 |
-
border-bottom: 1px solid #000000;
|
| 432 |
-
padding-bottom: 8px;
|
| 433 |
-
}
|
| 434 |
-
|
| 435 |
-
.sm-array {
|
| 436 |
-
display: flex;
|
| 437 |
-
gap: 15px;
|
| 438 |
-
flex-wrap: wrap;
|
| 439 |
-
justify-content: center;
|
| 440 |
-
margin: 20px 0;
|
| 441 |
-
}
|
| 442 |
-
|
| 443 |
-
.sm-unit {
|
| 444 |
-
background: #f8f8f8;
|
| 445 |
-
border: 2px solid #000000;
|
| 446 |
-
padding: 15px;
|
| 447 |
-
min-width: 150px;
|
| 448 |
-
text-align: center;
|
| 449 |
-
}
|
| 450 |
-
|
| 451 |
-
.sm-header {
|
| 452 |
-
font-weight: bold;
|
| 453 |
-
font-size: 14px;
|
| 454 |
-
margin-bottom: 10px;
|
| 455 |
-
background: #000000;
|
| 456 |
-
color: #ffffff;
|
| 457 |
-
padding: 5px;
|
| 458 |
-
}
|
| 459 |
-
|
| 460 |
-
.block-assignment {
|
| 461 |
-
display: flex;
|
| 462 |
-
flex-direction: column;
|
| 463 |
-
gap: 5px;
|
| 464 |
-
}
|
| 465 |
-
|
| 466 |
-
.assigned-block {
|
| 467 |
-
background: #ffffff;
|
| 468 |
-
border: 1px solid #000000;
|
| 469 |
-
padding: 5px;
|
| 470 |
-
font-size: 11px;
|
| 471 |
-
font-weight: bold;
|
| 472 |
-
}
|
| 473 |
-
|
| 474 |
-
.sm-detailed {
|
| 475 |
-
background: #f8f8f8;
|
| 476 |
-
border: 2px solid #000000;
|
| 477 |
-
padding: 20px;
|
| 478 |
-
margin: 20px 0;
|
| 479 |
-
}
|
| 480 |
-
|
| 481 |
-
.sm-title {
|
| 482 |
-
font-size: 14px;
|
| 483 |
-
font-weight: bold;
|
| 484 |
-
text-align: center;
|
| 485 |
-
margin-bottom: 20px;
|
| 486 |
-
background: #000000;
|
| 487 |
-
color: #ffffff;
|
| 488 |
-
padding: 10px;
|
| 489 |
-
}
|
| 490 |
-
|
| 491 |
-
.sm-components {
|
| 492 |
-
display: flex;
|
| 493 |
-
flex-direction: column;
|
| 494 |
-
gap: 15px;
|
| 495 |
-
}
|
| 496 |
-
|
| 497 |
-
.scheduler-layer {
|
| 498 |
-
display: flex;
|
| 499 |
-
gap: 10px;
|
| 500 |
-
justify-content: center;
|
| 501 |
-
}
|
| 502 |
-
|
| 503 |
-
.scheduler-unit {
|
| 504 |
-
background: #d0d0d0;
|
| 505 |
-
border: 1px solid #000000;
|
| 506 |
-
padding: 8px 15px;
|
| 507 |
-
font-size: 11px;
|
| 508 |
-
font-weight: bold;
|
| 509 |
-
text-align: center;
|
| 510 |
-
min-width: 80px;
|
| 511 |
-
}
|
| 512 |
-
|
| 513 |
-
.register-layer {
|
| 514 |
-
display: flex;
|
| 515 |
-
gap: 10px;
|
| 516 |
-
justify-content: center;
|
| 517 |
-
}
|
| 518 |
-
|
| 519 |
-
.register-file {
|
| 520 |
-
background: #e0e0e0;
|
| 521 |
-
border: 1px solid #000000;
|
| 522 |
-
padding: 8px 15px;
|
| 523 |
-
font-size: 11px;
|
| 524 |
-
font-weight: bold;
|
| 525 |
-
text-align: center;
|
| 526 |
-
min-width: 80px;
|
| 527 |
-
}
|
| 528 |
-
|
| 529 |
-
.execution-layer {
|
| 530 |
-
display: flex;
|
| 531 |
-
gap: 8px;
|
| 532 |
-
justify-content: center;
|
| 533 |
-
flex-wrap: wrap;
|
| 534 |
-
}
|
| 535 |
-
|
| 536 |
-
.execution-unit {
|
| 537 |
-
border: 1px solid #000000;
|
| 538 |
-
padding: 8px 12px;
|
| 539 |
-
font-size: 10px;
|
| 540 |
-
font-weight: bold;
|
| 541 |
-
text-align: center;
|
| 542 |
-
min-width: 50px;
|
| 543 |
-
}
|
| 544 |
-
|
| 545 |
-
.execution-unit.int32 {
|
| 546 |
-
background: #f0f0f0;
|
| 547 |
-
}
|
| 548 |
-
|
| 549 |
-
.execution-unit.fp32 {
|
| 550 |
-
background: #e8e8e8;
|
| 551 |
-
}
|
| 552 |
-
|
| 553 |
-
.execution-unit.tensor {
|
| 554 |
-
background: #d8d8d8;
|
| 555 |
-
}
|
| 556 |
-
|
| 557 |
-
.execution-unit.ldst {
|
| 558 |
-
background: #c8c8c8;
|
| 559 |
-
}
|
| 560 |
-
|
| 561 |
-
.execution-unit.sfu {
|
| 562 |
-
background: #b8b8b8;
|
| 563 |
-
}
|
| 564 |
-
|
| 565 |
-
.memory-layer {
|
| 566 |
-
display: flex;
|
| 567 |
-
justify-content: center;
|
| 568 |
-
}
|
| 569 |
-
|
| 570 |
-
.shared-memory {
|
| 571 |
-
background: #000000;
|
| 572 |
-
color: #ffffff;
|
| 573 |
-
border: 2px solid #000000;
|
| 574 |
-
padding: 10px 20px;
|
| 575 |
-
font-size: 12px;
|
| 576 |
-
font-weight: bold;
|
| 577 |
-
text-align: center;
|
| 578 |
-
width: 80%;
|
| 579 |
-
}
|
| 580 |
-
|
| 581 |
-
.warp-flow {
|
| 582 |
-
display: flex;
|
| 583 |
-
gap: 30px;
|
| 584 |
-
align-items: flex-start;
|
| 585 |
-
margin: 20px 0;
|
| 586 |
-
}
|
| 587 |
-
|
| 588 |
-
.warp-scheduler {
|
| 589 |
-
background: #f8f8f8;
|
| 590 |
-
border: 2px solid #000000;
|
| 591 |
-
padding: 15px;
|
| 592 |
-
min-width: 200px;
|
| 593 |
-
}
|
| 594 |
-
|
| 595 |
-
.scheduler-title {
|
| 596 |
-
font-size: 14px;
|
| 597 |
-
font-weight: bold;
|
| 598 |
-
text-align: center;
|
| 599 |
-
margin-bottom: 15px;
|
| 600 |
-
background: #000000;
|
| 601 |
-
color: #ffffff;
|
| 602 |
-
padding: 8px;
|
| 603 |
-
}
|
| 604 |
-
|
| 605 |
-
.warp-queue {
|
| 606 |
-
display: flex;
|
| 607 |
-
flex-direction: column;
|
| 608 |
-
gap: 8px;
|
| 609 |
-
}
|
| 610 |
-
|
| 611 |
-
.warp-item {
|
| 612 |
-
padding: 8px 12px;
|
| 613 |
-
border: 1px solid #000000;
|
| 614 |
-
font-size: 11px;
|
| 615 |
-
font-weight: bold;
|
| 616 |
-
text-align: center;
|
| 617 |
-
}
|
| 618 |
-
|
| 619 |
-
.warp-item.active {
|
| 620 |
-
background: #000000;
|
| 621 |
-
color: #ffffff;
|
| 622 |
-
}
|
| 623 |
-
|
| 624 |
-
.warp-item.ready {
|
| 625 |
-
background: #d0d0d0;
|
| 626 |
-
}
|
| 627 |
-
|
| 628 |
-
.warp-item.waiting {
|
| 629 |
-
background: #f0f0f0;
|
| 630 |
-
}
|
| 631 |
-
|
| 632 |
-
.execution-pipeline {
|
| 633 |
-
flex: 1;
|
| 634 |
-
background: #f8f8f8;
|
| 635 |
-
border: 2px solid #000000;
|
| 636 |
-
padding: 15px;
|
| 637 |
-
}
|
| 638 |
-
|
| 639 |
-
.pipeline-step {
|
| 640 |
-
margin-bottom: 15px;
|
| 641 |
-
padding: 10px;
|
| 642 |
-
border: 1px solid #000000;
|
| 643 |
-
background: #ffffff;
|
| 644 |
-
}
|
| 645 |
-
|
| 646 |
-
.step-title {
|
| 647 |
-
font-size: 12px;
|
| 648 |
-
font-weight: bold;
|
| 649 |
-
margin-bottom: 5px;
|
| 650 |
-
color: #000000;
|
| 651 |
-
}
|
| 652 |
-
|
| 653 |
-
.step-content {
|
| 654 |
-
font-size: 11px;
|
| 655 |
-
color: #333333;
|
| 656 |
-
line-height: 1.4;
|
| 657 |
-
}
|
| 658 |
-
|
| 659 |
.current-view {
|
| 660 |
position: absolute;
|
| 661 |
top: 10px;
|
|
@@ -758,46 +421,6 @@
|
|
| 758 |
</div>
|
| 759 |
</div>
|
| 760 |
</div>
|
| 761 |
-
|
| 762 |
-
<div class="spatial-explanation">
|
| 763 |
-
<h3>Understanding Spatial Relationships Through Direct Manipulation</h3>
|
| 764 |
-
<p>The ability to directly manipulate the 3D cube with your cursor creates a much deeper understanding of spatial relationships than static views or sliders ever could. As you rotate the cube, you can see exactly which blocks are neighbors and how the grid extends in all three dimensions simultaneously.</p>
|
| 765 |
-
|
| 766 |
-
<p><strong>Why Direct Interaction Builds Better Mental Models:</strong></p>
|
| 767 |
-
<p>When you drag to rotate the cube, your brain naturally builds a spatial mental model that connects the visual structure to the mathematical relationships. You can see how a block at position [1,0,1] relates spatially to blocks at [0,0,1], [2,0,1], [1,1,1], and [1,0,0]. This spatial understanding is crucial for writing efficient GPU code that takes advantage of memory locality and thread cooperation patterns.</p>
|
| 768 |
-
|
| 769 |
-
<p><strong>Learning Exercise:</strong> Try rotating the cube to view it from different angles while thinking about how data flows through your algorithm. Can you identify which blocks would naturally work together on shared data? The spatial arrangement you see directly represents the memory access patterns that will determine your algorithm's performance.</p>
|
| 770 |
-
|
| 771 |
-
<div class="code-example">
|
| 772 |
-
// Example: 3D convolution filter processing
|
| 773 |
-
fn apply_3d_convolution(input: UnsafePointer[Float32], output: UnsafePointer[Float32],
|
| 774 |
-
width: Int, height: Int, depth: Int):
|
| 775 |
-
// Each thread processes one output voxel
|
| 776 |
-
let <span class="highlight">x = global_idx.x</span> // Width position
|
| 777 |
-
let <span class="highlight">y = global_idx.y</span> // Height position
|
| 778 |
-
let <span class="highlight">z = global_idx.z</span> // Depth position
|
| 779 |
-
|
| 780 |
-
if x < width and y < height and z < depth:
|
| 781 |
-
var sum: Float32 = 0
|
| 782 |
-
|
| 783 |
-
// Access neighboring voxels for convolution
|
| 784 |
-
for dz in range(-1, 2):
|
| 785 |
-
for dy in range(-1, 2):
|
| 786 |
-
for dx in range(-1, 2):
|
| 787 |
-
let nx = x + dx
|
| 788 |
-
let ny = y + dy
|
| 789 |
-
let nz = z + dz
|
| 790 |
-
|
| 791 |
-
if nx >= 0 and nx < width and ny >= 0 and ny < height and nz >= 0 and nz < depth:
|
| 792 |
-
let neighbor_idx = nz * width * height + ny * width + nx
|
| 793 |
-
sum += input[neighbor_idx] * filter_weights[dz+1][dy+1][dx+1]
|
| 794 |
-
|
| 795 |
-
let output_idx = z * width * height + y * width + x
|
| 796 |
-
output[output_idx] = sum
|
| 797 |
-
</div>
|
| 798 |
-
|
| 799 |
-
<p>In this convolution example, threads processing nearby voxels (which you can see as spatially close when you rotate the cube) will access overlapping sets of input data. The 3D spatial organization ensures that these threads are grouped into nearby blocks, enabling efficient sharing of cached memory containing the input voxels they all need to access.</p>
|
| 800 |
-
</div>
|
| 801 |
</div>
|
| 802 |
|
| 803 |
<script>
|
|
@@ -847,11 +470,16 @@ fn apply_3d_convolution(input: UnsafePointer[Float32], output: UnsafePointer[Flo
|
|
| 847 |
|
| 848 |
const spacing = 80; // Space between blocks
|
| 849 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 850 |
// Create all blocks in 3D space
|
| 851 |
for (let z = 0; z < gridZ; z++) {
|
| 852 |
for (let y = 0; y < gridY; y++) {
|
| 853 |
for (let x = 0; x < gridX; x++) {
|
| 854 |
-
const block = createBlock3D(x, y, z, blockX, blockY, blockZ, spacing);
|
| 855 |
cube3d.appendChild(block);
|
| 856 |
}
|
| 857 |
}
|
|
@@ -860,19 +488,10 @@ fn apply_3d_convolution(input: UnsafePointer[Float32], output: UnsafePointer[Flo
|
|
| 860 |
updateCubeTransform();
|
| 861 |
}
|
| 862 |
|
| 863 |
-
function createBlock3D(blockX_idx, blockY_idx, blockZ_idx, blockDimX, blockDimY, blockDimZ, spacing) {
|
| 864 |
const block = document.createElement('div');
|
| 865 |
block.className = 'block-cube';
|
| 866 |
|
| 867 |
-
// Calculate center offset for better visual balance
|
| 868 |
-
const gridX = parseInt(document.getElementById('gridX').value);
|
| 869 |
-
const gridY = parseInt(document.getElementById('gridY').value);
|
| 870 |
-
const gridZ = parseInt(document.getElementById('gridZ').value);
|
| 871 |
-
|
| 872 |
-
const centerOffsetX = (gridX - 1) * spacing / 2;
|
| 873 |
-
const centerOffsetY = (gridY - 1) * spacing / 2;
|
| 874 |
-
const centerOffsetZ = (gridZ - 1) * spacing / 2;
|
| 875 |
-
|
| 876 |
// Position in 3D space
|
| 877 |
const translateX = blockX_idx * spacing - centerOffsetX;
|
| 878 |
const translateY = blockY_idx * spacing - centerOffsetY;
|
|
@@ -1007,22 +626,6 @@ fn apply_3d_convolution(input: UnsafePointer[Float32], output: UnsafePointer[Flo
|
|
| 1007 |
createThreadGrid();
|
| 1008 |
}
|
| 1009 |
|
| 1010 |
-
function createWarpVisualization() {
|
| 1011 |
-
const warpDemo = document.getElementById('warpDemo');
|
| 1012 |
-
if (!warpDemo) return;
|
| 1013 |
-
|
| 1014 |
-
warpDemo.innerHTML = '';
|
| 1015 |
-
|
| 1016 |
-
// Create 32 threads representing one warp
|
| 1017 |
-
for (let i = 0; i < 32; i++) {
|
| 1018 |
-
const thread = document.createElement('div');
|
| 1019 |
-
thread.className = 'warp-thread warp-0';
|
| 1020 |
-
thread.textContent = i;
|
| 1021 |
-
thread.title = `Thread ${i} in Warp 0`;
|
| 1022 |
-
warpDemo.appendChild(thread);
|
| 1023 |
-
}
|
| 1024 |
-
}
|
| 1025 |
-
|
| 1026 |
function createThreadGrid() {
|
| 1027 |
if (!selectedBlock) return;
|
| 1028 |
|
|
@@ -1182,7 +785,6 @@ fn apply_3d_convolution(input: UnsafePointer[Float32], output: UnsafePointer[Flo
|
|
| 1182 |
// Initialize everything
|
| 1183 |
setupMouseInteraction();
|
| 1184 |
updateVisualization();
|
| 1185 |
-
createWarpVisualization();
|
| 1186 |
</script>
|
| 1187 |
</body>
|
| 1188 |
</html>
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Interactive 3D GPU Threading</title>
|
| 7 |
<style>
|
| 8 |
body {
|
| 9 |
font-family: 'Consolas', 'Courier New', monospace;
|
|
|
|
| 131 |
padding-bottom: 10px;
|
| 132 |
}
|
| 133 |
|
| 134 |
+
.interaction-guide {
|
| 135 |
+
display: flex;
|
| 136 |
+
justify-content: space-around;
|
| 137 |
+
margin-bottom: 20px;
|
| 138 |
+
padding: 15px;
|
| 139 |
+
background: #f8f8f8;
|
| 140 |
+
border: 1px solid #cccccc;
|
| 141 |
+
font-size: 12px;
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
.interaction-item {
|
| 145 |
+
text-align: center;
|
| 146 |
+
color: #333333;
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
.interaction-item .icon {
|
| 150 |
+
font-size: 18px;
|
| 151 |
+
margin-bottom: 5px;
|
| 152 |
+
display: block;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
.cube-container {
|
| 156 |
height: 500px;
|
| 157 |
perspective: 1200px;
|
|
|
|
| 319 |
background: #f8f8f8;
|
| 320 |
}
|
| 321 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 322 |
.current-view {
|
| 323 |
position: absolute;
|
| 324 |
top: 10px;
|
|
|
|
| 421 |
</div>
|
| 422 |
</div>
|
| 423 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 424 |
</div>
|
| 425 |
|
| 426 |
<script>
|
|
|
|
| 470 |
|
| 471 |
const spacing = 80; // Space between blocks
|
| 472 |
|
| 473 |
+
// Calculate center offset for better visual balance
|
| 474 |
+
const centerOffsetX = (gridX - 1) * spacing / 2;
|
| 475 |
+
const centerOffsetY = (gridY - 1) * spacing / 2;
|
| 476 |
+
const centerOffsetZ = (gridZ - 1) * spacing / 2;
|
| 477 |
+
|
| 478 |
// Create all blocks in 3D space
|
| 479 |
for (let z = 0; z < gridZ; z++) {
|
| 480 |
for (let y = 0; y < gridY; y++) {
|
| 481 |
for (let x = 0; x < gridX; x++) {
|
| 482 |
+
const block = createBlock3D(x, y, z, blockX, blockY, blockZ, spacing, centerOffsetX, centerOffsetY, centerOffsetZ);
|
| 483 |
cube3d.appendChild(block);
|
| 484 |
}
|
| 485 |
}
|
|
|
|
| 488 |
updateCubeTransform();
|
| 489 |
}
|
| 490 |
|
| 491 |
+
function createBlock3D(blockX_idx, blockY_idx, blockZ_idx, blockDimX, blockDimY, blockDimZ, spacing, centerOffsetX, centerOffsetY, centerOffsetZ) {
|
| 492 |
const block = document.createElement('div');
|
| 493 |
block.className = 'block-cube';
|
| 494 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 495 |
// Position in 3D space
|
| 496 |
const translateX = blockX_idx * spacing - centerOffsetX;
|
| 497 |
const translateY = blockY_idx * spacing - centerOffsetY;
|
|
|
|
| 626 |
createThreadGrid();
|
| 627 |
}
|
| 628 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 629 |
function createThreadGrid() {
|
| 630 |
if (!selectedBlock) return;
|
| 631 |
|
|
|
|
| 785 |
// Initialize everything
|
| 786 |
setupMouseInteraction();
|
| 787 |
updateVisualization();
|
|
|
|
| 788 |
</script>
|
| 789 |
</body>
|
| 790 |
</html>
|