Added node connection beam animations

This commit is contained in:
TehRiehlDeal committed 2026-01-12 23:35:14 -08:00
1 parent 13a57b39a0
commit eb961b752c
1 file changed
+108 -39
+108 -39
View File
@@ -533,32 +533,6 @@
dragStartY = e.touches[0].clientY; dragStartY = e.touches[0].clientY;
containerStartX = treeContainer.x; containerStartX = treeContainer.x;
containerStartY = treeContainer.y; containerStartY = treeContainer.y;
} else if (e.touches.length === 2) {
// Two touches - start pinch zoom
isDragging = false;
isTouchZooming = true;
const dx = e.touches[0].clientX - e.touches[1].clientX;
const dy = e.touches[0].clientY - e.touches[1].clientY;
lastTouchDistance = Math.sqrt(dx * dx + dy * dy);
}
}, { passive: true });
// ========== TOUCH EVENTS FOR PANNING & ZOOMING ==========
let touchStartedOnNode = false;
app.canvas.addEventListener('touchstart', (e: TouchEvent) => {
// Check if touch started on a node by seeing if the target is interactive
touchStartedOnNode = false;
if (e.touches.length === 1) {
// Single touch - prepare for potential panning
isDragging = true;
hasMoved = false;
isTouchZooming = false;
dragStartX = e.touches[0].clientX;
dragStartY = e.touches[0].clientY;
containerStartX = treeContainer.x;
containerStartY = treeContainer.y;
} else if (e.touches.length === 2) { } else if (e.touches.length === 2) {
// Two touches - start pinch zoom // Two touches - start pinch zoom
isDragging = false; isDragging = false;
@@ -672,21 +646,48 @@
return Math.sqrt(node.x * node.x + node.y * node.y); return Math.sqrt(node.x * node.x + node.y * node.y);
} }
// ========== DRAW GLOWING LINES ========== // ========== DRAW GLOWING LINES WITH PLASMA BEAMS ==========
const lineObjects: { graphics: Graphics; glowGraphics: Graphics; node: TreeNode; parent: TreeNode }[] = []; const lineObjects: {
graphics: Graphics;
glowGraphics: Graphics;
plasmaBeam: Graphics;
node: TreeNode;
parent: TreeNode;
intensity: number;
}[] = [];
for (const node of treeNodes) { for (const node of treeNodes) {
if (node.parentId) { if (node.parentId) {
const parent = getNodeById(node.parentId); const parent = getNodeById(node.parentId);
if (parent) { if (parent) {
// Calculate beam intensity based on years of experience (for skill nodes)
let intensity = 0.3; // Default base intensity
if (node.category === 'skills' && node.yearsOfExperience) {
// Scale from 0.3 (beginner) to 1.0 (10+ years)
intensity = Math.min(0.3 + (node.yearsOfExperience / 10) * 0.7, 1.0);
} else if (node.category === 'experience') {
// Experience nodes get medium-high intensity
intensity = 0.7;
} else if (node.category === 'origin') {
// Origin connections are always bright
intensity = 1.0;
} else {
// Projects and education get medium intensity
intensity = 0.5;
}
const color = categoryColors[node.category];
// Base glow layer (wide, soft)
const glowGraphics = new Graphics(); const glowGraphics = new Graphics();
glowGraphics.alpha = 0; glowGraphics.alpha = 0;
glowGraphics glowGraphics
.moveTo(parent.x, parent.y) .moveTo(parent.x, parent.y)
.lineTo(node.x, node.y) .lineTo(node.x, node.y)
.stroke({ width: 8, color: categoryColors[node.category], alpha: 0.15 }); .stroke({ width: 12, color: color, alpha: 0.1 * intensity });
treeContainer.addChild(glowGraphics); treeContainer.addChild(glowGraphics);
// Core line (thin, solid)
const lineGraphics = new Graphics(); const lineGraphics = new Graphics();
lineGraphics.alpha = 0; lineGraphics.alpha = 0;
lineGraphics lineGraphics
@@ -695,7 +696,23 @@
.stroke({ width: 2, color: 0x4a4a5a }); .stroke({ width: 2, color: 0x4a4a5a });
treeContainer.addChild(lineGraphics); treeContainer.addChild(lineGraphics);
lineObjects.push({ graphics: lineGraphics, glowGraphics, node, parent }); // Plasma energy beam (medium, bright, animated)
const plasmaBeam = new Graphics();
plasmaBeam.alpha = 0;
plasmaBeam
.moveTo(parent.x, parent.y)
.lineTo(node.x, node.y)
.stroke({ width: 4, color: color, alpha: 0.6 * intensity });
treeContainer.addChild(plasmaBeam);
lineObjects.push({
graphics: lineGraphics,
glowGraphics,
plasmaBeam,
node,
parent,
intensity
});
} }
} }
} }
@@ -751,7 +768,8 @@
profileContainer.alpha = 0; profileContainer.alpha = 0;
profileContainer.scale.set(0.5); profileContainer.scale.set(0.5);
profileContainer.eventMode = 'static'; // Disable interactivity until animation completes
profileContainer.eventMode = 'none';
profileContainer.cursor = 'pointer'; profileContainer.cursor = 'pointer';
profileContainer.on('pointerdown', () => { profileContainer.on('pointerdown', () => {
@@ -817,7 +835,8 @@
nodeContainer.alpha = 0; nodeContainer.alpha = 0;
nodeContainer.scale.set(0.5); nodeContainer.scale.set(0.5);
nodeContainer.eventMode = 'static'; // Disable interactivity until animation completes
nodeContainer.eventMode = 'none';
nodeContainer.cursor = 'pointer'; nodeContainer.cursor = 'pointer';
nodeContainer.on('pointerdown', () => { nodeContainer.on('pointerdown', () => {
@@ -860,10 +879,11 @@
const zoomDuration = isMobile ? 2.5 : 4.5; const zoomDuration = isMobile ? 2.5 : 4.5;
const nodeStagger = isMobile ? 0.05 : 0.08; const nodeStagger = isMobile ? 0.05 : 0.08;
// Hide all lines initially // Hide all lines and plasma beams initially
lineObjects.forEach((line) => { lineObjects.forEach((line) => {
line.graphics.alpha = 0; line.graphics.alpha = 0;
line.glowGraphics.alpha = 0; line.glowGraphics.alpha = 0;
line.plasmaBeam.alpha = 0;
}); });
// Hide all nodes initially // Hide all nodes initially
@@ -906,6 +926,12 @@
duration: originDuration, duration: originDuration,
delay: originDelay, delay: originDelay,
ease: 'back.out(1.7)', ease: 'back.out(1.7)',
onComplete: () => {
// Enable interactivity after animation completes
if (originNode.graphics instanceof Container) {
originNode.graphics.eventMode = 'static';
}
},
}); });
gsap.to(originNode.glowGraphics, { gsap.to(originNode.glowGraphics, {
alpha: 1, alpha: 1,
@@ -932,7 +958,7 @@
otherNodes.forEach((obj, index) => { otherNodes.forEach((obj, index) => {
const delay = nodeStartDelay + (index * nodeStagger); const delay = nodeStartDelay + (index * nodeStagger);
gsap.to(obj.graphics, { gsap.to(obj.graphics, {
alpha: 1, alpha: 1,
duration: 0.5, duration: 0.5,
@@ -945,6 +971,12 @@
duration: 0.5, duration: 0.5,
delay: delay, delay: delay,
ease: 'back.out(1.7)', ease: 'back.out(1.7)',
onComplete: () => {
// Enable interactivity after animation completes
if (obj.graphics instanceof Container) {
obj.graphics.eventMode = 'static';
}
},
}); });
gsap.to(obj.glowGraphics, { gsap.to(obj.glowGraphics, {
alpha: 1, alpha: 1,
@@ -978,24 +1010,61 @@
}); });
} }
// STEP 4: Animate lines as nodes appear // STEP 4: Animate lines and plasma beams as nodes appear
const lineStartDelay = isMobile ? titleDuration - 0.3 : titleDuration + 0.4; const lineStartDelay = isMobile ? titleDuration - 0.3 : titleDuration + 0.4;
sortedLines.forEach((line, index) => { sortedLines.forEach((line, index) => {
const delay = lineStartDelay + (index * nodeStagger); const delay = lineStartDelay + (index * nodeStagger);
// Core line appears first
gsap.to(line.graphics, { gsap.to(line.graphics, {
alpha: 1, alpha: 1,
duration: 0.4, duration: 0.4,
delay: delay, delay: delay,
ease: 'power2.out', ease: 'power2.out',
}); });
// Base glow appears with line
gsap.to(line.glowGraphics, { gsap.to(line.glowGraphics, {
alpha: 1, alpha: 1,
duration: 0.6, duration: 0.6,
delay: delay + 0.1, delay: delay + 0.1,
ease: 'power2.out', ease: 'power2.out',
}); });
// Plasma beam fades in
gsap.to(line.plasmaBeam, {
alpha: 1,
duration: 0.8,
delay: delay + 0.2,
ease: 'power2.out',
onComplete: () => {
// After beam appears, start continuous pulsing animation
const pulseDuration = 2.0 + Math.random() * 1.0; // Vary pulse speed
const maxAlpha = 0.9 * line.intensity; // Base alpha on intensity
const minAlpha = 0.6 * line.intensity; // Minimum brightness - stays visible
// Pulsing alpha animation (breathing effect)
gsap.to(line.plasmaBeam, {
alpha: minAlpha,
duration: pulseDuration,
ease: 'sine.inOut',
yoyo: true,
repeat: -1,
});
// Glow layer also pulses
const glowMaxAlpha = 0.2 * line.intensity;
const glowMinAlpha = 0.12 * line.intensity;
gsap.to(line.glowGraphics, {
alpha: glowMinAlpha,
duration: pulseDuration * 1.2,
ease: 'sine.inOut',
yoyo: true,
repeat: -1,
});
},
});
}); });
// Clean up title card after animation (matches titleDuration) // Clean up title card after animation (matches titleDuration)
@@ -2157,12 +2226,12 @@
} }
.stats-panel-toggle.open { .stats-panel-toggle.open {
transform: translateY(-85vh) rotate(180deg); transform: translateY(-85dvh) rotate(180deg);
} }
.stats-panel { .stats-panel {
width: 100%; width: 100%;
height: 85vh; height: 85dvh;
border-left: none; border-left: none;
border-right: none; border-right: none;
border-top: 2px solid #ffd700; border-top: 2px solid #ffd700;