"use client"; import { Canvas } from "@react-three/fiber"; import { OrbitControls, PerspectiveCamera, Environment, ContactShadows, RoundedBox, } from "@react-three/drei"; import { Door3DEnhanced } from "./door-3d-enhanced"; import { useConfiguratorStore } from "@/lib/store"; import { STELRUIMTE, WALL_THICKNESS, mmToMeters, } from "@/lib/door-models"; import * as THREE from "three"; // ============================================ // MATERIALS // ============================================ const WallMaterial = () => ( ); const RevealMaterial = () => ( ); const FloorMaterial = () => ( ); const WoodMaterial = () => ( ); const DarkMetalMaterial = () => ( ); // ============================================ // WALL CONTAINER WITH PRECISE HOLE // ============================================ function WallContainer({ holeWidth, holeHeight, wallThickness, }: { holeWidth: number; holeHeight: number; wallThickness: number; }) { const wallWidth = 4.0; const wallHeight = 3.0; const halfHoleW = holeWidth / 2; const halfWallT = wallThickness / 2; const leftSectionWidth = (wallWidth - holeWidth) / 2; const leftSectionX = -(halfHoleW + leftSectionWidth / 2); const rightSectionWidth = leftSectionWidth; const rightSectionX = halfHoleW + rightSectionWidth / 2; const topSectionHeight = wallHeight - holeHeight; const topSectionY = holeHeight + topSectionHeight / 2; const gapPerSide = mmToMeters(STELRUIMTE / 2); return ( {/* Main wall sections */} {topSectionHeight > 0.01 && ( )} {/* Reveal surfaces */} {/* Reveal depth surfaces */} {/* Baseboard - front side */} ); } // ============================================ // ROOM STRUCTURE // ============================================ function RoomShell() { const wallHeight = 3.0; const roomDepth = 3.5; const roomWidth = 7.0; // Much wider than the 4m back wall const sideWallThickness = 0.08; const floorSize = 10; return ( {/* Front floor (viewer side) */} {/* Back floor (behind wall) */} {/* Floor plank lines (viewer side) */} {Array.from({ length: 20 }).map((_, i) => { const x = -2.7 + i * 0.27; return ( ); })} {/* Left side wall */} {/* Right side wall */} {/* Left side baseboard */} {/* Right side baseboard */} {/* Ceiling (partial - hint near the wall) */} {/* Back room - bedroom visible through glass door */} ); } // ============================================ // BEDROOM (visible through the glass door) // ============================================ function Bedroom() { const wallWidth = 4.0; const wallHeight = 3.0; const roomDepth = 4.0; const backZ = -roomDepth; return ( {/* Back wall */} {/* Left side wall (bedroom) */} {/* Right side wall (bedroom) */} {/* Bedroom ceiling */} {/* Bedroom baseboard - back wall */} {/* Bedroom baseboard - left */} {/* Bedroom baseboard - right */} {/* Window on back wall (bright rectangle suggesting daylight) */} {/* Window frame */} {[ { pos: [0, 2.1, backZ + 0.015] as [number, number, number], size: [1.26, 0.03, 0.02] as [number, number, number] }, { pos: [0, 1.1, backZ + 0.015] as [number, number, number], size: [1.26, 0.03, 0.02] as [number, number, number] }, { pos: [-0.615, 1.6, backZ + 0.015] as [number, number, number], size: [0.03, 1.06, 0.02] as [number, number, number] }, { pos: [0.615, 1.6, backZ + 0.015] as [number, number, number], size: [0.03, 1.06, 0.02] as [number, number, number] }, { pos: [0, 1.6, backZ + 0.015] as [number, number, number], size: [0.02, 1.0, 0.02] as [number, number, number] }, { pos: [0, 1.6, backZ + 0.015] as [number, number, number], size: [1.2, 0.02, 0.02] as [number, number, number] }, ].map((f, i) => ( ))} {/* Window light */} {/* === BED === */} {/* Bed frame base */} {/* Mattress */} {/* Duvet/blanket */} {/* Duvet fold at top */} {/* Pillows */} {/* Headboard */} {/* Bed legs (metal) */} {[ [-0.72, 0, -0.97], [0.72, 0, -0.97], [-0.72, 0, 0.97], [0.72, 0, 0.97], ].map(([x, _, z], i) => ( ))} {/* === NIGHTSTAND LEFT === */} {/* Legs */} {[[-0.17, -0.14], [0.17, -0.14], [-0.17, 0.14], [0.17, 0.14]].map(([x, z], i) => ( ))} {/* Lamp on nightstand */} {/* === NIGHTSTAND RIGHT === */} {[[-0.17, -0.14], [0.17, -0.14], [-0.17, 0.14], [0.17, 0.14]].map(([x, z], i) => ( ))} {/* Small plant on nightstand */} {/* === BEDROOM RUG === */} {/* === CEILING LIGHT (bedroom) === */} {/* === WALL ART (bedroom back wall) === */} {/* Simple abstract circle */} {/* Frame */} {[ [0, 0.225, 0.35, 0.02], [0, -0.225, 0.35, 0.02], [-0.175, 0, 0.02, 0.45], [0.175, 0, 0.02, 0.45], ].map(([x, y, w, h], i) => ( ))} {/* Second art piece */} {[ [0, 0.2, 0.3, 0.02], [0, -0.2, 0.3, 0.02], [-0.15, 0, 0.02, 0.4], [0.15, 0, 0.02, 0.4], ].map(([x, y, w, h], i) => ( ))} ); } // ============================================ // FURNITURE: SIDEBOARD // ============================================ function Sideboard() { const bodyW = 0.9; const bodyH = 0.44; const bodyD = 0.36; const legH = 0.12; const yBody = legH + bodyH / 2; const wallFaceZ = 0.075; // Front face of main wall return ( {/* Body */} {/* Top surface (darker edge) */} {/* Metal legs */} {[ [-bodyW / 2 + 0.06, 0, -bodyD / 2 + 0.06], [bodyW / 2 - 0.06, 0, -bodyD / 2 + 0.06], [-bodyW / 2 + 0.06, 0, bodyD / 2 - 0.06], [bodyW / 2 - 0.06, 0, bodyD / 2 - 0.06], ].map(([x, _, z], i) => ( ))} {/* Drawer line (decorative) */} ); } // ============================================ // FURNITURE: DECORATIVE OBJECTS // ============================================ function VaseWithBranches() { const wallFaceZ = 0.075; return ( {/* Vase body */} {/* Vase neck */} {/* Rim */} {/* Dried branches */} {[ { rot: [0.2, 0, 0.1] as [number, number, number], h: 0.3 }, { rot: [-0.15, 1.2, -0.1] as [number, number, number], h: 0.28 }, { rot: [0.1, 2.5, 0.2] as [number, number, number], h: 0.25 }, ].map((branch, i) => ( ))} ); } function BookStack() { const wallFaceZ = 0.075; return ( {[ { w: 0.15, h: 0.022, d: 0.1, color: "#2c3e50", y: 0 }, { w: 0.14, h: 0.018, d: 0.1, color: "#7f8c8d", y: 0.02 }, { w: 0.13, h: 0.016, d: 0.1, color: "#8e4a3b", y: 0.037 }, ].map((book, i) => ( ))} ); } // ============================================ // FURNITURE: TALL PLANT // ============================================ function TallPlant() { const wallFaceZ = 0.075; return ( {/* Pot */} {/* Pot rim */} {/* Soil */} {/* Trunk */} {/* Secondary trunk */} {/* Foliage clusters */} {[ [0, 0.92, 0, 0.14], [0.08, 0.84, 0.04, 0.11], [-0.07, 0.86, -0.03, 0.10], [0.04, 0.78, -0.06, 0.09], [-0.03, 0.97, 0.03, 0.10], [0.1, 0.72, 0.02, 0.08], [-0.05, 0.76, 0.05, 0.08], ].map(([x, y, z, r], i) => ( ))} ); } // ============================================ // FURNITURE: PENDANT LIGHT // ============================================ function PendantLight() { return ( {/* Cord */} {/* Canopy (ceiling mount) */} {/* Shade - open bottom */} {/* Shade rim */} {/* Warm point light (simulates bulb glow) */} ); } // ============================================ // FURNITURE: PICTURE FRAME // ============================================ function PictureFrame() { const frameW = 0.45; const frameH = 0.55; const border = 0.025; const wallFaceZ = 0.076; return ( {/* Canvas/art (abstract warm tones) */} {/* Abstract shape 1 */} {/* Abstract shape 2 */} {/* Frame border */} {[ { pos: [0, frameH / 2 - border / 2, 0.005] as [number, number, number], size: [frameW, border, 0.018] as [number, number, number] }, { pos: [0, -frameH / 2 + border / 2, 0.005] as [number, number, number], size: [frameW, border, 0.018] as [number, number, number] }, { pos: [-frameW / 2 + border / 2, 0, 0.005] as [number, number, number], size: [border, frameH, 0.018] as [number, number, number] }, { pos: [frameW / 2 - border / 2, 0, 0.005] as [number, number, number], size: [border, frameH, 0.018] as [number, number, number] }, ].map((side, i) => ( ))} ); } // ============================================ // FURNITURE: RUG // ============================================ function Rug() { return ( ); } // ============================================ // FURNITURE: SMALL SIDE TABLE (right side) // ============================================ function SideTable() { const wallFaceZ = 0.075; const tableR = 0.18; const tableH = 0.5; return ( {/* Tabletop */} {/* Single leg */} {/* Base */} {/* Small decorative candle */} ); } // ============================================ // DOOR + WALL COMPOSITION // ============================================ /** * Side panel: a fixed glass panel with steel frame, rendered next to the door. */ function SidePanelMesh({ panelWidth, panelHeight, finish, glassColor, }: { panelWidth: number; // meters panelHeight: number; // meters finish: import("@/lib/store").Finish; glassColor: import("@/lib/store").GlassColor; }) { const profileW = mmToMeters(40); const profileD = mmToMeters(40); const glassThick = mmToMeters(7); const FRAME_COLORS_LOCAL: Record = { zwart: "#1a1a1a", brons: "#8B6F47", grijs: "#525252", goud: "#B8860B", beige: "#C8B88A", ral: "#4A6741", }; const GLASS_COLORS_LOCAL: Record = { helder: { color: "#eff6ff", transmission: 0.98, roughness: 0.05 }, grijs: { color: "#3a3a3a", transmission: 0.85, roughness: 0.1 }, brons: { color: "#8B6F47", transmission: 0.85, roughness: 0.1 }, "mat-blank": { color: "#e8e8e8", transmission: 0.7, roughness: 0.3 }, "mat-brons": { color: "#A0845C", transmission: 0.6, roughness: 0.35 }, "mat-zwart": { color: "#1a1a1a", transmission: 0.5, roughness: 0.4 }, }; const frameColor = FRAME_COLORS_LOCAL[finish] || "#1a1a1a"; const glassProps = GLASS_COLORS_LOCAL[glassColor] || GLASS_COLORS_LOCAL.helder; const innerW = panelWidth - profileW * 2; const innerH = panelHeight - profileW * 2; return ( {/* Left stile */} {/* Right stile */} {/* Top rail */} {/* Bottom rail */} {/* Glass */} ); } function DoorInWall() { const { doorType, doorConfig, sidePanel, doorLeafWidth, sidePanelWidth, height, finish, glassColor } = useConfiguratorStore(); const doorWidthM = mmToMeters(doorLeafWidth); const doorHeightM = mmToMeters(height); const wallThicknessM = mmToMeters(WALL_THICKNESS); const stelruimteM = mmToMeters(STELRUIMTE); const sidePanelWidthM = mmToMeters(sidePanelWidth); const isDouble = doorConfig === "dubbele"; // Total door section width (all leaves) const doorSectionW = isDouble ? doorWidthM * 2 : doorWidthM; // Total hole width including side panels let holeWidthM = doorSectionW + stelruimteM; if (sidePanel === "links" || sidePanel === "rechts") holeWidthM += sidePanelWidthM; if (sidePanel === "beide") holeWidthM += sidePanelWidthM * 2; const holeHeightM = doorHeightM + stelruimteM / 2; const doorZOffset = doorType === "taats" ? 0 : wallThicknessM * 0.15; // Calculate X offset for the door(s) when side panels shift the center let doorCenterX = 0; if (sidePanel === "links") doorCenterX = sidePanelWidthM / 2; if (sidePanel === "rechts") doorCenterX = -sidePanelWidthM / 2; return ( <> {/* Door leaf(s) */} {isDouble ? ( ) : ( )} {/* Side panels */} {(sidePanel === "links" || sidePanel === "beide") && sidePanelWidthM > 0 && ( )} {(sidePanel === "rechts" || sidePanel === "beide") && sidePanelWidthM > 0 && ( )} ); } // ============================================ // LIGHTING // ============================================ function Lighting() { return ( <> {/* Main sunlight */} {/* Fill light from behind wall (simulates light from back room) */} {/* Viewer-side fill to show furniture */} {/* Top-down for reveal and furniture shadows */} ); } // ============================================ // MAIN SCENE EXPORT // ============================================ export function Scene3D() { return ( {/* Room structure */} {/* Door in wall */} {/* Interior furniture */} ); }