@hapticjs/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1205 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +384 -0
- package/dist/index.d.ts +384 -0
- package/dist/index.js +1181 -0
- package/dist/index.js.map +1 -0
- package/dist/presets/index.cjs +398 -0
- package/dist/presets/index.cjs.map +1 -0
- package/dist/presets/index.d.cts +950 -0
- package/dist/presets/index.d.ts +950 -0
- package/dist/presets/index.js +391 -0
- package/dist/presets/index.js.map +1 -0
- package/package.json +58 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
export { accessibility, gaming, notifications, presets, system, ui } from './presets/index.js';
|
|
2
|
+
|
|
3
|
+
/** A single step in a haptic sequence */
|
|
4
|
+
interface HapticStep {
|
|
5
|
+
type: 'vibrate' | 'pause';
|
|
6
|
+
/** Duration in milliseconds */
|
|
7
|
+
duration: number;
|
|
8
|
+
/** Intensity from 0.0 to 1.0 (0 = off, 1 = max) */
|
|
9
|
+
intensity: number;
|
|
10
|
+
/** Optional easing for intensity ramps */
|
|
11
|
+
easing?: EasingFunction;
|
|
12
|
+
}
|
|
13
|
+
/** A complete haptic pattern — a named sequence of steps */
|
|
14
|
+
interface HapticPattern {
|
|
15
|
+
name?: string;
|
|
16
|
+
steps: HapticStep[];
|
|
17
|
+
metadata?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
/** Easing function type for smooth transitions */
|
|
20
|
+
type EasingFunction = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
|
|
21
|
+
/** Semantic impact styles matching iOS UIImpactFeedbackGenerator */
|
|
22
|
+
type ImpactStyle = 'light' | 'medium' | 'heavy' | 'rigid' | 'soft';
|
|
23
|
+
/** Semantic notification types */
|
|
24
|
+
type NotificationType = 'success' | 'warning' | 'error';
|
|
25
|
+
/** All built-in semantic effect names */
|
|
26
|
+
type SemanticEffect = 'tap' | 'doubleTap' | 'longPress' | 'success' | 'warning' | 'error' | 'selection' | 'toggle' | ImpactStyle;
|
|
27
|
+
|
|
28
|
+
/** Capabilities a haptic adapter supports */
|
|
29
|
+
interface AdapterCapabilities {
|
|
30
|
+
/** Number of discrete intensity levels (1 = on/off only, 100+ = fine-grained) */
|
|
31
|
+
maxIntensityLevels: number;
|
|
32
|
+
/** Minimum pulse duration in ms */
|
|
33
|
+
minDuration: number;
|
|
34
|
+
/** Maximum continuous duration in ms */
|
|
35
|
+
maxDuration: number;
|
|
36
|
+
/** Whether the adapter can play multi-step patterns natively */
|
|
37
|
+
supportsPattern: boolean;
|
|
38
|
+
/** Whether the adapter can vary intensity (not just on/off) */
|
|
39
|
+
supportsIntensity: boolean;
|
|
40
|
+
/** Whether the adapter has dual motors (gamepad-style) */
|
|
41
|
+
dualMotor: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** Interface all haptic adapters must implement */
|
|
44
|
+
interface HapticAdapter {
|
|
45
|
+
readonly name: string;
|
|
46
|
+
readonly supported: boolean;
|
|
47
|
+
/** Get the capabilities of this adapter */
|
|
48
|
+
capabilities(): AdapterCapabilities;
|
|
49
|
+
/** Fire a single haptic pulse */
|
|
50
|
+
pulse(intensity: number, duration: number): Promise<void>;
|
|
51
|
+
/** Play a sequence of haptic steps */
|
|
52
|
+
playSequence(steps: HapticStep[]): Promise<void>;
|
|
53
|
+
/** Cancel any ongoing haptic effect */
|
|
54
|
+
cancel(): void;
|
|
55
|
+
/** Clean up resources */
|
|
56
|
+
dispose(): void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Visual fallback style when haptics are unavailable */
|
|
60
|
+
type VisualFallbackStyle = 'flash' | 'shake' | 'pulse';
|
|
61
|
+
/** Fallback configuration for non-haptic feedback */
|
|
62
|
+
interface FallbackConfig {
|
|
63
|
+
type: 'none' | 'visual' | 'audio' | 'both';
|
|
64
|
+
visual?: {
|
|
65
|
+
/** Element to animate */
|
|
66
|
+
element?: HTMLElement;
|
|
67
|
+
/** CSS class to toggle */
|
|
68
|
+
className?: string;
|
|
69
|
+
/** Animation style */
|
|
70
|
+
style?: VisualFallbackStyle;
|
|
71
|
+
};
|
|
72
|
+
audio?: {
|
|
73
|
+
enabled: boolean;
|
|
74
|
+
/** Volume from 0 to 1 */
|
|
75
|
+
volume: number;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** Main configuration for the haptic engine */
|
|
79
|
+
interface HapticConfig {
|
|
80
|
+
/** Explicitly set an adapter (overrides auto-detection) */
|
|
81
|
+
adapter?: HapticAdapter;
|
|
82
|
+
/** Global intensity multiplier (0.0 to 1.0) */
|
|
83
|
+
intensity: number;
|
|
84
|
+
/** Whether haptics are enabled */
|
|
85
|
+
enabled: boolean;
|
|
86
|
+
/** Fallback when haptics are unavailable */
|
|
87
|
+
fallback: FallbackConfig;
|
|
88
|
+
/** Respect system haptic settings */
|
|
89
|
+
respectSystemSettings: boolean;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** HPL Token types */
|
|
93
|
+
type HPLTokenType = 'LIGHT' | 'MEDIUM' | 'HEAVY' | 'PAUSE' | 'TAP' | 'SUSTAIN' | 'GROUP_START' | 'GROUP_END' | 'REPEAT';
|
|
94
|
+
/** A single HPL token */
|
|
95
|
+
interface HPLToken {
|
|
96
|
+
type: HPLTokenType;
|
|
97
|
+
value: string;
|
|
98
|
+
/** For REPEAT tokens, the repeat count */
|
|
99
|
+
repeatCount?: number;
|
|
100
|
+
}
|
|
101
|
+
/** AST node types */
|
|
102
|
+
type HPLNodeType = 'vibrate' | 'pause' | 'tap' | 'sustain' | 'group' | 'sequence';
|
|
103
|
+
/** Base AST node */
|
|
104
|
+
interface HPLBaseNode {
|
|
105
|
+
type: HPLNodeType;
|
|
106
|
+
}
|
|
107
|
+
/** Vibrate node — ~, #, or @ */
|
|
108
|
+
interface HPLVibrateNode extends HPLBaseNode {
|
|
109
|
+
type: 'vibrate';
|
|
110
|
+
intensity: number;
|
|
111
|
+
duration: number;
|
|
112
|
+
}
|
|
113
|
+
/** Pause node — . */
|
|
114
|
+
interface HPLPauseNode extends HPLBaseNode {
|
|
115
|
+
type: 'pause';
|
|
116
|
+
duration: number;
|
|
117
|
+
}
|
|
118
|
+
/** Tap node — | */
|
|
119
|
+
interface HPLTapNode extends HPLBaseNode {
|
|
120
|
+
type: 'tap';
|
|
121
|
+
duration: number;
|
|
122
|
+
intensity: number;
|
|
123
|
+
}
|
|
124
|
+
/** Sustain node — - */
|
|
125
|
+
interface HPLSustainNode extends HPLBaseNode {
|
|
126
|
+
type: 'sustain';
|
|
127
|
+
extension: number;
|
|
128
|
+
}
|
|
129
|
+
/** Group node — [...] with optional repeat */
|
|
130
|
+
interface HPLGroupNode extends HPLBaseNode {
|
|
131
|
+
type: 'group';
|
|
132
|
+
children: HPLNode[];
|
|
133
|
+
repeat: number;
|
|
134
|
+
}
|
|
135
|
+
/** Sequence node — the root */
|
|
136
|
+
interface HPLSequenceNode extends HPLBaseNode {
|
|
137
|
+
type: 'sequence';
|
|
138
|
+
children: HPLNode[];
|
|
139
|
+
}
|
|
140
|
+
/** Any HPL AST node */
|
|
141
|
+
type HPLNode = HPLVibrateNode | HPLPauseNode | HPLTapNode | HPLSustainNode | HPLGroupNode | HPLSequenceNode;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Fluent builder for composing haptic patterns programmatically.
|
|
145
|
+
*
|
|
146
|
+
* Usage:
|
|
147
|
+
* const pattern = new PatternComposer()
|
|
148
|
+
* .tap(0.5)
|
|
149
|
+
* .pause(100)
|
|
150
|
+
* .ramp(0.2, 1.0, 300)
|
|
151
|
+
* .buzz(200)
|
|
152
|
+
* .build();
|
|
153
|
+
*/
|
|
154
|
+
declare class PatternComposer {
|
|
155
|
+
private steps;
|
|
156
|
+
private _onPlay?;
|
|
157
|
+
/** Register a play callback (used by HapticEngine) */
|
|
158
|
+
onPlay(fn: (steps: HapticStep[]) => Promise<void>): this;
|
|
159
|
+
/** Add a short tap vibration */
|
|
160
|
+
tap(intensity?: number): this;
|
|
161
|
+
/** Add a vibration with specified duration and intensity */
|
|
162
|
+
vibrate(duration: number, intensity?: number): this;
|
|
163
|
+
/** Add a buzz (medium-length vibration) */
|
|
164
|
+
buzz(duration?: number, intensity?: number): this;
|
|
165
|
+
/** Add a pause */
|
|
166
|
+
pause(duration?: number): this;
|
|
167
|
+
/** Add an intensity ramp from start to end intensity over duration */
|
|
168
|
+
ramp(startIntensity: number, endIntensity: number, duration: number, easing?: EasingFunction): this;
|
|
169
|
+
/** Add a pulse pattern (on-off-on-off) */
|
|
170
|
+
pulse(count: number, onDuration?: number, offDuration?: number, intensity?: number): this;
|
|
171
|
+
/** Repeat the entire current sequence N times */
|
|
172
|
+
repeat(times: number): this;
|
|
173
|
+
/** Build and return the step array */
|
|
174
|
+
build(): HapticStep[];
|
|
175
|
+
/** Build and immediately play the pattern */
|
|
176
|
+
play(): Promise<void>;
|
|
177
|
+
/** Reset the composer */
|
|
178
|
+
clear(): this;
|
|
179
|
+
/** Get total duration in ms */
|
|
180
|
+
get duration(): number;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* The main haptic engine — orchestrates adapters, patterns, and fallbacks.
|
|
185
|
+
*
|
|
186
|
+
* Usage:
|
|
187
|
+
* const engine = HapticEngine.create();
|
|
188
|
+
* engine.tap();
|
|
189
|
+
* engine.success();
|
|
190
|
+
* engine.play('~~..##..@@');
|
|
191
|
+
*/
|
|
192
|
+
declare class HapticEngine {
|
|
193
|
+
private adapter;
|
|
194
|
+
private config;
|
|
195
|
+
private adaptive;
|
|
196
|
+
private fallback;
|
|
197
|
+
constructor(config?: Partial<HapticConfig>);
|
|
198
|
+
/** Create a new engine with auto-detected adapter */
|
|
199
|
+
static create(config?: Partial<HapticConfig>): HapticEngine;
|
|
200
|
+
/** Light tap feedback */
|
|
201
|
+
tap(intensity?: number): Promise<void>;
|
|
202
|
+
/** Double tap */
|
|
203
|
+
doubleTap(intensity?: number): Promise<void>;
|
|
204
|
+
/** Long press feedback */
|
|
205
|
+
longPress(intensity?: number): Promise<void>;
|
|
206
|
+
/** Success notification */
|
|
207
|
+
success(): Promise<void>;
|
|
208
|
+
/** Warning notification */
|
|
209
|
+
warning(): Promise<void>;
|
|
210
|
+
/** Error notification */
|
|
211
|
+
error(): Promise<void>;
|
|
212
|
+
/** Selection change feedback */
|
|
213
|
+
selection(): Promise<void>;
|
|
214
|
+
/** Toggle feedback */
|
|
215
|
+
toggle(on: boolean): Promise<void>;
|
|
216
|
+
/** Impact with style (matches iOS UIImpactFeedbackGenerator) */
|
|
217
|
+
impact(style?: ImpactStyle): Promise<void>;
|
|
218
|
+
/** Vibrate for a specified duration */
|
|
219
|
+
vibrate(duration: number, intensity?: number): Promise<void>;
|
|
220
|
+
/**
|
|
221
|
+
* Play a haptic pattern.
|
|
222
|
+
* Accepts:
|
|
223
|
+
* - HPL string: "~~..##..@@"
|
|
224
|
+
* - HapticPattern object
|
|
225
|
+
* - Raw HapticStep array
|
|
226
|
+
*/
|
|
227
|
+
play(pattern: string | HapticPattern | HapticStep[]): Promise<void>;
|
|
228
|
+
/** Create a new pattern composer */
|
|
229
|
+
compose(): PatternComposer;
|
|
230
|
+
/** Update engine configuration */
|
|
231
|
+
configure(config: Partial<HapticConfig>): void;
|
|
232
|
+
/** Check if haptics are supported on this device */
|
|
233
|
+
get isSupported(): boolean;
|
|
234
|
+
/** Get the current adapter name */
|
|
235
|
+
get adapterName(): string;
|
|
236
|
+
/** Cancel any ongoing haptic effect */
|
|
237
|
+
cancel(): void;
|
|
238
|
+
/** Clean up resources */
|
|
239
|
+
dispose(): void;
|
|
240
|
+
private _playSteps;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Adapts ideal haptic patterns to what the device can actually produce.
|
|
245
|
+
* Handles intensity quantization, duration clamping, and step merging.
|
|
246
|
+
*/
|
|
247
|
+
declare class AdaptiveEngine {
|
|
248
|
+
adapt(steps: HapticStep[], capabilities: AdapterCapabilities): HapticStep[];
|
|
249
|
+
private _adaptStep;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Provides visual/audio fallback when haptic hardware is unavailable.
|
|
254
|
+
*/
|
|
255
|
+
declare class FallbackManager {
|
|
256
|
+
private config;
|
|
257
|
+
constructor(config: FallbackConfig);
|
|
258
|
+
updateConfig(config: FallbackConfig): void;
|
|
259
|
+
/** Execute fallback feedback for the given steps */
|
|
260
|
+
execute(steps: HapticStep[]): Promise<void>;
|
|
261
|
+
private _visualFallback;
|
|
262
|
+
private _audioFallback;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Auto-detect the best available haptic adapter for the current platform.
|
|
267
|
+
*/
|
|
268
|
+
declare function detectAdapter(): HapticAdapter;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* No-op adapter — used in SSR, Node, or when no haptic hardware is available.
|
|
272
|
+
* Silently accepts all calls without doing anything.
|
|
273
|
+
*/
|
|
274
|
+
declare class NoopAdapter implements HapticAdapter {
|
|
275
|
+
readonly name = "noop";
|
|
276
|
+
readonly supported = false;
|
|
277
|
+
capabilities(): AdapterCapabilities;
|
|
278
|
+
pulse(_intensity: number, _duration: number): Promise<void>;
|
|
279
|
+
playSequence(_steps: HapticStep[]): Promise<void>;
|
|
280
|
+
cancel(): void;
|
|
281
|
+
dispose(): void;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Web Vibration API adapter.
|
|
286
|
+
* Uses navigator.vibrate() — supported on Android browsers.
|
|
287
|
+
* Intensity is simulated via PWM (rapid on/off) since the API only supports on/off.
|
|
288
|
+
*/
|
|
289
|
+
declare class WebVibrationAdapter implements HapticAdapter {
|
|
290
|
+
readonly name = "web-vibration";
|
|
291
|
+
readonly supported: boolean;
|
|
292
|
+
private _cancelled;
|
|
293
|
+
constructor();
|
|
294
|
+
capabilities(): AdapterCapabilities;
|
|
295
|
+
pulse(_intensity: number, duration: number): Promise<void>;
|
|
296
|
+
playSequence(steps: HapticStep[]): Promise<void>;
|
|
297
|
+
cancel(): void;
|
|
298
|
+
dispose(): void;
|
|
299
|
+
/** Convert steps to Vibration API pattern array */
|
|
300
|
+
private _toVibrationPattern;
|
|
301
|
+
/** Check if all steps can be played with native pattern (no intensity variation) */
|
|
302
|
+
private _canUseNativePattern;
|
|
303
|
+
/** Simulate lower intensity via pulse-width modulation */
|
|
304
|
+
private _pwmVibrate;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
declare class HPLParserError extends Error {
|
|
308
|
+
constructor(message: string);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Recursive descent parser for the Haptic Pattern Language (HPL).
|
|
312
|
+
*
|
|
313
|
+
* Grammar:
|
|
314
|
+
* Pattern := Segment+
|
|
315
|
+
* Segment := Group | Atom
|
|
316
|
+
* Group := '[' Segment+ ']' Repeat?
|
|
317
|
+
* Atom := '~' | '#' | '@' | '.' | '|' | '-'
|
|
318
|
+
* Repeat := 'x' Number
|
|
319
|
+
*/
|
|
320
|
+
declare class HPLParser {
|
|
321
|
+
private tokens;
|
|
322
|
+
private pos;
|
|
323
|
+
parse(input: string): HPLSequenceNode;
|
|
324
|
+
private _parseSegments;
|
|
325
|
+
private _parseSegment;
|
|
326
|
+
private _parseGroup;
|
|
327
|
+
private _parseAtom;
|
|
328
|
+
private _makeVibrate;
|
|
329
|
+
private _makePause;
|
|
330
|
+
private _makeTap;
|
|
331
|
+
private _makeSustain;
|
|
332
|
+
}
|
|
333
|
+
/** Convenience function to parse an HPL string */
|
|
334
|
+
declare function parseHPL(input: string): HPLSequenceNode;
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Compiles an HPL AST into a flat array of HapticSteps.
|
|
338
|
+
* Handles group expansion, sustain merging, and repeat unrolling.
|
|
339
|
+
*/
|
|
340
|
+
declare function compile(ast: HPLSequenceNode): HapticStep[];
|
|
341
|
+
/**
|
|
342
|
+
* Optimize a step sequence by merging adjacent same-type steps.
|
|
343
|
+
*/
|
|
344
|
+
declare function optimizeSteps(steps: HapticStep[]): HapticStep[];
|
|
345
|
+
|
|
346
|
+
declare class HPLTokenizerError extends Error {
|
|
347
|
+
readonly position: number;
|
|
348
|
+
constructor(message: string, position: number);
|
|
349
|
+
}
|
|
350
|
+
/** Tokenize an HPL pattern string into tokens */
|
|
351
|
+
declare function tokenize(input: string): HPLToken[];
|
|
352
|
+
|
|
353
|
+
/** Validate an HPL pattern string and return human-readable errors */
|
|
354
|
+
interface ValidationResult {
|
|
355
|
+
valid: boolean;
|
|
356
|
+
errors: string[];
|
|
357
|
+
}
|
|
358
|
+
declare function validateHPL(input: string): ValidationResult;
|
|
359
|
+
|
|
360
|
+
/** Platform detection utilities */
|
|
361
|
+
interface PlatformInfo {
|
|
362
|
+
isWeb: boolean;
|
|
363
|
+
isNode: boolean;
|
|
364
|
+
isReactNative: boolean;
|
|
365
|
+
hasVibrationAPI: boolean;
|
|
366
|
+
hasGamepadAPI: boolean;
|
|
367
|
+
isIOS: boolean;
|
|
368
|
+
isAndroid: boolean;
|
|
369
|
+
isMobile: boolean;
|
|
370
|
+
}
|
|
371
|
+
declare function detectPlatform(): PlatformInfo;
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Pre-configured haptic engine singleton.
|
|
375
|
+
* Import and use directly for quick haptic feedback:
|
|
376
|
+
*
|
|
377
|
+
* import { haptic } from '@hapticjs/core';
|
|
378
|
+
* haptic.tap();
|
|
379
|
+
* haptic.success();
|
|
380
|
+
* haptic.play('~~..##..@@');
|
|
381
|
+
*/
|
|
382
|
+
declare const haptic: HapticEngine;
|
|
383
|
+
|
|
384
|
+
export { type AdapterCapabilities, AdaptiveEngine, type EasingFunction, type FallbackConfig, FallbackManager, type HPLNode, type HPLNodeType, HPLParser, HPLParserError, type HPLToken, type HPLTokenType, HPLTokenizerError, type HapticAdapter, type HapticConfig, HapticEngine, type HapticPattern, type HapticStep, type ImpactStyle, NoopAdapter, type NotificationType, PatternComposer, type PlatformInfo, type SemanticEffect, type ValidationResult, type VisualFallbackStyle, WebVibrationAdapter, compile, detectAdapter, detectPlatform, haptic, optimizeSteps, parseHPL, tokenize, validateHPL };
|