/**
* ModelViewer3D - Interactive 3D model viewer using React Three Fiber.
*/
import { Suspense, useEffect } from 'react';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import { useGLTF, OrbitControls, Html, Loader, Environment, ContactShadows } from '@react-three/drei';
import * as THREE from 'three';
import { motion } from 'framer-motion';
import type { LightPreset } from '../types';
interface ModelViewer3DProps {
url: string;
wireframe: boolean;
lightPreset: LightPreset;
autoRotate: boolean;
}
function AutoScaledModel({ url, wireframe }: { url: string; wireframe: boolean }) {
const { scene } = useGLTF(url);
useEffect(() => {
const box = new THREE.Box3().setFromObject(scene);
const center = new THREE.Vector3();
box.getCenter(center);
scene.position.sub(center);
const size = new THREE.Vector3();
box.getSize(size);
const maxDim = Math.max(size.x, size.y, size.z);
const scale = maxDim > 0 ? 2 / maxDim : 1;
scene.scale.setScalar(scale);
}, [scene]);
useEffect(() => {
scene.traverse((child) => {
if ((child as THREE.Mesh).isMesh) {
const mesh = child as THREE.Mesh;
if (Array.isArray(mesh.material)) {
mesh.material.forEach((m) => { (m as THREE.Material & { wireframe: boolean }).wireframe = wireframe; });
} else {
(mesh.material as THREE.Material & { wireframe: boolean }).wireframe = wireframe;
}
}
});
}, [wireframe, scene]);
return ;
}
function SceneLighting({ preset }: { preset: LightPreset }) {
switch (preset) {
case 'studio':
return (
<>
>
);
case 'outdoor':
return (
<>
>
);
case 'dramatic':
return (
<>
>
);
default:
return null;
}
}
function Turntable({ autoRotate }: { autoRotate: boolean }) {
const { scene } = useThree();
useFrame((_, delta) => {
if (autoRotate) {
scene.rotation.y += delta * 0.5;
}
});
return null;
}
export default function ModelViewer3D({
url,
wireframe,
lightPreset,
autoRotate,
}: ModelViewer3DProps) {
return (