npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@trap_stevo/voxen

v0.0.2

Published

Unifies interface audio, spatial environments, and intelligent sound behavior inside one modular, extensible system — from reactive UI cues to full 3D soundfields, audio flows with precision, elegance, and control.

Readme

🔊 @trap_stevo/voxen

Universal Sound Intelligence Layer.
Every sound. Every space. One voice.

Unifies interface audio, spatial environments, and intelligent sound behavior inside one modular, extensible system.
From reactive UI cues to full 3D soundfields—audio flows with precision, elegance, and control.


✨ Features

  • 🧭 Universal Spatial Audio — 3D/2D positional playback (HRTF/equal-power) with distance rolloffs & cones
  • 🧩 Plugin Architecture — Built-ins: Occlusion, Proximity, Limiter, Reverb + custom DSP extensions
  • 🎚️ Layered Mixing — Arbitrary buses ("layer:<name>") with smooth volume automation
  • 📦 Direct Sources & Streamingload() for direct refs; auto-decoding + <audio> streaming cache
  • 🧠 AI Hearing Propagationpropagate() / cancelPropagation() waves; occlusion-aware intensity; heard event
  • 🚦 Audience Targeting — Include/exclude/byTag/custom predicates per play/propagation
  • 🚀 Optimized Core — Node pooling (Gain/Panner), audibility culling, guarded listener updates
  • 🗂️ Soundboards — Declarative registries with hierarchical extends and versioning
  • 🧾 Rich Events — Play/fade/updates, plugin diagnostics, preload + propagation lifecycle

⚙️ Constructor

import { Voxen } from "@trap_stevo/voxen";

const voxen = new Voxen({
  cullHz: 60
});

Options

| Option | Type | Default | Description | |---------|---------|---------|-------------| | cullHz | number | 30 | Tick rate for listener and plugin updates |


🧠 Core Concepts

  • Listener – Defines hearing point. Multiple listeners allowed; one active at a time.
  • Soundboard – Groups related sounds; supports overrides and inheritance.
  • Layer – Controls volume and mix per domain (UI, world, music).
  • Plugin – Extends system with DSP or behavioral logic.
  • Propagation – Expanding hearing waves for AI detection and stealth simulation.

⚙️ Core Methods

| Method | Description | Params (summary) | Returns | Async | |---|---|---|---|:---:| | resume() | Unlocks and resumes the AudioContext. | — | Promise<void> | ✅ | | destroy() | Stops all sounds, clears timers/caches, closes context. | — | void | ❌ | | on(type, handler) | Subscribes to an event. | type, handler(payload) | () => void | ❌ | | off(type, handler) | Unsubscribes an event handler. | type, handler | void | ❌ | | registerPlugin(plugin) | Registers a custom plugin. | { name, ... } | void | ❌ | | enableReverb(options?) | Enables built-in reverb bus. | { mix?, ir? } | Promise<void> | ✅ | | disableReverb() | Disables built-in reverb. | — | void | ❌ | | enableLimiter(options?) | Enables built-in limiter. | { threshold?, knee?, ratio?, attack?, release? } | void | ❌ | | disableLimiter() | Disables built-in limiter. | — | void | ❌ | | enableOcclusion(options?) | Enables occlusion (raycast-aware). | { raycast?, getListenerPosition?, maxAttenuation?, smoothing? } | void | ❌ | | disableOcclusion() | Disables occlusion. | — | void | ❌ | | setProximityTriggers(options) | Starts/updates proximity trigger loop. | { getListenerPosition, getInstancePosition?, triggers[], tickHz?, distance? } | void | ❌ | | registerSoundboard(board) | Registers a soundboard. | { name, items, extends? } | void | ❌ | | useSoundboards(names) | Activates soundboards (topmost wins). | string[] | void | ❌ | | contains(id) | Checks if an active soundboard has id. | string | boolean | ❌ | | preload(ids) | Prepares/decodes assets by ids. | string[] | Promise<void> | ✅ | | addListener(listener) | Adds a listener. | { id, position, orientation?, tags? } | void | ❌ | | updateListener(id, patch) | Patches listener fields. | string, { position?, orientation?, tags? } | void | ❌ | | removeListener(id) | Removes a listener. | string | void | ❌ | | setActiveListener(id) | Sets active listener and applies to context. | string | void | ❌ | | load(soundId, sourceRef, defaults?) | Registers & prepares a direct sound. | string, SourceRef, { loop?, volume?, pitch?, distance? } | Promise<void> | ✅ | | play(idOrDirect, opts?) | Plays by soundboard id or direct source. | string | DirectRef, PlayOptions | Promise<string> (instanceId) | ✅ | | stop(instanceId, opts?) | Stops an instance (optional fade). | string, { fadeOut? } | void | ❌ | | updateInstance(instanceId, patch) | Updates volume/pitch/spatial origin. | string, { volume?, pitch?, spatial? } | void | ❌ | | getActiveInstances() | Lists active instance ids. | — | string[] | ❌ | | setVolume(target, value) | Sets "master" or "layer:<name>" volume. | string, 0..1 | void | ❌ | | ensureLayer(name, node?) | Ensures a named layer exists (Gain by default). | string, AudioNode? | void | ❌ | | propagate(options) | Starts an expanding hearing wave. | PropagateOptions | string (token) | ❌ | | cancelPropagation(token, extra?) | Cancels an in-flight wave. | string, { natural? } | void | ❌ |


