bzzz!
Professional-grade haptic feedback for Flutter. Full control over vibration patterns on iOS (CoreHaptics) and Android (VibrationEffect), or just use the built-in presets and move on.
Quick Start
dependencies:
bzzz: ^0.1.0
import 'package:bzzz/bzzz.dart';
// Play a preset
await Bzzz.instance.play(HapticCollection.success);
// Stop playback (useful for long patterns)
await Bzzz.instance.cancel();
play plays the haptic and swallows errors silently — your app won't crash on devices without a vibration motor. If you want to handle errors explicitly, use playOrThrow.
HapticCollection has 22 built-in presets for common cases: clicks, success/error feedback, heartbeat, rumble, sparkle, and more. See full list below.
Platform Support
| Platform | Min version | Engine |
|---|---|---|
| iOS | 13+ | CoreHaptics |
| Android | API 26+ | VibrationEffect |
The plugin declares android.permission.VIBRATE in its manifest automatically.
Android: How Vibration Works Under the Hood
Android has fragmented haptics support. The library handles this by providing a tiered fallback system. You supply up to three configs in a single AndroidHapticConfig, and the library picks the best one the device can run:
| Priority | API | What it does |
|---|---|---|
| 1 | EnvelopeConfig (API 36+) |
VibrationEffect.BasicEnvelopeBuilder — full control over intensity + sharpness curves over time. Closest to CoreHaptics on iOS. |
| 2 | CompositionConfig (API 30+) |
VibrationEffect.startComposition() — chains hardware primitives (click, thud, spin, quickRise, slowRise, quickFall, tick, lowTick) with scale and delay between them. |
| 3 | WaveformConfig (API 26+) |
VibrationEffect.createWaveform() — timed on/off pattern with optional amplitude control (0–255). If the device has no amplitude control, it falls back to binary on/off. |
All values you pass are normalized ([0.0, 1.0] for intensities, seconds for durations). The native layer converts them to platform units (milliseconds, 0–255 amplitudes, etc.).
If none of the provided configs match the device capabilities, playback silently does nothing.
Using Presets
HapticCollection has 22 ready-to-use patterns:
// Basic UI feedback
HapticCollection.click
HapticCollection.lightClick
HapticCollection.heavyClick
HapticCollection.selection
HapticCollection.success
HapticCollection.error
HapticCollection.snap
// Expressive
HapticCollection.heartbeat
HapticCollection.charge
HapticCollection.sparkle
HapticCollection.drumRoll
HapticCollection.rumble
HapticCollection.boing
HapticCollection.wave
HapticCollection.coinDrop
HapticCollection.waterDrip
// ...and more
Some presets accept parameters:
await Bzzz.instance.play(ClickHaptic(intensity: 0.4));
Custom Haptics
If presets aren't enough, you have two options depending on how much control you need.
UnifiedHaptic — one config for both platforms
Define a haptic with normalized parameters, and the library translates it for each platform:
await Bzzz.instance.play(
UnifiedHaptic(
intensity: 0.7,
sharpness: 0.5,
duration: 0.3,
attack: 0.1,
decay: 0.2,
),
);
All values are normalized to [0.0, 1.0], durations are in seconds.
CustomHaptic — full per-platform control
When you need to squeeze out every bit of the hardware, configure each platform separately:
await Bzzz.instance.play(
CustomHaptic(
cupertinoConfig: CupertinoHapticConfig(
events: [
HapticTransient(time: 0.0, intensity: 1.0, sharpness: 0.8),
HapticContinuous(
time: 0.1,
duration: 0.5,
intensity: 0.6,
sharpness: 0.4,
),
],
parameterCurves: [
ParameterCurve(
parameterId: CurveParameterId.hapticIntensityControl,
controlPoints: [
ParameterCurveControlPoint(time: 0.0, value: 1.0),
ParameterCurveControlPoint(time: 0.5, value: 0.0),
],
),
],
),
androidConfig: AndroidHapticConfig(
compositionConfig: CompositionConfig(
primitives: [
CompositionPrimitive(
primitive: AndroidPrimitive.click,
scale: 1.0,
delay: 0,
),
],
),
),
),
);
On iOS you describe haptics as a timeline of transient/continuous events with optional parameter curves (ADSR envelopes, intensity/sharpness animations over time).
On Android the library picks the best available API automatically based on what the device supports (see Android section above). You can provide all three tiers in one config and the library will use the best match.
Checking Device Capabilities
final info = await Bzzz.instance.getDeviceHapticsInfo();
switch (info) {
case AndroidDeviceHapticsInfo():
print('Vibrator: ${info.hasVibrator}');
print('Amplitude control: ${info.hasAmplitudeControl}');
print('Primitives: ${info.supportedPrimitives}');
case CupertinoDeviceHapticsInfo():
print('CoreHaptics: ${info.supportsCoreHaptics}');
}
More Examples
The example app has a lot of patterns — from practical UI feedback (toggle switches, pull-to-refresh, message sent) to fun stuff (typewriter, raindrops, explosions) and even recognizable tunes (Imperial March, Beethoven's 5th). Good starting point if you want to design your own.
License
MIT
Libraries
- bzzz
- Flutter Haptics — rich cross-platform haptic feedback.