JindongJindong

Haptic

Fixed-duration vibration, transient impacts, and continuous haptic curves

Haptic

Module: jindong-compose | Package: io.github.compose.jindong.dsl

Emits a vibration event for the specified duration.

Signature

@Composable
fun JindongScope.Haptic(
    duration: Duration,
    intensity: HapticIntensity = HapticIntensity.MEDIUM
)

Parameters

ParameterTypeDefaultDescription
durationDuration-How long the vibration lasts
intensityHapticIntensityMEDIUMVibration strength

Description

Haptic creates a single vibration event in the haptic pattern. The event is scheduled relative to previous events in the pattern.

Usage

Basic Usage

Jindong(trigger) {
    Haptic(100.ms)  // 100ms vibration at medium intensity
}

With Intensity

Jindong(trigger) {
    Haptic(100.ms, HapticIntensity.LIGHT)   // Subtle
    Haptic(100.ms, HapticIntensity.MEDIUM)  // Standard
    Haptic(100.ms, HapticIntensity.STRONG)  // Noticeable
    Haptic(100.ms, HapticIntensity.HIGH)    // Maximum
}

Custom Intensity

Jindong(trigger) {
    Haptic(100.ms, HapticIntensity.Custom(0.65f))
}

Sequential Haptics

Events run one after another:

Jindong(trigger) {
    Haptic(100.ms)  // 0-100ms
    Haptic(50.ms)   // 100-150ms
    Haptic(30.ms)   // 150-180ms
}

With Delays

Jindong(trigger) {
    Haptic(50.ms)   // 0-50ms
    Delay(100.ms)   // 50-150ms (silence)
    Haptic(50.ms)   // 150-200ms
}

Examples

Single Tap Feedback

Jindong(tapCount) {
    Haptic(50.ms, HapticIntensity.LIGHT)
}

Double Tap Pattern

Jindong(trigger) {
    Haptic(40.ms)
    Delay(40.ms)
    Haptic(40.ms)
}

Success Feedback

Jindong(success) {
    Haptic(50.ms, HapticIntensity.MEDIUM)
    Delay(50.ms)
    Haptic(100.ms, HapticIntensity.STRONG)
}

Fade Out

Jindong(trigger) {
    RepeatWithIndex(5) { index ->
        val fade = HapticIntensity.Custom(1.0f - (index * 0.2f))
        Haptic(50.ms, fade)
        Delay(30.ms)
    }
}

Transient and Continuous

Use the common rich event model through these Compose functions:

@Composable
fun JindongScope.Transient(
    intensity: HapticIntensity = HapticIntensity.MEDIUM,
    sharpness: Float = 0.5f,
)
 
@Composable
fun JindongScope.Continuous(
    duration: Duration,
    intensity: HapticIntensity = HapticIntensity.MEDIUM,
    sharpness: Float = 0.5f,
    intensityCurve: HapticCurve? = null,
    sharpnessCurve: HapticCurve? = null,
)

Both use io.github.compose.jindong.dsl. Build shared curves with io.github.compose.jindong.core.dsl.hapticCurve:

val rise = hapticCurve {
    point(0.ms, 0f)
    point(80.ms, 0.8f)
    point(300.ms, 0f)
}
Jindong(trigger, playOnInitialComposition = false) {
    Repeat(3) {
        Transient(HapticIntensity.STRONG, sharpness = 0.9f)
        Delay(80.ms)
    }
    Continuous(300.ms, intensityCurve = rise, sharpness = 0.6f)
}

A transient has zero logical duration. Use Delay to separate impacts. A continuous event requires a positive duration. Curves replace the corresponding fixed value and must end at the event duration. Sharpness and curve values must be finite and within 0..1. The core DSL applies the same validation and produces equal compiled values.

As with Haptic and Clip, values are captured when the pattern compiles. Include changing values in Jindong trigger keys when they must update the pattern. See Migrating to 2.0 for curve and compatibility rules.

Platform Behavior

PlatformImplementation
AndroidVibrationEffect.createWaveform()
iOSCHHapticEvent (HapticContinuous) played via CHHapticEngine

Notes

  • Duration is the haptic event length, not a delay
  • Events are sequential by default
  • Use Delay to add gaps between haptics
  • Intensity values are normalized (0.0 to 1.0)

See Also

On this page