Skip to content

React Native SDK

The Pulsar React Native SDK (react-native-pulsar) exposes haptic feedback through three building blocks: Presets, usePatternComposer, and useRealtimeComposer. All preset functions and hook methods are worklet-compatible for use with Reanimated.

  • React Native 0.71+
  • New Architecture enabled
Terminal window
npx expo install react-native-pulsar

Then run prebuild to generate the native project files:

Terminal window
npx expo prebuild

A collection of ready-to-use haptic patterns. All preset functions are worklet-compatible and can be called directly inside Reanimated worklets.

import { Presets } from 'react-native-pulsar';
MethodDescription
afterglow()A three-beat phrase that dissolves gently, ideal for soft endings or gradually quieting feedback.
aftershock()A firm opening that settles calmly, ideal for transitions needing a strong start and a gentle finish.
alarm()Relentless and urgent, best for critical errors or emergencies that require immediate attention.
anvil()The full weight of a massive collision, conveys sheer physical force and momentum.
applause()A growing wave of appreciation, ideal for celebratory moments or social approval.

Example

import { Presets } from 'react-native-pulsar';
Presets.hammer();

Platform-specific haptic feedback styles, common across iOS and Android.

MethodDescription
impactHeavy()UIImpactFeedbackGenerator.heavy
impactLight()UIImpactFeedbackGenerator.light
impactMedium()UIImpactFeedbackGenerator.medium
impactRigid()UIImpactFeedbackGenerator.rigid
impactSoft()UIImpactFeedbackGenerator.soft

Example

import { Presets } from 'react-native-pulsar';
import { Gesture } from 'react-native-gesture-handler';
const tap = Gesture.Tap().onEnd(() => {
Presets.System.impactMedium();
});

Additional system haptic feedback styles that are only available on Android.

MethodDescription
calendarDate()HapticFeedbackConstants.CALENDAR_DATE
clockTick()HapticFeedbackConstants.CLOCK_TICK
confirm()HapticFeedbackConstants.CONFIRM
contextClick()HapticFeedbackConstants.CONTEXT_CLICK
dragCrossing()HapticFeedbackConstants.DRAG_CROSSING

Example

import { Presets } from 'react-native-pulsar';
Presets.System.Android.primitiveLowTick();

A React hook for composing and playing a custom Pattern. The pattern is parsed on mount and whenever it changes. Resources are released automatically on unmount.

const { play, parse, isParsed } = usePatternComposer(pattern);

Type: Pattern

A haptic pattern to parse on mount. When provided, the pattern is parsed automatically and re-parsed whenever the value changes. Resources are released on unmount.

Plays the parsed pattern.

Stops the active pattern.

Parses and replaces the current pattern.

Returns true if a pattern has been parsed and is ready to play.

import { usePatternComposer } from 'react-native-pulsar';
import { Gesture } from 'react-native-gesture-handler';
const pattern = {
discretePattern: [
{ time: 0, amplitude: 1, frequency: 0.5 },
{ time: 100, amplitude: 0.5, frequency: 0.5 },
],
continuousPattern: {
amplitude: [
{ time: 0, value: 0 },
{ time: 200, value: 1 },
{ time: 400, value: 0 },
],
frequency: [
{ time: 0, value: 0.3 },
{ time: 400, value: 0.8 },
],
},
};
function MyComponent() {
const composer = usePatternComposer(pattern);
const tap = Gesture.Tap().onEnd(() => {
composer.play();
});
return <GestureDetector gesture={tap}>...</GestureDetector>;
}

A React hook for real-time haptic control. Provides live amplitude and frequency modulation, useful for gesture-driven or continuously evolving haptic experiences. Haptics stop automatically on unmount.

const { set, playDiscrete, stop, isActive } = useRealtimeComposer();

useRealtimeComposer doesn’t take any parameters.

Updates the ongoing haptic with new amplitude and frequency values.

playDiscrete(amplitude: number, frequency: number)

Section titled “playDiscrete(amplitude: number, frequency: number)”

Plays a single discrete haptic event.

Stops the active haptic.

Returns true if a haptic is currently playing.

import { useRealtimeComposer } from 'react-native-pulsar';
import { Gesture } from 'react-native-gesture-handler';
function MyComponent() {
const realtime = useRealtimeComposer();
const pan = Gesture.Pan()
.onUpdate((e) => {
const amplitude = Math.min(Math.abs(e.velocityY) / 1000, 1);
realtime.set(amplitude, 0.5);
})
.onEnd(() => {
realtime.stop();
});
return <GestureDetector gesture={pan}>...</GestureDetector>;
}

A React hook that plays haptics from a cross-platform AdaptivePreset. It automatically selects the correct configuration for the current platform (iOS or Android). Each platform can provide either a custom Pattern or a native preset function.

const { play } = useAdaptiveHaptics(preset: AdaptivePreset);

An object with ios and android keys. Each value is either a Pattern object or a function that triggers a native preset directly.

