From 748a5814e7c10d9eb93be1ceec3afaccfb2d261c Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sat, 14 Feb 2026 01:23:18 +0000 Subject: [PATCH] feat: Wall mounting system with Sparingsmaat logic and reveal surfaces Phase 1 (Logic): Add Dutch mounting constants to door-models.ts - STELRUIMTE=10mm (tolerance), HANGNAAD=3mm (gap per side) - WALL_THICKNESS=150mm (standard interior wall) - calculateMountingDimensions() derives frame/leaf from sparingsmaat Phase 2 (Visual): Replace LivingRoom with WallContainer in scene.tsx - 4-box wall construction with precise rectangular hole - Hole = doorLeafWidth + STELRUIMTE (visible 5mm gap per side) - Door sits INSIDE the wall, not in front of it Phase 3 (Detail): Reveal surfaces and door-type positioning - Plaster/stucco material on reveal edges (inner hole surfaces) - Taats: door centered in wall depth (pivot at center) - Scharnier/Paneel: offset toward front face - Dedicated fill light illuminating reveal depth - Baseboard (plint) on both sides of opening Co-Authored-By: Claude Opus 4.6 --- components/configurator/scene.tsx | 425 +++++++++++++++++++----------- lib/door-models.ts | 33 +++ 2 files changed, 298 insertions(+), 160 deletions(-) diff --git a/components/configurator/scene.tsx b/components/configurator/scene.tsx index add7578..fc16a0d 100644 --- a/components/configurator/scene.tsx +++ b/components/configurator/scene.tsx @@ -1,182 +1,274 @@ "use client"; import { Canvas } from "@react-three/fiber"; -import { OrbitControls, PerspectiveCamera, Environment, ContactShadows } from "@react-three/drei"; +import { + OrbitControls, + PerspectiveCamera, + Environment, + ContactShadows, +} from "@react-three/drei"; import { Door3DEnhanced } from "./door-3d-enhanced"; import { useConfiguratorStore } from "@/lib/store"; +import { + STELRUIMTE, + WALL_THICKNESS, + TAATS_PIVOT_OFFSET, + mmToMeters, +} from "@/lib/door-models"; import * as THREE from "three"; -function LivingRoom({ doorWidth, doorHeight }: { doorWidth: number; doorHeight: number }) { - const wallThickness = 0.15; - const roomWidth = 8; - const roomDepth = 6; - const roomHeight = 3; +// ============================================ +// WALL MATERIALS +// ============================================ - // Calculate dynamic doorway dimensions - const doorwayWidth = doorWidth + wallThickness * 2 + 0.1; // Extra margin - const doorwayHeight = doorHeight + wallThickness + 0.1; +/** Smooth painted wall surface */ +const WallMaterial = () => ( + +); + +/** Stucco/plaster reveal surface (inside the door opening) */ +const RevealMaterial = () => ( + +); + +/** Floor material - light wood */ +const FloorMaterial = () => ( + +); + +// ============================================ +// WALL CONTAINER WITH PRECISE HOLE +// ============================================ + +/** + * Creates a wall with a precise rectangular opening (sparing). + * Uses 4 boxes to form the wall around the hole instead of CSG. + * The reveal (inner edge of the hole) has a plaster texture. + */ +function WallContainer({ + holeWidth, + holeHeight, + wallThickness, +}: { + holeWidth: number; // meters - sparingsmaat width + holeHeight: number; // meters - sparingsmaat height + wallThickness: number; // meters +}) { + const wallWidth = 4.0; // Total wall width in meters + const wallHeight = 3.0; // Total wall height (floor to ceiling) + + // Half dimensions for positioning + const halfHoleW = holeWidth / 2; + const halfWallT = wallThickness / 2; + + // Left wall section: from left edge to hole left edge + const leftSectionWidth = (wallWidth - holeWidth) / 2; + const leftSectionX = -(halfHoleW + leftSectionWidth / 2); + + // Right wall section: from hole right edge to right edge + const rightSectionWidth = leftSectionWidth; + const rightSectionX = halfHoleW + rightSectionWidth / 2; + + // Top section: above hole, full width + const topSectionHeight = wallHeight - holeHeight; + const topSectionY = holeHeight + topSectionHeight / 2; + + // Stelruimte gap (visual indicator) + const gapPerSide = mmToMeters(STELRUIMTE / 2); return ( - - {/* Floor - Modern light wood */} - - - + + {/* === MAIN WALL SECTIONS === */} + + {/* Left wall section */} + + + - {/* Back Wall with Dynamic Doorway */} - - {/* Left Pillar - Dynamic height */} - - - - - - {/* Right Pillar - Dynamic height */} - - - - - - {/* Doorway Frame - Left */} - - - - - - {/* Doorway Frame - Right */} - - - - - - {/* Doorway Frame - Top (Lintel) */} - - - - - - {/* Main Wall - Left Section */} - - - - - - {/* Main Wall - Right Section */} - - - - - - {/* Main Wall - Top Section (above doorway) */} - - - - - - - {/* Left Wall */} - - - + {/* Right wall section */} + + + - {/* Right Wall */} - - - + {/* Top section (above hole, full wall width) */} + {topSectionHeight > 0.01 && ( + + + + + )} + + {/* === REVEAL SURFACES (inside the hole) === */} + {/* These are the plaster/stucco edges visible inside the opening */} + + {/* Left reveal */} + + + - {/* Ceiling */} - - - + {/* Right reveal */} + + + - {/* Decorative Elements - Baseboard Left */} - - - + {/* Top reveal */} + + + - {/* Decorative Elements - Baseboard Right */} - - - + {/* === REVEAL DEPTH SURFACES (visible sides inside the opening) === */} + {/* Left inner wall (visible when looking at the opening from the side) */} + + + + + + {/* Right inner wall */} + + + + + + {/* Top inner wall (lintel reveal) */} + + + + + + {/* === FLOOR === */} + + + + + + {/* Floor behind wall */} + + + + + + {/* === BASEBOARD (Plint) === */} + {/* Left side baseboard */} + + + + + + {/* Right side baseboard */} + + + ); } -function DoorWithRoom() { - const { doorLeafWidth, height } = useConfiguratorStore(); +// ============================================ +// DOOR + WALL COMPOSITION +// ============================================ - // Convert mm to meters for 3D scene - const doorWidth = doorLeafWidth / 1000; - const doorHeight = height / 1000; +function DoorInWall() { + const { doorType, doorLeafWidth, height, holeWidth } = useConfiguratorStore(); + + // Convert mm to meters + const doorWidthM = mmToMeters(doorLeafWidth); + const doorHeightM = mmToMeters(height); + const wallThicknessM = mmToMeters(WALL_THICKNESS); + + // Sparingsmaat = the hole in the wall + // Use doorLeafWidth + stelruimte as the opening size + const stelruimteM = mmToMeters(STELRUIMTE); + const holeWidthM = doorWidthM + stelruimteM; + const holeHeightM = doorHeightM + stelruimteM / 2; // 5mm top tolerance + + // Door Z position depends on type + // Taats: centered in wall thickness (pivot at center) + // Scharnier/Paneel: flush with front wall face + const doorZOffset = doorType === 'taats' ? 0 : wallThicknessM * 0.15; return ( <> - - + {/* The wall with precise opening */} + + + {/* The door, positioned inside the wall opening */} + + + ); } +// ============================================ +// LIGHTING +// ============================================ + function Lighting() { return ( <> {/* Ambient for overall illumination */} - + - {/* Main directional light (sunlight from window) */} + {/* Main directional light (sunlight angle) */} - {/* Fill light from opposite side */} - + {/* Fill light from behind/left to illuminate reveal */} + - {/* Subtle top light */} - + {/* Subtle light from viewer side to show depth in reveal */} + + + {/* Top down light for reveal shadows */} + ); } +// ============================================ +// MAIN SCENE EXPORT +// ============================================ + export function Scene3D() { return ( - {/* Camera - Zoomed out for room context */} - + {/* Camera - positioned for wall view */} + - {/* Camera Controls - More freedom for room viewing */} + {/* Camera Controls */} - {/* Premium Studio Lighting */} + {/* Lighting */} - {/* Apartment Environment for warm, realistic steel reflections */} + {/* Apartment Environment for warm reflections */} - {/* High-Resolution Contact Shadows for grounding */} + {/* Contact shadows for floor grounding */} - {/* The Door - Enhanced with textures and dimensions */} - + {/* Door mounted inside wall */} + ); } diff --git a/lib/door-models.ts b/lib/door-models.ts index 87baf23..3e8c2b2 100644 --- a/lib/door-models.ts +++ b/lib/door-models.ts @@ -39,6 +39,39 @@ export const RAIL_HEIGHT_ROBUST = 40; // mm - Standard robust rails (same as pro */ export const TAATS_PIVOT_OFFSET = 60; // mm - Pivot axis offset from wall for Taats doors +/** + * Wall Mounting Dimensions (Sparingsmaat / Deurmaat) + * Dutch building standard: Sparingsmaat = rough wall opening + */ +export const STELRUIMTE = 10; // mm - Total tolerance between wall and frame (5mm per side) +export const HANGNAAD = 3; // mm - Gap between frame and door leaf per side +export const WALL_THICKNESS = 150; // mm - Standard interior wall thickness + +/** + * Calculate mounting dimensions from Sparingsmaat (wall opening). + * + * Sparingsmaat (input) -> Frame -> Door Leaf + * Frame = Sparingsmaat - STELRUIMTE (10mm tolerance) + * DoorLeaf = Frame - 2*PROFILE_WIDTH - 2*HANGNAAD (6mm gap) + */ +export function calculateMountingDimensions(sparingsmaatWidth: number, sparingsmaatHeight: number) { + const frameOuterWidth = sparingsmaatWidth - STELRUIMTE; + const frameOuterHeight = sparingsmaatHeight - STELRUIMTE / 2; // 5mm top tolerance only + const doorLeafWidth = frameOuterWidth - (2 * HANGNAAD); + const doorLeafHeight = frameOuterHeight - (2 * HANGNAAD); + + return { + sparingsmaatWidth, + sparingsmaatHeight, + frameOuterWidth, + frameOuterHeight, + doorLeafWidth, + doorLeafHeight, + stelruimtePerSide: STELRUIMTE / 2, // 5mm gap visible on each side + hangnaadPerSide: HANGNAAD, // 3mm gap between frame and leaf + }; +} + // ============================================ // PHYSICAL PART TYPES // ============================================