Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/src/content/docs/sdk/android.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,16 @@ Parses a `PatternData` object and prepares it for playback.
fun parsePattern(hapticsData: PatternData)
```

#### `parsePatternWithSound(hapticsData, sound)`

Parses a pattern together with a short sound played in sync with the haptics.

```kotlin
fun parsePatternWithSound(hapticsData: PatternData, sound: SoundData)
```

On devices that support audio-coupled haptics, provide an **`.ogg`** whose baked haptic channels drive the vibrator for perfect, single-stream sync. Any other file — `.wav`/`.mp3`, or a bare name (which defaults to `.wav`) — plays the audio while the pattern's own generated `VibrationEffect` fires in parallel. See [`SoundData`](#sounddata) for `uri`, `volume`, `offset`, and `hapticChannels`.

#### `play()`

Plays the previously parsed pattern.
Expand Down Expand Up @@ -768,6 +778,21 @@ data class PatternData(
)
```

### SoundData

A short sound to play in sync with a haptic pattern via [`parsePatternWithSound`](#parsepatternwithsoundhapticsdata-sound).

```kotlin
data class SoundData(
val uri: String, // File path, file:// uri, or res/raw resource name
val volume: Float = 1f, // Playback volume (0-1)
val offset: Long = 0L, // Audio delay relative to haptics, in ms (fallback path)
val hapticChannels: Boolean = true
)
```

The format comes from `uri`'s extension; when none is given the default is `.wav`, so a bare name like `"beep"` loads `res/raw/beep.wav`. Only an explicit `.ogg` with baked haptic channels uses the audio-coupled path (on supported devices); everything else plays the audio while the pattern's own haptics fire in parallel. Set `hapticChannels = false` to force that fallback for an `.ogg` that does not carry haptic channels.

### ContinuousPattern

Represents continuous haptic curves for amplitude and frequency.
Expand Down
26 changes: 26 additions & 0 deletions docs/src/content/docs/sdk/flutter.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,16 @@ Parses a `PatternData` object and prepares it for playback.
Future<void> parsePattern(PatternData data);
```

#### `parsePatternWithSound(pattern, sound)`

Parses a pattern together with a short sound played in sync with the haptics.

```dart
Future<void> parsePatternWithSound(PatternData data, Sound sound);
```

Provide the sound via a [`Sound`](#sound). On Android an explicit `.ogg` with baked haptic channels enables audio-coupled sync on supported devices; any other format — or a bare name, which defaults to `.wav` — plays the audio while the pattern's own haptics fire in parallel. On iOS the sound is registered as a Core Haptics audio event on the pattern's timeline. A Flutter asset is not a native file path — bundle the file natively (iOS app bundle / Android `res/raw`) and pass its name, or copy it from `rootBundle` to a temp file and pass that absolute path.

#### `playPattern(pattern)`

Convenience method that parses and immediately plays a pattern.
Expand Down Expand Up @@ -732,6 +742,22 @@ class PatternData {

The `PatternData.fromArrays` factory accepts the raw triplet form (`List<List<double>>`) for parity with serialized pattern definitions.

### Sound

A short sound to play in sync with a haptic pattern via [`parsePatternWithSound`](#parsepatternwithsoundpattern-sound).

```dart
class Sound {
const Sound({required this.uri, this.volume = 1.0, this.offset = 0});

final String uri; // File path, file:// uri, or bundled resource name
final double volume; // Playback volume (0-1)
final int offset; // Audio delay relative to haptics, in ms
}
```

The format comes from `uri`'s extension; when none is given the default is `.wav`, so a bare name like `'beep'` resolves `beep.wav` on both platforms (iOS app bundle / Android `res/raw`).

### ContinuousPattern

Represents continuous haptic curves for amplitude and frequency.
Expand Down
10 changes: 10 additions & 0 deletions docs/src/content/docs/sdk/ios.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,16 @@ Parses a `PatternData` object and prepares it for playback.
func parsePattern(hapticsData: PatternData)
```

#### `parsePatternWithSound(hapticsData:uri:volume:offset:)`

Parses a pattern together with a short sound played in sync with the haptics. The sound is registered as a Core Haptics audio event on the **same timeline** as the pattern, so audio and haptics stay sample-accurate. `volume` (0–1) and `offset` (milliseconds, shifting the audio relative to the haptics) are optional.

```swift
func parsePatternWithSound(hapticsData: PatternData, uri: String, volume: Float = 1, offset: Double = 0)
```

`uri` must resolve to a **local** file — an absolute path, a `file://` URL, or the name of a resource bundled in the app. When no extension is given it defaults to `.wav`, so a bare name like `"beep"` resolves `beep.wav` from the app bundle (add the file to your target's **Copy Bundle Resources**). Requires a real device — Core Haptics is unavailable on the simulator — and a missing or unregisterable file degrades gracefully to haptics-only.

#### `playPattern(hapticsData:)`

Parses and immediately plays a pattern. Equivalent to calling `parsePattern` followed by `play`.
Expand Down
24 changes: 24 additions & 0 deletions docs/src/content/docs/sdk/kmp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,16 @@ Parses a `PatternData` object and prepares it for playback.
fun parsePattern(pattern: PatternData)
```

#### `parsePatternWithSound(pattern, sound)`

Parses a pattern together with a short sound played in sync with the haptics.

```kotlin
fun parsePatternWithSound(pattern: PatternData, sound: SoundData)
```

On Android, an explicit `.ogg` with baked haptic channels enables audio-coupled sync on supported devices; any other file — or a bare name, which defaults to `.wav` — plays the audio while the pattern's own haptics fire in parallel. On iOS the sound is registered as a Core Haptics audio event on the pattern's timeline. See [`SoundData`](#sounddata).

#### `playPattern(pattern)`

Convenience method that parses and immediately plays a pattern.
Expand Down Expand Up @@ -673,6 +683,20 @@ data class PatternData(

A secondary constructor accepts the raw triplet form (`List<List<List<Float>>>` for continuous, `List<List<Float>>` for discrete) for parity with serialized pattern definitions.

### SoundData

A short sound to play in sync with a haptic pattern via [`parsePatternWithSound`](#parsepatternwithsoundpattern-sound).

```kotlin
data class SoundData(
val uri: String, // File path, file:// uri, or bundled resource name
val volume: Float = 1f, // Playback volume (0-1)
val offset: Long = 0L // Audio delay relative to haptics, in ms
)
```

The format comes from `uri`'s extension; when none is given the default is `.wav`, so a bare name like `"beep"` resolves `beep.wav` on both platforms (iOS app bundle / Android `res/raw`).

### ContinuousPattern

Represents continuous haptic curves for amplitude and frequency.
Expand Down
34 changes: 33 additions & 1 deletion docs/src/content/docs/sdk/react-native.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,23 @@ function MyComponent() {
}
```

### Synchronized sound

Add a `sound` field to the pattern to play a short audio file in sync with the haptics. On iOS the file is registered as a Core Haptics audio event on the pattern's timeline (sample-accurate); on Android an explicit `.ogg` with baked haptic channels drives the vibrator directly on supported devices, and any other file falls back to playing the audio while the pattern's haptics fire in parallel.

```tsx
const pattern = {
discretePattern: [{ time: 0, amplitude: 1, frequency: 0.5 }],
continuousPattern: { amplitude: [], frequency: [] },
sound: { uri: require('./beep.wav') },
};

const composer = usePatternComposer(pattern);
composer.play();
```

`sound.uri` accepts a `require('./beep.wav')` (resolved automatically via `Image.resolveAssetSource`) or a string — a bundled resource name, an absolute path, or a `file://` uri. When no extension is given it defaults to `.wav`, so a bare `'beep'` resolves `beep.wav` on both platforms. Because a `require()` resolves to a **remote** Metro URL in dev but a local file in release, test `require()` sounds on a release build or device. See the [`Sound`](#sound) type for `volume` and `offset`.

---

## useRealtimeComposer
Expand Down Expand Up @@ -627,10 +644,25 @@ type Pattern = {
value: number; // Frequency value (0-1)
}>;
};
sound?: Sound; // Optional audio played in sync with the haptics
};
```

Use `discretePattern` for distinct taps and impacts. Use `continuousPattern` envelopes to shape a sustained haptic over time. Add an optional `sound` to play an audio file in sync — see [Synchronized sound](#synchronized-sound).

### Sound

A short sound played in sync with a haptic pattern.

```ts
type Sound = {
uri: number | string; // require('./beep.wav') or a resource name / path / file:// uri
volume?: number; // Playback volume (0-1), defaults to 1
offset?: number; // Audio delay relative to haptics, in ms, defaults to 0
};
```

Use `discretePattern` for distinct taps and impacts. Use `continuousPattern` envelopes to shape a sustained haptic over time.
When `uri` has no extension it defaults to `.wav`, so a bare `'beep'` resolves `beep.wav` (iOS app bundle / Android `res/raw`). On Android, an explicit `.ogg` with baked haptic channels enables audio-coupled sync; every other format uses the audio + generated-haptics fallback.

### HapticSupport

Expand Down