Skip to main content
The video uses a specific AI coding tool to demonstrate the setup, but the configuration works 1:1 with Cursor, Claude Code, or any other tool. Despia is web framework and tooling agnostic, so the only thing that matters is the SDK call.
Five fire-and-forget URL schemes trigger the corresponding native haptic generator on iOS and the equivalent vibration pattern on Android. Each scheme maps to a standard interaction type, so picking the right one is mostly about matching intent (success, warning, error) rather than tweaking intensity.

Installation

npm install despia-native
import despia from 'despia-native';

How it works

Each scheme is fire-and-forget. The native runtime triggers the haptic immediately, your JavaScript keeps running. There are no parameters and no return value.
const isDespia = navigator.userAgent.toLowerCase().includes('despia')

if (isDespia) {
    despia('lighthaptic://')
}
In a regular browser the call is a no-op behind the isDespia guard, so the same code is safe to run during web preview.

The five haptic patterns

SchemeWhen to use it
lighthaptic://Subtle confirmations, toggle flips, minor selections, list item presses
heavyhaptic://Important commits, primary CTA taps, power-up activation
successhaptic://Completed transactions, saved state, finished workflows
warninghaptic://Confirmation needed, destructive action prompts, cautionary states
errorhaptic://Failed validation, rejected actions, network errors
Match the pattern to user intent rather than trying to engineer custom intensity through repeated calls. iOS users in particular are conditioned by system apps to read these patterns as signals (the success/warning/error trio matches Apple’s UINotificationFeedbackGenerator), so reusing them keeps your app feeling native.

Wire haptics to user actions

Call despia('...haptic://') directly at the call site. No helper, no wrapper, no abstraction. The scheme is already short and reads clearly.
import despia from 'despia-native'

const isDespia = navigator.userAgent.toLowerCase().includes('despia')

function onSavePressed() {
    if (isDespia) despia('heavyhaptic://')
    saveDocument()
}

function onSaveSuccess() {
    if (isDespia) despia('successhaptic://')
}

function onSaveFailed() {
    if (isDespia) despia('errorhaptic://')
}
In React, call directly inside event handlers. Avoid putting haptic calls inside useEffect reactions to derived state, since renders can fire faster than the user perceives, leading to phantom buzzing.
function SubmitButton({ onSubmit }) {
    async function handleClick() {
        if (isDespia) despia('heavyhaptic://')
        try {
            await onSubmit()
            if (isDespia) despia('successhaptic://')
        } catch {
            if (isDespia) despia('errorhaptic://')
        }
    }

    return <button onClick={handleClick}>Submit</button>
}

Game and confirmation patterns

Haptics work well in two places where regular web apps cannot reach: game-style feedback loops and confirmation dialogs. Both rely on the user feeling the result rather than reading it.
function onGameEvent(type) {
    if (!isDespia) return

    switch (type) {
        case 'powerup':  despia('heavyhaptic://');   break
        case 'damage':   despia('errorhaptic://');   break
        case 'victory':  despia('successhaptic://'); break
        case 'level-up': despia('successhaptic://'); break
    }
}

function onDeleteConfirm(confirmed) {
    if (!isDespia) return

    if (confirmed) {
        despia('heavyhaptic://')
        deleteItem()
    } else {
        despia('warninghaptic://')
    }
}
Users can disable system haptics under Settings, Sounds & Haptics, System Haptics, or globally under Accessibility, Touch, Vibration. Some Focus modes also suppress vibrations. The SDK call still succeeds in those cases, it just produces no tactile output. Never use a haptic as the only feedback channel for an important state change, always pair it with visual or audio feedback.

Resources

NPM Package

despia-native