Astro component wrapper around @arraypress/waveform-player. Exposes every library option as a typed prop, handles data-* attribute serialisation for you, and ships an optional lazy-mount IntersectionObserver for grids of many previews.
The core library stays a zero-dependency vanilla-JS package that works anywhere a <script> tag does (WordPress, Shopify, raw HTML). This package adds the framework-native ergonomics Astro users expect — without touching the runtime.
---
import WaveformPlayer from '@arraypress/waveform-player-astro';
import '@arraypress/waveform-player/dist/waveform-player.css';
import wfpJsUrl from '@arraypress/waveform-player/dist/waveform-player.min.js?url';
---
<script src={wfpJsUrl} is:inline></script>
<WaveformPlayer
url="/audio/track.mp3"
title="My Track"
waveformStyle="bars"
showBPM
/>npm install @arraypress/waveform-player-astro @arraypress/waveform-player@arraypress/waveform-player is a peer dependency — you bring it explicitly so you control the version.
The wrapper does not load the core library's JS or CSS for you. This is deliberate: you might want a CDN, a self-hosted asset, or the bundled npm path. Load both once in your root layout:
---
// src/layouts/Layout.astro
import '@arraypress/waveform-player/dist/waveform-player.css';
import wfpJsUrl from '@arraypress/waveform-player/dist/waveform-player.min.js?url';
---
<html>
<head>
<script src={wfpJsUrl} is:inline></script>
</head>
<body><slot /></body>
</html>Then <WaveformPlayer> works on any page.
<WaveformPlayer url="/audio/track.mp3" /><WaveformPlayer
url="/audio/track.mp3"
title="Midnight Dreams"
subtitle="The Wavelength"
artwork="/img/cover.jpg"
waveformStyle="bars"
barWidth={3}
barSpacing={1}
height={80}
/><WaveformPlayer
url="/audio/track.mp3"
waveform="/peaks/track.json"
/>Generate the JSON at build time with @arraypress/waveform-gen. Removes a full Web Audio decode from the runtime render path.
<WaveformPlayer
url="/audio/podcast.mp3"
markers={[
{ time: 0, label: 'Intro' },
{ time: 60, label: 'Main topic', color: '#a855f7' },
{ time: 600, label: 'Q&A' },
]}
/>Pass lazy and the wrapper switches the init attribute to data-waveform-player-lazy, then installs a single shared IntersectionObserver that promotes each mount when it crosses the viewport (with 200 px of buffer so audio is decoded before the user actually sees the player).
{previews.map((p) => (
<WaveformPlayer url={p.url} title={p.title} lazy />
))}The observer is installed at most once per page (window.__wfpLazyMountBound flag), and re-fires on Astro's astro:page-load event so cross-page navigations pick up new mounts.
For setups where one audio element (e.g. @arraypress/waveform-bar) drives many visual surfaces:
<WaveformPlayer
url={track.url}
audioMode="external"
waveformStyle="seekbar"
showInfo={false}
/>The player dispatches waveformplayer:request-play | request-pause | request-seek custom events instead of touching audio itself. Drive the visualisation from your controller via the player instance's setProgress(currentTime, duration) and setPlayingState(playing) methods.
Every prop maps 1:1 to an option on the core library. Omitting a prop emits no data-* attribute and lets the library apply its own default.
| Prop | Type | Default | Description |
|---|---|---|---|
url |
string (required) |
— | Audio file URL. |
audioMode |
'self' | 'external' |
'self' |
'external' renders waveform only and emits request events. |
preload |
'auto' | 'metadata' | 'none' |
'metadata' |
Browser preload hint. |
| Prop | Type | Default | Description |
|---|---|---|---|
waveformStyle |
'bars' | 'mirror' | 'line' | 'blocks' | 'dots' | 'seekbar' |
'mirror' |
Visual style. |
height |
number |
60 |
Canvas height in pixels. |
samples |
number |
200 |
Number of waveform peaks to render. |
barWidth |
number |
style-dependent | Width of each bar/block. |
barSpacing |
number |
style-dependent | Gap between bars. |
waveform |
number[] | string |
— | Pre-computed peaks (array, JSON URL, or inline JSON). |
All optional. colorPreset controls the auto theme, and any individual colour wins over the preset.
| Prop | Type | Description |
|---|---|---|
colorPreset |
'dark' | 'light' | null |
null (default) auto-detects. |
waveformColor |
string |
Unplayed peak colour. |
progressColor |
string |
Played-through peak colour. |
buttonColor |
string |
Play-button colour. |
buttonHoverColor |
string |
Play-button hover colour. |
textColor |
string |
Primary text colour. |
textSecondaryColor |
string |
Secondary text colour. |
backgroundColor |
string |
Reserved. |
borderColor |
string |
Reserved. |
| Prop | Type | Default | Description |
|---|---|---|---|
playbackRate |
number |
1 |
Initial speed. |
showPlaybackSpeed |
boolean |
false |
Show the speed menu. |
playbackRates |
number[] |
[0.5, 0.75, 1, 1.25, 1.5, 1.75, 2] |
Speeds offered in the menu. |
| Prop | Type | Default | Description |
|---|---|---|---|
showControls |
boolean |
true |
Show the play/pause button. |
showInfo |
boolean |
true |
Show the info bar (title, time, etc.). |
showTime |
boolean |
true |
Show current / total time. |
showHoverTime |
boolean |
false |
Reserved. |
showBPM |
boolean |
false |
Detect and display BPM. |
buttonAlign |
'auto' | 'top' | 'center' | 'bottom' |
'auto' |
Play-button vertical alignment. |
| Prop | Type | Default | Description |
|---|---|---|---|
markers |
Array<{ time: number; label: string; color?: string }> |
— | Clickable seek-point markers. |
showMarkers |
boolean |
true |
Render markers (false to hide without losing data). |
| Prop | Type | Description |
|---|---|---|
title |
string |
Track title (defaults to a prettified filename). |
subtitle |
string |
Subtitle / artist. |
artwork |
string |
Thumbnail image URL. |
album |
string |
Album name (Media Session API). |
| Prop | Type | Default | Description |
|---|---|---|---|
autoplay |
boolean |
false |
Start as soon as metadata loads. |
singlePlay |
boolean |
true |
Pause other players on the page when this one starts. |
playOnSeek |
boolean |
true |
Resume on seek if paused. |
enableMediaSession |
boolean |
true |
Wire up the Media Session API. |
| Prop | Type | Description |
|---|---|---|
playIcon |
string |
Inline HTML / SVG for the play button (injected raw — trust your source). |
pauseIcon |
string |
Inline HTML / SVG for the pause button. |
| Prop | Type | Default | Description |
|---|---|---|---|
lazy |
boolean |
false |
Defer mount until viewport entry. |
id |
string |
— | Forwarded to the container element. |
class |
string |
— | Appended to the container's classes (wfp-host is always present). |
style |
string |
— | Inline style on the container. |
Importing the types directly:
import type {
WaveformPlayerProps,
WaveformStyle,
WaveformMarker,
WaveformPeaks,
ColorPreset,
AudioMode,
AudioPreload,
ButtonAlign,
} from '@arraypress/waveform-player-astro';The package also ships an ambient declaration for window.WaveformPlayer so consumers reaching for it from their own scripts get autocomplete.
npm test # one-shot
npm run test:watch
npm run typecheckTests use Astro's official experimental_AstroContainer API to render the component to a string and assert on the resulting HTML. No browser required.
MIT © ArrayPress