Audio
Estella provides a complete audio system with ECS components, bus-based mixing, and spatial audio. The AudioPlugin is included by the engine by default.
Components
AudioSource
Attach to any entity to play audio. Requires a Transform component for spatial audio.
| Property | Type | Default | Description |
|---|---|---|---|
clip | string | '' | Audio file path |
bus | string | 'sfx' | Audio bus: sfx, music, ui, voice |
volume | number | 1.0 | Volume (0–1) |
pitch | number | 1.0 | Playback rate (0.1–3) |
loop | boolean | false | Loop playback |
playOnAwake | boolean | false | Auto-play when entity loads |
spatial | boolean | false | Enable spatial audio |
minDistance | number | 100 | Spatial reference distance |
maxDistance | number | 1000 | Spatial max distance |
attenuationModel | number | 1 | 0 = Linear, 1 = Inverse, 2 = Exponential |
rolloff | number | 1.0 | Spatial rolloff factor (0–5) |
priority | number | 0 | Playback priority |
enabled | boolean | true | Component active |
AudioListener
Add to the camera or player entity to receive spatial audio. Only one listener should be active at a time.
| Property | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Listener active |
Quick Playback API
For simple one-shot sounds that don’t need an entity, use the static Audio class:
import { Audio } from 'esengine';
// Play a sound effectconst handle = Audio.playSFX('assets/explosion.mp3', { volume: 0.8, pitch: 1.2, pan: -0.5, // stereo panning (-1 left, 0 center, 1 right)});
// Control playbackhandle.pause();handle.resume();handle.stop();handle.setVolume(0.6);handle.setLoop(true);handle.setPlaybackRate(1.5);
// Query stateconsole.log(handle.isPlaying, handle.currentTime, handle.duration);Background Music
// Play BGM with fade-inAudio.playBGM('assets/theme.mp3', { volume: 0.5, fadeIn: 2.0 });
// Switch BGM with cross-fade (old track fades out while new one fades in)Audio.playBGM('assets/boss.mp3', { volume: 0.7, crossFade: 1.5 });
// Stop BGM with fade-outAudio.stopBGM(1.0);
// Stop all audio immediately (BGM + cancel fades)Audio.stopAll();AudioHandle
Both playSFX and entity-based playback return an AudioHandle:
| Method / Property | Description |
|---|---|
stop() | Stop playback and release resources |
pause() | Pause playback |
resume() | Resume paused playback |
setVolume(v) | Set volume (0–1) |
setPan(p) | Set stereo panning (-1 left, 0 center, 1 right) |
setLoop(l) | Enable/disable looping |
setPlaybackRate(r) | Set playback speed |
isPlaying | Whether audio is currently playing |
currentTime | Current playback position in seconds |
duration | Total duration in seconds |
onEnd | Optional callback invoked when playback finishes |
Audio Buses
Every sound is routed through a bus — a virtual mixing channel. The engine provides 4 built-in buses, all connected to a master bus:
| Bus | Default Volume | Typical Usage |
|---|---|---|
sfx | 1.0 | Sound effects: explosions, footsteps, UI clicks, one-shot sounds |
music | 0.8 | Background music and ambient loops |
ui | 1.0 | UI-specific sounds: button hover, panel open/close, notifications |
voice | 1.0 | Character dialogue, narration, voiceover |
All 4 buses behave identically — they are simply independent volume/mute channels. The separation lets players adjust each category independently (e.g. lower music but keep SFX loud) via a settings menu:
master (1.0)├── sfx (1.0)├── music (0.8)├── ui (1.0)└── voice (1.0)Set the bus on an AudioSource component or in playSFX config. If not specified, sounds default to the sfx bus.
Volume Control
Control volume per bus via the mixer:
import { Audio } from 'esengine';
Audio.setMasterVolume(0.8);Audio.setMusicVolume(0.5);Audio.setSFXVolume(1.0);Audio.setUIVolume(0.7);
// Mute a specific busAudio.muteBus('music', true);Preloading
Preload audio files to avoid latency on first play:
import { Audio } from 'esengine';
await Audio.preload('assets/explosion.mp3');await Audio.preloadAll([ 'assets/jump.mp3', 'assets/coin.mp3', 'assets/bgm.mp3',]);Entity-Based Playback
Add AudioSource to an entity in the editor or via code:
import { defineSystem, addSystem, Query, Mut, AudioSource } from 'esengine';
addSystem(defineSystem( [Query(Mut(AudioSource))], (query) => { for (const [entity, audio] of query) { // Change clip at runtime audio.clip = 'assets/new-sound.mp3'; audio.volume = 0.5; } }));Spatial Audio
Enable spatial audio by setting spatial: true on AudioSource and adding an AudioListener to the camera entity.
import { AudioSource, AudioListener, AttenuationModel } from 'esengine';The system automatically calculates distance-based attenuation and stereo panning based on the Transform positions of the source and listener entities.
Attenuation models:
- Linear (0) — volume decreases linearly between
minDistanceandmaxDistance - Inverse (1, default) — realistic falloff based on inverse distance
- Exponential (2) — steep falloff using exponential curve
WeChat MiniGame
On WeChat, audio uses wx.createInnerAudioContext() instead of Web Audio API. Key differences:
- No mixer — bus-based volume control (
setMasterVolume,setSFXVolume, etc.) is unavailable. UseAudioHandle.setVolume()for per-sound control. - No stereo panning —
setPan()is a no-op. Spatial audio attenuation still works (volume-based). - Local file paths — audio files in the build package are accessed by relative path (e.g.
assets/sounds/bgm.mp3).
Editor Integration
- Inspector — audio files show an inline preview player with play/pause controls
- Drag-to-scene — drag an audio file from the asset browser onto the scene to create an entity with
AudioSource - Game View — a mute toggle button appears in the Game View toolbar
- Scene View — audio systems are skipped in Scene View to avoid unwanted playback during editing