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
Resource Cleanup
Audio handles are automatically stopped and released when the owning entity is despawned. You do not need to manually stop or clean up AudioSource playback when destroying entities.