🔔 Events

| Event | Description | |-------|--------------| | play | Fires when playback starts. | | ended | Fires when playback stops. | | audibility | Signals sound visibility to listener. | | layerVolumeChange | Occurs when layer volume changes. | | pluginError | Reports plugin failure. | | fadeStart | Marks fade-in or fade-out begin. | | fadeEnd | Marks fade completion. | | instanceUpdate | Reflects runtime parameter change. | | layerMute | Toggles layer mute state. | | preloadComplete | Confirms preload success. | | contextStateChange | Indicates context resume or suspend. | | propagateStart | Emitted when a sound wave begins. | | heard | Emitted when a listener perceives a propagated sound. | | propagateEnd | Fired when propagation completes or is canceled. |


📘 Parameter Reference

This section defines the shapes and defaults of Voxen’s primary configuration objects. All objects are plain JSON-like structures; functions are allowed where noted (e.g., for live positions).

🔤 Common Scalar & Utility Types

| Type | Meaning | |------|--------| | Seconds | Number in seconds (e.g., 0.25) | | Hertz | Number in Hz (e.g., 60) | | Decibels | Number in dBFS for WebAudio nodes (e.g., -3) | | Linear01 | Number clamped to 0..1 | | Vec3 | { x:number, y:number, z:number } | | Vec3Fn | () => Vec3 (evaluated per frame/tick) | | TimeFn<T> | T | (() => T) — static value or function return |


🗂️ Sound Sources

SourceRef

A reference to media to be decoded or streamed.

| Field | Type | Required | Notes | |------|------|----------|------| | kind | "url" | "element" | "buffer" | ✅ | How audio is provided | | href | string | ⬅ when kind:"url" | Absolute/relative URL | | element | HTMLMediaElement | ⬅ when kind:"element" | <audio> or <video> | | buffer | AudioBuffer | ⬅ when kind:"buffer" | Pre-decoded PCM | | stream | boolean | ❌ | If true, uses media element streaming path | | loop | boolean | ❌ | Default loop behavior (can be overridden) | | mime | string | ❌ | Hint (e.g., "audio/ogg") |

DirectRef

Play without a soundboard entry.

| Field | Type | Required | Notes | |------|------|----------|------| | id | string | ✅ | Logical id for this sound | | sources | SourceRef[] | ✅ | One or more fallbacks | | meta | Partial<PlayDefaults> | ❌ | Default volume/pitch/distance/loop |


🧭 Spatial & Distance

DistanceModel

"inverse" | "linear" | "exponential"

DistanceOptions

