From 60cdf4e6af6ba405083f65ccc1b02f7cfb041381 Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Mon, 25 Aug 2025 17:49:18 +0530 Subject: [PATCH] feat: add camera shortcut functionality for improved navigation in 3D space; refactor ShortcutHelper and Builder components for better structure --- app/src/components/footer/shortcutHelper.tsx | 2 + app/src/hooks/useCameraShortcuts.ts | 47 ++++++++++++++++++++ app/src/modules/builder/builder.tsx | 1 + app/src/modules/scene/controls/controls.tsx | 2 + 4 files changed, 52 insertions(+) create mode 100644 app/src/hooks/useCameraShortcuts.ts diff --git a/app/src/components/footer/shortcutHelper.tsx b/app/src/components/footer/shortcutHelper.tsx index 01ada84..230dff2 100644 --- a/app/src/components/footer/shortcutHelper.tsx +++ b/app/src/components/footer/shortcutHelper.tsx @@ -55,6 +55,7 @@ interface ShortcutHelperProps { const ShortcutHelper: React.FC = ({ setShowShortcuts, }) => { + const shortcuts: ShortcutGroup[] = [ // Essential { @@ -310,6 +311,7 @@ const ShortcutHelper: React.FC = ({ > +
{shortcuts.map((group) => ( diff --git a/app/src/hooks/useCameraShortcuts.ts b/app/src/hooks/useCameraShortcuts.ts new file mode 100644 index 0000000..e4b897a --- /dev/null +++ b/app/src/hooks/useCameraShortcuts.ts @@ -0,0 +1,47 @@ +import { useEffect } from "react"; +import { useThree } from "@react-three/fiber"; +import * as THREE from "three"; +import type { CameraControls } from "@react-three/drei"; + +export const useCameraShortcuts = (controlsRef: React.RefObject) => { + const { camera } = useThree(); + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (!controlsRef.current) return; + + // get current distance from camera to target + const target = new THREE.Vector3(); + controlsRef.current.getTarget(target); + + const distance = camera.position.distanceTo(target); + let pos: THREE.Vector3 | null = null; + + switch (e.key) { + case "1": // Front + pos = new THREE.Vector3(0, 0, distance).add(target); + break; + case "3": // Right + pos = new THREE.Vector3(distance, 0, 0).add(target); + break; + case "7": // Top + pos = new THREE.Vector3(0, distance, 0).add(target); + break; + case "9": // Back + pos = new THREE.Vector3(0, 0, -distance).add(target); + break; + } + + if (pos) { + controlsRef.current.setLookAt( + pos.x, pos.y, pos.z, // camera position + target.x, target.y, target.z, // keep same target + true // smooth transition + ); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [controlsRef, camera]); +}; diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index ab9434b..ef310fc 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -57,6 +57,7 @@ export default function Builder() { const { setHoveredPoint, setHoveredLine } = useBuilderStore(); const { userId, organization } = getUserData(); + useEffect(() => { if (!toggleView) { setHoveredLine(null); diff --git a/app/src/modules/scene/controls/controls.tsx b/app/src/modules/scene/controls/controls.tsx index c41a4bd..d63f0ac 100644 --- a/app/src/modules/scene/controls/controls.tsx +++ b/app/src/modules/scene/controls/controls.tsx @@ -18,6 +18,7 @@ import ContextControls from "./contextControls/contextControls"; import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D"; import UndoRedo2DControls from "./undoRedoControls/undoRedo2D/undoRedo2DControls"; import UndoRedo3DControls from "./undoRedoControls/undoRedo3D/undoRedo3DControls"; +import { useCameraShortcuts } from "../../../hooks/useCameraShortcuts"; export default function Controls() { const controlsRef = useRef(null); @@ -116,6 +117,7 @@ export default function Controls() { stopInterval(); }; }, [toggleView, state, socket]); + useCameraShortcuts(controlsRef); return ( <>