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.
+
+
+
+
+
+
+
+ )
+}