Spaces:
Running
Running
Add 1 files
Browse files- index.html +125 -67
index.html
CHANGED
@@ -383,6 +383,14 @@
|
|
383 |
scene.add(cabinetGroup);
|
384 |
updateCabinetModel();
|
385 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
386 |
// Handle window resize
|
387 |
window.addEventListener('resize', onWindowResize);
|
388 |
|
@@ -421,6 +429,7 @@
|
|
421 |
const shelvesCount = parseInt(shelvesSlider.value);
|
422 |
const drawersCount = cabinetType.value === 'base' ? parseInt(drawersSlider.value) : 0;
|
423 |
const hasGlassDoors = glassDoors.checked;
|
|
|
424 |
|
425 |
// Set main material
|
426 |
let mainMaterial = createMaterial(colorValue, false);
|
@@ -435,77 +444,91 @@
|
|
435 |
metalness: 0.0
|
436 |
});
|
437 |
|
438 |
-
//
|
439 |
-
|
440 |
-
const doorThickness =
|
441 |
-
const handleSize = 0
|
442 |
const shelfThickness = 0.5;
|
443 |
|
|
|
|
|
|
|
|
|
444 |
// Bottom panel
|
445 |
createPanel(width, thickness, depth,
|
446 |
[0, thickness/2, 0],
|
447 |
-
mainMaterial);
|
448 |
|
449 |
// Top panel
|
450 |
createPanel(width, thickness, depth,
|
451 |
[0, height - thickness/2, 0],
|
452 |
-
mainMaterial);
|
453 |
|
454 |
// Left side
|
455 |
createPanel(thickness, height - 2*thickness, depth,
|
456 |
[-width/2 + thickness/2, height/2, 0],
|
457 |
-
mainMaterial);
|
458 |
|
459 |
// Right side
|
460 |
createPanel(thickness, height - 2*thickness, depth,
|
461 |
[width/2 - thickness/2, height/2, 0],
|
462 |
-
mainMaterial);
|
463 |
|
464 |
// Back panel
|
465 |
createPanel(width - 2*thickness, height - 2*thickness, thickness,
|
466 |
[0, height/2, -depth/2 + thickness/2],
|
467 |
-
mainMaterial);
|
|
|
|
|
|
|
468 |
|
469 |
-
// Middle divider if two doors
|
470 |
if (isTwoDoors) {
|
471 |
-
|
472 |
-
|
473 |
-
|
|
|
474 |
}
|
475 |
|
476 |
// Create doors
|
477 |
-
const doorHeight = height - thickness - (
|
478 |
-
const doorYPosition =
|
479 |
|
480 |
if (isTwoDoors) {
|
481 |
const doorWidth = (width - thickness) / 2;
|
482 |
|
483 |
// Left door
|
484 |
createDoor(doorWidth, doorHeight, doorThickness,
|
485 |
-
[-(width -
|
486 |
-
mainMaterial, hasGlassDoors, true);
|
487 |
|
488 |
// Right door
|
489 |
createDoor(doorWidth, doorHeight, doorThickness,
|
490 |
-
[(width -
|
491 |
-
mainMaterial, hasGlassDoors, false);
|
492 |
} else {
|
493 |
// Single door
|
494 |
const doorWidth = width;
|
495 |
createDoor(doorWidth, doorHeight, doorThickness,
|
496 |
[0, doorYPosition, depth/2 - doorThickness/2],
|
497 |
-
mainMaterial, hasGlassDoors, false);
|
498 |
}
|
499 |
|
500 |
-
// Add shelves
|
501 |
-
const availableHeight =
|
502 |
const shelfSpacing = availableHeight / (shelvesCount + 1);
|
503 |
|
504 |
for (let i = 0; i < shelvesCount; i++) {
|
505 |
-
const shelfY = thickness + (i + 1) * shelfSpacing
|
|
|
|
|
|
|
|
|
|
|
|
|
506 |
createShelf(width - 2*thickness - 0.5, shelfThickness, depth - thickness - 0.5,
|
507 |
-
[0, shelfY,
|
508 |
-
shelfMaterial);
|
509 |
}
|
510 |
|
511 |
// Add drawers for base cabinets
|
@@ -515,19 +538,19 @@
|
|
515 |
|
516 |
for (let i = 0; i < drawersCount; i++) {
|
517 |
const drawerY = thickness + i * drawerHeight + drawerHeight/2;
|
518 |
-
createDrawer(width, drawerHeight, depth * 0.
|
519 |
-
[0, drawerY, depth/
|
520 |
-
drawerFrontMaterial, mainMaterial);
|
521 |
}
|
522 |
}
|
523 |
|
524 |
// Adjust camera target based on cabinet size
|
525 |
controls.target.set(0, height/2, 0);
|
526 |
controls.update();
|
|
|
527 |
|
528 |
// Update capacity calculation
|
529 |
const interiorWidth = width - 2*thickness;
|
530 |
-
const interiorHeight = height - 2*thickness - (drawersCount > 0 ? (height * 0.33) : 0);
|
531 |
const interiorDepth = depth - thickness;
|
532 |
const capacity = (interiorWidth * interiorHeight * interiorDepth) / 1728; // convert to cubic feet
|
533 |
|
@@ -538,6 +561,9 @@
|
|
538 |
capacityDisplay.textContent = `${capacity.toFixed(1)} cu.ft`;
|
539 |
dimensionsDisplay.textContent = `${width}" W × ${height}" H × ${depth}" D`;
|
540 |
shelvesDisplay.textContent = shelvesCount;
|
|
|
|
|
|
|
541 |
}
|
542 |
|
543 |
function createMaterial(colorValue, isDrawerFront = false) {
|
@@ -584,17 +610,17 @@
|
|
584 |
return new THREE.MeshStandardMaterial(materialOptions);
|
585 |
}
|
586 |
|
587 |
-
function createPanel(width, height, depth, position, material) {
|
588 |
const geometry = new THREE.BoxGeometry(width, height, depth);
|
589 |
const panel = new THREE.Mesh(geometry, material);
|
590 |
panel.castShadow = true;
|
591 |
panel.receiveShadow = true;
|
592 |
panel.position.set(position[0], position[1], position[2]);
|
593 |
-
|
594 |
return panel;
|
595 |
}
|
596 |
|
597 |
-
function createDoor(width, height, thickness, position, material, hasGlass, isLeftDoor) {
|
598 |
const doorGroup = new THREE.Group();
|
599 |
doorGroup.position.set(position[0], position[1], position[2]);
|
600 |
|
@@ -607,37 +633,53 @@
|
|
607 |
|
608 |
// Glass panel if selected
|
609 |
if (hasGlass) {
|
610 |
-
const glassWidth = width * 0.
|
611 |
-
const glassHeight = height * 0.
|
612 |
-
const glassGeometry = new THREE.BoxGeometry(glassWidth, glassHeight, thickness * 0.
|
613 |
const glassMaterial = new THREE.MeshPhysicalMaterial({
|
614 |
-
color:
|
615 |
-
transmission: 0.
|
616 |
-
roughness: 0.
|
617 |
metalness: 0.0,
|
618 |
transparent: true,
|
619 |
-
opacity: 0.
|
620 |
ior: 1.5,
|
621 |
thickness: 0.1
|
622 |
});
|
623 |
const glass = new THREE.Mesh(glassGeometry, glassMaterial);
|
624 |
-
glass.position.z = thickness * 0.
|
625 |
doorGroup.add(glass);
|
626 |
}
|
627 |
|
628 |
// Handle
|
629 |
-
const handleGeometry = new THREE.CylinderGeometry(0.
|
630 |
const handleMaterial = new THREE.MeshStandardMaterial({ color: 0x333333 });
|
631 |
const handle = new THREE.Mesh(handleGeometry, handleMaterial);
|
632 |
handle.rotation.z = Math.PI/2;
|
633 |
handle.position.set(isLeftDoor ? -width/2 + 2 : width/2 - 2, 0, thickness);
|
634 |
doorGroup.add(handle);
|
635 |
|
636 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
637 |
return doorGroup;
|
638 |
}
|
639 |
|
640 |
-
function createShelf(width, thickness, depth, position, material) {
|
641 |
const shelfGroup = new THREE.Group();
|
642 |
shelfGroup.position.set(position[0], position[1], position[2]);
|
643 |
|
@@ -649,79 +691,94 @@
|
|
649 |
shelfGroup.add(shelf);
|
650 |
|
651 |
// Shelf supports
|
652 |
-
const supportGeometry = new THREE.BoxGeometry(0.5, 1, 0.5);
|
653 |
const supportMaterial = new THREE.MeshStandardMaterial({ color: 0xCCCCCC });
|
654 |
|
655 |
// Left support
|
656 |
const leftSupport = new THREE.Mesh(supportGeometry, supportMaterial);
|
657 |
-
leftSupport.position.set(-width/2 + 0.25, -thickness/2 - 0.
|
658 |
shelfGroup.add(leftSupport);
|
659 |
|
660 |
// Right support
|
661 |
const rightSupport = new THREE.Mesh(supportGeometry, supportMaterial);
|
662 |
-
rightSupport.position.set(width/2 - 0.25, -thickness/2 - 0.
|
663 |
shelfGroup.add(rightSupport);
|
664 |
|
665 |
if (width > 24) {
|
666 |
// Middle support for wider shelves
|
667 |
const midSupport = new THREE.Mesh(supportGeometry, supportMaterial);
|
668 |
-
midSupport.position.set(0, -thickness/2 - 0.
|
669 |
shelfGroup.add(midSupport);
|
670 |
}
|
671 |
|
672 |
-
|
673 |
return shelfGroup;
|
674 |
}
|
675 |
|
676 |
-
function createDrawer(width, height, depth, position, frontMaterial, sideMaterial) {
|
677 |
const drawerGroup = new THREE.Group();
|
678 |
drawerGroup.position.set(position[0], position[1], position[2]);
|
679 |
|
680 |
-
// Drawer
|
681 |
-
const
|
682 |
-
const
|
|
|
683 |
|
684 |
// Front
|
685 |
-
const frontGeometry = new THREE.BoxGeometry(width
|
686 |
const front = new THREE.Mesh(frontGeometry, frontMaterial);
|
687 |
-
front.position.set(0,
|
688 |
drawerGroup.add(front);
|
689 |
|
690 |
// Bottom
|
691 |
-
const bottomGeometry = new THREE.BoxGeometry(width * 0.
|
692 |
const bottom = new THREE.Mesh(bottomGeometry, sideMaterial);
|
693 |
-
bottom.position.set(0,
|
694 |
drawerGroup.add(bottom);
|
695 |
|
696 |
// Sides
|
697 |
-
const sideWidth = width * 0.
|
698 |
-
const sideGeometry = new THREE.BoxGeometry(0.2,
|
699 |
|
700 |
// Left side
|
701 |
const leftSide = new THREE.Mesh(sideGeometry, sideMaterial);
|
702 |
-
leftSide.position.set(-sideWidth/2,
|
703 |
drawerGroup.add(leftSide);
|
704 |
|
705 |
// Right side
|
706 |
const rightSide = new THREE.Mesh(sideGeometry, sideMaterial);
|
707 |
-
rightSide.position.set(sideWidth/2,
|
708 |
drawerGroup.add(rightSide);
|
709 |
|
710 |
// Back
|
711 |
-
const backGeometry = new THREE.BoxGeometry(sideWidth,
|
712 |
const back = new THREE.Mesh(backGeometry, sideMaterial);
|
713 |
-
back.position.set(0,
|
714 |
drawerGroup.add(back);
|
715 |
|
716 |
-
// Handle (
|
717 |
-
const handleGeometry = new THREE.CylinderGeometry(0.
|
718 |
const handleMaterial = new THREE.MeshStandardMaterial({ color: 0x333333 });
|
719 |
const handle = new THREE.Mesh(handleGeometry, handleMaterial);
|
720 |
handle.rotation.z = Math.PI/2;
|
721 |
-
handle.position.set(0,
|
722 |
drawerGroup.add(handle);
|
723 |
|
724 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
725 |
return drawerGroup;
|
726 |
}
|
727 |
|
@@ -729,6 +786,7 @@
|
|
729 |
loadingOverlay.style.opacity = 1;
|
730 |
loadingOverlay.style.pointerEvents = 'auto';
|
731 |
let progress = 0;
|
|
|
732 |
const interval = setInterval(() => {
|
733 |
progress += 10;
|
734 |
const offset = 314 * (1 - progress/100);
|
@@ -736,7 +794,7 @@
|
|
736 |
if (progress >= 100) {
|
737 |
clearInterval(interval);
|
738 |
}
|
739 |
-
},
|
740 |
}
|
741 |
|
742 |
function hideLoading() {
|
|
|
383 |
scene.add(cabinetGroup);
|
384 |
updateCabinetModel();
|
385 |
|
386 |
+
// Add a grid helper and axes helper for debugging (can be removed in production)
|
387 |
+
const gridHelper = new THREE.GridHelper(100, 100);
|
388 |
+
scene.add(gridHelper);
|
389 |
+
|
390 |
+
const axesHelper = new THREE.AxesHelper(5);
|
391 |
+
axesHelper.position.y = 0.1; // Slightly above ground
|
392 |
+
scene.add(axesHelper);
|
393 |
+
|
394 |
// Handle window resize
|
395 |
window.addEventListener('resize', onWindowResize);
|
396 |
|
|
|
429 |
const shelvesCount = parseInt(shelvesSlider.value);
|
430 |
const drawersCount = cabinetType.value === 'base' ? parseInt(drawersSlider.value) : 0;
|
431 |
const hasGlassDoors = glassDoors.checked;
|
432 |
+
const thickness = 0.75; // Material thickness in inches
|
433 |
|
434 |
// Set main material
|
435 |
let mainMaterial = createMaterial(colorValue, false);
|
|
|
444 |
metalness: 0.0
|
445 |
});
|
446 |
|
447 |
+
// These factors help with converting inches to Three.js units
|
448 |
+
// Since Three.js uses arbitrary units, we'll treat 1 unit = 1 inch
|
449 |
+
const doorThickness = 0.75;
|
450 |
+
const handleSize = 2.0; // Door handle size
|
451 |
const shelfThickness = 0.5;
|
452 |
|
453 |
+
// Create the cabinet box structure first
|
454 |
+
let cabinetBox = new THREE.Group();
|
455 |
+
cabinetGroup.add(cabinetBox);
|
456 |
+
|
457 |
// Bottom panel
|
458 |
createPanel(width, thickness, depth,
|
459 |
[0, thickness/2, 0],
|
460 |
+
mainMaterial, cabinetBox);
|
461 |
|
462 |
// Top panel
|
463 |
createPanel(width, thickness, depth,
|
464 |
[0, height - thickness/2, 0],
|
465 |
+
mainMaterial, cabinetBox);
|
466 |
|
467 |
// Left side
|
468 |
createPanel(thickness, height - 2*thickness, depth,
|
469 |
[-width/2 + thickness/2, height/2, 0],
|
470 |
+
mainMaterial, cabinetBox);
|
471 |
|
472 |
// Right side
|
473 |
createPanel(thickness, height - 2*thickness, depth,
|
474 |
[width/2 - thickness/2, height/2, 0],
|
475 |
+
mainMaterial, cabinetBox);
|
476 |
|
477 |
// Back panel
|
478 |
createPanel(width - 2*thickness, height - 2*thickness, thickness,
|
479 |
[0, height/2, -depth/2 + thickness/2],
|
480 |
+
mainMaterial, cabinetBox);
|
481 |
+
|
482 |
+
// Calculate interior height (accounting for drawers if they exist)
|
483 |
+
const interiorHeight = height - 2*thickness - (drawersCount > 0 ? (height * 0.33) : 0);
|
484 |
|
485 |
+
// Middle divider if two doors (only extends down to drawer section if drawers exist)
|
486 |
if (isTwoDoors) {
|
487 |
+
const dividerHeight = drawersCount > 0 ? height - 2*thickness - (height * 0.33) : height - 2*thickness;
|
488 |
+
createPanel(thickness, dividerHeight, depth,
|
489 |
+
[0, (drawersCount > 0 ? (height/2 - (height * 0.33)/2) : height/2), 0],
|
490 |
+
mainMaterial, cabinetBox);
|
491 |
}
|
492 |
|
493 |
// Create doors
|
494 |
+
const doorHeight = drawersCount > 0 ? height - thickness - (height * 0.33) : height - 2*thickness;
|
495 |
+
const doorYPosition = drawersCount > 0 ? height/2 - (height * 0.33)/2 : height/2;
|
496 |
|
497 |
if (isTwoDoors) {
|
498 |
const doorWidth = (width - thickness) / 2;
|
499 |
|
500 |
// Left door
|
501 |
createDoor(doorWidth, doorHeight, doorThickness,
|
502 |
+
[-(width - thickness)/2 + doorThickness/2, doorYPosition, depth/2 - doorThickness/2],
|
503 |
+
mainMaterial, hasGlassDoors, true, cabinetBox);
|
504 |
|
505 |
// Right door
|
506 |
createDoor(doorWidth, doorHeight, doorThickness,
|
507 |
+
[(width - thickness)/2 - doorThickness/2, doorYPosition, depth/2 - doorThickness/2],
|
508 |
+
mainMaterial, hasGlassDoors, false, cabinetBox);
|
509 |
} else {
|
510 |
// Single door
|
511 |
const doorWidth = width;
|
512 |
createDoor(doorWidth, doorHeight, doorThickness,
|
513 |
[0, doorYPosition, depth/2 - doorThickness/2],
|
514 |
+
mainMaterial, hasGlassDoors, false, cabinetBox);
|
515 |
}
|
516 |
|
517 |
+
// Add shelves only in the upper section (above any drawers)
|
518 |
+
const availableHeight = interiorHeight;
|
519 |
const shelfSpacing = availableHeight / (shelvesCount + 1);
|
520 |
|
521 |
for (let i = 0; i < shelvesCount; i++) {
|
522 |
+
const shelfY = thickness + (i + 1) * shelfSpacing;
|
523 |
+
if (drawersCount > 0) {
|
524 |
+
// Adjust shelf position to be above the drawer section
|
525 |
+
const drawerSectionHeight = height * 0.33;
|
526 |
+
shelfY = thickness + (i + 1) * shelfSpacing + (height - thickness - drawerSectionHeight - availableHeight);
|
527 |
+
}
|
528 |
+
|
529 |
createShelf(width - 2*thickness - 0.5, shelfThickness, depth - thickness - 0.5,
|
530 |
+
[0, shelfY, 0],
|
531 |
+
shelfMaterial, cabinetBox);
|
532 |
}
|
533 |
|
534 |
// Add drawers for base cabinets
|
|
|
538 |
|
539 |
for (let i = 0; i < drawersCount; i++) {
|
540 |
const drawerY = thickness + i * drawerHeight + drawerHeight/2;
|
541 |
+
createDrawer(width, drawerHeight, depth * 0.8,
|
542 |
+
[0, drawerY, depth/2 - depth*0.1],
|
543 |
+
drawerFrontMaterial, mainMaterial, cabinetBox);
|
544 |
}
|
545 |
}
|
546 |
|
547 |
// Adjust camera target based on cabinet size
|
548 |
controls.target.set(0, height/2, 0);
|
549 |
controls.update();
|
550 |
+
camera.position.set(width * 1.2, height * 1.2, depth * 1.2);
|
551 |
|
552 |
// Update capacity calculation
|
553 |
const interiorWidth = width - 2*thickness;
|
|
|
554 |
const interiorDepth = depth - thickness;
|
555 |
const capacity = (interiorWidth * interiorHeight * interiorDepth) / 1728; // convert to cubic feet
|
556 |
|
|
|
561 |
capacityDisplay.textContent = `${capacity.toFixed(1)} cu.ft`;
|
562 |
dimensionsDisplay.textContent = `${width}" W × ${height}" H × ${depth}" D`;
|
563 |
shelvesDisplay.textContent = shelvesCount;
|
564 |
+
if (drawersCount > 0) {
|
565 |
+
drawersDisplay.textContent = drawersCount;
|
566 |
+
}
|
567 |
}
|
568 |
|
569 |
function createMaterial(colorValue, isDrawerFront = false) {
|
|
|
610 |
return new THREE.MeshStandardMaterial(materialOptions);
|
611 |
}
|
612 |
|
613 |
+
function createPanel(width, height, depth, position, material, parentGroup) {
|
614 |
const geometry = new THREE.BoxGeometry(width, height, depth);
|
615 |
const panel = new THREE.Mesh(geometry, material);
|
616 |
panel.castShadow = true;
|
617 |
panel.receiveShadow = true;
|
618 |
panel.position.set(position[0], position[1], position[2]);
|
619 |
+
parentGroup.add(panel);
|
620 |
return panel;
|
621 |
}
|
622 |
|
623 |
+
function createDoor(width, height, thickness, position, material, hasGlass, isLeftDoor, parentGroup) {
|
624 |
const doorGroup = new THREE.Group();
|
625 |
doorGroup.position.set(position[0], position[1], position[2]);
|
626 |
|
|
|
633 |
|
634 |
// Glass panel if selected
|
635 |
if (hasGlass) {
|
636 |
+
const glassWidth = width * 0.9;
|
637 |
+
const glassHeight = height * 0.8;
|
638 |
+
const glassGeometry = new THREE.BoxGeometry(glassWidth, glassHeight, thickness * 0.05);
|
639 |
const glassMaterial = new THREE.MeshPhysicalMaterial({
|
640 |
+
color: 0xE6F0FF,
|
641 |
+
transmission: 0.9,
|
642 |
+
roughness: 0.0,
|
643 |
metalness: 0.0,
|
644 |
transparent: true,
|
645 |
+
opacity: 0.8,
|
646 |
ior: 1.5,
|
647 |
thickness: 0.1
|
648 |
});
|
649 |
const glass = new THREE.Mesh(glassGeometry, glassMaterial);
|
650 |
+
glass.position.z = thickness * 0.3;
|
651 |
doorGroup.add(glass);
|
652 |
}
|
653 |
|
654 |
// Handle
|
655 |
+
const handleGeometry = new THREE.CylinderGeometry(0.5, 0.5, 3, 16);
|
656 |
const handleMaterial = new THREE.MeshStandardMaterial({ color: 0x333333 });
|
657 |
const handle = new THREE.Mesh(handleGeometry, handleMaterial);
|
658 |
handle.rotation.z = Math.PI/2;
|
659 |
handle.position.set(isLeftDoor ? -width/2 + 2 : width/2 - 2, 0, thickness);
|
660 |
doorGroup.add(handle);
|
661 |
|
662 |
+
// Hinges (simple representation)
|
663 |
+
const hingeGeometry = new THREE.CylinderGeometry(0.2, 0.2, 0.5, 16);
|
664 |
+
const hingeMaterial = new THREE.MeshStandardMaterial({ color: 0x888888 });
|
665 |
+
|
666 |
+
// Top hinge
|
667 |
+
const topHinge = new THREE.Mesh(hingeGeometry, hingeMaterial);
|
668 |
+
topHinge.rotation.x = Math.PI/2;
|
669 |
+
topHinge.position.set(isLeftDoor ? width/2 - 1 : -width/2 + 1, height/2 - 2, -thickness/2);
|
670 |
+
doorGroup.add(topHinge);
|
671 |
+
|
672 |
+
// Bottom hinge
|
673 |
+
const bottomHinge = new THREE.Mesh(hingeGeometry, hingeMaterial);
|
674 |
+
bottomHinge.rotation.x = Math.PI/2;
|
675 |
+
bottomHinge.position.set(isLeftDoor ? width/2 - 1 : -width/2 + 1, -height/2 + 2, -thickness/2);
|
676 |
+
doorGroup.add(bottomHinge);
|
677 |
+
|
678 |
+
parentGroup.add(doorGroup);
|
679 |
return doorGroup;
|
680 |
}
|
681 |
|
682 |
+
function createShelf(width, thickness, depth, position, material, parentGroup) {
|
683 |
const shelfGroup = new THREE.Group();
|
684 |
shelfGroup.position.set(position[0], position[1], position[2]);
|
685 |
|
|
|
691 |
shelfGroup.add(shelf);
|
692 |
|
693 |
// Shelf supports
|
694 |
+
const supportGeometry = new THREE.BoxGeometry(0.5, 1.5, 0.5);
|
695 |
const supportMaterial = new THREE.MeshStandardMaterial({ color: 0xCCCCCC });
|
696 |
|
697 |
// Left support
|
698 |
const leftSupport = new THREE.Mesh(supportGeometry, supportMaterial);
|
699 |
+
leftSupport.position.set(-width/2 + 0.25, -thickness/2 - 0.75, 0);
|
700 |
shelfGroup.add(leftSupport);
|
701 |
|
702 |
// Right support
|
703 |
const rightSupport = new THREE.Mesh(supportGeometry, supportMaterial);
|
704 |
+
rightSupport.position.set(width/2 - 0.25, -thickness/2 - 0.75, 0);
|
705 |
shelfGroup.add(rightSupport);
|
706 |
|
707 |
if (width > 24) {
|
708 |
// Middle support for wider shelves
|
709 |
const midSupport = new THREE.Mesh(supportGeometry, supportMaterial);
|
710 |
+
midSupport.position.set(0, -thickness/2 - 0.75, 0);
|
711 |
shelfGroup.add(midSupport);
|
712 |
}
|
713 |
|
714 |
+
parentGroup.add(shelfGroup);
|
715 |
return shelfGroup;
|
716 |
}
|
717 |
|
718 |
+
function createDrawer(width, height, depth, position, frontMaterial, sideMaterial, parentGroup) {
|
719 |
const drawerGroup = new THREE.Group();
|
720 |
drawerGroup.position.set(position[0], position[1], position[2]);
|
721 |
|
722 |
+
// Drawer body
|
723 |
+
const bodyWidth = width * 0.9;
|
724 |
+
const bodyHeight = height * 0.85;
|
725 |
+
const bodyDepth = depth;
|
726 |
|
727 |
// Front
|
728 |
+
const frontGeometry = new THREE.BoxGeometry(width, height, 0.5);
|
729 |
const front = new THREE.Mesh(frontGeometry, frontMaterial);
|
730 |
+
front.position.set(0, 0, depth/2 + 0.25);
|
731 |
drawerGroup.add(front);
|
732 |
|
733 |
// Bottom
|
734 |
+
const bottomGeometry = new THREE.BoxGeometry(width * 0.9, 0.2, depth);
|
735 |
const bottom = new THREE.Mesh(bottomGeometry, sideMaterial);
|
736 |
+
bottom.position.set(0, -height/2 + 0.1, 0);
|
737 |
drawerGroup.add(bottom);
|
738 |
|
739 |
// Sides
|
740 |
+
const sideWidth = width * 0.9;
|
741 |
+
const sideGeometry = new THREE.BoxGeometry(0.2, bodyHeight, depth);
|
742 |
|
743 |
// Left side
|
744 |
const leftSide = new THREE.Mesh(sideGeometry, sideMaterial);
|
745 |
+
leftSide.position.set(-sideWidth/2, 0, 0);
|
746 |
drawerGroup.add(leftSide);
|
747 |
|
748 |
// Right side
|
749 |
const rightSide = new THREE.Mesh(sideGeometry, sideMaterial);
|
750 |
+
rightSide.position.set(sideWidth/2, 0, 0);
|
751 |
drawerGroup.add(rightSide);
|
752 |
|
753 |
// Back
|
754 |
+
const backGeometry = new THREE.BoxGeometry(sideWidth, bodyHeight, 0.2);
|
755 |
const back = new THREE.Mesh(backGeometry, sideMaterial);
|
756 |
+
back.position.set(0, 0, -depth/2 + 0.1);
|
757 |
drawerGroup.add(back);
|
758 |
|
759 |
+
// Handle (as a bar)
|
760 |
+
const handleGeometry = new THREE.CylinderGeometry(0.3, 0.3, 3, 16);
|
761 |
const handleMaterial = new THREE.MeshStandardMaterial({ color: 0x333333 });
|
762 |
const handle = new THREE.Mesh(handleGeometry, handleMaterial);
|
763 |
handle.rotation.z = Math.PI/2;
|
764 |
+
handle.position.set(0, 0, depth/2 + 0.3);
|
765 |
drawerGroup.add(handle);
|
766 |
|
767 |
+
// Drawer slides
|
768 |
+
const slideGeometry = new THREE.BoxGeometry(0.1, 0.5, depth * 1.2);
|
769 |
+
const slideMaterial = new THREE.MeshStandardMaterial({ color: 0x888888 });
|
770 |
+
|
771 |
+
// Left slide
|
772 |
+
const leftSlide = new THREE.Mesh(slideGeometry, slideMaterial);
|
773 |
+
leftSlide.position.set(-width/2 + 0.25, -height/2 + 0.25, 0);
|
774 |
+
drawerGroup.add(leftSlide);
|
775 |
+
|
776 |
+
// Right slide
|
777 |
+
const rightSlide = new THREE.Mesh(slideGeometry, slideMaterial);
|
778 |
+
rightSlide.position.set(width/2 - 0.25, -height/2 + 0.25, 0);
|
779 |
+
drawerGroup.add(rightSlide);
|
780 |
+
|
781 |
+
parentGroup.add(drawerGroup);
|
782 |
return drawerGroup;
|
783 |
}
|
784 |
|
|
|
786 |
loadingOverlay.style.opacity = 1;
|
787 |
loadingOverlay.style.pointerEvents = 'auto';
|
788 |
let progress = 0;
|
789 |
+
progressRing.style.strokeDashoffset = 314;
|
790 |
const interval = setInterval(() => {
|
791 |
progress += 10;
|
792 |
const offset = 314 * (1 - progress/100);
|
|
|
794 |
if (progress >= 100) {
|
795 |
clearInterval(interval);
|
796 |
}
|
797 |
+
}, 50);
|
798 |
}
|
799 |
|
800 |
function hideLoading() {
|