| Field | Type | Default | Notes | |------|------|---------|------| | refDistance | number | 1 | Distance at which volume is 100% | | maxDistance | number | 10000 | Beyond this, no further attenuation | | rolloff | DistanceModel | "inverse" | Attenuation curve | | coneInner | number | 360 | Degrees of full volume | | coneOuter | number | 360 | Degrees at outer cone edge | | coneOuterGain | Linear01 | 0 | Gain at outer cone edge |

SpatialOptions

| Field | Type | Required | Default | Notes | |------|------|----------|---------|------| | origin | TimeFn<Vec3> | ✅ | — | World position of emitter | | forward | TimeFn<Vec3> | ❌ | {0,0,1} | Emitter forward vector | | up | TimeFn<Vec3> | ❌ | {0,1,0} | Emitter up vector | | distance | DistanceOptions | ❌ | see above | Distance/cone controls | | hrtf | boolean | ❌ | true | If false, uses equal-power panner | | stereo | boolean | ❌ | false | If true, bypasses HRTF for stereo sources |


🎚️ Playback

FadeOptions

| Field | Type | Default | Notes | |------|------|---------|------| | in | Seconds | 0 | Fade-in duration | | out | Seconds | 0 | Fade-out duration |

PlayDefaults

| Field | Type | Default | Notes | |------|------|---------|------| | volume | Linear01 | 1.0 | Base gain | | pitch | number | 1.0 | PlaybackRate | | loop | boolean | false | Looping behavior | | distance | DistanceOptions | — | If spatialized |

PlayOptions

| Field | Type | Default | Notes | |------|------|---------|------| | layer | string | "master" | Route to "layer:<name>" | | volume | Linear01 | inherits | Overrides default | | pitch | number | 1.0 | 0.5 = down octave, 2.0 = up octave | | loop | boolean | inherits | — | | spatial | SpatialOptions | — | Enables 3D/2D panning | | fade | FadeOptions | {} | Smooth in/out | | tags | string[] | [] | Arbitrary metadata tags | | audience | Audience | — | Targeting rules (see below) | | onEnd | () => void | — | Convenience callback |

updateInstance(instanceId, patch)

| Field | Type | Notes | |------|------|------| | volume | Linear01 | Smooth internal ramping | | pitch | number | PlaybackRate update | | spatial | Partial<SpatialOptions> | Live move/aim updates | | layer | string | Re-route to a different bus |


🧑‍🦻 Audience Targeting

Use to filter who can hear a sound or who participates in a propagation wave.

Audience

A discriminated union:

type Audience =
  | { kind:"all" }
  | { kind:"include"; ids:string[] }
  | { kind:"exclude"; ids:string[] }
  | { kind:"byTag"; tags:string[] }
  | { kind:"predicate"; test:(meta:{ id:string; tags?:string[]; extra?:any }) => boolean }
  • When used for playback, audience is applied at instance connect time.
  • When used for propagate(), audience is sampled per wavefront step.

🛰️ Propagation (AI Hearing)

PropagateOptions

| Field | Type | Required | Default | Notes | |------|------|----------|---------|------| | origin | TimeFn<Vec3> | ✅ | — | Source of the wave | | power | number | ✅ | — | Scalar “loudness” that maps to effective radius | | maxRadius | number | ✅ | — | Upper bound for distance check | | velocity | number | ❌ | 343 | m/s (speed of sound at ~20°C) | | sampleHz | Hertz | ❌ | 30 | Wave stepping rate | | decay | Linear01 | ❌ | 0.0 | Per-meter loss beyond distance model | | occlusionAware | boolean | ❌ | false | Enables raycast penalty | | occlusionPenalty | Linear01 | ❌ | 0.5 | Additional attenuation when blocked | | audience | Audience | ❌ | {kind:"all"} | Target listeners/entities | | tags | string[] | ❌ | [] | Labels attached to heard events | | token | string | ❌ | auto | Return value; can be supplied for idempotence |

Events (Propagation)

  • propagateStart{ token, origin, power, maxRadius }
  • heard{ token, listenerId, distance, intensity, tags }
  • propagateEnd{ token, reason:"completed"|"canceled" }

