Sound
A game answers every press. Twelve short sounds — one for each kind of moment — that every component already makes, quietly, through one provider the app mounts at its root.
The twelve
navigate
The cursor lands on something: a row by key or by mouse, a button under the pointer, a dropdown item.
MenuListButtonTileSelectDropdownMenu
adjust
A value steps. A drag ticks at most every 70ms.
OptionStepperMenuSliderColorGridMenuChoice
tab
A section switches, by Q / E, a click or the arrows.
MenuTabsTabs
select
A press or a confirm. A purchase is still only this — the outcome comes later.
ButtonMenuItemTileCheckoutBarSelectDropdownMenu
back
A step back out of a sub-menu: BACKSPACE or the back row.
MenuList
toggle-on
Something switched on.
SwitchCheckboxMenuToggleDropdownMenuCheckboxItem
toggle-off
Something switched off.
SwitchCheckboxMenuToggle
open
An overlay or a menu arrives.
MenuScreenDialogSheetSelectDropdownMenuFaqAccordion
close
It leaves — unless a press just closed it, which already made its sound.
MenuScreenDialogSheetSelectDropdownMenuFaqAccordion
success
The server said yes: bought, saved, sent. The app plays it, or a success toast does.
Toasterthe app
error
The server said no, or a stepper hit its end.
ToasterOptionStepperthe app
notify
Something arrived unasked: any other toast.
Toaster
Rules
- 1One action, one sound. The provider drops a sound that lands within 140ms of a weightier one: the
selectof a dropdown item swallows thecloseafter it, theopenof a dialog swallows thenavigateof its first item. Never play two on purpose. - 2Only actions sound. Nothing plays on its own: no ambience, no loop, no sound on page load, no sound for an animation. A toast is the one exception — it arrives unasked, so it announces itself.
- 3No typing sounds, no scroll sounds, no hover sounds on text or on a swatch grid. The pointer ticks only on things that act.
- 4A press is
select, whatever it buys.successanderrorare the server’s answer: play them, or toast them, when the answer comes back — never optimistically on the click. - 5Use the components and they sound by themselves. A hand-made control takes
data-sfx="select"anddata-sfx-hover="navigate", or callsuseUiSound()— never an<audio>of its own. - 6Frequent sounds sit lowest.
navigateis the quietest of the twelve andsuccessthe loudest; a cursor walking a list must never be louder than a purchase. The default volume is 0.35: felt more than heard, under the game’s own audio. - 7Players can turn it off. The game ties the player’s volume to its settings; a site that should not tick mutes
navigate(volumes: { navigate: 0 }).
Setting it up
import { createUiSoundPlayer, UiSoundsProvider } from '@/components/ds/ui-sounds';
const player = createUiSoundPlayer({ volume: 0.35 });
export function Root({ children }) {
return <UiSoundsProvider onSound={player.play}>{children}</UiSoundsProvider>;
}In the game
Pass the webview’s shared context —createUiSoundPlayer({ context: getSharedAudioContext }) — so the sounds go through the one AudioContext the NUI already owns, and set the volume from the player’s settings. The sounds play inside the NUI, so they are the same in the hub and in the city.Credits
- David McKee (ViRiX) — UI Sound Pack 1, CC-BY 3.0 · “Some of the sounds in this project were created by David McKee (ViRiX) soundcloud.com/virix”
- Paolo Migliorisi (Urizen) — UI Sci-Fi SFXs Confirm Pack Vol 1, OGA-BY 4.0
- Lokif — GUI Sound Effects, CC0
- bosslevelaudio — Wierd Whooshes, CC0