111 lines
2.4 KiB
JavaScript
111 lines
2.4 KiB
JavaScript
/**
|
|
* WebGL Visualizer Scene
|
|
* Three.js particle system that reacts to audio frequency data
|
|
*/
|
|
|
|
import * as THREE from 'three';
|
|
import { ParticleSystem } from './particles.js';
|
|
|
|
export class Visualizer {
|
|
constructor(canvas, audioManager) {
|
|
this.canvas = canvas;
|
|
this.audioManager = audioManager;
|
|
this.running = false;
|
|
this.time = 0;
|
|
|
|
if (!canvas) {
|
|
console.warn('Visualizer: No canvas provided');
|
|
return;
|
|
}
|
|
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
// Scene setup
|
|
this.scene = new THREE.Scene();
|
|
|
|
// Camera
|
|
this.camera = new THREE.PerspectiveCamera(
|
|
75,
|
|
window.innerWidth / window.innerHeight,
|
|
0.1,
|
|
1000
|
|
);
|
|
this.camera.position.z = 50;
|
|
|
|
// Renderer
|
|
this.renderer = new THREE.WebGLRenderer({
|
|
canvas: this.canvas,
|
|
alpha: true,
|
|
antialias: true,
|
|
powerPreference: 'high-performance'
|
|
});
|
|
this.renderer.setSize(window.innerWidth, window.innerHeight);
|
|
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
|
|
// Particles
|
|
this.particles = new ParticleSystem(5000);
|
|
this.scene.add(this.particles.mesh);
|
|
|
|
// Event listeners
|
|
window.addEventListener('resize', () => this.resize());
|
|
|
|
// Start animation
|
|
this.start();
|
|
}
|
|
|
|
resize() {
|
|
if (!this.camera || !this.renderer) return;
|
|
|
|
this.camera.aspect = window.innerWidth / window.innerHeight;
|
|
this.camera.updateProjectionMatrix();
|
|
this.renderer.setSize(window.innerWidth, window.innerHeight);
|
|
}
|
|
|
|
start() {
|
|
if (this.running) return;
|
|
this.running = true;
|
|
this.animate();
|
|
}
|
|
|
|
pause() {
|
|
this.running = false;
|
|
}
|
|
|
|
resume() {
|
|
this.start();
|
|
}
|
|
|
|
animate() {
|
|
if (!this.running) return;
|
|
requestAnimationFrame(() => this.animate());
|
|
|
|
this.time += 0.01;
|
|
|
|
// Get audio frequency bands
|
|
let bands = { low: 0, mid: 0, high: 0 };
|
|
if (this.audioManager?.isInitialized) {
|
|
bands = this.audioManager.getFrequencyBands();
|
|
}
|
|
|
|
// Update particles with audio data
|
|
this.particles.update(bands, this.time);
|
|
|
|
// Subtle camera movement
|
|
this.camera.position.x = Math.sin(this.time * 0.1) * 3;
|
|
this.camera.position.y = Math.cos(this.time * 0.15) * 2;
|
|
this.camera.lookAt(0, 0, 0);
|
|
|
|
this.renderer.render(this.scene, this.camera);
|
|
}
|
|
|
|
destroy() {
|
|
this.running = false;
|
|
this.particles?.dispose();
|
|
this.renderer?.dispose();
|
|
}
|
|
}
|
|
|
|
export default Visualizer;
|