Javascript audio library for the modern web with Web Audio API and HTML5 Audio support.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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.
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 numberSet 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);
}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);
}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);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[];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); // 40class 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);// 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();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);
}Spatial audio features require Web Audio API 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);
}