🧲 Proximity Triggers

setProximityTriggers(options)

| Field | Type | Required | Default | Notes | |------|------|----------|---------|------| | getListenerPosition | () => Vec3 | ✅ | — | Primary tracked subject | | getInstancePosition | (id:string) => Vec3 | ❌ | — | Resolve instance anchor | | triggers | ProximityTrigger[] | ✅ | — | Zones to monitor | | tickHz | Hertz | ❌ | 30 | Polling rate | | distance | { metric?:"euclidean"|"manhattan" } | ❌ | "euclidean" | Distance metric |

ProximityTrigger

| Field | Type | Required | Default | Notes | |------|------|----------|---------|------| | id | string | ✅ | — | Unique zone id | | position | TimeFn<Vec3> | ✅ | — | Center of zone | | radius | number | ✅ | — | Meters | | hysteresis | number | ❌ | 0.0 | Entry/exit stability band | | cooldown | Seconds | ❌ | 0.0 | Rate limit events | | enterPlay | { soundId:string, options?:PlayOptions } | ❌ | — | Fire on first entry | | exitPlay | { soundId:string, options?:PlayOptions } | ❌ | — | Fire on first exit | | tags | string[] | ❌ | [] | Zone metadata |

Events:

  • proximityEnter{ id, position }
  • proximityExit{ id, position }

🧱 Occlusion Plugin

enableOcclusion(options)

| Field | Type | Required | Default | Notes | |------|------|----------|---------|------| | raycast | (from:Vec3, to:Vec3) => boolean | ✅ | — | true if blocked | | getListenerPosition | () => Vec3 | ✅ | — | For primary listener | | maxAttenuation | Linear01 | ❌ | 0.55 | Max gain drop when blocked | | smoothing | Seconds | ❌ | 0.08 | Attack/release toward target | | bypassLayers | string[] | ❌ | [] | Skip occlusion on these buses |


🧰 Limiter Plugin

enableLimiter(options)

| Field | Type | Default | Notes | |------|------|---------|------| | threshold | Decibels | -1.0 | Compressor threshold | | knee | Decibels | 0.0 | Soft knee amount | | ratio | number | 8.0 | Compression ratio | | attack | Seconds | 0.005 | Attack time | | release | Seconds | 0.100 | Release time | | makeupGain | Decibels | 0.0 | Optional post-comp gain | | bypassLayers | string[] | [] | Do not route these layers through limiter (alias: excludeLayers) |

Recommended: bypass UI, keep world/music under control.

engine.enableLimiter({
  threshold : -3, ratio : 12, attack : 0.003, release : 0.120,
  bypassLayers : ["ui"]
});

🌫️ Reverb Bus

enableReverb(options)

| Field | Type | Default | Notes | |------|------|---------|------| | mix | Linear01 | 0.2 | Wet contribution on master | | ir | AudioBuffer | URL | builtin | Convolution impulse response | | preDelay | Seconds | 0.0 | Optional pre-delay | | decay | Seconds | 1.2 | Tail shaping (when using algorithmic IR) | | bypassLayers | string[] | [] | Do not send these layers to reverb |


🎛️ Mixing & Layers

  • setVolume("master", value) — Set master gain.
  • setVolume("layer:<name>", value) — Set per-bus gain.
  • ensureLayer(name, node?) — Create a custom bus (default GainNode); you can pass a pre-wired AudioNode for advanced routing (e.g., side-chains).

👂 Listeners

addListener(listener)

| Field | Type | Required | Default | Notes | |------|------|----------|---------|------| | id | string | ✅ | — | Unique id | | position | TimeFn<Vec3> | ✅ | — | Ear position | | orientation.forward | TimeFn<Vec3> | ❌ | {0,0,-1} | Facing | | orientation.up | TimeFn<Vec3> | ❌ | {0,1,0} | Up vector | | tags | string[] | ❌ | [] | Audience/meta |

setActiveListener(id) switches the engine to drive WebAudio’s AudioListener from this definition.


