From 6a70c3f0b005f79fef332987607dc57ed1bb9210 Mon Sep 17 00:00:00 2001 From: Andrew Neal <141008525+AndrewN4675@users.noreply.github.com> Date: Tue, 4 Nov 2025 18:30:40 -0800 Subject: [PATCH] Implement camera control for genre selection --- src/app/music-map/genre-graph.tsx | 62 ++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/src/app/music-map/genre-graph.tsx b/src/app/music-map/genre-graph.tsx index a512e6f..62c605c 100644 --- a/src/app/music-map/genre-graph.tsx +++ b/src/app/music-map/genre-graph.tsx @@ -13,6 +13,45 @@ import GenreSearch from "./genre-search"; const radius = 0.8; const circleGeo = new THREE.CircleGeometry(radius, 32); +function CameraController({ targetGenre }: { targetGenre: Genre | null }) { + const { camera } = useThree(); + const controlsRef = useRef(null); + + useFrame(() => { + if (targetGenre && controlsRef.current) { + // Calculate target position (move camera back from the node) + const targetPos = new THREE.Vector3( + targetGenre.x, + targetGenre.y, + targetGenre.z + 10 // offset camera behind the node + ); + + // Smoothly interpolate camera position + camera.position.lerp(targetPos, 0.05); + + // Update controls target to focus on the node + const focusPoint = new THREE.Vector3( + targetGenre.x, + targetGenre.y, + targetGenre.z + ); + controlsRef.current.target.lerp(focusPoint, 0.05); + controlsRef.current.update(); + } + }); + + return ( + + ); +} + function GenreNode({ genre }: { genre: Genre }) { const [hovered, setHovered] = useState(false); const meshReference = useRef(null); @@ -122,7 +161,8 @@ function Connections({ export default function GenreGraph() { const [nodeMap, setNodeMap] = useState>({}); // record (hash table) for faster indexing for search - + const [targetGenre, setTargetGenre] = useState(null); + useEffect(() => { Papa.parse("genre_coords.csv", { download: true, @@ -171,7 +211,16 @@ export default function GenreGraph() { {/* overlay for the search bar and random seek button */}
{/* TODO: placeholder onSelect for now, will move camera to node */} - {}} /> + { + const genre = nodeMap[name]; + if (genre) { + setTargetGenre(genre); + setTimeout(() => setTargetGenre(null), 5000); + } + }} + />
@@ -192,13 +241,8 @@ export default function GenreGraph() { {renderedNodes} - + + dummy text to load font shader to fix flashing