source-code/
snakey-extension
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 Browser Extension is a cross-browser extension built using Manifest V3 that injects a playable Phaser 3 game onto any active tab. It parses the page DOM, turns HTML elements into target coordinates, and features custom chomp/collapse animations. It supports both Chromium (background service worker) and Firefox (background scripts), implements a Canvas-based rendering fallback to bypass strict WebGL CORS limitations, and applies fully container-scoped vanilla CSS overrides to prevent style bleeding on host pages.
linkrasis.me
Browser ExtensionChrome MV3Firefox MV3PhaserReactTypeScriptVite