@wix/interact 1.92.0 → 2.0.0-rc.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 (179) hide show
  1. package/dist/cjs/index.js +2 -23
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/react.js +15 -0
  4. package/dist/cjs/react.js.map +1 -0
  5. package/dist/cjs/web.js +2 -0
  6. package/dist/cjs/web.js.map +1 -0
  7. package/dist/es/index.js +8 -0
  8. package/dist/es/index.js.map +1 -0
  9. package/dist/es/react.js +650 -0
  10. package/dist/es/react.js.map +1 -0
  11. package/dist/es/web.js +56 -0
  12. package/dist/es/web.js.map +1 -0
  13. package/dist/index-C8QxOkui.mjs +7940 -0
  14. package/dist/index-C8QxOkui.mjs.map +1 -0
  15. package/dist/index-DEPRHaUt.js +18 -0
  16. package/dist/index-DEPRHaUt.js.map +1 -0
  17. package/dist/tsconfig.build.tsbuildinfo +1 -0
  18. package/dist/types/core/Interact.d.ts +17 -7
  19. package/dist/types/core/Interact.d.ts.map +1 -0
  20. package/dist/types/core/InteractionController.d.ts +19 -0
  21. package/dist/types/core/InteractionController.d.ts.map +1 -0
  22. package/dist/types/core/add.d.ts +4 -3
  23. package/dist/types/core/add.d.ts.map +1 -0
  24. package/dist/types/core/css.d.ts +3 -0
  25. package/dist/types/core/css.d.ts.map +1 -0
  26. package/dist/types/core/remove.d.ts +3 -1
  27. package/dist/types/core/remove.d.ts.map +1 -0
  28. package/dist/types/core/utilities.d.ts +1 -0
  29. package/dist/types/core/utilities.d.ts.map +1 -0
  30. package/dist/types/dom/api.d.ts +3 -0
  31. package/dist/types/dom/api.d.ts.map +1 -0
  32. package/dist/types/handlers/animationEnd.d.ts +3 -2
  33. package/dist/types/handlers/animationEnd.d.ts.map +1 -0
  34. package/dist/types/handlers/click.d.ts +3 -2
  35. package/dist/types/handlers/click.d.ts.map +1 -0
  36. package/dist/types/handlers/hover.d.ts +3 -2
  37. package/dist/types/handlers/hover.d.ts.map +1 -0
  38. package/dist/types/handlers/index.d.ts +1 -0
  39. package/dist/types/handlers/index.d.ts.map +1 -0
  40. package/dist/types/handlers/pointerMove.d.ts +3 -2
  41. package/dist/types/handlers/pointerMove.d.ts.map +1 -0
  42. package/dist/types/handlers/utilities.d.ts +1 -0
  43. package/dist/types/handlers/utilities.d.ts.map +1 -0
  44. package/dist/types/handlers/viewEnter.d.ts +3 -2
  45. package/dist/types/handlers/viewEnter.d.ts.map +1 -0
  46. package/dist/types/handlers/viewProgress.d.ts +4 -3
  47. package/dist/types/handlers/viewProgress.d.ts.map +1 -0
  48. package/dist/types/index.d.ts +3 -2
  49. package/dist/types/index.d.ts.map +1 -0
  50. package/dist/types/react/Interaction.d.ts +10 -0
  51. package/dist/types/react/Interaction.d.ts.map +1 -0
  52. package/dist/types/react/index.d.ts +8 -0
  53. package/dist/types/react/index.d.ts.map +1 -0
  54. package/dist/types/react/interactRef.d.ts +3 -0
  55. package/dist/types/react/interactRef.d.ts.map +1 -0
  56. package/dist/types/types.d.ts +25 -10
  57. package/dist/types/types.d.ts.map +1 -0
  58. package/dist/types/utils.d.ts +4 -2
  59. package/dist/types/utils.d.ts.map +1 -0
  60. package/dist/types/{InteractElement.d.ts → web/InteractElement.d.ts} +115 -77
  61. package/dist/types/web/InteractElement.d.ts.map +1 -0
  62. package/dist/types/web/defineInteractElement.d.ts +2 -0
  63. package/dist/types/web/defineInteractElement.d.ts.map +1 -0
  64. package/dist/types/web/index.d.ts +6 -0
  65. package/dist/types/web/index.d.ts.map +1 -0
  66. package/docs/README.md +211 -0
  67. package/docs/advanced/README.md +164 -0
  68. package/docs/api/README.md +157 -0
  69. package/docs/api/element-selection.md +607 -0
  70. package/docs/api/functions.md +638 -0
  71. package/docs/api/interact-class.md +663 -0
  72. package/docs/api/interact-element.md +565 -0
  73. package/docs/api/interaction-controller.md +450 -0
  74. package/docs/api/types.md +957 -0
  75. package/docs/examples/README.md +212 -0
  76. package/docs/examples/click-interactions.md +977 -0
  77. package/docs/examples/entrance-animations.md +935 -0
  78. package/docs/examples/hover-effects.md +930 -0
  79. package/docs/examples/list-patterns.md +737 -0
  80. package/docs/guides/README.md +49 -0
  81. package/docs/guides/conditions-and-media-queries.md +1068 -0
  82. package/docs/guides/configuration-structure.md +726 -0
  83. package/docs/guides/custom-elements.md +327 -0
  84. package/docs/guides/effects-and-animations.md +634 -0
  85. package/docs/guides/getting-started.md +379 -0
  86. package/docs/guides/lists-and-dynamic-content.md +713 -0
  87. package/docs/guides/state-management.md +747 -0
  88. package/docs/guides/understanding-triggers.md +690 -0
  89. package/docs/integration/README.md +264 -0
  90. package/docs/integration/react.md +605 -0
  91. package/package.json +73 -56
  92. package/rules/Integration.md +255 -0
  93. package/rules/click-rules.md +533 -0
  94. package/rules/full-lean.md +346 -0
  95. package/rules/hover-rules.md +593 -0
  96. package/rules/pointermove-rules.md +1341 -0
  97. package/rules/scroll-list-rules.md +900 -0
  98. package/rules/viewenter-rules.md +1015 -0
  99. package/rules/viewprogress-rules.md +1044 -0
  100. package/dist/cjs/InteractElement.js +0 -162
  101. package/dist/cjs/InteractElement.js.map +0 -1
  102. package/dist/cjs/__tests__/interact.spec.js +0 -1930
  103. package/dist/cjs/__tests__/interact.spec.js.map +0 -1
  104. package/dist/cjs/__tests__/viewEnter.spec.js +0 -207
  105. package/dist/cjs/__tests__/viewEnter.spec.js.map +0 -1
  106. package/dist/cjs/core/Interact.js +0 -257
  107. package/dist/cjs/core/Interact.js.map +0 -1
  108. package/dist/cjs/core/add.js +0 -246
  109. package/dist/cjs/core/add.js.map +0 -1
  110. package/dist/cjs/core/remove.js +0 -35
  111. package/dist/cjs/core/remove.js.map +0 -1
  112. package/dist/cjs/core/utilities.js +0 -16
  113. package/dist/cjs/core/utilities.js.map +0 -1
  114. package/dist/cjs/external-types.d.js +0 -2
  115. package/dist/cjs/external-types.d.js.map +0 -1
  116. package/dist/cjs/handlers/animationEnd.js +0 -33
  117. package/dist/cjs/handlers/animationEnd.js.map +0 -1
  118. package/dist/cjs/handlers/click.js +0 -116
  119. package/dist/cjs/handlers/click.js.map +0 -1
  120. package/dist/cjs/handlers/hover.js +0 -141
  121. package/dist/cjs/handlers/hover.js.map +0 -1
  122. package/dist/cjs/handlers/index.js +0 -32
  123. package/dist/cjs/handlers/index.js.map +0 -1
  124. package/dist/cjs/handlers/pointerMove.js +0 -49
  125. package/dist/cjs/handlers/pointerMove.js.map +0 -1
  126. package/dist/cjs/handlers/utilities.js +0 -49
  127. package/dist/cjs/handlers/utilities.js.map +0 -1
  128. package/dist/cjs/handlers/viewEnter.js +0 -127
  129. package/dist/cjs/handlers/viewEnter.js.map +0 -1
  130. package/dist/cjs/handlers/viewProgress.js +0 -65
  131. package/dist/cjs/handlers/viewProgress.js.map +0 -1
  132. package/dist/cjs/test-types.d.js +0 -2
  133. package/dist/cjs/test-types.d.js.map +0 -1
  134. package/dist/cjs/types.js +0 -2
  135. package/dist/cjs/types.js.map +0 -1
  136. package/dist/cjs/utils.js +0 -68
  137. package/dist/cjs/utils.js.map +0 -1
  138. package/dist/esm/InteractElement.js +0 -156
  139. package/dist/esm/InteractElement.js.map +0 -1
  140. package/dist/esm/__tests__/interact.spec.js +0 -1937
  141. package/dist/esm/__tests__/interact.spec.js.map +0 -1
  142. package/dist/esm/__tests__/viewEnter.spec.js +0 -210
  143. package/dist/esm/__tests__/viewEnter.spec.js.map +0 -1
  144. package/dist/esm/core/Interact.js +0 -251
  145. package/dist/esm/core/Interact.js.map +0 -1
  146. package/dist/esm/core/add.js +0 -241
  147. package/dist/esm/core/add.js.map +0 -1
  148. package/dist/esm/core/remove.js +0 -30
  149. package/dist/esm/core/remove.js.map +0 -1
  150. package/dist/esm/core/utilities.js +0 -14
  151. package/dist/esm/core/utilities.js.map +0 -1
  152. package/dist/esm/external-types.d.js +0 -2
  153. package/dist/esm/external-types.d.js.map +0 -1
  154. package/dist/esm/handlers/animationEnd.js +0 -29
  155. package/dist/esm/handlers/animationEnd.js.map +0 -1
  156. package/dist/esm/handlers/click.js +0 -116
  157. package/dist/esm/handlers/click.js.map +0 -1
  158. package/dist/esm/handlers/hover.js +0 -141
  159. package/dist/esm/handlers/hover.js.map +0 -1
  160. package/dist/esm/handlers/index.js +0 -27
  161. package/dist/esm/handlers/index.js.map +0 -1
  162. package/dist/esm/handlers/pointerMove.js +0 -48
  163. package/dist/esm/handlers/pointerMove.js.map +0 -1
  164. package/dist/esm/handlers/utilities.js +0 -43
  165. package/dist/esm/handlers/utilities.js.map +0 -1
  166. package/dist/esm/handlers/viewEnter.js +0 -129
  167. package/dist/esm/handlers/viewEnter.js.map +0 -1
  168. package/dist/esm/handlers/viewProgress.js +0 -61
  169. package/dist/esm/handlers/viewProgress.js.map +0 -1
  170. package/dist/esm/index.js +0 -5
  171. package/dist/esm/index.js.map +0 -1
  172. package/dist/esm/test-types.d.js +0 -2
  173. package/dist/esm/test-types.d.js.map +0 -1
  174. package/dist/esm/types.js +0 -2
  175. package/dist/esm/types.js.map +0 -1
  176. package/dist/esm/utils.js +0 -63
  177. package/dist/esm/utils.js.map +0 -1
  178. package/dist/types/__tests__/interact.spec.d.ts +0 -1
  179. package/dist/types/__tests__/viewEnter.spec.d.ts +0 -0
