@arraypress/waveform-player
v1.2.0
Published
Lightweight, customizable audio player with waveform visualization
Downloads
253
Maintainers
Readme
WaveformPlayer
A lightweight, customizable audio player with waveform visualization. Under 6KB gzipped.
Live Demo | Documentation | NPM Package

Why WaveformPlayer?
- Zero Config - Just add
data-waveform-playerto any div. No JavaScript required. - Tiny - 8KB gzipped vs 40KB+ for alternatives
- Real Waveforms - Actual audio analysis, not fake waves
- No Dependencies - No jQuery, no bloat, pure vanilla JS
- Works Everywhere - WordPress, Shopify, React, Vue, or plain HTML
- Ecosystem - Optional playlist and analytics addons available
Quick Start
Simplest possible usage:
<!-- Just this. That's it. -->
<div data-waveform-player data-url="song.mp3"></div>Installation
NPM
npm install @arraypress/waveform-playerCDN
<link rel="stylesheet" href="https://unpkg.com/@arraypress/waveform-player@latest/dist/waveform-player.css">
<script src="https://unpkg.com/@arraypress/waveform-player@latest/dist/waveform-player.min.js"></script>Download
<link rel="stylesheet" href="waveform-player.css">
<script src="waveform-player.js"></script>Features
- 🎨 6 Visual Styles - Bars, mirror, line, blocks, dots, seekbar
- 🎯 Tiny Footprint - Under 8KB gzipped
- ⚡ Zero Dependencies - Pure JavaScript
- 🎭 Fully Customizable - Colors, sizes, styles
- 📱 Responsive - Works on all devices
- 🎵 BPM Detection - Automatic tempo detection (optional)
- 💾 Waveform Caching - Pre-generate waveforms for performance
- 🌐 Framework Agnostic - Works with React, Vue, Angular, or vanilla JS
- ⌨️ Keyboard Controls - Full keyboard navigation support
- 📱 Media Session API - System media controls, lock screen integration
- ⏩ Speed Control - Adjustable playback rate for podcasts/audiobooks
- 📍 Chapter Markers - Add clickable markers for navigation
- 🔄 Dynamic Loading - Load new tracks without page refresh
Ecosystem
WaveformPlaylist (Optional Addon)
Add playlist and chapter support with zero JavaScript:
<div data-waveform-playlist data-continuous="true">
<div data-track data-url="song1.mp3" data-title="Track 1">
<div data-chapter data-time="0:00">Intro</div>
<div data-chapter data-time="2:30">Verse</div>
</div>
<div data-track data-url="song2.mp3" data-title="Track 2"></div>
</div>WaveformTracker (Optional Addon)
Track meaningful audio engagement:
WaveformTracker.init({
endpoint: '/api/analytics',
events: {
listen: 30 // Track after 30 seconds of listening
}
});Comparison
| Feature | WaveformPlayer | WaveSurfer.js | Amplitude.js | |---------|----------------|---------------|--------------| | Size (gzipped) | 8KB | 40KB+ | 35KB+ | | Zero Config | ✅ | ❌ | ❌ | | Dependencies | None | None | None | | Waveform Styles | 6 | 3 | N/A | | Setup Time | 30 seconds | 5+ minutes | 5+ minutes | | Real Waveforms | ✅ | ✅ | ❌ | | Keyboard Controls | ✅ | ✅ | ❌ | | Media Session API | ✅ | ❌ | ❌ | | Speed Control | ✅ | ✅ | ❌ |
Usage
HTML (Zero JavaScript)
<div data-waveform-player
data-url="audio.mp3"
data-title="My Song"
data-subtitle="Artist Name"
data-waveform-style="mirror"
data-show-playback-speed="true"
data-markers='[{"time": 30, "label": "Chorus"}]'>
</div>JavaScript API
import WaveformPlayer from '@arraypress/waveform-player';
const player = new WaveformPlayer('#player', {
url: 'audio.mp3',
waveformStyle: 'mirror',
height: 80,
barWidth: 2,
barSpacing: 1,
markers: [
{time: 30, label: 'Verse', color: '#4ade80'},
{time: 60, label: 'Chorus', color: '#f59e0b'}
]
});Visual Styles
Choose from 6 built-in styles:
- bars - Classic waveform bars
- mirror - SoundCloud-style mirrored waveform
- line - Smooth oscilloscope line
- blocks - LED meter blocks
- dots - Circular dots
- seekbar - Minimal progress bar
Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| url | string | '' | Audio file URL |
| waveformStyle | string | 'bars' | Visual style: bars, mirror, line, blocks, dots, seekbar |
| height | number | 60 | Waveform height in pixels |
| barWidth | number | 3 | Width of waveform bars |
| barSpacing | number | 1 | Space between bars |
| samples | number | 200 | Number of waveform samples |
| waveformColor | string | 'rgba(255,255,255,0.3)' | Waveform color |
| progressColor | string | 'rgba(255,255,255,0.9)' | Progress color |
| buttonColor | string | 'rgba(255,255,255,0.9)' | Play button color |
| showTime | boolean | true | Show time display |
| showBPM | boolean | false | Enable BPM detection |
| showPlaybackSpeed | boolean | false | Show speed control menu |
| playbackRate | number | 1 | Initial playback speed (0.5-2) |
| autoplay | boolean | false | Autoplay on load |
| title | string | '' | Track title |
| subtitle | string | '' | Track subtitle |
| artwork | string | '' | Album artwork URL |
| markers | array | [] | Chapter markers array |
| enableMediaSession | boolean | true | Enable system media controls |
API Methods
// Control playback
player.play();
player.pause();
player.togglePlay();
// Seek
player.seekTo(30); // Seek to 30 seconds
player.seekToPercent(0.5); // Seek to 50%
// Volume
player.setVolume(0.8); // 80% volume
// Speed
player.setPlaybackRate(1.5); // 1.5x speed
// Dynamic loading
await player.loadTrack('new-song.mp3', 'New Title', 'New Artist');
// Destroy
player.destroy();Events
new WaveformPlayer('#player', {
url: 'audio.mp3',
onLoad: (player) => console.log('Loaded'),
onPlay: (player) => console.log('Playing'),
onPause: (player) => console.log('Paused'),
onEnd: (player) => console.log('Ended'),
onTimeUpdate: (current, total, player) => {
console.log(`${current}/${total}`);
}
});Keyboard Controls
When a player is focused (click on it):
Space- Play/pause←/→- Seek backward/forward 5 seconds↑/↓- Volume up/downM- Mute/unmute0-9- Jump to 0%-90% of track
Advanced Usage
Pre-generated Waveforms
For better performance, generate waveform data server-side:
// Generate waveform data once
const waveformData = await WaveformPlayer.generateWaveformData('audio.mp3');
// Use pre-generated data for instant display
new WaveformPlayer('#player', {
url: 'audio.mp3',
waveform: waveformData // Bypass client-side processing
});Multiple Players
// Get all instances
const players = WaveformPlayer.getAllInstances();
// Find specific player
const player = WaveformPlayer.getInstance('my-player');
// Destroy all players
WaveformPlayer.destroyAll();Custom Styling
.waveform-player {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
}
.waveform-btn {
border-color: #fff;
}Framework Integration
React
import { useEffect, useRef } from 'react';
import WaveformPlayer from '@arraypress/waveform-player';
function AudioPlayer({ url }) {
const playerRef = useRef();
useEffect(() => {
const player = new WaveformPlayer(playerRef.current, { url });
return () => player.destroy();
}, [url]);
return <div ref={playerRef} />;
}Vue
<template>
<div ref="player"></div>
</template>
<script>
import WaveformPlayer from '@arraypress/waveform-player';
export default {
mounted() {
this.player = new WaveformPlayer(this.$refs.player, {
url: this.audioUrl
});
},
beforeDestroy() {
this.player?.destroy();
}
}
</script>Browser Support
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- Mobile browsers (iOS Safari, Chrome Android)
Examples
See the live demo for:
- All visual styles
- Custom styling examples
- Event handling
- Player builder
- BPM detection
- Pre-generated waveforms
- Keyboard navigation
- Speed controls
- Chapter markers
- Playlist support
- Analytics tracking
Development
# Install dependencies
npm install
# Development mode
npm run dev
# Build
npm run build
# Check size
npm run sizeLicense
MIT © ArrayPress
Credits
Created by David Sherlock
