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 how to use 3D positional audio with HRTF panning, distance attenuation, and the AudioListener component.
Spatial audio (also called 3D audio or positional audio) simulates how sounds behave in the real world. Sounds get quieter as they move away from the listener, and HRTF panning creates realistic directional cues.
The AudioListener component represents the "ears" of your audio system. It's typically attached to the camera entity so that sounds are heard from the player's perspective.
| Property | Type | Default | Description |
|---|---|---|---|
| active | boolean | true | Whether this listener is active. Only one listener should be active at a time. |
To enable spatial audio:
AudioListener componenttrueOne Listener Only
Only one AudioListener should be active at a time. Having multiple active listeners will cause unpredictable behavior. If you need to switch listeners (e.g., camera cut), disable the old one before enabling the new one.
When an AudioSource has spatial enabled, its position in 3D space determines how the sound is heard:
import { AudioSource, Transform } from '@web-engine-dev/core';// Create a spatial sound at a specific positionexport default (api) => {return {onStart() {// Enable spatial audioAudioSource.spatial[api.entity] = 1;AudioSource.spatialBlend[api.entity] = 1.0; // Full 3D// Position is automatically synced from TransformTransform.position[api.entity][0] = 10; // XTransform.position[api.entity][1] = 0; // YTransform.position[api.entity][2] = 5; // Z// Configure spatial parametersAudioSource.refDistance[api.entity] = 5.0;AudioSource.maxDistance[api.entity] = 50.0;AudioSource.rolloffFactor[api.entity] = 1.0;// Start playingAudioSource.playing[api.entity] = 1;}};};
Automatic Position Sync
The AudioSystem automatically updates sound positions from the entity's Transform component every frame. You don't need to manually update audio positions—just move the entity and the sound follows.
Distance attenuation controls how sound volume decreases with distance. Web Engine uses the inverse distance model by default:
The refDistance is the distance at which the sound starts to fade. Within this distance, the sound plays at full volume.
The maxDistance is the distance beyond which the sound becomes inaudible (or nearly so):
The rolloffFactor controls how quickly volume decreases with distance:
// Distant explosion - audible from far awayAudioSource.refDistance[explosion] = 20.0; // Loud close-upAudioSource.maxDistance[explosion] = 500.0; // Audible 500 units awayAudioSource.rolloffFactor[explosion] = 0.8; // Slow falloff// Campfire - only audible when closeAudioSource.refDistance[campfire] = 2.0; // Cozy close-upAudioSource.maxDistance[campfire] = 30.0; // Fades by 30 unitsAudioSource.rolloffFactor[campfire] = 1.5; // Faster falloff// Character dialogueAudioSource.refDistance[dialogue] = 3.0; // Clear nearbyAudioSource.maxDistance[dialogue] = 40.0; // Audible in same roomAudioSource.rolloffFactor[dialogue] = 1.0; // Natural falloff
Web Engine uses HRTF (Head-Related Transfer Function) panning by default for the most realistic spatial audio:
Browser Support
HRTF is supported in all modern browsers. If HRTF is not available, the browser falls back to equal-power panning automatically.
To optimize performance, the audio system automatically stops sounds that are too far from the listener:
// With maxDistance = 100// Sound will be automatically culled at distance > 150AudioSource.maxDistance[entity] = 100.0;// Automatically culled at 150 units (1.5 × 100)// Manual culling check in scriptsexport default (api) => {return (dt) => {const distance = api.position.distanceTo(listenerPosition);if (distance > AudioSource.maxDistance[api.entity] * 1.5) {// Sound will be culled by the audio systemapi.log('Sound culled due to distance');}};};
Audio LOD automatically reduces quality and volume for distant sounds to save CPU resources:
Audio LOD is automatically applied to all spatial audio sources. You can see LOD status in the audio performance profiler.
LOD Configuration
LOD thresholds are configured globally and can be adjusted based on your scene's scale. Contact the audio system documentation for advanced LOD configuration options.
The AudioZone component creates spatial regions that apply audio effects like reverb to sounds within them:
| Property | Type | Default | Description |
|---|---|---|---|
| shapeType | number | 0 | Zone shape: 0 = sphere, 1 = box |
| innerRadius | number | 5.0 | Inner radius where effect starts fading in |
| outerRadius | number | 10.0 | Outer radius where effect is at full strength |
| reverbPreset | number | 0 | Reverb preset: 0 = none, 1 = small room, 2 = medium room, 3 = large hall, 4 = cave |
| occlusionFactor | number | 0.0 | Occlusion amount (0.0 = clear, 1.0 = fully muffled) |
| active | boolean | true | Whether this zone is active |
import { AudioZone } from '@web-engine-dev/core';// Create a cathedral reverb zoneexport default (api) => {return {onStart() {AudioZone.shapeType[api.entity] = 1; // BoxAudioZone.innerRadius[api.entity] = 20.0;AudioZone.outerRadius[api.entity] = 50.0;AudioZone.reverbPreset[api.entity] = 3; // Large hallAudioZone.active[api.entity] = 1;}};};
Available reverb presets:
export default (api) => {return {onStart() {// Position waterfall in worldapi.position = { x: 50, y: 10, z: 30 };// Configure spatial audioAudioSource.assetId[api.entity] = waterfallSoundId;AudioSource.spatial[api.entity] = 1;AudioSource.spatialBlend[api.entity] = 1.0; // Full 3D// Waterfall is loud up close, audible from distanceAudioSource.refDistance[api.entity] = 10.0; // Full volume within 10 unitsAudioSource.maxDistance[api.entity] = 200.0; // Fade out by 200 unitsAudioSource.rolloffFactor[api.entity] = 0.7; // Slow falloff (large sound source)// Waterfall loops continuouslyAudioSource.loop[api.entity] = 1;AudioSource.volume[api.entity] = 0.6; // Not too loudAudioSource.group[api.entity] = 0; // SFX channel// Start playingAudioSource.playing[api.entity] = 1;}};};