Sound effects
Interactive components play short UI sounds (hover, click, drag, boot, ...) through a React context. Without a provider they stay silent, so audio is strictly opt-in.
Enable sound
JarvisProvider turns sound on for the whole app. Sound is on by
default; sfx={false} starts muted, and useJarvis() returns { isMuted, toggleMute } for a mute
switch. The user's choice is stored in localStorage, so it survives reloads. Try the SFX switch
in the header of this site.
import { JarvisProvider } from 'jarvis-react-ui';
<JarvisProvider sfx={false}>
<App />
</JarvisProvider>;
Manual setup
Without JarvisProvider, mount the audio engine yourself and pass it to SfxProvider:
import type { ReactNode } from 'react';
import { SfxProvider, useAudioEngine } from 'jarvis-react-ui';
export function SoundRoot({ children }: { children: ReactNode }) {
const { playOneShot, play, stop } = useAudioEngine('idle', true, false, {
initialMuted: false,
});
return (
<SfxProvider playOneShot={playOneShot} play={play} stop={stop}>
{children}
</SfxProvider>
);
}
Browsers only start audio after a user gesture. The first sounds play after the first click or key press on the page.
Serve the sound files
The sound files ship inside the package under public/sounds. The engine loads them from a base URL
that defaults to /sounds/ on your site.
Option 1: copy them into your static folder (no configuration):
cp -r node_modules/jarvis-react-ui/public/sounds public/sounds
Option 2: point soundBaseUrl at your own path or a CDN (pin the version in the URL):
const { playOneShot, play, stop } = useAudioEngine('idle', true, false, {
soundBaseUrl: 'https://cdn.jsdelivr.net/npm/jarvis-react-ui@0.1.0/public/sounds/',
});
The value may be relative or absolute; a trailing slash is added if missing. Query strings and hashes are rejected. The engine is a process-wide singleton, so the last applied URL wins. A CDN must send CORS headers (unpkg and jsDelivr do). Missing files are logged and skipped; nothing throws.
Sounds in your own components
| Hook | Use |
|---|---|
useClickSfx(onClick) |
Wraps a click handler: plays click, then calls yours. |
useHoverSfx('button') |
Returns an onMouseEnter handler that plays a throttled hover sound ('panel' for surfaces). |
useSfx() |
{ playOneShot, play, stop } for any other sound event. |
import { useClickSfx, useHoverSfx } from 'jarvis-react-ui';
export function ScanButton({ onScan }: { onScan: () => void }) {
const onMouseEnter = useHoverSfx('button');
const onClick = useClickSfx(onScan);
return (
<button type="button" onMouseEnter={onMouseEnter} onClick={onClick} data-sfx-hover="button">
Scan
</button>
);
}
Mark buttons with data-sfx-hover="button" so the hover sound of a surrounding panel does not play
on top of the button's own.