'use client' import { useEffect, useRef } from 'react' /* ─── Animated data stream (Track 1) ─── */ /* Compact flowing waveform + particles, self-contained */ export function StreamViz() { const canvasRef = useRef(null) useEffect(() => { const canvas = canvasRef.current if (!canvas) return const ctx = canvas.getContext('2d') if (!ctx) return const dpr = window.devicePixelRatio || 1 let w = 0, h = 0 const resize = () => { const rect = canvas.getBoundingClientRect() w = rect.width h = rect.height canvas.width = w * dpr canvas.height = h * dpr ctx.setTransform(dpr, 0, 0, dpr, 0, 0) } resize() const particles: { x: number; y: number; vy: number; size: number; alpha: number }[] = [] for (let i = 0; i < 30; i++) { particles.push({ x: Math.random() * 250, y: Math.random() * 300, vy: -0.2 - Math.random() * 0.5, size: 1 + Math.random() * 2, alpha: 0.15 + Math.random() * 0.35, }) } let t = 0 let animId: number const draw = () => { ctx.clearRect(0, 0, w, h) t += 0.02 // Flowing wave lines for (let line = 0; line < 4; line++) { ctx.beginPath() const baseY = h * 0.25 + line * (h * 0.15) for (let x = 0; x <= w; x += 2) { const y = baseY + Math.sin(x * 0.03 + t + line * 1.5) * 12 + Math.sin(x * 0.015 + t * 0.7) * 8 if (x === 0) ctx.moveTo(x, y) else ctx.lineTo(x, y) } ctx.strokeStyle = `rgba(217, 94, 42, ${0.06 + line * 0.03})` ctx.lineWidth = 1 ctx.stroke() } // Particles particles.forEach((p) => { ctx.beginPath() ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2) ctx.fillStyle = `rgba(217, 94, 42, ${p.alpha})` ctx.fill() p.y += p.vy if (p.y < -5) { p.y = h + 5; p.x = Math.random() * w } }) // Connections between close particles for (let i = 0; i < particles.length; i++) { for (let j = i + 1; j < particles.length; j++) { const dx = particles[i].x - particles[j].x const dy = particles[i].y - particles[j].y const dist = Math.sqrt(dx * dx + dy * dy) if (dist < 60) { ctx.beginPath() ctx.moveTo(particles[i].x, particles[i].y) ctx.lineTo(particles[j].x, particles[j].y) ctx.strokeStyle = `rgba(217, 94, 42, ${0.06 * (1 - dist / 60)})` ctx.lineWidth = 0.5 ctx.stroke() } } } animId = requestAnimationFrame(draw) } draw() window.addEventListener('resize', resize) return () => { cancelAnimationFrame(animId); window.removeEventListener('resize', resize) } }, []) return } /* ─── Pulsing lock with rings (Track 2) ─── */ export function SecureViz() { return (
{/* Pulsing rings */}
{/* Rotating orbit */} {/* Orbiting dots */}
{/* Center lock */}
) } /* ─── Floating code snippets (Track 3) ─── */ export function ExtendViz() { const snippets = [ { x: '10%', y: '12%', text: 'fn extend()', delay: '0s' }, { x: '45%', y: '8%', text: '', delay: '0.8s' }, { x: '20%', y: '45%', text: '.hook()', delay: '1.2s' }, { x: '55%', y: '42%', text: 'export', delay: '0.4s' }, { x: '15%', y: '75%', text: 'pipe()', delay: '1.6s' }, { x: '50%', y: '78%', text: 'import', delay: '0.6s' }, ] return (
{/* Radiating lines */} {[0, 45, 90, 135, 180, 225, 270, 315].map((angle) => { const rad = (angle * Math.PI) / 180 return ( ) })} {/* Floating snippets */} {snippets.map((s, i) => (
{s.text}
))} {/* Center node */}
) }