"use client"; import { useEffect, useRef } from "react"; export function GateScene() { const canvasRef = useRef(null); const mouse = useRef({ x: -1000, y: -1000 }); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext("2d"); if (!ctx) return; const FONT_SIZE = 13; const COL_GAP = 18; const ROW_GAP = 20; interface Cell { char: string; alpha: number; targetAlpha: number; speed: number; nextChange: number; } let cells: Cell[][] = []; let cols = 0; let rows = 0; let animId: number; const init = () => { cols = Math.ceil(canvas.width / COL_GAP); rows = Math.ceil(canvas.height / ROW_GAP); cells = Array.from({ length: cols }, () => Array.from({ length: rows }, () => ({ char: Math.random() > 0.5 ? "1" : "0", alpha: Math.random() * 0.08, targetAlpha: Math.random() * 0.15, speed: 0.008 + Math.random() * 0.02, nextChange: Math.floor(Math.random() * 80), })), ); }; const onMouseMove = (e: MouseEvent) => { mouse.current = { x: e.clientX, y: e.clientY }; }; const resize = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; init(); }; let frame = 0; const draw = () => { frame++; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.font = `${FONT_SIZE}px 'Courier New', monospace`; for (let c = 0; c < cols; c++) { for (let r = 0; r < rows; r++) { const cell = cells[c][r]; const x = c * COL_GAP; const y = r * ROW_GAP + FONT_SIZE; // Mouse proximity influence const dx = mouse.current.x - x; const dy = mouse.current.y - y; const distSq = dx * dx + dy * dy; const proximity = Math.max(0, 1 - Math.sqrt(distSq) / 250); // Nudge alpha toward target cell.alpha += (cell.targetAlpha - cell.alpha) * cell.speed; // More aggressive random behavior if (frame >= cell.nextChange) { cell.targetAlpha = Math.random() * 0.25; // Higher max alpha cell.speed = 0.01 + Math.random() * 0.03; // Faster transitions cell.nextChange = frame + 20 + Math.floor(Math.random() * 80); // More frequent changes // Higher flip probability near mouse const flipProb = 0.3 + proximity * 0.5; if (Math.random() < flipProb) { cell.char = cell.char === "0" ? "1" : "0"; } } const a = Math.min(0.4, cell.alpha + proximity * 0.35); if (a < 0.01) continue; // Dark chars on light background ctx.fillStyle = `rgba(0, 0, 0, ${a})`; ctx.fillText(cell.char, x, y); } } animId = requestAnimationFrame(draw); }; resize(); window.addEventListener("resize", resize); window.addEventListener("mousemove", onMouseMove); animId = requestAnimationFrame(draw); return () => { cancelAnimationFrame(animId); window.removeEventListener("resize", resize); window.removeEventListener("mousemove", onMouseMove); }; }, []); return (
); }