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.

By phaserjs · 633 installs

npx skills add phaserjs/phaser --skill audio-and-sound

Source repository · Upstream listing

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 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). Common Patterns Playing Sounds Fire and forget this.sound.play(key, config?) adds, plays, and auto destroys the sound on completion: Retained reference this.sound.add(key, config?) then call play() on the instance: 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() ). The effective playback rate is: sound.rate manager.rate detuneRate where detuneRate = Math.pow(1.0005777895065548, sound.detune + manager.detune) . Looping The LOOPED event fires each time the sound loops back to the start. The LOOP event fires when the loop property changes. Seeking Setting seek on a stopped sound has no effect. Stereo Panning 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. The JSON spritemap entries are automatically converted to markers with name , start , duration , and optional loop . Manual markers you can also add markers to any sound: Marker API on BaseSound: addMarker(marker) , updateMarker(marker) , removeMarker(markerName) . Background Music Pattern The manager's pauseOnBlur (default true ) automatically pauses all sounds when the tab loses focus. Spatial Audio (WebAudio Only) Spatial audio uses the Web Audio PannerNode to position sounds in 2D/3D space relative to a listener. You can set sound.x and sound.y directly on a WebAudioSound to reposition it at any time. If follow is set to an object with x / y properties, the spatial position updates automatically each frame. setListenerPosition() defaults to the center of the game canvas if called with no arguments. Muting Querying Sounds Removing and Stopping Decoding Audio at Runtime (WebAudio Only) Configuration Reference SoundConfig Property Type Default Description mute boolean false Whether the sound is muted volume number 1 Volume, 0 (silence) to 1 (full) rate number 1 Playback speed (0.5 = half, 2.0 = double) detune number 0 Detuning in cents ( 1200 to 1200) seek number 0 Start playback position in seconds loop boolean false Whether the sound should loop delay number 0 Delay before playback starts, in seconds pan number 0 Stereo pan, 1 (left) to 1 (right) source SpatialSoundConfig null Spatial audio configuration (WebAudio only) SpatialSoundConfig Position: x (0), y (0), z (0) source position in world space. Orientation: orientationX (0), orientationY (0), orientationZ ( 1) source direction vector. Models: panningModel ( 'equalpower' or 'HRTF' ), distanceModel ( 'linear' , 'inverse' , 'exponential' ). Distance: refDistance (1), maxDistance (10000), rolloffFactor (1). Cone: coneInnerAngle (360), coneOuterAngle (0), coneOuterGain (0). Tracking: follow (null) a Vector2Like object whose x/y is auto tracked each frame. SoundMarker Property Type Default Description name string (required) Unique identifier for the marker start number 0 Start position in seconds duration number (remaining) Playback duration in seconds config SoundConfig {} Default settings for this marker Events Sound Instance Events (emitted on a Sound object) Event Constant String Value Callback Args When Events.PLAY 'play' (sound) Sound starts playing Events.PAUSE 'pause' (sound) Sound is paused Events.RESUME 'resume' (sound) Sound resumes from pause Events.STOP 'stop' (sound) Sound is stopped Events.COMPLETE 'complete' (sound) Sound finishes (non looping) Events.LOOPED 'looped' (sound) Sound loops back to start Events.LOOP 'loop' (sound, value) Loop property changes Events.MUTE 'mute' (sound, value) Mute state changes Events.VOLUME 'volume' (sound, value) Volume changes Events.RATE 'rate' (sound, value) Rate changes Events.DETUNE 'detune' (sound, value) Detune changes Events.SEEK 'seek' (sound, value) Seek position changes Events.PAN 'pan' (sound, value) Pan value changes Events.DESTROY 'destroy' (sound) Sound is destroyed SoundManager Events (emitted on this.sound ) Event Constant String Value Callback Args When Events.PAUSE ALL 'pauseall' (manager) pauseAll() called Events.RESUME ALL 'resumeall' (manager) resumeAll() called Events.STOP ALL 'stopall' (manager) stopAll() called Events.GLOBAL MUTE 'globalmute' (manager, value) Global mute changes Events.GLOBAL VOLUME 'globalvolume' (manager, value) Global volume changes Events.GLOBAL RATE 'globalrate' (manager, value) Global rate changes Events.GLOBAL DETUNE 'globaldetune' (manager, value) Global detune changes Events.UNLOCKED 'unlocked' (manager) Audio system unlocked after user interaction Events.DECODED 'decoded' (key) Single audio key decoded (WebAudio) Events.DECODED ALL 'decodedall' () All queued audio decoded (WebAudio) API Quick Reference BaseSoundManager ( this.sound ) Methods: add(key, config?) , addAudioSprite(key, config?) , play(key, extra?) , playAudioSprite(key, spriteName, config?) , get(key) , getAll(key?) , getAllPlaying() , isPlaying(key?) , remove(sound) , removeByKey(key) , removeAll() , stopAll() , stopByKey(key) , pauseAll() , resumeAll() , setListenerPosition(x?, y?) , setMute(value) , setVolume(value) , setRate(value) , setDetune(value) . Properties: volume (0 1), mute (boolean), rate (number), detune ( 1200 to 1200), pauseOnBlur (boolean, default true), locked (boolean, read only), listenerPosition (Vector2), sounds (array, private). BaseSound (sound instance) Methods: play(markerName?, config?) , pause() , resume() , stop() , destroy() , addMarker(marker) , updateMarker(marker) , removeMarker(name) , setMute(value) , setVolume(value) , setRate(value) , setDetune(value) , setSeek(value) , setLoop(value) , setPan(value) . Properties: volume (0 1), mute (boolean), rate (number), detune (number), seek (seconds), loop (boolean), pan ( 1 to 1), isPlaying (read only), isPaused (read only), duration (seconds), totalDuration (seconds), key (string), x / y (spatial position, WebAudio only). All set methods return this for chaining. Gotchas Browser Autoplay Policy Browsers block audio until user interaction. Phaser handles this automatically: WebAudio : AudioContext starts suspended. Phaser listens for touchstart/touchend/mousedown/mouseup/keydown on document.body to call context.resume() . The locked property is true until unlocked; UNLOCKED event fires once resolved. HTML5 Audio : Locked audio tags queue all actions until the first touch replays them. You do not need to handle unlocking manually. To know when ready, listen for UNLOCKED : Audio Format Support No single format works everywhere. Provide multiple formats: this.load.audio('bgm', ['assets/bgm.ogg', 'assets/bgm.mp3']) . MP3 has broadest support. OGG Vorbis lacks Safari support. AAC/M4A works well on Safari/iOS. WebM/Opus has excellent quality but limited older browser support. HTML5 Audio Simultaneous Playback HTML5 Audio uses a pool of <audio tags. Specify instances when loading for simultaneous playback: this.load.audio('shot', 'assets/shot.mp3', { instances: 4 }) . Default is 1. If all tags are in use and manager.override is true (default), the sound with the most progress is hijacked. WebAudio has no such limitation. iOS/Safari Specifics StereoPannerNode not supported on iOS/Safari, so pan has no audible effect (events still fire). iOS 17/18+ can interrupt audio on background. Phaser handles this via context.suspend() / context.resume() on the VISIBLE game event. setListenerPosition() and spatial audio are WebAudio only. WebAudio Context Reuse For SPAs that recreate the game without a full page reload, pass audio: { context: existingAudioContext } in the game config. You can also swap contexts at runtime via this.sound.setAudioContext(newContext) (WebAudio only). Sound Manager is Shared (Global) There is one SoundManager per game, not per scene. this.sound in every scene references the same manager. Sounds are not automatically cleaned up on scene shutdown you must stop/remove them yourself if needed. Looping sounds will continue playing across scene changes unless explicitly stopped. Fire and Forget vs Persistent Sounds this.sound.play(key) creates a sound that auto destroys on completion you cannot control it after calling play. Use this.sound.add(key) when you need a persistent reference to pause, stop, adjust volume, or listen for events. Spatial Audio is WebAudio