Skip to content

Commit 47a86ed

Browse files
committed
label upgrade
1 parent da73bb5 commit 47a86ed

1 file changed

Lines changed: 66 additions & 32 deletions

File tree

src/components/BuckyBall.tsx

Lines changed: 66 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,10 @@ const buckyballVertices = () => {
8888

8989
const BuckyballScene = ({ skills }: { skills: string[] }) => {
9090
const groupRef = useRef<THREE.Group>(null);
91-
const meshRef = useRef<THREE.Mesh>(null);
92-
const [cameraPos, setCameraPos] = useState(new THREE.Vector3(0, 0, 5));
93-
const [visibleNodes, setVisibleNodes] = useState<number[]>([]);
91+
const [cameraPos, setCameraPos] = useState(new THREE.Vector3(0, 0, 7));
92+
const [nodeAssignments, setNodeAssignments] = useState<{ nodeIndex: number, skillIndex: number }[]>([]);
93+
const [nodesToUpdate, setNodesToUpdate] = useState<number[]>([]);
94+
const [frameCount, setFrameCount] = useState(0);
9495
const vertices = useRef(buckyballVertices());
9596

9697
// Rotate the group and update camera position for skills visibility calculation
@@ -100,53 +101,86 @@ const BuckyballScene = ({ skills }: { skills: string[] }) => {
100101
groupRef.current.rotation.x += 0.0005;
101102
}
102103
setCameraPos(state.camera.position);
104+
105+
// Update frameCount only every 10 frames to avoid too frequent checks
106+
setFrameCount(prev => (prev + 1) % 10);
107+
108+
// Check every 10 frames which nodes are far away and should be updated
109+
if (frameCount === 0) {
110+
const newNodesToUpdate: number[] = [];
111+
112+
// Check each node with an assignment
113+
nodeAssignments.forEach(({ nodeIndex }) => {
114+
const position = vertices.current[nodeIndex];
115+
const positionVector = new THREE.Vector3(...position);
116+
117+
// Calculate distance and angle to determine if node is far from camera
118+
const cameraToPoint = positionVector.clone().sub(state.camera.position);
119+
const distance = cameraToPoint.length();
120+
const dotProduct = positionVector.clone().normalize().dot(state.camera.position.normalize());
121+
122+
// If node is far away and facing away from camera, mark for update
123+
if (dotProduct < -0.5 && distance > 6) {
124+
newNodesToUpdate.push(nodeIndex);
125+
}
126+
});
127+
128+
if (newNodesToUpdate.length > 0) {
129+
setNodesToUpdate(newNodesToUpdate);
130+
}
131+
}
103132
});
104133

105-
// Update visible nodes - show more nodes at once
134+
// Initial assignment of skills to nodes
106135
useEffect(() => {
107-
const updateVisibleNodes = () => {
136+
if (nodeAssignments.length === 0) {
108137
const totalNodes = vertices.current.length;
109-
// Show even more nodes - 10 instead of 8
110-
const numVisibleNodes = Math.min(10, skills.length);
111-
const newVisibleNodes = [];
138+
const numNodes = Math.min(10, skills.length);
139+
const initialAssignments = [];
112140

113-
// Select random nodes to display skills
114-
while (newVisibleNodes.length < numVisibleNodes) {
115-
const randomIndex = Math.floor(Math.random() * totalNodes);
116-
if (!newVisibleNodes.includes(randomIndex)) {
117-
newVisibleNodes.push(randomIndex);
118-
}
141+
// Create initial random assignments
142+
for (let i = 0; i < numNodes; i++) {
143+
initialAssignments.push({
144+
nodeIndex: Math.floor(Math.random() * totalNodes),
145+
skillIndex: i
146+
});
119147
}
120148

121-
setVisibleNodes(newVisibleNodes);
122-
};
123-
124-
updateVisibleNodes();
125-
// Change more frequently
126-
const interval = setInterval(updateVisibleNodes, 2000);
127-
128-
return () => clearInterval(interval);
149+
setNodeAssignments(initialAssignments);
150+
}
129151
}, [skills]);
130152

153+
// Update skills for nodes that are far away from camera
154+
useEffect(() => {
155+
if (nodesToUpdate.length > 0) {
156+
setNodeAssignments(prev => prev.map(assignment => {
157+
if (nodesToUpdate.includes(assignment.nodeIndex)) {
158+
return { ...assignment, skillIndex: Math.floor(Math.random() * skills.length) };
159+
}
160+
return assignment;
161+
}));
162+
setNodesToUpdate([]);
163+
}
164+
}, [nodesToUpdate, skills]);
165+
131166
return (
132167
<group ref={groupRef}>
133168
{/* Create edges for the buckyball wireframe */}
134169
<lineSegments>
135170
<edgesGeometry args={[new THREE.IcosahedronGeometry(BUCKYBALL_RADIUS, 1)]} />
136171
<lineBasicMaterial color="#3b82f6" transparent opacity={0.5} fog={true} />
137172
</lineSegments>
138-
139-
{/* Create the invisible buckyball mesh for reference */}
140-
<mesh ref={meshRef} visible={false}>
141-
<icosahedronGeometry args={[BUCKYBALL_RADIUS, 1]} />
142-
<meshBasicMaterial color="white" wireframe />
143-
</mesh>
144-
173+
145174
{/* Place skill nodes at vertex positions */}
146175
{vertices.current.map((position, i) => {
147-
const visible = visibleNodes.includes(i);
148-
const skillIndex = visibleNodes.indexOf(i);
149-
const text = visible && skillIndex < skills.length ? skills[skillIndex] : "";
176+
// Find if this node has a skill assignment
177+
const assignment = nodeAssignments.find(a => a.nodeIndex === i);
178+
const visible = !!assignment;
179+
let text = "";
180+
181+
if (visible && assignment) {
182+
text = skills[assignment.skillIndex % skills.length];
183+
}
150184

151185
return (
152186
<SkillNode

0 commit comments

Comments
 (0)