diff --git a/src/components/Universe/Graph/Cubes/SelectionDataNodes/Connections/Connection/index.tsx b/src/components/Universe/Graph/Cubes/SelectionDataNodes/Connections/Connection/index.tsx index c6d9b2b61..aebb4cadf 100644 --- a/src/components/Universe/Graph/Cubes/SelectionDataNodes/Connections/Connection/index.tsx +++ b/src/components/Universe/Graph/Cubes/SelectionDataNodes/Connections/Connection/index.tsx @@ -23,16 +23,16 @@ const _Connection = (props: LineComponentProps) => { - + - + {label} diff --git a/src/components/Universe/Graph/Cubes/SelectionDataNodes/Connections/index.tsx b/src/components/Universe/Graph/Cubes/SelectionDataNodes/Connections/index.tsx index 6a6c49a80..dbd321832 100644 --- a/src/components/Universe/Graph/Cubes/SelectionDataNodes/Connections/index.tsx +++ b/src/components/Universe/Graph/Cubes/SelectionDataNodes/Connections/index.tsx @@ -4,14 +4,18 @@ import { Line2 } from 'three-stdlib' import { useShallow } from 'zustand/react/shallow' import { useGraphStore } from '~/stores/useGraphStore' import { Link, NodeExtended } from '~/types' +import { colors } from '~/utils' +import { PathNode } from '..' import { LinkPosition } from '../../..' import { Connection } from './Connection' type Props = { links: Link[] - nodes: NodeExtended[] + nodes: PathNode[] } +const PATH_COLOR = '#68BE3E' + export const Connections = memo(({ links, nodes }: Props) => { const groupRef = useRef(null) const linksPositionRef = useRef(new Map()) @@ -22,8 +26,6 @@ export const Connections = memo(({ links, nodes }: Props) => { return } - console.log('connection to updated') - const grConnections = groupRef.current grConnections.children.forEach((g, i) => { @@ -70,13 +72,22 @@ export const Connections = memo(({ links, nodes }: Props) => { const { material } = Line - material.color = new Color('white') + material.color = new Color(colors.white) + text.visible = true + material.opacity = 1 + material.linewidth = 2 + + if (targetNode.isPathNode && sourceNode.isPathNode) { + material.color = new Color(PATH_COLOR) + text.visible = false + material.linewidth = 4 + material.transparent = true + material.opacity = 0.3 + } } } }) - console.log('connection updated') - const nodesVector = nodes.map((i: NodeExtended) => new Vector3(i.x, i.y, i.z)) const boundingBox = new Box3().setFromPoints(nodesVector) diff --git a/src/components/Universe/Graph/Cubes/SelectionDataNodes/Node/index.tsx b/src/components/Universe/Graph/Cubes/SelectionDataNodes/Node/index.tsx index 117288b3e..a7f392925 100644 --- a/src/components/Universe/Graph/Cubes/SelectionDataNodes/Node/index.tsx +++ b/src/components/Universe/Graph/Cubes/SelectionDataNodes/Node/index.tsx @@ -9,16 +9,16 @@ import CloseIcon from '~/components/Icons/CloseIcon' import NodesIcon from '~/components/Icons/NodesIcon' import { useGraphStore } from '~/stores/useGraphStore' import { useSchemaStore } from '~/stores/useSchemaStore' -import { NodeExtended } from '~/types' import { colors } from '~/utils' import { truncateText } from '~/utils/truncateText' +import { PathNode } from '..' type TagProps = { rounded: boolean } type Props = { - node: NodeExtended + node: PathNode rounded?: boolean selected: boolean onClick: (id: string) => void diff --git a/src/components/Universe/Graph/Cubes/SelectionDataNodes/index.tsx b/src/components/Universe/Graph/Cubes/SelectionDataNodes/index.tsx index fd6c2ac75..681fd6824 100644 --- a/src/components/Universe/Graph/Cubes/SelectionDataNodes/index.tsx +++ b/src/components/Universe/Graph/Cubes/SelectionDataNodes/index.tsx @@ -10,9 +10,13 @@ import { LinkPosition } from '../..' import { Connections } from './Connections' import { Node as GraphNode } from './Node' -const radius = 50 +const RADIUS = 50 const MAX_LENGTH = 7 +export type PathNode = NodeExtended & { + isPathNode?: boolean +} + type GraphData = { links: Link[] nodes: NodeExtended[] @@ -39,12 +43,13 @@ export const SelectionDataNodes = memo(() => { } const oldNodes = pathGraph?.nodes || [] + const oldLinks = pathGraph?.links.filter((i) => !selectionData.links.some((l) => l.ref_id === i.ref_id)) || [] // Filter out nodes that already exist in oldNodes const newNodes = selectionData.nodes.filter((i) => !oldNodes.some((n) => n.ref_id === i.ref_id)) // Find the start position from oldNodes - const startPositionNode = oldNodes.find((i) => i.x !== 0 || i.y !== 0) + const startPositionNode = oldNodes.at(-1) const startPosition = startPositionNode ? { x: startPositionNode.x, y: startPositionNode.y } : { x: 0, y: 0 } // Calculate the starting angle (theta) for the start position @@ -59,16 +64,16 @@ export const SelectionDataNodes = memo(() => { ...newNodes.map((node, index) => { // Calculate angular position for the new node const theta = startTheta + thetaSpan * (index + 1) // Start adding from startTheta - const x = node.ref_id === selectedNode?.ref_id ? 0 : Math.cos(theta) * radius - const y = node.ref_id === selectedNode?.ref_id ? 0 : Math.sin(theta) * radius + const x = node.ref_id === selectedNode?.ref_id ? 0 : Math.cos(theta) * RADIUS + const y = node.ref_id === selectedNode?.ref_id ? 0 : Math.sin(theta) * RADIUS const z = node.ref_id === selectedNode?.ref_id ? 0 : 0 return { ...node, x, y, z } }), ] - return { nodes, links: selectionData.links } - }, [selectionData, selectedNode, pathGraph?.nodes]) + return { nodes, links: [...selectionData.links, ...oldLinks] } + }, [selectionData?.nodes, selectionData?.links, pathGraph?.nodes, pathGraph?.links, selectedNode?.ref_id]) const graphData: GraphData = useMemo(() => { if (newData?.nodes?.length) { @@ -103,7 +108,7 @@ export const SelectionDataNodes = memo(() => { const graphNodes = filteredNodes.map((node: Node) => ({ ...node, x: 0, y: 0, z: 0 })) - const nodes: NodeExtended[] = [...graphNodes, { ...selectedNode, x: 0, y: 0, z: 0, fx: 0, fy: 0, fz: 0 }] + const nodes: PathNode[] = [...graphNodes, { ...selectedNode, x: 0, y: 0, z: 0, fx: 0, fy: 0, fz: 0 }] const links = data.edges.filter( (link: Link) => @@ -132,32 +137,76 @@ export const SelectionDataNodes = memo(() => { if (selectedNode) { const newSelectedNode = graphData.nodes.find((i) => i.ref_id === id) - const nodes = [ - { ...newSelectedNode, x: 0, y: 0, z: 0, fx: 0, fy: 0, fz: 0 }, - { - ...selectedNode, - ...(newSelectedNode?.x !== undefined ? { fx: -newSelectedNode.x, x: -newSelectedNode.x } : { x: 0 }), - ...(newSelectedNode?.y !== undefined ? { fy: -newSelectedNode.y, y: -newSelectedNode.y } : { y: 0 }), - ...(newSelectedNode?.z !== undefined ? { fz: newSelectedNode?.z, z: newSelectedNode.z } : { z: 0 }), - }, - ] + if (!newSelectedNode) { + return + } + + const oldPathNodes = pathGraph?.nodes.filter((i) => i.ref_id !== newSelectedNode.ref_id) || [] + + // Create new path nodes, keeping up to 2 older nodes + const newPathNodes = [ + { ...newSelectedNode, isPathNode: false }, + ...(oldPathNodes.length ? oldPathNodes : [{ ...selectedNode, isPathNode: true }]), + ].slice(0, 3) + + const angle = Math.atan2(-newSelectedNode.y, -newSelectedNode.x) + const x = RADIUS * Math.cos(angle) + const y = RADIUS * Math.sin(angle) + + const updatedPathNodes = newPathNodes.map((node, index) => { + if (index === 0) { + return { ...node, x: 0, y: 0, z: 0, fx: 0, fy: 0, fz: 0, isPathNode: true } + } + + if (index === 1) { + return newPathNodes.length === 3 + ? { + ...node, + x: x / 2, + y: y / 2, + z: 0, + fx: x / 2, + fy: y / 2, + fz: 0, + isPathNode: true, + } + : { + ...node, + x, + y, + z: 0, + fx: x, + fy: y, + fz: 0, + isPathNode: true, + } + } + + return { + ...node, + x, + y, + z: 0, + fx: x, + fy: y, + fz: 0, + isPathNode: true, + } + }) const links = graphData.links.filter( (i) => - (i.target === selectedNode?.ref_id && i.source === id) || - (i.source === selectedNode?.ref_id && i.target === id), + updatedPathNodes.some((node) => node.ref_id === i.target) && + updatedPathNodes.some((node) => node.ref_id === i.source), ) - console.log(links, 'here') setSelectionData(null) - setPathGraph({ nodes: nodes as NodeExtended[], links }) + setPathGraph({ nodes: updatedPathNodes as NodeExtended[], links }) - if (newSelectedNode) { - setSelectedNode(newSelectedNode) - } + setSelectedNode(newSelectedNode) } }, - [graphData.links, graphData.nodes, selectedNode, setSelectedNode], + [graphData.links, graphData.nodes, pathGraph, selectedNode, setSelectedNode], ) return ( diff --git a/src/components/mindset/data/index.tsx b/src/components/mindset/data/index.tsx deleted file mode 100644 index 2fae3709e..000000000 --- a/src/components/mindset/data/index.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { Link, NodeExtended } from '~/types' - -// const transcript = 'Entrepreneurship is being revolutionized by Blockchain and AI, as they open new frontiers for innovation and secure digital solutions.' - -export const nodes: NodeExtended[] = [ - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '1', node_type: 'Clip', name: 'Podcast' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '2', node_type: 'Topic', name: 'Bitcoin' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '3', node_type: 'Topic', name: 'Blockchain' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '4', node_type: 'Topic', name: 'Hard Money' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '5', node_type: 'Topic', name: 'Digital Currency' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '6', node_type: 'Topic', name: 'Government Control' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '7', node_type: 'Topic', name: 'Inflation' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '8', node_type: 'Topic', name: 'Public Network' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '9', node_type: 'Topic', name: 'Energy Consumption' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '10', node_type: 'Topic', name: 'Immutability' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '11', node_type: 'Topic', name: 'Scarcity' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '12', node_type: 'Topic', name: 'Decentralization' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '13', node_type: 'Topic', name: 'Investment Risks' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '14', node_type: 'Topic', name: 'Adoption' }, - { edge_count: 0, x: 0, y: 0, z: 0, label: 'label', ref_id: '15', node_type: 'Person', name: 'Satoshi Nakamoto' }, -] - -export const edges: Link[] = [ - // Bitcoin as a digital currency - { - ref_id: '1', - edge_type: 'Mentioned', - target: '1', // Clip - source: '2', // Bitcoin - properties: { start: 7.68, end: 19.619 }, - }, - - // Bitcoin's hard money nature - { - ref_id: '2', - edge_type: 'Mentioned', - target: '1', // Clip - source: '4', // Hard Money - properties: { start: 28.019, end: 38.04 }, - }, - - // Blockchain as a public ledger - { - ref_id: '3', - edge_type: 'Mentioned', - target: '1', // Clip - source: '3', // Blockchain - properties: { start: 50.82, end: 56.52 }, - }, - - // Scarcity of Bitcoin - { - ref_id: '4', - edge_type: 'Mentioned', - target: '1', // Clip - source: '5', // Scarcity - properties: { start: 19.439, end: 25.619 }, - }, - - // Government control contrasted with Bitcoin - { - ref_id: '5', - edge_type: 'Mentioned', - target: '1', // Clip - source: '6', // Government Control - properties: { start: 34.619, end: 43.02 }, - }, - - // Energy consumption in Bitcoin mining - { - ref_id: '6', - edge_type: 'Mentioned', - target: '1', // Clip - source: '9', // Energy Consumption - properties: { start: 31.8, end: 38.04 }, - }, - - // Immutability ensured by the blockchain - { - ref_id: '7', - edge_type: 'Mentioned', - target: '1', // Clip - source: '10', // Immutability - properties: { start: 56.52, end: 60.48 }, - }, - - // Decentralization of Bitcoin's public network - { - ref_id: '8', - edge_type: 'Mentioned', - target: '1', // Clip - source: '12', // Decentralization - properties: { start: 90.72, end: 97.52 }, - }, - - // Bitcoin investment risks - { - ref_id: '9', - edge_type: 'Mentioned', - target: '1', // Clip - source: '13', // Investment Risks - properties: { start: 126.44, end: 133.48 }, - }, - - // Bitcoin adoption rates and potential - { - ref_id: '10', - edge_type: 'Mentioned', - target: '1', // Clip - source: '14', // Adoption - properties: { start: 122.44, end: 130.48 }, - }, -] - -export const edgesMention: Array<{ source: string; start: number }> = edges - .filter((e) => e?.start) - .map((edge) => ({ source: edge.source, start: edge?.start as number })) - -export const nodesWithTimestamp: NodeExtended[] = (nodes || []) - .filter((node) => edgesMention.some((ed) => ed.source === node.ref_id)) - .map((node) => { - const edge = edgesMention.find((ed) => node.ref_id === ed.source) - - return { ...node, start: edge?.start || 0 } - }) - .filter((node) => node) - -export const data = { - nodes, - edges, -} - -const timestamps = edges.flatMap((e) => { - const { start, end } = e.properties ?? {} - - return start !== undefined && end !== undefined ? [start, end] : [0, 0] -}) - -export const minTimestamp = Math.min(...(timestamps as number[])) - -export const maxTimestamp = Math.max(...(timestamps as number[])) - -export const normalizeTimestamp = (value: number, min: number, max: number, rangeMin: number, rangeMax: number) => - rangeMin + ((value - min) / (max - min)) * (rangeMax - rangeMin) diff --git a/src/components/mindset/data/transcript/index.tsx b/src/components/mindset/data/transcript/index.tsx deleted file mode 100644 index 0e097e8c0..000000000 --- a/src/components/mindset/data/transcript/index.tsx +++ /dev/null @@ -1,76 +0,0 @@ -export const transcript = [ - { text: 'when money is easy to make Society', timestamp: 179 }, - { text: 'begins to break', timestamp: 2760 }, - { text: 'well one solution is Bitcoin', timestamp: 7680 }, - { text: 'back in 2008 I became fed up with', timestamp: 11219 }, - { text: 'government money with the corruption the', timestamp: 13620 }, - { text: 'manipulation so I created a digital', timestamp: 15599 }, - { text: 'currency digital money that can be sent', timestamp: 17760 }, - { text: 'directly from one person to another', timestamp: 19619 }, - { text: 'without any bank or government involved', timestamp: 21119 }, - { text: "and the best part it's hard money", timestamp: 23400 }, - { text: 'Bitcoin is very hard to make more of', timestamp: 28019 }, - { text: 'each new coin gets added to the supply', timestamp: 29939 }, - { text: 'only after a computer works very hard to', timestamp: 31800 }, - { text: "solve a math problem where there's no", timestamp: 34200 }, - { text: 'shortcut and solving it costs a lot of', timestamp: 35880 }, - { text: 'energy and time', timestamp: 38040 }, - { text: "okay but if it's on a computer can't I", timestamp: 40559 }, - { text: 'just copy and paste', timestamp: 43020 }, - { text: 'not with Bitcoin you', timestamp: 46559 }, - { text: 'have public record of every Bitcoin ever', timestamp: 48600 }, - { text: "created it's called the blockchain it's", timestamp: 50820 }, - { text: 'like a puzzle and each Bitcoin has its', timestamp: 54300 }, - { text: 'own unique shape and because everyone', timestamp: 56520 }, - { text: 'has a copy of the public record if', timestamp: 58260 }, - { text: 'someone tries to fake a Bitcoin', timestamp: 60480 }, - { text: "it won't fit the puzzle and will be", timestamp: 65099 }, - { text: 'rejected by the network before anyone', timestamp: 67140 }, - { text: 'can use it', timestamp: 69060 }, - { text: "that's why Bitcoin is so safe from", timestamp: 70860 }, - { text: 'criminals and the government you said', timestamp: 72960 }, - { text: 'criminals twice', timestamp: 75420 }, - { text: 'dollars which can be printed endlessly', timestamp: 77439 }, - { text: 'there will only ever be 21 million', timestamp: 79720 }, - { text: "Bitcoin it's almost impossible to", timestamp: 81720 }, - { text: 'inflate the only way to get it is to', timestamp: 83759 }, - { text: 'earn it or buy it from someone who has', timestamp: 85619 }, - { text: 'no offense but if you', timestamp: 89820 }, - { text: "if you coin couldn't you manipulate it", timestamp: 91320 }, - { text: "just like the government I don't control", timestamp: 92880 }, - { text: "it no one person does it's controlled by", timestamp: 94619 }, - { text: 'a public network of Bitcoin users that', timestamp: 97619 }, - { text: 'anyone can join so if someone wanted to', timestamp: 99720 }, - { text: "change something in bitcoin's code they", timestamp: 101939 }, - { text: 'would need to get the majority of the', timestamp: 103920 }, - { text: 'millions of Bitcoin users to agree to it', timestamp: 104659 }, - { text: "all the change doesn't happen and when", timestamp: 104752 }, - { text: 'has the majority of us agreed on', timestamp: 104860 }, - { text: 'anything', timestamp: 105360 }, - { text: "touche wow I didn't know made up money", timestamp: 105720 }, - { text: 'could make so much sense today millions', timestamp: 105960 }, - { text: 'of people send Bitcoin instantly and', timestamp: 106180 }, - { text: 'cheaply to each other around the world', timestamp: 106399 }, - { text: 'without any bank or government involved', timestamp: 106620 }, - { text: 'and because Bitcoin is hard money you', timestamp: 106859 }, - { text: "can't just print more of the more people", timestamp: 107360 }, - { text: 'who use it the more valuable it becomes', timestamp: 107960 }, - { text: "Emily if we take Lyle's Bitcoin we could", timestamp: 108640 }, - { text: 'be rich I could pay for college entirely', timestamp: 109040 }, - { text: 'you could Outsource your movie and pay', timestamp: 109440 }, - { text: 'to have your name in the credits slow', timestamp: 109840 }, - { text: "down I'm not saying that Bitcoin will", timestamp: 110240 }, - { text: 'make you rich quick or even at all right', timestamp: 110640 }, - { text: 'now only about one percent of the world', timestamp: 110780 }, - { text: "owns Bitcoin and because it's still", timestamp: 111280 }, - { text: 'being adopted some days it goes up and', timestamp: 111580 }, - { text: 'even down also Investments or', timestamp: 111820 }, - { text: 'potentially lucrative can be risky', timestamp: 112380 }, - { text: 'oh I think I get it good money should be', timestamp: 112879 }, - { text: 'easy to use but hard to create and', timestamp: 113459 }, - { text: "because Bitcoin is digital it's fast and", timestamp: 113800 }, - { text: 'cheap to use and the blockchain makes it', timestamp: 113900 }, - { text: 'hard to inflate thanks Mr Satoshi', timestamp: 114379 }, - { text: 'what Mr Satoshi', timestamp: 114819 }, - { text: 'gone or was he Aaron even here', timestamp: 115340 }, -] diff --git a/src/components/mindset/index.tsx b/src/components/mindset/index.tsx index f82f05831..ba850ccc7 100644 --- a/src/components/mindset/index.tsx +++ b/src/components/mindset/index.tsx @@ -165,14 +165,14 @@ export const MindSet = () => { if (previousTimeRef.current !== null) { const deltaTime = time - previousTimeRef.current - if (deltaTime > 2000) { + if (deltaTime > 1000) { if (nodesAndEdgesRef.current && playerRef) { const { nodes, edges } = nodesAndEdgesRef.current const currentTime = playerRef?.getCurrentTime() const [matchingLinks, remainingLinks] = edges.reduce<[Link[], Link[]]>( ([matches, remaining], link) => { - if (link?.properties?.start !== undefined && (link?.properties?.start as number) < currentTime + 3) { + if (link?.properties?.start !== undefined && (link?.properties?.start as number) < currentTime + 5) { matches.push(link) } else { remaining.push(link)