@wix/interact 1.93.0 → 2.0.0-rc.4
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/cjs/index.js +2 -23
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react.js +15 -0
- package/dist/cjs/react.js.map +1 -0
- package/dist/cjs/web.js +2 -0
- package/dist/cjs/web.js.map +1 -0
- package/dist/es/index.js +8 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/react.js +650 -0
- package/dist/es/react.js.map +1 -0
- package/dist/es/web.js +56 -0
- package/dist/es/web.js.map +1 -0
- package/dist/index-BoEj_7uB.js +18 -0
- package/dist/index-BoEj_7uB.js.map +1 -0
- package/dist/index-DUTdIvfw.mjs +7969 -0
- package/dist/index-DUTdIvfw.mjs.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types/core/Interact.d.ts +25 -10
- package/dist/types/core/Interact.d.ts.map +1 -0
- package/dist/types/core/InteractionController.d.ts +24 -0
- package/dist/types/core/InteractionController.d.ts.map +1 -0
- package/dist/types/core/add.d.ts +4 -3
- package/dist/types/core/add.d.ts.map +1 -0
- package/dist/types/core/css.d.ts +3 -0
- package/dist/types/core/css.d.ts.map +1 -0
- package/dist/types/core/remove.d.ts +3 -1
- package/dist/types/core/remove.d.ts.map +1 -0
- package/dist/types/core/utilities.d.ts +1 -0
- package/dist/types/core/utilities.d.ts.map +1 -0
- package/dist/types/dom/api.d.ts +3 -0
- package/dist/types/dom/api.d.ts.map +1 -0
- package/dist/types/handlers/animationEnd.d.ts +3 -2
- package/dist/types/handlers/animationEnd.d.ts.map +1 -0
- package/dist/types/handlers/click.d.ts +3 -2
- package/dist/types/handlers/click.d.ts.map +1 -0
- package/dist/types/handlers/hover.d.ts +3 -2
- package/dist/types/handlers/hover.d.ts.map +1 -0
- package/dist/types/handlers/index.d.ts +1 -0
- package/dist/types/handlers/index.d.ts.map +1 -0
- package/dist/types/handlers/pointerMove.d.ts +3 -2
- package/dist/types/handlers/pointerMove.d.ts.map +1 -0
- package/dist/types/handlers/utilities.d.ts +1 -0
- package/dist/types/handlers/utilities.d.ts.map +1 -0
- package/dist/types/handlers/viewEnter.d.ts +3 -2
- package/dist/types/handlers/viewEnter.d.ts.map +1 -0
- package/dist/types/handlers/viewProgress.d.ts +4 -3
- package/dist/types/handlers/viewProgress.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/react/Interaction.d.ts +10 -0
- package/dist/types/react/Interaction.d.ts.map +1 -0
- package/dist/types/react/index.d.ts +8 -0
- package/dist/types/react/index.d.ts.map +1 -0
- package/dist/types/react/interactRef.d.ts +3 -0
- package/dist/types/react/interactRef.d.ts.map +1 -0
- package/dist/types/types.d.ts +31 -12
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/utils.d.ts +2 -1
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/{InteractElement.d.ts → web/InteractElement.d.ts} +117 -77
- package/dist/types/web/InteractElement.d.ts.map +1 -0
- package/dist/types/web/defineInteractElement.d.ts +2 -0
- package/dist/types/web/defineInteractElement.d.ts.map +1 -0
- package/dist/types/web/index.d.ts +6 -0
- package/dist/types/web/index.d.ts.map +1 -0
- package/docs/README.md +211 -0
- package/docs/advanced/README.md +164 -0
- package/docs/api/README.md +157 -0
- package/docs/api/element-selection.md +607 -0
- package/docs/api/functions.md +638 -0
- package/docs/api/interact-class.md +663 -0
- package/docs/api/interact-element.md +565 -0
- package/docs/api/interaction-controller.md +450 -0
- package/docs/api/types.md +957 -0
- package/docs/examples/README.md +212 -0
- package/docs/examples/click-interactions.md +977 -0
- package/docs/examples/entrance-animations.md +935 -0
- package/docs/examples/hover-effects.md +930 -0
- package/docs/examples/list-patterns.md +737 -0
- package/docs/guides/README.md +49 -0
- package/docs/guides/conditions-and-media-queries.md +1068 -0
- package/docs/guides/configuration-structure.md +726 -0
- package/docs/guides/custom-elements.md +327 -0
- package/docs/guides/effects-and-animations.md +634 -0
- package/docs/guides/getting-started.md +379 -0
- package/docs/guides/lists-and-dynamic-content.md +713 -0
- package/docs/guides/state-management.md +747 -0
- package/docs/guides/understanding-triggers.md +690 -0
- package/docs/integration/README.md +264 -0
- package/docs/integration/react.md +605 -0
- package/package.json +73 -56
- package/rules/Integration.md +255 -0
- package/rules/click-rules.md +533 -0
- package/rules/full-lean.md +346 -0
- package/rules/hover-rules.md +593 -0
- package/rules/pointermove-rules.md +1341 -0
- package/rules/scroll-list-rules.md +900 -0
- package/rules/viewenter-rules.md +1015 -0
- package/rules/viewprogress-rules.md +1044 -0
- package/dist/cjs/InteractElement.js +0 -163
- package/dist/cjs/InteractElement.js.map +0 -1
- package/dist/cjs/__tests__/interact.spec.js +0 -2094
- package/dist/cjs/__tests__/interact.spec.js.map +0 -1
- package/dist/cjs/__tests__/viewEnter.spec.js +0 -207
- package/dist/cjs/__tests__/viewEnter.spec.js.map +0 -1
- package/dist/cjs/core/Interact.js +0 -257
- package/dist/cjs/core/Interact.js.map +0 -1
- package/dist/cjs/core/add.js +0 -250
- package/dist/cjs/core/add.js.map +0 -1
- package/dist/cjs/core/remove.js +0 -35
- package/dist/cjs/core/remove.js.map +0 -1
- package/dist/cjs/core/utilities.js +0 -16
- package/dist/cjs/core/utilities.js.map +0 -1
- package/dist/cjs/external-types.d.js +0 -2
- package/dist/cjs/external-types.d.js.map +0 -1
- package/dist/cjs/handlers/animationEnd.js +0 -37
- package/dist/cjs/handlers/animationEnd.js.map +0 -1
- package/dist/cjs/handlers/click.js +0 -122
- package/dist/cjs/handlers/click.js.map +0 -1
- package/dist/cjs/handlers/hover.js +0 -147
- package/dist/cjs/handlers/hover.js.map +0 -1
- package/dist/cjs/handlers/index.js +0 -32
- package/dist/cjs/handlers/index.js.map +0 -1
- package/dist/cjs/handlers/pointerMove.js +0 -49
- package/dist/cjs/handlers/pointerMove.js.map +0 -1
- package/dist/cjs/handlers/utilities.js +0 -49
- package/dist/cjs/handlers/utilities.js.map +0 -1
- package/dist/cjs/handlers/viewEnter.js +0 -131
- package/dist/cjs/handlers/viewEnter.js.map +0 -1
- package/dist/cjs/handlers/viewProgress.js +0 -79
- package/dist/cjs/handlers/viewProgress.js.map +0 -1
- package/dist/cjs/test-types.d.js +0 -2
- package/dist/cjs/test-types.d.js.map +0 -1
- package/dist/cjs/types.js +0 -2
- package/dist/cjs/types.js.map +0 -1
- package/dist/cjs/utils.js +0 -98
- package/dist/cjs/utils.js.map +0 -1
- package/dist/esm/InteractElement.js +0 -157
- package/dist/esm/InteractElement.js.map +0 -1
- package/dist/esm/__tests__/interact.spec.js +0 -2102
- package/dist/esm/__tests__/interact.spec.js.map +0 -1
- package/dist/esm/__tests__/viewEnter.spec.js +0 -210
- package/dist/esm/__tests__/viewEnter.spec.js.map +0 -1
- package/dist/esm/core/Interact.js +0 -251
- package/dist/esm/core/Interact.js.map +0 -1
- package/dist/esm/core/add.js +0 -245
- package/dist/esm/core/add.js.map +0 -1
- package/dist/esm/core/remove.js +0 -30
- package/dist/esm/core/remove.js.map +0 -1
- package/dist/esm/core/utilities.js +0 -14
- package/dist/esm/core/utilities.js.map +0 -1
- package/dist/esm/external-types.d.js +0 -2
- package/dist/esm/external-types.d.js.map +0 -1
- package/dist/esm/handlers/animationEnd.js +0 -33
- package/dist/esm/handlers/animationEnd.js.map +0 -1
- package/dist/esm/handlers/click.js +0 -122
- package/dist/esm/handlers/click.js.map +0 -1
- package/dist/esm/handlers/hover.js +0 -147
- package/dist/esm/handlers/hover.js.map +0 -1
- package/dist/esm/handlers/index.js +0 -27
- package/dist/esm/handlers/index.js.map +0 -1
- package/dist/esm/handlers/pointerMove.js +0 -48
- package/dist/esm/handlers/pointerMove.js.map +0 -1
- package/dist/esm/handlers/utilities.js +0 -43
- package/dist/esm/handlers/utilities.js.map +0 -1
- package/dist/esm/handlers/viewEnter.js +0 -133
- package/dist/esm/handlers/viewEnter.js.map +0 -1
- package/dist/esm/handlers/viewProgress.js +0 -75
- package/dist/esm/handlers/viewProgress.js.map +0 -1
- package/dist/esm/index.js +0 -5
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/test-types.d.js +0 -2
- package/dist/esm/test-types.d.js.map +0 -1
- package/dist/esm/types.js +0 -2
- package/dist/esm/types.js.map +0 -1
- package/dist/esm/utils.js +0 -92
- package/dist/esm/utils.js.map +0 -1
- package/dist/types/__tests__/interact.spec.d.ts +0 -1
- package/dist/types/__tests__/viewEnter.spec.d.ts +0 -0
|
@@ -0,0 +1,900 @@
|
|
|
1
|
+
# Scroll List Animation Rules for @wix/interact
|
|
2
|
+
|
|
3
|
+
These rules help generate scroll-driven list animations using the `@wix/interact` library. List animations encompass sticky containers, sticky items, and their content animations, providing comprehensive patterns for modern scroll-driven list interactions including parallax effects, staggered reveals, and progressive content disclosure.
|
|
4
|
+
|
|
5
|
+
## Rule 1: Sticky Container List Animations with Named Effects
|
|
6
|
+
|
|
7
|
+
**Use Case**: Animations applied to list containers that are sticky-positioned within their wrapper, using pre-built named effects for smooth scroll-driven transformations (e.g., horizontal sliding galleries, parallax backgrounds, container reveals)
|
|
8
|
+
|
|
9
|
+
**When to Apply**:
|
|
10
|
+
- For sticky container horizontal sliding during scroll
|
|
11
|
+
- When creating parallax container effects
|
|
12
|
+
- For container-level background transformations
|
|
13
|
+
- When using pre-built motion effects for container animations
|
|
14
|
+
|
|
15
|
+
**Pattern**:
|
|
16
|
+
```typescript
|
|
17
|
+
{
|
|
18
|
+
key: '[CONTAINER_SELECTOR]',
|
|
19
|
+
trigger: 'viewProgress',
|
|
20
|
+
effects: [
|
|
21
|
+
{
|
|
22
|
+
key: '[CONTAINER_KEY]',
|
|
23
|
+
namedEffect: {
|
|
24
|
+
type: '[CONTAINER_NAMED_EFFECT]'
|
|
25
|
+
},
|
|
26
|
+
rangeStart: { name: 'contain', offset: { type: 'percentage', value: [START_PERCENTAGE] } },
|
|
27
|
+
rangeEnd: { name: 'contain', offset: { type: 'percentage', value: [END_PERCENTAGE] } },
|
|
28
|
+
easing: 'linear',
|
|
29
|
+
effectId: '[UNIQUE_EFFECT_ID]'
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Variables**:
|
|
36
|
+
- `[CONTAINER_KEY]`: Unique identifier for sticky list container
|
|
37
|
+
- `[CONTAINER_NAMED_EFFECT]`: Container-level scroll effects ('BgParallax', 'PanScroll', 'MoveScroll', 'ParallaxScroll') or background effects ('BgPan', 'BgZoom', 'BgFade', 'BgReveal')
|
|
38
|
+
- `[START_PERCENTAGE]`: Start point in contain range (typically 0)
|
|
39
|
+
- `[END_PERCENTAGE]`: End point in contain range (typically 100)
|
|
40
|
+
- `[UNIQUE_EFFECT_ID]`: Optional unique identifier
|
|
41
|
+
|
|
42
|
+
**Example - Horizontal Sliding Gallery Container**:
|
|
43
|
+
```typescript
|
|
44
|
+
{
|
|
45
|
+
key: 'gallery-container',
|
|
46
|
+
trigger: 'viewProgress',
|
|
47
|
+
effects: [
|
|
48
|
+
{
|
|
49
|
+
key: 'gallery-container',
|
|
50
|
+
namedEffect: {
|
|
51
|
+
type: 'PanScroll'
|
|
52
|
+
},
|
|
53
|
+
rangeStart: { name: 'contain', offset: { type: 'percentage', value: 0 } },
|
|
54
|
+
rangeEnd: { name: 'contain', offset: { type: 'percentage', value: 100 } },
|
|
55
|
+
easing: 'linear',
|
|
56
|
+
effectId: 'gallery-slide'
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Example - Parallax Container Background**:
|
|
63
|
+
```typescript
|
|
64
|
+
{
|
|
65
|
+
key: 'sticky-list-wrapper',
|
|
66
|
+
trigger: 'viewProgress',
|
|
67
|
+
effects: [
|
|
68
|
+
{
|
|
69
|
+
key: 'list-background',
|
|
70
|
+
namedEffect: {
|
|
71
|
+
type: 'BgParallax'
|
|
72
|
+
},
|
|
73
|
+
rangeStart: { name: 'contain', offset: { type: 'percentage', value: 0 } },
|
|
74
|
+
rangeEnd: { name: 'contain', offset: { type: 'percentage', value: 100 } },
|
|
75
|
+
easing: 'linear',
|
|
76
|
+
effectId: 'bg-parallax'
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Rule 2: Sticky Item List Animations with Named Effects
|
|
85
|
+
|
|
86
|
+
**Use Case**: Animations on individual list items that are sticky-positioned within the container, using named effects for entrance/exit animations as items enter sticky positioning (e.g., progressive item reveals, item transformation sequences)
|
|
87
|
+
|
|
88
|
+
**When to Apply**:
|
|
89
|
+
- For item entrance/exit animations during sticky phases
|
|
90
|
+
- When creating progressive item reveals
|
|
91
|
+
- For individual item transformations
|
|
92
|
+
- When using pre-built item-level effects
|
|
93
|
+
|
|
94
|
+
**Pattern**:
|
|
95
|
+
```typescript
|
|
96
|
+
{
|
|
97
|
+
key: '[ITEM_KEY]',
|
|
98
|
+
trigger: 'viewProgress',
|
|
99
|
+
effects: [
|
|
100
|
+
{
|
|
101
|
+
key: '[ITEM_KEY]',
|
|
102
|
+
namedEffect: {
|
|
103
|
+
type: '[ITEM_NAMED_EFFECT]'
|
|
104
|
+
},
|
|
105
|
+
rangeStart: { name: '[RANGE_TYPE]', offset: { type: 'percentage', value: [START_PERCENTAGE] } },
|
|
106
|
+
rangeEnd: { name: '[RANGE_TYPE]', offset: { type: 'percentage', value: [END_PERCENTAGE] } },
|
|
107
|
+
easing: '[EASING_FUNCTION]',
|
|
108
|
+
effectId: '[UNIQUE_EFFECT_ID]'
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Variables**:
|
|
115
|
+
- `[ITEM_KEY]`: Unique identifier for individual list items
|
|
116
|
+
- `[ITEM_NAMED_EFFECT]`: Item-level scroll effects from @wix/motion scroll animations:
|
|
117
|
+
- **Reveal/Fade**: 'FadeScroll', 'BlurScroll', 'RevealScroll', 'ShapeScroll', 'ShuttersScroll'
|
|
118
|
+
- **Movement**: 'MoveScroll', 'SlideScroll', 'PanScroll', 'SkewPanScroll'
|
|
119
|
+
- **Scale**: 'GrowScroll', 'ShrinkScroll', 'StretchScroll'
|
|
120
|
+
- **Rotation**: 'SpinScroll', 'FlipScroll', 'TiltScroll', 'TurnScroll'
|
|
121
|
+
- **3D**: 'ArcScroll', 'Spin3dScroll'
|
|
122
|
+
- `[RANGE_TYPE]`: 'entry' for entrance, 'exit' for exit, 'contain' for during sticky, 'cover' for full scroll range
|
|
123
|
+
- `[START_PERCENTAGE]`: Range start percentage (0-100)
|
|
124
|
+
- `[END_PERCENTAGE]`: Range end percentage (0-100)
|
|
125
|
+
- `[EASING_FUNCTION]`: Timing function
|
|
126
|
+
|
|
127
|
+
**Example - Item Entrance Reveal**:
|
|
128
|
+
```typescript
|
|
129
|
+
{
|
|
130
|
+
key: 'list-item',
|
|
131
|
+
trigger: 'viewProgress',
|
|
132
|
+
effects: [
|
|
133
|
+
{
|
|
134
|
+
key: 'list-item',
|
|
135
|
+
namedEffect: {
|
|
136
|
+
type: 'RevealScroll',
|
|
137
|
+
direction: 'bottom'
|
|
138
|
+
},
|
|
139
|
+
rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
|
|
140
|
+
rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 60 } },
|
|
141
|
+
easing: 'ease-out',
|
|
142
|
+
effectId: 'item-reveal'
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Example - Item Scale During Sticky**:
|
|
149
|
+
```typescript
|
|
150
|
+
{
|
|
151
|
+
key: 'sticky-list-item',
|
|
152
|
+
trigger: 'viewProgress',
|
|
153
|
+
effects: [
|
|
154
|
+
{
|
|
155
|
+
key: 'sticky-list-item',
|
|
156
|
+
namedEffect: {
|
|
157
|
+
type: 'GrowScroll'
|
|
158
|
+
},
|
|
159
|
+
rangeStart: { name: 'contain', offset: { type: 'percentage', value: 0 } },
|
|
160
|
+
rangeEnd: { name: 'contain', offset: { type: 'percentage', value: 50 } },
|
|
161
|
+
easing: 'ease-in-out',
|
|
162
|
+
effectId: 'item-grow'
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Rule 3: Sticky Item List Content Animations with Named Effects
|
|
171
|
+
|
|
172
|
+
**Use Case**: Animations on content within sticky list items, using named effects with each individual item being the viewProgress trigger (e.g., text reveals within cards, image animations within items, progressive content disclosure)
|
|
173
|
+
|
|
174
|
+
**When to Apply**:
|
|
175
|
+
- For content animations within sticky items
|
|
176
|
+
- When creating staggered content reveals
|
|
177
|
+
- For text/image animations inside list items
|
|
178
|
+
- When coordinating multiple content elements
|
|
179
|
+
|
|
180
|
+
**Pattern**:
|
|
181
|
+
```typescript
|
|
182
|
+
{
|
|
183
|
+
key: '[ITEM_CONTAINER_SELECTOR]',
|
|
184
|
+
trigger: 'viewProgress',
|
|
185
|
+
effects: [
|
|
186
|
+
{
|
|
187
|
+
key: '[CONTENT_SELECTOR]',
|
|
188
|
+
namedEffect: {
|
|
189
|
+
type: '[CONTENT_NAMED_EFFECT]'
|
|
190
|
+
},
|
|
191
|
+
rangeStart: { name: '[RANGE_TYPE]', offset: { type: 'percentage', value: [START_PERCENTAGE] } },
|
|
192
|
+
rangeEnd: { name: '[RANGE_TYPE]', offset: { type: 'percentage', value: [END_PERCENTAGE] } },
|
|
193
|
+
easing: '[EASING_FUNCTION]',
|
|
194
|
+
effectId: '[UNIQUE_EFFECT_ID]'
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Variables**:
|
|
201
|
+
- `[ITEM_CONTAINER_SELECTOR]`: CSS selector for the containing list item
|
|
202
|
+
- `[CONTENT_SELECTOR]`: CSS selector for content within the item
|
|
203
|
+
- `[CONTENT_NAMED_EFFECT]`: Content-level scroll effects from @wix/motion:
|
|
204
|
+
- **Opacity/Visibility**: 'FadeScroll', 'BlurScroll'
|
|
205
|
+
- **Reveal**: 'RevealScroll', 'ShapeScroll', 'ShuttersScroll'
|
|
206
|
+
- **3D Transforms**: 'TiltScroll', 'FlipScroll', 'ArcScroll', 'TurnScroll', 'Spin3dScroll'
|
|
207
|
+
- **Movement**: 'MoveScroll', 'SlideScroll'
|
|
208
|
+
- **Scale**: 'GrowScroll', 'ShrinkScroll'
|
|
209
|
+
- Other variables same as Rule 2
|
|
210
|
+
|
|
211
|
+
**Example - Staggered Text Content Reveal**:
|
|
212
|
+
```typescript
|
|
213
|
+
{
|
|
214
|
+
key: 'list-item-1',
|
|
215
|
+
trigger: 'viewProgress',
|
|
216
|
+
effects: [
|
|
217
|
+
{
|
|
218
|
+
key: 'list-item-1',
|
|
219
|
+
selector: '.content-text',
|
|
220
|
+
namedEffect: {
|
|
221
|
+
type: 'FadeScroll'
|
|
222
|
+
},
|
|
223
|
+
rangeStart: { name: 'entry', offset: { type: 'percentage', value: 20 } },
|
|
224
|
+
rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 80 } },
|
|
225
|
+
easing: 'ease-out',
|
|
226
|
+
effectId: 'text-reveal-1'
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
key: 'list-item-2',
|
|
232
|
+
trigger: 'viewProgress',
|
|
233
|
+
effects: [
|
|
234
|
+
{
|
|
235
|
+
key: 'list-item-2',
|
|
236
|
+
selector: '.content-text',
|
|
237
|
+
namedEffect: {
|
|
238
|
+
type: 'FadeScroll'
|
|
239
|
+
},
|
|
240
|
+
rangeStart: { name: 'entry', offset: { type: 'percentage', value: 20 } },
|
|
241
|
+
rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 80 } },
|
|
242
|
+
easing: 'ease-out',
|
|
243
|
+
effectId: 'text-reveal-2'
|
|
244
|
+
}
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Example - Image Animation Within List Item**:
|
|
250
|
+
```typescript
|
|
251
|
+
{
|
|
252
|
+
key: 'product-card',
|
|
253
|
+
trigger: 'viewProgress',
|
|
254
|
+
effects: [
|
|
255
|
+
{
|
|
256
|
+
key: 'product-card',
|
|
257
|
+
selector: ' .hero-image',
|
|
258
|
+
namedEffect: {
|
|
259
|
+
type: 'RevealScroll'
|
|
260
|
+
},
|
|
261
|
+
rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
|
|
262
|
+
rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 50 } },
|
|
263
|
+
easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
|
|
264
|
+
effectId: 'product-image-reveal'
|
|
265
|
+
}
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Rule 4: List Container Keyframe Animations
|
|
273
|
+
|
|
274
|
+
**Use Case**: Custom scroll-driven container animations using keyframe effects for precise control over sticky container behaviors (e.g., multi-property container transformations, responsive container animations, complex background effects)
|
|
275
|
+
|
|
276
|
+
**When to Apply**:
|
|
277
|
+
- For custom container effects not available in named effects
|
|
278
|
+
- When combining multiple CSS properties in container animations
|
|
279
|
+
- For responsive container behaviors
|
|
280
|
+
- When creating unique container visual effects
|
|
281
|
+
|
|
282
|
+
**Pattern**:
|
|
283
|
+
```typescript
|
|
284
|
+
{
|
|
285
|
+
key: '[CONTAINER_SELECTOR]',
|
|
286
|
+
trigger: 'viewProgress',
|
|
287
|
+
effects: [
|
|
288
|
+
{
|
|
289
|
+
key: '[CONTAINER_KEY]',
|
|
290
|
+
keyframeEffect: {
|
|
291
|
+
name: '[UNIQUE_KEYFRAME_EFFECT_NAME]',
|
|
292
|
+
keyframes: [
|
|
293
|
+
{ [CSS_PROPERTY_1]: '[START_VALUE_1]', [CSS_PROPERTY_2]: '[START_VALUE_2]', [CSS_PROPERTY_3]: '[START_VALUE_3]' },
|
|
294
|
+
{ [CSS_PROPERTY_1]: '[MID_VALUE_1]' },
|
|
295
|
+
{ [CSS_PROPERTY_1]: '[END_VALUE_1]', [CSS_PROPERTY_2]: '[END_VALUE_2]', [CSS_PROPERTY_3]: '[END_VALUE_3]' }
|
|
296
|
+
]
|
|
297
|
+
},
|
|
298
|
+
rangeStart: { name: 'contain', offset: { type: 'percentage', value: [START_PERCENTAGE] } },
|
|
299
|
+
rangeEnd: { name: 'contain', offset: { type: 'percentage', value: [END_PERCENTAGE] } },
|
|
300
|
+
easing: 'linear',
|
|
301
|
+
fill: 'both',
|
|
302
|
+
effectId: '[UNIQUE_EFFECT_ID]'
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**Variables**:
|
|
309
|
+
- `[CONTAINER_KEY]`: Unique identifier for list container
|
|
310
|
+
- `[UNIQUE_KEYFRAME_EFFECT_NAME]`: unique name for the CSS keyframe effect (can equal `[UNIQUE_EFFECT_ID]` if provided)
|
|
311
|
+
- `[CSS_PROPERTY_N]`: CSS property names ('transform', 'filter', 'opacity', 'backgroundColor')
|
|
312
|
+
- `[START/MID/END_VALUE_N]`: Keyframe values for each property
|
|
313
|
+
- Other variables same as Rule 1
|
|
314
|
+
|
|
315
|
+
**Example - Multi-Property Container Animation**:
|
|
316
|
+
```typescript
|
|
317
|
+
{
|
|
318
|
+
key: 'feature-list-container',
|
|
319
|
+
trigger: 'viewProgress',
|
|
320
|
+
effects: [
|
|
321
|
+
{
|
|
322
|
+
key: 'feature-list-container',
|
|
323
|
+
keyframeEffect: {
|
|
324
|
+
name: 'container-slide',
|
|
325
|
+
keyframes: [
|
|
326
|
+
{ transform: 'translateX(0)', filter: 'brightness(1)', backgroundColor: 'rgb(255 255 255 / 0)' },
|
|
327
|
+
{ transform: 'translateX(-50%)', filter: 'brightness(1.2)', backgroundColor: 'rgb(255 255 255 / 0.1)' },
|
|
328
|
+
{ transform: 'translateX(-100%)', filter: 'brightness(1)', backgroundColor: 'rgb(255 255 255 / 0)' }
|
|
329
|
+
]
|
|
330
|
+
},
|
|
331
|
+
rangeStart: { name: 'contain', offset: { type: 'percentage', value: 0 } },
|
|
332
|
+
rangeEnd: { name: 'contain', offset: { type: 'percentage', value: 100 } },
|
|
333
|
+
easing: 'linear',
|
|
334
|
+
fill: 'both',
|
|
335
|
+
effectId: 'container-slide'
|
|
336
|
+
}
|
|
337
|
+
]
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Example - Container Background Transformation**:
|
|
342
|
+
```typescript
|
|
343
|
+
{
|
|
344
|
+
key: 'gallery-wrapper',
|
|
345
|
+
trigger: 'viewProgress',
|
|
346
|
+
effects: [
|
|
347
|
+
{
|
|
348
|
+
key: 'gallery-background',
|
|
349
|
+
keyframeEffect: {
|
|
350
|
+
name: 'bg-transform',
|
|
351
|
+
keyframes: [
|
|
352
|
+
{ transform: 'scale(1.1) rotate(6deg)', opacity: '0.8', filter: 'hue-rotate(30deg)' },
|
|
353
|
+
{ transform: 'scale(1) rotate(0deg)', opacity: '1', filter: 'hue-rotate(0deg)' }
|
|
354
|
+
]
|
|
355
|
+
},
|
|
356
|
+
rangeStart: { name: 'contain', offset: { type: 'percentage', value: 0 } },
|
|
357
|
+
rangeEnd: { name: 'contain', offset: { type: 'percentage', value: 100 } },
|
|
358
|
+
easing: 'linear',
|
|
359
|
+
fill: 'both',
|
|
360
|
+
effectId: 'bg-transform'
|
|
361
|
+
}
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Rule 5: List Item Keyframe Entrance/Exit Animations
|
|
369
|
+
|
|
370
|
+
**Use Case**: Custom entrance and exit animations for list items using keyframe effects for precise control over item reveals and dismissals (e.g., complex item entrances, item position flow, responsive item animations)
|
|
371
|
+
|
|
372
|
+
**When to Apply**:
|
|
373
|
+
- For complex item entrance effects beyond named effects
|
|
374
|
+
- When creating unique item position flows
|
|
375
|
+
- For multi-stage item animations
|
|
376
|
+
- When coordinating item wrapper with content animations
|
|
377
|
+
|
|
378
|
+
**Pattern**:
|
|
379
|
+
```typescript
|
|
380
|
+
{
|
|
381
|
+
key: '[ITEM_KEY]',
|
|
382
|
+
trigger: 'viewProgress',
|
|
383
|
+
effects: [
|
|
384
|
+
{
|
|
385
|
+
key: '[ITEM_KEY]',
|
|
386
|
+
keyframeEffect: {
|
|
387
|
+
name: '[UNIQUE_KEYFRAME_EFFECT_NAME]',
|
|
388
|
+
keyframes: [
|
|
389
|
+
{ [CSS_PROPERTY_1]: '[START_VALUE_1]', [CSS_PROPERTY_2]: '[START_VALUE_2]' },
|
|
390
|
+
{ [CSS_PROPERTY_1]: '[MID_VALUE_1]' },
|
|
391
|
+
{ [CSS_PROPERTY_1]: '[END_VALUE_1]', [CSS_PROPERTY_2]: '[END_VALUE_2]' }
|
|
392
|
+
]
|
|
393
|
+
},
|
|
394
|
+
rangeStart: { name: '[RANGE_TYPE]', offset: { type: 'percentage', value: [START_PERCENTAGE] } },
|
|
395
|
+
rangeEnd: { name: '[RANGE_TYPE]', offset: { type: 'percentage', value: [END_PERCENTAGE] } },
|
|
396
|
+
easing: '[EASING_FUNCTION]',
|
|
397
|
+
fill: 'both',
|
|
398
|
+
effectId: '[UNIQUE_EFFECT_ID]'
|
|
399
|
+
}
|
|
400
|
+
]
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
**Variables**:
|
|
405
|
+
- `[ITEM_KEY]`: Unique identifier for individual list items
|
|
406
|
+
- `[RANGE_TYPE]`: 'entry', 'exit', or 'contain' depending on animation phase
|
|
407
|
+
- `[EASING_FUNCTION]`: Easing function to use
|
|
408
|
+
- Other variables same as Rule 4
|
|
409
|
+
|
|
410
|
+
**Example - Complex Item Entrance**:
|
|
411
|
+
```typescript
|
|
412
|
+
{
|
|
413
|
+
key: 'timeline-item',
|
|
414
|
+
trigger: 'viewProgress',
|
|
415
|
+
effects: [
|
|
416
|
+
{
|
|
417
|
+
key: 'timeline-item',
|
|
418
|
+
keyframeEffect: {
|
|
419
|
+
name: 'timeline-entrance',
|
|
420
|
+
keyframes: [
|
|
421
|
+
{ opacity: '0', transform: 'translateY(100px) scale(0.8) rotate(5deg)', filter: 'blur(10px)', boxShadow: '0 0 0 rgb(0 0 0 / 0)' },
|
|
422
|
+
{ opacity: '0.5', transform: 'translateY(20px) scale(0.95) rotate(1deg)', filter: 'blur(2px)', boxShadow: '0 10px 20px rgb(0 0 0 / 0.1)' },
|
|
423
|
+
{ opacity: '1', transform: 'translateY(0) scale(1) rotate(0deg)', filter: 'blur(0)', boxShadow: '0 20px 40px rgb(0 0 0 / 0.15)' }
|
|
424
|
+
]
|
|
425
|
+
},
|
|
426
|
+
rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
|
|
427
|
+
rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 80 } },
|
|
428
|
+
easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
|
|
429
|
+
fill: 'both',
|
|
430
|
+
effectId: 'timeline-entrance'
|
|
431
|
+
}
|
|
432
|
+
]
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
**Example - Item Exit Sequence**:
|
|
437
|
+
```typescript
|
|
438
|
+
{
|
|
439
|
+
key: 'card-item',
|
|
440
|
+
trigger: 'viewProgress',
|
|
441
|
+
effects: [
|
|
442
|
+
{
|
|
443
|
+
key: 'card-item',
|
|
444
|
+
keyframeEffect: {
|
|
445
|
+
name: 'card-exit-6',
|
|
446
|
+
keyframes: [
|
|
447
|
+
{ opacity: '1', transform: 'scale(1) rotate(0deg)', filter: 'brightness(1)' },
|
|
448
|
+
{ opacity: '0.7', transform: 'scale(0.9) rotate(-2deg)', filter: 'brightness(0.8)' },
|
|
449
|
+
{ opacity: '0', transform: 'scale(0.8) rotate(-5deg)', filter: 'brightness(0.6)' }
|
|
450
|
+
]
|
|
451
|
+
},
|
|
452
|
+
rangeStart: { name: 'exit', offset: { type: 'percentage', value: 20 } },
|
|
453
|
+
rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 100 } },
|
|
454
|
+
easing: 'ease-in',
|
|
455
|
+
fill: 'both',
|
|
456
|
+
effectId: 'card-exit'
|
|
457
|
+
}
|
|
458
|
+
]
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## Rule 6: Staggered List Animations with Custom Timing
|
|
465
|
+
|
|
466
|
+
**Use Case**: Coordinated animations across multiple list items with each individual item used as the viewProgress trigger and custom timing patterns (e.g., wave animations, linear stagger, exponential stagger, reverse stagger)
|
|
467
|
+
|
|
468
|
+
**When to Apply**:
|
|
469
|
+
- For creating wave-like animation propagation
|
|
470
|
+
- When implementing linear or exponential stagger patterns
|
|
471
|
+
- For reverse-order animations (exit effects)
|
|
472
|
+
|
|
473
|
+
**Pattern**:
|
|
474
|
+
```typescript
|
|
475
|
+
{
|
|
476
|
+
effects: {
|
|
477
|
+
[EFFECT_ID]: {
|
|
478
|
+
[EFFECT_TYPE]: [EFFECT_DEFINITION],
|
|
479
|
+
rangeStart: { name: '[RANGE_TYPE]', offset: { type: 'percentage', value: [START_PERCENTAGE] } },
|
|
480
|
+
rangeEnd: { name: '[RANGE_TYPE]', offset: { type: 'percentage', value: [END_PERCENTAGE] } },
|
|
481
|
+
easing: '[EASING_FUNCTION]'
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
interactions: [
|
|
485
|
+
{
|
|
486
|
+
key: '[ITEM_SELECTOR_N]',
|
|
487
|
+
trigger: 'viewProgress',
|
|
488
|
+
effects: [
|
|
489
|
+
{
|
|
490
|
+
effectId: '[EFFECT_ID]'
|
|
491
|
+
}
|
|
492
|
+
]
|
|
493
|
+
},
|
|
494
|
+
// ... repeat for each item
|
|
495
|
+
]
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**Example - Linear Staggered Card Entrance**:
|
|
500
|
+
```typescript
|
|
501
|
+
{
|
|
502
|
+
effects: {
|
|
503
|
+
'card-entrance': {
|
|
504
|
+
namedEffect: {
|
|
505
|
+
type: 'SlideScroll'
|
|
506
|
+
},
|
|
507
|
+
rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
|
|
508
|
+
rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 60 } },
|
|
509
|
+
easing: 'linear'
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
interactions: [
|
|
513
|
+
{
|
|
514
|
+
key: 'card-1',
|
|
515
|
+
trigger: 'viewProgress',
|
|
516
|
+
effects: [
|
|
517
|
+
{
|
|
518
|
+
effectId: 'card-entrance'
|
|
519
|
+
}
|
|
520
|
+
]
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
key: 'card-2',
|
|
524
|
+
trigger: 'viewProgress',
|
|
525
|
+
effects: [
|
|
526
|
+
{
|
|
527
|
+
effectId: 'card-entrance'
|
|
528
|
+
}
|
|
529
|
+
]
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
key: 'card-3',
|
|
533
|
+
trigger: 'viewProgress',
|
|
534
|
+
effects: [
|
|
535
|
+
{
|
|
536
|
+
effectId: 'card-entrance'
|
|
537
|
+
}
|
|
538
|
+
]
|
|
539
|
+
},
|
|
540
|
+
]
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**Example - Exponential Stagger for Dramatic Effect**:
|
|
545
|
+
```typescript
|
|
546
|
+
{
|
|
547
|
+
effects: {
|
|
548
|
+
'feature-entrance': {
|
|
549
|
+
keyframeEffect: {
|
|
550
|
+
name: 'feature-entrance',
|
|
551
|
+
keyframes: [
|
|
552
|
+
{ opacity: '0', transform: 'translateY(50px) scale(0.9)' },
|
|
553
|
+
{ opacity: '1', transform: 'translateY(0) scale(1)' }
|
|
554
|
+
]
|
|
555
|
+
},
|
|
556
|
+
rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
|
|
557
|
+
rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 100 } },
|
|
558
|
+
easing: 'expoOut',
|
|
559
|
+
fill: 'both'
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
interactions: [
|
|
563
|
+
{
|
|
564
|
+
key: 'feature-1',
|
|
565
|
+
trigger: 'viewProgress',
|
|
566
|
+
effects: [
|
|
567
|
+
{
|
|
568
|
+
effectId: 'feature-entrance'
|
|
569
|
+
}
|
|
570
|
+
]
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
key: 'feature-2',
|
|
574
|
+
trigger: 'viewProgress',
|
|
575
|
+
effects: [
|
|
576
|
+
{
|
|
577
|
+
effectId: 'feature-entrance'
|
|
578
|
+
}
|
|
579
|
+
]
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
key: 'feature-3',
|
|
583
|
+
trigger: 'viewProgress',
|
|
584
|
+
effects: [
|
|
585
|
+
{
|
|
586
|
+
effectId: 'feature-entrance'
|
|
587
|
+
}
|
|
588
|
+
]
|
|
589
|
+
},
|
|
590
|
+
]
|
|
591
|
+
}
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
## Rule 7: Dynamic Content Animations with Custom Effects
|
|
597
|
+
|
|
598
|
+
**Use Case**: JavaScript-powered list animations with custom effects for complex interactions that require calculations or dynamic content updates (e.g., scroll counters, progress tracking, data visualization, dynamic text updates)
|
|
599
|
+
|
|
600
|
+
**When to Apply**:
|
|
601
|
+
- For animations requiring complex calculations
|
|
602
|
+
- When integrating with data visualization
|
|
603
|
+
- For dynamic content updates based on scroll
|
|
604
|
+
- When creating interactive scroll-driven counters
|
|
605
|
+
|
|
606
|
+
**Pattern**:
|
|
607
|
+
```typescript
|
|
608
|
+
{
|
|
609
|
+
key: '[LIST_CONTAINER_SELECTOR]',
|
|
610
|
+
trigger: 'viewProgress',
|
|
611
|
+
effects: [
|
|
612
|
+
{
|
|
613
|
+
key: '[DYNAMIC_CONTENT_SELECTOR]',
|
|
614
|
+
customEffect: (element, progress, params) => {
|
|
615
|
+
// progress is 0-1 representing scroll position within range
|
|
616
|
+
[CUSTOM_CALCULATION_LOGIC]
|
|
617
|
+
[DYNAMIC_CONTENT_UPDATE]
|
|
618
|
+
[VISUAL_PROPERTY_UPDATES]
|
|
619
|
+
},
|
|
620
|
+
rangeStart: { name: '[RANGE_TYPE]', offset: { type: 'percentage', value: [START_PERCENTAGE] } },
|
|
621
|
+
rangeEnd: { name: '[RANGE_TYPE]', offset: { type: 'percentage', value: [END_PERCENTAGE] } },
|
|
622
|
+
fill: 'both',
|
|
623
|
+
effectId: '[UNIQUE_EFFECT_ID]'
|
|
624
|
+
}
|
|
625
|
+
]
|
|
626
|
+
}
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
**Variables**:
|
|
630
|
+
- `[LIST_CONTAINER_KEY]`: Unique identifier for list or section containing dynamic content
|
|
631
|
+
- `[DYNAMIC_CONTENT_KEY]`: Unique identifier for elements that will be dynamically updated
|
|
632
|
+
- `[CUSTOM_CALCULATION_LOGIC]`: JavaScript calculations based on progress
|
|
633
|
+
- `[DYNAMIC_CONTENT_UPDATE]`: Code to update element content
|
|
634
|
+
- `[VISUAL_PROPERTY_UPDATES]`: Code to update visual properties
|
|
635
|
+
|
|
636
|
+
**Example - Scroll-Driven Counter in List**:
|
|
637
|
+
```typescript
|
|
638
|
+
{
|
|
639
|
+
key: 'stats-list-container',
|
|
640
|
+
trigger: 'viewProgress',
|
|
641
|
+
effects: [
|
|
642
|
+
{
|
|
643
|
+
key: 'stat-counter',
|
|
644
|
+
customEffect: (element, progress) => {
|
|
645
|
+
const targetValue = parseInt(element.dataset.targetValue) || 100;
|
|
646
|
+
const currentValue = Math.floor(targetValue * progress);
|
|
647
|
+
const percentage = Math.floor(progress * 100);
|
|
648
|
+
|
|
649
|
+
// Update counter text
|
|
650
|
+
element.textContent = currentValue.toLocaleString();
|
|
651
|
+
|
|
652
|
+
// Update visual properties based on progress
|
|
653
|
+
element.style.color = `hsl(${progress * 120}, 70%, 50%)`; // Green to red progression
|
|
654
|
+
element.style.transform = `scale(${0.8 + progress * 0.2})`; // Subtle scale effect
|
|
655
|
+
|
|
656
|
+
// Update progress bar if exists
|
|
657
|
+
const progressBar = element.querySelector('.progress-bar');
|
|
658
|
+
if (progressBar) {
|
|
659
|
+
progressBar.style.width = `${percentage}%`;
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
|
|
663
|
+
rangeEnd: { name: 'exit', offset: { type: 'percentage', value: 100 } },
|
|
664
|
+
fill: 'both',
|
|
665
|
+
effectId: 'stats-counter'
|
|
666
|
+
}
|
|
667
|
+
]
|
|
668
|
+
}
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
**Example - Interactive List Progress Tracking**:
|
|
672
|
+
```typescript
|
|
673
|
+
{
|
|
674
|
+
key: 'task-list',
|
|
675
|
+
trigger: 'viewProgress',
|
|
676
|
+
effects: [
|
|
677
|
+
{
|
|
678
|
+
key: 'task-item',
|
|
679
|
+
customEffect: (element, progress) => {
|
|
680
|
+
const items = element.closest('interact-element')?.querySelectorAll('.task-item') || [];
|
|
681
|
+
const totalItems = items.length;
|
|
682
|
+
const elementIndex = Array.from(items).indexOf(element);
|
|
683
|
+
|
|
684
|
+
// Calculate staggered progress for each item
|
|
685
|
+
const itemStartProgress = elementIndex / totalItems;
|
|
686
|
+
const itemEndProgress = (elementIndex + 1) / totalItems;
|
|
687
|
+
|
|
688
|
+
// Calculate individual item progress
|
|
689
|
+
let itemProgress = 0;
|
|
690
|
+
if (progress > itemStartProgress) {
|
|
691
|
+
itemProgress = Math.min(1, (progress - itemStartProgress) / (itemEndProgress - itemStartProgress));
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// Update visual state
|
|
695
|
+
const checkbox = element.querySelector('.task-checkbox');
|
|
696
|
+
const taskText = element.querySelector('.task-text');
|
|
697
|
+
|
|
698
|
+
if (itemProgress > 0.5) {
|
|
699
|
+
element.classList.add('active');
|
|
700
|
+
checkbox.style.transform = `scale(${0.8 + itemProgress * 0.4})`;
|
|
701
|
+
checkbox.style.opacity = itemProgress;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
if (itemProgress > 0.8) {
|
|
705
|
+
element.classList.add('completed');
|
|
706
|
+
taskText.style.textDecoration = 'line-through';
|
|
707
|
+
taskText.style.opacity = '0.7';
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Update overall progress indicator
|
|
711
|
+
const progressIndicator = document.querySelector('#overall-progress');
|
|
712
|
+
if (progressIndicator && elementIndex === 0) {
|
|
713
|
+
progressIndicator.style.width = `${progress * 100}%`;
|
|
714
|
+
progressIndicator.textContent = `${Math.floor(progress * 100)}% Complete`;
|
|
715
|
+
}
|
|
716
|
+
},
|
|
717
|
+
rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
|
|
718
|
+
rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
|
|
719
|
+
fill: 'both',
|
|
720
|
+
effectId: 'task-progress'
|
|
721
|
+
}
|
|
722
|
+
]
|
|
723
|
+
}
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
---
|
|
727
|
+
|
|
728
|
+
## Advanced Patterns and Combinations
|
|
729
|
+
|
|
730
|
+
### Multi-Layer List Coordination
|
|
731
|
+
Coordinating container, items, and content simultaneously:
|
|
732
|
+
|
|
733
|
+
```typescript
|
|
734
|
+
{
|
|
735
|
+
key: 'complex-list-section',
|
|
736
|
+
trigger: 'viewProgress',
|
|
737
|
+
effects: [
|
|
738
|
+
// Background layer
|
|
739
|
+
{
|
|
740
|
+
key: 'list-background',
|
|
741
|
+
keyframeEffect: {
|
|
742
|
+
name: 'background-parallax',
|
|
743
|
+
keyframes: [
|
|
744
|
+
{ transform: 'scale(1.1) translateY(0)', filter: 'blur(0)' },
|
|
745
|
+
{ transform: 'scale(1) translateY(-50px)', filter: 'blur(2px)' }
|
|
746
|
+
]
|
|
747
|
+
},
|
|
748
|
+
rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
|
|
749
|
+
rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
|
|
750
|
+
easing: 'linear',
|
|
751
|
+
fill: 'both'
|
|
752
|
+
},
|
|
753
|
+
// Container layer
|
|
754
|
+
{
|
|
755
|
+
key: 'list-container',
|
|
756
|
+
keyframeEffect: {
|
|
757
|
+
name: 'container-slide',
|
|
758
|
+
keyframes: [
|
|
759
|
+
{ transform: 'translateX(0)' },
|
|
760
|
+
{ transform: 'translateX(-50%)' }
|
|
761
|
+
]
|
|
762
|
+
},
|
|
763
|
+
rangeStart: { name: 'contain', offset: { type: 'percentage', value: 0 } },
|
|
764
|
+
rangeEnd: { name: 'contain', offset: { type: 'percentage', value: 100 } },
|
|
765
|
+
easing: 'linear',
|
|
766
|
+
fill: 'both'
|
|
767
|
+
},
|
|
768
|
+
// Foreground decorations
|
|
769
|
+
{
|
|
770
|
+
key: 'list-decorations',
|
|
771
|
+
keyframeEffect: {
|
|
772
|
+
name: 'decorations-parallax',
|
|
773
|
+
keyframes: [
|
|
774
|
+
{ transform: 'translateY(0)', opacity: '0.8' },
|
|
775
|
+
{ transform: 'translateY(-100px)', opacity: '1' }
|
|
776
|
+
]
|
|
777
|
+
},
|
|
778
|
+
rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
|
|
779
|
+
rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } },
|
|
780
|
+
easing: 'linear',
|
|
781
|
+
fill: 'both'
|
|
782
|
+
}
|
|
783
|
+
]
|
|
784
|
+
}
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
### Responsive List Animations
|
|
788
|
+
Adaptive patterns based on screen size and device capabilities:
|
|
789
|
+
|
|
790
|
+
```typescript
|
|
791
|
+
// Desktop version with complex effects
|
|
792
|
+
{
|
|
793
|
+
key: 'responsive-list',
|
|
794
|
+
trigger: 'viewProgress',
|
|
795
|
+
conditions: ['desktop-only', 'prefers-motion'],
|
|
796
|
+
effects: [
|
|
797
|
+
{
|
|
798
|
+
key: 'list-item',
|
|
799
|
+
keyframeEffect: {
|
|
800
|
+
name: 'list-item-complex',
|
|
801
|
+
keyframes: [
|
|
802
|
+
{ transform: 'translateY(-20px) rotateY(5deg)', boxShadow: '0 20px 40px rgb(0 0 0 / 0.15)' },
|
|
803
|
+
{ transform: 'translateY(0) rotateY(0deg)', boxShadow: '0 0 0 rgb(0 0 0 / 0)' }
|
|
804
|
+
]
|
|
805
|
+
},
|
|
806
|
+
rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
|
|
807
|
+
rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 80 } },
|
|
808
|
+
easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
|
|
809
|
+
fill: 'both'
|
|
810
|
+
}
|
|
811
|
+
]
|
|
812
|
+
},
|
|
813
|
+
// Mobile version with simplified effects
|
|
814
|
+
{
|
|
815
|
+
key: 'responsive-list',
|
|
816
|
+
trigger: 'viewProgress',
|
|
817
|
+
conditions: ['mobile-only'],
|
|
818
|
+
effects: [
|
|
819
|
+
{
|
|
820
|
+
key: 'list-item',
|
|
821
|
+
keyframeEffect: {
|
|
822
|
+
name: 'list-item-simple',
|
|
823
|
+
keyframes: [
|
|
824
|
+
{ opacity: '0', transform: 'translateY(30px)' },
|
|
825
|
+
{ opacity: '1', transform: 'translateY(0)' }
|
|
826
|
+
]
|
|
827
|
+
},
|
|
828
|
+
rangeStart: { name: 'entry', offset: { type: 'percentage', value: 0 } },
|
|
829
|
+
rangeEnd: { name: 'entry', offset: { type: 'percentage', value: 60 } },
|
|
830
|
+
easing: 'ease-out',
|
|
831
|
+
fill: 'both'
|
|
832
|
+
}
|
|
833
|
+
]
|
|
834
|
+
}
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
---
|
|
838
|
+
|
|
839
|
+
## Best Practices for List Scroll Animations
|
|
840
|
+
|
|
841
|
+
### Performance Guidelines
|
|
842
|
+
1. **Use hardware-accelerated properties**: `transform`, `opacity`, `filter` for smooth animations
|
|
843
|
+
2. **Limit concurrent animations**: Avoid animating too many items simultaneously
|
|
844
|
+
3. **Use position:sticky for scrolling effects**: Animate elements while they're stuck in position and not scrolling with the page
|
|
845
|
+
4. **Consider `will-change` property**: When doing complex style animations inside custom effects that the browser can not predict automatically
|
|
846
|
+
|
|
847
|
+
### Range Selection Guidelines
|
|
848
|
+
1. **Container animations**: Use `contain` range for sticky container effects
|
|
849
|
+
2. **Item entrance**: Use `entry` range (0-60%) for natural reveals
|
|
850
|
+
3. **Item exit**: Use `exit` range (20-100%) for smooth dismissals
|
|
851
|
+
4. **Content coordination**: Use same timeline with `cover`/`contain` range and staggered offsets, or use a different timeline per item with same range and offsets
|
|
852
|
+
|
|
853
|
+
### User Experience Guidelines
|
|
854
|
+
1. **Keep animations subtle**: Avoid overwhelming users with excessive motion
|
|
855
|
+
2. **Maintain content readability**: Ensure text remains legible during animations
|
|
856
|
+
3. **Provide reduced motion alternatives**: Respect `prefers-reduced-motion` setting
|
|
857
|
+
|
|
858
|
+
### Accessibility Considerations
|
|
859
|
+
1. **Respect motion preferences**: Include `prefers-motion` conditions
|
|
860
|
+
2. **Provide keyboard navigation**: Ensure list remains navigable during animations
|
|
861
|
+
3. **Maintain focus management**: Don't break focus states with animations
|
|
862
|
+
4. **Ensure content accessibility**: Keep content accessible throughout animation states
|
|
863
|
+
|
|
864
|
+
### Common Use Cases by Pattern
|
|
865
|
+
|
|
866
|
+
**Sticky Container (Rule 1)**:
|
|
867
|
+
- Horizontal scrolling galleries
|
|
868
|
+
- Timeline navigation
|
|
869
|
+
- Product showcase carousels
|
|
870
|
+
- Feature comparison tables
|
|
871
|
+
|
|
872
|
+
**Sticky Items (Rule 2)**:
|
|
873
|
+
- Progressive story reveals
|
|
874
|
+
- Step-by-step processes
|
|
875
|
+
- Card-based layouts
|
|
876
|
+
- Interactive portfolios
|
|
877
|
+
|
|
878
|
+
**Content Animations (Rule 3)**:
|
|
879
|
+
- Text reveals within cards
|
|
880
|
+
- Image animations in galleries
|
|
881
|
+
- Icon animations in feature lists
|
|
882
|
+
- Progressive data visualization
|
|
883
|
+
|
|
884
|
+
**Keyframe Effects (Rules 4-5)**:
|
|
885
|
+
- Complex brand animations
|
|
886
|
+
- Multi-property transformations
|
|
887
|
+
- Responsive design adaptations
|
|
888
|
+
- Advanced visual effects
|
|
889
|
+
|
|
890
|
+
**Staggered Animations (Rule 6)**:
|
|
891
|
+
- Team member introductions
|
|
892
|
+
- Product grid reveals
|
|
893
|
+
- Feature list presentations
|
|
894
|
+
- Testimonial carousels
|
|
895
|
+
|
|
896
|
+
**Dynamic Content (Rule 7)**:
|
|
897
|
+
- Statistics counters
|
|
898
|
+
- Progress tracking
|
|
899
|
+
- Data visualization
|
|
900
|
+
- Interactive dashboards
|