Documentation

Everything you need to use bzzz.

Installation

Install the package from your command line.

Terminal
npm install bzzz

Basic usage

Import the haptics singleton and call a named pattern. Always trigger from a user interaction — browsers may reject playback outside click, tap, or keyboard handlers.

Patterns

Five built-in patterns for common interaction feedback. Each returns a PlaybackResult with the output mode.

Rising 3-pulse. Use after save, submit, or successful completion.

haptics.success()
// → { mode: "haptics" | "audio" | "none" }

play()

Play a raw PatternBlock[] array when you need direct control. Each block is a pulse (vibration) or gap (pause). Intensity ranges from 0 to 1 (default: 1.0) — lower values produce softer feedback.

Capabilities & fallbacks

The runtime uses native haptics when available and falls back to audio. Every call returns a PlaybackResult reporting what actually happened.

When the user has prefers-reduced-motion: reduce enabled, all feedback is automatically suppressed and methods return { mode: "none" }. Browsers may also reject playback outside user-triggered interactions — that is why mode reporting matters.

Configuration

Globally enable or disable haptic feedback. When disabled, all methods return { mode: "none" }.

haptics.setEnabled(false); // mute all feedback
haptics.isEnabled();       // → false

haptics.setEnabled(true);  // resume
haptics.success();         // → { mode: "haptics" }

Output mode

Control which output channels are used. The default "auto" mode uses haptics when available and falls back to audio — never both at once.

haptics.setOutput("audio");   // audio only, never vibrate
haptics.setOutput("haptics"); // vibration only, never play audio
haptics.setOutput("both");    // always fire both when available
haptics.setOutput("auto");    // default: haptics if available, else audio

haptics.getOutput(); // → "audio"

Pass output to createHaptics() to set the mode per-instance from creation.

Call dispose() to clean up the AudioContext and any internal DOM elements. Safe to call multiple times.

haptics.dispose();

createHaptics()

Create isolated instances with custom pattern registries. Each instance has its own enabled state and does not affect the global singleton.

Add patterns after creation with register(). Call dispose() when the instance is no longer needed.

appHaptics.register("delete", [
  { type: "pulse", duration: 40 },
  { type: "gap", duration: 18 },
  { type: "pulse", duration: 44 }
]);

appHaptics.play("delete");
appHaptics.dispose();

React

Hooks for React 18+. Available from bzzz/react — no extra packages or providers needed.

useHaptics

Wraps the global singleton with stable callbacks safe for dependency arrays. Does not cause re-renders.

import { useHaptics } from "bzzz/react";

function SaveButton() {
  const { success, error } = useHaptics();

  async function handleSave() {
    try {
      await save();
      success();
    } catch {
      error();
    }
  }

  return <button onClick={handleSave}>Save</button>;
}

useCreateHaptics

Creates an isolated instance scoped to the component. Automatically disposes on unmount.

import { useCreateHaptics } from "bzzz/react";

function GameController() {
  const haptics = useCreateHaptics({
    patterns: {
      hit: [
        { type: "pulse", duration: 30, intensity: 1.0 },
        { type: "gap", duration: 20 },
        { type: "pulse", duration: 50, intensity: 0.8 },
      ],
    },
  });

  return <button onClick={() => haptics.play("hit")}>Attack</button>;
}

Enable / Disable

Both hooks expose isEnabled() and setEnabled() for building settings UIs.

const { isEnabled, setEnabled } = useHaptics();

setEnabled(false); // mute
setEnabled(true);  // resume
isEnabled();       // → boolean

Browser support

bzzz adapts to each platform automatically. Native vibration is preferred, with audio click fallback when unavailable.

PlatformHapticsAudioHow
Android Chrome / Edge / OperaYesYesVibration API
Android Samsung InternetYesYesVibration API
Android FirefoxNoYesAudio only (Vibration API removed v129)
iOS 18+ (all browsers)YesYesTaptic Engine (switch hack)
iOS < 18 (all browsers)NoYesAudio only
Desktop browsersNoYesAudio only
SSR / Node.jsNoNoSilent (none)

iOS Taptic Engine (input switch hack)

iOS doesn't support the Vibration API. Instead, bzzz uses a hidden <input type="checkbox" switch> element. Toggling it triggers the Taptic Engine at the WebKit level — works in all iOS browsers.

Browsernavigator.vibrateSwitch hackbzzz mode
Android ChromeYesNohaptics
Android FirefoxNo (removed v129)Noaudio
iOS SafariNoYes (iOS 18+)haptics
iOS ChromeNoYes (iOS 18+)haptics
iOS FirefoxNoYes (iOS 18+)haptics

On desktop, demos return { mode: "audio" } or { mode: "none" }. For the full haptic experience, try on a mobile device.

API Reference

haptics

Global singleton. Import from bzzz.

MethodReturnsDescription
selection()PlaybackResultLight 2-pulse tap
success()PlaybackResultRising 3-pulse
error()PlaybackResultUrgent 4-pulse buzz
toggle()PlaybackResultSymmetric 3-pulse
snap()PlaybackResultEscalating 5-pulse ramp
play(pattern)PlaybackResultPlay a PatternBlock[]
getCapabilities()CapabilityStateCheck device support
setEnabled(bool)voidEnable or disable globally
isEnabled()booleanCheck enabled state
setOutput(mode)voidSet output channel routing
getOutput()OutputModeCurrent output mode
dispose()voidClean up AudioContext and DOM

createHaptics(options?)

Factory for isolated instances. Import from bzzz.

OptionTypeDefault
patternsRecord<string, PatternBlock[]>{}
outputOutputMode"auto"

Returns a HapticsInstance with play(name | pattern), register(name, pattern), getCapabilities(), setEnabled(), isEnabled(), and dispose().

OutputMode

ValueDescription
"auto"Haptics if available, audio fallback — never both (default)
"haptics"Vibration / Taptic Engine only — never plays audio
"audio"Audio clicks only — never vibrates
"both"Fire both channels simultaneously when available

PlaybackResult

PropTypeDescription
mode"haptics" | "audio" | "none"Primary output channel used
hapticsbooleanWhether vibration / Taptic Engine fired
audiobooleanWhether audio click fired

CapabilityState

PropTypeDescription
hapticsbooleanVibration API available
audiobooleanWeb Audio API available
iosbooleaniOS / iPadOS device
reducedMotionbooleanprefers-reduced-motion active

PatternBlock

TypeFieldsDescription
pulseduration: number, intensity?: numberVibration. Intensity 0–1 (default: 1.0)
gapduration: numberPause between pulses

Pattern Editor

Draw a pattern or start from a preset. Fine-tune the blocks, preview and copy the code.