Package Exports
- waveform-renderer
- waveform-renderer/package.json
Readme
๐ต Waveform Renderer
A high-performance, lightweight TypeScript library for rendering audio waveforms on HTML5 Canvas. Create beautiful, interactive audio visualizations with intelligent caching and advanced performance optimizations.
๐ Table of Contents
- Features
- Installation
- Quick Start
- Configuration Options
- API Reference
- Examples
- Architecture
- Performance
- Browser Support
- Development
- Contributing
- License
โจ Features
- ๐จ Highly customizable appearance - Full control over colors, dimensions, and visual styling
- โก High performance - Intelligent caching system with optimized rendering pipeline
- ๐ฑ Responsive and touch-friendly - Automatic canvas resizing with HiDPI/Retina support
- ๐ Real-time progress updates - Smooth animation and instant feedback
- ๐ฏ Interactive seeking - Built-in click-to-seek functionality
- ๐ช TypeScript-first - Complete type safety with comprehensive interfaces
- ๐ฆ Zero dependencies - Lightweight with no external dependencies
- ๐งช Well tested - 231 unit tests ensuring reliability and stability
- ๐ง Debug system - Built-in performance monitoring and logging
- ๐พ Smart caching - Automatic render optimization with intelligent cache management
- ๐๏ธ Modular architecture - Clean separation of concerns for maintainability
๐ Installation
# npm
npm install waveform-renderer
# pnpm
pnpm add waveform-renderer
# yarn
yarn add waveform-renderer๐ Quick Start
import { WaveformRenderer, getPeaksFromAudioBuffer } from "waveform-renderer";
// Get your audio buffer (from Web Audio API)
const audioContext = new AudioContext();
const response = await fetch("path/to/audio.mp3");
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
// Extract peaks from the audio buffer
const peaks = getPeaksFromAudioBuffer(audioBuffer, 1000); // 1000 samples
// Create the waveform renderer
const canvas = document.getElementById("waveform") as HTMLCanvasElement;
const waveform = new WaveformRenderer(canvas, peaks, {
color: "#2196F3",
backgroundColor: "#E3F2FD",
progressLine: {
color: "#1565C0",
},
});
// Listen to events
waveform.on("seek", progress => {
console.log(`Seeked to ${progress * 100}%`);
});โ๏ธ Configuration Options
WaveformOptions
| Option | Type | Default | Description |
|---|---|---|---|
amplitude |
number |
1 |
Amplitude multiplier for the waveform |
backgroundColor |
string |
"#CCCCCC" |
Background color of the waveform |
barWidth |
number |
2 |
Width of each bar in pixels |
borderColor |
string |
"#000000" |
Border color of the bars |
borderRadius |
number |
0 |
Border radius of the bars in pixels |
borderWidth |
number |
0 |
Border width of the bars in pixels |
color |
string |
"#000000" |
Color of the waveform bars |
gap |
number |
1 |
Gap between bars in pixels |
minPixelRatio |
number |
1 |
Minimum pixel ratio for rendering |
position |
"bottom" | "center" | "top" |
"center" |
Vertical positioning of the waveform |
progress |
number |
0 |
Initial progress (0-1) |
smoothing |
boolean |
true |
Whether to apply smoothing to the rendering |
progressLine |
ProgressLineOptions | null |
{...} |
Progress line configuration (see below) |
debug |
boolean |
false |
Enable debug logging and performance stats |
ProgressLineOptions
| Option | Type | Default | Description |
|---|---|---|---|
color |
string |
"#FF0000" |
Color of the progress line |
heightPercent |
number |
1 |
Height of the line as percentage of total height |
position |
"bottom" | "center" | "top" |
"center" |
Vertical position of the line |
style |
"solid" | "dashed" | "dotted" |
"solid" |
Style of the progress line |
width |
number |
2 |
Width of the line in pixels |
๐ API Reference
WaveformRenderer
Constructor
new WaveformRenderer(
canvas: HTMLCanvasElement,
peaks: number[],
options?: Partial<WaveformOptions>
)Instance Methods
setOptions(options: Partial<WaveformOptions>): Updates the waveform optionssetPeaks(peaks: number[]): Updates the waveform peaks datasetProgress(progress: number): Updates the current progress (0-1)setProgressLineOptions(options: Partial<ProgressLineOptions> | null): Updates progress line optionssetDebug(enabled: boolean): Enable/disable debug moderesetDebugCounters(): Reset debug performance counterssetCustomRenderer(renderer?: CustomRenderer): Set a custom rendering functionsetRenderHooks(hooks: RenderHook): Set custom render hooks for advanced customizationclearRenderHooks(): Clear all custom render hooksdestroy(): Cleans up and removes the instance
๐ฏ Events
The waveform renderer emits the following events:
| Event | Payload | Description |
|---|---|---|
renderStart |
void |
Emitted when rendering begins |
renderComplete |
void |
Emitted when rendering is complete |
seek |
number |
Progress value between 0-1 when user seeks |
error |
Error |
Error object when an error occurs |
destroy |
void |
Emitted when the instance is destroyed |
ready |
void |
Emitted when the waveform is ready |
resize |
{ width: number; height: number } |
New dimensions when canvas is resized |
progressChange |
number |
New progress value between 0-1 |
๐ฆ Exports
// Main Component
import { WaveformRenderer } from "waveform-renderer";
// Utility Functions
import { getPeaksFromAudioBuffer } from "waveform-renderer";
// TypeScript Types
import type {
WaveformOptions,
ProgressLineOptions,
WaveformEvents,
RenderMode,
CustomRenderer,
RenderHook,
} from "waveform-renderer";
// Default Configuration
import { DEFAULT_OPTIONS } from "waveform-renderer";๐ก Examples
Basic Usage
import { WaveformRenderer } from "waveform-renderer";
const canvas = document.getElementById("waveform") as HTMLCanvasElement;
const peaks = [0.1, 0.3, 0.8, 0.4, 0.6, 0.2, 0.9, 0.1]; // Your audio peaks
const waveform = new WaveformRenderer(canvas, peaks);Custom Styling
const waveform = new WaveformRenderer(canvas, peaks, {
color: "#2196F3",
backgroundColor: "#E3F2FD",
barWidth: 3,
gap: 2,
borderRadius: 2,
progressLine: {
color: "#1565C0",
style: "dashed",
width: 2,
},
debug: false,
});Event Handling with Audio Element
const audio = new Audio("path/to/audio.mp3");
const waveform = new WaveformRenderer(canvas, peaks);
// Sync progress with audio playback
audio.addEventListener("timeupdate", () => {
const progress = audio.currentTime / audio.duration;
waveform.setProgress(progress);
});
// Handle seek events
waveform.on("seek", progress => {
audio.currentTime = progress * audio.duration;
audio.play();
});
// Listen to other events
waveform.on("ready", () => {
console.log("Waveform is ready!");
});
waveform.on("resize", ({ width, height }) => {
console.log(`Canvas resized to ${width}x${height}`);
});Debug Mode and Performance Monitoring
const waveform = new WaveformRenderer(canvas, peaks, {
debug: true, // Enable debug mode
});
// Enable/disable debug mode dynamically
waveform.setDebug(true);
// Reset performance counters
waveform.resetDebugCounters();
// Debug information is logged to console when debug mode is enabledAdvanced Customization
Custom Renderer
import type { CustomRenderer } from "waveform-renderer";
const customRenderer: CustomRenderer = {
render(ctx, cache, options, staticPath) {
// Your custom rendering logic here
// Return true if you handled the rendering, false to use default
return false;
},
};
waveform.setCustomRenderer(customRenderer);Render Hooks
import type { RenderHook } from "waveform-renderer";
const hooks: RenderHook = {
beforeRender: (ctx, cache, options) => {
// Called before any rendering starts
},
afterBackground: (ctx, cache, options) => {
// Called after background is drawn
},
afterProgress: (ctx, cache, options, progress) => {
// Called after progress line is drawn
},
afterComplete: (ctx, cache, options) => {
// Called when rendering is complete
},
};
waveform.setRenderHooks(hooks);Working with Audio Buffers
// Get an AudioBuffer from your audio source
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
// Calculate peaks with custom sample count
const peaks = getPeaksFromAudioBuffer(audioBuffer, 2000);
// Create waveform with calculated peaks
const waveform = new WaveformRenderer(canvas, peaks, {
color: "#10b981",
backgroundColor: "#1f2937",
debug: false,
});๐๏ธ Architecture
The library follows a modular architecture with clean separation of concerns:
- Renderer: Main rendering logic and canvas management
- RenderingEngine: Core drawing operations and optimizations
- CacheManager: Intelligent caching system for performance
- DebugSystem: Performance monitoring and logging
- EventHandler: Event management and user interactions
This architecture ensures:
- Maintainability: Clear separation of responsibilities
- Performance: Optimized rendering with intelligent caching
- Extensibility: Easy to add new features and customizations
- Testability: Comprehensive unit test coverage (231 tests)
โก Performance
The library is designed for high performance with several optimizations:
- Intelligent Caching: Automatic render optimization that prevents unnecessary redraws
- Efficient Peak Processing: Optimized algorithms for handling large audio datasets
- Canvas Optimization: Smart canvas management with pixel ratio handling
- Memory Management: Proper cleanup and resource management
- Event Debouncing: Optimized event handling to prevent performance bottlenecks
Performance monitoring is available in debug mode to help optimize your implementation.
๐ Browser Support
- Chrome 88+
- Firefox 78+
- Safari 14+
- Edge 88+
The library works in all modern browsers that support Canvas and ES6.
๐ง Development
# Install dependencies
pnpm install
# Run development server with demo
pnpm dev
# Build the library
pnpm build
# Build demo page
pnpm build:webpage
# Run tests
pnpm test
# Run tests with coverage
pnpm test:coverage
# Lint code
pnpm lint
# Type check
pnpm type-check๐ก Motivation
While wavesurfer.js is an excellent library, we needed a more focused solution. Waveform Renderer was created to be a lightweight alternative that concentrates solely on waveform visualization, eliminating additional features like playback, regions, or spectrograms. This results in:
- ๐ฏ Focused scope: Just waveform rendering and interaction
- ๐ฆ Smaller bundle size: No unnecessary features or dependencies
- ๐ช TypeScript-first development: Built from the ground up with TypeScript
- โก Optimized performance: Intelligent caching and rendering optimizations
- ๐๏ธ Modern architecture: Clean, testable, and maintainable codebase
Choose Waveform Renderer when you need efficient waveform visualization without the overhead of a full-featured audio library.
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
๐ License
MIT License - see the LICENSE file for details.
๐ Links
- Demo - Live interactive demo
- NPM Package
- GitHub Repository
- Issues
๐ Acknowledgements
- Inspired by wavesurfer.js
- Co-created with the help of Claude
Made with โค๏ธ by Andres Alarcon