Skip to main content
The @waveform-playlist/spectrogram package provides FFT-based frequency visualization for audio tracks, rendered alongside waveforms using Web Workers and OffscreenCanvas.

Installation

npm install @waveform-playlist/spectrogram fft.js react styled-components
Peer dependencies:
  • @waveform-playlist/browser - Main browser package
  • fft.js (^4.0.4) - FFT computation library
  • react (^18.0.0) - React framework
  • styled-components (^6.0.0) - Styling

Overview

This package enables frequency-domain visualization using the Short-Time Fourier Transform (STFT). Features include:
  • Web Worker computation - FFT processing runs off the main thread
  • OffscreenCanvas rendering - GPU-accelerated spectrogram drawing
  • Virtual scrolling - Memory-efficient for long audio files
  • Configurable color maps - Viridis, Plasma, Inferno, Magma, and more
  • Frequency scales - Linear or logarithmic (mel-like) frequency axis
  • Integration context pattern - Works with or without the spectrogram package

Key Exports

Provider

ExportDescription
SpectrogramProviderProvider component that supplies spectrogram components to the browser package
SpectrogramProviderPropsProvider props type

Components

ExportDescription
SpectrogramMenuItemsUI controls for spectrogram settings
SpectrogramSettingsModalModal dialog for color map and frequency scale selection

Computation

ExportDescription
computeSpectrogram()Compute STFT for stereo audio
computeSpectrogramMono()Compute STFT for mono audio
getColorMap()Get color LUT by name (viridis, plasma, etc.)
getFrequencyScale()Get frequency scale function (linear or logarithmic)
FrequencyScaleNameType for scale names

Worker

ExportDescription
createSpectrogramWorker()Factory for creating spectrogram web workers
SpectrogramWorkerApiWorker API interface
SpectrogramWorkerRenderParamsRender parameters type

Usage

Basic Integration

Wrap your app with SpectrogramProvider to enable spectrogram visualization:
import { WaveformPlaylistProvider, Waveform } from '@waveform-playlist/browser';
import { SpectrogramProvider } from '@waveform-playlist/spectrogram';

function App() {
  const [tracks, setTracks] = useState([]);

  return (
    <SpectrogramProvider>
      <WaveformPlaylistProvider tracks={tracks}>
        <Waveform />
      </WaveformPlaylistProvider>
    </SpectrogramProvider>
  );
}
The SpectrogramProvider must wrap WaveformPlaylistProvider to supply the integration context.

Color Maps

Available color maps for spectrogram rendering:
  • viridis (default) - Perceptually uniform, colorblind-friendly
  • plasma - Purple to yellow gradient
  • inferno - Black to white through red/orange
  • magma - Dark to light through purple/pink
  • jet - Rainbow gradient (not perceptually uniform)
  • hot - Black-red-yellow-white gradient
  • cool - Cyan-magenta gradient
  • gray - Grayscale

Frequency Scales

Two frequency scale options:
  • linear - Uniform frequency spacing (default)
  • logarithmic - Mel-like scale emphasizing lower frequencies

Integration Context Pattern

The spectrogram package uses the same integration pattern as annotations:
// Browser package defines the context
import { 
  SpectrogramIntegrationProvider, 
  useSpectrogramIntegration 
} from '@waveform-playlist/browser';

// Spectrogram package provides the implementation
import { SpectrogramProvider } from '@waveform-playlist/spectrogram';
The useSpectrogramIntegration() hook throws if used without the provider (Kent C. Dodds pattern), ensuring fast failure with clear error messages.

Performance Characteristics

Web Worker Architecture

  • FFT computation runs in a dedicated Web Worker
  • OffscreenCanvas rendering happens off the main thread
  • Virtual scrolling renders only visible spectrogram chunks (1000px wide)
  • Memory usage: ~150MB for 10-hour file (vs ~1.5GB without virtual scrolling)

Browser Support

Requires:
  • Web Workers - All modern browsers
  • OffscreenCanvas - Chrome 69+, Firefox 105+, Safari 16.4+, Edge 79+
Safari versions before 16.4 and Firefox versions before 105 fall back to main-thread rendering, which may impact performance on long files.

Example

import { useState, useEffect } from 'react';
import { 
  WaveformPlaylistProvider, 
  Waveform, 
  useAudioTracks,
  PlayButton,
  PauseButton
} from '@waveform-playlist/browser';
import { SpectrogramProvider, SpectrogramMenuItems } from '@waveform-playlist/spectrogram';

function SpectrogramExample() {
  const { tracks, loading } = useAudioTracks([
    { src: '/audio/music.mp3', name: 'Track 1' }
  ]);

  if (loading) return <div>Loading...</div>;

  return (
    <SpectrogramProvider>
      <WaveformPlaylistProvider tracks={tracks}>
        <div>
          <PlayButton />
          <PauseButton />
          <SpectrogramMenuItems />
        </div>
        <Waveform />
      </WaveformPlaylistProvider>
    </SpectrogramProvider>
  );
}

Source Code

View the complete source code on GitHub:

Build docs developers (and LLMs) love