🧩 Plugin Hook Context (ctx)

Hook argument available to beforeConnect, afterConnect, frame, onStop.

type PluginCtx = {
  engine : Voxen;
  audioCtx : AudioContext;
  nodes : {
    source : AudioNode;
    gain : GainNode;
    layer : GainNode;      // or custom node if provided
    master : GainNode;
  };
  layer : string;          // "master" or "layer:<name>"
  contextTime : number;    // audioCtx.currentTime
  instanceId : string;     // current play instance
  meta? : any;             // item meta / tags
};

📡 Events (Payload Shapes)

  • play{ instanceId, id, layer, tags? }
  • ended{ instanceId, id, reason:"natural"|"stop"|"error" }
  • audibility{ instanceId, audible:boolean }
  • layerVolumeChange{ layer, value }
  • pluginError{ plugin, error }
  • fadeStart{ instanceId, kind:"in"|"out", duration }
  • fadeEnd{ instanceId, kind:"in"|"out" }
  • instanceUpdate{ instanceId, patch }
  • preloadComplete{ ids:string[] }
  • contextStateChange{ state:"running"|"suspended"|"closed" }
  • proximityEnter / proximityExit{ id, position }
  • propagateStart / heard / propagateEnd — see Propagation above

📦 Installation

npm install @trap_stevo/voxen

# or

yarn add @trap_stevo/voxen

⚡ Quick Start & Examples

Example 1 — UI Click

import { Voxen } from "@trap_stevo/voxen";

const voxen = new Voxen();

voxen.registerSoundboard({
  name: "ui",
  items: [
    {
      id: "ui/click",
      sources: [{ kind: "url", href: "https://upload.wikimedia.org/wikipedia/commons/2/26/Computer_mouse_single_click.ogg" }],
      meta: { volume: 0.85 }
    }
  ]
});

voxen.useSoundboards(["ui"]);
await voxen.preload(["ui/click"]);
await voxen.resume();

document.addEventListener("click", () => voxen.play("ui/click", { layer: "ui" }));

Example 2 — 3D Fountain Ambience

voxen.addListener({
  id: "listener",
  position: () => ({ x: camera.x, y: camera.y, z: camera.z }),
  orientation: {
    forward: () => camera.forward(),
    up: () => ({ x: 0, y: 1, z: 0 })
  }
});
voxen.setActiveListener("listener");

voxen.registerSoundboard({
  name: "scene",
  items: [
    {
      id: "env/fountain",
      sources: [{ kind: "url", href: "https://upload.wikimedia.org/wikipedia/commons/5/54/Fountainnoise.ogg" }],
      meta: { loop: true, volume: 0.85, distance: { refDistance: 1, maxDistance: 45 } }
    }
  ]
});

voxen.useSoundboards(["scene"]);
await voxen.preload(["env/fountain"]);
await voxen.play("env/fountain", {
  spatial: {
    origin: () => ({ x: 6, y: 0.5, z: -10 }),
    distance: { refDistance: 1, maxDistance: 45 },
    hrtf: true
  },
  layer: "ambient",
  fade: { in: 1.0 }
});

Example 3 — Proximity + Occlusion + AI Propagation

voxen.enableOcclusion({
  raycast: (from, to) => performRaycast(from, to),
  getListenerPosition: () => player.position,
  maxAttenuation: 0.55,
  smoothing: 0.08
});

voxen.setProximityTriggers({
  getListenerPosition: () => player.position,
  triggers: [
    {
      id: "pickup-zone",
      position: { x: 5, y: 0, z: -8 },
      radius: 1.5,
      enterPlay: { soundId: "ui/click", options: { layer: "ui" } }
    }
  ],
  tickHz: 45
});

// AI Hearing Example
voxen.on("heard", e => console.log("AI heard:", e.listenerId, e.tags));

voxen.propagate({
  origin: () => player.position,
  power: 1,
  maxRadius: 40,
  velocity: 343,
  sampleHz: 30,
  audience: { kind: "byTag", tags: ["ai"] },
  occlusionAware: true,
  occlusionPenalty: 0.6
});

