Add certificate template, shield logo, audio tracks, and enhance game UI/UX

This commit is contained in:
Vishva
2026-09-26 18:07:22 +05:30
parent db6840b870
commit 0f555fdb17
13 changed files with 2603 additions and 787 deletions
+259
View File
@@ -25,6 +25,22 @@ class SoundEngine {
this.activeGrinderNode = null;
this.activeLiquidNode = null;
// Dedicated Countdown Tick Sound Clip (User uploaded custom audio)
try {
this.countdownTickAudio = new Audio('audio/countdown_tick.mp3');
this.countdownTickAudio.preload = 'auto';
} catch (e) {
this.countdownTickAudio = null;
}
// Dedicated Top Timer Last 10-Second Warning Sound Clip (User uploaded custom audio)
try {
this.timerLast10sAudio = new Audio('audio/timer_last_10s.wav');
this.timerLast10sAudio.preload = 'auto';
} catch (e) {
this.timerLast10sAudio = null;
}
this.isInitialized = false;
}
@@ -91,6 +107,12 @@ class SoundEngine {
if (this.masterGain && this.ctx) {
this.masterGain.gain.setTargetAtTime(this.isMuted ? 0 : 1.0, this.ctx.currentTime, 0.05);
}
if (this.countdownTickAudio) {
this.countdownTickAudio.volume = this.isMuted ? 0 : this.sfxVolume;
}
if (this.timerLast10sAudio) {
this.timerLast10sAudio.volume = this.isMuted ? 0 : this.sfxVolume;
}
}
setMusicVolume(val) {
@@ -105,6 +127,94 @@ class SoundEngine {
if (this.sfxGain && this.ctx) {
this.sfxGain.gain.setTargetAtTime(this.sfxVolume, this.ctx.currentTime, 0.05);
}
if (this.countdownTickAudio) {
this.countdownTickAudio.volume = this.isMuted ? 0 : this.sfxVolume;
}
if (this.timerLast10sAudio) {
this.timerLast10sAudio.volume = this.isMuted ? 0 : this.sfxVolume;
}
}
playCountdownTickAudio() {
this.ensureContext();
if (this.isMuted) return;
if (this.countdownTickAudio) {
try {
const sound = this.countdownTickAudio.cloneNode();
sound.volume = Math.max(0, Math.min(1, this.sfxVolume));
sound.play().catch(err => {
console.warn("Countdown tick audio playback note:", err);
});
} catch (e) {
try {
this.countdownTickAudio.currentTime = 0;
this.countdownTickAudio.volume = Math.max(0, Math.min(1, this.sfxVolume));
this.countdownTickAudio.play().catch(() => {});
} catch (err) {}
}
}
}
/**
* Normal Clock Tick for the first 20 seconds (30s down to 11s)
*/
playTimerTick() {
this.ensureContext();
if (!this.ctx || this.isMuted) return;
const t = this.ctx.currentTime;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
const filter = this.ctx.createBiquadFilter();
// Crisp high-tech clock tick matching 1st beat
osc.type = 'triangle';
osc.frequency.setValueAtTime(1100, t);
osc.frequency.exponentialRampToValueAtTime(320, t + 0.035);
filter.type = 'bandpass';
filter.frequency.setValueAtTime(1200, t);
filter.Q.setValueAtTime(3.5, t);
gain.gain.setValueAtTime(0.22, t);
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.045);
osc.connect(filter);
filter.connect(gain);
gain.connect(this.sfxGain);
osc.start(t);
osc.stop(t + 0.05);
}
/**
* Dedicated Last 10 Seconds Audio Track (User uploaded custom audio)
*/
playTimerLast10sAudio() {
this.ensureContext();
if (this.isMuted) return;
if (this.timerLast10sAudio) {
try {
this.timerLast10sAudio.currentTime = 0;
this.timerLast10sAudio.volume = Math.max(0, Math.min(1, this.sfxVolume));
this.timerLast10sAudio.play().catch(err => {
console.warn("Timer last 10s audio playback note:", err);
});
} catch (e) {
console.warn("Error playing timer last 10s audio:", e);
}
}
}
stopTimerLast10sAudio() {
if (this.timerLast10sAudio) {
try {
this.timerLast10sAudio.pause();
this.timerLast10sAudio.currentTime = 0;
} catch (e) {}
}
}
setAmbientEnabled(enabled) {
@@ -520,6 +630,155 @@ class SoundEngine {
});
}
/**
* Timer Warning Tick & Urgent Countdown Beep SFX
*/
playTimerWarningTick(isUrgent = false) {
this.ensureContext();
if (!this.ctx || this.isMuted) return;
const t = this.ctx.currentTime;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
const filter = this.ctx.createBiquadFilter();
if (isUrgent) {
// Rapid, tense dual-tone hazard emergency beep
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(880, t);
osc.frequency.setValueAtTime(700, t + 0.06);
filter.type = 'bandpass';
filter.frequency.setValueAtTime(1400, t);
filter.Q.setValueAtTime(4.0, t);
gain.gain.setValueAtTime(0.22, t);
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.14);
osc.connect(filter);
filter.connect(gain);
gain.connect(this.sfxGain);
osc.start(t);
osc.stop(t + 0.15);
} else {
// High-tech warning clock tick
osc.type = 'sine';
osc.frequency.setValueAtTime(560, t);
osc.frequency.exponentialRampToValueAtTime(420, t + 0.05);
gain.gain.setValueAtTime(0.12, t);
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.08);
osc.connect(gain);
gain.connect(this.sfxGain);
osc.start(t);
osc.stop(t + 0.09);
}
}
/**
* Industrial Emergency Hazard Alarm Sound (Time Expired / Hazard Warning)
*/
playTimerHazardAlarm() {
this.ensureContext();
if (!this.ctx || this.isMuted) return;
const t = this.ctx.currentTime;
// Industrial emergency hazard klaxon / buzzer burst
[0, 0.18, 0.36].forEach(offset => {
const time = t + offset;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
const filter = this.ctx.createBiquadFilter();
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(620, time);
osc.frequency.linearRampToValueAtTime(380, time + 0.14);
filter.type = 'lowpass';
filter.frequency.setValueAtTime(2000, time);
gain.gain.setValueAtTime(0.26, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + 0.15);
osc.connect(filter);
filter.connect(gain);
gain.connect(this.sfxGain);
osc.start(time);
osc.stop(time + 0.16);
});
}
/**
* Central Screen Start Countdown Beep (3, 2, 1)
*/
playCountdownBeep(num) {
this.ensureContext();
if (!this.ctx || this.isMuted) return;
const t = this.ctx.currentTime;
const osc = this.ctx.createOscillator();
const osc2 = this.ctx.createOscillator();
const gain = this.ctx.createGain();
const filter = this.ctx.createBiquadFilter();
// Pitch rises: 3 (520Hz) -> 2 (680Hz) -> 1 (880Hz)
const baseFreq = num === 3 ? 520 : (num === 2 ? 680 : 880);
osc.type = 'triangle';
osc.frequency.setValueAtTime(baseFreq, t);
osc2.type = 'sine';
osc2.frequency.setValueAtTime(baseFreq * 2, t);
filter.type = 'lowpass';
filter.frequency.setValueAtTime(2400, t);
gain.gain.setValueAtTime(0.24, t);
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.28);
osc.connect(filter);
osc2.connect(filter);
filter.connect(gain);
gain.connect(this.sfxGain);
osc.start(t);
osc2.start(t);
osc.stop(t + 0.3);
osc2.stop(t + 0.3);
}
/**
* Central Screen Countdown Launch / GO! Chime
*/
playCountdownGo() {
this.ensureContext();
if (!this.ctx || this.isMuted) return;
const t = this.ctx.currentTime;
// Energetic ascending triad (C5 -> E5 -> G5)
[523.25, 659.25, 783.99, 1046.50].forEach((freq, idx) => {
const time = t + (idx * 0.05);
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(freq, time);
gain.gain.setValueAtTime(0.22, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + 0.45);
osc.connect(gain);
gain.connect(this.sfxGain);
osc.start(time);
osc.stop(time + 0.5);
});
}
playCriticalStopAlert() {
this.ensureContext();
if (!this.ctx || this.isMuted) return;