diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 03bfad0..8ca4f46 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -168,7 +168,7 @@ const SideBarRight: React.FC = () => { } setDisplayComponent("none"); - }, [viewVersionHistory, activeModule, subModule, isVersionSaved, selectedFloorItem, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal]); + }, [viewVersionHistory, activeModule, subModule, isVersionSaved, selectedFloorItem, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal, selectedCollider]); const renderComponent = () => { switch (displayComponent) { diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx index a7502db..02f3d75 100644 --- a/app/src/modules/builder/asset/models/model/model.tsx +++ b/app/src/modules/builder/asset/models/model/model.tsx @@ -232,7 +232,7 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere asset={asset} /> */} - {asset.eventData && asset.eventData.type === 'Conveyor' && fieldData && + {asset.eventData && asset.eventData.type === 'Conveyor' && fieldData && activeModule === 'simulation' && window.removeEventListener("keydown", handleKeyDown); }, []); - return visible ? : null; + return visible ? : null; } diff --git a/app/src/modules/scene/physics/conveyor/types/curvedConveyorCollider.tsx b/app/src/modules/scene/physics/conveyor/types/curvedConveyorCollider.tsx index fa67e0f..5f45e46 100644 --- a/app/src/modules/scene/physics/conveyor/types/curvedConveyorCollider.tsx +++ b/app/src/modules/scene/physics/conveyor/types/curvedConveyorCollider.tsx @@ -4,368 +4,370 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import { useFrame } from '@react-three/fiber'; function CurvedConveyorCollider({ - points, - boundingBox, - asset, - forward, - isPaused, - onDirectionChange + points, + boundingBox, + asset, + forward, + isPaused, + onDirectionChange }: { - points: [number, number, number][][]; - boundingBox: THREE.Box3 | null; - asset: Asset; - forward: boolean; - isPaused: boolean; - onDirectionChange?: (newDirection: boolean) => void; + points: [number, number, number][][]; + boundingBox: THREE.Box3 | null; + asset: Asset; + forward: boolean; + isPaused: boolean; + onDirectionChange?: (newDirection: boolean) => void; }) { - const conveyorRef = useRef(null); - const [objectsOnConveyor, setObjectsOnConveyor] = useState>(new Set()); - const conveyorDirection = useRef(new THREE.Vector3()); - // const [forward, setForward] = useState(initialForward); - const [showDirection, setShowDirection] = useState(false); - const [hoverState, setHoverState] = useState(false); - const conveyorSpeed = 2; - const lastClickTime = useRef(0); - const arrowRefs = useRef([]); - const [geometryKey, setGeometryKey] = useState(0); + const conveyorRef = useRef(null); + const [objectsOnConveyor, setObjectsOnConveyor] = useState>(new Set()); + const conveyorDirection = useRef(new THREE.Vector3()); + // const [forward, setForward] = useState(initialForward); + const [showDirection, setShowDirection] = useState(false); + const [hoverState, setHoverState] = useState(false); + const conveyorSpeed = 2; + const lastClickTime = useRef(0); + const arrowRefs = useRef([]); + const [geometryKey, setGeometryKey] = useState(0); - // Toggle direction on double right click - useEffect(() => { - const handleClick = (e: MouseEvent) => { - if (e.button === 2 && hoverState) { // Right click and hovering over conveyor - const now = Date.now(); - if (now - lastClickTime.current < 300) { - if (onDirectionChange) { - console.log('forwardcurve: ', forward); - onDirectionChange(!forward); - } + // Toggle direction on double right click + useEffect(() => { + const handleClick = (e: MouseEvent) => { + if (e.button === 2 && hoverState) { // Right click and hovering over conveyor + const now = Date.now(); + if (now - lastClickTime.current < 300) { + if (onDirectionChange) { + console.log('forwardcurve: ', forward); + onDirectionChange(!forward); + } + } + lastClickTime.current = now; + } + }; + + window.addEventListener('mousedown', handleClick); + return () => window.removeEventListener('mousedown', handleClick); + }, [forward, hoverState]); + + + const bezierPoints = useMemo(() => { + const segments = 20; + const allPoints: THREE.Vector3[] = []; + + points.forEach(segment => { + let vectorPoints = segment.map(p => new THREE.Vector3(...p)); + if (!forward) vectorPoints.reverse(); + + for (let group = 0; group + 2 < vectorPoints.length; group += 2) { + const p0 = vectorPoints[group]; + const p1 = vectorPoints[group + 1]; + const p2 = vectorPoints[group + 2]; + + for (let i = 0; i <= segments; i++) { + const t = i / segments; + const point = new THREE.Vector3() + .copy(p0) + .multiplyScalar((1 - t) ** 2) + .addScaledVector(p1, 2 * (1 - t) * t) + .addScaledVector(p2, t ** 2); + allPoints.push(point); + } + } + }); + + return allPoints; + }, [points, forward]); + + const geometries = useMemo(() => { + const width = 1; + const segments = 20; + const geos: THREE.BufferGeometry[] = []; + + points.forEach(segment => { + const vertices: number[] = []; + const indices: number[] = []; + + const vectorPoint = segment.map(p => new THREE.Vector3(...p)); + if (vectorPoint.length < 3) return; + + for (let group = 0; group + 2 < vectorPoint.length; group += 2) { + const p0 = vectorPoint[group]; + const p1 = vectorPoint[group + 1]; + const p2 = vectorPoint[group + 2]; + + for (let i = 0; i <= segments; i++) { + const t = i / segments; + const point = new THREE.Vector3() + .copy(p0) + .multiplyScalar((1 - t) ** 2) + .addScaledVector(p1, 2 * (1 - t) * t) + .addScaledVector(p2, t ** 2); + + const tangent = new THREE.Vector3() + .copy(p0) + .multiplyScalar(-2 * (1 - t)) + .addScaledVector(p1, 2 - 4 * t) + .addScaledVector(p2, 2 * t) + .normalize(); + + const normal = new THREE.Vector3().crossVectors(tangent, new THREE.Vector3(0, 1, 0)).normalize(); + const left = new THREE.Vector3().copy(point).addScaledVector(normal, -width / 2); + const right = new THREE.Vector3().copy(point).addScaledVector(normal, width / 2); + + vertices.push(...left.toArray(), ...right.toArray()); + } + } + + const totalSegments = ((vectorPoint.length - 1) / 2) * segments; + for (let i = 0; i < totalSegments; i++) { + const base = i * 2; + indices.push(base, base + 1, base + 2); + indices.push(base + 1, base + 3, base + 2); + } + + const ribbonGeometry = new THREE.BufferGeometry(); + ribbonGeometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); + ribbonGeometry.setIndex(indices); + ribbonGeometry.computeVertexNormals(); + geos.push(ribbonGeometry); + }); + + setGeometryKey(k => k + 1); + return geos; + }, [points, asset.position, asset.rotation]); + + useEffect(() => { + if (bezierPoints.length >= 2) { + const start = bezierPoints[0]; + const end = bezierPoints[bezierPoints.length - 1]; + conveyorDirection.current.copy(end).sub(start).normalize(); + const rotation = new THREE.Euler().fromArray(asset.rotation || [0, 0, 0]); + conveyorDirection.current.applyEuler(rotation); + } + }, [bezierPoints, forward, asset.rotation]); + + + const handleMaterialEnter = (e: CollisionPayload) => { + if (e.other.rigidBody) { + setObjectsOnConveyor(prev => { + const newSet = new Set(prev); + newSet.add(e.other.rigidBody); + return newSet; + }); } - lastClickTime.current = now; - } }; - window.addEventListener('mousedown', handleClick); - return () => window.removeEventListener('mousedown', handleClick); - }, [forward, hoverState]); - - - const bezierPoints = useMemo(() => { - const segments = 20; - const allPoints: THREE.Vector3[] = []; - - points.forEach(segment => { - let vectorPoints = segment.map(p => new THREE.Vector3(...p)); - if (!forward) vectorPoints.reverse(); - - for (let group = 0; group + 2 < vectorPoints.length; group += 2) { - const p0 = vectorPoints[group]; - const p1 = vectorPoints[group + 1]; - const p2 = vectorPoints[group + 2]; - - for (let i = 0; i <= segments; i++) { - const t = i / segments; - const point = new THREE.Vector3() - .copy(p0) - .multiplyScalar((1 - t) ** 2) - .addScaledVector(p1, 2 * (1 - t) * t) - .addScaledVector(p2, t ** 2); - allPoints.push(point); + const handleMaterialExit = (e: CollisionPayload) => { + if (e.other.rigidBody) { + setObjectsOnConveyor(prev => { + const newSet = new Set(prev); + newSet.delete(e.other.rigidBody); + return newSet; + }); } - } - }); - - return allPoints; - }, [points, forward]); - - const geometries = useMemo(() => { - const width = 1; - const segments = 20; - const geos: THREE.BufferGeometry[] = []; - - points.forEach(segment => { - const vertices: number[] = []; - const indices: number[] = []; - - const vectorPoint = segment.map(p => new THREE.Vector3(...p)); - if (vectorPoint.length < 3) return; - - for (let group = 0; group + 2 < vectorPoint.length; group += 2) { - const p0 = vectorPoint[group]; - const p1 = vectorPoint[group + 1]; - const p2 = vectorPoint[group + 2]; - - for (let i = 0; i <= segments; i++) { - const t = i / segments; - const point = new THREE.Vector3() - .copy(p0) - .multiplyScalar((1 - t) ** 2) - .addScaledVector(p1, 2 * (1 - t) * t) - .addScaledVector(p2, t ** 2); - - const tangent = new THREE.Vector3() - .copy(p0) - .multiplyScalar(-2 * (1 - t)) - .addScaledVector(p1, 2 - 4 * t) - .addScaledVector(p2, 2 * t) - .normalize(); - - const normal = new THREE.Vector3().crossVectors(tangent, new THREE.Vector3(0, 1, 0)).normalize(); - const left = new THREE.Vector3().copy(point).addScaledVector(normal, -width / 2); - const right = new THREE.Vector3().copy(point).addScaledVector(normal, width / 2); - - vertices.push(...left.toArray(), ...right.toArray()); - } - } - - const totalSegments = ((vectorPoint.length - 1) / 2) * segments; - for (let i = 0; i < totalSegments; i++) { - const base = i * 2; - indices.push(base, base + 1, base + 2); - indices.push(base + 1, base + 3, base + 2); - } - - const ribbonGeometry = new THREE.BufferGeometry(); - ribbonGeometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); - ribbonGeometry.setIndex(indices); - ribbonGeometry.computeVertexNormals(); - geos.push(ribbonGeometry); - }); - - setGeometryKey(k => k + 1); - return geos; - }, [points, asset.position, asset.rotation]); - - useEffect(() => { - if (bezierPoints.length >= 2) { - const start = bezierPoints[0]; - const end = bezierPoints[bezierPoints.length - 1]; - conveyorDirection.current.copy(end).sub(start).normalize(); - const rotation = new THREE.Euler().fromArray(asset.rotation || [0, 0, 0]); - conveyorDirection.current.applyEuler(rotation); - } - }, [bezierPoints, forward, asset.rotation]); + }; - const handleMaterialEnter = (e: CollisionPayload) => { - if (e.other.rigidBody) { - setObjectsOnConveyor(prev => { - const newSet = new Set(prev); - newSet.add(e.other.rigidBody); - return newSet; - }); - } - }; + useFrame(({ clock }) => { + if (isPaused) return; - const handleMaterialExit = (e: CollisionPayload) => { - if (e.other.rigidBody) { - setObjectsOnConveyor(prev => { - const newSet = new Set(prev); - newSet.delete(e.other.rigidBody); - return newSet; - }); - } - }; + // Physics simulation + const assetPos = new THREE.Vector3(...(asset.position || [0, 0, 0])); + const assetRot = new THREE.Euler(...(asset.rotation || [0, 0, 0])); + const assetQuat = new THREE.Quaternion().setFromEuler(assetRot); + const inverseQuat = assetQuat.clone().invert(); + objectsOnConveyor.forEach(rigidBody => { + const worldPos = new THREE.Vector3().copy(rigidBody.translation()); + const localPos = worldPos.clone().sub(assetPos).applyQuaternion(inverseQuat); - useFrame(({ clock }) => { - if (isPaused) return; - - // Physics simulation - const assetPos = new THREE.Vector3(...(asset.position || [0, 0, 0])); - const assetRot = new THREE.Euler(...(asset.rotation || [0, 0, 0])); - const assetQuat = new THREE.Quaternion().setFromEuler(assetRot); - const inverseQuat = assetQuat.clone().invert(); - - objectsOnConveyor.forEach(rigidBody => { - const worldPos = new THREE.Vector3().copy(rigidBody.translation()); - const localPos = worldPos.clone().sub(assetPos).applyQuaternion(inverseQuat); - - let closestIndex = 0; - let minDist = Infinity; - for (let i = 0; i < bezierPoints.length; i++) { - const dist = bezierPoints[i].distanceToSquared(localPos); - if (dist < minDist) { - minDist = dist; - closestIndex = i; - } - } - - const point = bezierPoints[closestIndex]; - const prev = bezierPoints[closestIndex - 1] || point; - const next = bezierPoints[closestIndex + 1] || point; - const tangent = new THREE.Vector3().subVectors(next, prev).normalize(); - - const side = new THREE.Vector3().crossVectors(tangent, new THREE.Vector3(0, 1, 0)).normalize(); - const relative = new THREE.Vector3().subVectors(localPos, point); - const sideOffset = relative.dot(side); - - const centeringForce = side.clone().multiplyScalar(-sideOffset * 10); - const forwardForce = tangent.clone().multiplyScalar(conveyorSpeed); - const totalForce = forwardForce.add(centeringForce).applyQuaternion(assetQuat); - - rigidBody.setAngvel({ x: 0, y: 0, z: 0 }, true); - rigidBody.setLinvel(totalForce, true); - }); - - // Arrow animations - if (showDirection && arrowRefs.current.length > 0) { - const elapsedTime = clock.getElapsedTime(); - arrowRefs.current.forEach((arrowGroup, index) => { - // Pulse animation - const pulseScale = 0.9 + 0.1 * Math.sin(elapsedTime * 5 + index * 0.5); - arrowGroup.scale.setScalar(pulseScale); - - // Flow animation (color intensity) - const intensity = 0.7 + 0.3 * Math.sin(elapsedTime * 3 + index * 0.3); - arrowGroup.children.forEach(child => { - if (child instanceof THREE.Mesh) { - const material = child.material as THREE.MeshBasicMaterial; - if (forward) { - material.color.setRGB(0, intensity, 0); - } else { - material.color.setRGB(intensity, 0, 0); + let closestIndex = 0; + let minDist = Infinity; + for (let i = 0; i < bezierPoints.length; i++) { + const dist = bezierPoints[i].distanceToSquared(localPos); + if (dist < minDist) { + minDist = dist; + closestIndex = i; + } } - } + + const point = bezierPoints[closestIndex]; + const prev = bezierPoints[closestIndex - 1] || point; + const next = bezierPoints[closestIndex + 1] || point; + const tangent = new THREE.Vector3().subVectors(next, prev).normalize(); + + const side = new THREE.Vector3().crossVectors(tangent, new THREE.Vector3(0, 1, 0)).normalize(); + const relative = new THREE.Vector3().subVectors(localPos, point); + const sideOffset = relative.dot(side); + + const centeringForce = side.clone().multiplyScalar(-sideOffset * 10); + const forwardForce = tangent.clone().multiplyScalar(conveyorSpeed); + const totalForce = forwardForce.add(centeringForce).applyQuaternion(assetQuat); + + rigidBody.setAngvel({ x: 0, y: 0, z: 0 }, true); + rigidBody.setLinvel(totalForce, true); }); - }); - } - }); + // Arrow animations + if (showDirection && arrowRefs.current.length > 0) { + const elapsedTime = clock.getElapsedTime(); + arrowRefs.current.forEach((arrowGroup, index) => { + // Pulse animation + const pulseScale = 0.9 + 0.1 * Math.sin(elapsedTime * 5 + index * 0.5); + arrowGroup.scale.setScalar(pulseScale); - // Create curved direction indicators - const directionArrows = useMemo(() => { - if (!showDirection) return null; - - const arrows: THREE.Group[] = []; - const arrowHeight = 0.2; - const arrowRadius = 0.05; - const segments = 8; // Fewer arrows for curved conveyors - - points.forEach(segment => { - let vectorPoints = segment.map(p => new THREE.Vector3(...p)); - if (!forward) vectorPoints.reverse(); - - for (let group = 0; group + 2 < vectorPoints.length; group += 2) { - const p0 = vectorPoints[group]; - const p1 = vectorPoints[group + 1]; - const p2 = vectorPoints[group + 2]; - - for (let i = 0; i <= segments; i++) { - const t = i / segments; - const point = new THREE.Vector3() - .copy(p0) - .multiplyScalar((1 - t) ** 2) - .addScaledVector(p1, 2 * (1 - t) * t) - .addScaledVector(p2, t ** 2); - - const tangent = new THREE.Vector3() - .copy(p0) - .multiplyScalar(-2 * (1 - t)) - .addScaledVector(p1, 2 - 4 * t) - .addScaledVector(p2, 2 * t) - .normalize(); - - // Create arrow group - const arrowGroup = new THREE.Group(); - - // Arrow shaft (cylinder) - const shaftLength = arrowHeight * 0.7; - const shaftGeometry = new THREE.CylinderGeometry(arrowRadius * 0.3, arrowRadius * 0.3, shaftLength, 8); - const shaftMaterial = new THREE.MeshBasicMaterial({ - color: forward ? 0x00ff00 : 0xff0000 - }); - const shaft = new THREE.Mesh(shaftGeometry, shaftMaterial); - shaft.position.y = shaftLength / 2; - shaft.rotation.x = Math.PI / 2; - - // Arrow head (cone) - const headGeometry = new THREE.ConeGeometry(arrowRadius, arrowHeight * 0.3, 8); - const headMaterial = new THREE.MeshBasicMaterial({ - color: forward ? 0x00ff00 : 0xff0000 - }); - const head = new THREE.Mesh(headGeometry, headMaterial); - head.position.y = shaftLength; - - // Position and orient the entire arrow - arrowGroup.add(shaft); - arrowGroup.add(head); - arrowGroup.position.copy(point); - arrowGroup.position.y += 0.1; // Slightly above conveyor - arrowGroup.quaternion.setFromUnitVectors( - new THREE.Vector3(0, 1, 0), - new THREE.Vector3(tangent.x, 0.1, tangent.z) - ); - - arrows.push(arrowGroup); + // Flow animation (color intensity) + const intensity = 0.7 + 0.3 * Math.sin(elapsedTime * 3 + index * 0.3); + arrowGroup.children.forEach(child => { + if (child instanceof THREE.Mesh) { + const material = child.material as THREE.MeshBasicMaterial; + if (forward) { + material.color.setRGB(0, intensity, 0); + } else { + material.color.setRGB(intensity, 0, 0); + } + } + }); + }); } - } }); - arrowRefs.current = arrows; - return arrows; - }, [points, showDirection, forward]); - return ( - { - setShowDirection(true); - setHoverState(true); - }} - onPointerOut={() => { - setShowDirection(false); - setHoverState(false); - }} - > - {/* Conveyor surface */} - {geometries.length > 0 && ( - { + if (!showDirection) return null; + + const arrows: THREE.Group[] = []; + const arrowHeight = 0.2; + const arrowRadius = 0.05; + const segments = 8; // Fewer arrows for curved conveyors + + points.forEach(segment => { + let vectorPoints = segment.map(p => new THREE.Vector3(...p)); + if (!forward) vectorPoints.reverse(); + + for (let group = 0; group + 2 < vectorPoints.length; group += 2) { + const p0 = vectorPoints[group]; + const p1 = vectorPoints[group + 1]; + const p2 = vectorPoints[group + 2]; + + for (let i = 0; i <= segments; i++) { + const t = i / segments; + const point = new THREE.Vector3() + .copy(p0) + .multiplyScalar((1 - t) ** 2) + .addScaledVector(p1, 2 * (1 - t) * t) + .addScaledVector(p2, t ** 2); + + const tangent = new THREE.Vector3() + .copy(p0) + .multiplyScalar(-2 * (1 - t)) + .addScaledVector(p1, 2 - 4 * t) + .addScaledVector(p2, 2 * t) + .normalize(); + + // Create arrow group + const arrowGroup = new THREE.Group(); + + // Arrow shaft (cylinder) + const shaftLength = arrowHeight * 0.7; + const shaftGeometry = new THREE.CylinderGeometry(arrowRadius * 0.3, arrowRadius * 0.3, shaftLength, 8); + const shaftMaterial = new THREE.MeshBasicMaterial({ + color: forward ? 0x00ff00 : 0xff0000 + }); + const shaft = new THREE.Mesh(shaftGeometry, shaftMaterial); + shaft.position.y = shaftLength / 2; + shaft.rotation.x = Math.PI / 2; + + // Arrow head (cone) + const headGeometry = new THREE.ConeGeometry(arrowRadius, arrowHeight * 0.3, 8); + const headMaterial = new THREE.MeshBasicMaterial({ + color: forward ? 0x00ff00 : 0xff0000 + }); + const head = new THREE.Mesh(headGeometry, headMaterial); + head.position.y = shaftLength; + + // Position and orient the entire arrow + arrowGroup.add(shaft); + arrowGroup.add(head); + arrowGroup.position.copy(point); + arrowGroup.position.y += 0.1; // Slightly above conveyor + arrowGroup.quaternion.setFromUnitVectors( + new THREE.Vector3(0, 1, 0), + new THREE.Vector3(tangent.x, 0.1, tangent.z) + ); + + arrows.push(arrowGroup); + } + } + }); + + arrowRefs.current = arrows; + return arrows; + }, [points, showDirection, forward]); + + return ( + { + setShowDirection(true); + setHoverState(true); + }} + onPointerOut={() => { + setShowDirection(false); + setHoverState(false); + }} > - {geometries.map((geometry, index) => ( - - - - ))} - - )} + {/* Conveyor surface */} + {geometries.length > 0 && ( + + {geometries.map((geometry, index) => ( + + + + ))} + + )} - {/* Direction indicators */} - {showDirection && directionArrows?.map((arrow, i) => ( - - ))} + {/* Direction indicators */} + {showDirection && directionArrows?.map((arrow, i) => ( + + ))} - {/* Hover highlight */} - {hoverState && ( - - {geometries.map((geometry, index) => ( - - - - ))} + {/* Hover highlight */} + {hoverState && ( + + {geometries.map((geometry, index) => ( + + + + ))} + + )} - )} - - ); + ); } export default CurvedConveyorCollider; \ No newline at end of file diff --git a/app/src/modules/scene/physics/conveyor/types/normalConveyorCollider.tsx b/app/src/modules/scene/physics/conveyor/types/normalConveyorCollider.tsx index 7766b83..735306b 100644 --- a/app/src/modules/scene/physics/conveyor/types/normalConveyorCollider.tsx +++ b/app/src/modules/scene/physics/conveyor/types/normalConveyorCollider.tsx @@ -20,7 +20,7 @@ function NormalConveyorCollider({ points, boundingBox, asset, forward, isPaused, const conveyorSpeed = 2; const lastClickTime = useRef(0); const [hoverState, setHoverState] = useState(false); - const[localForward,setLocalForward]=useState() + const [localForward, setLocalForward] = useState() useEffect(() => { const handleClick = (e: MouseEvent) => { @@ -215,6 +215,7 @@ function NormalConveyorCollider({ points, boundingBox, asset, forward, isPaused, side={THREE.DoubleSide} transparent opacity={0.5} + visible={false} /> @@ -231,6 +232,7 @@ function NormalConveyorCollider({ points, boundingBox, asset, forward, isPaused, key={`highlight-${index}`} geometry={geometry} position={[0, 0.002, 0]} + // visible={false} > @@ -230,6 +231,7 @@ function YSplitConveyorCollider({ points, boundingBox, asset, forward, isPaused, key={`highlight-${index}`} geometry={geometry} position={[0, 0.002, 0]} + // visible={false} > [ { name: "forward", keys: ["ArrowUp", "w", "W"] }, { name: "backward", keys: ["ArrowDown", "s", "S"] }, @@ -58,6 +58,18 @@ export default function Scene({ layout }: { readonly layout: "Main Layout" | "Co // eslint-disable-next-line }, [activeModule, assets, loadingProgress]); + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "F1") { + event.preventDefault(); + setVisible(prev => !prev); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, []); + return ( - + - {/* */} - diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 4490aeb..e1951c4 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -13,6 +13,7 @@ import Products from './products/products'; import Trigger from './triggers/trigger'; import useModuleStore from '../../store/useModuleStore'; import SimulationAnalysis from './analysis/simulationAnalysis'; +import PhysicsSimulator from '../scene/physics/physicsSimulator'; import { useSceneContext } from '../scene/sceneContext'; function Simulation() { @@ -62,6 +63,8 @@ function Simulation() { + + }