Skip to content

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.

PropertyTypeDefaultDescription
clipstring''Audio file path
busstring'sfx'Audio bus: sfx, music, ui, voice
volumenumber1.0Volume (0–1)
pitchnumber1.0Playback rate (0.1–3)
loopbooleanfalseLoop playback
playOnAwakebooleanfalseAuto-play when entity loads
spatialbooleanfalseEnable spatial audio
minDistancenumber100Spatial reference distance
maxDistancenumber1000Spatial max distance
attenuationModelnumber10 = Linear, 1 = Inverse, 2 = Exponential
rolloffnumber1.0Spatial rolloff factor (0–5)
prioritynumber0Playback priority
enabledbooleantrueComponent active

AudioListener

Add to the camera or player entity to receive spatial audio. Only one listener should be active at a time.

PropertyTypeDefaultDescription
enabledbooleantrueListener 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 effect
const handle = Audio.playSFX('assets/explosion.mp3', {
volume: 0.8,
pitch: 1.2,
pan: -0.5, // stereo panning (-1 left, 0 center, 1 right)
});
// Control playback
handle.pause();
handle.resume();
handle.stop();
handle.setVolume(0.6);
handle.setLoop(true);
handle.setPlaybackRate(1.5);
// Query state
console.log(handle.isPlaying, handle.currentTime, handle.duration);

Background Music

// Play BGM with fade-in
Audio.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-out
Audio.stopBGM(1.0);
// Stop all audio immediately (BGM + cancel fades)
Audio.stopAll();

AudioHandle

Both playSFX and entity-based playback return an AudioHandle:

Method / PropertyDescription
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
isPlayingWhether audio is currently playing
currentTimeCurrent playback position in seconds
durationTotal duration in seconds
onEndOptional 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:

BusDefault VolumeTypical Usage
sfx1.0Sound effects: explosions, footsteps, UI clicks, one-shot sounds
music0.8Background music and ambient loops
ui1.0UI-specific sounds: button hover, panel open/close, notifications
voice1.0Character 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 bus
Audio.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 minDistance and maxDistance
  • 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. Use AudioHandle.setVolume() for per-sound control.
  • No stereo panningsetPan() 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