// @ts-nocheck import { useRef, useMemo, useEffect } from 'react'; import { Canvas, useFrame, useThree } from '@react-three/fiber'; import * as THREE from 'three'; const BOARD_SIZE = 200; const GRID_DIVISIONS = 16; const JUNCTION_SPACING = BOARD_SIZE / GRID_DIVISIONS; const HALF_BOARD = BOARD_SIZE / 2; const ORB_COUNT = 20; const PULSE_COUNT = 10; interface Junction { x: number; z: number; connections: number[]; } interface Trace { start: number; end: number; } interface ParticleData { pos: THREE.Vector3; target: THREE.Vector3; junctionIndex: number; targetJunctionIndex: number; progress: number; speed: number; type: 'orb' | 'pulse'; } function seededRandom(seed: number): () => number { let s = seed; return () => { s = (s * 9301 + 49297) % 233280; return s / 233280; }; } function createGlowTexture(color: string): THREE.CanvasTexture { const canvas = document.createElement('canvas'); canvas.width = 64; canvas.height = 64; const ctx = canvas.getContext('2d')!; const gradient = ctx.createRadialGradient(32, 32, 0, 32, 32, 32); gradient.addColorStop(0, color); gradient.addColorStop(0.3, color.replace(')', ', 0.8)').replace('rgb', 'rgba')); gradient.addColorStop(0.6, color.replace(')', ', 0.3)').replace('rgb', 'rgba')); gradient.addColorStop(1, 'rgba(0,0,0,0)'); ctx.fillStyle = gradient; ctx.fillRect(0, 0, 64, 64); return new THREE.CanvasTexture(canvas); } function generateBoardData() { const rand = seededRandom(42); const junctions: Junction[] = []; const indexMap: Map = new Map(); for (let gx = 0; gx <= GRID_DIVISIONS; gx++) { for (let gz = 0; gz <= GRID_DIVISIONS; gz++) { const x = -HALF_BOARD + gx * JUNCTION_SPACING; const z = -HALF_BOARD + gz * JUNCTION_SPACING; const idx = junctions.length; junctions.push({ x, z, connections: [] }); indexMap.set(`${gx},${gz}`, idx); } } for (let gx = 0; gx <= GRID_DIVISIONS; gx++) { for (let gz = 0; gz <= GRID_DIVISIONS; gz++) { const idx = indexMap.get(`${gx},${gz}`); if (idx === undefined) continue; if (gx < GRID_DIVISIONS) { const rightIdx = indexMap.get(`${gx + 1},${gz}`); if (rightIdx !== undefined) { junctions[idx].connections.push(rightIdx); junctions[rightIdx].connections.push(idx); } } if (gz < GRID_DIVISIONS) { const downIdx = indexMap.get(`${gx},${gz + 1}`); if (downIdx !== undefined) { junctions[idx].connections.push(downIdx); junctions[downIdx].connections.push(idx); } } if (gx < GRID_DIVISIONS && gz < GRID_DIVISIONS && rand() > 0.85) { const diagIdx = indexMap.get(`${gx + 1},${gz + 1}`); if (diagIdx !== undefined) { junctions[idx].connections.push(diagIdx); junctions[diagIdx].connections.push(idx); } } } } const traceSet = new Set(); const traces: Trace[] = []; for (const j of junctions) { const jIdx = junctions.indexOf(j); for (const c of j.connections) { const key = j.x < junctions[c].x || (j.x === junctions[c].x && j.z <= junctions[c].z) ? `${jIdx},${c}` : `${c},${jIdx}`; if (!traceSet.has(key)) { traceSet.add(key); traces.push({ start: jIdx, end: c }); } } } const chips: Array<{ x: number; z: number; width: number; depth: number }> = []; const usedIndices = new Set(); for (let i = 0; i < 22; i++) { let attempts = 0; while (attempts < 50) { const idx = Math.floor(rand() * junctions.length); if (!usedIndices.has(idx) && junctions[idx].connections.length >= 2) { usedIndices.add(idx); chips.push({ x: junctions[idx].x, z: junctions[idx].z, width: 5 + rand() * 7, depth: 5 + rand() * 7, }); break; } attempts++; } } const capacitors: Array<{ x: number; z: number; radius: number; height: number }> = []; for (let i = 0; i < 45; i++) { const idx = Math.floor(rand() * junctions.length); capacitors.push({ x: junctions[idx].x + (rand() - 0.5) * 3, z: junctions[idx].z + (rand() - 0.5) * 3, radius: 0.35 + rand() * 0.45, height: 1.2 + rand() * 2.2, }); } const ics: Array<{ x: number; z: number; width: number; depth: number }> = []; const icCandidates = junctions.filter(j => j.connections.length > 2); for (let i = 0; i < Math.min(16, icCandidates.length); i++) { const j = icCandidates[i]; ics.push({ x: j.x, z: j.z, width: 10 + rand() * 6, depth: 6 + rand() * 4, }); } return { junctions, traces, chips, capacitors, ics }; } function TraceLines({ traces, junctions }: { traces: Trace[]; junctions: Junction[] }) { const geometry = useMemo(() => { const positions: number[] = []; for (const t of traces) { const start = junctions[t.start]; const end = junctions[t.end]; positions.push(start.x, 0.1, start.z); positions.push(end.x, 0.1, end.z); } const geo = new THREE.BufferGeometry(); geo.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); return geo; }, [traces, junctions]); return ( ); } function Chips({ chips }: { chips: Array<{ x: number; z: number; width: number; depth: number }> }) { return ( {chips.map((chip, i) => ( {[-1, 1].map((side) => Array.from({ length: Math.floor(chip.width / 1.2) }).map((_, pi) => ( )) )} {[-1, 1].map((side) => Array.from({ length: Math.floor(chip.depth / 1.2) }).map((_, pi) => ( )) )} ))} ); } function Capacitors({ capacitors }: { capacitors: Array<{ x: number; z: number; radius: number; height: number }> }) { return ( {capacitors.map((cap, i) => ( ))} ); } function ICs({ ics }: { ics: Array<{ x: number; z: number; width: number; depth: number }> }) { return ( {ics.map((ic, i) => ( ))} ); } function ParticleSystem({ junctions }: { junctions: Junction[] }) { const orbRefs = useRef<(THREE.Mesh | null)[]>([]); const pulseRefs = useRef<(THREE.Mesh | null)[]>([]); const particles = useRef([]); const initialized = useRef(false); const glowTexture = useMemo(() => createGlowTexture('rgb(0, 255, 68)'), []); const pulseGlowTexture = useMemo(() => createGlowTexture('rgb(0, 255, 255)'), []); useEffect(() => { if (initialized.current) return; initialized.current = true; const rand = seededRandom(Date.now()); const initial: ParticleData[] = []; for (let i = 0; i < ORB_COUNT; i++) { const idx = Math.floor(rand() * junctions.length); const conn = junctions[idx].connections; const target = conn.length > 0 ? conn[Math.floor(rand() * conn.length)] : idx; initial.push({ pos: new THREE.Vector3(junctions[idx].x, 0.4, junctions[idx].z), target: new THREE.Vector3(junctions[target].x, 0.4, junctions[target].z), junctionIndex: idx, targetJunctionIndex: target, progress: rand(), speed: 0.002 + rand() * 0.003, type: 'orb', }); } for (let i = 0; i < PULSE_COUNT; i++) { const idx = Math.floor(rand() * junctions.length); const conn = junctions[idx].connections; const target = conn.length > 0 ? conn[Math.floor(rand() * conn.length)] : idx; initial.push({ pos: new THREE.Vector3(junctions[idx].x, 0.4, junctions[idx].z), target: new THREE.Vector3(junctions[target].x, 0.4, junctions[target].z), junctionIndex: idx, targetJunctionIndex: target, progress: rand(), speed: 0.01 + rand() * 0.015, type: 'pulse', }); } particles.current = initial; }, [junctions]); useFrame(() => { const p = particles.current; if (!p.length) return; for (let i = 0; i < p.length; i++) { const particle = p[i]; particle.progress += particle.speed; if (particle.progress >= 1) { const conn = junctions[particle.junctionIndex].connections; if (conn.length > 0) { particle.junctionIndex = particle.targetJunctionIndex; const nextConn = junctions[particle.targetJunctionIndex].connections.filter(c => c !== particle.junctionIndex); particle.targetJunctionIndex = nextConn.length > 0 ? nextConn[Math.floor(Math.random() * nextConn.length)] : conn[Math.floor(Math.random() * conn.length)]; particle.progress = 0; particle.target.set( junctions[particle.targetJunctionIndex].x, 0.4, junctions[particle.targetJunctionIndex].z ); } else { particle.progress = 0; } } const startJ = junctions[particle.junctionIndex]; particle.pos.x = startJ.x + (particle.target.x - startJ.x) * particle.progress; particle.pos.z = startJ.z + (particle.target.z - startJ.z) * particle.progress; particle.pos.y = 0.4 + Math.sin(particle.progress * Math.PI) * 0.6; if (particle.type === 'orb') { const mesh = orbRefs.current[i]; if (mesh) { mesh.position.copy(particle.pos); } } else { const mesh = pulseRefs.current[i - ORB_COUNT]; if (mesh) { mesh.position.copy(particle.pos); const scale = 1 - Math.abs(particle.progress - 0.5) * 2; mesh.scale.setScalar(0.4 + scale * 0.6); (mesh.material as THREE.MeshStandardMaterial).emissiveIntensity = 2 + scale * 4; } } } }); return ( {Array.from({ length: ORB_COUNT }).map((_, i) => ( { orbRefs.current[i] = el; }} > ))} {Array.from({ length: PULSE_COUNT }).map((_, i) => ( { pulseRefs.current[i] = el; }} rotation={[-Math.PI / 2, 0, 0]} > ))} ); } function CameraDrift() { const { camera } = useThree(); const timeRef = useRef(0); useFrame((_, delta) => { timeRef.current += delta; const t = timeRef.current; camera.position.x = Math.sin(t * 0.05) * 3; camera.position.y = 80 + Math.sin(t * 0.07) * 2.5; camera.position.z = Math.cos(t * 0.04) * 5; camera.lookAt(0, 0, 0); }); return null; } function Scene() { const boardData = useMemo(() => generateBoardData(), []); return ( <> ); } export default function GadgetGrid() { return (
); }