Skip to content

v0.1.0 — first public release

Latest

Choose a tag to compare

@productdevbook productdevbook released this 30 Apr 11:42
· 2 commits to main since this release

First public release of seslen — a zero-dependency Web Audio library that ships with 36 synthesised UI sound presets and a high-DX API on top of AudioContext. No audio files, no network, no decode: every preset is generated at call time from oscillators + envelopes.

import { createSeslen } from "seslen"
import { presets, presetDefaults } from "seslen/presets"

const ses = createSeslen({
  sources: presets,
  defaults: presetDefaults,
  persist: "seslen:master",
})

await ses.play("victory")

What's in the box

Core API

  • createSeslen({ sources, defaults, volume, buses, maxVoices, respectReducedMotion, persist })
  • play(name, opts?) — returns Promise<PlayHandle | null> (null when throttled / dropped)
  • playPattern(steps) — schedule a timed sequence
  • preload, stop(name), stopAll, register, unregister, has, names
  • Master: getVolume, setVolume, mute, unmute, isMuted
  • Lifecycle: pause, resume, close, isReady, state
  • Events: play, ended, throttled, statechange

Web Audio surface

  • 🎛 Per-call optionsgain, rate, detune, loop, pan, fadeIn, fadeOut, when, sprite, interrupt
  • 🌀 JitterrateJitter / gainJitter / detuneJitter so 100 ticks don't sound like 1 tick repeated
  • 🚦 Throttle per call — drop rapid-fire repeats inside a window
  • 🎚 Polyphony cap — per-source voices + steal: "oldest" | "newest" | "drop"
  • 🚌 Buses — named sub-mixers (ses.bus("music")) with their own volume / mute and ducking (sidechain)
  • Sample-accurate schedulingplay(name, { when: ses.now() + 0.25 })
  • 🪄 PlayHandlestop, done, duration, onEnded, fadeTo, setGain, rampRate
  • 📼 OfflineAudioContext render-to-WAVawait ses.render("victory") returns a Blob
  • 📈 AnalyserNode tapses.analyser({ fftSize }) for waveform / spectrum data

Accessibility, persistence, SSR

  • ♿️ Honours prefers-reduced-motion: reduce by auto-muting (opt-out via respectReducedMotion: false)
  • 💾 localStorage persistence for master volume + mute (opt-in via persist: "key")
  • 🛡 SSR-safe stub at seslen/server — every method is a typed no-op
  • 🔓 Auto-unlocks the AudioContext on the first user gesture

36 built-in presets

Group Presets
Original eight tick, success, error, warning, message, add, delete, victory
UI feedback hover, pop, swoosh, toggle-on, toggle-off, notify, keypress, scroll-tick, drag, drop, expand, collapse, undo, redo, send, receive, copy, paste
Game / playful level-up, coin, jump, shoot, explosion
Ambient / state heartbeat, alarm, typewriter, lock, unlock

Every preset ships its own metadata (label, description, tags, recipe, durationMs, motion, accent, defaults) so picker UIs and docs can introspect the library directly.

Quality

  • Zero runtime dependencies
  • Pure ESM, tree-shakeable
  • Strict TypeScript (tsgo --noEmit clean, verbatimModuleSyntax, isolatedModules)
  • Vitest 56/56 green — separate suites for buses, voices, throttle, jitter, persist, render, presets, registry, cache, server stub and the browser integration
  • Bundle budget enforced — core 12 KB raw, presets/index 8 KB, preset entry 2 KB, server 2 KB (gzip ≈ ⅓)

Playground

web/ ships a Vite + React + Tailwind v4 + Tanstack Router composer where you can drop preset blocks onto lanes, edit timing/intensity per block, share patterns via URL, render the snippet with syntax-highlighted code via @comark/react, and preview the waveform live.

Install

npm install seslen

What's next (v0.2.0)

  • Framework adapters: seslen/react, seslen/vue, seslen/svelte
  • Theme / preset packs (shadcn-style installable preset bundles)
  • Per-instance effect chain (filter / reverb send) + built-in reverb / compressor