Interactive audio waveform rendering and playback library for web applications
—
Comprehensive waveform appearance configuration including colors, styling, dimensions, zoom, and display options for creating visually appealing and functional waveform interfaces.
Configure the target container and waveform dimensions.
interface WaveSurferOptions {
/** Required: HTML element or CSS selector where the waveform will be rendered */
container: HTMLElement | string;
/** The height of the waveform in pixels, or "auto" to fill the container height */
height?: number | 'auto';
/** The width of the waveform in pixels or any CSS value; defaults to 100% */
width?: number | string;
/** Stretch the waveform to fill the container, true by default */
fillParent?: boolean;
}Usage Examples:
// Using CSS selector
const wavesurfer = WaveSurfer.create({
container: "#waveform",
height: 200,
});
// Using DOM element
const container = document.getElementById("my-waveform");
const wavesurfer = WaveSurfer.create({
container: container,
height: "auto", // Fill container height
width: 800,
});
// Responsive sizing
const wavesurfer = WaveSurfer.create({
container: "#responsive-waveform",
height: 150,
fillParent: true, // Fill available width
});Configure waveform colors for wave, progress, and cursor elements.
interface WaveSurferOptions {
/** The color of the waveform - can be solid color, array of colors, or gradient */
waveColor?: string | string[] | CanvasGradient;
/** The color of the progress mask - can be solid color, array of colors, or gradient */
progressColor?: string | string[] | CanvasGradient;
/** The color of the playback cursor */
cursorColor?: string;
/** The cursor width in pixels */
cursorWidth?: number;
}Usage Examples:
// Solid colors
const wavesurfer = WaveSurfer.create({
container: "#waveform",
waveColor: "#4F4A85",
progressColor: "#383351",
cursorColor: "#ffffff",
cursorWidth: 2,
});
// Multi-color waveform for stereo channels
const stereoWaveform = WaveSurfer.create({
container: "#stereo",
waveColor: ["#ff0000", "#0000ff"], // Red for left, blue for right
progressColor: ["#800000", "#000080"], // Darker versions for progress
});
// Using CSS gradients
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const gradient = ctx.createLinearGradient(0, 0, 0, 150);
gradient.addColorStop(0, "#ff0000");
gradient.addColorStop(1, "#0000ff");
const gradientWaveform = WaveSurfer.create({
container: "#gradient",
waveColor: gradient,
});Configure bar-style waveform visualization with spacing and styling options.
interface WaveSurferOptions {
/** If set, the waveform will be rendered with bars like this: ▁ ▂ ▇ ▃ ▅ ▂ */
barWidth?: number;
/** Spacing between bars in pixels */
barGap?: number;
/** Rounded borders for bars (border-radius) */
barRadius?: number;
/** A vertical scaling factor for the waveform */
barHeight?: number;
/** Vertical bar alignment */
barAlign?: 'top' | 'bottom';
}Usage Examples:
// Basic bar visualization
const barWaveform = WaveSurfer.create({
container: "#bars",
barWidth: 3,
barGap: 1,
barRadius: 2,
waveColor: "#4F4A85",
});
// Tall bars aligned to bottom
const tallBars = WaveSurfer.create({
container: "#tall-bars",
barWidth: 4,
barGap: 2,
barHeight: 2, // 2x height scaling
barAlign: "bottom",
barRadius: 3,
});
// Thin separated bars
const thinBars = WaveSurfer.create({
container: "#thin-bars",
barWidth: 1,
barGap: 2,
barRadius: 0,
waveColor: "#333",
});Control waveform zoom level and pixel density for detailed visualization.
interface WaveSurferOptions {
/** Minimum pixels per second of audio (i.e. the zoom level) */
minPxPerSec?: number;
/** Stretch the waveform to the full height */
normalize?: boolean;
}
interface WaveSurfer {
/**
* Zoom the waveform by a given pixels-per-second factor
* @param minPxPerSec - Pixels per second zoom level
*/
zoom(minPxPerSec: number): void;
}Usage Examples:
// High zoom level for detailed view
const detailedWaveform = WaveSurfer.create({
container: "#detailed",
minPxPerSec: 200, // 200 pixels per second
normalize: true, // Stretch to full height
});
// Dynamic zoom control
wavesurfer.zoom(100); // Zoom to 100 pixels per second
wavesurfer.zoom(50); // Zoom out to 50 pixels per second
// Zoom controls
document.getElementById("zoom-in").addEventListener("click", () => {
const currentZoom = wavesurfer.options.minPxPerSec || 0;
wavesurfer.zoom(currentZoom * 2);
});
document.getElementById("zoom-out").addEventListener("click", () => {
const currentZoom = wavesurfer.options.minPxPerSec || 100;
wavesurfer.zoom(currentZoom / 2);
});Configure scrolling behavior and scrollbar visibility.
interface WaveSurferOptions {
/** Hide the scrollbar */
hideScrollbar?: boolean;
/** Automatically scroll the container to keep the current position in viewport */
autoScroll?: boolean;
/** If autoScroll is enabled, keep the cursor in the center of the waveform during playback */
autoCenter?: boolean;
}
interface WaveSurfer {
/**
* Get the current scroll position in pixels
* @returns Scroll position in pixels from left
*/
getScroll(): number;
/**
* Set the current scroll position in pixels
* @param pixels - Scroll position in pixels from left
*/
setScroll(pixels: number): void;
/**
* Move the start of the viewing window to a specific time in the audio
* @param time - Time in seconds to scroll to
*/
setScrollTime(time: number): void;
}Usage Examples:
// Custom scroll behavior
const customScrollWaveform = WaveSurfer.create({
container: "#custom-scroll",
hideScrollbar: true,
autoScroll: false, // Manual scroll control
autoCenter: false,
});
// Manual scroll control
wavesurfer.setScrollTime(30); // Scroll to 30 seconds
wavesurfer.setScroll(500); // Scroll 500 pixels from left
// Get current scroll position
const scrollPos = wavesurfer.getScroll();
console.log(`Scrolled ${scrollPos} pixels from left`);
// Auto-centered playback
const centeredWaveform = WaveSurfer.create({
container: "#centered",
autoScroll: true,
autoCenter: true, // Keep playback cursor centered
});Render multiple audio channels as separate waveforms with individual styling.
interface WaveSurferOptions {
/** Render each audio channel as a separate waveform */
splitChannels?: Array<Partial<WaveSurferOptions> & { overlay?: boolean }>;
}Usage Examples:
// Separate channel visualization
const multiChannelWaveform = WaveSurfer.create({
container: "#multi-channel",
splitChannels: [
{
waveColor: "#ff0000",
progressColor: "#800000",
overlay: false, // Separate visual tracks
},
{
waveColor: "#0000ff",
progressColor: "#000080",
overlay: false,
},
],
});
// Overlaid stereo channels
const overlaidStereo = WaveSurfer.create({
container: "#overlaid",
splitChannels: [
{
waveColor: "rgba(255, 0, 0, 0.7)",
progressColor: "rgba(128, 0, 0, 0.7)",
overlay: true, // Overlay on same track
},
{
waveColor: "rgba(0, 0, 255, 0.7)",
progressColor: "rgba(0, 0, 128, 0.7)",
overlay: true,
},
],
});Provide custom rendering functions for advanced waveform visualization.
interface WaveSurferOptions {
/** Custom render function for waveform drawing */
renderFunction?: (peaks: Array<Float32Array | number[]>, ctx: CanvasRenderingContext2D) => void;
}Usage Examples:
// Custom visualization function
const customRenderWaveform = WaveSurfer.create({
container: "#custom-render",
renderFunction: (peaks, ctx) => {
const width = ctx.canvas.width;
const height = ctx.canvas.height;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "#4F4A85";
// Custom rendering logic
peaks[0].forEach((peak, i) => {
const x = (i / peaks[0].length) * width;
const y = height / 2;
const amplitude = Math.abs(peak) * height / 2;
// Draw custom shape (e.g., circles instead of bars)
ctx.beginPath();
ctx.arc(x, y, amplitude / 10, 0, 2 * Math.PI);
ctx.fill();
});
},
});
// Frequency spectrum visualization
const spectrumWaveform = WaveSurfer.create({
container: "#spectrum",
renderFunction: (peaks, ctx) => {
// Custom spectrum analyzer rendering
const gradient = ctx.createLinearGradient(0, 0, 0, ctx.canvas.height);
gradient.addColorStop(0, "#ff0000");
gradient.addColorStop(0.5, "#ffff00");
gradient.addColorStop(1, "#00ff00");
ctx.fillStyle = gradient;
// Render frequency bars
peaks[0].forEach((peak, i) => {
const barWidth = ctx.canvas.width / peaks[0].length;
const barHeight = Math.abs(peak) * ctx.canvas.height;
ctx.fillRect(i * barWidth, ctx.canvas.height - barHeight, barWidth - 1, barHeight);
});
},
});Create responsive waveforms that adapt to container size changes.
interface WaveSurfer {
/**
* Get the current waveform width in pixels
* @returns Width in pixels
*/
getWidth(): number;
}Usage Examples:
// Responsive waveform setup
const responsiveWaveform = WaveSurfer.create({
container: "#responsive",
height: 200,
fillParent: true,
autoScroll: true,
});
// Handle window resize
window.addEventListener("resize", () => {
// WaveSurfer automatically handles resize when fillParent: true
console.log(`New width: ${responsiveWaveform.getWidth()}px`);
});
// Mobile-optimized settings
const isMobile = window.innerWidth < 768;
const mobileWaveform = WaveSurfer.create({
container: "#mobile",
height: isMobile ? 100 : 200,
barWidth: isMobile ? 2 : 3,
barGap: isMobile ? 0 : 1,
autoCenter: isMobile,
hideScrollbar: isMobile,
});Install with Tessl CLI
npx tessl i tessl/npm-wavesurfer-js