/audio-and-sound
Use this skill when adding audio or sound to a Phaser 4 game. Covers loading audio, playing sounds, music, volume, spatial audio, Web Audio API, and SoundManager. Triggers on: sound, audio, music, volume, mute.
Claude Code
$ npx -y skills add phaserjs/phaser --skill audio-and-sound --agent claude-code
Codex
$ npx skills add phaserjs/phaser --skill audio-and-sound -a codex -y
Cursor
$ npx skills add phaserjs/phaser --skill audio-and-sound -a cursor -y
Gemini CLI
$ npx skills add phaserjs/phaser --skill audio-and-sound -a gemini-cli -y
GitHub Copilot
$ npx skills add phaserjs/phaser --skill audio-and-sound -a github-copilot -y
OpenCode
$ npx skills add phaserjs/phaser --skill audio-and-sound -a opencode -y
Windsurf
$ npx skills add phaserjs/phaser --skill audio-and-sound -a windsurf -y
SKILL.md
audio-and-sound.SKILL.mdname: audio-and-sound
description: "Use this skill when adding audio or sound to a Phaser 4 game. Covers loading audio, playing sounds, music, volume, spatial audio, Web Audio API, and SoundManager. Triggers on: sound, audio, music, volume, mute."
Audio and Sound
> Phaser provides a unified Sound system via `this.sound` (a SoundManager) that abstracts over Web Audio API and HTML5 Audio. It handles loading, playback, volume, panning, looping, markers, audio sprites, spatial audio, and browser autoplay-policy unlocking.
**Key source paths:** `src/sound/BaseSoundManager.js`, `src/sound/BaseSound.js`, `src/sound/webaudio/`, `src/sound/html5/`, `src/sound/SoundManagerCreator.js`, `src/sound/events/`, `src/sound/typedefs/` **Related skills:** ../loading-assets/SKILL.md, ../game-setup-and-config/SKILL.md
Quick Start
class GameScene extends Phaser.Scene {
preload() {
this.load.audio('bgm', 'assets/music.mp3');
this.load.audio('coin', ['assets/coin.ogg', 'assets/coin.mp3']);
}
create() {
// Fire-and-forget (auto-destroys when complete)
this.sound.play('coin');
// Retained reference for ongoing control
this.music = this.sound.add('bgm', { loop: true, volume: 0.5 });
this.music.play();
}
}Assets loaded via `this.load.audio()` in `preload()` are ready by the time `create()` runs. Provide an array of URLs for cross-browser format fallback.
Core Concepts
WebAudio vs HTML5 Audio
Phaser auto-selects the best backend via `SoundManagerCreator.create()`:
1. If `config.audio.noAudio` is true, or the device supports neither Web Audio nor HTML5 Audio, a **NoAudioSoundManager** is created (all calls are no-ops). 2. If the device supports Web Audio and `config.audio.disableWebAudio` is not true, a **WebAudioSoundManager** is created (preferred). 3. Otherwise, an **HTML5AudioSoundManager** is created as fallback.
**WebAudio** advantages: precise timing, gapless looping, stereo panning (`StereoPannerNode`), spatial audio (`PannerNode`), per-sound gain nodes, `decodeAudio()` for runtime decoding.
**HTML5 Audio** limitations: no spatial audio, no real stereo panning (pan fires events but no audible effect), less precise looping, requires `instances` count at load time for simultaneous playback.
Force HTML5 or disable audio via game config: `audio: { disableWebAudio: true }` or `audio: { noAudio: true }`. Pass `audio: { context: existingAudioContext }` to reuse a WebAudio context in SPAs.
The SoundManager (`this.sound`)
Accessed via `this.sound` in any Scene. It is a single shared instance across the entire game. Key responsibilities:
- Adding, playing, and removing sound instances
- Global volume, mute, rate, and detune
- Automatic pause/resume when the browser tab loses/gains focus (`pauseOnBlur`, default `true`)
- Audio unlock handling for mobile browsers
- Spatial audio listener position (WebAudio only)
Sound Instances
Created via `this.sound.add(key, config)`. Each instance has its own playback state, volume, rate, detune, loop, pan, and seek properties. A sound must exist in the audio cache (loaded via the Loader) before it can be added.
State flags: `isPlaying` (boolean), `isPaused` (boolean).
const sfx = this.sound.add('explosion', { volume: 0.8 });
sfx.play(); // returns boolean
sfx.pause(); // only works if isPlaying
sfx.resume(); // only works if isPaused
sfx.stop(); // resets to stopped state
sfx.destroy(); // marks for removal from managerCommon Patterns
Playing Sounds
**Fire-and-forget** -- `this.sound.play(key, config?)` adds, plays, and auto-destroys the sound on completion:
this.sound.play('explosion');
this.sound.play('powerup', { volume: 0.5, rate: 1.2 });**Retained reference** -- `this.sound.add(key, config?)` then call `play()` on the instance:
const laser = this.sound.add('laser');
laser.play();
// Later: laser.stop(), laser.volume = 0.3, etc.Volume, Rate, and Detune
Each property can be set per-sound or globally on the manager. Global and per-sound values combine (for rate/detune, they multiply via `calculateRate()`).
// Per-sound
sound.volume = 0.5; // 0 to 1
sound.setVolume(0.5); // chainable alternative
sound.rate = 1.5; // 0.5 = half speed, 2.0 = double speed
sound.setRate(1.5);
sound.detune = 200; // cents, -1200 to 1200
sound.setDetune(200);
// Global (affects all sounds)
this.sound.volume = 0.8;
this.sound.setVolume(0.8);
this.sound.rate = 1.0;
this.sound.setRate(1.0);
this.sound.detune = 0;
this.sound.setDetune(0);
The effective playback rate is: `sound.rate * manager.rate * detuneRate` where `detuneRate = Math.pow(1.0005777895065548, sound.detune + manager.detune)`.
Looping
// Via config at creation
const bgm = this.sound.add('music', { loop: true });
bgm.play();
// Toggle during playback
bgm.loop = false;
bgm.setLoop(false); // chainableThe `LOOPED` event fires each time the sound loops back to the start. The `LOOP` event fires when the loop property changes.
Seeking
sound.seek = 5.0; // jump to 5 seconds in
sound.setSeek(5.0); // chainable
console.log(sound.seek); // current playback position in seconds
Setting seek on a stopped sound has no effect.
Stereo Panning
sound.pan = -1; // full left
sound.pan = 0; // center
sound.pan = 1; // full right
sound.setPan(0.5); // chainable
Uses `StereoPannerNode`, if it exists, on WebAudio. On HTML5 Audio, the pan property fires events but has no audible effect.
Audio Sprites and Markers
Audio sprites combine multiple sounds into a single audio file with a JSON config (generated by the `audiosprite` tool). The JSON must be loaded separately.
// In preload
this.load.audioSprite('sfx', 'assets/sfx.json', ['assets/sfx.ogg', 'assets/sfx.mp3']);
// In create
this.sound.playAudioSprite('sfx', 'explosion');Read more
name: audio-and-sound description: "Use this skill when adding audio or sound to a Phaser 4 game. Covers loading audio, playing sounds, music, volume, spatial audio, Web Audio API, and SoundManager. Triggers on: sound, audio, music, volume, mute."
Audio and Sound
> Phaser provides a unified Sound system via `this.sound` (a SoundManager) that abstracts over Web Audio API and HTML5 Audio. It handles loading, playback, volume, panning, looping, markers, audio sprites, spatial audio, and browser autoplay-policy unlocking.
**Key source paths:** `src/sound/BaseSoundManager.js`, `src/sound/BaseSound.js`, `src/sound/webaudio/`, `src/sound/html5/`, `src/sound/SoundManagerCreator.js`, `src/sound/events/`, `src/sound/typedefs/` **Related skills:** ../loading-assets/SKILL.md, ../game-setup-and-config/SKILL.md
Quick Start
class GameScene extends Phaser.Scene {
preload() {
this.load.audio('bgm', 'assets/music.mp3');
this.load.audio('coin', ['assets/coin.ogg', 'assets/coin.mp3']);
}
create() {
// Fire-and-forget (auto-destroys when complete)
this.sound.play('coin');
// Retained reference for ongoing control
this.music = this.sound.add('bgm', { loop: true, volume: 0.5 });
this.music.play();
}
}Assets loaded via `this.load.audio()` in `preload()` are ready by the time `create()` runs. Provide an array of URLs for cross-browser format fallback.
Core Concepts
WebAudio vs HTML5 Audio
Phaser auto-selects the best backend via `SoundManagerCreator.create()`:
1. If `config.audio.noAudio` is true, or the device supports neither Web Audio nor HTML5 Audio, a **NoAudioSoundManager** is created (all calls are no-ops). 2. If the device supports Web Audio and `config.audio.disableWebAudio` is not true, a **WebAudioSoundManager** is created (preferred). 3. Otherwise, an **HTML5AudioSoundManager** is created as fallback.
**WebAudio** advantages: precise timing, gapless looping, stereo panning (`StereoPannerNode`), spatial audio (`PannerNode`), per-sound gain nodes, `decodeAudio()` for runtime decoding.
**HTML5 Audio** limitations: no spatial audio, no real stereo panning (pan fires events but no audible effect), less precise looping, requires `instances` count at load time for simultaneous playback.
Force HTML5 or disable audio via game config: `audio: { disableWebAudio: true }` or `audio: { noAudio: true }`. Pass `audio: { context: existingAudioContext }` to reuse a WebAudio context in SPAs.
The SoundManager (`this.sound`)
Accessed via `this.sound` in any Scene. It is a single shared instance across the entire game. Key responsibilities:
- Adding, playing, and removing sound instances
- Global volume, mute, rate, and detune
- Automatic pause/resume when the browser tab loses/gains focus (`pauseOnBlur`, default `true`)
- Audio unlock handling for mobile browsers
- Spatial audio listener position (WebAudio only)
Sound Instances
Created via `this.sound.add(key, config)`. Each instance has its own playback state, volume, rate, detune, loop, pan, and seek properties. A sound must exist in the audio cache (loaded via the Loader) before it can be added.
State flags: `isPlaying` (boolean), `isPaused` (boolean).
const sfx = this.sound.add('explosion', { volume: 0.8 });
sfx.play(); // returns boolean
sfx.pause(); // only works if isPlaying
sfx.resume(); // only works if isPaused
sfx.stop(); // resets to stopped state
sfx.destroy(); // marks for removal from managerCommon Patterns
Playing Sounds
**Fire-and-forget** -- `this.sound.play(key, config?)` adds, plays, and auto-destroys the sound on completion:
this.sound.play('explosion');
this.sound.play('powerup', { volume: 0.5, rate: 1.2 });**Retained reference** -- `this.sound.add(key, config?)` then call `play()` on the instance:
const laser = this.sound.add('laser');
laser.play();
// Later: laser.stop(), laser.volume = 0.3, etc.Volume, Rate, and Detune
Each property can be set per-sound or globally on the manager. Global and per-sound values combine (for rate/detune, they multiply via `calculateRate()`).
// Per-sound sound.volume = 0.5; // 0 to 1 sound.setVolume(0.5); // chainable alternative sound.rate = 1.5; // 0.5 = half speed, 2.0 = double speed sound.setRate(1.5); sound.detune = 200; // cents, -1200 to 1200 sound.setDetune(200); // Global (affects all sounds) this.sound.volume = 0.8; this.sound.setVolume(0.8); this.sound.rate = 1.0; this.sound.setRate(1.0); this.sound.detune = 0; this.sound.setDetune(0);
The effective playback rate is: `sound.rate * manager.rate * detuneRate` where `detuneRate = Math.pow(1.0005777895065548, sound.detune + manager.detune)`.
Looping
// Via config at creation
const bgm = this.sound.add('music', { loop: true });
bgm.play();
// Toggle during playback
bgm.loop = false;
bgm.setLoop(false); // chainableThe `LOOPED` event fires each time the sound loops back to the start. The `LOOP` event fires when the loop property changes.
Seeking
sound.seek = 5.0; // jump to 5 seconds in sound.setSeek(5.0); // chainable console.log(sound.seek); // current playback position in seconds
Setting seek on a stopped sound has no effect.
Stereo Panning
sound.pan = -1; // full left sound.pan = 0; // center sound.pan = 1; // full right sound.setPan(0.5); // chainable
Uses `StereoPannerNode`, if it exists, on WebAudio. On HTML5 Audio, the pan property fires events but has no audible effect.
Audio Sprites and Markers
Audio sprites combine multiple sounds into a single audio file with a JSON config (generated by the `audiosprite` tool). The JSON must be loaded separately.
// In preload
this.load.audioSprite('sfx', 'assets/sfx.json', ['assets/sfx.ogg', 'assets/sfx.mp3']);
// In create
this.sound.playAudioSprite('sfx', 'explosion');Phaser is a fast, free, and fun open source HTML5 game framework that offers WebGL and Canvas rendering across desktop and mobile web browsers and has been actively developed for over 13 years.
Other skills on phaser.
More skills from other plugins.
migrate-radix-to-base
Migrates React projects and components from Radix UI to Base UI. Use when asked to migrate from radix, move to base-ui, convert…
taste-skill
tasteskill v2, the anti-slop frontend skill. Art direction for websites, distilled from a study of 247 curated gallery sites (One…
Questions about audio-and-sound.
- Which coding agents can use audio-and-sound?
- audio-and-sound installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

