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

audio-ambient-light

v1.0.0

Published

Audio-reactive ambient light visualization library for Web Audio API

Readme

🎵 Audio Ambient Light

npm version license

Audio-reactive ambient light visualization library for Web Audio API. Create beautiful, responsive light effects that dance to your music.

✨ Features

  • 🎵 Audio Processing Core - Converts frequency data to energy values (0-1)
  • 🌉 Bridge Pattern - Manages data flow between audio source and visualization
  • 🎨 DOM Renderer - Smooth animations with configurable appearance
  • 🌈 Gradient Presets - Built-in beautiful gradient color themes
  • 🎭 Custom Gradients - Define your own color arrays for unique effects
  • 📡 Event System - Subscribe to peaks, silence, and update events
  • Zero Dependencies - Lightweight and framework-agnostic
  • 🚀 High Performance - Optimized processing and CSS-variable-based rendering
  • 📦 Multiple Formats - ESM, CJS, and IIFE (browser) builds

📦 Installation

# npm
npm install audio-ambient-light

# pnpm
pnpm add audio-ambient-light

# yarn
yarn add audio-ambient-light

🚀 Quick Start

Browser (CDN/IIFE)

<div id="visualizer" style="width: 80px; height: 400px;"></div>

<script src="https://unpkg.com/audio-ambient-light/dist/index.global.js"></script>
<script>
  const renderer = new AmbientLight.AmbientLightRenderer({
    container: document.getElementById('visualizer'),
    appearance: {
      color: 'gradient-blue-purple',
      gradient: true,
      direction: 'up',
    },
  });

  renderer.mount();

  // Update with audio data (0-1 range)
  renderer.update(0.75);
</script>

ES Module

import {
  AmbientLightCore,
  AmbientLightBridge,
  AmbientLightRenderer,
} from 'audio-ambient-light';

// 1. Create renderer
const renderer = new AmbientLightRenderer({
  container: document.getElementById('visualizer')!,
  appearance: {
    color: 'gradient-rainbow',
    gradient: true,
  },
});
renderer.mount();

// 2. Create core processor
const core = new AmbientLightCore();

// 3. Set up audio analyser (Web Audio API)
const audioContext = new AudioContext();
const analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
const frequencyData = new Uint8Array(analyser.frequencyBinCount);

// 4. Animation loop
function animate() {
  analyser.getByteFrequencyData(frequencyData);
  const energy = core.process(frequencyData);
  if (energy !== null) {
    renderer.update(energy);
  }
  requestAnimationFrame(animate);
}
animate();

With Audio File

// Load and play audio file
const audioContext = new AudioContext();
const analyser = audioContext.createAnalyser();

const response = await fetch('your-audio.mp3');
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);

const source = audioContext.createBufferSource();
source.buffer = audioBuffer;
source.connect(analyser);
analyser.connect(audioContext.destination);
source.start(0);

// Now use the analyser with AmbientLightCore

📖 API Reference

AmbientLightCore

The core audio processing engine.

const core = new AmbientLightCore(config?: Partial<AmbientLightConfig>);

// Process frequency data → returns 0-1 energy value
const energy = core.process(frequencyData: Uint8Array);

// Update configuration
core.setConfig({ minDecibels: -90, bassWeight: 1.2 });

// Get current config
const config = core.getConfig();

// Reset internal state
core.reset();

// Subscribe to events
core.on('peak', ({ value }) => console.log('Peak detected:', value));
core.on('silence', ({ duration }) => console.log('Silence duration:', duration));
core.on('update', ({ value }) => console.log('Energy updated:', value));

AmbientLightRenderer

DOM-based renderer with smooth animations.

const renderer = new AmbientLightRenderer({
  container: HTMLElement,
  side?: 'left' | 'right',
  appearance?: {
    color: string,           // RGB string or 'gradient-{preset}'
    opacity: number,         // 0-1
    shape: 'rounded' | 'rectangle' | 'pill',
    gradient: boolean,       // Enable top fade effect
    border: boolean,         // Enable border
    direction: 'up' | 'center',
    width: number | string,  // Width in % or px (default: 50)
    customGradient?: string[], // Array of RGB strings
  },
  animationConfig?: {
    lerpUp: number,          // Rise speed (0-1)
    lerpDown: number,        // Fall speed (0-1)
    minDiff: number,         // Min change threshold (default: 2)
  },
});

