glsl-audio-visualizer
v1.0.4
Published
A WebGL particle sphere that reacts to audio. Drop it into any DOM element — it handles everything else.
Readme
glsl-audio-visualizer
A WebGL particle sphere that reacts to audio. Drop it into any DOM element — it handles everything else.
Inspired by the NCS-style visualizers with the neon glow and bass drops.
Install
npm install glsl-audio-visualizer threethree is a peer dependency — you need it installed separately.
Quick start
import { GLSLAudioVisualizer } from 'glsl-audio-visualizer';
const viz = new GLSLAudioVisualizer(document.getElementById('container')!);
// Load an audio file
fileInput.addEventListener('change', (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (file) viz.loadAudio(file);
});
// Clean up when done
viz.dispose();The container must have explicit dimensions (width + height). The canvas fills it 100%.
Constructor
new GLSLAudioVisualizer(container: HTMLElement, options?: DeepPartial<VisualizerConfig>)All config options are optional — defaults are applied for anything you don't specify:
const viz = new GLSLAudioVisualizer(el, {
color: {
mode: 'gradient',
colors: ['#ff0000', '#00aaff', '#00ff88'],
},
sphere: { baseRadius: 1.2 },
bloom: { strength: 0.4 },
});Config
The config is split into groups matching the visual sections.
color
| Property | Type | Default | Description |
|------------|-------------|----------------------|-------------|
| mode | ColorMode | 'audio' | How colors are applied (see modes below) |
| colors | string[] | ['#fa0000','#0066ff'] | Color palette — 1 to 16 hex colors |
| hueSpeed | number | 0.05 | Rotation speed for hue mode |
Color modes:
solid— uses the first colorgradient— blends across the color array by vertical positionaudio— blends across the color array by energy levelhue— rainbow hue rotation, uses first color as base
sphere
| Property | Type | Default | Description |
|-------------|----------|---------|-------------|
| baseRadius | number | 1.4 | Base sphere size |
| bassScale | number | 0.5 | How much bass expands the radius |
| feather | number | 0.45 | Softness of the sphere edge |
displacement
| Property | Type | Default | Description |
|------------|----------|---------|-------------|
| amplitude | number | 0.35 | Maximum particle displacement |
| noiseScale| number | 2.2 | Scale of the noise pattern |
| flowSpeed | number | 0.15 | Animation speed of the noise |
particles
| Property | Type | Default | Description |
|-----------|----------|---------|-------------|
| size | number | 5.0 | Base particle size in pixels |
| opacity | number | 0.4 | Particle opacity (additive blending, keep low) |
| softness | number | 0.12 | Edge softness of each particle |
| sparkle | number | 1.5 | How much energy adds size variance |
| variance | number | 0.25 | Noise-based color variance per particle |
bloom
| Property | Type | Default | Description |
|------------|----------|---------|-------------|
| strength | number | 0.15 | Bloom/glow intensity |
| radius | number | 0.85 | Bloom spread radius |
| threshold | number | 0.0 | Minimum brightness to bloom |
audio
| Property | Type | Default | Description |
|--------------|----------|---------|-------------|
| attackSpeed | number | 0.3 | How fast the sphere reacts to beats (0–1) |
| releaseSpeed| number | 0.05 | How fast it decays after a beat (0–1) |
| bassBoost | number | 0.5 | Bass frequency amplification |
| energyBoost | number | 1.0 | Overall energy amplification |
API
Audio
viz.loadAudio(file: File): Promise<void>
viz.play(): void
viz.pause(): void
viz.togglePlay(): void
viz.seek(ratio: number): void // 0–1
viz.eject(): voidExternal audio source
Connect any Web Audio API node — microphone, oscillator, media element, etc:
// Microphone
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const ctx = viz.getAudioContext();
const source = ctx.createMediaStreamSource(stream);
viz.connectNode(source);
// HTML <audio> element
const source = ctx.createMediaElementSource(audioEl);
viz.connectNode(source);State
// Subscribe to playback state changes
viz.onAudioStateChange = (state) => {
console.log(state.playing, state.progress, state.trackName);
console.log(state.currentTime, state.duration);
};
// Read current state
const state = viz.audioState;Config
// Update any subset of config at runtime — other values are preserved
viz.setConfig({ bloom: { strength: 1.0 } });
viz.setConfig({ color: { mode: 'hue', colors: ['#ff00ff'] } });
// Read current config
const cfg = viz.getConfig();Lifecycle
viz.dispose() // cancels RAF, releases GPU resources, removes canvasBackground
Background is controlled via CSS on the container — not through the config. The canvas is always transparent:
#container {
background: #000; /* solid black */
background: transparent; /* see-through */
background: rgba(0,0,0,0.5); /* semi-transparent */
}This keeps the WebGL bloom pipeline clean and lets you composite the sphere over any content.
TypeScript
All config types are exported:
import type {
VisualizerConfig,
ColorConfig,
SphereConfig,
DisplacementConfig,
ParticlesConfig,
BloomConfig,
AudioConfig,
AudioState,
ColorMode,
DeepPartial,
} from 'glsl-audio-visualizer';Playground (dev)
The repo includes a Vue playground with a full settings panel:
npm install
npm run dev # start playground at localhost:5173
npm run build # build playground for GitHub Pages
npm run build:lib # build the library into dist/How it works
- 262,144 particles on a 512×512 grid, projected onto a sphere
- Simplex 3D noise (Ashima Arts) drives displacement — three swizzled axes for smooth 3D flow
- Bass expands the sphere radius with a quadratic response curve (weak bass barely registers, strong beats punch hard)
- Energy drives displacement amplitude — gated by bass so the sphere stays calm without beats
- UnrealBloomPass (Three.js post-processing) for the glow effect
- AdditiveBlending — works best on dark backgrounds
- Up to 16 colors interpolated across the palette based on mode
License
MIT
