Import source: src/components/Hero/AudioVisualizer3D
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,92 @@
|
|||||||
|
import { useRef, useMemo } from 'react'
|
||||||
|
import { Canvas, useFrame } from '@react-three/fiber'
|
||||||
|
import * as THREE from 'three'
|
||||||
|
|
||||||
|
const BAR_COUNT = 80
|
||||||
|
|
||||||
|
function Bars({ isPlaying }) {
|
||||||
|
const barsRef = useRef([])
|
||||||
|
const phases = useMemo(() => Array.from({ length: BAR_COUNT }, () => Math.random() * Math.PI * 2), [])
|
||||||
|
const speeds = useMemo(() => Array.from({ length: BAR_COUNT }, () => 0.5 + Math.random() * 1.6), [])
|
||||||
|
|
||||||
|
useFrame(({ clock }, delta) => {
|
||||||
|
const t = clock.getElapsedTime()
|
||||||
|
barsRef.current.forEach((mesh, i) => {
|
||||||
|
if (!mesh) return
|
||||||
|
const target = isPlaying
|
||||||
|
? Math.abs(Math.sin(t * speeds[i] + phases[i])) * 2.4 + 0.06
|
||||||
|
: Math.abs(Math.sin(t * 0.22 + phases[i])) * 0.28 + 0.04
|
||||||
|
mesh.scale.y = THREE.MathUtils.lerp(mesh.scale.y, target, 0.09)
|
||||||
|
mesh.position.y = mesh.scale.y * 0.5
|
||||||
|
// Subtle colour shift along ring
|
||||||
|
const hue = 0.12 + (i / BAR_COUNT) * 0.04
|
||||||
|
mesh.material.emissiveIntensity = 0.5 + mesh.scale.y * 0.25
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const positions = useMemo(() => {
|
||||||
|
const r = 3.4
|
||||||
|
return Array.from({ length: BAR_COUNT }, (_, i) => {
|
||||||
|
const a = (i / BAR_COUNT) * Math.PI * 2
|
||||||
|
return { x: Math.cos(a) * r, z: Math.sin(a) * r }
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group rotation={[0.18, 0, 0]}>
|
||||||
|
{positions.map((p, i) => (
|
||||||
|
<mesh key={i} ref={el => (barsRef.current[i] = el)} position={[p.x, 0.5, p.z]}>
|
||||||
|
<boxGeometry args={[0.06, 1, 0.06]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color="#c9a84c" emissive="#c9a84c" emissiveIntensity={0.55}
|
||||||
|
roughness={0.15} metalness={0.95} toneMapped={false}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Outer ring */}
|
||||||
|
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.03, 0]}>
|
||||||
|
<ringGeometry args={[3.15, 3.65, 80]} />
|
||||||
|
<meshBasicMaterial color="#c9a84c" transparent opacity={0.08} side={THREE.DoubleSide} />
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
{/* Inner ring */}
|
||||||
|
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.03, 0]}>
|
||||||
|
<ringGeometry args={[1.1, 1.25, 64]} />
|
||||||
|
<meshBasicMaterial color="#e8c547" transparent opacity={0.1} side={THREE.DoubleSide} />
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
{/* Centre glow disc */}
|
||||||
|
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.03, 0]}>
|
||||||
|
<circleGeometry args={[1.1, 64]} />
|
||||||
|
<meshBasicMaterial color="#c9a84c" transparent opacity={0.03} />
|
||||||
|
</mesh>
|
||||||
|
</group>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Scene({ isPlaying }) {
|
||||||
|
const groupRef = useRef()
|
||||||
|
useFrame((_, delta) => {
|
||||||
|
if (groupRef.current) groupRef.current.rotation.y += delta * (isPlaying ? 0.38 : 0.07)
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
<group ref={groupRef}>
|
||||||
|
<Bars isPlaying={isPlaying} />
|
||||||
|
</group>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AudioVisualizer3D({ isPlaying }) {
|
||||||
|
return (
|
||||||
|
<Canvas camera={{ position: [0, 3.8, 9.5], fov: 46 }} gl={{ antialias: true, alpha: true }}
|
||||||
|
style={{ background: 'transparent' }}>
|
||||||
|
<ambientLight intensity={0.08} />
|
||||||
|
<pointLight position={[0, 7, 0]} intensity={5} color="#c9a84c" />
|
||||||
|
<pointLight position={[5, 2, 5]} intensity={2.5} color="#e8c547" />
|
||||||
|
<pointLight position={[-5, 1, -5]} intensity={1.5} color="#8a6f2e" />
|
||||||
|
<pointLight position={[0, -4, 0]} intensity={1} color="#c9a84c" />
|
||||||
|
<Scene isPlaying={isPlaying} />
|
||||||
|
</Canvas>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user