renderer.mount();                        // Mount to container
renderer.update(energy);                 // Update with 0-1 value
renderer.updateAppearance({ color: 'gradient-sunset' });
renderer.updateAnimationConfig({ lerpDown: 0.15 });

// Subscribe to events
renderer.on('update', ({ height }) => console.log('Visual height:', height));
renderer.on('mounted', () => console.log('Renderer mounted'));

renderer.unmount();                      // Cleanup

AmbientLightBridge

Manages the processing loop automatically.

const bridge = new AmbientLightBridge({
  dataProvider: {
    getFrequencyData: () => Uint8Array | null,
    setAnalyserConfig?: (config) => void,
  },
  onData: (value: number) => void,
  onConfig?: (config: AnimationConfig) => void,
  config?: Partial<AmbientLightConfig>,
});

bridge.start();   // Start processing loop
bridge.stop();    // Stop processing loop
bridge.updateConfig({ bassWeight: 1.5 });

🎨 Gradient Presets

| Preset | Colors | |--------|--------| | gradient-blue-purple | Blue → Purple | | gradient-rainbow | Green → Yellow → Red | | gradient-sunset | Pink → Orange-Pink | | gradient-flame | Magenta → Orange | | gradient-ocean | Deep Blue → Cyan | | gradient-forest | Forest Green → Light Green |

import { GRADIENT_PRESETS, isGradientPreset } from 'audio-ambient-light';

// Check if color is a preset
isGradientPreset('gradient-blue-purple'); // true

// Access preset config
console.log(GRADIENT_PRESETS['blue-purple']);
// { colors: ['59, 130, 246', '168, 85, 247'], glowColor: '168, 85, 247' }

📡 Event System

Both Core and Renderer implement a simple event emitter for integration.

Core Events

  • update: Emitted on every energy update.
  • peak: Emitted when energy exceeds the peak threshold.
  • silence: Emitted when no significant audio is detected.

Renderer Events

  • update: Emitted when the visual height changes.
  • mounted: Emitted after the DOM elements are added.
  • unmounted: Emitted after removal.
import { SimpleEventEmitter } from 'audio-ambient-light';

const emitter = new SimpleEventEmitter();
emitter.on('some-event', (data) => { ... });

⚡ Performance Optimization

  • CSS Variables: Styles are applied via CSS variables to minimize DOM style property writes and layout thrashing.
  • TypedArrays: Audio processing uses Uint8Array directly without unnecessary slicing or object creation.
  • Single Pass: RMS and Peak values are calculated in a single loop over frequency data.
  • Batched Updates: Rendering updates are throttled using a configurable minDiff threshold.

⚙️ Configuration

AmbientLightConfig

interface AmbientLightConfig {
  // Sensitivity
  minDecibels: number;        // -100 to 0, filter weak sounds
  maxDecibels: number;        // -100 to 0
  minThreshold: number;       // 0-1, values below become zero

  // Visual
  curveExponent: number;      // 1-3, contrast control
  lerpUp: number;             // 0-1, rise speed
  lerpDown: number;           // 0-1, fall speed
  minDiff: number;            // 0-100, min energy change to emit (Core)

  // ... (Renderer minDiff is set in animationConfig, default 2)

  // Smoothing
  smallChangeThreshold: number;
  smallChangeSmoothing: number;

  // Peak Detection
  rmsWeight: number;          // RMS contribution
  peakWeight: number;         // Peak contribution

  // Spectrum
  fftSize: number;            // 32, 64, 128...
  smoothingTimeConstant: number;
  bassEndRatio: number;       // Bass frequency range
  midEndRatio: number;        // Mid frequency range
  bassWeight: number;         // Bass importance
  midWeight: number;          // Mid importance

  // Normalization
  peaksHistoryLength: number;
  minReferencePeak: number;
}

📊 Output

The core outputs a normalized energy value from 0 to 1:

0.0  → Silent / No audio
0.5  → Medium energy
1.0  → Maximum energy (peak)

The renderer converts this to visual height (0-95% of container).

🔗 Examples

Run the interactive demo:

git clone https://github.com/flystar233/ambient-light.git
cd ambient-light
npm install
npm run build
npm run example

Then open http://localhost:3000/examples/standalone.html

📄 License

MIT © xfly