otofx
v0.1.2
Published
Tiny, dependency-free interaction sounds for the web, synthesized live with Web Audio.
Maintainers
Readme
otofx
Tiny, dependency-free interaction sounds for the web. Every cue is synthesized live with the Web Audio API — no audio files, no runtime deps, ~4KB.
Demo: otofx.pages.dev
22 cues out of the box: chime sparkle droplet bloom whisper tick
press release toggle success pop blip swoosh ding alert
error unlock complete notify click expand collapse.
Install
npm install otofxUsage
Declarative — data attributes
<button data-oto-press data-oto-release>Save</button>
<a data-oto-hover="tick">Docs</a>
<button data-oto-toggle aria-pressed="false">Dark mode</button>import { bind } from "otofx";
bind(); // wires every data-oto-* attribute currently in the DOMCall bind() again (or pass a container element) whenever you add new
interactive elements dynamically — it re-scans from scratch. Call
unbind() to remove all listeners.
Imperative
import { play } from "otofx";
play("success");
play("toggle", { on: true }); // toggle cue takes an on/off flagVolume
import { setVolume, mute, unmute } from "otofx";
setVolume(0.5); // 0 (silent) to 1 (full)
mute();
unmute();Custom cues
Register your own using the same synthesis primitives, or bring your own Web Audio graph entirely:
import { register, play, tone } from "otofx";
register("boop", () => tone(300, 0.1, "sine", 0, 0.2));
play("boop");Why synthesized, not sampled
No audio files means no network requests, no format/codec concerns, no asset pipeline — the whole library is source code. It also means every cue is trivially tweakable: change a frequency, a duration, a waveform type, and you've got a new sound.
Browser autoplay policy
Browsers block audio until a user gesture. bind() and play() both
lazily create the shared AudioContext on first use, so as long as
you're calling them from inside a click/press/hover handler (which
bind() does for you), this is handled automatically.
License
MIT