@@ -0,0 +1,1044 @@
1
+ # ViewProgress Trigger Rules for @wix/interact
2
+
3
+ These rules help generate scroll-driven interactions using the `@wix/interact` library. ViewProgress triggers create scroll-based animations that update continuously as elements move through the viewport, perfect for parallax effects, progress indicators, and scroll-responsive content.
4
+
5
+ ## Rule 1: Range-Based Parallax/Continuous Animation Control with Named Effects
6
+
7
+ **Use Case**: Continuous scroll-driven animations using pre-built named effects that respond to scroll position (e.g., parallax backgrounds, floating elements, scroll-responsive decorations)
8
+
9
+ **When to Apply**:
10
+ - For smooth parallax background movements
11
+ - When creating scroll-responsive floating elements
12
+ - For continuous scroll-driven decorative animations
13
+ - When using pre-built motion effects for scroll interactions
14
+
15
+ **Pattern**:
16
+ ```typescript
17
+ {
18
+ key: '[SOURCE_SELECTOR]',
19
+ trigger: 'viewProgress',
20
+ effects: [
21
+ {
22
+ key: '[TARGET_SELECTOR]',
23
+ namedEffect: {
24
+ type: '[NAMED_EFFECT]',
25
+ },
26
+ rangeStart: { name: '[RANGE_NAME]', offset: { type: 'percentage', value: [START_PERCENTAGE] } },
27
+ rangeEnd: { name: '[RANGE_NAME]', offset: { type: 'percentage', value: [END_PERCENTAGE] } },
28
+ easing: '[EASING_FUNCTION]',
29
+ effectId: '[UNIQUE_EFFECT_ID]'
30
+ }
31
+ ]
32
+ }
33
+ ```
34
+
35
+ **Variables**:
36
+ - `[SOURCE_SELECTOR]`: Unique identifier for element that tracks scroll progress
37
+ - `[TARGET_SELECTOR]`: Unique identifier for element to animate (can be same as source or different)
38
+ - `[NAMED_EFFECT]`: Pre-built scroll effect name from @wix/motion (e.g., 'ParallaxScroll', 'MoveScroll', 'FadeScroll', 'RevealScroll', 'GrowScroll', 'SlideScroll', 'SpinScroll', 'PanScroll', 'BlurScroll', 'ArcScroll', 'FlipScroll', 'Spin3dScroll', 'TiltScroll', 'TurnScroll', 'ShapeScroll', 'ShuttersScroll', 'ShrinkScroll', 'SkewPanScroll', 'StretchScroll')
39
+ - `[RANGE_NAME]`: 'cover', 'contain', 'entry', 'exit', 'entry-crossing', or 'exit-crossing'
40
+ - `[START_PERCENTAGE]`: Start point as percentage (0-100)
41
+ - `[END_PERCENTAGE]`: End point as percentage (0-100)
42
+ - `[EASING_FUNCTION]`: Timing function (typically 'linear' for smooth scroll effects)
43
+ - `[UNIQUE_EFFECT_ID]`: Optional unique identifier
44
+
45
+ **Example - Background Parallax**:
46
+ ```typescript
47
+ {
48
+ key: 'hero-section',
49
+ trigger: 'viewProgress',
50
+ effects: [
51
+ {
52
+ key: 'hero-background',
53
+ namedEffect: {
54
+ type: 'ParallaxScroll'
55
+ },
56
+ rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
57
+ rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
58
+ easing: 'linear'
59
+ }
60
+ ]
61
+ }
62
+ ```
63
+
64
+ **Example - Floating Element Scroll Response**:
65
+ ```typescript
66
+ {
67
+ key: 'content-section',
68
+ trigger: 'viewProgress',
69
+ effects: [
70
+ {
71
+ key: 'floating-decoration',
72
+ namedEffect: {
73
+ type: 'MoveScroll',
74
+ angle: 45 // 45-degree angle movement
75
+ },
76
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
77
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 100 } },
78
+ easing: 'linear',
79
+ effectId: 'decoration-float'
80
+ }
81
+ ]
82
+ }
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Rule 2: Range-Based Entry Animation Control with Named Effects
88
+
89
+ **Use Case**: Scroll-driven entrance animations using named effects that start when elements enter the viewport (e.g., content reveals, scroll-driven introductions)
90
+
91
+ **When to Apply**:
92
+ - For scroll-controlled entrance animations
93
+ - When elements should reveal gradually as they come into view
94
+ - For progressive content disclosure based on scroll
95
+ - When using pre-built entrance effects with scroll control
96
+
97
+ **Pattern**:
98
+ ```typescript
99
+ {
100
+ key: '[SOURCE_SELECTOR]',
101
+ trigger: 'viewProgress',
102
+ effects: [
103
+ {
104
+ key: '[TARGET_SELECTOR]',
105
+ namedEffect: {
106
+ type: '[ENTRANCE_EFFECT]'
107
+ },
108
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: [ENTRY_START] } },
109
+ rangeEnd: { name: 'entry', offset: { type: 'percentage', value: [ENTRY_END] } },
110
+ easing: '[EASING_FUNCTION]',
111
+ effectId: '[UNIQUE_EFFECT_ID]'
112
+ }
113
+ ]
114
+ }
115
+ ```
116
+
117
+ **Variables**:
118
+ - `[ENTRANCE_EFFECT]`: Named entrance effect from @wix/motion scroll animations (e.g., 'FadeScroll', 'SlideScroll', 'RevealScroll', 'ShapeScroll', 'GrowScroll', 'MoveScroll', 'BlurScroll')
119
+ - `[ENTRY_START]`: Entry animation start percentage (typically 0-30)
120
+ - `[ENTRY_END]`: Entry animation end percentage (typically 70-100)
121
+ - Other variables same as Rule 1
122
+
123
+ **Example - Content Reveal on Entry**:
124
+ ```typescript
125
+ {
126
+ key: 'content-block',
127
+ trigger: 'viewProgress',
128
+ effects: [
129
+ {
130
+ key: 'content-block',
131
+ namedEffect: {
132
+ type: 'RevealScroll',
133
+ direction: 'left'
134
+ },
135
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
136
+ rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 60 } },
137
+ easing: 'ease-out'
138
+ }
139
+ ]
140
+ }
141
+ ```
142
+
143
+ **Example - Progressive Image Reveal**:
144
+ ```typescript
145
+ {
146
+ key: 'image-container',
147
+ trigger: 'viewProgress',
148
+ effects: [
149
+ {
150
+ key: 'feature-image',
151
+ namedEffect: {
152
+ type: 'FadeScroll'
153
+ },
154
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: 20 } },
155
+ rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 80 } },
156
+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
157
+ effectId: 'image-reveal'
158
+ }
159
+ ]
160
+ }
161
+ ```
162
+
163
+ ---
164
+
165
+ ## Rule 3: Range-Based Exit Animation Control with Named Effects
166
+
167
+ **Use Case**: Scroll-driven exit animations using named effects that trigger when elements leave the viewport (e.g., content hiding, scroll-out effects, element dismissals)
168
+
169
+ **When to Apply**:
170
+ - For scroll-controlled exit animations
171
+ - When elements should hide gradually as they leave view
172
+ - For creating scroll-responsive content dismissals
173
+ - When using pre-built exit effects with scroll control
174
+
175
+ **Pattern**:
176
+ ```typescript
177
+ {
178
+ key: '[SOURCE_SELECTOR]',
179
+ trigger: 'viewProgress',
180
+ effects: [
181
+ {
182
+ key: '[TARGET_SELECTOR]',
183
+ namedEffect: {
184
+ type: '[EXIT_EFFECT]',
185
+ range: 'out'
186
+ },
187
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: [EXIT_START] } },
188
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: [EXIT_END] } },
189
+ easing: '[EASING_FUNCTION]',
190
+ effectId: '[UNIQUE_EFFECT_ID]'
191
+ }
192
+ ]
193
+ }
194
+ ```
195
+
196
+ **Variables**:
197
+ - `[EXIT_EFFECT]`: Named exit effect (e.g., 'FadeScroll', 'SlideScroll', 'GrowScroll', 'ShrinkScroll')
198
+ - `[EXIT_START]`: Exit animation start percentage (typically 0-30)
199
+ - `[EXIT_END]`: Exit animation end percentage (typically 70-100)
200
+ - Other variables same as Rule 1
201
+
202
+ **Example - Content Fade Out on Exit**:
203
+ ```typescript
204
+ {
205
+ key: 'hero-content',
206
+ trigger: 'viewProgress',
207
+ effects: [
208
+ {
209
+ key: 'hero-text',
210
+ namedEffect: {
211
+ type: 'FadeScroll',
212
+ range: 'out'
213
+ },
214
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: 0 } },
215
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 50 } },
216
+ easing: 'ease-in'
217
+ }
218
+ ]
219
+ }
220
+ ```
221
+
222
+ **Example - Navigation Hide on Scroll Out**:
223
+ ```typescript
224
+ {
225
+ key: 'main-content',
226
+ trigger: 'viewProgress',
227
+ effects: [
228
+ {
229
+ key: 'floating-nav',
230
+ namedEffect: {
231
+ type: 'SlideScroll',
232
+ direction: 'top',
233
+ range: 'out'
234
+ },
235
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: 20 } },
236
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 80 } },
237
+ easing: 'ease-in-out',
238
+ effectId: 'nav-hide'
239
+ }
240
+ ]
241
+ }
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Rule 4: Range-Based Parallax/Continuous Animation Control with Keyframe Effects
247
+
248
+ **Use Case**: Custom scroll-driven animations using keyframe effects for precise control over continuous scroll-responsive animations (e.g., custom parallax movements, complex scroll transformations, multi-property scroll effects)
249
+
250
+ **When to Apply**:
251
+ - For custom parallax effects not available in named effects
252
+ - When combining multiple CSS properties in scroll animations
253
+ - For precise control over scroll-driven transformations
254
+ - When creating unique scroll-responsive visual effects
255
+
256
+ **Pattern**:
257
+ ```typescript
258
+ {
259
+ key: '[SOURCE_SELECTOR]',
260
+ trigger: 'viewProgress',
261
+ effects: [
262
+ {
263
+ key: '[TARGET_SELECTOR]',
264
+ keyframeEffect: {
265
+ name: '[UNIQUE_KEYFRAME_EFFECT_NAME]',
266
+ keyframes: [
267
+ { [CSS_PROPERTY_1]: '[START_VALUE_1]', [CSS_PROPERTY_2]: '[START_VALUE_2]', [CSS_PROPERTY_3]: '[START_VALUE_3]' },
268
+ { [CSS_PROPERTY_1]: '[END_VALUE_1]', [CSS_PROPERTY_2]: '[END_VALUE_2]', [CSS_PROPERTY_3]: '[END_VALUE_3]' }
269
+ ]
270
+ },
271
+ rangeStart: { name: '[RANGE_NAME]', offset: { type: 'percentage', value: [START_PERCENTAGE] } },
272
+ rangeEnd: { name: '[RANGE_NAME]', offset: { type: 'percentage', value: [END_PERCENTAGE] } },
273
+ easing: '[EASING_FUNCTION]',
274
+ fill: 'both',
275
+ effectId: '[UNIQUE_EFFECT_ID]'
276
+ }
277
+ ]
278
+ }
279
+ ```
280
+
281
+ **Variables**:
282
+ - `[UNIQUE_KEYFRAME_EFFECT_NAME]`: unique name for the CSS keyframe effect (can equal `[UNIQUE_EFFECT_ID]` if provided)
283
+ - `[CSS_PROPERTY_N]`: CSS property names (e.g., 'transform', 'opacity', 'filter')
284
+ - `[START_VALUE_N]`: Starting value for the property
285
+ - `[END_VALUE_N]`: Ending value for the property
286
+ - Other variables same as Rule 1
287
+
288
+ **Example - Custom Background Parallax**:
289
+ ```typescript
290
+ {
291
+ key: 'parallax-section',
292
+ trigger: 'viewProgress',
293
+ effects: [
294
+ {
295
+ key: 'parallax-bg',
296
+ keyframeEffect: {
297
+ name: 'parallax-bg',
298
+ keyframes: [
299
+ { transform: 'translateY(0)', filter: 'brightness(1)', opacity: '0.9' },
300
+ { opacity: '1' },
301
+ { transform: 'translateY(-200px)', filter: 'brightness(0.8)', opacity: '0.9' }
302
+ ]
303
+ },
304
+ rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
305
+ rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
306
+ easing: 'linear',
307
+ fill: 'both'
308
+ }
309
+ ]
310
+ }
311
+ ```
312
+
313
+ **Example - Multi-Layer Scroll Effect**:
314
+ ```typescript
315
+ {
316
+ key: 'complex-section',
317
+ trigger: 'viewProgress',
318
+ effects: [
319
+ {
320
+ key: 'background-layer',
321
+ keyframeEffect: {
322
+ name: 'bg-scroll',
323
+ keyframes: [
324
+ { transform: 'scale(1.1) translateY(0)', filter: 'blur(0)' },
325
+ { transform: 'scale(1) translateY(-100px)', filter: 'blur(2px)' }
326
+ ]
327
+ },
328
+ rangeStart: { name: 'enter', offset: { type: 'percentage', value: 0 } },
329
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 100 } },
330
+ easing: 'linear',
331
+ fill: 'both',
332
+ effectId: 'bg-scroll'
333
+ }
334
+ ]
335
+ }
336
+ ```
337
+
338
+ ---
339
+
340
+ ## Rule 5: Range-Based Entry Animation Control with Keyframe Effects
341
+
342
+ **Use Case**: Custom scroll-driven entrance animations using keyframe effects for precise control over how elements appear as they enter the viewport (e.g., custom reveal effects, multi-property entrances, unique scroll-in animations)
343
+
344
+ **When to Apply**:
345
+ - For custom entrance effects not available in named effects
346
+ - When combining multiple properties in entrance animations
347
+ - For brand-specific or unique entry animations
348
+ - When creating complex reveal sequences
349
+
350
+ **Pattern**:
351
+ ```typescript
352
+ {
353
+ key: '[SOURCE_SELECTOR]',
354
+ trigger: 'viewProgress',
355
+ effects: [
356
+ {
357
+ key: '[TARGET_SELECTOR]',
358
+ keyframeEffect: {
359
+ name: '[UNIQUE_KEYFRAME_EFFECT_NAME]',
360
+ keyframes: [
361
+ { [CSS_PROPERTY_1]: '[START_VALUE_1]', [CSS_PROPERTY_2]: '[START_VALUE_2]' },
362
+ { [CSS_PROPERTY_1]: '[END_VALUE_1]', [CSS_PROPERTY_2]: '[END_VALUE_2]' }
363
+ ]
364
+ },
365
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: [ENTRY_START] } },
366
+ rangeEnd: { name: 'entry', offset: { type: 'percentage', value: [ENTRY_END] } },
367
+ easing: '[EASING_FUNCTION]',
368
+ fill: 'both',
369
+ effectId: '[UNIQUE_EFFECT_ID]'
370
+ }
371
+ ]
372
+ }
373
+ ```
374
+
375
+ **Variables**:
376
+ Same as Rule 4, with focus on entry range
377
+
378
+ **Example - Custom Card Entrance**:
379
+ ```typescript
380
+ {
381
+ key: 'card-section',
382
+ trigger: 'viewProgress',
383
+ effects: [
384
+ {
385
+ key: 'product-card',
386
+ keyframeEffect: {
387
+ name: 'card-entrance',
388
+ keyframes: [
389
+ { opacity: '0', transform: 'translateY(80px) scale(0.9)', filter: 'blur(5px)' },
390
+ { opacity: '1', transform: 'translateY(0) scale(1)', filter: 'blur(0)' }
391
+ ]
392
+ },
393
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
394
+ rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 70 } },
395
+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
396
+ fill: 'both'
397
+ }
398
+ ]
399
+ }
400
+ ```
401
+
402
+ **Example - Text Progressive Reveal**:
403
+ ```typescript
404
+ {
405
+ key: 'text-container',
406
+ trigger: 'viewProgress',
407
+ effects: [
408
+ {
409
+ key: 'main-heading',
410
+ keyframeEffect: {
411
+ name: 'heading-reveal',
412
+ keyframes: [
413
+ { opacity: '0', transform: 'translateX(-50px)', color: 'rgba(0,0,0,0.3)' },
414
+ { opacity: '1', transform: 'translateX(0)', color: 'rgba(0,0,0,1)' }
415
+ ]
416
+ },
417
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: 10 } },
418
+ rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 60 } },
419
+ easing: 'ease-out',
420
+ fill: 'both',
421
+ effectId: 'heading-reveal'
422
+ }
423
+ ]
424
+ }
425
+ ```
426
+
427
+ ---
428
+
429
+ ## Rule 6: Range-Based Exit Animation Control with Keyframe Effects
430
+
431
+ **Use Case**: Custom scroll-driven exit animations using keyframe effects for precise control over how elements disappear as they leave the viewport (e.g., custom hide effects, multi-property exits, unique scroll-out animations)
432
+
433
+ **When to Apply**:
434
+ - For custom exit effects not available in named effects
435
+ - When combining multiple properties in exit animations
436
+ - For creating smooth content transitions on scroll out
437
+ - When elements need complex hiding sequences
438
+
439
+ **Pattern**:
440
+ ```typescript
441
+ {
442
+ key: '[SOURCE_SELECTOR]',
443
+ trigger: 'viewProgress',
444
+ effects: [
445
+ {
446
+ key: '[TARGET_SELECTOR]',
447
+ keyframeEffect: {
448
+ name: '[UNIQUE_KEYFRAME_EFFECT_NAME]',
449
+ keyframes: [
450
+ { [CSS_PROPERTY_1]: '[START_VALUE_1]', [CSS_PROPERTY_2]: '[START_VALUE_2]' },
451
+ { [CSS_PROPERTY_1]: '[END_VALUE_1]', [CSS_PROPERTY_2]: '[END_VALUE_2]' }
452
+ ]
453
+ },
454
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: [EXIT_START] } },
455
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: [EXIT_END] } },
456
+ easing: '[EASING_FUNCTION]',
457
+ fill: 'both',
458
+ effectId: '[UNIQUE_EFFECT_ID]'
459
+ }
460
+ ]
461
+ }
462
+ ```
463
+
464
+ **Variables**:
465
+ Same as Rule 4, with focus on exit range
466
+
467
+ **Example - Hero Content Exit**:
468
+ ```typescript
469
+ {
470
+ key: 'hero-section',
471
+ trigger: 'viewProgress',
472
+ effects: [
473
+ {
474
+ key: 'hero-content',
475
+ keyframeEffect: {
476
+ name: 'hero-content-animation',
477
+ keyframes: [
478
+ { opacity: '1', transform: 'translateY(0) scale(1)', filter: 'blur(0)' },
479
+ { opacity: '0', transform: 'translateY(-50px) scale(0.95)', filter: 'blur(3px)' }
480
+ ]
481
+ },
482
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: 0 } },
483
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 60 } },
484
+ easing: 'ease-in',
485
+ fill: 'both'
486
+ }
487
+ ]
488
+ }
489
+ ```
490
+
491
+ **Example - Navigation Scroll Hide**:
492
+ ```typescript
493
+ {
494
+ key: 'main-header',
495
+ trigger: 'viewProgress',
496
+ effects: [
497
+ {
498
+ key: 'sticky-nav',
499
+ keyframeEffect: {
500
+ name: 'nav-hide',
501
+ keyframes: [
502
+ { transform: 'translateY(0)', opacity: '1', backdropFilter: 'blur(10px)' },
503
+ { transform: 'translateY(-100%)', opacity: '0.7', backdropFilter: 'blur(0)' }
504
+ ]
505
+ },
506
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: 20 } },
507
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 80 } },
508
+ easing: 'ease-in-out',
509
+ fill: 'both',
510
+ effectId: 'nav-hide'
511
+ }
512
+ ]
513
+ }
514
+ ```
515
+
516
+ ---
517
+
518
+ ## Rule 7: Range-Based Parallax/Continuous Animation Control with Custom Effects
519
+
520
+ **Use Case**: JavaScript-powered scroll-driven animations with full programmatic control for complex interactions (e.g., canvas animations, complex calculations, dynamic content updates, interactive scroll effects)
521
+
522
+ **When to Apply**:
523
+ - For animations requiring complex calculations
524
+ - When integrating with canvas or WebGL
525
+ - For dynamic content updates based on scroll
526
+ - When CSS keyframes are insufficient
527
+
528
+ **Pattern**:
529
+ ```typescript
530
+ {
531
+ key: '[SOURCE_SELECTOR]',
532
+ trigger: 'viewProgress',
533
+ effects: [
534
+ {
535
+ key: '[TARGET_SELECTOR]',
536
+ customEffect: (element, progress, params) => {
537
+ // progress is 0-1 representing scroll position within range
538
+ [CUSTOM_ANIMATION_LOGIC]
539
+ },
540
+ rangeStart: { name: '[RANGE_NAME]', offset: { type: 'percentage', value: [START_PERCENTAGE] } },
541
+ rangeEnd: { name: '[RANGE_NAME]', offset: { type: 'percentage', value: [END_PERCENTAGE] } },
542
+ fill: 'both',
543
+ effectId: '[UNIQUE_EFFECT_ID]'
544
+ }
545
+ ]
546
+ }
547
+ ```
548
+
549
+ **Variables**:
550
+ - `[CUSTOM_ANIMATION_LOGIC]`: JavaScript code for custom animation
551
+ - Other variables same as Rule 1
552
+
553
+ **Example - Scroll Counter Update**:
554
+ ```typescript
555
+ {
556
+ key: 'stats-section',
557
+ trigger: 'viewProgress',
558
+ effects: [
559
+ {
560
+ key: 'progress-counter',
561
+ customEffect: (element, progress) => {
562
+ const currentValue = Math.floor(progress * 100);
563
+ element.textContent = `${currentValue}%`;
564
+ element.style.color = `hsl(${progress * 120}, 70%, 50%)`;
565
+ },
566
+ rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
567
+ rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
568
+ fill: 'both',
569
+ effectId: 'progress-counter'
570
+ }
571
+ ]
572
+ }
573
+ ```
574
+
575
+ **Example - Complex Particle Animation**:
576
+ ```typescript
577
+ {
578
+ key: 'particle-container',
579
+ trigger: 'viewProgress',
580
+ effects: [
581
+ {
582
+ key: 'particle-canvas',
583
+ customEffect: (element, progress) => {
584
+ const particles = element.querySelectorAll('.particle');
585
+ particles.forEach((particle, index) => {
586
+ const delay = index * 0.1;
587
+ const adjustedProgress = Math.max(0, Math.min(1, (progress - delay) / (1 - delay)));
588
+ const rotation = adjustedProgress * 360;
589
+ const scale = 0.5 + (adjustedProgress * 0.5);
590
+ const translateY = (1 - adjustedProgress) * 200;
591
+
592
+ particle.style.transform = `
593
+ translateY(${translateY}px)
594
+ rotate(${rotation}deg)
595
+ scale(${scale})
596
+ `;
597
+ particle.style.opacity = adjustedProgress;
598
+ });
599
+ },
600
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
601
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 100 } },
602
+ fill: 'both',
603
+ effectId: 'particle-scroll'
604
+ }
605
+ ]
606
+ }
607
+ ```
608
+
609
+ ---
610
+
611
+ ## Rule 8: Range-Based Entry Animation Control with Custom Effects
612
+
613
+ **Use Case**: JavaScript-powered entrance animations with programmatic control for complex entry sequences (e.g., dynamic counters, interactive reveals, calculated animations, progressive loading effects)
614
+
615
+ **When to Apply**:
616
+ - For entrance animations requiring calculations
617
+ - When creating dynamic content reveals
618
+ - For interactive entrance sequences
619
+ - When standard keyframes cannot achieve the desired effect
620
+
621
+ **Pattern**:
622
+ ```typescript
623
+ {
624
+ key: '[SOURCE_SELECTOR]',
625
+ trigger: 'viewProgress',
626
+ effects: [
627
+ {
628
+ key: '[TARGET_SELECTOR]',
629
+ customEffect: (element, progress, params) => {
630
+ // progress is 0-1 representing entry progress
631
+ [ENTRY_ANIMATION_LOGIC]
632
+ },
633
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: [ENTRY_START] } },
634
+ rangeEnd: { name: 'entry', offset: { type: 'percentage', value: [ENTRY_END] } },
635
+ fill: 'both',
636
+ effectId: '[UNIQUE_EFFECT_ID]'
637
+ }
638
+ ]
639
+ }
640
+ ```
641
+
642
+ **Variables**:
643
+ - `[ENTRY_ANIMATION_LOGIC]`: JavaScript code for custom entry animation
644
+ - Other variables same as previous rules
645
+
646
+ **Example - Dynamic Text Reveal**:
647
+ ```typescript
648
+ {
649
+ key: 'text-section',
650
+ trigger: 'viewProgress',
651
+ effects: [
652
+ {
653
+ key: 'animated-text',
654
+ customEffect: (element, progress) => {
655
+ const text = element.dataset.fullText || element.textContent;
656
+ const visibleLength = Math.floor(text.length * progress);
657
+ const visibleText = text.substring(0, visibleLength);
658
+ element.textContent = visibleText + (progress < 1 ? '|' : '');
659
+
660
+ element.style.opacity = Math.min(1, progress * 2);
661
+ element.style.transform = `translateY(${(1 - progress) * 30}px)`;
662
+ },
663
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
664
+ rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 80 } },
665
+ fill: 'both',
666
+ effectId: 'text-reveal'
667
+ }
668
+ ]
669
+ }
670
+ ```
671
+
672
+ **Example - Progressive Chart Fill**:
673
+ ```typescript
674
+ {
675
+ key: 'chart-container',
676
+ trigger: 'viewProgress',
677
+ effects: [
678
+ {
679
+ key: 'chart-bar',
680
+ customEffect: (element, progress) => {
681
+ const targetHeight = element.dataset.targetHeight || 100;
682
+ const currentHeight = targetHeight * progress;
683
+ const colorIntensity = Math.floor(255 * progress);
684
+
685
+ element.style.height = `${currentHeight}px`;
686
+ element.style.backgroundColor = `rgb(${255 - colorIntensity}, ${colorIntensity}, 100)`;
687
+ element.style.boxShadow = `0 0 ${progress * 20}px rgba(0, ${colorIntensity}, 255, 0.5)`;
688
+ },
689
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: 20 } },
690
+ rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 90 } },
691
+ fill: 'both',
692
+ effectId: 'chart-fill'
693
+ }
694
+ ]
695
+ }
696
+ ```
697
+
698
+ ---
699
+
700
+ ## Rule 9: Range-Based Exit Animation Control with Custom Effects
701
+
702
+ **Use Case**: JavaScript-powered exit animations with programmatic control for complex exit sequences (e.g., dynamic hiding effects, calculated dismissals, interactive fade-outs, progressive unloading effects)
703
+
704
+ **When to Apply**:
705
+ - For exit animations requiring calculations
706
+ - When creating dynamic content hiding
707
+ - For interactive exit sequences
708
+ - When standard keyframes cannot achieve the desired exit effect
709
+
710
+ **Pattern**:
711
+ ```typescript
712
+ {
713
+ key: '[SOURCE_SELECTOR]',
714
+ trigger: 'viewProgress',
715
+ effects: [
716
+ {
717
+ key: '[TARGET_SELECTOR]',
718
+ customEffect: (element, progress, params) => {
719
+ // progress is 0-1 representing exit progress
720
+ [EXIT_ANIMATION_LOGIC]
721
+ },
722
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: [EXIT_START] } },
723
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: [EXIT_END] } },
724
+ fill: 'both',
725
+ effectId: '[UNIQUE_EFFECT_ID]'
726
+ }
727
+ ]
728
+ }
729
+ ```
730
+
731
+ **Variables**:
732
+ - `[EXIT_ANIMATION_LOGIC]`: JavaScript code for custom exit animation
733
+ - Other variables same as previous rules
734
+
735
+ **Example - Dissolve Effect Exit**:
736
+ ```typescript
737
+ {
738
+ key: 'content-section',
739
+ trigger: 'viewProgress',
740
+ effects: [
741
+ {
742
+ key: 'dissolving-content',
743
+ customEffect: (element, progress) => {
744
+ const particles = element.querySelectorAll('.content-particle');
745
+ const dissolveProgress = progress;
746
+
747
+ particles.forEach((particle, index) => {
748
+ const delay = (index / particles.length) * 0.5;
749
+ const particleProgress = Math.max(0, (dissolveProgress - delay) / (1 - delay));
750
+
751
+ particle.style.opacity = 1 - particleProgress;
752
+ particle.style.transform = `
753
+ translateY(${particleProgress * -100}px)
754
+ rotate(${particleProgress * 180}deg)
755
+ scale(${1 - particleProgress * 0.5})
756
+ `;
757
+ });
758
+ },
759
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: 10 } },
760
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 90 } },
761
+ fill: 'both',
762
+ effectId: 'dissolve-exit'
763
+ }
764
+ ]
765
+ }
766
+ ```
767
+
768
+ **Example - Data Visualization Exit**:
769
+ ```typescript
770
+ {
771
+ key: 'data-visualization',
772
+ trigger: 'viewProgress',
773
+ effects: [
774
+ {
775
+ key: 'data-point',
776
+ customEffect: (element, progress) => {
777
+ const dataPoints = element.closest('interact-element')?.querySelectorAll('.data-point') || [];
778
+ const totalPoints = dataPoints.length;
779
+ const elementIndex = Array.from(dataPoints).indexOf(element);
780
+
781
+ // Staggered exit based on data point position
782
+ const staggerDelay = (elementIndex / totalPoints) * 0.3;
783
+ const adjustedProgress = Math.max(0, (progress - staggerDelay) / (1 - staggerDelay));
784
+
785
+ const scale = 1 - (adjustedProgress * 0.8);
786
+ const rotation = adjustedProgress * 720; // Two full rotations
787
+ const opacity = 1 - adjustedProgress;
788
+
789
+ element.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
790
+ element.style.opacity = opacity;
791
+ element.style.filter = `blur(${adjustedProgress * 10}px)`;
792
+ },
793
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: 0 } },
794
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 80 } },
795
+ fill: 'both',
796
+ effectId: 'data-exit'
797
+ }
798
+ ]
799
+ }
800
+ ```
801
+
802
+ ---
803
+
804
+ ## Advanced Patterns and Combinations
805
+
806
+ ### Multi-Range ViewProgress Effects
807
+ Combining different ranges for complex scroll animations:
808
+
809
+ ```typescript
810
+ {
811
+ key: 'complex-section',
812
+ trigger: 'viewProgress',
813
+ effects: [
814
+ // Entry phase
815
+ {
816
+ key: 'section-content',
817
+ keyframeEffect: {
818
+ name: 'content-entrance',
819
+ keyframes: [
820
+ { opacity: '0', transform: 'translateY(50px)' },
821
+ { opacity: '1', transform: 'translateY(0)' }
822
+ ]
823
+ },
824
+ rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
825
+ rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 50 } },
826
+ easing: 'ease-out',
827
+ fill: 'backwards'
828
+ },
829
+ // Cover phase
830
+ {
831
+ key: 'background-element',
832
+ keyframeEffect: {
833
+ name: 'background-parallax-hue',
834
+ keyframes: [
835
+ { transform: 'translateY(0)', filter: 'hue-rotate(0deg)' },
836
+ { transform: 'translateY(-100px)', filter: 'hue-rotate(180deg)' }
837
+ ]
838
+ },
839
+ rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
840
+ rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
841
+ easing: 'linear',
842
+ fill: 'both'
843
+ },
844
+ // Exit phase
845
+ {
846
+ key: 'section-content',
847
+ keyframeEffect: {
848
+ name: 'content-exit',
849
+ keyframes: [
850
+ { opacity: '1', transform: 'scale(1)' },
851
+ { opacity: '0', transform: 'scale(0.8)' }
852
+ ]
853
+ },
854
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: 50 } },
855
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 100 } },
856
+ easing: 'ease-in',
857
+ fill: 'forwards'
858
+ }
859
+ ]
860
+ }
861
+ ```
862
+
863
+ ### ViewProgress with Conditional Behavior
864
+ Responsive scroll animations:
865
+
866
+ ```typescript
867
+ {
868
+ key: 'responsive-parallax',
869
+ trigger: 'viewProgress',
870
+ conditions: ['desktop-only', 'prefers-motion'],
871
+ effects: [
872
+ {
873
+ key: 'parallax-bg',
874
+ keyframeEffect: {
875
+ name: 'parallax-bg',
876
+ keyframes: [
877
+ { transform: 'translateY(0)' },
878
+ { transform: 'translateY(-300px)' }
879
+ ]
880
+ },
881
+ rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
882
+ rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
883
+ easing: 'linear',
884
+ fill: 'both'
885
+ }
886
+ ]
887
+ },
888
+ // Simplified version for mobile
889
+ {
890
+ key: 'responsive-parallax',
891
+ trigger: 'viewProgress',
892
+ conditions: ['mobile-only'],
893
+ effects: [
894
+ {
895
+ key: 'parallax-bg',
896
+ keyframeEffect: {
897
+ name: 'fade-out-bg',
898
+ keyframes: [
899
+ { opacity: '1' },
900
+ { opacity: '0.7' }
901
+ ]
902
+ },
903
+ rangeStart: { name: 'exit', offset: { type: 'percentage', value: 0 } },
904
+ rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 100 } },
905
+ easing: 'linear',
906
+ fill: 'both'
907
+ }
908
+ ]
909
+ }
910
+ ```
911
+
912
+ ### Multiple Element Coordination
913
+ Orchestrating multiple elements with viewProgress:
914
+
915
+ ```typescript
916
+ {
917
+ key: 'orchestrated-section',
918
+ trigger: 'viewProgress',
919
+ effects: [
920
+ {
921
+ key: 'bg-layer-1',
922
+ keyframeEffect: {
923
+ name: 'layer-1-parallax',
924
+ keyframes: [
925
+ { transform: 'translateY(0)' },
926
+ { transform: 'translateY(-50px)' }
927
+ ]
928
+ },
929
+ rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
930
+ rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
931
+ easing: 'linear',
932
+ fill: 'both'
933
+ },
934
+ {
935
+ key: 'bg-layer-2',
936
+ keyframeEffect: {
937
+ name: 'layer-2-parallax',
938
+ keyframes: [
939
+ { transform: 'translateY(0)' },
940
+ { transform: 'translateY(-100px)' }
941
+ ]
942
+ },
943
+ rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
944
+ rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
945
+ easing: 'linear',
946
+ fill: 'both'
947
+ },
948
+ {
949
+ key: 'fg-content',
950
+ keyframeEffect: {
951
+ name: 'layer-3-parallax',
952
+ keyframes: [
953
+ { transform: 'translateY(0)' },
954
+ { transform: 'translateY(-150px)' }
955
+ ]
956
+ },
957
+ rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
958
+ rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
959
+ easing: 'linear',
960
+ fill: 'both'
961
+ }
962
+ ]
963
+ }
964
+ ```
965
+
966
+ ---
967
+
968
+ ## Best Practices for ViewProgress Interactions
969
+
970
+ ### Performance Guidelines
971
+ 1. **Use `linear` easing** for most scroll effects to avoid jarring transitions
972
+ 2. **Prefer `transform`, `filter`, and `opacity`** properties for hardware acceleration
973
+
974
+ ### Range Configuration Guidelines
975
+ 1. **Use appropriate range names**:
976
+ - `entry`: For animations that happen as element enters viewport
977
+ - `cover`: For animations while element is intersecting viewport
978
+ - `exit`: For animations as element leaves viewport
979
+ - `contain`: For animations while element is contained within viewport
980
+
981
+ 2. **Offset Guidelines**:
982
+ - **0-100 values**: Represent percentage of the range
983
+ - **Start with broad ranges** (0-100) then refine
984
+ - **Use smaller ranges** (20-80) for more controlled animations
985
+ - **Avoid overlapping ranges** to prevent conflicting animations
986
+ - **Use 0-50% cover range or 0-100% entry range** for entry animations
987
+ - **Use 50-100% cover range or 0-100% exit range** for exit animations
988
+
989
+ ### User Experience Guidelines
990
+ 1. **Keep scroll animations subtle** to avoid motion sickness
991
+ 2. **Ensure content remains readable** during animations
992
+ 3. **Use progressive enhancement** - ensure content works without animations
993
+ 4. **Test on various devices** for performance and smoothness
994
+
995
+ ### Accessibility Considerations
996
+ 1. **Respect `prefers-reduced-motion`** for all scroll animations
997
+ 2. **Provide alternatives** for motion-sensitive users
998
+ 3. **Don't rely solely on scroll animations** for important content
999
+ 4. **Ensure keyboard navigation** still works with scroll effects
1000
+
1001
+ ### Common Use Cases by Pattern
1002
+
1003
+ **Parallax/Continuous (Rules 1, 4, 7)**:
1004
+ - Background image parallax
1005
+ - Floating decorative elements
1006
+ - Continuous progress indicators
1007
+ - Multi-layer depth effects
1008
+ - Scroll-responsive backgrounds
1009
+
1010
+ **Entry Animation (Rules 2, 5, 8)**:
1011
+ - Content reveals on scroll
1012
+ - Progressive image loading
1013
+ - Element introductions
1014
+ - Staggered content appearance
1015
+
1016
+ **Exit Animation (Rules 3, 6, 9)**:
1017
+ - Hero content fade-out
1018
+ - Navigation hiding
1019
+ - Content dismissals
1020
+ - Scroll-out transitions
1021
+ - Element cleanup effects
1022
+
1023
+ ### Troubleshooting Common Issues
1024
+
1025
+ **Janky scroll performance**:
1026
+ - Use hardware-accelerated properties only
1027
+ - Simplify custom effect calculations
1028
+ - Test on lower-end devices
1029
+
1030
+ **Unexpected animation behavior**:
1031
+ - Check range configurations match intended behavior
1032
+ - Verify source element visibility throughout scroll
1033
+ - Ensure target elements exist and are selectable
1034
+ - Test range offset values
1035
+
1036
+ **Poor visual results**:
1037
+ - Adjust easing functions for scroll context
1038
+ - Fine-tune range start/end percentages
1039
+ - Consider element positioning and layering
1040
+ - Test across different content heights
1041
+
1042
+ ---
1043
+
1044
+ These rules provide comprehensive coverage for ViewProgress trigger interactions in `@wix/interact`, supporting all range types (entry, cover, contain, exit) and effect types (named, keyframe, custom) as outlined in the development plan Stage 1.4.