source-code/
snakey
Public
typescript97 lines3.2 KB
export class AudioManager {
private audioCtx: AudioContext | null = null;
public init() {
try {
// Lazy initialize AudioContext on the first player interaction.
// Browsers restrict audio context creation until a user gesture occurs.
if (!this.audioCtx) {
const AudioContextClass = window.AudioContext || (window as any).webkitAudioContext;
if (AudioContextClass) {
this.audioCtx = new AudioContextClass();
}
}
// Auto-resumed suspended context if it was blocked by autoplay policies
if (this.audioCtx && this.audioCtx.state === 'suspended') {
this.audioCtx.resume().catch(() => {
// Ignore failures to resume context as it will retry on the next user action
});
}
} catch (error) {
// Fail silently to ensure the game remains fully playable even if audio fails to load
console.warn('AudioManager failed to initialize:', error);
this.audioCtx = null;
}
}
public playTurnSound() {
if (!this.audioCtx) return;
try {
const osc = this.audioCtx.createOscillator();
const gain = this.audioCtx.createGain();
osc.type = 'triangle';
osc.frequency.setValueAtTime(500, this.audioCtx.currentTime);
osc.frequency.exponentialRampToValueAtTime(150, this.audioCtx.currentTime + 0.05);
gain.gain.setValueAtTime(0.2, this.audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, this.audioCtx.currentTime + 0.05);
osc.connect(gain);
gain.connect(this.audioCtx.destination);
osc.start();
osc.stop(this.audioCtx.currentTime + 0.05);
} catch (e) {
console.warn('Failed to play turn sound:', e);
}
}
public playEatSound() {
if (!this.audioCtx) return;
try {
const osc = this.audioCtx.createOscillator();
const gain = this.audioCtx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(600, this.audioCtx.currentTime);
osc.frequency.setValueAtTime(900, this.audioCtx.currentTime + 0.1);
gain.gain.setValueAtTime(0.3, this.audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, this.audioCtx.currentTime + 0.2);
osc.connect(gain);
gain.connect(this.audioCtx.destination);
osc.start();
osc.stop(this.audioCtx.currentTime + 0.2);
} catch (e) {
console.warn('Failed to play eat sound:', e);
}
}
public playDieSound() {
if (!this.audioCtx) return;
try {
const osc = this.audioCtx.createOscillator();
const gain = this.audioCtx.createGain();
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(150, this.audioCtx.currentTime);
osc.frequency.exponentialRampToValueAtTime(40, this.audioCtx.currentTime + 0.4);
gain.gain.setValueAtTime(0.4, this.audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, this.audioCtx.currentTime + 0.4);
osc.connect(gain);
gain.connect(this.audioCtx.destination);
osc.start();
osc.stop(this.audioCtx.currentTime + 0.4);
} catch (e) {
console.warn('Failed to play die sound:', e);
}
}
}
About
Snakey Web Game is the official hub and sandbox playground for the Snakey project. Built with React 19, Phaser 3, and Tailwind CSS, it offers a central playable zone alongside a Sandbox Playground that lets visitors test eating custom HTML elements. It also hosts and serves self-compiled browser extension packages (ZIP) for Chrome and Firefox, as well as a dynamically-generated bookmarklet installer that enables users to drag-and-drop a shortcut to run the game on any external website.
linkrasis.me
Web GamePhaserReactTypeScriptTailwind CSSViteBookmarklet