or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

global-audio.mdindex.mdsound-playback.mdspatial-audio.md
tile.json

spatial-audio.mddocs/

Spatial Audio

The spatial audio plugin extends Howler.js with 3D positional audio capabilities and stereo panning, enabling immersive audio experiences with realistic spatial positioning, orientation, and distance-based attenuation.

Capabilities

Stereo Panning

Control stereo positioning of sounds across the left-right audio field.

/**
 * Helper method to update stereo panning position globally
 * @param pan - Panning value (-1.0 = full left, 0.0 = center, 1.0 = full right)
 * @returns Howler instance for chaining
 */
Howler.stereo(pan: number): Howler;

/**
 * Set stereo panning for specific sound or sound group
 * @param pan - Panning value (-1.0 to 1.0)
 * @param id - Sound ID (optional, affects all sounds in group if not provided)
 * @returns Current panning if getting, Howl instance if setting
 */
Howl.prototype.stereo(pan: number, id?: number): Howl | number;

Usage Examples:

import { Howl, Howler } from "howler";

// Global stereo panning for all sounds
Howler.stereo(-0.5); // Pan all sounds to the left

// Per-sound stereo panning
const leftSound = new Howl({
  src: ['left.mp3']
});

const rightSound = new Howl({
  src: ['right.mp3']
});

leftSound.stereo(-1.0);  // Full left
rightSound.stereo(1.0);  // Full right

// Control specific sound instances
const id = leftSound.play();
leftSound.stereo(0.5, id); // Pan this specific instance to the right

// Get current panning
const currentPan = leftSound.stereo(); // Returns number

3D Listener Position

Set the position of the audio listener in 3D space, affecting how all positioned sounds are heard.

/**
 * Get/set the position of the listener in 3D cartesian space
 * @param x - The x-position of the listener
 * @param y - The y-position of the listener (optional)
 * @param z - The z-position of the listener (optional)
 * @returns Current position array if getting, Howler instance if setting
 */
Howler.pos(x: number, y?: number, z?: number): Howler | number[];

Usage Examples:

// Set listener position
Howler.pos(0, 0, 0); // Center position
Howler.pos(10, 5, -2); // Move listener to specific coordinates

// Get current listener position
const listenerPos = Howler.pos(); // Returns [x, y, z] array

// Update position over time (e.g., player movement)
function updatePlayerPosition(x, y, z) {
  Howler.pos(x, y, z);
}

3D Listener Orientation

Control the direction the listener is facing and their up vector in 3D space.

/**
 * Get/set the direction the listener is pointing in 3D space
 * @param x - The x-orientation of the listener's front vector
 * @param y - The y-orientation of the listener's front vector  
 * @param z - The z-orientation of the listener's front vector
 * @param xUp - The x-orientation of the listener's up vector
 * @param yUp - The y-orientation of the listener's up vector
 * @param zUp - The z-orientation of the listener's up vector
 * @returns Current orientation vectors if getting, Howler instance if setting
 */
Howler.orientation(x: number, y: number, z: number, xUp: number, yUp: number, zUp: number): Howler | number[];

Usage Examples:

// Set listener to face forward with normal up vector
Howler.orientation(0, 0, -1, 0, 1, 0);

// Face right
Howler.orientation(1, 0, 0, 0, 1, 0);

// Get current orientation
const orientation = Howler.orientation(); // Returns [x, y, z, xUp, yUp, zUp]

// Rotate listener based on player camera
function updateListenerRotation(forward, up) {
  Howler.orientation(forward.x, forward.y, forward.z, up.x, up.y, up.z);
}

3D Sound Positioning

Position individual sounds in 3D space relative to the listener.

/**
 * Set 3D position for sound or sound group
 * @param x - The x-position of the sound
 * @param y - The y-position of the sound (optional)
 * @param z - The z-position of the sound (optional)
 * @param id - Sound ID (optional, affects all sounds in group if not provided)
 * @returns Current position if getting, Howl instance if setting
 */
Howl.prototype.pos(x: number, y?: number, z?: number, id?: number): Howl | number[];

Usage Examples:

const ambientSound = new Howl({
  src: ['forest.mp3'],
  loop: true
});

const footsteps = new Howl({
  src: ['footsteps.mp3']
});

// Position sounds in 3D space
ambientSound.pos(0, 0, 0);     // Center
footsteps.pos(-5, 0, 10);      // To the left and forward

// Position specific sound instance
const stepId = footsteps.play();
footsteps.pos(2, 0, 5, stepId); // Move this specific footstep

// Get current position
const soundPos = ambientSound.pos(); // Returns [x, y, z]

// Animate sound movement
let x = -10;
setInterval(() => {
  x += 0.1;
  footsteps.pos(x, 0, 0); // Sound moves from left to right
}, 100);

3D Sound Orientation

Set the directional orientation of sounds for directional audio effects.

/**
 * Set 3D orientation for sound
 * @param x - The x-orientation of the sound's front vector
 * @param y - The y-orientation of the sound's front vector
 * @param z - The z-orientation of the sound's front vector  
 * @param id - Sound ID (optional, affects all sounds in group if not provided)
 * @returns Current orientation if getting, Howl instance if setting
 */
Howl.prototype.orientation(x: number, y: number, z: number, id?: number): Howl | number[];

Advanced Panner Attributes

Configure detailed 3D audio properties for realistic sound attenuation and directional effects.

/**
 * Set 3D panner attributes for realistic audio positioning
 * @param o - Panner attributes object (optional for getting current attributes)
 * @param id - Sound ID (optional, affects all sounds in group if not provided)
 * @returns Current attributes if getting, Howl instance if setting
 */
Howl.prototype.pannerAttr(o?: PannerAttributes, id?: number): Howl | PannerAttributes;

