Peaks.ts is a TypeScript-first UI component for displaying and interacting with audio waveforms in the browser. It is a typed, modernised fork of the BBC's peaks.js library.
The public API surface is broadly compatible with upstream peaks.js, but with
the following differences:
- Strict TypeScript: full type definitions are bundled and the codebase is
written in TypeScript with no
anyescapes in the public API. - Promise /
Resultinitialisation:Peaks.from()returnsPromise<Peaks>. APeaks.tryFrom()variant returns aResultAsync<Peaks, Error>for callers that prefer explicit error values. - Typed event bus: instances expose
peaks.events, a typed event target withaddEventListener/removeEventListenersemantics. - Pluggable canvas drivers: the rendering backend is injected. A Konva driver ships by default; an experimental Pixi.js driver is available and lazily loaded.
- Pluggable audio drivers: choose between an
<audio>/MediaElementAudioDriveror a Web AudioClipNodeAudioDriverthat owns its ownAudioBuffer. - No callback-style APIs:
Peaks.from()andpeaks.setSource()are Promise-returning. The legacy callback signatures have been removed.
For a list of breaking changes vs. upstream peaks.js, see
doc/migration-guide.md.
npm install @jadujoel/peaks.ts waveform-data konva
# or
bun add @jadujoel/peaks.ts waveform-data konvakonva and pixi.js are both declared as optional peer dependencies. Only
install the one(s) you actually use:
| Driver | Required peer dependency |
|---|---|
KonvaCanvasDriver |
konva |
PixiCanvasDriver |
pixi.js |
waveform-data is required at runtime.
import {
ClipNodeAudioDriver,
KonvaCanvasDriver,
Peaks,
} from "@jadujoel/peaks.ts";
const audioContext = new AudioContext();
const buffer = await fetch("/sample.mp3")
.then((r) => r.arrayBuffer())
.then((a) => audioContext.decodeAudioData(a));
const peaks = await Peaks.from({
audio: ClipNodeAudioDriver.from({ buffer, context: audioContext }),
driver: KonvaCanvasDriver.default(),
zoomview: { container: document.getElementById("zoomview-container")! },
overview: { container: document.getElementById("overview-container")! },
zoomLevels: [128, 256, 512, 1024, 2048, 4096],
keyboard: true,
});
peaks.events.addEventListener("player.timeupdate", (event) => {
console.log(event.time);
});
peaks.player.play();Peaks.tryFrom() is the same call expressed as a ResultAsync:
const result = await Peaks.tryFrom(config);
if (result.isErr()) {
console.error(result.error);
return;
}
const peaks = result.value;The canvas backend is selected at construction time by passing a
CanvasDriver to Peaks.from({ driver }). Two implementations are bundled:
KonvaCanvasDriver(default). UseKonvaCanvasDriver.default(). Pulls inkonvasynchronously.PixiCanvasDriver(experimental). Useawait PixiCanvasDriver.create(). The Pixi backend is loaded via dynamicimport("pixi.js")so it is only fetched when actually used. To take advantage of this in a bundle, enable code splitting in your bundler (splitting: truein Bun,build.rollupOptions.output.manualChunksin Vite, etc.).
If driver is omitted, Peaks.from() falls back to
KonvaCanvasDriver.default().
Audio playback is also pluggable, via audio on PeaksConfiguration. Two
implementations are bundled:
-
ClipNodeAudioDriver— Web Audio. Owns anAudioBufferand uses the@jadujoel/web-audio-clip-nodepackage internally. Construct from a buffer:ClipNodeAudioDriver.from({ buffer, context });
or from a URL:
ClipNodeAudioDriver.from({ url: "/sample.mp3", context });
When the driver owns the buffer,
webAudio.audioBuffer/webAudio.audioContexton the Peaks options can be omitted — they are filled in automatically byPeaks.from()andpeaks.setSource(). -
MediaElementAudioDriver— wraps anHTMLMediaElement. Used automatically when noaudiodriver is provided andmediaElementis set in the options.
If audio is omitted, the legacy mediaElement / webAudio options are used
to derive a default driver.
- doc/API.md — full public API reference (configuration, methods, events).
- doc/customizing.md — custom point/segment markers, segment labels, and player implementations.
- doc/migration-guide.md — breaking changes vs.
upstream
peaks.js. - doc/faq.md — frequently asked questions.
This repository uses Bun for installs, scripts, and the build. Common commands:
bun install # install workspace deps
bun run lint # biome check
bun run typecheck # tsc --noEmit on src + tests
bun run test # vitest unit + component tests
bun run test:e2e # playwright end-to-end tests
bun run build # build dist/peaks.esm.js
bun run example # serve workspaces/main-example on :8090
bun run test:all # lint + typecheck + tests + build + e2eSource layout (top level):
src/— library source.src/driver/konvaandsrc/driver/pixi— canvas drivers.src/driver/audio/{clip-node,media-element}— audio drivers.src/waveform/— view, builder, layers, axis, shapes.
workspaces/main-example/— interactive demo that exercises every major feature against both canvas drivers. See its README.e2e/— Playwright end-to-end tests.test/— unit and component tests (Vitest, browser mode).doc/— user-facing documentation.
See CONTRIBUTING.md for contribution guidelines.
LGPL-3.0. See COPYING.