Play sounds through the engine's mixer and add haptics that respect player settings.
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
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
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");
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.
| Audio API | Behavior |
|---|---|
| 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.muted | Global sound switch; muted is its inverse. |
| audio.volume | Master gain, 0..2. |
| audio.running | True once the device's audio output is running. |
Background music with cleanup
React and React Native · shared engine API
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]);}
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
import { audio, haptics } from "@nayan-ui/engine";export function applySettings(settings: { enableSounds: boolean; enableHaptics: boolean }) {audio.enabled = settings.enableSounds;haptics.enabled = settings.enableHaptics;}
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
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 },});}
iOS and Android use their native haptics; browsers vibrate where supported and skip it otherwise, without intensity or sharpness control.
| Haptics API | Behavior |
|---|---|
| haptics.enabled | Global switch for the haptics API. |
| haptics.supported | True 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
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 },]);}