@wix/interact 1.93.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.
- 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-C8QxOkui.mjs +7940 -0
- package/dist/index-C8QxOkui.mjs.map +1 -0
- package/dist/index-DEPRHaUt.js +18 -0
- package/dist/index-DEPRHaUt.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types/core/Interact.d.ts +17 -7
- package/dist/types/core/Interact.d.ts.map +1 -0
- package/dist/types/core/InteractionController.d.ts +19 -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 +23 -10
- 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} +115 -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,634 @@
|
|
|
1
|
+
# Effects and Animations
|
|
2
|
+
|
|
3
|
+
Effects define what visual changes happen when a trigger fires. `@wix/interact` integrates seamlessly with `@wix/motion` to provide three types of effects: **Time Effects**, **Scrub Effects**, and **Transition Effects**.
|
|
4
|
+
|
|
5
|
+
## Overview of Effect Types
|
|
6
|
+
|
|
7
|
+
| Effect Type | Best For | Timing | Use Cases |
|
|
8
|
+
|-------------|----------|---------|-----------|
|
|
9
|
+
| **Time Effects** | Traditional animations | time-based | Entrance animations, Loop animations |
|
|
10
|
+
| **Scrub Effects** | Scroll-driven and Pointer-driven animations | Progress-based | Parallax effects, horizontal-sliding effect |
|
|
11
|
+
| **Transition Effects** | CSS property changes | Duration-based | Micro-interactions, simple state changes |
|
|
12
|
+
|
|
13
|
+
## Time Effects
|
|
14
|
+
|
|
15
|
+
Time effects are traditional time-based animations perfect for entrance effects, hover interactions, and click responses.
|
|
16
|
+
|
|
17
|
+
### Using Named Effects
|
|
18
|
+
|
|
19
|
+
Named effects are pre-built animations from `@wix/motion`:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
{
|
|
23
|
+
key: 'my-element',
|
|
24
|
+
namedEffect: { type: 'FadeIn' }, // Predefined animation
|
|
25
|
+
duration: 800, // Animation duration in ms
|
|
26
|
+
easing: 'ease-out', // Animation timing curve
|
|
27
|
+
delay: 200, // Delay before starting
|
|
28
|
+
iterations: 1, // How many times to repeat
|
|
29
|
+
fill: 'forwards' // Animation fill mode
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Available Named Effects
|
|
34
|
+
|
|
35
|
+
Entrance named effects include:
|
|
36
|
+
|
|
37
|
+
- `ArcIn`
|
|
38
|
+
- `BlurIn`
|
|
39
|
+
- `BounceIn`
|
|
40
|
+
- `ExpandIn`
|
|
41
|
+
- `FadeIn`
|
|
42
|
+
- `FlipIn`
|
|
43
|
+
- `FloatIn`
|
|
44
|
+
- `FoldIn`
|
|
45
|
+
- `GlitchIn`
|
|
46
|
+
- `GrowIn`
|
|
47
|
+
- `RevealIn`
|
|
48
|
+
- `ShapeIn`
|
|
49
|
+
- `ShuttersIn`
|
|
50
|
+
- `SlideIn`
|
|
51
|
+
- `SpinIn`
|
|
52
|
+
- `TiltIn`
|
|
53
|
+
- `TurnIn`
|
|
54
|
+
- `WinkIn`
|
|
55
|
+
|
|
56
|
+
### Using Keyframe Effects
|
|
57
|
+
|
|
58
|
+
For custom animations, use keyframe effects:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
{
|
|
62
|
+
key: 'custom-animation',
|
|
63
|
+
keyframeEffect: {
|
|
64
|
+
name: 'custom-animation',
|
|
65
|
+
keyframes: [
|
|
66
|
+
{ transform: 'scale(1) rotate(0deg)', opacity: '1', backgroundColor: '#ff0000' },
|
|
67
|
+
{ transform: 'scale(1.2) rotate(180deg)', opacity: '0.8', backgroundColor: '#0000ff' }
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
duration: 600,
|
|
71
|
+
easing: 'cubic-bezier(0.4, 0, 0.2, 1)'
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Advanced Time Effect Properties
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
{
|
|
79
|
+
key: 'advanced-element',
|
|
80
|
+
namedEffect: { type: 'SlideIn' },
|
|
81
|
+
duration: 1000,
|
|
82
|
+
easing: 'ease-in-out',
|
|
83
|
+
iterations: 2, // Repeat twice
|
|
84
|
+
alternate: true, // Reverse on alternate iterations
|
|
85
|
+
fill: 'both', // Keep start and end states
|
|
86
|
+
reversed: false, // Play backwards
|
|
87
|
+
delay: 500, // Wait before starting
|
|
88
|
+
effectId: 'my-animation' // Unique identifier for chaining
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Real-World Example: Card Entrance
|
|
93
|
+
```typescript
|
|
94
|
+
{
|
|
95
|
+
key: 'product-card',
|
|
96
|
+
trigger: 'viewEnter',
|
|
97
|
+
params: { type: 'once', threshold: 0.3 },
|
|
98
|
+
effects: [
|
|
99
|
+
{
|
|
100
|
+
keyframeEffect: {
|
|
101
|
+
name: 'card-entrance',
|
|
102
|
+
keyframes: [
|
|
103
|
+
{ opacity: '0', transform: 'translateY(60px) scale(0.9)' },
|
|
104
|
+
{ opacity: '1', transform: 'translateY(0) scale(1)' }
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
duration: 800,
|
|
108
|
+
easing: 'cubic-bezier(0.16, 1, 0.3, 1)', // Custom easing
|
|
109
|
+
fill: 'forwards'
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Scrub Effects
|
|
116
|
+
|
|
117
|
+
Scrub effects are progress-based animations that respond to scroll position or pointer position.
|
|
118
|
+
|
|
119
|
+
### Basic Scrub Effect
|
|
120
|
+
```typescript
|
|
121
|
+
{
|
|
122
|
+
key: 'parallax-bg',
|
|
123
|
+
keyframeEffect: {
|
|
124
|
+
name: 'parallax',
|
|
125
|
+
keyframes: [
|
|
126
|
+
{ transform: 'translateY(0)' },
|
|
127
|
+
{ transform: 'translateY(-200px)' }
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
// No duration - controlled by scroll/pointer progress
|
|
131
|
+
easing: 'linear',
|
|
132
|
+
rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
|
|
133
|
+
rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } }
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Range Configuration
|
|
138
|
+
Control when the animation starts and stops:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
{
|
|
142
|
+
key: 'fade-element',
|
|
143
|
+
keyframeEffect: {
|
|
144
|
+
name: 'fade',
|
|
145
|
+
keyframes: [
|
|
146
|
+
{ opacity: '1' },
|
|
147
|
+
{ opacity: '0' }
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
rangeStart: { name: 'cover', offset: { type: 'percentage', value: 30 } }, // Start at 30% scroll
|
|
151
|
+
rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 80 } } // End at 80% scroll
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Advanced Pointer Properties
|
|
156
|
+
|
|
157
|
+
TBD
|
|
158
|
+
|
|
159
|
+
### Real-World Example: Parallax Hero
|
|
160
|
+
```typescript
|
|
161
|
+
{
|
|
162
|
+
key: 'hero-section',
|
|
163
|
+
trigger: 'viewProgress',
|
|
164
|
+
effects: [
|
|
165
|
+
// Background image moves slower
|
|
166
|
+
{
|
|
167
|
+
key: 'hero-bg',
|
|
168
|
+
keyframeEffect: {
|
|
169
|
+
name: 'image-parallax',
|
|
170
|
+
keyframes: [
|
|
171
|
+
{ transform: 'translateY(0)' },
|
|
172
|
+
{ transform: 'translateY(-150px)' }
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
rangeStart: { name: 'cover', offset: { type: 'percentage', value: 0 } },
|
|
176
|
+
rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 100 } }
|
|
177
|
+
},
|
|
178
|
+
// Text fades out faster
|
|
179
|
+
{
|
|
180
|
+
key: 'hero-text',
|
|
181
|
+
keyframeEffect: {
|
|
182
|
+
name: 'text-fade',
|
|
183
|
+
keyframes: [
|
|
184
|
+
{ opacity: '1', transform: 'translateY(0)' },
|
|
185
|
+
{ opacity: '0', transform: 'translateY(-50px)' }
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
rangeStart: { name: 'cover', offset: { type: 'percentage', value: 20 } },
|
|
189
|
+
rangeEnd: { name: 'cover', offset: { type: 'percentage', value: 60 } }
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Transition Effects
|
|
196
|
+
|
|
197
|
+
Transition effects create smooth CSS property changes with automatic transitions.
|
|
198
|
+
|
|
199
|
+
### Basic Transition Effect
|
|
200
|
+
```typescript
|
|
201
|
+
{
|
|
202
|
+
key: 'theme-button',
|
|
203
|
+
transition: {
|
|
204
|
+
duration: 300,
|
|
205
|
+
delay: 0,
|
|
206
|
+
easing: 'ease-in-out',
|
|
207
|
+
styleProperties: [
|
|
208
|
+
{ name: 'backgroundColor', value: '#2563eb' },
|
|
209
|
+
{ name: 'color', value: '#ffffff' },
|
|
210
|
+
{ name: 'borderRadius', value: '12px' }
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Individual Property Transitions
|
|
217
|
+
For different timing per property:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
{
|
|
221
|
+
key: 'complex-transition',
|
|
222
|
+
transitionProperties: [
|
|
223
|
+
{
|
|
224
|
+
name: 'backgroundColor',
|
|
225
|
+
value: '#ef4444',
|
|
226
|
+
duration: 200,
|
|
227
|
+
delay: 0,
|
|
228
|
+
easing: 'ease-out'
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: 'transform',
|
|
232
|
+
value: 'scale(1.05)',
|
|
233
|
+
duration: 300,
|
|
234
|
+
delay: 100,
|
|
235
|
+
easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
|
|
236
|
+
}
|
|
237
|
+
]
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Real-World Example: Theme Switcher
|
|
242
|
+
```typescript
|
|
243
|
+
{
|
|
244
|
+
key: 'theme-toggle',
|
|
245
|
+
trigger: 'click',
|
|
246
|
+
params: { type: 'alternate' },
|
|
247
|
+
effects: [
|
|
248
|
+
{
|
|
249
|
+
key: 'page-body',
|
|
250
|
+
transition: {
|
|
251
|
+
duration: 400,
|
|
252
|
+
easing: 'ease-in-out',
|
|
253
|
+
styleProperties: [
|
|
254
|
+
{ name: '--bg-color', value: '#1a1a1a' },
|
|
255
|
+
{ name: '--text-color', value: '#ffffff' },
|
|
256
|
+
{ name: '--accent-color', value: '#3b82f6' }
|
|
257
|
+
]
|
|
258
|
+
},
|
|
259
|
+
effectId: 'theme-switch'
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Custom Effects
|
|
266
|
+
|
|
267
|
+
For complete control, use custom effects with JavaScript functions:
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
{
|
|
271
|
+
key: 'custom-element',
|
|
272
|
+
customEffect: (element, progress) => {
|
|
273
|
+
// progress is 0-1 for scrub effects, or animation timing for time effects
|
|
274
|
+
const scale = 1 + (progress * 0.2);
|
|
275
|
+
const rotation = progress * 360;
|
|
276
|
+
|
|
277
|
+
element.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
278
|
+
element.style.filter = `hue-rotate(${progress * 180}deg)`;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Advanced Custom Effect
|
|
284
|
+
```typescript
|
|
285
|
+
{
|
|
286
|
+
key: 'particle-system',
|
|
287
|
+
customEffect: (element, progress, params) => {
|
|
288
|
+
const particles = element.querySelectorAll('.particle');
|
|
289
|
+
|
|
290
|
+
particles.forEach((particle, index) => {
|
|
291
|
+
const delay = index * 0.1;
|
|
292
|
+
const adjustedProgress = Math.max(0, progress - delay);
|
|
293
|
+
|
|
294
|
+
particle.style.opacity = adjustedProgress;
|
|
295
|
+
particle.style.transform = `
|
|
296
|
+
translateY(${(1 - adjustedProgress) * 50}px)
|
|
297
|
+
rotate(${adjustedProgress * 180}deg)
|
|
298
|
+
`;
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Combining Multiple Effects
|
|
305
|
+
|
|
306
|
+
You can apply multiple effects to different targets from a single trigger:
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
{
|
|
310
|
+
key: 'card-container',
|
|
311
|
+
trigger: 'hover',
|
|
312
|
+
effects: [
|
|
313
|
+
// Card itself
|
|
314
|
+
{
|
|
315
|
+
key: 'card-container',
|
|
316
|
+
keyframeEffect: {
|
|
317
|
+
name: 'card-shadow',
|
|
318
|
+
keyframes: [
|
|
319
|
+
{ transform: 'translateY(0)', boxShadow: '0 4px 6px rgba(0,0,0,0.1)' },
|
|
320
|
+
{ transform: 'translateY(-8px)', boxShadow: '0 20px 25px rgba(0,0,0,0.15)' }
|
|
321
|
+
]
|
|
322
|
+
},
|
|
323
|
+
duration: 200,
|
|
324
|
+
easing: 'ease-out'
|
|
325
|
+
},
|
|
326
|
+
// Card image
|
|
327
|
+
{
|
|
328
|
+
key: 'card-image',
|
|
329
|
+
namedEffect: {
|
|
330
|
+
type: 'Scale'
|
|
331
|
+
},
|
|
332
|
+
duration: 300,
|
|
333
|
+
easing: 'ease-out'
|
|
334
|
+
},
|
|
335
|
+
// Card title
|
|
336
|
+
{
|
|
337
|
+
key: 'card-title',
|
|
338
|
+
keyframeEffect: {
|
|
339
|
+
name: 'title-color',
|
|
340
|
+
keyframes: [
|
|
341
|
+
{ color: '#374151' },
|
|
342
|
+
{ color: '#2563eb' }
|
|
343
|
+
]
|
|
344
|
+
},
|
|
345
|
+
duration: 150
|
|
346
|
+
},
|
|
347
|
+
// Card button
|
|
348
|
+
{
|
|
349
|
+
key: 'card-button',
|
|
350
|
+
transition: {
|
|
351
|
+
duration: 200,
|
|
352
|
+
styleProperties: [
|
|
353
|
+
{ name: 'opacity', value: '1' },
|
|
354
|
+
{ name: 'transform', value: 'translateY(0)' }
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
]
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## Animation Targeting
|
|
363
|
+
|
|
364
|
+
### Self-Targeting
|
|
365
|
+
Most common pattern - effect applies to the trigger element:
|
|
366
|
+
```typescript
|
|
367
|
+
{
|
|
368
|
+
key: 'my-button',
|
|
369
|
+
trigger: 'hover',
|
|
370
|
+
effects: [
|
|
371
|
+
{
|
|
372
|
+
// Ommitted key means same as source
|
|
373
|
+
namedEffect: {
|
|
374
|
+
type: 'Scale'
|
|
375
|
+
},
|
|
376
|
+
duration: 200
|
|
377
|
+
}
|
|
378
|
+
]
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Cross-Targeting
|
|
383
|
+
Effect applies to different elements:
|
|
384
|
+
```typescript
|
|
385
|
+
{
|
|
386
|
+
key: 'menu-trigger',
|
|
387
|
+
trigger: 'click',
|
|
388
|
+
effects: [
|
|
389
|
+
{
|
|
390
|
+
key: 'mobile-menu', // Different element
|
|
391
|
+
namedEffect: {
|
|
392
|
+
type: 'SlideIn',
|
|
393
|
+
direction: 'down'
|
|
394
|
+
},
|
|
395
|
+
duration: 300
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
key: 'menu-overlay', // Another different element
|
|
399
|
+
keyframeEffect: {
|
|
400
|
+
name: 'fade',
|
|
401
|
+
keyframes: [
|
|
402
|
+
{ opacity: '0' },
|
|
403
|
+
{ opacity: '1' }
|
|
404
|
+
]
|
|
405
|
+
},
|
|
406
|
+
duration: 200
|
|
407
|
+
}
|
|
408
|
+
]
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Multiple Targets with Same Effect
|
|
413
|
+
```typescript
|
|
414
|
+
{
|
|
415
|
+
key: 'master-control',
|
|
416
|
+
trigger: 'click',
|
|
417
|
+
effects: [
|
|
418
|
+
{
|
|
419
|
+
key: 'item-1', // first target
|
|
420
|
+
namedEffect: {
|
|
421
|
+
type: 'FadeIn'
|
|
422
|
+
},
|
|
423
|
+
duration: 400
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
key: 'item-2', // second target
|
|
427
|
+
namedEffect: {
|
|
428
|
+
type: 'FadeIn'
|
|
429
|
+
},
|
|
430
|
+
duration: 400
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
key: 'item-3', // third target
|
|
434
|
+
namedEffect: {
|
|
435
|
+
type: 'FadeIn'
|
|
436
|
+
},
|
|
437
|
+
duration: 400
|
|
438
|
+
}
|
|
439
|
+
]
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## Performance Optimization
|
|
444
|
+
|
|
445
|
+
### Use Efficient Properties
|
|
446
|
+
Prefer these properties for smooth animations:
|
|
447
|
+
- `transform` (translate, scale, rotate)
|
|
448
|
+
- `opacity`
|
|
449
|
+
- `filter`
|
|
450
|
+
- Custom CSS properties
|
|
451
|
+
|
|
452
|
+
Avoid animating:
|
|
453
|
+
- Layout properties (`width`, `height`, `margin`, `padding`)
|
|
454
|
+
- Position properties (`top`, `left`)
|
|
455
|
+
- Properties that trigger reflow
|
|
456
|
+
|
|
457
|
+
### Named Effects vs Keyframes
|
|
458
|
+
```typescript
|
|
459
|
+
// Preferred - optimized by @wix/motion
|
|
460
|
+
{
|
|
461
|
+
namedEffect: {
|
|
462
|
+
type: 'FadeIn'
|
|
463
|
+
},
|
|
464
|
+
duration: 300
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Use sparingly - custom keyframes
|
|
468
|
+
{
|
|
469
|
+
keyframeEffect: {
|
|
470
|
+
name: 'fade',
|
|
471
|
+
keyframes: [
|
|
472
|
+
{ opacity: '0' },
|
|
473
|
+
{ opacity: '1' }
|
|
474
|
+
]
|
|
475
|
+
},
|
|
476
|
+
duration: 300
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## Real-World Examples
|
|
481
|
+
|
|
482
|
+
### Image Gallery Hover Effect
|
|
483
|
+
```typescript
|
|
484
|
+
{
|
|
485
|
+
key: 'gallery-item',
|
|
486
|
+
trigger: 'hover',
|
|
487
|
+
effects: [
|
|
488
|
+
{
|
|
489
|
+
selector: 'img',
|
|
490
|
+
keyframeEffect: {
|
|
491
|
+
name: 'img-glow',
|
|
492
|
+
keyframes: [
|
|
493
|
+
{ transform: 'scale(1)', filter: 'brightness(1)' },
|
|
494
|
+
{ transform: 'scale(1.1)', filter: 'brightness(1.1)' }
|
|
495
|
+
]
|
|
496
|
+
},
|
|
497
|
+
duration: 400,
|
|
498
|
+
easing: 'ease-out'
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
selector: '.overlay',
|
|
502
|
+
keyframeEffect: {
|
|
503
|
+
name: 'overlay-slide',
|
|
504
|
+
keyframes: [
|
|
505
|
+
{ opacity: '0', transform: 'translateY(100%)' },
|
|
506
|
+
{ opacity: '1', transform: 'translateY(0)' }
|
|
507
|
+
]
|
|
508
|
+
},
|
|
509
|
+
duration: 300,
|
|
510
|
+
delay: 100
|
|
511
|
+
}
|
|
512
|
+
]
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Loading Animation Sequence
|
|
517
|
+
```typescript
|
|
518
|
+
{
|
|
519
|
+
key: 'app-loader',
|
|
520
|
+
trigger: 'viewEnter',
|
|
521
|
+
params: { type: 'once' },
|
|
522
|
+
effects: [
|
|
523
|
+
{
|
|
524
|
+
key: 'logo',
|
|
525
|
+
keyframeEffect: {
|
|
526
|
+
name: 'scale-fade',
|
|
527
|
+
keyframes: [
|
|
528
|
+
{ opacity: '0', transform: 'scale(0.8)' },
|
|
529
|
+
{ opacity: '1', transform: 'scale(1)' }
|
|
530
|
+
]
|
|
531
|
+
},
|
|
532
|
+
duration: 600,
|
|
533
|
+
easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
|
|
534
|
+
effectId: 'logo-entrance'
|
|
535
|
+
}
|
|
536
|
+
]
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
key: 'logo',
|
|
540
|
+
trigger: 'animationEnd',
|
|
541
|
+
params: { effectId: 'logo-entrance' },
|
|
542
|
+
effects: [
|
|
543
|
+
{
|
|
544
|
+
key: 'loading-text',
|
|
545
|
+
namedEffect: {
|
|
546
|
+
type: 'SlideUp'
|
|
547
|
+
},
|
|
548
|
+
duration: 400,
|
|
549
|
+
effectId: 'text-entrance'
|
|
550
|
+
}
|
|
551
|
+
]
|
|
552
|
+
}
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Scroll-Triggered Counter
|
|
556
|
+
```typescript
|
|
557
|
+
{
|
|
558
|
+
key: 'stats-section',
|
|
559
|
+
trigger: 'viewEnter',
|
|
560
|
+
params: { type: 'once', threshold: 0.5 },
|
|
561
|
+
effects: [
|
|
562
|
+
{
|
|
563
|
+
key: 'counter-1',
|
|
564
|
+
customEffect: (element, progress) => {
|
|
565
|
+
const targetValue = 1000;
|
|
566
|
+
const currentValue = Math.floor(targetValue * progress);
|
|
567
|
+
element.textContent = currentValue.toLocaleString();
|
|
568
|
+
},
|
|
569
|
+
duration: 2000,
|
|
570
|
+
easing: 'ease-out'
|
|
571
|
+
}
|
|
572
|
+
]
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
## Best Practices
|
|
577
|
+
|
|
578
|
+
### Animation Timing
|
|
579
|
+
- **Micro-interactions**: 100-300ms (hover, clicks)
|
|
580
|
+
- **Page transitions**: 300-500ms
|
|
581
|
+
- **Entrance animations**: 500-800ms
|
|
582
|
+
- **Complex sequences**: 800-1200ms
|
|
583
|
+
|
|
584
|
+
### Easing Functions
|
|
585
|
+
- **Entrances**: `ease-out` or `cubic-bezier(0.16, 1, 0.3, 1)`
|
|
586
|
+
- **Exits**: `ease-in` or `cubic-bezier(0.4, 0, 1, 1)`
|
|
587
|
+
- **Interactions**: `ease-in-out`
|
|
588
|
+
- **Elastic effects**: `cubic-bezier(0.34, 1.56, 0.64, 1)`
|
|
589
|
+
|
|
590
|
+
### Accessibility
|
|
591
|
+
```typescript
|
|
592
|
+
// Respect user preferences
|
|
593
|
+
{
|
|
594
|
+
effects: {
|
|
595
|
+
'reduced-motion-entry': {
|
|
596
|
+
namedEffect: {
|
|
597
|
+
type: 'FadeIn'
|
|
598
|
+
},
|
|
599
|
+
duration: 600
|
|
600
|
+
}
|
|
601
|
+
},
|
|
602
|
+
interactions: [
|
|
603
|
+
{
|
|
604
|
+
key: 'animated-element',
|
|
605
|
+
trigger: 'viewEnter',
|
|
606
|
+
effects: [
|
|
607
|
+
{
|
|
608
|
+
namedEffect: {
|
|
609
|
+
type: 'SlideIn'
|
|
610
|
+
},
|
|
611
|
+
duration: 600
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
effectId: 'reduced-motion-entry',
|
|
615
|
+
conditions: ['reduced-motion'] // Only animate if user allows motion
|
|
616
|
+
}
|
|
617
|
+
]
|
|
618
|
+
}
|
|
619
|
+
],
|
|
620
|
+
conditions: {
|
|
621
|
+
'reduced-motion': {
|
|
622
|
+
type: 'media',
|
|
623
|
+
predicate: '(prefers-reduced-motion: reduce)'
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
## Next Steps
|
|
630
|
+
|
|
631
|
+
Now that you understand effects and animations:
|
|
632
|
+
- **[Configuration Structure](./configuration-structure.md)** - Organize complex interactions
|
|
633
|
+
- **[State Management](./state-management.md)** - Advanced state handling
|
|
634
|
+
- **[Conditions and Media Queries](./conditions-and-media-queries.md)** - Responsive animations
|