Procedural Web Audio UI sound engine. Spatial HRTF, brand voice seeding, and zero network requests.
Preview • Source Code • SpaceUI.one
@usespaceui/sounds is a highly-optimized procedural sound engine for the web.
No .mp3 or .wav files to load. Everything is generated entirely in the browser using the Web Audio API with Apple device output mastering and 3D spatial panning.
pnpm add @usespaceui/sounds
# or
npm install @usespaceui/sounds
# or
yarn add @usespaceui/soundsZero dependencies. react >= 18 is an optional peer dependency, only needed if you use the useSpaceSound hook.
You can automatically bind sounds to DOM events without writing repetitive event listeners. Call bind() once in your app entry point, and then use data-space-* attributes on any element. If you leave the attribute empty, it will use its sensible default.
import { bind } from '@usespaceui/sounds'
// Call once at app startup
bind()<!-- Automatically plays "tap" on click (default behavior) -->
<button data-space-click>Submit</button>
<!-- Plays a specific sound ("confirm") overriding the default -->
<button data-space-click="confirm">Save Changes</button>
<!-- Plays "tick" on mouse hover (debounced automatically) -->
<a href="#" data-space-hover>Hover me</a>
<!-- Plays "press" on pointerdown, and "release" on pointerup -->
<div data-space-press data-space-release>Press me</div>
<!-- Automatically calculates 3D spatial panning based on element position on screen -->
<button data-space-click="sparkle" data-space-spatial>Spatial Sound</button>data-space-click-> Defaults totap(Listens to theclickevent)data-space-hover-> Defaults totick(Listens to thepointerenterevent. Automatically debounced and ignores touch/coarse pointers)data-space-press-> Defaults topress(Listens to thepointerdownevent)data-space-release-> Defaults torelease(Listens to thepointerupevent)data-space-toggle-> Defaults totoggle-on(Listens to theclickevent. Ideal for switches/checkboxes)data-space-sound-> Defaults toconfirm(Listens to theclickevent. Ideal for primary actions)data-space-contextmenu-> Defaults toopen(Listens to thecontextmenuright-click event)data-space-copy-> Defaults tocopy(Listens to the nativecopyevent)data-space-paste-> Defaults topaste(Listens to the nativepasteevent)
Because bind() uses delegated event listeners, you can attach attributes directly to your <body> (or root layout) to enable app-wide audio interactions:
<!-- Enables app-wide sound feedback for click, right-click, copy, and paste -->
<body data-space-click data-space-contextmenu data-space-copy data-space-paste>
...
</body>| Attribute | Default Sound | Description |
|---|---|---|
data-space-click |
tap |
Plays on general clicks across elements without specific sound overrides. |
data-space-contextmenu |
open |
Plays on every right-click context menu event anywhere on the page. |
data-space-copy |
copy |
Plays on any native copy action (via Ctrl+C / Cmd+C or context menu). |
data-space-paste |
paste |
Plays on any native paste action into inputs or editable areas (via Ctrl+V / Cmd+V). |
If you use React, the useSpaceSound hook gives you bound functions to trigger sounds and manage engine settings inside your components.
import { useSpaceSound } from '@usespaceui/sounds'
export default function Demo() {
const { tap, confirm, slide, setVolume } = useSpaceSound()
return (
<button
onPointerDown={() => tap()}
onClick={() => {
confirm()
slide('in')
}}
>
Submit Action
</button>
)
}Note for React users: You can absolutely use the HTML data attributes approach in React instead of hooks! It's often cleaner for simple buttons. Just call
bind()once in a root layout or a generic Provider:
// components/SoundProvider.tsx
'use client'
import { useEffect } from 'react'
import { bind } from '@usespaceui/sounds'
export function SoundProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
bind() // Safely binds delegated event listeners to document
}, [])
return <>{children}</>
}Then sprinkle the data attributes on your standard HTML elements anywhere in your app:
<button data-space-click="sparkle">I play a sound!</button>You can also trigger sounds procedurally and adjust the engine settings globally via direct imports.
import { tap, slide, setVoice, play } from '@usespaceui/sounds'
// Set an optional global brand voice seed (alters the tonality of all sounds)
setVoice('Space UI')
// Trigger directly via dedicated functions
tap()
slide('in') // Some triggers accept parameters
// Or dynamically by name (useful for CMS or dynamic mappings)
play('slide-in', { volume: 0.8 })There are multiple ways to trigger sounds:
- Direct method imports:
import { tap } from "@usespaceui/sounds" - React Hook:
const { tap } = useSpaceSound() - Dynamic String:
play("tap") - HTML attribute:
<button data-space-click="tap">
The package includes 24 procedural interactions:
- Core:
tap,press,release,tick,page - Actions:
copy,paste,remove,confirm,deny - Overlays:
open,close - Status:
loading,ready - Tones:
chime,sparkle,droplet,bloom,whisper - Directional (requires argument):
nudge('up' | 'down')toggle('on' | 'off')slide('in' | 'out')turn('forward' | 'back')
Note: When using play or HTML attributes, directional triggers use hyphenated strings (e.g. play("slide-in") or data-space-click="toggle-on").
-
useSpaceSound()React hook providing all sound trigger methods, properly bound to the engine, as well as state forvolumeandenabled. -
play(name: string, options?: PlayOptions)Helper to play any sound dynamically using its string name. -
setVoice(seed: string | null)Set a deterministic brand voice seed to slightly alter the tonality of all sounds. -
setOutputProfile(profile: OutputProfile)Adjusts the mastering EQ curve applied to all sounds, optimizing them for different listening environments. Profiles available:"auto": Detects the device and picks the best EQ curve automatically. (Default)"headphones": Flatter frequency response with a subtle bass lift, optimized for close-ear listening and binaural spatial panning."speakers": Compensates for the limited frequency range of typical laptop and monitor speakers by boosting presence and low-end."studio": Completely flat, uncolored output designed for high-fidelity studio monitors and mixing environments.
import { setOutputProfile } from '@usespaceui/sounds' setOutputProfile('headphones')
-
setRespectReducedMotion(respect: boolean)If enabled, completely mutes sounds when the user prefers reduced motion (enabled by default). -
bind(root?: ParentNode)Utility to automatically bind DOM interactions to a sound via event delegation. Safe to call multiple times.
| Package | Description |
|---|---|
@usespaceui/avatars |
Generative deterministic avatars |
@usespaceui/squircle |
Figma-style corner smoothing (Apple squircles) |
MIT — Free for commercial and personal use.
If you find a bug or have a feature request, please open an issue on GitHub. Engine internals are intentionally not part of the public API.