Web Engine Docs
Preparing documentation
Use the search bar to quickly find any topic
Preparing documentation
Use the search bar to quickly find any topic
Learn about the channel-based mixing system with independent volume control for SFX, Music, Voice, and Master channels.
Web Engine uses a channel-based audio mixing system that routes sounds through independent channels. This allows players to adjust SFX, Music, and Voice volumes separately while maintaining a master volume control.
The audio system provides four built-in channels:
0 or AudioChannel.SFX1 or AudioChannel.Music2 or AudioChannel.VoiceEvery audio source is routed through one channel. Set the channel using the group property:
import { AudioSource, AudioChannel } from '@web-engine-dev/core';// Route to SFX channel (default)AudioSource.group[explosionEntity] = AudioChannel.SFX; // 0// Route to Music channelAudioSource.group[musicEntity] = AudioChannel.Music; // 1// Route to Voice channelAudioSource.group[dialogueEntity] = AudioChannel.Voice; // 2
The final volume calculation flows through the channel hierarchy:
// Volume calculation hierarchyfinalVolume = source.volume* channel.volume // SFX, Music, or Voice* master.volume; // Master channel// Examplesource.volume = 0.8; // Source at 80%sfx.volume = 0.5; // SFX channel at 50%master.volume = 0.7; // Master at 70%finalVolume = 0.8 * 0.5 * 0.7 = 0.28 (28%)
The AudioMixer provides centralized control over all channel volumes and mute states:
import { audioMixer, AudioChannel } from '@web-engine-dev/core';// Set individual channel volume (0.0 to 1.0)audioMixer.setVolume(AudioChannel.Master, 0.8);audioMixer.setVolume(AudioChannel.SFX, 0.7);audioMixer.setVolume(AudioChannel.Music, 0.4);audioMixer.setVolume(AudioChannel.Voice, 1.0);// Set multiple volumes at once (more efficient)audioMixer.setVolumes({[AudioChannel.Master]: 0.8,[AudioChannel.SFX]: 0.7,[AudioChannel.Music]: 0.4,[AudioChannel.Voice]: 1.0,});// Get current volumeconst sfxVolume = audioMixer.getVolume(AudioChannel.SFX);console.log('SFX Volume:', sfxVolume);
// Mute a single channelaudioMixer.setMuted(AudioChannel.Music, true); // Mute musicaudioMixer.setMuted(AudioChannel.Music, false); // Unmute music// Toggle mute stateaudioMixer.toggleMute(AudioChannel.SFX);// Mute all channels at onceaudioMixer.setMuted('all', true);// Check if channel is mutedconst isMusicMuted = audioMixer.isMuted(AudioChannel.Music);console.log('Music muted:', isMusicMuted);
Master Mute Override
When Master is muted, all audio is silenced regardless of individual channel mute states. Unmuting a channel while Master is muted will not produce sound until Master is also unmuted.
// Get complete mixer state snapshotconst state = audioMixer.snapshot();console.log(state);// {// master: 0.8,// music: 0.4,// sfx: 0.7,// voice: 1.0,// muteMaster: false,// muteMusic: true,// muteSfx: false,// muteVoice: false// }
For player settings, you'll typically want to save and restore volume preferences:
import { audioMixer, AudioChannel } from '@web-engine-dev/core';// Save volume settings to localStoragefunction saveAudioSettings() {const settings = {master: audioMixer.getVolume(AudioChannel.Master),sfx: audioMixer.getVolume(AudioChannel.SFX),music: audioMixer.getVolume(AudioChannel.Music),voice: audioMixer.getVolume(AudioChannel.Voice),muteMaster: audioMixer.isMuted(AudioChannel.Master),muteMusic: audioMixer.isMuted(AudioChannel.Music),muteSfx: audioMixer.isMuted(AudioChannel.SFX),muteVoice: audioMixer.isMuted(AudioChannel.Voice),};localStorage.setItem('audioSettings', JSON.stringify(settings));}// Load volume settings from localStoragefunction loadAudioSettings() {const stored = localStorage.getItem('audioSettings');if (!stored) return;const settings = JSON.parse(stored);// Restore volumesaudioMixer.setVolumes({[AudioChannel.Master]: settings.master ?? 1.0,[AudioChannel.SFX]: settings.sfx ?? 1.0,[AudioChannel.Music]: settings.music ?? 1.0,[AudioChannel.Voice]: settings.voice ?? 1.0,});// Restore mute statesaudioMixer.setMuted(AudioChannel.Master, settings.muteMaster ?? false);audioMixer.setMuted(AudioChannel.Music, settings.muteMusic ?? false);audioMixer.setMuted(AudioChannel.SFX, settings.muteSfx ?? false);audioMixer.setMuted(AudioChannel.Voice, settings.muteVoice ?? false);}// Call on game startloadAudioSettings();
Create volume sliders in your settings menu that control the mixer:
import { audioMixer, AudioChannel } from '@web-engine-dev/core';import { useState, useEffect } from 'react';function AudioSettings() {const [masterVolume, setMasterVolume] = useState(1.0);const [sfxVolume, setSfxVolume] = useState(1.0);const [musicVolume, setMusicVolume] = useState(1.0);const [voiceVolume, setVoiceVolume] = useState(1.0);// Load initial valuesuseEffect(() => {setMasterVolume(audioMixer.getVolume(AudioChannel.Master) ?? 1.0);setSfxVolume(audioMixer.getVolume(AudioChannel.SFX) ?? 1.0);setMusicVolume(audioMixer.getVolume(AudioChannel.Music) ?? 1.0);setVoiceVolume(audioMixer.getVolume(AudioChannel.Voice) ?? 1.0);}, []);const handleMasterChange = (value: number) => {setMasterVolume(value);audioMixer.setVolume(AudioChannel.Master, value);};const handleSfxChange = (value: number) => {setSfxVolume(value);audioMixer.setVolume(AudioChannel.SFX, value);};return (<div className="audio-settings"><label>Master Volume<inputtype="range"min="0"max="1"step="0.01"value={masterVolume}onChange={(e) => handleMasterChange(parseFloat(e.target.value))}/></label><label>SFX Volume<inputtype="range"min="0"max="1"step="0.01"value={sfxVolume}onChange={(e) => handleSfxChange(parseFloat(e.target.value))}/></label>{/* Repeat for Music and Voice */}</div>);}
Follow these guidelines for routing sounds to the appropriate channel:
When to Use Voice vs SFX
Character vocalizations can go in either Voice or SFX depending on context. Use Voice for dialogue and clear speech. Use SFX for combat grunts, pain sounds, and other non-verbal vocalizations.
The AudioMixer is optimized for zero-GC performance:
// Inefficient - multiple callsaudioMixer.setVolume(AudioChannel.Master, 0.8);audioMixer.setVolume(AudioChannel.SFX, 0.7);audioMixer.setVolume(AudioChannel.Music, 0.4);// Efficient - batch updateaudioMixer.setVolumes({[AudioChannel.Master]: 0.8,[AudioChannel.SFX]: 0.7,[AudioChannel.Music]: 0.4,});
import { audioMixer, AudioChannel } from '@web-engine-dev/core';class AudioSettingsPanel {private storageKey = 'gameAudioSettings';// Initialize and load saved settingsinit() {this.loadSettings();this.setupUI();}// Save current settingssaveSettings() {const settings = {master: audioMixer.getVolume(AudioChannel.Master),sfx: audioMixer.getVolume(AudioChannel.SFX),music: audioMixer.getVolume(AudioChannel.Music),voice: audioMixer.getVolume(AudioChannel.Voice),muteMaster: audioMixer.isMuted(AudioChannel.Master),muteMusic: audioMixer.isMuted(AudioChannel.Music),};localStorage.setItem(this.storageKey, JSON.stringify(settings));}// Load saved settingsloadSettings() {const stored = localStorage.getItem(this.storageKey);if (!stored) return;try {const settings = JSON.parse(stored);audioMixer.setVolumes({[AudioChannel.Master]: settings.master ?? 1.0,[AudioChannel.SFX]: settings.sfx ?? 1.0,[AudioChannel.Music]: settings.music ?? 0.7,[AudioChannel.Voice]: settings.voice ?? 1.0,});if (settings.muteMaster) {audioMixer.setMuted(AudioChannel.Master, true);}if (settings.muteMusic) {audioMixer.setMuted(AudioChannel.Music, true);}} catch (e) {console.error('Failed to load audio settings:', e);}}// Setup UI event handlerssetupUI() {// Master volume sliderdocument.getElementById('masterSlider')?.addEventListener('input', (e) => {const value = parseFloat((e.target as HTMLInputElement).value);audioMixer.setVolume(AudioChannel.Master, value);this.saveSettings();});// SFX volume sliderdocument.getElementById('sfxSlider')?.addEventListener('input', (e) => {const value = parseFloat((e.target as HTMLInputElement).value);audioMixer.setVolume(AudioChannel.SFX, value);this.saveSettings();});// Music mute toggledocument.getElementById('muteMusic')?.addEventListener('click', () => {audioMixer.toggleMute(AudioChannel.Music);this.saveSettings();});}// Reset to defaultsresetToDefaults() {audioMixer.setVolumes({[AudioChannel.Master]: 1.0,[AudioChannel.SFX]: 1.0,[AudioChannel.Music]: 0.7,[AudioChannel.Voice]: 1.0,});audioMixer.setMuted('all', false);this.saveSettings();}}// Usageconst audioSettings = new AudioSettingsPanel();audioSettings.init();