diff --git a/components/configurator/door-3d-enhanced.tsx b/components/configurator/door-3d-enhanced.tsx new file mode 100644 index 0000000..10451d9 --- /dev/null +++ b/components/configurator/door-3d-enhanced.tsx @@ -0,0 +1,266 @@ +"use client"; + +import { useRef } from "react"; +import { useConfiguratorStore } from "@/lib/store"; +import { RoundedBox, Text, useTexture } from "@react-three/drei"; +import { getMetalTexture } from "@/lib/asset-map"; +import * as THREE from "three"; + +// Steel material with photorealistic texture mapping +const SteelMaterial = ({ color, finish }: { color: string; finish: string }) => { + try { + const metalTexture = useTexture(getMetalTexture(finish)); + + // Configure texture repeat for realistic grain (4x horizontal, 8x vertical) + metalTexture.wrapS = metalTexture.wrapT = THREE.RepeatWrapping; + metalTexture.repeat.set(4, 8); + + return ( + + ); + } catch (error) { + // Fallback to solid color if texture fails + return ( + + ); + } +}; + +// Glass material +const GlassMaterial = () => ( + +); + +// 3D Dimension Label Component +function DimensionLabel({ + value, + position, + label, +}: { + value: number; + position: [number, number, number]; + label: string; +}) { + return ( + + + {`${Math.round(value)} ${label}`} + + {/* Background for better readability */} + + + + + + ); +} + +export function Door3DEnhanced() { + const { doorType, gridType, finish, handle, doorLeafWidth, height } = + useConfiguratorStore(); + const doorRef = useRef(null); + + // Frame color based on finish + const frameColor = { + zwart: "#1a1a1a", + brons: "#8B6F47", + grijs: "#525252", + }[finish]; + + // Convert mm to meters for 3D scene + const doorWidth = doorLeafWidth / 1000; // Convert mm to m + const doorHeight = height / 1000; // Convert mm to m + + // Profile dimensions (in meters) + const stileWidth = 0.04; // 40mm vertical profiles + const stileDepth = 0.04; // 40mm depth + const railHeight = 0.02; // 20mm horizontal profiles + const railDepth = 0.04; // 40mm depth + const glassThickness = 0.008; // 8mm glass + const profileRadius = 0.001; // 1mm rounded corners + + // Calculate positions for grid dividers + const getDividerPositions = () => { + if (gridType === "3-vlak") { + return [-doorHeight / 3, doorHeight / 3]; + } else if (gridType === "4-vlak") { + return [-doorHeight / 2, 0, doorHeight / 2]; + } + return []; + }; + + const dividerPositions = getDividerPositions(); + + return ( + + {/* LEFT STILE - Vertical profile */} + + + + + {/* RIGHT STILE - Vertical profile */} + + + + + {/* TOP RAIL - Horizontal profile */} + + + + + {/* BOTTOM RAIL - Horizontal profile */} + + + + + {/* INTERMEDIATE RAILS (Grid dividers) */} + {dividerPositions.map((yPos, index) => ( + + + + ))} + + {/* VERTICAL DIVIDER for Paneel */} + {doorType === "paneel" && ( + + + + )} + + {/* GLASS PANEL - Sits inside the frame */} + + + + + + {/* HANDLE - U-Greep for Taats */} + {doorType === "taats" && handle === "u-greep" && ( + + + + )} + + {/* HANDLE - Klink for Scharnier */} + {doorType === "scharnier" && handle === "klink" && ( + + + + + + + + + + )} + + {/* 3D DIMENSION LABELS */} + {/* Width dimension */} + + + {/* Height dimension */} + + + {/* Dimension lines */} + {/* Horizontal line for width */} + + + + + + {/* Vertical line for height */} + + + + + + ); +} diff --git a/components/configurator/scene.tsx b/components/configurator/scene.tsx index e9c8766..6e2f744 100644 --- a/components/configurator/scene.tsx +++ b/components/configurator/scene.tsx @@ -2,7 +2,7 @@ import { Canvas } from "@react-three/fiber"; import { OrbitControls, PerspectiveCamera, Environment, ContactShadows } from "@react-three/drei"; -import { Door3D } from "./door-3d"; +import { Door3DEnhanced } from "./door-3d-enhanced"; import * as THREE from "three"; function Room() { @@ -152,8 +152,8 @@ export function Scene3D() { {/* The Room */} - {/* The Door */} - + {/* The Door - Enhanced with textures and dimensions */} + ); } diff --git a/lib/asset-map.ts b/lib/asset-map.ts new file mode 100644 index 0000000..006a9b6 --- /dev/null +++ b/lib/asset-map.ts @@ -0,0 +1,125 @@ +/** + * Asset mapping for Aluwdoors textures + * Maps configurator state values to texture file paths + */ + +export type MetalTexture = 'antraciet' | 'beige' | 'brons' | 'goud' | 'zwart' | 'ral'; +export type GlassTexture = 'blank' | 'brons-tint' | 'grijs-tint' | 'mat-blank' | 'mat-brons' | 'mat-zwart'; +export type HandleType = 'beugelgreep' | 'geen' | 'hoekgreep' | 'maangreep' | 'ovaalgreep'; +export type DividerType = 'platte-roede' | 't-roede'; + +const TEXTURE_BASE = '/textures/aluwdoors'; + +/** + * Metal texture mapping + */ +export const metalTextures: Record = { + antraciet: `${TEXTURE_BASE}/aluwdoors-configurator-metaalkleur-antraciet.jpg`, + beige: `${TEXTURE_BASE}/aluwdoors-configurator-metaalkleur-beige.jpg`, + brons: `${TEXTURE_BASE}/aluwdoors-configurator-metaalkleur-brons.jpg`, + goud: `${TEXTURE_BASE}/aluwdoors-configurator-metaalkleur-goud.jpg`, + zwart: `${TEXTURE_BASE}/aluwdoors-configurator-metaalkleur-zwart.jpg`, + ral: `${TEXTURE_BASE}/aluwdoors-configurator-metaalkleur-ral-keuze.jpg`, +}; + +/** + * Glass texture mapping + */ +export const glassTextures: Record = { + 'blank': `${TEXTURE_BASE}/aluwdoors-configurator-glaskleur-blank.jpg`, + 'brons-tint': `${TEXTURE_BASE}/aluwdoors-configurator-glaskleur-brons.jpg`, + 'grijs-tint': `${TEXTURE_BASE}/aluwdoors-configurator-glaskleur-grijs.jpg`, + 'mat-blank': `${TEXTURE_BASE}/aluwdoors-configurator-glaskleur-mat-blank.jpg`, + 'mat-brons': `${TEXTURE_BASE}/aluwdoors-configurator-glaskleur-mat-brons.jpg`, + 'mat-zwart': `${TEXTURE_BASE}/aluwdoors-configurator-glaskleur-mat-zwart.jpg`, +}; + +/** + * Handle SVG mapping + */ +export const handleSVGs: Record = { + beugelgreep: `${TEXTURE_BASE}/aluwdoors-configurator-fineer-handgreep-beugelgreep.svg`, + geen: `${TEXTURE_BASE}/aluwdoors-configurator-fineer-handgreep-geen.svg`, + hoekgreep: `${TEXTURE_BASE}/aluwdoors-configurator-fineer-handgreep-hoekgreep.svg`, + maangreep: `${TEXTURE_BASE}/aluwdoors-configurator-fineer-handgreep-maangreep.svg`, + ovaalgreep: `${TEXTURE_BASE}/aluwdoors-configurator-fineer-handgreep-ovaalgreep.svg`, +}; + +/** + * Divider SVG mapping + */ +export const dividerSVGs: Record = { + 'platte-roede': `${TEXTURE_BASE}/aluwdoors-configurator-roedetype-platte-roede.svg`, + 't-roede': `${TEXTURE_BASE}/aluwdoors-configurator-roedetype-t-roede.svg`, +}; + +/** + * Map store finish values to metal textures + */ +export function getMetalTexture(finish: string): string { + const mapping: Record = { + 'zwart': 'zwart', + 'brons': 'brons', + 'grijs': 'antraciet', + }; + + return metalTextures[mapping[finish] || 'zwart']; +} + +/** + * Glass material properties based on texture type + */ +export interface GlassMaterialProps { + texture: string; + transmission: number; + roughness: number; + color: string; + opacity: number; +} + +export function getGlassMaterial(glassType: GlassTexture): GlassMaterialProps { + // Frosted/Mat glass + if (glassType.startsWith('mat')) { + return { + texture: glassTextures[glassType], + transmission: 0.6, + roughness: 0.4, + color: '#ffffff', + opacity: 0.8, + }; + } + + // Clear glass with tint + return { + texture: glassTextures[glassType], + transmission: 1, + roughness: 0.05, + color: '#eff6ff', + opacity: 0.3, + }; +} + +/** + * Aluwdoors extracted color scheme + */ +export const aluwColors = { + // Primary action color (from CSS analysis) + primary: '#b1de6e', // Pistachio green + primaryDark: '#9fcd5b', + + // Dark backgrounds + darkest: '#1b2221', + dark: '#2b3937', + darkMedium: '#3e4b49', + + // Light backgrounds + light: '#e0e5e5', + lightest: '#f0f3f3', + + // Neutral + gray: '#868c8b', + + // Accent/Error + error: '#e74242', + errorDark: '#c40c0c', +} as const;