144 lines
4.5 KiB
TypeScript
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>
|
|
)
|
|
}
|