Sounds Guide
This guide explains how to work with sounds in RPG-JS, including static sound configuration, playing sounds from the server, and dynamic sound resolution.Overview
Sounds are audio files that can be played during gameplay to provide audio feedback for actions, events, and ambient effects. RPG-JS supports both pre-loaded static sounds and dynamic sound creation through a resolver system.Audio channels and player preferences
The existing sound API supports four channels:master, music, sfx, and ui. Values range from 0 to 1 and are persisted in the browser for each project.
RpgSound.global.volume(value) call is kept as an alias of the Master channel.
Semantic menu sounds
Native menus use the semantic cuesnavigate, confirm, cancel, open, close, and error. RPGJS includes a small original neutral-fantasy pack generated at runtime, so these cues work without assets or attribution.
Override the global Studio interface theme with audio.ui:
playSound() remains the single API for ordinary and spatial effects. Passing positions enables distance attenuation and stereo panning; without positions it behaves exactly as before.
Studio and Action Battle
Studio stores interface defaults inaudio.ui and the general Action Battle defaults in combatAudio, both in the Project Audio tab. Title-screen presentation belongs to menus.titleScreen.settings, with backgroundMusic and backgroundImage. Maps keep their normal background music and ambience but do not override combat audio. Enemies can override audio.combat, and skills keep their dedicated sound and impactSound fields.
Action Battle resolves sounds in this order:
- cast: skill
sound, source enemy, project, built-in default; - impact: skill
impactSound, source enemy, project, built-in default; - hurt/defeat: target enemy, project, built-in default.
0.75. Battle music is optional: when no enemy or project battle track is configured, map music is not ducked. Music transitions are sequential: the current track fades out before the next track fades in, preventing two background tracks from playing audibly together.
The built-in map renderer registers its BGM with the shared Howler music manager automatically. A custom map renderer can do the same when its source changes:
null or undefined stops the owned map track. The manager applies the Music channel gain and coordinates that track with title-screen and battle overrides.
The legacy project audio.combat shape and enemy combatMusic / combatMusicPriority fields remain supported by the runtime.
Static Sounds
Basic Configuration
Add sounds to your client module configuration:Sound Object Structure
A sound object can have the following properties:play() method, it will be used directly. Otherwise, the engine will create an Audio element from the src property.
Playing Sounds from Server
Using player.playSound()
You can play sounds from the server side using the playSound() method on a player instance. This method plays the sound only for the specific player, making it ideal for personal feedback sounds.
Using player.stopAllSounds()
Stop all currently playing sounds for this specific player. This is useful when changing maps or resetting the audio state for a player.
Using map.playSound()
To play a sound for all players on the map, use the playSound() method on the map instance. This is ideal for environmental sounds, battle music, or map-wide events.
Using map.stopSound()
Stop a specific sound for all players on the map.
Examples
Play Sound for Current Player Only
Play Sound for All Players on Map
Stopping Sounds
You can stop sounds usingstopSound() on either the player or map:
Stop All Sounds
You can also stop all currently playing sounds at once:Map Sounds Configuration
Maps can automatically play sounds when a player joins. These sounds are configured using thesounds property in the map configuration.
Basic Map Sounds
The simplest way to configure map sounds is using a plain object withprovideServerModules:
Stop All Sounds Before Joining
By default, sounds from the previous map continue playing when a player changes maps. If you want to stop all sounds before playing the new map’s sounds, use thestopAllSoundsBeforeJoin option:
stopAllSoundsBeforeJoin: true:
- Battle maps (to cut off peaceful background music)
- Important cutscenes or story moments
- Areas where you want a clean audio transition
- Maps with their own distinct audio atmosphere
false (default):
- Smooth transitions between similar areas
- Continuous ambient sounds that should carry over
- When you want sounds to layer naturally
Complete Map Sound Example
Using defineModule
You can also usedefineModule to define your server configuration separately:
Alternative: Using @MapData or @RpgModule (Legacy)
For backward compatibility, you can still use decorators, though plain objects are now the recommended approach:@RpgModule:
Note: Using plain objects withprovideServerModulesordefineModuleis the recommended approach. Decorators are still supported for backward compatibility but not required.
Use Cases
Usingmap.playSound() (for all players):
- Environmental sounds (explosions, doors opening)
- Battle sounds (combat start, victory fanfare)
- Map-wide events (boss spawn, treasure chest opening)
- Ambient effects that should be synchronized
- Background music that everyone should hear
player.playSound() (for current player only):
- UI feedback sounds (menu navigation, button clicks)
- Personal notifications (level up, achievement unlocked)
- Item pickup sounds (only the player who picked it up hears it)
- Private messages or alerts
- Personal background music
Complete Example
Dynamic Sound Resolver
The sound resolver allows you to create sounds on-the-fly when they are requested but not found in the cache. This is useful for:- Loading sounds from external APIs
- Generating sounds programmatically
- Creating sounds based on runtime data
- Lazy loading sounds to reduce initial load time
Configuration
Add asoundResolver function to your client module:
Asynchronous Resolver
The resolver can also be asynchronous, useful for loading sounds from APIs or files:Programmatic Generation
You can also generate sounds programmatically:How It Works
- When a sound is requested (e.g., via
player.playSound()), the engine first checks the cache - If the sound is not found and a resolver is configured, the resolver is called with the sound ID
- The resolved sound is automatically cached for future use
- If the resolver returns
undefinedornull, the sound is not found and a warning is logged
Resolver Function Signature
id: string- The sound ID that was requested
SoundDefinition- A sound configuration object (synchronous)Promise<SoundDefinition>- A Promise that resolves to a sound (asynchronous)undefined | null- Indicates the sound cannot be created
Programmatic API
You can also set a resolver programmatically using the engine:Example: Loading from CDN
Example: Fallback Chain
Combining Static and Dynamic
You can use both static sounds and a resolver together. Static sounds are loaded first, and the resolver is only called for sounds not found in the static list:Client-Side Sound API
You can also play sounds directly from the client side using the engine:Best Practices
1. Sound File Formats
- Use compressed formats (MP3, OGG) for better performance
- Provide multiple formats for browser compatibility:
2. Error Handling
Always handle errors gracefully in async resolvers:3. Performance
- Use static sounds for frequently played sounds (UI feedback, common actions)
- Use resolvers for sounds that are rarely used or loaded on-demand
- Pre-load critical sounds in the static
soundsarray
4. ID Patterns
Use consistent ID patterns to make resolver logic easier:5. Volume Management
Consider implementing volume controls:6. Memory Management
Resolved sounds are automatically cached. If you need to invalidate the cache:Common Use Cases
Dialog Box Sounds
Footstep Sounds
Weapon Sounds
See Also
- Spritesheets Guide - Learn about dynamic spritesheet resolution (similar pattern)
- Display Animations Guide - Combine sounds with visual effects
- Dialog Box Guide - Using sounds in dialog boxes