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

@open-din/react

v0.1.0

Published

A React-first declarative WebAudio library for building audio graphs

Readme

@open-din/react

A React-first declarative WebAudio library for building audio graphs, focused for interactive sound design.

The DIN editor product is being split into a separate din-studio repository so this repository can stay focused on the @open-din/react library surface.

Build complex audio graphs using React's declarative paradigm. Audio nodes are represented as React components that automatically connect based on their parent-child relationships.

[!WARNING]
This is a work in progress. The API is not stable and may change in the future. It has been published under the npm package name @open-din/react.

Features

  • 🎛️ Declarative Audio Graph - Build audio graphs using JSX components
  • 🔊 AudioContext Management - Automatic context creation, unlock handling, and master bus
  • 🎹 Sequencer & Transport - Musical timing with BPM, time signature, and step sequencing
  • 🎯 Scoped Triggers - Per-track trigger events for instruments
  • 🎚️ MIDI Runtime - Shared MIDI provider, hooks, transport sync, and declarative MIDI outputs
  • 📊 Analyzers - FFT, waveform, and metering analysis
  • 🎨 Effects - Reverb, Chorus, Distortion, and more
  • 🖥️ SSR-Safe - No AudioContext errors on the server
  • Headless - No DOM output, pure audio graph
  • 🔊 3D Spatial Audio - Built-in Panner for 3D positioning

Installation

npm install @open-din/react
# or
yarn add @open-din/react
# or
pnpm add @open-din/react

Quick Start

import { AudioProvider, Gain, Filter, Osc } from '@open-din/react';

function App() {
  return (
    <AudioProvider masterGain={0.8}>
      <Gain gain={0.5}>
        <Filter type="lowpass" frequency={1000}>
          <Osc type="sawtooth" frequency={440} autoStart />
        </Filter>
      </Gain>
    </AudioProvider>
  );
}

Core Concepts

Audio Graph

Components automatically connect to their parent's output. The tree structure defines the audio routing:

<AudioProvider>           {/* Creates AudioContext + master bus */}
  <Gain gain={0.8}>       {/* Connects to master bus */}
    <Filter>              {/* Connects to Gain above */}
      <Osc />             {/* Connects to Filter above */}
    </Filter>
  </Gain>
</AudioProvider>

Sequencer & Tracks

Create step sequences with pattern-based triggering:

import { Sequencer, Track, useTrigger, Sampler } from '@open-din/react';

function DrumMachine() {
  return (
    <Sequencer bpm={120} steps={16} loop autoStart>
      <Track id="kick" pattern={[1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]}>
        <Sampler src="/kick.wav" />
      </Track>
      <Track id="snare" pattern={[0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]}>
        <Sampler src="/snare.wav" />
      </Track>
    </Sequencer>
  );
}

Transport

Use musical timing with the transport system:

import { TransportProvider, useTransport, useBeat } from '@open-din/react';

function PlayButton() {
  const { isPlaying, play, stop, bpm } = useTransport();
  
  return (
    <button onClick={isPlaying ? stop : play}>
      {isPlaying ? '⏹' : '▶'} {bpm} BPM
    </button>
  );
}

function BeatDisplay() {
  const { beat, bar, step } = useBeat('step');
  return <div>Bar {bar + 1}, Beat {beat + 1}</div>;
}

MIDI

Use the shared MIDI runtime for note input, controller input, outbound MIDI, and transport sync:

import {
  AudioProvider,
  MidiProvider,
  MidiNoteInput,
  MidiCCOutput,
  MidiTransportSync,
  TransportProvider,
} from '@open-din/react';

function MidiPatch() {
  return (
    <MidiProvider requestOnMount>
      <AudioProvider>
        <TransportProvider>
          <MidiTransportSync mode="transport-master" />
          <MidiNoteInput>
            {({ note, gate }) => (
              <MidiCCOutput cc={74} value={gate ? 0.8 : 0.2} />
            )}
          </MidiNoteInput>
        </TransportProvider>
      </AudioProvider>
    </MidiProvider>
  );
}

Analyzers

Analyze audio with FFT and metering:

import { useFFT, useMeter, Analyzer } from '@open-din/react';

function Visualizer() {
  const { bass, mid, high, spectrum } = useFFT({ fftSize: 512 });
  const { rmsDb, isClipping } = useMeter();
  
  return (
    <div style={{ transform: `scale(${1 + bass * 0.5})` }}>
      Level: {rmsDb.toFixed(1)} dB
    </div>
  );
}