Example 4 — Layer Mixing & Live Updates

voxen.setVolume("layer:ambient", 0.3);
voxen.updateInstance(fountainId, { pitch: 1.15 });
voxen.stop(fountainId, { fadeOut: 0.5 });

🧩 Custom Plugin API

Custom DSP, analyzers, or automation logic can slot directly into the playback chain.

Configuration Hooks

| Hook | Trigger | Description | |------|----------|-------------| | onRegister({ engine, audioCtx }) | Plugin registration | Prepare nodes or parameters. | | beforeConnect(ctx, node) | Before connection | Insert filters, delays, or custom nodes. | | afterConnect(ctx) | After connection | Run post-setup logic. | | frame(ctx, dt) | Every tick (cullHz) | Update dynamic parameters. | | onStop(ctx) | Sound stop | Clean resources. |

Usage Example

const EchoPlugin = {
  name: "custom:echo",

  onRegister({ audioCtx }) {
    this.delay = audioCtx.createDelay();
    this.delay.delayTime.value = 0.3;
    this.feedback = audioCtx.createGain();
    this.feedback.gain.value = 0.4;
    this.delay.connect(this.feedback);
    this.feedback.connect(this.delay);
  },

  beforeConnect(ctx, node) {
    node.connect(this.delay);
    return this.delay;
  },

  frame(ctx, dt) {
    const g = ctx.nodes.gain.gain.value;
    this.feedback.gain.setTargetAtTime(g * 0.4, ctx.nodes.master.contextTime, 0.05);
  },

  onStop() {
    this.delay.disconnect();
    this.feedback.disconnect();
  }
};

voxen.registerPlugin(EchoPlugin);

⚡ Performance & Integration Notes

🎛️ Plugin Chain Order

Source → [Plugin.beforeConnect nodes] → preGain → gain → layer → master → destination

Use beforeConnect for filters or delays.
Use custom layers for post-processing or global DSP.

🧮 Frame Efficiency

Set cullHz to match simulation tick:

  • 90 Hz for rhythmic or rapid feedback loops
  • 30–45 Hz for dense spatial environments

🧠 Memory & Pooling

Gain and Panner nodes reuse pooled memory.
Inactive nodes disconnect automatically.
Streamed sources skip redundant decoding.

⚡ Latency Control

Chromium engines reach sub-5 ms latency with preloaded buffers.
Call .preload() before playback to prevent decode delays.
Trigger .resume() once after user gesture to unlock playback.

🕹️ Integration Guidelines

Three.js

  • Update listener in render loop via updateListener().
  • Pass camera.getWorldPosition() and camera.getWorldDirection().

Babylon.js

  • Hook into camera.onViewMatrixChangedObservable.

React / DOM

  • Resume audio after click:
    useEffect(() => {
      const click = () => voxen.play("ui/click");
      document.addEventListener("click", click);
      return () => document.removeEventListener("click", click);
    }, []);

Physics Engines

  • Provide world coordinates in spatial.origin.
  • Interpolation handled internally.

🧭 Debugging

Monitor pluginError for DSP exceptions.
Audit getActiveInstances() for pool usage.
Trace audibility for live diagnostics:

voxen.on("audibility", e => console.log("Audible:", e.audible));

🚀 Best Practice Summary

| Area | Action | |------|--------| | Update Rate | Maintain 30–60 Hz listener updates | | Buffering | Preload every large asset | | Layers | Separate UI, World, Music buses | | Plugins | Register once; reuse globally | | Stop | Fade out softly to avoid clicks | | Environment | Use 48 kHz audio contexts for consistency |


📜 License

See License in LICENSE.md


🔊 Orchestrate Sound. One Voice.

Unify UI clicks, spatial worlds, and cinematic layers into one deterministic audio fabric. From web apps to 3D games, Voxen delivers low-latency playback, precise spatialization, and event-driven control—so sound design scales with your vision, not your constraints. Every sound. Every space. One voice.