Skip to Content
raavl

Quickstart

A working player in no time.

Install

Add raavl to your application:

npm install raavl

Use a bundler that supports ESM and CSS imports, such as Vite or Next.js. Import raavl/styles.css once in your application for the default waveform styles, or supply your own CSS tokens.

For React integration, use the raavl/react adapter with react and react-dom. The JavaScript API works independently of React.

JavaScript

Create your own container and controls:

<div id="waveform"></div>
<button id="play" disabled>Play</button>
<p id="error" role="alert"></p>
import { createPlayer, mountWaveform } from "raavl";
import "raavl/styles.css";

const container = document.querySelector<HTMLElement>("#waveform")!;
const button = document.querySelector<HTMLButtonElement>("#play")!;
const errorText = document.querySelector<HTMLElement>("#error")!;
const report = (error: unknown) => {
  errorText.textContent =
    error instanceof Error ? error.message : String(error);
};
const player = createPlayer();
const view = mountWaveform(container, {
  player,
  appearance: { style: "bars", height: 160 },
  interaction: { drag: "seek" },
  label: "Episode waveform",
});

const off = player.subscribe(() => {
  const state = player.getSnapshot();
  button.disabled = state.source !== "ready";
  button.textContent = state.playback === "playing" ? "Pause" : "Play";
  if (state.error) report(state.error);
  if (state.waveformError) report(state.waveformError);
});

button.onclick = () => {
  if (player.getSnapshot().playback === "playing") player.pause();
  else void player.play().catch(report);
};

try {
  await player.setSource({ kind: "url", id: "episode-1", url: "/episode.mp3" });
} catch (error) {
  report(error);
}

// Call when leaving the page or destroying this component.
function cleanup() {
  button.onclick = null;
  off();
  view.dispose();
  player.dispose();
}

React

Use the complete player for a default UI with connected controls. Mark this as a client component in a Next.js App Router application.

"use client";
import { AudioPlayer } from "raavl/react";
import "raavl/styles.css";

export function EpisodePlayer() {
  return (
    <AudioPlayer
      source={{ kind: "url", id: "episode-1", url: "/episode.mp3" }}
      waveform={{ appearance: { style: "bars", height: 160 } }}
      controls={{ playbackRate: true, loop: true }}
      aria-label="Episode player"
    />
  );
}

The player owns source loading, controls, status feedback, and cleanup. Pass an existing player instead of source to borrow playback. For a custom layout, compose PlayerRoot, Waveform, and the individual controls; for a fully custom interface, use the headless hooks. See the React API.

Supply your audio

Replace /episode.mp3 with an actual asset served by your app. Demo audio URLs on the documentation site are not assets installed with the library. For cross-origin waveform decoding, the audio host must permit CORS fetches.

setSource() resolves when metadata is available. Waveform preparation and playback buffering have separate states. Handle the play() promise because browsers may reject playback without a user gesture.

Next: sources and peaks, styling, or the player API.

On this page