@renegades/react-native-tickle 0.1.0 → 0.1.2

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.
Files changed (2) hide show
  1. package/README.md +51 -64
  2. package/package.json +3 -4
package/README.md CHANGED
@@ -1,4 +1,6 @@
1
- # react-native-tickle
1
+ <img width="1536" height="1024" alt="banner" src="https://github.com/user-attachments/assets/61f1f3bf-24dc-4e0d-ba6a-4dce3a548c96" />
2
+
3
+ # @renegades/react-native-tickle
2
4
 
3
5
  AHAP-style haptics (transient + continuous) on top of [Nitro Modules](https://nitro.margelo.com/) — the core functions are **UI-thread friendly** (`'worklet'`).
4
6
 
@@ -6,17 +8,17 @@ AHAP-style haptics (transient + continuous) on top of [Nitro Modules](https://ni
6
8
 
7
9
  Complete flexibility over iOS haptics with synchronous UI-thread execution.
8
10
 
9
- > iOS only (Core Haptics). Android support could be added in the future, but its currently unplanned.
11
+ > iOS only (Core Haptics). Android support could be added in the future, but it's currently unplanned.
10
12
 
11
13
  ## Installation
12
14
 
13
15
  ```sh
14
- npm i react-native-tickle react-native-nitro-modules
16
+ npm i @renegades/react-native-tickle react-native-nitro-modules
15
17
  ```
16
18
 
17
19
  ## Concepts (what to use when)
18
20
 
19
- - **Transient**: Instant click/tap events. No duration — you trigger them at a point in time.
21
+ - **Transient**: Instant "click/tap" events. No duration — you trigger them at a point in time.
20
22
  - **Continuous (pattern)**: Time-based patterns you _can_ define ahead of time. You provide **events** (with `duration`) and optionally **curves** (automation over time).
21
23
  - **Continuous player (real-time)**: For _unpredictable_ input (gesture position, scroll velocity, real-time data). You create a player once, then **start → update (many times) → stop**.
22
24
 
@@ -24,10 +26,29 @@ npm i react-native-tickle react-native-nitro-modules
24
26
 
25
27
  On iOS Core Haptics, a pattern is made of two different building blocks:
26
28
 
27
- - **Events**: things that happen (transient ticks or continuous segments) at a `relativeTime`, with base `intensity`/`sharpness`.
28
- - **Curves**: how parameters (intensity/sharpness) evolve over time via control points, independent of what event is currently playing.
29
+ - **Events**: things that happen (transient "ticks" or continuous segments) at a `relativeTime`, with base `intensity`/`sharpness`.
30
+ - **Curves**: how parameters (intensity/sharpness) evolve over time via control points, independent of "what event" is currently playing.
31
+
32
+ They're separate because they're different object types in Core Haptics (events vs parameter curves) and they serve different jobs: **events define the structure**, **curves define the modulation**. You often combine both in one pattern.
33
+
34
+ ## Haptix Studio
35
+
36
+ <table>
37
+ <tr>
38
+ <td>
39
+ <img src="https://github.com/user-attachments/assets/9a0edcfa-37ee-440d-9ae3-48fdcce59780" alt="Haptix Studio" width="280" />
40
+ </td>
41
+ <td>
29
42
 
30
- They’re separate because they’re different object types in Core Haptics (events vs parameter curves) and they serve different jobs: **events define the structure**, **curves define the modulation**. You often combine both in one pattern.
43
+ Try out **Haptix Studio** to see what's possible with haptics.
44
+
45
+ Play with continuous patterns and real-time updates, then export your creations directly into code.
46
+
47
+ [Download on Test Flight](https://testflight.apple.com/join/HJn3mbb3)
48
+
49
+ </td>
50
+ </tr>
51
+ </table>
31
52
 
32
53
  ## Usage
33
54
 
@@ -36,7 +57,7 @@ They’re separate because they’re different object types in Core Haptics (eve
36
57
  Wrap your app inside `HapticProvider`. This initializes the engine and automatically destroys it when the app goes to background.
37
58
 
38
59
  ```tsx
39
- import { HapticProvider } from 'react-native-tickle';
60
+ import { HapticProvider } from '@renegades/react-native-tickle';
40
61
 
41
62
  export function App() {
42
63
  return <HapticProvider>{/* {Rest of your app} */}</HapticProvider>;
@@ -48,7 +69,7 @@ export function App() {
48
69
  Play a transient:
49
70
 
50
71
  ```ts
51
- import { startHaptic } from 'react-native-tickle';
72
+ import { startHaptic } from '@renegades/react-native-tickle';
52
73
 
53
74
  startHaptic(
54
75
  [
@@ -68,7 +89,7 @@ startHaptic(
68
89
  Play a continuous pattern (events + curves together):
69
90
 
70
91
  ```ts
71
- import { startHaptic } from 'react-native-tickle';
92
+ import { startHaptic } from '@renegades/react-native-tickle';
72
93
 
73
94
  startHaptic(
74
95
  [
@@ -99,7 +120,7 @@ startHaptic(
99
120
  Combine transient + continuous in one pattern:
100
121
 
101
122
  ```ts
102
- import { startHaptic } from 'react-native-tickle';
123
+ import { startHaptic } from '@renegades/react-native-tickle';
103
124
 
104
125
  startHaptic(
105
126
  [
@@ -129,10 +150,8 @@ startHaptic(
129
150
 
130
151
  Use this when you _can't_ predefine a pattern. You start the player, update it in real time, then stop it.
131
152
 
132
- **Using the hook (recommended):**
133
-
134
153
  ```tsx
135
- import { useContinuousPlayer } from 'react-native-tickle';
154
+ import { useContinuousPlayer } from '@renegades/react-native-tickle';
136
155
 
137
156
  function MyComponent() {
138
157
  const { start, stop, update } = useContinuousPlayer('my-player', 1.0, 0.5);
@@ -150,44 +169,12 @@ function MyComponent() {
150
169
  }
151
170
  ```
152
171
 
153
- **Manual control:**
154
-
155
- ```ts
156
- import {
157
- createContinuousPlayer,
158
- startContinuousPlayer,
159
- updateContinuousPlayer,
160
- stopContinuousPlayer,
161
- destroyContinuousPlayer,
162
- } from 'react-native-tickle';
163
-
164
- const PLAYER_ID = 'my-player';
165
-
166
- createContinuousPlayer(PLAYER_ID, 1.0, 0.5);
167
- startContinuousPlayer(PLAYER_ID);
168
- updateContinuousPlayer(PLAYER_ID, 0.8, 0.1);
169
- stopContinuousPlayer(PLAYER_ID);
170
- destroyContinuousPlayer(PLAYER_ID);
171
- ```
172
-
173
- ### Opt out of the provider (manual engine control)
174
-
175
- If you don’t want the provider behavior:
176
-
177
- ```ts
178
- import { initializeEngine, destroyEngine } from 'react-native-tickle';
179
-
180
- initializeEngine();
181
- // ...
182
- destroyEngine();
183
- ```
184
-
185
- ### Stop everything (recommended in screen cleanups)
172
+ ### Stop everything
186
173
 
187
- Call `stopAllHaptics()` in your cleanup functions to terminate any ongoing continuous haptics. This prevents haptics from bleeding through to the next screen when navigating.
174
+ If users can navigate away from a screen while haptics are still playing, call `stopAllHaptics()` in your cleanup to stop them.
188
175
 
189
176
  ```ts
190
- import { stopAllHaptics } from 'react-native-tickle';
177
+ import { stopAllHaptics } from '@renegades/react-native-tickle';
191
178
  import { useEffect } from 'react';
192
179
 
193
180
  export function SomeScreen() {
@@ -200,10 +187,8 @@ export function SomeScreen() {
200
187
 
201
188
  Disable haptics globally for users who prefer no haptic feedback. The setting is **persisted** across app restarts. When disabled, all haptic calls become no-ops.
202
189
 
203
- **Using the hook (recommended):**
204
-
205
190
  ```tsx
206
- import { useHapticsEnabled } from 'react-native-tickle';
191
+ import { useHapticsEnabled } from '@renegades/react-native-tickle';
207
192
 
208
193
  function SettingsScreen() {
209
194
  const [hapticsEnabled, setHapticsEnabled] = useHapticsEnabled();
@@ -212,26 +197,16 @@ function SettingsScreen() {
212
197
  }
213
198
  ```
214
199
 
215
- **Manual control:**
216
-
217
- ```ts
218
- import { setHapticsEnabled, getHapticsEnabled } from 'react-native-tickle';
219
-
220
- const isEnabled = getHapticsEnabled(); // true by default
221
- setHapticsEnabled(false); // Disable all haptics
222
- setHapticsEnabled(true); // Re-enable haptics
223
- ```
224
-
225
200
  ### System haptics (predefined OS-level feedback)
226
201
 
227
- While the main purpose of this package is to support AHAP-style patterns (transient + continuous haptics with curves), system haptics are also available for completeness. These are simple, predefined OS-level feedback types that don't require pattern definitions. They can be called from the UI thread and don't require the haptic engine to be initialized.
202
+ While the main purpose of this package is to support AHAP-style patterns (transient + continuous haptics with curves), system haptics are also available for completeness. These are simple, predefined OS-level feedback types that don't require pattern definitions. These methods are also UI-thread friendly.
228
203
 
229
204
  ```ts
230
205
  import {
231
206
  triggerImpact,
232
207
  triggerNotification,
233
208
  triggerSelection,
234
- } from 'react-native-tickle';
209
+ } from '@renegades/react-native-tickle';
235
210
 
236
211
  // Impact feedback - simulates a physical collision
237
212
  triggerImpact('light'); // 'light' | 'medium' | 'heavy' | 'soft' | 'rigid'
@@ -243,6 +218,14 @@ triggerNotification('success'); // 'success' | 'warning' | 'error'
243
218
  triggerSelection();
244
219
  ```
245
220
 
221
+ ### Advanced control
222
+
223
+ For fine-grained control over the haptic API, you can opt out of the managed hooks and call the underlying functions directly:
224
+
225
+ - **Engine lifecycle**: `initializeEngine()` / `destroyEngine()` instead of `HapticProvider`
226
+ - **Enable/disable toggle**: `setHapticsEnabled()` / `getHapticsEnabled()` instead of `useHapticsEnabled()`
227
+ - **Continuous player**: `createContinuousPlayer()` / `startContinuousPlayer()` / `updateContinuousPlayer()` / `stopContinuousPlayer()` / `destroyContinuousPlayer()` instead of `useContinuousPlayer()`
228
+
246
229
  ## API
247
230
 
248
231
  | Function | Purpose |
@@ -341,6 +324,10 @@ Each call creates an isolated pattern/player — curves from one won't affect ev
341
324
 
342
325
  > **Note:** The library automatically resets control values to `1.0` at the end of each continuous event, so transients **after** a continuous event finishes are not affected. This limitation only applies to transients **during** a continuous event with active curves.
343
326
 
327
+ ## Acknowledgment
328
+
329
+ Shoutout to [Jai](https://github.com/jaic231) for kicking off the Swift implementation 🙌
330
+
344
331
  ## Contributing
345
332
 
346
333
  - [Development workflow](CONTRIBUTING.md#development-workflow)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@renegades/react-native-tickle",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Build and fine-tune haptic patterns with real-time previews",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -34,9 +34,8 @@
34
34
  "!**/.*"
35
35
  ],
36
36
  "scripts": {
37
- "postinstall": "bash scripts/postinstall.sh",
38
37
  "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
39
- "prepare": "bob build",
38
+ "prepare": "bun --yes nitrogen && bob build",
40
39
  "nitrogen": "nitrogen",
41
40
  "typecheck": "tsc",
42
41
  "lint": "eslint \"**/*.{js,ts,tsx}\"",
@@ -99,7 +98,7 @@
99
98
  "peerDependencies": {
100
99
  "react": "*",
101
100
  "react-native": "*",
102
- "react-native-nitro-modules": "^0.32.0"
101
+ "react-native-nitro-modules": "*"
103
102
  },
104
103
  "packageManager": "bun@1.1.38",
105
104
  "react-native-builder-bob": {