Audio, impact feedback and haptics

Play sounds through the engine's mixer and add haptics that respect player settings.

Load a sound bank

audio.load({ name: source }) returns a SoundBank at once; await bank.ready before relying on it, since plays before then are ignored and failed files are logged and skipped. Sounds are WAV (PCM or float, mono or stereo): URLs on the web, require(...) in React Native.

Web sound bank

React · browser

Web sound bank
import { audio } from "@nayan-ui/engine";
export const sfx = audio.load({ coin: "/sounds/coin.wav", music: "/sounds/music.wav" });
await sfx.ready;
sfx.play("coin");

React Native sound bank

React Native · iOS and Android

React Native sound bank
import { audio } from "@nayan-ui/engine";
export const sfx = audio.load({ coin: require("./coin.wav"), music: require("./music.wav") });
await sfx.ready;
sfx.play("coin");

Play, loop and stop voices

Playing returns a Voice (or null); keep it and pass it to audio.stop when leaving. A screen owns its loops and stops them on unmount.

Play, loop and stop voices reference
Audio APIBehavior
audio.load(sources)SoundBank; each asset decodes once per session.
bank.ready / bank.get(name)Load promise; the Sound (for impact.sound) or undefined.
bank.play(name, options) / audio.play(sound, options)Mixed in Rust; returns a Voice or null.
{ volume, pan, pitch, loop }0..2, -1..1, speed; defaults 1, 0, 1, false.
audio.stop(voice)Stops one voice; null and undefined are fine.
audio.enabled / audio.mutedGlobal sound switch; muted is its inverse.
audio.volumeMaster gain, 0..2.
audio.runningTrue once the device's audio output is running.

Background music with cleanup

React and React Native · shared engine API

Background music with cleanup
import { useEffect } from "react";
import { audio, type SoundBank } from "@nayan-ui/engine";
export function useMusic(bank: SoundBank<"music">) {
useEffect(() => {
const voice = bank.play("music", { volume: 0.35, loop: true });
return () => audio.stop(voice);
}, [bank]);
}

Player settings and autoplay

Mirror the player's settings onto audio.enabled and haptics.enabled; both are global switches. On the web, output starts on the first click, touch or key press and suspends in hidden tabs.

Apply feedback settings

React and React Native · shared engine API

Apply feedback settings
import { audio, haptics } from "@nayan-ui/engine";
export function applySettings(settings: { enableSounds: boolean; enableHaptics: boolean }) {
audio.enabled = settings.enableSounds;
haptics.enabled = settings.enableHaptics;
}

Collision sounds and haptics

Give an entity impact feedback and the core plays sound and haptics for solid hits with no JS per collision: minSpeed 1, maxSpeed 10, volume 1 and haptic 0 by default. world.listener pans and fades impact sounds relative to that entity.

haptics.enabled doesn't rewrite existing impact options, so update them (or pass impact: null) when settings change.

Settings-aware impacts

React and React Native · shared engine API

Settings-aware impacts
import type { Entity, Sound, World } from "@nayan-ui/engine";
export function attachImpacts(world: World, ball: Entity, bump: Sound | undefined, sounds: boolean, vibrate: boolean) {
world.listener = ball;
world.set(ball, {
impact: { sound: sounds ? bump : undefined, minSpeed: 1, maxSpeed: 8, volume: 0.6, haptic: vibrate ? 0.5 : 0 },
});
}

Haptic taps and patterns

iOS and Android use their native haptics; browsers vibrate where supported and skip it otherwise, without intensity or sharpness control.

Haptic taps and patterns reference
Haptics APIBehavior
haptics.enabledGlobal switch for the haptics API.
haptics.supportedTrue when the device has an actuator (false on simulators).
impact(intensity = 0.6, sharpness = 0.5)One tap; repeats under 35 ms apart are dropped.
selection()A light, crisp tick for UI selection.
notify('success' | 'warning' | 'error')The platform's notification pattern.
play(taps)HapticTap[]: time in seconds, intensity and sharpness 0..1.

A reward pattern

React and React Native · shared engine API

A reward pattern
import { haptics } from "@nayan-ui/engine";
export function reward() {
if (!haptics.supported) return;
haptics.notify("success");
haptics.play([
{ time: 0, intensity: 0.4, sharpness: 0.3 },
{ time: 0.12, intensity: 0.8, sharpness: 0.7 },
]);
}