Waveform

Previous

Canvas-based audio waveform visualization components with recording, playback scrubbing, and microphone input support.

Installation

pnpm dlx @elevenlabs/agents-cli@latest components add waveform

Usage

import {
  AudioScrubber,
  LiveMicrophoneWaveform,
  MicrophoneWaveform,
  RecordingWaveform,
  ScrollingWaveform,
  StaticWaveform,
  Waveform,
} from "@/components/ui/waveform"

Basic Waveform

const data = Array.from({ length: 50 }, () => Math.random())
 
;<Waveform data={data} height={100} barWidth={4} barGap={2} />

Scrolling Animation

<ScrollingWaveform
  height={80}
  speed={50}
  barCount={60}
  barColor="hsl(var(--primary))"
  fadeEdges={true}
/>

Microphone Input

const [isRecording, setIsRecording] = useState(false)
 
;<MicrophoneWaveform
  active={isRecording}
  height={100}
  sensitivity={1.5}
  onError={(error) => console.error("Microphone error:", error)}
/>

API Reference

Waveform

The base waveform component that displays audio data as bars.

<Waveform data={audioData} />

Props

PropTypeDescription
datanumber[]Array of values between 0 and 1 for each bar
barWidthnumberWidth of each bar in pixels. Default: 4
barGapnumberGap between bars in pixels. Default: 2
barRadiusnumberBorder radius of bars. Default: 2
barColorstringCustom bar color. Uses foreground color by default
fadeEdgesbooleanApply fade effect to edges. Default: true
fadeWidthnumberWidth of fade effect in pixels. Default: 24
heightstring | numberHeight of the waveform. Default: 128
onBarClick(index: number, value: number) => voidCallback when a bar is clicked

ScrollingWaveform

Continuously scrolling waveform with auto-generated bars.

<ScrollingWaveform speed={50} />

Props

PropTypeDescription
speednumberScroll speed in pixels per second. Default: 50
barCountnumberNumber of bars to display. Default: 60
...propsWaveformPropsAll Waveform props except data and onBarClick

AudioScrubber

Interactive waveform for audio playback with seek functionality.

<AudioScrubber
  data={waveformData}
  currentTime={playbackTime}
  duration={totalDuration}
  onSeek={handleSeek}
/>

Props

PropTypeDescription
currentTimenumberCurrent playback time in seconds
durationnumberTotal duration in seconds. Default: 100
onSeek(time: number) => voidCallback when user seeks to a new time
showHandlebooleanShow draggable handle. Default: true
...propsWaveformPropsAll standard Waveform props

MicrophoneWaveform

Real-time microphone input visualization.

<MicrophoneWaveform active={isListening} sensitivity={1.5} />

Props

PropTypeDescription
activebooleanEnable/disable microphone input. Default: false
fftSizenumberFFT size for frequency analysis. Default: 256
smoothingTimeConstantnumberSmoothing factor (0-1). Default: 0.8
sensitivitynumberAmplitude sensitivity. Default: 1
onError(error: Error) => voidError callback
...propsWaveformPropsAll standard Waveform props

StaticWaveform

Waveform with deterministic random data based on seed.

<StaticWaveform bars={40} seed={42} />

Props

PropTypeDescription
barsnumberNumber of bars to generate. Default: 40
seednumberRandom seed for consistent data
...propsWaveformPropsAll standard Waveform props

LiveMicrophoneWaveform

Advanced microphone visualization with recording history and playback scrubbing.

<LiveMicrophoneWaveform
  active={isRecording}
  enableAudioPlayback={true}
  playbackRate={1}
/>

Props

PropTypeDescription
activebooleanEnable/disable recording
historySizenumberMax bars to keep in history. Default: 150
updateRatenumberUpdate interval in ms. Default: 50
enableAudioPlaybackbooleanEnable audio scrubbing when stopped. Default: true
playbackRatenumberAudio playback speed. Default: 1
savedHistoryRefReact.MutableRefObject<number[]>External ref to persist history
dragOffsetnumberExternal drag offset control
setDragOffset(offset: number) => voidExternal drag offset setter
...propsScrollingWaveformPropsAll ScrollingWaveform props

RecordingWaveform

Recording interface with scrubbing through recorded audio.

<RecordingWaveform
  recording={isRecording}
  onRecordingComplete={(data) => console.log("Recording data:", data)}
/>

Props

PropTypeDescription
recordingbooleanRecording state. Default: false
onRecordingComplete(data: number[]) => voidCallback with recorded waveform data
showHandlebooleanShow scrubbing handle. Default: true
updateRatenumberUpdate interval in ms. Default: 50
...propsWaveformPropsAll standard Waveform props

Examples

Music Player Visualization

function MusicPlayer() {
  const [audioData] = useState(() =>
    Array.from({ length: 100 }, () => 0.2 + Math.random() * 0.6)
  )
 
  return (
    <AudioScrubber
      data={audioData}
      currentTime={currentTime}
      duration={duration}
      onSeek={handleSeek}
      height={60}
      barWidth={3}
      barGap={1}
      barColor="hsl(var(--primary))"
    />
  )
}

Voice Recorder

function VoiceRecorder() {
  const [recording, setRecording] = useState(false)
 
  return (
    <div className="space-y-4">
      <RecordingWaveform
        recording={recording}
        height={100}
        onRecordingComplete={(data) => {
          console.log("Recording complete", data)
        }}
      />
      <Button onClick={() => setRecording(!recording)}>
        {recording ? "Stop" : "Start"} Recording
      </Button>
    </div>
  )
}

Live Audio Monitor

function AudioMonitor() {
  const [active, setActive] = useState(false)
 
  return (
    <MicrophoneWaveform
      active={active}
      height={80}
      sensitivity={2}
      barWidth={2}
      barGap={1}
      onError={(error) => {
        console.error("Microphone error:", error)
        setActive(false)
      }}
    />
  )
}

Notes

  • All waveform components use HTML5 Canvas for high-performance rendering
  • Animations are synchronized using requestAnimationFrame for smooth 60fps updates
  • Microphone components require user permission to access audio input devices
  • The components automatically handle device pixel ratio for crisp rendering on high-DPI displays
  • Bar colors default to the CSS variable --foreground but can be customized
  • Canvas-based implementation ensures high performance even with hundreds of bars
  • ResizeObserver used for responsive canvas sizing
  • Proper cleanup of audio contexts and media streams on unmount
  • Supports both static data visualization and real-time audio input
  • Click handlers available on bars for interactive waveforms