HapWeave

English | 日本語

Weave meaningful haptics into Flutter.

HapWeave is a capability-aware Flutter plugin for semantic feedback and custom haptic patterns on iOS and Android. It selects the highest-quality native implementation available on each device and reports when a fallback was used.

HapWeave is in early development. Its public API may change before 1.0.0.

Why HapWeave?

Flutter's built-in haptic API intentionally exposes a small set of platform defaults. HapWeave adds:

  • 30 presets for common interactions, gestures, state, and expression;
  • transient and continuous events on a shared timeline;
  • intensity and sharpness controls from 0.0 to 1.0;
  • parameter curves for continuous feedback;
  • device capability inspection and automatic fallbacks;
  • playback diagnostics for development and device testing.

HapWeave aims for the same meaning and perceived intent across devices, not identical physical waveforms. Actuators and manufacturer tuning differ.

Platform support

Platform Minimum Highest-quality backend
iOS 13.0 Core Haptics
Android API 26 Basic Envelope on API 36+, Composition on API 30+, Waveform otherwise

Some devices do not contain compatible haptic hardware. Always treat haptics as an enhancement rather than the only way to communicate state.

Installation

Add HapWeave from pub.flutter-io.cn:

flutter pub add hap_weave

Or add it manually to pubspec.yaml:

dependencies:
  hap_weave: ^0.1.0

Then import the package with import 'package:hap_weave/hap_weave.dart';.

Preset catalog

HapWeave includes 30 presets. Preset names describe intent rather than a fixed motor waveform, so the result can be adapted to each platform and device.

import 'package:hap_weave/hap_weave.dart';

await HapWeave.instance.play(HapticPreset.selection);
await HapWeave.instance.play(HapticPreset.longPressComplete);
await HapWeave.instance.play(HapticPreset.success);
await HapWeave.instance.play(HapticPreset.heartbeat);

Basic interactions

Preset Intended use Feel
selection Picker or segmented-control changes Very light tick
tap Ordinary taps Familiar light impact
softTap Secondary actions Soft, restrained impact
firmTap Prominent primary actions Crisp, weighty impact
toggle Neutral switch changes Soft single response
toggleOn Enabling a feature Rising two-step response
toggleOff Disabling a feature Falling two-step response
longPressStart Acknowledging that a hold began Short, soft continuous touch
longPressComplete Committing a hold action Soft cue followed by a firm cue
dragTick Slider or scrubber steps Tiny sharp tick
snap Locking an object into position Short, sharp stop

Gestures and movement

Preset Intended use Feel
swipeCommit Crossing a swipe action threshold Light-to-firm pair
pullReady Pull-to-refresh release threshold Gradual rising pull
refreshComplete Refreshed content has arrived Light two-step finish
reorderLift Picking up a reorderable item Decaying lift sensation
reorderDrop Placing a reordered item Two-step landing
boundary Reaching a range or scroll edge Firm stop with soft rebound

State feedback

Preset Intended use Feel
confirm Confirming a decision Decisive single impact
success Save, send, or operation success Positive system-style response
warning A state requiring attention Warning system-style response
error A failed action Unmistakable error response
notification General incoming information Compact notification response
completion Completing a longer task Rewarding completion response
delete Removing content Heavy cue that falls away
denied Locked or unavailable actions Two firm stops
copied Copying content Two tiny crisp ticks

Expressive patterns

Preset Intended use Feel
doublePulse Emphasis or lightweight reactions Two even beats
triplePulse Special attention Three rising beats
heartbeat Favorites or warm emotional moments Two repeated lub-dub pairs
crescendo Achievement or building anticipation Continuous rise to a strong finish

The original platform-semantic presets use UIKit feedback generators and Android predefined effects where available. The additional authored presets use HapWeave's event timeline so their timing and intensity remain intentional. Hardware differences mean they will not feel physically identical on every device; always validate important interactions on real iOS and Android devices.

Custom patterns

Build a pattern as a sequence:

final pattern = HapticSequence()
    .transient(intensity: 0.3, sharpness: 0.9)
    .wait(const Duration(milliseconds: 70))
    .transient(intensity: 0.8, sharpness: 0.5)
    .build();

final playback = await HapWeave.instance.play(pattern);
print(playback.backend);
print(playback.wasFallback);

Continuous effects can change over time:

final crescendo = HapticSequence()
    .continuous(
      duration: const Duration(milliseconds: 600),
      intensity: 0.7,
      sharpness: 0.3,
      intensityCurve: HapticCurve(const [
        HapticPoint(0.0, 0.1),
        HapticPoint(0.6, 0.5),
        HapticPoint(1.0, 1.0),
      ]),
    )
    .build();

await HapWeave.instance.play(crescendo);

Patterns are limited to ten seconds. This keeps the API focused on interface feedback and helps prevent accidental long, uncomfortable vibrations.

Playback policies

await HapWeave.instance.play(
  HapticPreset.confirm,
  policy: HapticPlaybackPolicy.ignoreIfPlaying,
  fallback: HapticFallbackPolicy.automatic,
);

await HapWeave.instance.stop();
  • replace: stop the current effect and play immediately;
  • ignoreIfPlaying: skip the request while another effect is active;
  • enqueue: wait until the current effect's estimated duration has elapsed.

Fallback policies are automatic for the best available translation, system to request a simple platform effect, and none to prevent custom-pattern fallbacks.

Capabilities and diagnostics

final capabilities = await HapWeave.instance.capabilities;
print(capabilities.supportLevel);
print(capabilities.supportsSharpnessControl);

final playback = await HapWeave.instance.play(HapticPreset.success);
print(playback.backend);
print(playback.quality);
print(playback.fallbackReason);

Try it on a device

Haptics cannot be evaluated accurately in a simulator. Connect an iPhone or Android device and run the included laboratory app:

cd example
flutter run

The app is available in English and Japanese. Each preset is demonstrated with a matching UI control—such as a switch, long press, slider, swipe, reorder, copy, or delete action—rather than an undifferentiated grid of play buttons. It also includes a visual custom-pattern designer with a draggable event timeline, an intensity/sharpness feel pad, undo and redo, device playback, and Dart code export.

Learn how haptics work

Project scope

HapWeave targets general mobile applications. Frame-accurate game feedback, audio-haptic synchronization, direct frequency authoring, AHAP file playback, desktop platforms, and web are not part of the initial release.

Development

flutter analyze
flutter test
cd example && flutter test

See CONTRIBUTING.md before proposing public API or preset changes. Presets should be tuned and reviewed on physical iOS and Android hardware.

License

MIT. See LICENSE.