diff --git a/frontend/src/components/login/NetworkGlobe.tsx b/frontend/src/components/login/NetworkGlobe.tsx index 2a3c69695..89f88cc67 100644 --- a/frontend/src/components/login/NetworkGlobe.tsx +++ b/frontend/src/components/login/NetworkGlobe.tsx @@ -34,8 +34,10 @@ interface CentralNodeChild extends THREE.Object3D { const NetworkGlobe = ({ isLoaded = true }: NetworkGlobeProps) => { const { t } = useTranslation(); const globeRef = useRef(null); + const gridLinesRef = useRef(null); const centralNodeRef = useRef(null); const dataFlowsRef = useRef(null); + const rotatingContentRef = useRef(null); const frameCount = useRef(0); // Track document visibility to pause rendering when tab/page is not active @@ -231,16 +233,17 @@ const NetworkGlobe = ({ isLoaded = true }: NetworkGlobeProps) => { // Increment frame counter frameCount.current += 1; + const time = state.clock.getElapsedTime(); // Update animation progress for reveal effect - only when loading if (isLoaded && animationProgress < 1) { setAnimationProgress(Math.min(animationProgress + 0.01, 1)); } - // Rotate the globe slowly - limit updates for better performance if (globeRef.current && frameCount.current % 2 === 0) { - globeRef.current.rotation.y = state.clock.getElapsedTime() * 0.05; - globeRef.current.rotation.x = Math.sin(state.clock.getElapsedTime() * 0.2) * 0.02; + globeRef.current.rotation.y = time * 0.05; + globeRef.current.rotation.x = Math.sin(time * 0.15) * 0.04; + globeRef.current.rotation.z = Math.cos(time * 0.08) * 0.015; // Update material opacity if (globeMaterial.opacity !== 0.08 * animationProgress) { @@ -252,12 +255,18 @@ const NetworkGlobe = ({ isLoaded = true }: NetworkGlobeProps) => { globeRef.current.scale.setScalar(scale); } + // Rotate grid lines to match globe rotation with same slow speed + if (gridLinesRef.current && frameCount.current % 2 === 0) { + gridLinesRef.current.rotation.y = time * 0.05; + gridLinesRef.current.rotation.x = Math.sin(time * 0.15) * 0.04; + gridLinesRef.current.rotation.z = Math.cos(time * 0.08) * 0.015; + } + // Animate central node - less frequently if (centralNodeRef.current && frameCount.current % 3 === 0) { - centralNodeRef.current.rotation.y = state.clock.getElapsedTime() * 0.2; - centralNodeRef.current.scale.setScalar( - (1 + Math.sin(state.clock.getElapsedTime() * 1.5) * 0.05) * animationProgress - ); + centralNodeRef.current.rotation.y = time * 0.15; + centralNodeRef.current.rotation.x = Math.sin(time * 0.2) * 0.05; + centralNodeRef.current.scale.setScalar((1 + Math.sin(time * 1.5) * 0.05) * animationProgress); // Fade in the central node with throttled updates centralNodeRef.current.children.forEach((child: CentralNodeChild) => { @@ -271,6 +280,13 @@ const NetworkGlobe = ({ isLoaded = true }: NetworkGlobeProps) => { }); } + // Rotate the cluster group around the central node - same frequency as central node + if (rotatingContentRef.current && frameCount.current % 3 === 0) { + rotatingContentRef.current.rotation.y = time * 0.05; // Match globe speed + rotatingContentRef.current.rotation.x = Math.sin(time * 0.15) * 0.04; + rotatingContentRef.current.rotation.z = Math.cos(time * 0.08) * 0.015; + } + // Animate data flows - only every 3 frames if (dataFlowsRef.current && frameCount.current % 3 === 0) { dataFlowsRef.current.children.forEach((flow: FlowChild, i) => { @@ -299,7 +315,7 @@ const NetworkGlobe = ({ isLoaded = true }: NetworkGlobeProps) => { {/* Grid lines for the globe - optimized with shared geometry */} - + {Array.from({ length: 4 }).map((_, idx) => ( { - {/* Clusters of nodes */} - {clusters.map((cluster, idx) => ( - - ))} + {/* Rotating cluster group */} + + {/* Clusters of nodes */} + {clusters.map((cluster, idx) => ( + + ))} + {/* Data flow connections - use reduced detail and memoized materials */}