Import source: src/components/WaveSection/WaveSection
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -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 (
|
||||||
|
<instancedMesh ref={meshRef} args={[null, null, count]}>
|
||||||
|
<sphereGeometry args={[1, 6, 6]} />
|
||||||
|
<meshStandardMaterial color="#c9a84c" emissive="#c9a84c" emissiveIntensity={0.5} roughness={0.2} metalness={0.8} toneMapped={false} />
|
||||||
|
</instancedMesh>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function WaveSection() {
|
||||||
|
return (
|
||||||
|
<section className="relative overflow-hidden" style={{ background: '#050505', height: '500px' }}>
|
||||||
|
<div className="section-divider" />
|
||||||
|
|
||||||
|
<Canvas camera={{ position: [0, 6, 14], fov: 52, near: 0.1, far: 100 }} gl={{ antialias: true, alpha: false }}
|
||||||
|
style={{ background: 'transparent' }}>
|
||||||
|
<ambientLight intensity={0.1} />
|
||||||
|
<pointLight position={[0, 8, 4]} intensity={5} color="#c9a84c" />
|
||||||
|
<pointLight position={[-8, 4, 0]} intensity={2} color="#e8c547" />
|
||||||
|
<pointLight position={[8, 4, 0]} intensity={2} color="#8a6f2e" />
|
||||||
|
<WaveGrid />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
{/* Centered content overlay */}
|
||||||
|
<div className="absolute inset-0 flex flex-col items-center justify-center pointer-events-none">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
|
whileInView={{ opacity: 1, scale: 1 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
|
className="text-center glass-gold px-10 py-6 rounded-2xl"
|
||||||
|
style={{ border: '1px solid rgba(201,168,76,0.2)' }}
|
||||||
|
>
|
||||||
|
<p className="text-xs tracking-[0.3em] uppercase gold-text mb-2">Frequency Field</p>
|
||||||
|
<h2 className="font-display font-bold text-3xl md:text-4xl text-white">
|
||||||
|
Every Beat. <span className="gold-text">Visualized.</span>
|
||||||
|
</h2>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="absolute top-0 left-0 right-0 h-24 pointer-events-none" style={{ background: 'linear-gradient(to bottom, #0d0d0d, transparent)' }} />
|
||||||
|
<div className="absolute bottom-0 left-0 right-0 h-24 pointer-events-none" style={{ background: 'linear-gradient(to top, #080808, transparent)' }} />
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user