Effects

Apply effects to audio:

import { Reverb, Chorus, Distortion } from '@open-din/react/effects';

function EffectsChain() {
  return (
    <Reverb decay={2} mix={0.3}>
      <Chorus rate={1.5} depth={3} mix={0.4}>
        <Distortion type="soft" drive={0.5}>
          <Osc type="sawtooth" frequency={220} />
        </Distortion>
      </Chorus>
    </Reverb>
  );
}

Notes & Frequencies

Use note strings (English or French) instead of raw MIDI numbers:

import { noteToMidi, midiToNote, noteToFreq, parseNote } from '@open-din/react';

// English note names
noteToMidi('C4');      // 60
noteToMidi('A4');      // 69
noteToFreq('A4');      // 440

// French (solfege) names
noteToMidi('Do4');     // 60
noteToMidi('Sol#2');   // 44
noteToFreq('La4');     // 440

// MIDI to note
midiToNote(60);        // "C4"
midiToNote(61, true);  // "Db4" (prefer flats)

// Parse any note format
parseNote('Eb4');      // { note: 'D#', octave: 4, midi: 63, frequency: 311.13 }

Synths

Built-in synthesizer components inspired by Tone.js:

import { Synth, MonoSynth, FMSynth, AMSynth, NoiseSynth, Envelope } from '@open-din/react';

// Basic synth with ADSR envelope
<Track id="lead" pattern={pattern}>
  <Synth
    notes={['C4', 'E4', 'G4', 'C5']}
    oscillator={{ type: 'sawtooth' }}
    envelope={{ attack: 0.01, decay: 0.2, sustain: 0.7, release: 0.3 }}
    filter={{ type: 'lowpass', frequency: 2000, Q: 2 }}
  />
</Track>

// TB-303 style acid synth with filter envelope
<Track id="acid" pattern={pattern}>
  <MonoSynth
    notes={['C3', 'C3', 'G3', 'C4']}
    accents={[1, 0, 0, 1]}
    oscillator={{ type: 'sawtooth' }}
    filter={{ frequency: 600, Q: 15, envelope: 3000 }}
  />
</Track>

// FM synthesis
<FMSynth
  notes={notes}
  modulationRatio={2}
  modulationIndex={3}
  envelope={{ attack: 0.01, decay: 0.3, sustain: 0.4, release: 0.5 }}
/>

// Standalone envelope wrapper
<Envelope attack={0.01} decay={0.2} sustain={0.7} release={0.5}>
  <Osc type="sawtooth" frequency={440} autoStart />
</Envelope>

// Custom Patching with Voice (Mono)
<Track id="lead" pattern={pattern}>
  <Voice portamento={0.02}>
    {(v) => (
      <Envelope trigger={v.gate} velocity={v.velocity} duration={v.duration}>
        <Filter frequency={v.frequency * 4}>
           {/* v.oscRef allows Voice to schedule frequency updates without re-renders */}
           <Osc nodeRef={v.oscRef} type="sawtooth" autoStart />
        </Filter>
      </Envelope>
    )}
  </Voice>
</Track>

// Polyphonic Patching
<Track id="pad" pattern={pattern}>
  <PolyVoice voices={8} notes={notes} portamento={0.05}>
    {(v) => (
      <Envelope trigger={v.gate} velocity={v.velocity} duration={v.duration}>
        <Osc nodeRef={v.oscRef} type="sine" autoStart />
      </Envelope>
    )}
  </PolyVoice>
</Track>

3D Spatial Audio

Use the Panner component for 3D positional audio:

import { AudioProvider, Panner, Sampler } from '@open-din/react';

function SpatialAudio() {
  const [position, setPosition] = useState({ x: 0, y: 0, z: -5 });
  
  return (
    <AudioProvider>
      <Panner
        positionX={position.x}
        positionY={position.y}
        positionZ={position.z}
        panningModel="HRTF"
        distanceModel="inverse"
        refDistance={1}
        maxDistance={10000}
        rolloffFactor={1}
      >
        <Sampler src="/ambient.wav" loop autoStart />
      </Panner>
    </AudioProvider>
  );
}

API Reference

Core

| Export | Type | Description | |--------|------|-------------| | AudioProvider | Component | Root provider, owns AudioContext | | useAudio | Hook | Access AudioContext and state |

