/** * Cosmic Garden - Audio System * Web Audio API-based sound generation (no external assets needed) */ const Audio = { ctx: null, enabled: true, /** * Initialize audio context (must be called after user interaction) */ init() { try { window.AudioContext = window.AudioContext || window.webkitAudioContext; this.ctx = new AudioContext(); console.log('🔊 Audio system initialized'); } catch (e) { console.warn('Web Audio API not supported'); this.enabled = false; } }, /** * Resume audio context (for browsers that suspend it) */ resume() { if (this.ctx && this.ctx.state === 'suspended') { this.ctx.resume(); } }, /** * Create a simple tone */ playTone(frequency, duration, type = 'sine', volume = 0.1) { if (!this.enabled || !this.ctx) return; const osc = this.ctx.createOscillator(); const gain = this.ctx.createGain(); osc.type = type; osc.frequency.setValueAtTime(frequency, this.ctx.currentTime); gain.gain.setValueAtTime(volume, this.ctx.currentTime); gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + duration); osc.connect(gain); gain.connect(this.ctx.destination); osc.start(this.ctx.currentTime); osc.stop(this.ctx.currentTime + duration); }, /** * Play a rising arpeggio (for clicks) */ playClick() { if (!this.enabled) return; this.resume(); const now = this.ctx.currentTime; const notes = [523.25, 659.25, 783.99]; // C major chord notes.forEach((freq, i) => { setTimeout(() => { this.playTone(freq, 0.1, 'sine', 0.08); }, i * 30); }); }, /** * Play a purchase sound (descending chime) */ playPurchase() { if (!this.enabled) return; this.resume(); const notes = [783.99, 659.25, 523.25]; // G - E - C notes.forEach((freq, i) => { setTimeout(() => { this.playTone(freq, 0.15, 'triangle', 0.1); }, i * 50); }); }, /** * Play an achievement unlock fanfare */ playAchievement() { if (!this.enabled) return; this.resume(); const notes = [523.25, 659.25, 783.99, 1046.50]; // C - E - G - C (high) notes.forEach((freq, i) => { setTimeout(() => { this.playTone(freq, 0.2, 'square', 0.06); }, i * 80); }); }, /** * Play a notification sound */ playNotification() { if (!this.enabled) return; this.resume(); this.playTone(880, 0.1, 'sine', 0.08); setTimeout(() => { this.playTone(1100, 0.15, 'sine', 0.08); }, 100); } }; // Make globally accessible window.Audio = Audio;