interface PannerAttributes {
  /** Inner cone angle in degrees (default: 360) */
  coneInnerAngle?: number;
  /** Outer cone angle in degrees (default: 360) */  
  coneOuterAngle?: number;
  /** Gain outside the outer cone (0.0-1.0, default: 0) */
  coneOuterGain?: number;
  /** Distance model for attenuation ('inverse' | 'linear' | 'exponential') */
  distanceModel?: 'inverse' | 'linear' | 'exponential';
  /** Maximum distance for attenuation (default: 10000) */
  maxDistance?: number;
  /** Panning model ('equalpower' | 'HRTF') */
  panningModel?: 'equalpower' | 'HRTF';
  /** Reference distance for attenuation (default: 1) */
  refDistance?: number;
  /** Rolloff factor for attenuation (default: 1) */
  rolloffFactor?: number;
}

Usage Examples:

const directionalSound = new Howl({
  src: ['speaker.mp3'],
  loop: true
});

// Configure realistic speaker characteristics
directionalSound.pannerAttr({
  coneInnerAngle: 40,        // 40-degree inner cone
  coneOuterAngle: 120,       // 120-degree outer cone  
  coneOuterGain: 0.3,        // 30% volume outside cone
  distanceModel: 'inverse',   // Realistic distance falloff
  maxDistance: 100,          // Inaudible beyond 100 units
  refDistance: 1,            // Full volume at 1 unit
  rolloffFactor: 2,          // Faster distance falloff
  panningModel: 'HRTF'       // Head-related transfer function
});

// Position and orient the directional sound
directionalSound.pos(0, 0, 10);        // 10 units forward
directionalSound.orientation(0, 0, -1); // Pointing toward listener

// Get current panner attributes
const attrs = directionalSound.pannerAttr();
console.log(attrs.coneInnerAngle); // 40

Spatial Audio Patterns

Game Audio Positioning

class GameAudio {
  constructor() {
    this.sounds = new Map();
    
    // Initialize listener at player position
    Howler.pos(0, 0, 0);
    Howler.orientation(0, 0, -1, 0, 1, 0);
  }
  
  createPositionalSound(name, src, loop = false) {
    const sound = new Howl({
      src: src,
      loop: loop
    });
    
    // Configure for realistic 3D audio
    sound.pannerAttr({
      distanceModel: 'inverse',
      maxDistance: 50,
      refDistance: 1,
      rolloffFactor: 1.5
    });
    
    this.sounds.set(name, sound);
    return sound;
  }
  
  updatePlayerPosition(x, y, z, forwardX, forwardY, forwardZ) {
    Howler.pos(x, y, z);
    Howler.orientation(forwardX, forwardY, forwardZ, 0, 1, 0);
  }
  
  playAt(soundName, x, y, z) {
    const sound = this.sounds.get(soundName);
    if (sound) {
      sound.pos(x, y, z);
      return sound.play();
    }
  }
}

// Usage
const gameAudio = new GameAudio();
gameAudio.createPositionalSound('gunshot', ['gunshot.mp3']);
gameAudio.createPositionalSound('footsteps', ['footsteps.mp3']);

// Play sound at specific location
gameAudio.playAt('gunshot', -10, 0, 5);

Dynamic Stereo Effects

// Create moving stereo effect
const movingSound = new Howl({
  src: ['car.mp3'],
  loop: true
});

// Animate from left to right
let pan = -1.0;
const moveTimer = setInterval(() => {
  movingSound.stereo(pan);
  pan += 0.1;
  
  if (pan > 1.0) {
    pan = -1.0; // Reset to left
  }
}, 100);

movingSound.play();

Environmental Audio Zones

class AudioZone {
  constructor(sound, centerX, centerZ, radius, maxVolume = 1.0) {
    this.sound = sound;
    this.centerX = centerX;
    this.centerZ = centerZ;
    this.radius = radius;
    this.maxVolume = maxVolume;
    this.soundId = null;
  }
  
  updateVolume(listenerX, listenerZ) {
    const distance = Math.sqrt(
      Math.pow(listenerX - this.centerX, 2) + 
      Math.pow(listenerZ - this.centerZ, 2)
    );
    
    if (distance <= this.radius) {
      const volume = this.maxVolume * (1 - (distance / this.radius));
      
      if (!this.soundId) {
        this.soundId = this.sound.play();
      }
      
      this.sound.volume(volume, this.soundId);
    } else if (this.soundId) {
      this.sound.stop(this.soundId);
      this.soundId = null;
    }
  }
}

// Create environmental zones
const forestZone = new AudioZone(
  new Howl({ src: ['forest.mp3'], loop: true }),
  0, 0, 20, 0.8
);

const riverZone = new AudioZone(
  new Howl({ src: ['river.mp3'], loop: true }),
  30, 10, 15, 0.6
);

// Update as player moves
function updateEnvironmentalAudio(playerX, playerZ) {
  forestZone.updateVolume(playerX, playerZ);
  riverZone.updateVolume(playerX, playerZ);
}

Browser Compatibility

Spatial audio features require Web Audio API support:

  • Chrome 14+ - Full support
  • Firefox 25+ - Full support
  • Safari 6+ - Full support
  • Edge 12+ - Full support
  • iOS Safari 6+ - Limited (no HRTF)
  • Android Chrome 25+ - Full support

Graceful Degradation:

// Check for spatial audio support
if (Howler.usingWebAudio && Howler.ctx && Howler.ctx.listener) {
  // Use full spatial audio features
  sound.pos(x, y, z);
  sound.pannerAttr({ panningModel: 'HRTF' });
} else {
  // Fallback to stereo panning only
  const pan = (x > 0) ? Math.min(x / 10, 1) : Math.max(x / 10, -1);
  sound.stereo(pan);
}