psilo-cybernetics-website/components/network-visualization.tsx

144 lines
4.5 KiB
TypeScript

"use client"
import { useEffect, useRef } from "react"
export function NetworkVisualization() {
const canvasRef = useRef<HTMLCanvasElement>(null)
useEffect(() => {
const canvas = canvasRef.current
if (!canvas) return
const ctx = canvas.getContext("2d")
if (!ctx) return
// Set canvas size
const updateSize = () => {
canvas.width = canvas.offsetWidth * window.devicePixelRatio
canvas.height = canvas.offsetHeight * window.devicePixelRatio
ctx.scale(window.devicePixelRatio, window.devicePixelRatio)
}
updateSize()
window.addEventListener("resize", updateSize)
const nodes: Array<{
x: number
y: number
vx: number
vy: number
radius: number
hue: number
pulsePhase: number
}> = []
const nodeCount = 40
for (let i = 0; i < nodeCount; i++) {
nodes.push({
x: Math.random() * canvas.offsetWidth,
y: Math.random() * canvas.offsetHeight,
vx: (Math.random() - 0.5) * 0.8,
vy: (Math.random() - 0.5) * 0.8,
radius: Math.random() * 4 + 2,
hue: Math.random() * 60 + 170, // Cyan to magenta range
pulsePhase: Math.random() * Math.PI * 2,
})
}
let time = 0
// Animation loop
let animationId: number
const animate = () => {
time += 0.01
ctx.fillStyle = "rgba(13, 13, 26, 0.1)"
ctx.fillRect(0, 0, canvas.offsetWidth, canvas.offsetHeight)
// Update and draw nodes
nodes.forEach((node, i) => {
node.x += node.vx
node.y += node.vy
node.pulsePhase += 0.05
// Bounce off edges
if (node.x < 0 || node.x > canvas.offsetWidth) node.vx *= -1
if (node.y < 0 || node.y > canvas.offsetHeight) node.vy *= -1
nodes.forEach((otherNode, j) => {
if (i === j) return
const dx = otherNode.x - node.x
const dy = otherNode.y - node.y
const distance = Math.sqrt(dx * dx + dy * dy)
if (distance < 180) {
const opacity = (1 - distance / 180) * 0.6
const gradient = ctx.createLinearGradient(node.x, node.y, otherNode.x, otherNode.y)
gradient.addColorStop(0, `hsla(${node.hue}, 100%, 60%, ${opacity})`)
gradient.addColorStop(1, `hsla(${otherNode.hue}, 100%, 60%, ${opacity})`)
ctx.strokeStyle = gradient
ctx.lineWidth = 2
ctx.shadowBlur = 10
ctx.shadowColor = `hsl(${node.hue}, 100%, 60%)`
ctx.beginPath()
ctx.moveTo(node.x, node.y)
ctx.lineTo(otherNode.x, otherNode.y)
ctx.stroke()
ctx.shadowBlur = 0
}
})
const pulse = Math.sin(node.pulsePhase) * 0.5 + 1
const glowRadius = node.radius * pulse * 3
// Outer glow
const gradient = ctx.createRadialGradient(node.x, node.y, 0, node.x, node.y, glowRadius)
gradient.addColorStop(0, `hsla(${node.hue}, 100%, 60%, 0.8)`)
gradient.addColorStop(0.5, `hsla(${node.hue}, 100%, 60%, 0.3)`)
gradient.addColorStop(1, `hsla(${node.hue}, 100%, 60%, 0)`)
ctx.fillStyle = gradient
ctx.beginPath()
ctx.arc(node.x, node.y, glowRadius, 0, Math.PI * 2)
ctx.fill()
// Core node
ctx.fillStyle = `hsl(${node.hue}, 100%, 70%)`
ctx.shadowBlur = 15
ctx.shadowColor = `hsl(${node.hue}, 100%, 60%)`
ctx.beginPath()
ctx.arc(node.x, node.y, node.radius * pulse, 0, Math.PI * 2)
ctx.fill()
ctx.shadowBlur = 0
})
animationId = requestAnimationFrame(animate)
}
animate()
return () => {
window.removeEventListener("resize", updateSize)
cancelAnimationFrame(animationId)
}
}, [])
return (
<section className="py-24 px-4 relative overflow-hidden scan-lines">
<div className="absolute inset-0 cyber-grid opacity-10" />
<canvas ref={canvasRef} className="absolute inset-0 w-full h-full" />
<div className="relative max-w-4xl mx-auto text-center space-y-6 z-10">
<h2 className="text-3xl md:text-5xl font-bold text-balance glow-text text-primary">
{"Mycelial Intelligence"}
</h2>
<p className="text-lg md:text-xl text-accent leading-relaxed glow-text">
{
"Like mycelial networks that connect forest ecosystems, MycoFi creates living infrastructure for communities to share resources, make decisions, and evolve together. Each node strengthens the whole, enabling emergence of collective intelligence."
}
</p>
</div>
</section>
)
}