Skip to content

joe-byounghern-kim/zusound

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

61 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🔊 zusound

npm version bundle size CI License: MIT

Hear your state changes. Debug faster.

zusound is a browser-first Zustand middleware that turns state diffs into short, meaningful Web Audio cues.

  • Zero runtime dependencies (besides Zustand peer dependency)
  • Safe default: disabled in production unless explicitly enabled
  • Lightweight diffing and lazy AudioContext
  • Optional aesthetics mapping for timbre, pleasantness, and timing behavior

Zusound Signal Lab Demo

Try the interactive Signal Lab →

Why Zusound

When state bugs are temporal, logs are often too late. Audio feedback makes update patterns obvious in real time:

  • Infinite loops become rapid-fire bursts
  • Thrashing updates become unstable rhythms
  • Healthy flows become predictable motifs

Install

npm install zusound

Supported Zustand versions: >=4 <6.

Quick Usage

import { create } from 'zustand'
import { zusound } from 'zusound'

const useStore = create(
  zusound((set) => ({
    count: 0,
    inc: () => set((state) => ({ count: state.count + 1 })),
  }))
)

API

zusound(initializer, options?)

The middleware signature matches standard Zustand middleware usage.

createZusound(options?)

Create a configured, stateful instance that works in both middleware and subscriber mode:

import { create } from 'zustand'
import { createZusound } from 'zusound'

const useStore = create((set) => ({
  count: 0,
  inc: () => set((state) => ({ count: state.count + 1 })),
}))

const zs = createZusound({ enabled: true, volume: 0.5, debounceMs: 80 })
const unsubscribe = useStore.subscribe(zs)

// later
unsubscribe()
zs.cleanup()

Use a fresh createZusound(...) instance for each store.subscribe(...) attachment when you want explicit lifecycle control.

ZusoundOptions

Option Type Default Description
enabled boolean true in dev-like envs, false otherwise Enables/disables audio feedback
volume number 0.3 Global playback volume (0..1)
debounceMs number 0 Debounce state-change sound emission
soundMapping Record<string, Partial<SoundParams>> undefined Path-level overrides for timbre/frequency/waveform
aesthetics Partial<AestheticParams> type-specific defaults Base tuning for pleasantness/brightness/arousal/valence/simultaneity
mapChangeToAesthetics (change) => Partial<AestheticParams> undefined Per-change dynamic aesthetic override hook
performanceMode boolean false Uses static consonance ranking to reduce dissonance computation cost
onError (error, context) => void undefined Optional hook for non-fatal middleware/audio errors

Aesthetic Parameters

Param Range Effect
pleasantness 0..1 Consonance selection, supports fractional semitone interpolation
brightness 0..1 Harmonic rolloff control for timbre brightness
arousal 0..1 Envelope speed (attack/decay/release)
valence 0..1 Envelope sustain character
simultaneity 0..1 Dyad onset spread (1 = together, 0 = spread over ~80% duration)
baseMidi number Base pitch center before interval mapping
duration number Optional note duration override (seconds)

Advanced Example

import { create } from 'zustand'
import { zusound } from 'zusound'

const useStore = create(
  zusound(
    (set) => ({
      count: 0,
      status: 'idle',
      inc: () => set((state) => ({ count: state.count + 1 })),
      setStatus: (status: string) => set({ status }),
    }),
    {
      enabled: true,
      volume: 0.28,
      debounceMs: 40,
      performanceMode: false,
      aesthetics: {
        pleasantness: 0.75,
        brightness: 0.65,
        arousal: 0.55,
        valence: 0.6,
        simultaneity: 1,
        baseMidi: 69,
      },
      mapChangeToAesthetics: (change) => {
        if (change.operation === 'add') return { pleasantness: 0.9, valence: 0.8 }
        if (change.operation === 'remove') return { pleasantness: 0.35, arousal: 0.7 }
        return {}
      },
    }
  )
)

Production Notes

  • Defaults are production-safe: audio is off in production unless enabled: true is explicitly set.
  • If the runtime environment cannot be classified, audio stays off unless enabled: true is set.
  • Browsers may keep AudioContext suspended until user interaction.
  • performanceMode is recommended for low-power or high-frequency update scenarios.
  • Use onError if you need telemetry for non-fatal audio/debugging failures.

What You'll Hear

  • Numbers: pitch-centric tones
  • Booleans: short click-like cues
  • Strings: brighter/longer character
  • Objects/arrays: more layered motion

Launch Checklist

Before tagging a release:

pnpm lint
pnpm typecheck
pnpm test:coverage
pnpm build

Release gate setup (GitHub environment + npm trusted publisher) is documented in docs/RELEASE_GATES.md.

Docs Map

  • Quick start: QUICK_START.md
  • Development workflow: DEVELOPMENT.md
  • Package API and recipes: packages/zusound/README.md
  • Contributor workflow: docs/CONTRIB.md
  • Operations runbook: docs/RUNBOOK.md
  • Release gates: docs/RELEASE_GATES.md
  • Security policy: SECURITY.md
  • Technical requirements baseline: REQUIREMENTS.MD

User-Facing Skill Pack

The canonical user-facing skills live in .agents/skills/:

  • zusound-onboarding
  • zusound-tuning
  • zusound-debugging
  • zusound-migration

Run the distribution path locally:

pnpm skills:validate
pnpm skills:bridge

Then load generated local bridge files from .claude/skills/.

Demo

  • Hosted demo: https://joe-byounghern-kim.github.io/zusound/

Run the demo locally:

pnpm build
node demo/server.js

Then open http://localhost:3000.

For detailed demo setup, scenes, and architecture notes, see demo/README.md.

TypeScript users can also verify framework integration with the React + Vite strict demo:

pnpm demo:react:typecheck
pnpm demo:react:dev

See examples/README.md for details.

Pages deploys are automated through .github/workflows/deploy-demo.yml on relevant main changes or manual workflow dispatch.

License

MIT © joe-byounghern-kim

About

zusound: Hear Your State Changes

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors