Overview
WebHaptics uses Pulse-Width Modulation (PWM) to simulate variable intensity vibrations. Since the Web Vibration API only supports binary on/off states, PWM creates the perception of different intensities by rapidly toggling vibration on and off within fixed time cycles.How PWM Works
ThemodulateVibration function (index.ts:60-82) converts intensity values (0.0-1.0) into on/off patterns:
Key Constants
| Constant | Value | Purpose |
|---|---|---|
PWM_CYCLE | 20ms | Duration of each on/off cycle |
TOGGLE_MIN | 16ms | Minimum toggle interval at intensity 1.0 |
TOGGLE_MAX | 184ms | Additional range for lower intensities |
MAX_PHASE_MS | 1000ms | Browser haptic API window limit |
Intensity Mapping
The PWM cycle divides each 20ms window into on-time and off-time based on intensity.
Example Calculations
Intensity 0.5 (50% power):onTime = max(1, round(20 * 0.5)) = 10msoffTime = 20 - 10 = 10ms- Pattern:
[10, 10, 10, 10, ...]for equal on/off periods
onTime = max(1, round(20 * 0.25)) = 5msoffTime = 20 - 5 = 15ms- Pattern:
[5, 15, 5, 15, ...]for short pulses
- Returns
[duration]directly - continuous vibration
- Returns
[]- no vibration
Visual Representation
Partial Cycle Handling
How are incomplete cycles processed?
How are incomplete cycles processed?
When the remaining duration is less than a full PWM cycle, the algorithm proportionally scales the on/off times:For example, with 15ms remaining at 0.5 intensity:
remOn = max(1, round(15 * 0.5)) = 8msremOff = 15 - 8 = 7ms- Adds:
[8, 7]
Integration with Vibration API
The modulated pattern is flattened and passed tonavigator.vibrate():
toVibratePattern function (index.ts:88-132) applies PWM to each vibration object and concatenates the results into a single number array.
The browser’s Vibration API receives a flat array like
[10, 10, 10, 10, 5, 15] where odd indices are vibration durations and even indices are pauses.Performance Considerations
Timing Accuracy
Toggle Frequency in Debug Mode
For fallback visual/audio feedback, the library uses a different approach withrequestAnimationFrame:
Edge Cases
Minimum On-Time
Minimum On-Time
The
Math.max(1, ...) ensures at least 1ms on-time even at very low intensities. Without this, intensities below 0.05 would round to 0ms and produce no vibration.Zero and Full Intensity
Zero and Full Intensity
The function short-circuits for
intensity >= 1 and intensity <= 0 to avoid unnecessary PWM computation:- 1.0: Returns single duration value (no modulation)
- 0.0: Returns empty array (treated as silence)