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

@broberg/soundkit

v0.1.0

Published

Browser audio-effect engine: a zero-dependency Web Audio synth (oscillator tones + noise) with autoplay-policy handling (lazy AudioContext gated on the first user gesture), a single typed play(name) over a sound registry, mute/volume persisted to localSto

Readme

@broberg/soundkit

A tiny browser audio-effect engine — synthesized tones + noise via the Web Audio API, optional MP3/Opus via Howler.js, a single typed play(name) over a sound registry, and mute/volume persisted to localStorage. It handles the browser autoplay policy for you (the AudioContext is created + resumed on the first user gesture) and ships dark: with no Web Audio in scope it's an inert no-op that never throws, so it's safe to construct anywhere.

Generalises the ~80-line Web Audio file independently hand-copied into buddy, cms and catan.

npm i @broberg/soundkit

Core (no framework)

import { createSoundKit } from "@broberg/soundkit";
import { UI_SOUNDS } from "@broberg/soundkit/presets";

const kit = createSoundKit(UI_SOUNDS);      // or your own registry
// … on a click / keydown somewhere in the app the engine warms up automatically
kit.play("success");
kit.toggleMute();                            // persisted to localStorage
kit.setVolume(0.5);                          // master volume, persisted

A sound is a step or an ordered sequence of steps — a tone, a noise burst, or a file — each with an optional delay (ms) so you can compose little jingles:

const registry = {
  ping:  [{ freq: 880, duration: 0.2, type: "sine", volume: 0.15 }],
  chord: [
    { freq: 523, duration: 0.12, type: "sine" },
    { freq: 659, duration: 0.16, type: "sine", delay: 100 },
  ],
  tick:  [{ noise: 0.05, volume: 0.18 }, { freq: 300, duration: 0.08, type: "triangle" }],
  bell:  { file: "/sounds/bell.mp3", volume: 0.7 },   // needs the Howler layer
};

play(name) on an unknown name, before the first gesture, or with no Web Audio present is always a safe no-op.

File sounds (optional Howler layer)

howler is an optional peer — tone-only apps tree-shake it out. Enable file playback by passing the Howler namespace (avoids a dynamic import):

import { Howl, Howler } from "howler";
const kit = createSoundKit(registry, { howler: { Howl, Howler } });
kit.play("bell");            // plays the MP3; mute() also calls Howler.mute()

Without Howler, file steps silently no-op while every tone/noise sound keeps working.

React (Stack A)

import { useSoundKit } from "@broberg/soundkit/react";
import { UI_SOUNDS } from "@broberg/soundkit/presets";

function Toolbar() {
  const sound = useSoundKit(UI_SOUNDS);
  return (
    <button data-testid="mute-toggle" onClick={sound.toggleMute} onMouseDown={() => sound.play("click")}>
      {sound.muted ? "🔇" : "🔊"}
    </button>
  );
}

The kit is created once (stable across re-renders); muted/volume are reactive React state kept in sync with the engine, torn down on unmount. react is an optional peer; no next/* import, so it works in any React app.

Preact signals (Stack B)

import { useSoundKitSignals } from "@broberg/soundkit/preact";

const { kit, enabled, volume } = useSoundKitSignals(UI_SOUNDS);
enabled.value = false;   // mutes
volume.value = 0.4;      // sets master volume
kit.play("notify");

enabled/volume are @preact/signals wired to the engine via effect() (the trail ambient-store pattern) and persisted to localStorage.

Options

createSoundKit(registry, {
  storageKeyPrefix: "myapp-sound",   // localStorage keys, default "broberg-soundkit"
  initialVolume: 0.8,                // 0–1, used when nothing is persisted
  disabled: userPrefersSilence,      // force the kit inert (consumer policy)
  howler: { Howl, Howler },          // enable file playback
  // audioContextFactory / storage — injection seams for tests + custom hosts
});

Presets

UI_SOUNDS (success · notify · click · error) is a small brand-neutral starter set. buddy's severity tones and cms's publish/expire chimes ship as exact-transcribed BUDDY_SOUNDS / CMS_SOUNDS presets when those apps adopt the package (so their audio stays byte-identical post-migration).

Notes

  • Autoplay policy — audio can't start before a user gesture; the engine arms itself on the first click/keydown, so play() before any interaction is a no-op by design.
  • Zero runtime deps — core is pure Web Audio; howler, react, preact and @preact/signals are all optional peers.
  • Not an ambient-stream engine — this is for short UI/game SFX, deliberately separate from a long-running ambient audio provider.

License

MIT · part of the @broberg/* shared inventory.