No audio files. No config. No setup.
Pure Web Audio API synthesis at runtime.
32 sounds. One import.
npm i sonance
Your button clicks in silence.
Your form submits in silence.
Your delete confirmation —
the one that wipes everything —
in silence.
All 32 sounds. Generated in your browser at runtime. No files fetched. Just math turned into sound.
// first click wakes the audio engine. browser policy, not ours.
Apple has a sound team.
Slack has a sound team.
You have one import.
Not samples. Not presets. Each one is synthesized — specific frequency, envelope, and character designed for a specific moment in your UI.
Sound reduces cognitive load.
Users stop watching the screen.
They start trusting the product.
Not a React library. Not a Vue plugin. A plain JavaScript object. Works wherever JS runs.
import { sonance } from "sonance" export function SaveButton() { async function handle() { try { await save() sonance.play("success") } catch { sonance.play("error") } } return <button onClick={handle}>Save</button> }
import { sonance } from "sonance" document.querySelector("#save") .addEventListener("click", async () => { sonance.play("click") await save() sonance.play("saved") })
<script setup> import { sonance } from "sonance" </script> <template> <button @click="sonance.play('confirm')"> Save </button> </template>
<script> import { sonance } from "sonance" </script> <button on:click={() => sonance.play("confirm")}> Save </button>
Every play() returns a handle. Which means you can do things that are either genuinely useful or deeply unnecessary. Both are valid.
We're not hiding anything. This is genuinely it.
import { sonance } from "sonance" // options: gain, pitch (semitones), speed sonance.play("confirm", { pitch: +4, gain: 0.8 }) // chain sonance.play("confirm") .then("success", 300) // custom sound sonance.register({ id: "myPop", pitchRange: [-1, 1], fn(v) { v({ freq: 400, dur: 0.1, gain: 0.3 }) } })
Your favicon is probably bigger
than this entire library.
Ship sounds already.