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