Initial commit
This commit is contained in:
110
assets/js/visualizer/scene.js
Normal file
110
assets/js/visualizer/scene.js
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 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;
|
||||
Reference in New Issue
Block a user