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.
| 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:
- Find your main camera entity
- Add the
AudioListenercomponent - Set active to
true - 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 positionexport 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 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 falloffPanning 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 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 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:
| 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; // 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; } };};