npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

wavegram

v0.1.2

Published

Lightweight waveform and spectrogram Web Component for audio previews.

Readme

wavegram

Lightweight Web Component for previewing audio with a synchronized waveform, spectrogram, and playback cursor. It is intended for research demos, paper companion pages, audio dataset previews, and source-separation result comparisons.

Wavegram aims to provide a minimal, academic, and scientific visualization surface rather than a general-purpose media player or audio editor.

It is not an editor. It does not implement recording, effects, multitrack editing, annotation editing, ASR, or server-side processing.

Design Focus

Wavegram is closest in spirit to lightweight waveform players, but its primary view is not just a waveform. It always treats waveform and spectrogram as two synchronized views over the same audio timeline.

The core feature set is deliberately narrow:

  • Simultaneous waveform and spectrogram display.
  • One playback cursor rendered at the same time position in both views.
  • Click-to-seek from either waveform or spectrogram. By default, clicking a stopped player starts playback from that position, and clicking a playing player pauses after seeking.
  • Minimal, low-decoration presentation suitable for academic papers, scientific demos, and dataset browsers.
  • No DAW-style editing, multitrack arrangement, effects, recording, or annotation workflow.

Install

npm install wavegram
import "wavegram";

Minimal Usage

<wavegram-player
  src="https://raw.githubusercontent.com/pdx-cs-sound/wavs/main/voice.wav"
></wavegram-player>

Minimal wavegram-player example showing a waveform and spectrogram

The package is named wavegram. The custom element tag is wavegram-player because browser custom element names must contain a hyphen.

The src value may be a relative URL such as audio/example.wav or an absolute URI such as the example above. Remote audio must be served with CORS headers so the component can fetch and decode it for waveform and spectrogram analysis.

const player = document.createElement("wavegram-player");
player.src = "https://raw.githubusercontent.com/pdx-cs-sound/wavs/main/voice.wav";
document.body.appendChild(player);

Attributes

| Attribute | Property | Default | Description | | --- | --- | --- | --- | | src | src | "" | Audio URL. Uses browser-supported decodeAudioData() formats. | | height | height | 200 | Total visual height. Used to auto-allocate pane heights when individual heights are not set. | | waveform-height | waveformHeight | 80 | Waveform canvas height in CSS pixels. | | spectrogram-height | spectrogramHeight | 120 | Spectrogram canvas height in CSS pixels. | | show-waveform | showWaveform | true | Show waveform pane. | | show-spectrogram | showSpectrogram | true | Show spectrogram pane. | | show-controls | showControls | false | Show the play/pause button. | | show-time | showTime | false | Show current time and duration. | | waveform-style | waveformStyle | waveform | waveform, bars, lines, blocks, or dots. line is accepted as a legacy alias. | | waveform-bar-width | waveformBarWidth | style-dependent | Width of bars, blocks, or dots in CSS pixels. | | waveform-bar-spacing | waveformBarSpacing | style-dependent | Spacing between bars, blocks, or dots in CSS pixels. | | autoplay | autoplay | false | Start playback after loading. Browser autoplay policies still apply. | | fft-size | fftSize | 1024 | Radix-2 FFT size. Non-power-of-two values are errors. | | hop-size | hopSize | 256 | STFT hop size in samples. | | window-type | windowType | hann | hann, hamming, or rectangular. | | min-db | minDb | -80 | Lower display bound. | | max-db | maxDb | 0 | Upper display bound. | | color-map | colorMap | audition | audition, gray, magma, viridis, or inferno. | | channel | channel | mix | mix or zero-based channel index. |

Events

The component dispatches CustomEvents named loadstart, loaded, play, pause, seek, timeupdate, profile, playprofile, and error.

Normal event detail:

{
  currentTime: number;
  duration: number;
}

Error event detail:

{
  message: string;
  cause?: unknown;
}

profile reports load and analysis timing in milliseconds. It is emitted once when the player first becomes usable and again when spectrogram analysis finishes:

{
  fetchMs: number;
  audioReadyMs: number;
  decodeMs: number;
  waveformMs: number;
  spectrogramMs?: number;
  firstUsableMs: number;
  totalMs?: number;
}

playprofile reports playback startup latency:

{
  playToPlayingMs: number;
}

Spectrogram Settings

Spectrograms are computed with STFT:

S[k, t] = 20 log10(|FFT(x_t)[k]| + 1e-10)

The internal values layout is time-major:

values[t * freqBins + k]

The initial implementation uses a pure TypeScript radix-2 FFT and runs spectrogram analysis in a Web Worker when Workers are available. If Workers are unavailable, the component can fall back to waveform-only or main-thread analysis depending on the environment.

Browser Support

Audio decoding follows AudioContext.decodeAudioData() support in the user's browser. WAV, MP3, and Ogg Vorbis are common targets. FLAC support is browser-dependent.

Playback uses HTMLAudioElement; waveform and spectrogram analysis use AudioBuffer.

Backward Compatibility

The recommended element name is <wavegram-player>. The older <audio-preview-spectrogram> tag is still registered as a compatibility alias.

Demo Audio

The examples use WAV files from pdx-cs-sound/wavs, a sample collection for Portland State University's Computers, Sound and Music course. The repository states that the files are Creative Commons CC0 unless otherwise indicated.

The 16 kHz keyword-spotting example uses a WAV file from fkuhne/KWS-Dataset. Its wavs directory is described by that project as WAV audio converted to 16 kHz and is distributed under CC0-1.0.

Acknowledgements

Wavegram is inspired by wavesurfer.js, especially its lightweight browser-based waveform player model. Wavegram is an independent implementation focused on synchronized waveform and spectrogram previews for research demos and dataset browsing.

Styling

The component uses Shadow DOM and supports CSS custom properties:

wavegram-player {
  --ap-bg: #ffffff;
  --ap-fg: #222222;
  --ap-waveform-bg: #020604;
  --ap-waveform: rgba(0, 214, 163, 0.34);
  --ap-waveform-played: #00f0b5;
  --ap-waveform-center: rgba(0, 92, 58, 0.7);
  --ap-waveform-progress: #00f0b5;
  --ap-cursor: #00d7ff;
  --ap-cursor-shadow: rgba(0, 0, 0, 0.45);
  --ap-spectrogram-tick: rgba(255, 255, 255, 0.42);
  --ap-spectrogram-unplayed-opacity: 0.48;
  --ap-border: #dddddd;
}

Known Limitations

Long audio files are supported conservatively in the initial version. Large decoded buffers can still consume significant memory, and precomputed waveform or spectrogram JSON is reserved for a future extension.

The component fetches each audio source once, then creates a Blob URL for playback and decodes the same ArrayBuffer for analysis. This avoids a second network request for HTMLAudioElement playback.

Development

npm install
npm run build
npm test
npm run test:e2e

Examples

Run the local dev server:

npm run dev -- --port 4173

Then open:

  • http://127.0.0.1:4173/examples/basic.html
  • http://127.0.0.1:4173/examples/multiple.html
  • http://127.0.0.1:4173/examples/large-file.html
  • http://127.0.0.1:4173/examples/profile.html
  • http://127.0.0.1:4173/examples/multichannel.html
  • http://127.0.0.1:4173/examples/kws-16khz.html
  • http://127.0.0.1:4173/examples/waveform-only.html
  • http://127.0.0.1:4173/examples/spectrogram-only.html
  • http://127.0.0.1:4173/examples/styles.html

For automated local checks, run:

npm run test
npm run typecheck
npm run build
npm run test:e2e

License

MIT