diff --git a/src/components/WaveSection/WaveSection.jsx b/src/components/WaveSection/WaveSection.jsx new file mode 100644 index 0000000..ada4366 --- /dev/null +++ b/src/components/WaveSection/WaveSection.jsx @@ -0,0 +1,88 @@ +import { useRef, useMemo } from 'react' +import { Canvas, useFrame } from '@react-three/fiber' +import { motion } from 'framer-motion' +import * as THREE from 'three' + +const COLS = 80 +const ROWS = 30 + +function WaveGrid({ isPlaying }) { + const meshRef = useRef() + const dummy = useMemo(() => new THREE.Object3D(), []) + + const count = COLS * ROWS + + const basePositions = useMemo(() => { + const pos = [] + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + pos.push({ + x: (c - COLS / 2) * 0.38, + z: (r - ROWS / 2) * 0.55, + phase: (c * 0.25 + r * 0.4), + }) + } + } + return pos + }, []) + + useFrame(({ clock }) => { + if (!meshRef.current) return + const t = clock.getElapsedTime() + basePositions.forEach((p, i) => { + const wave1 = Math.sin(p.phase + t * 1.4) * 0.9 + const wave2 = Math.sin(p.phase * 0.7 + t * 0.9 + 1.5) * 0.5 + const y = wave1 + wave2 + const scale = 0.04 + Math.abs(y) * 0.06 + dummy.position.set(p.x, y * 0.6, p.z) + dummy.scale.setScalar(scale) + dummy.updateMatrix() + meshRef.current.setMatrixAt(i, dummy.matrix) + }) + meshRef.current.instanceMatrix.needsUpdate = true + }) + + return ( + + + + + ) +} + +export default function WaveSection() { + return ( +
+
+ + + + + + + + + + {/* Centered content overlay */} +
+ +

Frequency Field

+

+ Every Beat. Visualized. +

+
+
+ +
+
+
+ ) +}