type AdaptivePresetConfig = (() => void) | Pattern;
type AdaptivePreset = {
ios: AdaptivePresetConfig;
android: AdaptivePresetConfig;
};

Plays the haptic for the current platform. If the platform config is a function, it is called directly. If it is a Pattern, it is played via the pattern composer.

import { useAdaptiveHaptics, Presets } from 'react-native-pulsar';
const adaptivePreset = {
ios: Presets.Success, // native iOS preset function
android: { // custom pattern for Android
discretePattern: [
{ time: 0, amplitude: 1, frequency: 0.5 },
{ time: 150, amplitude: 0.6, frequency: 0.4 },
],
continuousPattern: {
amplitude: [],
frequency: [],
},
},
};
function MyComponent() {
const haptics = useAdaptiveHaptics(adaptivePreset);
return (
<Button onPress={haptics.play} title="Tap me" />
);
}

Global configuration for the Pulsar SDK. All methods are available on the Settings object.

import { Settings } from 'react-native-pulsar';
MethodDescription
Settings.enableHaptics(state: boolean)Enable or disable all haptic feedback
Settings.enableSound(state: boolean)Enable or disable audio simulation
Settings.enableCache(state: boolean)Enable or disable preset caching
Settings.clearCache()Clear the preset cache
Settings.preloadPresets(presetNames: string[])Preload presets by name for faster playback
Settings.stopHaptics()Stop all currently playing haptics
Settings.shutDownEngine()Shut down the haptic engine
Settings.getHapticsSupportLevel()Returns the device’s HapticSupport level
Settings.forceHapticsSupportLevel(level)(Android only) Override the detected support level
Settings.enableImpulseCompositionMode(state: boolean)(Android only) Enable or disable impulse composition mode
Settings.setRealtimeComposerStrategy(strategy)(Android only) Set the strategy used by the realtime composer
import { Settings } from 'react-native-pulsar';
// Preload frequently used presets
Settings.preloadPresets(['Fanfare', 'Explosion', 'Heartbeat']);
// Disable haptics temporarily
Settings.enableHaptics(false);
// Check device support
const support = Settings.getHapticsSupportLevel();

The haptic capability level of the current device, returned by Settings.getHapticsSupportLevel().

import { HapticSupport } from 'react-native-pulsar';
enum HapticSupport {
NO_SUPPORT = 0,
MINIMAL_SUPPORT = 1,
LIMITED_SUPPORT = 2,
STANDARD_SUPPORT = 3,
ADVANCED_SUPPORT = 4,
}
import { Settings, HapticSupport, Presets } from 'react-native-pulsar';
const support = Settings.getHapticsSupportLevel();
if (support >= HapticSupport.STANDARD_SUPPORT) {
Presets.dogBark();
}

Describes a complete haptic pattern with discrete pulses and continuous envelope curves.

type Pattern = {
discretePattern: Array<{
time: number; // Milliseconds from pattern start
amplitude: number; // Intensity (0-1)
frequency: number; // Sharpness (0-1)
}>;
continuousPattern: {
amplitude: Array<{
time: number; // Milliseconds from pattern start
value: number; // Amplitude value (0-1)
}>;
frequency: Array<{
time: number; // Milliseconds from pattern start
value: number; // Frequency value (0-1)
}>;
};
};

Use discretePattern for distinct taps and impacts. Use continuousPattern envelopes to shape a sustained haptic over time.

enum HapticSupport {
NO_SUPPORT = 0,
MINIMAL_SUPPORT = 1,
LIMITED_SUPPORT = 2,
STANDARD_SUPPORT = 3,
ADVANCED_SUPPORT = 4,
}

Android-only. Controls how useRealtimeComposer simulates continuous haptics, since Android has no native continuous haptic API. Pass one of these values to Settings.setRealtimeComposerStrategy().

import { RealtimeComposerStrategy } from 'react-native-pulsar';
enum RealtimeComposerStrategy {
ENVELOPE = 0,
PRIMITIVE_TICK = 1,
PRIMITIVE_COMPLEX = 2,
ENVELOPE_WITH_DISCRETE_PRIMITIVES = 3,
}
ValueDescription
ENVELOPEApproximation based on the Envelope API. Allows control over amplitude and frequency, but the signal oscillates and can be unstable. Available on Android API 36+.
PRIMITIVE_TICKApproximation using the Composition API TICK primitive at varying intervals. Amplitude is controllable; frequency is simulated by the timing between ticks. Signal is discrete rather than continuous.
PRIMITIVE_COMPLEXSimilar to PRIMITIVE_TICK, but uses multiple primitives depending on the requested frequency.
ENVELOPE_WITH_DISCRETE_PRIMITIVESDefault. Hybrid strategy. Uses the Envelope API for continuous events (API 36+) and composition primitives for discrete events (API 33+). Best of both worlds when both event types are used.

Example

import { Settings, RealtimeComposerStrategy } from 'react-native-pulsar';
Settings.setRealtimeComposerStrategy(RealtimeComposerStrategy.PRIMITIVE_COMPLEX);