Files

208 lines
6.3 KiB
JavaScript

/**
* Cosmic Garden - Audio System
* Sound effects using Web Audio API (no external assets needed)
*/
const Audio = {
ctx: null,
/**
* Initialize audio context
*/
init() {
try {
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
} catch (e) {
console.log('Web Audio API not supported');
}
},
/**
* Resume audio context (needed for some browsers)
*/
resume() {
if (this.ctx && this.ctx.state === 'suspended') {
this.ctx.resume();
}
},
/**
* Play click sound - rising C-major arpeggio
*/
playClick() {
if (!this.ctx) return;
this.resume();
const now = this.ctx.currentTime;
const notes = [523.25, 659.25, 783.99]; // C5, E5, G5
notes.forEach((freq, i) => {
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.frequency.value = freq;
osc.type = 'sine';
gain.gain.setValueAtTime(0.1, now + i * 0.05);
gain.gain.exponentialRampToValueAtTime(0.01, now + i * 0.05 + 0.15);
osc.start(now + i * 0.05);
osc.stop(now + i * 0.05 + 0.15);
});
},
/**
* Play purchase sound - descending chime
*/
playPurchase() {
if (!this.ctx) return;
this.resume();
const now = this.ctx.currentTime;
const notes = [783.99, 659.25, 523.25]; // G5, E5, C5
notes.forEach((freq, i) => {
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.frequency.value = freq;
osc.type = 'triangle';
gain.gain.setValueAtTime(0.15, now + i * 0.08);
gain.gain.exponentialRampToValueAtTime(0.01, now + i * 0.08 + 0.2);
osc.start(now + i * 0.08);
osc.stop(now + i * 0.08 + 0.2);
});
},
/**
* Play achievement sound - ascending chord fanfare
*/
playAchievement() {
if (!this.ctx) return;
this.resume();
const now = this.ctx.currentTime;
const chords = [
[523.25, 659.25, 783.99], // C major
[659.25, 783.99, 987.77], // E major
[783.99, 987.77, 1174.66] // G major
];
chords.forEach((chord, chordIndex) => {
chord.forEach(freq => {
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.frequency.value = freq;
osc.type = 'sine';
const startTime = now + chordIndex * 0.15;
gain.gain.setValueAtTime(0.12, startTime);
gain.gain.exponentialRampToValueAtTime(0.01, startTime + 0.3);
osc.start(startTime);
osc.stop(startTime + 0.3);
});
});
},
/**
* Play prestige sound - ethereal whoosh
*/
playPrestige() {
if (!this.ctx) return;
this.resume();
const now = this.ctx.currentTime;
// Rising sweep
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.type = 'sine';
osc.frequency.setValueAtTime(200, now);
osc.frequency.exponentialRampToValueAtTime(800, now + 0.5);
gain.gain.setValueAtTime(0.2, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.8);
osc.start(now);
osc.stop(now + 0.8);
// Sparkle overlay
for (let i = 0; i < 5; i++) {
const sparkle = this.ctx.createOscillator();
const sparkleGain = this.ctx.createGain();
sparkle.connect(sparkleGain);
sparkleGain.connect(this.ctx.destination);
sparkle.frequency.value = 1200 + Math.random() * 800;
sparkle.type = 'sine';
const startTime = now + 0.1 + i * 0.1;
sparkleGain.gain.setValueAtTime(0.08, startTime);
sparkleGain.gain.exponentialRampToValueAtTime(0.01, startTime + 0.2);
sparkle.start(startTime);
sparkle.stop(startTime + 0.2);
}
},
/**
* Play golden starbloom sound - an ethereal shimmering arpeggio with a
* rising sweep, to distinguish it from regular purchase sounds.
*/
playGoldenBloom() {
if (!this.ctx) return;
this.resume();
const now = this.ctx.currentTime;
// Rising magical sweep (like the prestige sound but brighter).
const sweep = this.ctx.createOscillator();
const sweepGain = this.ctx.createGain();
sweep.connect(sweepGain);
sweepGain.connect(this.ctx.destination);
sweep.type = 'sine';
sweep.frequency.setValueAtTime(300, now);
sweep.frequency.exponentialRampToValueAtTime(1200, now + 0.6);
sweepGain.gain.setValueAtTime(0.18, now);
sweepGain.gain.exponentialRampToValueAtTime(0.01, now + 0.7);
sweep.start(now);
sweep.stop(now + 0.7);
// A bright, ascending shimmer chord played quickly.
const shimmerNotes = [1046.5, 1318.5, 1568.0, 2093.0]; // C5, E5, G5, C6
shimmerNotes.forEach((freq, i) => {
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.frequency.value = freq;
osc.type = 'triangle';
const startTime = now + 0.05 + i * 0.06;
gain.gain.setValueAtTime(0.1, startTime);
gain.gain.exponentialRampToValueAtTime(0.01, startTime + 0.25);
osc.start(startTime);
osc.stop(startTime + 0.25);
});
}
};
window.Audio = Audio;