Nodes

| Export | Type | Description | |--------|------|-------------| | Gain | Component | Volume control | | Filter | Component | Biquad filter (lowpass, highpass, etc.) | | Osc | Component | Oscillator (sine, square, sawtooth, triangle) | | Delay | Component | Delay effect | | Compressor | Component | Dynamics compressor | | Convolver | Component | Convolution reverb | | Panner | Component | 3D spatial audio | | StereoPanner | Component | Simple L/R panning | | WaveShaper | Component | Distortion/waveshaping |

Transport

| Export | Type | Description | |--------|------|-------------| | TransportProvider | Component | Musical timing provider | | useTransport | Hook | Access transport state and controls | | useBeat | Hook | Reactive time position |

Sequencer

| Export | Type | Description | |--------|------|-------------| | Sequencer | Component | Step sequencer | | Track | Component | Defines pattern and triggers children | | useTrigger | Hook | Receive trigger events (state-based) | | useOnTrigger | Hook | Receive trigger events (callback-based) |

Analyzers

| Export | Type | Description | |--------|------|-------------| | Analyzer | Component | Analysis node | | useAnalyzer | Hook | Raw analysis data | | useFFT | Hook | Frequency band analysis | | useMeter | Hook | Level metering |

Sources

| Export | Type | Description | |--------|------|-------------| | Sampler | Component | Audio buffer playback | | Noise | Component | Noise generator | | MediaStream | Component | Microphone/stream input | | ConstantSource | Component | Constant value source |

Effects

| Export | Type | Description | |--------|------|-------------| | Reverb | Component | Algorithmic/convolution reverb | | Chorus | Component | Chorus effect | | Distortion | Component | Distortion/overdrive |

Utils

| Export | Type | Description | |--------|------|-------------| | useFrame | Hook | Per-frame updates | | tickAudio | Function | Manual frame tick for external loops | | isSSR | Function | Check if running on server |

Documentation

Examples

The example workspace stays in the repository for local development and release verification, but it is not bundled into the published npm tarball.

DIN Editor MCP

The local MCP server for DIN Editor lives in editor/targets/mcp.

npm run editor:build:web
npm run editor:build:app
npm run editor:build:mcp
npm run editor:mcp:start

The editor now has one root build surface with three targets:

  • editor:build:web for the stateless web shell
  • editor:build:app for the Electron app shell
  • editor:build:mcp for the local MCP runtime

The MCP target stays local-only. It exposes a stdio MCP server plus a loopback bridge so an AI agent can inspect, preview, and apply graph operations against a live DIN Editor instance or work offline from patch JSON files.

For local development, run the dev MCP server over plain HTTP on localhost:

npm run editor:dev:mcp

By default, the dev bridge uses http://localhost:17374 so it does not collide with the secure standalone MCP server on 17373.

Use npm run editor:mcp:start only for the secure standalone MCP server. If you want the browser editor to connect to that secure server, you must trust the generated local CA and set VITE_DIN_EDITOR_MCP_PROTOCOL=https.

Quality Gates

npm run validate:docs
npm run validate:patch-schema
npm run validate:coverage
npm run validate:changes
npm run test:library
npm run test:editor
npm run test:e2e

Every component and DIN Editor node in scope is mapped to a dedicated documentation page and at least one required automated test file in project/COVERAGE_MANIFEST.json. Any source change must update the mapped docs and tests in the same change set. The public patch JSON contract is versioned and tracked separately in schemas/patch.schema.json.

Spatial Audio with @react-three/drei

If you're using react-three-fiber for 3D graphics, you can integrate spatial audio using @react-three/drei's PositionalAudio component which wraps Three.js Audio system.

import { Canvas } from '@react-three/fiber';
import { PositionalAudio } from '@react-three/drei';

function Scene() {
  return (
    <Canvas>
      {/* Moving audio source in 3D space */}
      <mesh position={[5, 0, 0]}>
        <sphereGeometry args={[0.5]} />
        <meshStandardMaterial color="hotpink" />
        <PositionalAudio
          url="/sounds/ambient.mp3"
          distance={1}
          loop
          autoplay
        />
      </mesh>
      
      {/* Camera acts as the listener */}
      <OrbitControls />
    </Canvas>
  );
}

For more advanced Three.js audio integration, see the drei PositionalAudio documentation.

License

MIT