cuelume-native
v0.1.0
Published
Curated interaction sounds for React Native & Expo — synthesized live with react-native-audio-api, zero audio files, zero bundled runtime dependencies.
Maintainers
Readme
Cuelume Native
Seventeen carefully designed interaction sounds for React Native & Expo. Synthesized live with react-native-audio-api — no audio files, no bundled runtime dependencies.
Cuelume Native is a curated sound palette, not an audio engine. It gives buttons, toggles, and completed actions clear feedback without asking you to design sounds yourself. Call play(), or wire a Pressable with useCuelumeSound() — done.
This is a native-only fork of
cuelumeby Daniel Belyi — same sound recipes and synthesis logic, ported from the browser's Web Audio API toreact-native-audio-api. Building for the web? Use the originalcuelumepackage instead.
Contents
- Install
- Requirements
- Quick start
- Sounds
- API
- Defaults that behave
- Example app
- Contributing & releasing
- License
Install
npx expo install cuelume-native react-native-audio-api react-native-workletsreact-native-audio-api has native code, so this does not work in Expo Go — you need a development build (npx expo run:ios / npx expo run:android, or an EAS dev build).
Requirements
- React Native 0.74+, React 18+.
react-native-audio-apiandreact-native-workletsas peer dependencies (installed above).- ESM-only — used through native
importor an ESM-compatible bundler (Metro handles this automatically).
Quick start
Play a sound imperatively, from anywhere:
import { play } from "cuelume-native";
await Clipboard.setStringAsync(text);
play("success");
play("success", { volume: 0.4 }); // quieter for this play onlyWire a Pressable with press/release/toggle sounds — the native equivalent of the web package's bind():
import { Pressable, Text } from "react-native";
import { useCuelumeSound } from "cuelume-native";
function SaveButton() {
const sound = useCuelumeSound({ toggle: "success" });
return (
<Pressable {...sound}>
<Text>Save</Text>
</Pressable>
);
}useCuelumeSound defaults to press/release/toggle — matching the web package's data-cuelume-press/-release/-toggle defaults. Pass false for any of them to skip that sound, or a specific SoundName to override it. There's no native equivalent of data-cuelume-hover — touch devices have no hover state.
Need sound preferences? Your app owns the settings; Cuelume Native only applies them:
import { setEnabled, setVolume } from "cuelume-native";
setVolume(0.7); // global multiplier, clamped to 0–1
setEnabled(false); // future play attempts become no-ops
setEnabled(true); // enable playback againCuelume Native starts enabled at full volume and does not read or write storage.
Sounds
| Name | Character | Suggested use |
| --------- | ------------------------------------ | -------------------------------------------------- |
| chime | Soft two-note ascending bell | Confirmations |
| sparkle | Quick four-note twinkle | Playful accents |
| droplet | Single note gliding down | Dismiss, collapse |
| bloom | Warm slow swell | Reveal, expand |
| whisper | Soft hush with a falling tone | Tooltips and quiet previews |
| tick | Crisp instant tick | Nav and menu selection |
| press | Dull muted knock | Press in |
| release | Brighter springy tick | Press out |
| toggle | Mechanical click-clack | Switches, tabs |
| success | Warm three-note confirmation | After an action succeeds (e.g. copy to clipboard) |
| error | Soft knock and descending refusal | Recoverable errors |
| page | Papery flick with a glass tick | Pages, galleries, carousels |
| loading | Brief unresolved rising shimmer | User-initiated work starting |
| ready | Rising lock-on with a clear resolve | Content or system ready |
| pulse | Compact synthetic chirp | Primary buttons and controls |
| scan | Fast three-step locator signal | Menus and secondary buttons |
| arrival | Rising harmonic portal | Screen/route arrivals |
API
import { play, useCuelumeSound, setEnabled, setVolume, sounds, type SoundName } from "cuelume-native";| Export | Signature | Description |
| --- | --- | --- |
| play | (name?: SoundName, options?: { volume?: number }) => void | Play a sound immediately. Defaults to "chime"; options.volume controls this play only. |
| useCuelumeSound | (options?: { press?, release?, toggle? }) => { onPressIn, onPressOut, onPress } | Returns handlers to spread onto a Pressable. Each option is a SoundName (defaults: press/release/toggle) or false to disable that sound. |
| setEnabled | (enabled: boolean) => void | Enable or disable future playback. Doesn't persist the preference or stop sounds already playing. |
| setVolume | (volume: number) => void | Set the global volume for future playback, clamped to 0–1. Non-finite values are ignored. |
| sounds | readonly SoundName[] | The list of all sound names. |
| SoundName | type | Union type of the seventeen sound names. |
Defaults that behave
- Audible without harsh clipping. One shared boosted output stage keeps sounds clear, softened by a limiter curve on overlapping cues. (
react-native-audio-apihas noDynamicsCompressorNodeyet, so this is a static soft-clip curve rather than true time-based compression — plenty for these short, percussive cues.) - One lazy
AudioContext. Shared across all sounds, created on first use. - iOS audio session configured for you. Sounds play under the
ambientsession category — they respect the silent switch and never interrupt music or other audio, like standard iOS UI sounds. - Safe fallback. Invalid sound names, a disabled state, or an unavailable native audio module all make
play()a silent no-op.
Example app
example/ is a real Expo dev-client app exercising every sound plus the hook — see example/README.md for how to run it.
Contributing & releasing
Issues and PRs are welcome. Maintainers: see RELEASING.md for the release process.
License
MIT. Portions © 2026 Daniel Belyi (original cuelume); see LICENSE.
