// Clickable navigation setup const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); const clickTargets = []; navigationGroup.children.forEach(group => { group.children.forEach(child => { if (child.type === 'Mesh' || child.type === 'Sprite') { clickTargets.push(child); } }); }); function updateMouseFromEvent(event) { const rect = renderer.domElement.getBoundingClientRect(); mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; } function handlePointerMove(event) { updateMouseFromEvent(event); raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(clickTargets, false); renderer.domElement.style.cursor = intersects.length > 0 ? 'pointer' : 'default'; } function handlePointerDown(event) { updateMouseFromEvent(event); raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(clickTargets, false); if (intersects.length > 0) { const hit = intersects[0].object; const label = (hit.userData && hit.userData.label) || (hit.parent && hit.parent.userData && hit.parent.userData.label) || 'Unknown'; console.log('Orb clicked:', label); // Placeholder: ready to assign links per label in future } } renderer.domElement.addEventListener('pointermove', handlePointerMove); renderer.domElement.addEventListener('pointerdown', handlePointerDown);