noboarding 1.0.3-beta → 1.0.7
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/ANIMATIONS.md +446 -0
- package/README.md +356 -323
- package/lib/OnboardingFlow.js +21 -4
- package/lib/animationUtils.d.ts +19 -0
- package/lib/animationUtils.js +252 -0
- package/lib/components/ElementRenderer.d.ts +5 -0
- package/lib/components/ElementRenderer.js +231 -40
- package/lib/types.d.ts +46 -0
- package/package.json +4 -2
- package/src/OnboardingFlow.tsx +19 -0
- package/src/animationUtils.ts +292 -0
- package/src/components/ElementRenderer.tsx +287 -22
- package/src/types.ts +51 -0
package/ANIMATIONS.md
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# 🎬 Noboarding Animations Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Noboarding supports **fully OTA-updateable animations** for your onboarding screens. Update animation styles, timing, and effects instantly without App Store review.
|
|
6
|
+
|
|
7
|
+
All animations are configured via JSON and use React Native's built-in `Animated` API for optimal performance.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## ✨ Animation Types
|
|
12
|
+
|
|
13
|
+
### 1. Entrance Animations
|
|
14
|
+
|
|
15
|
+
Elements can animate in when the screen loads.
|
|
16
|
+
|
|
17
|
+
**Supported Types:**
|
|
18
|
+
- `fadeIn` - Fade from transparent to opaque
|
|
19
|
+
- `slideUp` - Slide up from below
|
|
20
|
+
- `slideDown` - Slide down from above
|
|
21
|
+
- `slideLeft` - Slide in from right
|
|
22
|
+
- `slideRight` - Slide in from left
|
|
23
|
+
- `scaleIn` - Scale up from small
|
|
24
|
+
- `none` - No animation (instant appearance)
|
|
25
|
+
|
|
26
|
+
**Configuration:**
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"type": "vstack",
|
|
31
|
+
"entrance": {
|
|
32
|
+
"type": "fadeIn",
|
|
33
|
+
"duration": 400,
|
|
34
|
+
"delay": 200,
|
|
35
|
+
"stagger": 50,
|
|
36
|
+
"easing": "ease-in-out"
|
|
37
|
+
},
|
|
38
|
+
"children": [...]
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Parameters:**
|
|
43
|
+
- `type`: Animation style (required)
|
|
44
|
+
- `duration`: Animation duration in milliseconds (default: 400)
|
|
45
|
+
- `delay`: Delay before animation starts in milliseconds (default: 0)
|
|
46
|
+
- `stagger`: For containers - delay between each child (default: 0)
|
|
47
|
+
- `easing`: Timing function: `linear`, `ease-in`, `ease-out`, `ease-in-out`, `spring`
|
|
48
|
+
|
|
49
|
+
**Examples:**
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
// Fade in welcome text
|
|
53
|
+
{
|
|
54
|
+
"type": "text",
|
|
55
|
+
"props": { "text": "Welcome!" },
|
|
56
|
+
"entrance": {
|
|
57
|
+
"type": "fadeIn",
|
|
58
|
+
"duration": 600
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Slide up with spring effect
|
|
63
|
+
{
|
|
64
|
+
"type": "vstack",
|
|
65
|
+
"entrance": {
|
|
66
|
+
"type": "slideUp",
|
|
67
|
+
"duration": 500,
|
|
68
|
+
"easing": "spring"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Staggered list items
|
|
73
|
+
{
|
|
74
|
+
"type": "vstack",
|
|
75
|
+
"entrance": {
|
|
76
|
+
"type": "fadeIn",
|
|
77
|
+
"stagger": 100
|
|
78
|
+
},
|
|
79
|
+
"children": [
|
|
80
|
+
{ "type": "text", "props": { "text": "Item 1" } },
|
|
81
|
+
{ "type": "text", "props": { "text": "Item 2" } },
|
|
82
|
+
{ "type": "text", "props": { "text": "Item 3" } }
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### 2. Interactive Animations
|
|
90
|
+
|
|
91
|
+
Elements respond to user interaction.
|
|
92
|
+
|
|
93
|
+
**Supported Types:**
|
|
94
|
+
- `scale` - Shrink slightly on tap
|
|
95
|
+
- `pulse` - Grow and shrink rhythmically
|
|
96
|
+
- `shake` - Shake horizontally
|
|
97
|
+
- `bounce` - Bounce vertically
|
|
98
|
+
- `none` - No animation
|
|
99
|
+
|
|
100
|
+
**Configuration:**
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"type": "vstack",
|
|
105
|
+
"interactive": {
|
|
106
|
+
"type": "scale",
|
|
107
|
+
"trigger": "tap",
|
|
108
|
+
"duration": 200,
|
|
109
|
+
"intensity": 0.95,
|
|
110
|
+
"haptic": true,
|
|
111
|
+
"hapticType": "light"
|
|
112
|
+
},
|
|
113
|
+
"action": { "type": "navigate", "destination": "next-screen" }
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Parameters:**
|
|
118
|
+
- `type`: Animation style (required)
|
|
119
|
+
- `trigger`: When to animate - `tap` or `load` (default: `tap`)
|
|
120
|
+
- `duration`: Animation duration in milliseconds (default: 200)
|
|
121
|
+
- `intensity`: Effect strength - 0-1 for scale, pixels for shake/bounce (default: 0.95 for scale, 10 for shake)
|
|
122
|
+
- `repeat`: Loop continuously - only for `pulse` (default: false)
|
|
123
|
+
- `haptic`: Trigger haptic feedback (default: false)
|
|
124
|
+
- `hapticType`: Haptic style - `light`, `medium`, `heavy`, `success`, `warning`, `error`
|
|
125
|
+
|
|
126
|
+
**Examples:**
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
// Button with scale-down on tap
|
|
130
|
+
{
|
|
131
|
+
"type": "vstack",
|
|
132
|
+
"props": {},
|
|
133
|
+
"interactive": {
|
|
134
|
+
"type": "scale",
|
|
135
|
+
"trigger": "tap",
|
|
136
|
+
"intensity": 0.92,
|
|
137
|
+
"haptic": true,
|
|
138
|
+
"hapticType": "medium"
|
|
139
|
+
},
|
|
140
|
+
"action": { "type": "navigate", "destination": "next" }
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Continuous pulsing badge
|
|
144
|
+
{
|
|
145
|
+
"type": "vstack",
|
|
146
|
+
"interactive": {
|
|
147
|
+
"type": "pulse",
|
|
148
|
+
"trigger": "load",
|
|
149
|
+
"repeat": true,
|
|
150
|
+
"duration": 1000
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Shake animation for errors
|
|
155
|
+
{
|
|
156
|
+
"type": "text",
|
|
157
|
+
"props": { "text": "Invalid input" },
|
|
158
|
+
"interactive": {
|
|
159
|
+
"type": "shake",
|
|
160
|
+
"trigger": "load",
|
|
161
|
+
"intensity": 8,
|
|
162
|
+
"haptic": true,
|
|
163
|
+
"hapticType": "error"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### 3. Typewriter Text Animation
|
|
171
|
+
|
|
172
|
+
Text appears character-by-character with optional cursor and haptic feedback.
|
|
173
|
+
|
|
174
|
+
**Configuration:**
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"type": "text",
|
|
179
|
+
"props": {
|
|
180
|
+
"text": "Welcome to BodyMaxx! Your #1 AI assistant to losing body fat sustainably."
|
|
181
|
+
},
|
|
182
|
+
"textAnimation": {
|
|
183
|
+
"type": "typewriter",
|
|
184
|
+
"speed": 25,
|
|
185
|
+
"delay": 500,
|
|
186
|
+
"cursor": true,
|
|
187
|
+
"haptic": {
|
|
188
|
+
"enabled": true,
|
|
189
|
+
"type": "light",
|
|
190
|
+
"frequency": "every-2"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Parameters:**
|
|
197
|
+
- `type`: Must be `typewriter` or `none`
|
|
198
|
+
- `speed`: Characters per second (default: 20)
|
|
199
|
+
- `delay`: Delay before typing starts in milliseconds (default: 0)
|
|
200
|
+
- `cursor`: Show blinking cursor while typing (default: false)
|
|
201
|
+
- `haptic.enabled`: Trigger haptic feedback (default: false)
|
|
202
|
+
- `haptic.type`: Haptic style - `light`, `medium`, `heavy`
|
|
203
|
+
- `haptic.frequency`: How often to vibrate - `every`, `every-2`, `every-3`, `every-5`
|
|
204
|
+
|
|
205
|
+
**Examples:**
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
// Fast typewriter with cursor
|
|
209
|
+
{
|
|
210
|
+
"type": "text",
|
|
211
|
+
"props": { "text": "Get started now!" },
|
|
212
|
+
"textAnimation": {
|
|
213
|
+
"type": "typewriter",
|
|
214
|
+
"speed": 30,
|
|
215
|
+
"cursor": true
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Slow dramatic reveal with haptics
|
|
220
|
+
{
|
|
221
|
+
"type": "text",
|
|
222
|
+
"props": { "text": "You've completed your journey" },
|
|
223
|
+
"textAnimation": {
|
|
224
|
+
"type": "typewriter",
|
|
225
|
+
"speed": 15,
|
|
226
|
+
"delay": 1000,
|
|
227
|
+
"haptic": {
|
|
228
|
+
"enabled": true,
|
|
229
|
+
"type": "light",
|
|
230
|
+
"frequency": "every-3"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 🎯 Best Practices
|
|
239
|
+
|
|
240
|
+
### Performance
|
|
241
|
+
|
|
242
|
+
1. **Use stagger sparingly** - Large stagger delays on long lists can feel slow
|
|
243
|
+
2. **Limit haptic frequency** - Use `every-2` or `every-3` for long text to avoid battery drain
|
|
244
|
+
3. **Disable typewriter for long text** - Typewriter works best for short, impactful messages (< 50 chars)
|
|
245
|
+
|
|
246
|
+
### UX Guidelines
|
|
247
|
+
|
|
248
|
+
1. **Entrance animations**
|
|
249
|
+
- Keep duration under 500ms for most elements
|
|
250
|
+
- Use `fadeIn` for subtle, professional feel
|
|
251
|
+
- Use `slideUp` for content reveals
|
|
252
|
+
- Use `spring` easing for playful, bouncy effects
|
|
253
|
+
|
|
254
|
+
2. **Interactive animations**
|
|
255
|
+
- Always use `scale` on tap for buttons - it provides visual feedback
|
|
256
|
+
- Use `pulse` for attention-grabbing elements (badges, notifications)
|
|
257
|
+
- Reserve `shake` for errors and warnings
|
|
258
|
+
- Keep intensity subtle (0.92-0.95 for scale)
|
|
259
|
+
|
|
260
|
+
3. **Typewriter animations**
|
|
261
|
+
- Best for welcome messages, taglines, success messages
|
|
262
|
+
- Speed 20-30 chars/sec feels natural
|
|
263
|
+
- Use cursor for chat-like experiences
|
|
264
|
+
- Haptic feedback adds tactile dimension but drains battery
|
|
265
|
+
|
|
266
|
+
4. **Combine animations thoughtfully**
|
|
267
|
+
- ✅ Entrance + Interactive (fade in, then scale on tap)
|
|
268
|
+
- ✅ Typewriter + Haptic (chatbot-style messages)
|
|
269
|
+
- ❌ Multiple entrance animations on same screen (overwhelming)
|
|
270
|
+
- ❌ Pulse + Typewriter (too many moving parts)
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## 🚀 OTA Update Examples
|
|
275
|
+
|
|
276
|
+
### Before
|
|
277
|
+
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"type": "text",
|
|
281
|
+
"props": { "text": "Welcome to our app!" }
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### After (No App Update Required!)
|
|
286
|
+
|
|
287
|
+
```json
|
|
288
|
+
{
|
|
289
|
+
"type": "text",
|
|
290
|
+
"props": { "text": "Welcome to our app!" },
|
|
291
|
+
"entrance": {
|
|
292
|
+
"type": "fadeIn",
|
|
293
|
+
"duration": 600
|
|
294
|
+
},
|
|
295
|
+
"textAnimation": {
|
|
296
|
+
"type": "typewriter",
|
|
297
|
+
"speed": 25,
|
|
298
|
+
"cursor": true
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Result:** Your welcome text now fades in and types out character-by-character, all without submitting to the App Store!
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## 📱 Haptic Feedback
|
|
308
|
+
|
|
309
|
+
Requires `expo-haptics` to be installed in your app:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
npx expo install expo-haptics
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
If not installed, haptic animations will silently skip without errors.
|
|
316
|
+
|
|
317
|
+
**Haptic Types:**
|
|
318
|
+
- `light` - Subtle tap (best for typewriter, frequent events)
|
|
319
|
+
- `medium` - Noticeable feedback (buttons, selections)
|
|
320
|
+
- `heavy` - Strong impact (important actions)
|
|
321
|
+
- `success` - Confirmation (completed actions)
|
|
322
|
+
- `warning` - Attention (alerts)
|
|
323
|
+
- `error` - Problem notification (validation errors)
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## 🎨 Animation Recipes
|
|
328
|
+
|
|
329
|
+
### Welcome Screen
|
|
330
|
+
|
|
331
|
+
```json
|
|
332
|
+
{
|
|
333
|
+
"type": "vstack",
|
|
334
|
+
"entrance": {
|
|
335
|
+
"type": "fadeIn",
|
|
336
|
+
"duration": 800
|
|
337
|
+
},
|
|
338
|
+
"children": [
|
|
339
|
+
{
|
|
340
|
+
"type": "text",
|
|
341
|
+
"props": { "text": "Welcome!" },
|
|
342
|
+
"textAnimation": {
|
|
343
|
+
"type": "typewriter",
|
|
344
|
+
"speed": 20,
|
|
345
|
+
"delay": 800,
|
|
346
|
+
"haptic": {
|
|
347
|
+
"enabled": true,
|
|
348
|
+
"type": "light",
|
|
349
|
+
"frequency": "every-2"
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
]
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Card List with Stagger
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"type": "vstack",
|
|
362
|
+
"entrance": {
|
|
363
|
+
"type": "slideUp",
|
|
364
|
+
"stagger": 80,
|
|
365
|
+
"easing": "ease-out"
|
|
366
|
+
},
|
|
367
|
+
"children": [
|
|
368
|
+
{ "type": "vstack", "props": {} },
|
|
369
|
+
{ "type": "vstack", "props": {} },
|
|
370
|
+
{ "type": "vstack", "props": {} }
|
|
371
|
+
]
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Interactive Button
|
|
376
|
+
|
|
377
|
+
```json
|
|
378
|
+
{
|
|
379
|
+
"type": "vstack",
|
|
380
|
+
"entrance": {
|
|
381
|
+
"type": "scaleIn",
|
|
382
|
+
"duration": 400,
|
|
383
|
+
"delay": 600
|
|
384
|
+
},
|
|
385
|
+
"interactive": {
|
|
386
|
+
"type": "scale",
|
|
387
|
+
"trigger": "tap",
|
|
388
|
+
"intensity": 0.94,
|
|
389
|
+
"haptic": true,
|
|
390
|
+
"hapticType": "medium"
|
|
391
|
+
},
|
|
392
|
+
"action": { "type": "navigate", "destination": "next" }
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Error Message
|
|
397
|
+
|
|
398
|
+
```json
|
|
399
|
+
{
|
|
400
|
+
"type": "text",
|
|
401
|
+
"props": { "text": "Invalid email address" },
|
|
402
|
+
"entrance": {
|
|
403
|
+
"type": "fadeIn",
|
|
404
|
+
"duration": 200
|
|
405
|
+
},
|
|
406
|
+
"interactive": {
|
|
407
|
+
"type": "shake",
|
|
408
|
+
"trigger": "load",
|
|
409
|
+
"intensity": 10,
|
|
410
|
+
"haptic": true,
|
|
411
|
+
"hapticType": "error"
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## 🔧 Technical Details
|
|
419
|
+
|
|
420
|
+
### Implementation
|
|
421
|
+
|
|
422
|
+
- Uses React Native's `Animated` API (no external libraries required)
|
|
423
|
+
- All animations run on the native thread (60 FPS performance)
|
|
424
|
+
- Animation configurations stored in JSON (fully OTA updateable)
|
|
425
|
+
- Haptic feedback is optional (gracefully degrades if unavailable)
|
|
426
|
+
|
|
427
|
+
### Compatibility
|
|
428
|
+
|
|
429
|
+
- ✅ iOS 11+
|
|
430
|
+
- ✅ Android 5.0+
|
|
431
|
+
- ✅ Works with React Native Web (animations disabled for preview)
|
|
432
|
+
|
|
433
|
+
### Bundle Size
|
|
434
|
+
|
|
435
|
+
Zero impact - animations use built-in React Native APIs only!
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## 🎓 Next Steps
|
|
440
|
+
|
|
441
|
+
1. **Try it out** - Add entrance animations to your first screen
|
|
442
|
+
2. **Experiment** - Test different timing and easing functions
|
|
443
|
+
3. **A/B test** - Create variants with and without animations to measure engagement
|
|
444
|
+
4. **Update OTA** - Push animation changes instantly to all users
|
|
445
|
+
|
|
446
|
+
**Questions?** Check the main README or contact support.
|