Skip to content

Rhythm Sync

RhythmSync synchronizes haptic feedback to a musical BPM. It provides beat detection via tap tempo, BPM control, and automatic haptic triggering on each beat.

Basic Usage

typescript
import { RhythmSync, HapticEngine } from '@hapticjs/core';

const rhythm = new RhythmSync({ bpm: 120, intensity: 0.7 });
const engine = HapticEngine.create();

// Auto-trigger haptic on each beat
rhythm.syncHaptic(engine, 'tap');

// Start the rhythm
rhythm.start();

// Stop when done
rhythm.stop();

Options

typescript
interface RhythmSyncOptions {
  bpm?: number;         // Beats per minute, 60-300 (default: 120)
  intensity?: number;   // Global intensity multiplier, 0-1 (default: 0.7)
  pattern?: string;     // HPL pattern string for each beat
}

BPM Control

typescript
const rhythm = new RhythmSync({ bpm: 120 });

// Change BPM at any time (clamped to 60-300)
rhythm.setBPM(140);

// Read current BPM
rhythm.bpm; // 140

Tap Tempo

Detect BPM from user taps. Call tapTempo() repeatedly and it calculates the average BPM from the last 4-8 tap intervals.

typescript
const rhythm = new RhythmSync();

// User taps a button in time with music
document.getElementById('tap-btn')?.addEventListener('click', () => {
  const estimatedBPM = rhythm.tapTempo();
  console.log(`BPM: ${estimatedBPM}`);
});

Beat Callbacks

Register callbacks to execute on each beat:

typescript
// Via start()
rhythm.start((beat) => {
  console.log(`Beat ${beat}`);
});

// Via onBeat()
rhythm.onBeat((beat) => {
  // Update UI on each beat
  updateVisualizer(beat);
});

Syncing Haptics

Automatically trigger a haptic effect on each beat:

typescript
// Default: calls engine.tap() on each beat
rhythm.syncHaptic(engine);

// Use a different semantic effect
rhythm.syncHaptic(engine, 'impact');
rhythm.syncHaptic(engine, 'selection');

The syncHaptic method calls the specified method on the engine with the configured intensity on each beat tick.

Properties

PropertyTypeDescription
bpmnumberCurrent BPM
isPlayingbooleanWhether the rhythm is active
beatCountnumberTotal beats since start
patternstringConfigured HPL pattern

Audio BPM Detection

Store an audio element reference for future sync capabilities:

typescript
const audioEl = document.getElementById('music') as HTMLAudioElement;
rhythm.detectBPM(audioEl);

INFO

For reliable BPM detection, use tapTempo() to manually tap along with the audio. The detectBPM() method stores the audio element reference for future use.

Cleanup

typescript
rhythm.dispose(); // Stops rhythm, clears callbacks and timestamps

Example: Music Visualizer with Haptics

typescript
import { RhythmSync, HapticEngine, SensoryEngine } from '@hapticjs/core';

const engine = SensoryEngine.create({ theme: 'gaming' });
const rhythm = new RhythmSync({ bpm: 128, intensity: 0.8 });

rhythm.syncHaptic(engine.haptic, 'tap');

rhythm.onBeat((beat) => {
  // Flash on every 4th beat (downbeat)
  if (beat % 4 === 1) {
    engine.visual.flash({ color: '#a855f7' });
    engine.sound.click({ pitch: 'low' });
  }
});

rhythm.start();

Released under the MIT License.