Import source: src/components/Player/Waveform3D
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,49 @@
|
|||||||
|
import { useRef, useMemo } from 'react'
|
||||||
|
import { Canvas, useFrame } from '@react-three/fiber'
|
||||||
|
import * as THREE from 'three'
|
||||||
|
|
||||||
|
const BAR_COUNT = 28
|
||||||
|
|
||||||
|
function Waveform({ isPlaying }) {
|
||||||
|
const barsRef = useRef([])
|
||||||
|
const phases = useMemo(() => Array.from({ length: BAR_COUNT }, () => Math.random() * Math.PI * 2), [])
|
||||||
|
|
||||||
|
useFrame(({ clock }) => {
|
||||||
|
const t = clock.getElapsedTime()
|
||||||
|
barsRef.current.forEach((mesh, i) => {
|
||||||
|
if (!mesh) return
|
||||||
|
const target = isPlaying
|
||||||
|
? Math.abs(Math.sin(t * 3.5 + phases[i])) * 0.7 + 0.04
|
||||||
|
: 0.04 + Math.abs(Math.sin(t * 0.4 + phases[i])) * 0.08
|
||||||
|
mesh.scale.y = THREE.MathUtils.lerp(mesh.scale.y, target, 0.18)
|
||||||
|
mesh.position.y = mesh.scale.y * 0.5
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group>
|
||||||
|
{Array.from({ length: BAR_COUNT }, (_, i) => (
|
||||||
|
<mesh
|
||||||
|
key={i}
|
||||||
|
ref={el => (barsRef.current[i] = el)}
|
||||||
|
position={[(i - BAR_COUNT / 2) * 0.075, 0.04, 0]}
|
||||||
|
>
|
||||||
|
<boxGeometry args={[0.05, 1, 0.05]} />
|
||||||
|
<meshBasicMaterial color={i % 2 === 0 ? '#c9a84c' : '#8a6f2e'} />
|
||||||
|
</mesh>
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Waveform3D({ isPlaying }) {
|
||||||
|
return (
|
||||||
|
<Canvas
|
||||||
|
camera={{ position: [0, 0.4, 2.2], fov: 45 }}
|
||||||
|
gl={{ alpha: true, antialias: false }}
|
||||||
|
style={{ background: 'transparent' }}
|
||||||
|
>
|
||||||
|
<Waveform isPlaying={isPlaying} />
|
||||||
|
</Canvas>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user