Spatial Audio

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.

AudioListener Component#

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.

PropertyTypeDefaultDescription
activebooleantrueWhether this listener is active. Only one listener should be active at a time.

To enable spatial audio:

  1. Find your main camera entity
  2. Add the AudioListener component
  3. Set active to true
  4. All spatial AudioSource components will now be positioned relative to this listener

One 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.

3D Sound Positioning#

When an AudioSource has spatial enabled, its position in 3D space determines how the sound is heard:

  • Distance — Sound gets quieter as it moves away from the listener
  • Direction — HRTF panning creates left/right and front/back cues
  • Velocity — Doppler effect for moving sounds (optional)
import { AudioSource, Transform } from '@web-engine-dev/core';
// Create a spatial sound at a specific position
export default (api) => {
return {
onStart() {
// Enable spatial audio
AudioSource.spatial[api.entity] = 1;
AudioSource.spatialBlend[api.entity] = 1.0; // Full 3D
// Position is automatically synced from Transform
Transform.position[api.entity][0] = 10; // X
Transform.position[api.entity][1] = 0; // Y
Transform.position[api.entity][2] = 5; // Z
// Configure spatial parameters
AudioSource.refDistance[api.entity] = 5.0;
AudioSource.maxDistance[api.entity] = 50.0;
AudioSource.rolloffFactor[api.entity] = 1.0;
// Start playing
AudioSource.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#

Distance attenuation controls how sound volume decreases with distance. Web Engine uses the inverse distance model by default:

Reference Distance#

The refDistance is the distance at which the sound starts to fade. Within this distance, the sound plays at full volume.

  • Small refDistance (0.1-1.0) — Quiet, intimate sounds (whisper, small object)
  • Medium refDistance (1.0-5.0) — Normal sounds (footsteps, voice)
  • Large refDistance (5.0-20.0) — Loud sounds (explosion, engine, music)

Maximum Distance#

The maxDistance is the distance beyond which the sound becomes inaudible (or nearly so):

  • Short maxDistance (10-50) — Small environmental sounds
  • Medium maxDistance (50-200) — Normal gameplay sounds
  • Long maxDistance (200+) — Distant explosions, ambient atmosphere

Rolloff Factor#

The rolloffFactor controls how quickly volume decreases with distance:

  • 0.5 — Slow falloff, sound audible at long distances
  • 1.0 — Natural falloff (default, realistic)
  • 2.0 — Fast falloff, sound fades quickly
  • 3.0+ — Very fast falloff, sound only audible nearby
// Distant explosion - audible from far away
AudioSource.refDistance[explosion] = 20.0; // Loud close-up
AudioSource.maxDistance[explosion] = 500.0; // Audible 500 units away
AudioSource.rolloffFactor[explosion] = 0.8; // Slow falloff
// Campfire - only audible when close
AudioSource.refDistance[campfire] = 2.0; // Cozy close-up
AudioSource.maxDistance[campfire] = 30.0; // Fades by 30 units
AudioSource.rolloffFactor[campfire] = 1.5; // Faster falloff
// Character dialogue
AudioSource.refDistance[dialogue] = 3.0; // Clear nearby
AudioSource.maxDistance[dialogue] = 40.0; // Audible in same room
AudioSource.rolloffFactor[dialogue] = 1.0; // Natural falloff

Panning Models#

Web Engine uses HRTF (Head-Related Transfer Function) panning by default for the most realistic spatial audio:

HRTF Panning#

  • Simulates how sound waves interact with human head and ears
  • Provides accurate left/right panning
  • Creates front/back and up/down directional cues
  • Best for headphones, but works with speakers too
  • Automatically enabled for all 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.

Spatial Culling#

To optimize performance, the audio system automatically stops sounds that are too far from the listener:

  • Sounds beyond 1.5× maxDistance are automatically paused
  • When you move back in range, sounds resume automatically
  • This prevents wasting CPU on inaudible distant sounds
  • Culling happens before distance attenuation calculations
// With maxDistance = 100
// Sound will be automatically culled at distance > 150
AudioSource.maxDistance[entity] = 100.0;
// Automatically culled at 150 units (1.5 × 100)
// Manual culling check in scripts
export 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 system
api.log('Sound culled due to distance');
}
};
};

Audio LOD (Level of Detail)#

Audio LOD automatically reduces quality and volume for distant sounds to save CPU resources:

  • Near (0-50 units) — Full quality, 100% volume
  • Medium (50-150 units) — Reduced quality, 70% volume
  • Far (150-300 units) — Low quality, 40% volume
  • Very Far (300+ units) — Disabled

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.

Audio Zones (Reverb)#

The AudioZone component creates spatial regions that apply audio effects like reverb to sounds within them:

PropertyTypeDefaultDescription
shapeTypenumber0Zone shape: 0 = sphere, 1 = box
innerRadiusnumber5.0Inner radius where effect starts fading in
outerRadiusnumber10.0Outer radius where effect is at full strength
reverbPresetnumber0Reverb preset: 0 = none, 1 = small room, 2 = medium room, 3 = large hall, 4 = cave
occlusionFactornumber0.0Occlusion amount (0.0 = clear, 1.0 = fully muffled)
activebooleantrueWhether this zone is active
import { AudioZone } from '@web-engine-dev/core';
// Create a cathedral reverb zone
export default (api) => {
return {
onStart() {
AudioZone.shapeType[api.entity] = 1; // Box
AudioZone.innerRadius[api.entity] = 20.0;
AudioZone.outerRadius[api.entity] = 50.0;
AudioZone.reverbPreset[api.entity] = 3; // Large hall
AudioZone.active[api.entity] = 1;
}
};
};

Available reverb presets:

  • 0 - None — No reverb (dry signal only)
  • 1 - Small Room — Tight reverb, 0.5s decay
  • 2 - Medium Room — Moderate reverb, 1.0s decay
  • 3 - Large Hall — Spacious reverb, 2.5s decay
  • 4 - Cave — Long reverb, 4.0s decay

Spatial Audio Best Practices#

  • Always add AudioListener — Attach to camera for spatial audio to work
  • Set realistic distances — Match refDistance and maxDistance to your game's scale
  • Test with headphones — HRTF panning is most effective with headphones
  • Use appropriate rolloff — Higher rolloff for small sounds, lower for large sounds
  • Mind the performance — Spatial audio is more expensive than 2D audio
  • Use Audio LOD — Let distant sounds reduce quality automatically
  • Place sounds carefully — Position matters! Place campfire at fire, not player

Example: Environmental Waterfall#

export default (api) => {
return {
onStart() {
// Position waterfall in world
api.position = { x: 50, y: 10, z: 30 };
// Configure spatial audio
AudioSource.assetId[api.entity] = waterfallSoundId;
AudioSource.spatial[api.entity] = 1;
AudioSource.spatialBlend[api.entity] = 1.0; // Full 3D
// Waterfall is loud up close, audible from distance
AudioSource.refDistance[api.entity] = 10.0; // Full volume within 10 units
AudioSource.maxDistance[api.entity] = 200.0; // Fade out by 200 units
AudioSource.rolloffFactor[api.entity] = 0.7; // Slow falloff (large sound source)
// Waterfall loops continuously
AudioSource.loop[api.entity] = 1;
AudioSource.volume[api.entity] = 0.6; // Not too loud
AudioSource.group[api.entity] = 0; // SFX channel
// Start playing
AudioSource.playing[api.entity] = 1;
}
};
};
Audio | Web Engine Docs | Web Engine Docs