diff --git a/src/components/App/index.tsx b/src/components/App/index.tsx
index 4e0464179..4e99431c5 100644
--- a/src/components/App/index.tsx
+++ b/src/components/App/index.tsx
@@ -1,4 +1,3 @@
-import { Leva } from 'leva'
import { lazy, Suspense, useCallback, useEffect, useRef } from 'react'
import { FormProvider, useForm } from 'react-hook-form'
import { useSearchParams } from 'react-router-dom'
@@ -8,7 +7,6 @@ import styled from 'styled-components'
import { Flex } from '~/components/common/Flex'
import { GlobalStyle } from '~/components/GlobalStyle'
import { Overlay } from '~/components/Universe/Overlay' // Import Overlay directly
-import { isDevelopment } from '~/constants'
import { useSocket } from '~/hooks/useSockets'
import { useAiSummaryStore } from '~/stores/useAiSummaryStore'
import { useAppStore } from '~/stores/useAppStore'
@@ -341,8 +339,6 @@ export const App = () => {
-
-
Loading...}>
{!splashDataLoading ? (
diff --git a/src/components/Universe/Graph/Connections/LineComponent.tsx b/src/components/Universe/Graph/Connections/LineComponent.tsx
index 25b0890ac..e36a6fe86 100644
--- a/src/components/Universe/Graph/Connections/LineComponent.tsx
+++ b/src/components/Universe/Graph/Connections/LineComponent.tsx
@@ -1,8 +1,10 @@
import { Billboard, Line, Text } from '@react-three/drei'
+import { useFrame } from '@react-three/fiber'
import gsap from 'gsap'
import { memo, useEffect, useRef } from 'react'
import { Vector3 } from 'three'
import { Line2 } from 'three-stdlib'
+import { useGraphStore } from '~/stores/useGraphStore'
import { LinkPosition } from '..'
import { LINE_WIDTH } from '../../constants'
@@ -10,10 +12,12 @@ type LineComponentProps = {
isSelected: boolean
position: LinkPosition
label: string
+ target: string
+ source: string
}
// eslint-disable-next-line no-underscore-dangle
-const _LineComponent = ({ isSelected, position, label }: LineComponentProps) => {
+const _LineComponent = ({ isSelected, position, label, target, source }: LineComponentProps) => {
const lineRef = useRef(null)
useEffect(() => {
@@ -31,6 +35,33 @@ const _LineComponent = ({ isSelected, position, label }: LineComponentProps) =>
}
}, [isSelected, lineRef])
+ useFrame(() => {
+ const { selectedNode, hoveredNode } = useGraphStore.getState()
+
+ if (lineRef.current) {
+ const line = lineRef.current
+ const activeNode = selectedNode || hoveredNode
+
+ if (activeNode?.ref_id === source || activeNode?.ref_id === target) {
+ line.visible = true
+
+ // Increase line width
+ gsap.to(line.material, {
+ linewidth: 6, // Target line width
+ duration: 0.5, // Smooth increase
+ ease: 'power1.out',
+ })
+ } else {
+ // Decrease line width back to default
+ gsap.to(line.material, {
+ linewidth: 1, // Default line width
+ duration: 0.5, // Smooth decrease
+ ease: 'power1.out',
+ })
+ }
+ }
+ })
+
return (
{
tz: 0,
}
- return
+ return (
+
+ )
})}
)
diff --git a/src/components/Universe/Graph/Cubes/SelectionDataNodes/index.tsx b/src/components/Universe/Graph/Cubes/SelectionDataNodes/index.tsx
index e392edd48..bac65beb7 100644
--- a/src/components/Universe/Graph/Cubes/SelectionDataNodes/index.tsx
+++ b/src/components/Universe/Graph/Cubes/SelectionDataNodes/index.tsx
@@ -118,7 +118,7 @@ export const SelectionDataNodes = memo(() => {
{selectionGraphData?.nodes.map((node) => (
-
+
))}
diff --git a/src/components/Universe/Graph/Cubes/Text/index.tsx b/src/components/Universe/Graph/Cubes/Text/index.tsx
index 85b4faee1..b597d2d2b 100644
--- a/src/components/Universe/Graph/Cubes/Text/index.tsx
+++ b/src/components/Universe/Graph/Cubes/Text/index.tsx
@@ -4,48 +4,18 @@ import gsap from 'gsap'
import { memo, useEffect, useRef } from 'react'
import { Mesh, MeshBasicMaterial, Vector3 } from 'three'
import { Icons } from '~/components/Icons'
-import { useNodeTypes } from '~/stores/useDataStore'
+import { useTraceUpdate } from '~/hooks/useTraceUpdate'
import { useGraphStore } from '~/stores/useGraphStore'
import { useSchemaStore } from '~/stores/useSchemaStore'
import { NodeExtended } from '~/types'
-import { colors } from '~/utils/colors'
import { removeEmojis } from '~/utils/removeEmojisFromText'
import { truncateText } from '~/utils/truncateText'
import { fontProps } from './constants'
import { useTexture } from './hooks/useTexture'
-const COLORS_MAP = [
- '#fff',
- '#9747FF',
- '#00887A',
- '#0098A6',
- '#0288D1',
- '#33691E',
- '#465A65',
- '#512DA7',
- '#5C6BC0',
- '#5D4038',
- '#662C00',
- '#689F39',
- '#6B1B00',
- '#750000',
- '#78909C',
- '#7E57C2',
- '#8C6E63',
- '#AA47BC',
- '#BF360C',
- '#C2175B',
- '#EC407A',
- '#EF6C00',
- '#F5511E',
- '#FF9696',
- '#FFC064',
- '#FFCD29',
- '#FFEA60',
-]
-
type Props = {
node: NodeExtended
+ color: string
hide?: boolean
ignoreDistance: boolean
}
@@ -68,110 +38,113 @@ function splitStringIntoThreeParts(text: string): string {
return `${firstPart}\n${secondPart}\n${thirdPart}`
}
-export const TextNode = memo(({ node, hide, ignoreDistance }: Props) => {
- const svgRef = useRef(null)
- const ringRef = useRef(null)
- const circleRef = useRef(null)
-
- const nodePositionRef = useRef(new Vector3())
-
- const { texture } = useTexture(node.properties?.image_url || '')
+export const TextNode = memo(
+ (props: Props) => {
+ const { node, hide, ignoreDistance, color } = props
- const { normalizedSchemasByType, getNodeKeysByType } = useSchemaStore((s) => s)
+ const svgRef = useRef(null)
+ const ringRef = useRef(null)
+ const circleRef = useRef(null)
- useFrame(({ camera, clock }) => {
- const { selectedNode, hoveredNode, activeEdge } = useGraphStore.getState()
+ useTraceUpdate(props)
- const checkDistance = () => {
- const nodePosition = nodePositionRef.current.setFromMatrixPosition(ringRef.current!.matrixWorld)
+ const nodePositionRef = useRef(new Vector3())
- if (ringRef.current) {
- ringRef.current.visible = ignoreDistance ? true : nodePosition.distanceTo(camera.position) < 2500
- }
+ const { texture } = useTexture(node.properties?.image_url || '')
- // Set visibility based on distance
- }
+ const { normalizedSchemasByType, getNodeKeysByType } = useSchemaStore((s) => s)
- const isActive =
- node.ref_id === selectedNode?.ref_id ||
- node.ref_id === hoveredNode?.ref_id ||
- activeEdge?.target === node.ref_id ||
- activeEdge?.source === node.ref_id
+ useFrame(({ camera, clock }) => {
+ const { selectedNode, hoveredNode, activeEdge } = useGraphStore.getState()
- if (isActive) {
- if (ringRef.current) {
- ringRef.current.visible = true
- }
+ const checkDistance = () => {
+ const nodePosition = nodePositionRef.current.setFromMatrixPosition(ringRef.current!.matrixWorld)
- const scale = 3 + 0.2 * Math.sin(clock.getElapsedTime() * 2) // Adjust frequency and amplitude
+ if (ringRef.current) {
+ ringRef.current.visible = ignoreDistance ? true : nodePosition.distanceTo(camera.position) < 1500
+ }
- if (circleRef.current) {
- circleRef.current.visible = true
- circleRef.current.scale.set(scale, scale, scale)
+ // Set visibility based on distance
}
- return
- }
-
- if (circleRef.current) {
- circleRef.current.visible = false
- }
+ const isActive =
+ node.ref_id === selectedNode?.ref_id ||
+ node.ref_id === hoveredNode?.ref_id ||
+ activeEdge?.target === node.ref_id ||
+ activeEdge?.source === node.ref_id
- checkDistance()
- })
+ if (isActive) {
+ if (ringRef.current) {
+ ringRef.current.visible = true
+ }
- useEffect(() => {
- if (!ringRef.current) {
- return
- }
+ const scale = 3 + 0.2 * Math.sin(clock.getElapsedTime() * 2) // Adjust frequency and amplitude
- gsap.fromTo(
- ringRef.current.scale, // Target
- { x: 1, y: 1, z: 1 }, // From values
- {
- x: 6,
- y: 6,
- z: 6, // To values
- duration: 1.5, // Animation duration
- yoyo: true,
- repeat: 1,
- },
- )
- }, [ringRef])
+ if (circleRef.current) {
+ circleRef.current.visible = true
+ circleRef.current.scale.set(scale, scale, scale)
+ }
- const nodeTypes = useNodeTypes()
-
- const primaryColor = normalizedSchemasByType[node.node_type]?.primary_color
- const primaryIcon = normalizedSchemasByType[node.node_type]?.icon
-
- const color = primaryColor ?? (COLORS_MAP[nodeTypes.indexOf(node.node_type)] || colors.white)
+ return
+ }
- const Icon = primaryIcon ? Icons[primaryIcon] : null
- const iconName = Icon ? primaryIcon : 'NodesIcon'
- const keyProperty = getNodeKeysByType(node.node_type) || ''
+ if (circleRef.current) {
+ circleRef.current.visible = false
+ }
- const sanitizedNodeName =
- keyProperty && node?.properties ? removeEmojis(String(node?.properties[keyProperty] || '')) : ''
+ checkDistance()
+ })
- const uniforms = {
- u_texture: { value: texture },
- u_radius: { value: 0.5 }, // Radius of the circular mask
- }
+ useEffect(() => {
+ if (!ringRef.current) {
+ return
+ }
- return (
-
-
-
-
-
-
+ gsap.fromTo(
+ ringRef.current.scale, // Target
+ { x: 1, y: 1, z: 1 }, // From values
+ {
+ x: 2,
+ y: 2,
+ z: 2, // To values
+ duration: 1.5, // Animation duration
+ yoyo: true,
+ repeat: 1,
+ },
+ )
+ }, [ringRef])
+
+ const primaryColor = normalizedSchemasByType[node.node_type]?.primary_color
+ const primaryIcon = normalizedSchemasByType[node.node_type]?.icon
+
+ const nodeColor = primaryColor ?? color
+
+ const Icon = primaryIcon ? Icons[primaryIcon] : null
+ const iconName = Icon ? primaryIcon : 'NodesIcon'
+ const keyProperty = getNodeKeysByType(node.node_type) || ''
+
+ const sanitizedNodeName =
+ keyProperty && node?.properties ? removeEmojis(String(node?.properties[keyProperty] || '')) : ''
+
+ const uniforms = {
+ u_texture: { value: texture },
+ u_radius: { value: 0.5 }, // Radius of the circular mask
+ }
- {node.properties?.image_url &&
- ['Person', 'Episode', 'Guest', 'Host', 'Show'].includes(node.node_type) &&
- texture ? (
-
-
+
+
+
+
+
+
+ {node.properties?.image_url &&
+ ['Person', 'Episode', 'Guest', 'Host', 'Show'].includes(node.node_type) &&
+ texture ? (
+
+ {
}
}
`}
- uniforms={uniforms}
- vertexShader={`
+ uniforms={uniforms}
+ vertexShader={`
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`}
+ />
+
+ ) : (
+
- ) : (
-
-
- )
-})
+ )}
+
+ {sanitizedNodeName && (
+
+ {splitStringIntoThreeParts(sanitizedNodeName)}
+
+ )}
+
+
+ )
+ },
+ (prevProps, nextProps) =>
+ prevProps.hide === nextProps.hide &&
+ prevProps.ignoreDistance === nextProps.ignoreDistance &&
+ prevProps.node.ref_id === nextProps.node.ref_id,
+)
TextNode.displayName = 'TextNode'
diff --git a/src/components/Universe/Graph/Cubes/index.tsx b/src/components/Universe/Graph/Cubes/index.tsx
index c7517eccb..3c677261e 100644
--- a/src/components/Universe/Graph/Cubes/index.tsx
+++ b/src/components/Universe/Graph/Cubes/index.tsx
@@ -3,9 +3,10 @@ import { ThreeEvent } from '@react-three/fiber'
import { memo, useCallback, useRef } from 'react'
import { Object3D } from 'three'
import { useAppStore } from '~/stores/useAppStore'
-import { useDataStore } from '~/stores/useDataStore'
+import { useDataStore, useNodeTypes } from '~/stores/useDataStore'
import { useGraphStore, useHoveredNode, useSelectedNode, useSelectedNodeRelativeIds } from '~/stores/useGraphStore'
import { NodeExtended } from '~/types'
+import { colors } from '~/utils'
import { NodePoints } from './NodePoints'
import { RelevanceBadges } from './RelevanceBadges'
import { SelectionDataNodes } from './SelectionDataNodes'
@@ -13,12 +14,43 @@ import { TextNode } from './Text'
const POINTER_IN_DELAY = 200
+const COLORS_MAP = [
+ '#fff',
+ '#9747FF',
+ '#00887A',
+ '#0098A6',
+ '#0288D1',
+ '#33691E',
+ '#465A65',
+ '#512DA7',
+ '#5C6BC0',
+ '#5D4038',
+ '#662C00',
+ '#689F39',
+ '#6B1B00',
+ '#750000',
+ '#78909C',
+ '#7E57C2',
+ '#8C6E63',
+ '#AA47BC',
+ '#BF360C',
+ '#C2175B',
+ '#EC407A',
+ '#EF6C00',
+ '#F5511E',
+ '#FF9696',
+ '#FFC064',
+ '#FFCD29',
+ '#FFEA60',
+]
+
export const Cubes = memo(() => {
const selectedNode = useSelectedNode()
const hoveredNode = useHoveredNode()
const relativeIds = useSelectedNodeRelativeIds()
const { selectionGraphData, showSelectionGraph, setHoveredNode, setIsHovering } = useGraphStore((s) => s)
+ const nodeTypes = useNodeTypes()
const data = useDataStore((s) => s.dataInitial)
const setTranscriptOpen = useAppStore((s) => s.setTranscriptOpen)
@@ -112,12 +144,19 @@ export const Cubes = memo(() => {
{data?.nodes.map((node: NodeExtended) => {
const hide = !!selectedNode && (relativeIds.includes(node.ref_id) || selectedNode.ref_id === node.ref_id)
+ const color = COLORS_MAP[nodeTypes.indexOf(node.node_type)] || colors.white
return (
-
+
)
})}
diff --git a/src/components/Universe/Graph/index.tsx b/src/components/Universe/Graph/index.tsx
index d6262f506..c1c78840c 100644
--- a/src/components/Universe/Graph/index.tsx
+++ b/src/components/Universe/Graph/index.tsx
@@ -10,6 +10,7 @@ import { Connections } from './Connections'
import { Cubes } from './Cubes'
import { Earth } from './Earth'
import { LoadingNodes } from './LoadingNodes'
+import { Particles } from './Particles/index'
import { NodeDetailsPanel } from './UI'
export type LinkPosition = {
@@ -176,7 +177,16 @@ export const Graph = () => {
})
simulation.on('end', () => {
- const nodesVector = simulation.nodes().map((i: NodeExtended) => new Vector3(i.x, i.y, i.z))
+ const nodesVector = simulation.nodes().map((i: NodeExtended) => {
+ // eslint-disable-next-line no-param-reassign
+ i.fx = i.x
+ // eslint-disable-next-line no-param-reassign
+ i.fy = i.y
+ // eslint-disable-next-line no-param-reassign
+ i.fz = i.z
+
+ return new Vector3(i.x, i.y, i.z)
+ })
const boundingBox = new Box3().setFromPoints(nodesVector)
@@ -200,6 +210,7 @@ export const Graph = () => {
{graphStyle === 'earth' && }
+
{(isLoadingNew || isFetching) && }
diff --git a/src/components/Universe/Lights/index.tsx b/src/components/Universe/Lights/index.tsx
index 96bb3da9a..0da717496 100644
--- a/src/components/Universe/Lights/index.tsx
+++ b/src/components/Universe/Lights/index.tsx
@@ -1,19 +1,11 @@
import { useFrame } from '@react-three/fiber'
-import { useControls } from 'leva'
import { useRef } from 'react'
import { DirectionalLight, PointLight } from 'three'
-import { GRAPH_FOG_COLOR, GRAPH_GROUND_COLOR, GRAPH_LIGHT_INTENSITY } from '~/constants'
-import { useGraphStore } from '~/stores/useGraphStore'
+import { GRAPH_GROUND_COLOR, GRAPH_LIGHT_INTENSITY } from '~/constants'
import { colors } from '~/utils/colors'
import { UNIVERSE_SCALE } from '../Graph/constant'
export const Lights = () => {
- const { fogColor } = useControls('universe', {
- fogColor: GRAPH_FOG_COLOR,
- })
-
- const graphStyle = useGraphStore((s) => s.graphStyle)
-
const pLightRefAmbient = useRef(null)
const cameraLightRef = useRef(null)
const dLightRef = useRef(null)
@@ -46,7 +38,6 @@ export const Lights = () => {
<>
{/* static lights */}
- {graphStyle !== 'earth' && }
{/* moving lights */}
diff --git a/src/components/Universe/index.tsx b/src/components/Universe/index.tsx
index 1b0e131a2..3a5ce713e 100644
--- a/src/components/Universe/index.tsx
+++ b/src/components/Universe/index.tsx
@@ -3,7 +3,7 @@
import { AdaptiveDpr, AdaptiveEvents, Html, Loader, Preload } from '@react-three/drei'
import { Canvas, RootState } from '@react-three/fiber'
import { Bloom, EffectComposer, Outline, Selection, Vignette } from '@react-three/postprocessing'
-import { useControls } from 'leva'
+import { Leva, useControls } from 'leva'
import { BlendFunction, Resolution } from 'postprocessing'
import { Perf } from 'r3f-perf'
import { Suspense, memo, useCallback, useMemo } from 'react'
@@ -18,13 +18,13 @@ import { colors } from '~/utils/colors'
import { addToGlobalForE2e } from '~/utils/tests'
import { UniverseQuestion } from '../App/UniverseQuestion'
import { Flex } from '../common/Flex'
+import { outlineEffectColor } from './constants'
import { Controls } from './Controls'
import { initialCameraPosition } from './Controls/CameraAnimations/constants'
import { Graph } from './Graph'
import { Lights } from './Lights'
import { Overlay } from './Overlay'
import { Preloader } from './Preloader'
-import { outlineEffectColor } from './constants'
const Fallback = () => (
@@ -131,6 +131,7 @@ const _Universe = () => {
return (
+