import React, { useRef, useMemo } from 'react'; import { Canvas, useFrame } from '@react-three/fiber'; import { OrbitControls, Grid, PerspectiveCamera, Text, Box, Environment, RoundedBox } from '@react-three/drei'; import * as THREE from 'three'; import { RobotTarget, IOPoint } from '../types'; interface Machine3DProps { target: RobotTarget; ioState: IOPoint[]; doorStates: { front: boolean; right: boolean; left: boolean; back: boolean; }; } // -- Parts Components -- const TowerLamp = ({ ioState }: { ioState: IOPoint[] }) => { // Outputs 0,1,2 mapped to Red, Yellow, Green const redOn = ioState.find(io => io.id === 0 && io.type === 'output')?.state; const yellowOn = ioState.find(io => io.id === 1 && io.type === 'output')?.state; const greenOn = ioState.find(io => io.id === 2 && io.type === 'output')?.state; const redMat = useRef(null); const yelMat = useRef(null); const grnMat = useRef(null); useFrame((state) => { const time = state.clock.elapsedTime; const pulse = (Math.sin(time * 6) * 0.5 + 0.5); const intensity = 0.5 + (pulse * 3.0); if (redMat.current) { redMat.current.emissiveIntensity = redOn ? intensity : 0; redMat.current.opacity = redOn ? 1.0 : 0.3; redMat.current.color.setHex(redOn ? 0xff0000 : 0x550000); } if (yelMat.current) { yelMat.current.emissiveIntensity = yellowOn ? intensity : 0; yelMat.current.opacity = yellowOn ? 1.0 : 0.3; yelMat.current.color.setHex(yellowOn ? 0xffff00 : 0x555500); } if (grnMat.current) { grnMat.current.emissiveIntensity = greenOn ? intensity : 0; grnMat.current.opacity = greenOn ? 1.0 : 0.3; grnMat.current.color.setHex(greenOn ? 0x00ff00 : 0x005500); } }); return ( {/* Pole */} {/* Green */} {/* Yellow */} {/* Red */} ); }; // -- DIPPING STATION COMPONENTS -- const LiquidBath = ({ position, label, liquidColor, }: { position: [number, number, number], label: string, liquidColor: string, }) => { const width = 1.0; const depth = 0.8; const height = 0.3; const wallThick = 0.03; const SteelMaterial = ( ); return ( {SteelMaterial} {SteelMaterial} {SteelMaterial} {SteelMaterial} {SteelMaterial} {label} ); }; const HakkoFX305 = ({ position }: { position: [number, number, number] }) => { return ( {/* Main Blue Chassis */} HAKKO FX-305 {[-0.12, 0, 0.12, 0.24].map((x, i) => ( ))} 2. HAKKO SOLDER ); }; const DippingStations = () => { return ( ); }; const Door = ({ position, rotation = [0,0,0], size, isOpen }: { position: [number, number, number], rotation?: [number, number, number], size: [number, number], isOpen: boolean }) => { const meshRef = useRef(null); useFrame((state, delta) => { if (!meshRef.current) return; const targetY = isOpen ? position[1] + 2 : position[1]; meshRef.current.position.y = THREE.MathUtils.lerp(meshRef.current.position.y, targetY, delta * 5); }); return ( ); }; const MachineFrame = ({ doorStates }: { doorStates: { front: boolean, right: boolean, left: boolean, back: boolean } }) => { return ( {[[-2, -2], [2, -2], [2, 2], [-2, 2]].map(([x, z], i) => ( ))} ); }; // --- MISUMI STYLE INDUSTRIAL ACTUATOR COMPONENT --- const IndustrialActuatorRail = ({ length, label, hasMotor = true }: { length: number, label?: string, hasMotor?: boolean }) => { const width = 0.14; // Actuator Width const height = 0.08; // Actuator Height (Profile) return ( {/* 1. Main Aluminum Body (White/Light Grey Matte) */} {/* 2. Top Stainless Steel Cover Strip */} {/* 3. Black Gap/Slit for Slider */} {/* 4. End Caps (Plastic White) */} {/* 5. Servo Motor Unit (Black & Silver) */} {hasMotor && ( {/* Flange */} {/* Motor Body */} {/* Encoder Cap */} {/* Cable Gland */} )} {/* 6. Label/Branding */} {label && ( {label} )} ); } // The Moving Block on top of the actuator const IndustrialSlider = ({ width = 0.16, length = 0.18, height = 0.03 }) => { return ( {/* Mounting Holes (Visual) */} {[-1, 1].map(x => [-1, 1].map(z => ( )))} ) } // -- MAIN ROBOT ASSEMBLY -- const Robot = ({ target }: { target: RobotTarget }) => { const bridgeGroup = useRef(null); const carriageGroup = useRef(null); const zAxisGroup = useRef(null); useFrame((state, delta) => { if (bridgeGroup.current) { // Y-Axis Movement bridgeGroup.current.position.z = THREE.MathUtils.lerp(bridgeGroup.current.position.z, target.y, delta * 3); } if (carriageGroup.current) { // X-Axis Movement carriageGroup.current.position.x = THREE.MathUtils.lerp(carriageGroup.current.position.x, target.x, delta * 3); } if (zAxisGroup.current) { // Z-Axis Movement zAxisGroup.current.position.y = THREE.MathUtils.lerp(zAxisGroup.current.position.y, target.z, delta * 3); } }); return ( {/* --- Y-AXIS (Left & Right Fixed Actuators) --- */} {/* --- MOVING BRIDGE (Y-AXIS CARRIAGE + X-AXIS ACTUATOR) --- */} {/* Y-Sliders (Connecting Bridge to Y-Rails) */} {/* Bridge Beam Structure */} {/* X-AXIS ACTUATOR (Mounted on top of Bridge) */} {/* --- MOVING CARRIAGE (X-AXIS SLIDER + Z-AXIS) --- */} {/* X-Slider */} {/* --- Z-AXIS ACTUATOR (Vertical) --- */} {/* Z-Actuator Body (Fixed to X-Slider) */} {/* Z-Motor on Top */} {/* MOVING Z-HEAD (The Slider of Z-Axis) */} {/* Connection Plate */} {/* PICKER MECHANISM */} {/* Fingers */} {/* PCB STRIP */} ); }; export const Machine3D: React.FC = ({ target, ioState, doorStates }) => { return ( ); };