@wix/interact 2.1.3 → 2.2.0
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 +1 -1
- package/dist/cjs/react.js +1 -1
- package/dist/cjs/web.js +1 -1
- package/dist/cjs/web.js.map +1 -1
- package/dist/es/index.js +1 -1
- package/dist/es/react.js +2 -2
- package/dist/es/web.js +15 -15
- package/dist/es/web.js.map +1 -1
- package/dist/index-ByLXasWO.mjs +2832 -0
- package/dist/index-ByLXasWO.mjs.map +1 -0
- package/dist/index-CzRuJxn8.js +18 -0
- package/dist/index-CzRuJxn8.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/core/Interact.d.ts +2 -2
- package/dist/types/core/InteractionController.d.ts +2 -2
- package/dist/types/core/InteractionController.d.ts.map +1 -1
- package/dist/types/core/add.d.ts.map +1 -1
- package/dist/types/core/css.d.ts.map +1 -1
- package/dist/types/handlers/effectHandlers.d.ts +4 -4
- package/dist/types/handlers/effectHandlers.d.ts.map +1 -1
- package/dist/types/handlers/eventTrigger.d.ts +2 -2
- package/dist/types/handlers/eventTrigger.d.ts.map +1 -1
- package/dist/types/handlers/index.d.ts.map +1 -1
- package/dist/types/handlers/viewEnter.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/react/index.d.ts +1 -1
- package/dist/types/react/index.d.ts.map +1 -1
- package/dist/types/types/config.d.ts +47 -0
- package/dist/types/types/config.d.ts.map +1 -0
- package/dist/types/types/controller.d.ts +34 -0
- package/dist/types/types/controller.d.ts.map +1 -0
- package/dist/types/types/effects.d.ts +75 -0
- package/dist/types/types/effects.d.ts.map +1 -0
- package/dist/types/types/external.d.ts +6 -0
- package/dist/types/types/external.d.ts.map +1 -0
- package/dist/types/types/global.d.ts +11 -0
- package/dist/types/types/global.d.ts.map +1 -0
- package/dist/types/types/handlers.d.ts +41 -0
- package/dist/types/types/handlers.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +8 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/types/internal.d.ts +36 -0
- package/dist/types/types/internal.d.ts.map +1 -0
- package/dist/types/types/triggers.d.ts +28 -0
- package/dist/types/types/triggers.d.ts.map +1 -0
- package/dist/types/web/InteractElement.d.ts +2 -2
- package/dist/types/web/InteractElement.d.ts.map +1 -1
- package/dist/types/web/index.d.ts +1 -1
- package/dist/types/web/index.d.ts.map +1 -1
- package/docs/api/README.md +2 -3
- package/docs/api/functions.md +4 -4
- package/docs/api/interact-class.md +2 -3
- package/docs/api/interact-element.md +2 -2
- package/docs/api/interaction-controller.md +4 -4
- package/docs/api/types.md +38 -69
- package/docs/examples/README.md +1 -1
- package/docs/examples/click-interactions.md +0 -7
- package/docs/examples/entrance-animations.md +28 -27
- package/docs/examples/list-patterns.md +17 -16
- package/docs/guides/conditions-and-media-queries.md +2 -3
- package/docs/guides/configuration-structure.md +5 -7
- package/docs/guides/effects-and-animations.md +2 -4
- package/docs/guides/getting-started.md +0 -1
- package/docs/guides/lists-and-dynamic-content.md +10 -9
- package/docs/guides/sequences.md +3 -4
- package/docs/guides/state-management.md +0 -2
- package/docs/guides/understanding-triggers.md +9 -13
- package/package.json +2 -2
- package/rules/click.md +96 -560
- package/rules/full-lean.md +536 -360
- package/rules/hover.md +107 -530
- package/rules/integration.md +212 -261
- package/rules/pointermove.md +154 -1407
- package/rules/viewenter.md +128 -863
- package/rules/viewprogress.md +88 -322
- package/dist/index-BtEG0cjF.mjs +0 -2791
- package/dist/index-BtEG0cjF.mjs.map +0 -1
- package/dist/index-ErMKtmX2.js +0 -18
- package/dist/index-ErMKtmX2.js.map +0 -1
- package/dist/types/types.d.ts +0 -256
- package/dist/types/types.d.ts.map +0 -1
- package/rules/MASTER-CLEANUP-PLAN.md +0 -286
- package/rules/scroll-list.md +0 -748
package/rules/viewprogress.md
CHANGED
|
@@ -1,378 +1,144 @@
|
|
|
1
1
|
# ViewProgress Trigger Rules for @wix/interact
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
These rules help generate scroll-driven interactions using `@wix/interact`. ViewProgress triggers create animations that update continuously as elements move through the viewport, leveraging native CSS ViewTimelines where supported, and using a polyfill library where unsupported. Use when animation progress should be tied to the element's scroll position.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> **CRITICAL:** You MUST replace all usage of `overflow: hidden` with `overflow: clip` on every element between the trigger source element and the scroll container. `overflow: hidden` creates a new scroll context that breaks the ViewTimeline; `overflow: clip` clips overflow visually without affecting scroll ancestry. If using Tailwind, replace all `overflow-hidden` classes with `overflow-clip`.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**Offset semantics:** The `offset` inside `rangeStart`/`rangeEnd` is an object `{ unit: 'percentage', value: NUMBER }` where value is 0–100. For absolute lengths use `{ unit: 'px', value: NUMBER }` (or other CSS length units). Positive values move the effective range boundary forward along the scroll axis.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
{
|
|
11
|
-
key: '[SOURCE_KEY]',
|
|
12
|
-
trigger: 'viewProgress',
|
|
13
|
-
conditions: ['[CONDITION_NAME]'], // optional: e.g. 'prefers-motion', 'desktop-only'
|
|
14
|
-
effects: [
|
|
15
|
-
{
|
|
16
|
-
key: '[TARGET_KEY]',
|
|
17
|
-
// Effect block — use exactly one of: namedEffect | keyframeEffect | customEffect
|
|
18
|
-
namedEffect: { type: '[NAMED_EFFECT]', /* preset-specific options only if documented */ }, // OR
|
|
19
|
-
keyframeEffect: { name: '[EFFECT_NAME]', keyframes: [EFFECT_KEYFRAMES] }, // OR
|
|
20
|
-
customEffect: (element, progress) => { [CUSTOM_LOGIC] },
|
|
21
|
-
rangeStart: { name: '[RANGE_NAME]', offset: { unit: 'percentage', value: [START_PERCENTAGE] } },
|
|
22
|
-
rangeEnd: { name: '[RANGE_NAME]', offset: { unit: 'percentage', value: [END_PERCENTAGE] } },
|
|
23
|
-
easing: '[EASING_FUNCTION]',
|
|
24
|
-
fill: '[FILL_MODE]',
|
|
25
|
-
effectId: '[UNIQUE_EFFECT_ID]'
|
|
26
|
-
}
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Variable Key
|
|
32
|
-
|
|
33
|
-
| Placeholder | Valid Values / Notes |
|
|
34
|
-
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
35
|
-
| `[SOURCE_KEY]` | Unique identifier for element that tracks scroll progress |
|
|
36
|
-
| `[TARGET_KEY]` | Unique identifier for element to animate (can equal source) |
|
|
37
|
-
| `[NAMED_EFFECT]` | Preset from @wix/motion-presets (see Named Scroll Effects below). Some presets accept options (e.g. `direction`) — only use options you have documentation for; omit and rely on defaults otherwise |
|
|
38
|
-
| `[EFFECT_NAME]` | Unique name for keyframe effect |
|
|
39
|
-
| `[EFFECT_KEYFRAMES]` | Array of keyframe objects, e.g. `[{ opacity: '0' }, { opacity: '1' }]` |
|
|
40
|
-
| `[CUSTOM_LOGIC]` | JS: `progress` is 0–1 within range; mutate `element.style` or DOM |
|
|
41
|
-
| `[RANGE_NAME]` | 'cover', 'contain', 'entry', 'exit', 'entry-crossing', 'exit-crossing' |
|
|
42
|
-
| `[START_PERCENTAGE]` | 0–100 |
|
|
43
|
-
| `[END_PERCENTAGE]` | 0–100 |
|
|
44
|
-
| `[EASING_FUNCTION]` | 'linear', 'ease-in', 'ease-out', 'ease-in-out', or cubic-bezier string |
|
|
45
|
-
| `[FILL_MODE]` | 'both', 'backwards', 'forwards', 'none' |
|
|
46
|
-
| `[UNIQUE_EFFECT_ID]` | Optional unique identifier |
|
|
47
|
-
| `[CONDITION_NAME]` | User-defined condition ID declared in the top-level `conditions` map (e.g. `'prefers-motion'`, `'desktop-only'`) |
|
|
9
|
+
## Table of Contents
|
|
48
10
|
|
|
49
|
-
|
|
11
|
+
- [Rule 1: ViewProgress with keyframeEffect or namedEffect](#rule-1-viewprogress-with-keyframeeffect-or-namedeffect)
|
|
12
|
+
- [Rule 2: ViewProgress with customEffect](#rule-2-viewprogress-with-customeffect)
|
|
13
|
+
- [Rule 3: ViewProgress with Tall Wrapper + Sticky Container (contain range)](#rule-3-viewprogress-with-tall-wrapper--sticky-container-contain-range)
|
|
50
14
|
|
|
51
|
-
|
|
15
|
+
---
|
|
52
16
|
|
|
53
|
-
|
|
54
|
-
| ------------------------------------------------------------- | ---------------- | --------------------------------- |
|
|
55
|
-
| Parallax, scroll-responsive decorations, floating elements | `namedEffect` | Use presets; fastest to implement |
|
|
56
|
-
| Custom multi-property animations, brand-specific reveals | `keyframeEffect` | Full control over CSS keyframes |
|
|
57
|
-
| Dynamic content (counters, text reveal, canvas, calculations) | `customEffect` | JS callback; `progress` 0–1 |
|
|
17
|
+
## Rule 1: ViewProgress with keyframeEffect or namedEffect
|
|
58
18
|
|
|
59
|
-
|
|
19
|
+
**Use Case**: Scroll-driven CSS-based effects.
|
|
60
20
|
|
|
61
|
-
|
|
62
|
-
| --------------------------------------- | --------------- | ------------- | ---------------------- |
|
|
63
|
-
| Parallax / continuous while visible | cover | cover | 0–100 |
|
|
64
|
-
| Entry animation (element entering view) | entry | entry | 0–30 start, 70–100 end |
|
|
65
|
-
| Exit animation (element leaving view) | exit | exit | 0–30 start, 70–100 end |
|
|
66
|
-
| Cross-range (entry to exit) | entry | exit | 0–100 |
|
|
67
|
-
| Contained phase | contain | contain | 0–100 |
|
|
21
|
+
**Multiple effects:** The `effects` array can contain multiple effects — all are driven by the same scroll progress. Use this to animate different targets or properties in sync with the same scroll position.
|
|
68
22
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
From `@wix/motion-presets` scroll animations: ParallaxScroll, MoveScroll, FadeScroll, RevealScroll, GrowScroll, SlideScroll, SpinScroll, PanScroll, BlurScroll, ArcScroll, FlipScroll, Spin3dScroll, TiltScroll, TurnScroll, ShapeScroll, ShuttersScroll, ShrinkScroll, SkewPanScroll, StretchScroll.
|
|
72
|
-
|
|
73
|
-
## Examples
|
|
74
|
-
|
|
75
|
-
### Example 1: Named Effect (Parallax)
|
|
23
|
+
### Template
|
|
76
24
|
|
|
77
25
|
```typescript
|
|
78
26
|
{
|
|
79
|
-
key: '
|
|
27
|
+
key: '[SOURCE_KEY]',
|
|
80
28
|
trigger: 'viewProgress',
|
|
81
29
|
effects: [
|
|
82
30
|
{
|
|
83
|
-
key: '
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
rangeEnd: { name: 'cover', offset: { unit: 'percentage', value: 100 } },
|
|
89
|
-
easing: 'linear'
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Example 2: Keyframe Effect (Custom Animation)
|
|
31
|
+
key: '[TARGET_KEY]',
|
|
32
|
+
// --- pick ONE of the two effect types ---
|
|
33
|
+
namedEffect: [NAMED_EFFECT_DEFINITION],
|
|
34
|
+
// OR
|
|
35
|
+
keyframeEffect: { name: '[EFFECT_NAME]', keyframes: [EFFECT_KEYFRAMES] },
|
|
96
36
|
|
|
97
|
-
|
|
98
|
-
{
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
keyframeEffect: {
|
|
105
|
-
name: 'card-entrance',
|
|
106
|
-
keyframes: [
|
|
107
|
-
{ opacity: '0', transform: 'translateY(80px) scale(0.9)', filter: 'blur(5px)' },
|
|
108
|
-
{ opacity: '1', transform: 'translateY(0) scale(1)', filter: 'blur(0)' }
|
|
109
|
-
]
|
|
110
|
-
},
|
|
111
|
-
rangeStart: { name: 'entry', offset: { unit: 'percentage', value: 0 } },
|
|
112
|
-
rangeEnd: { name: 'entry', offset: { unit: 'percentage', value: 70 } },
|
|
113
|
-
easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
|
|
114
|
-
fill: 'both'
|
|
115
|
-
}
|
|
37
|
+
rangeStart: { name: '[RANGE_NAME]', offset: { unit: 'percentage', value: [START_PERCENTAGE] } },
|
|
38
|
+
rangeEnd: { name: '[RANGE_NAME]', offset: { unit: 'percentage', value: [END_PERCENTAGE] } },
|
|
39
|
+
easing: '[EASING_FUNCTION]', // usually 'linear'
|
|
40
|
+
fill: 'both',
|
|
41
|
+
effectId: '[UNIQUE_EFFECT_ID]'
|
|
42
|
+
},
|
|
43
|
+
// additional effects targeting other elements can be added here
|
|
116
44
|
]
|
|
117
45
|
}
|
|
118
46
|
```
|
|
119
47
|
|
|
120
|
-
###
|
|
48
|
+
### Variables
|
|
121
49
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
50
|
+
- `[SOURCE_KEY]` — identifier matching the element's key (`data-interact-key` for web, `interactKey` for React). The element whose scroll position drives the animation.
|
|
51
|
+
- `[TARGET_KEY]` — identifier matching the element's key (`data-interact-key` for web, `interactKey` for React) on the element to animate (can be same as source or different).
|
|
52
|
+
- `[NAMED_EFFECT_DEFINITION]` — object with properties of pre-built effect from `@wix/motion-presets`. **CRITICAL:** Scroll presets (`*Scroll`) MUST include `range: 'in' | 'out' | 'continuous'` in their options. `'in'` ends at the idle state, `'out'` starts from the idle state, `'continuous'` passes through it.
|
|
53
|
+
- `[EFFECT_NAME]` — unique name for custom keyframe effect.
|
|
54
|
+
- `[EFFECT_KEYFRAMES]` — array of keyframe objects defining CSS property values (e.g. `[{ opacity: 0 }, { opacity: 1 }]`). Property names in camelCase.
|
|
55
|
+
- `[RANGE_NAME]` — scroll range name:
|
|
56
|
+
- `'cover'` — full visibility span from first pixel entering to last pixel leaving.
|
|
57
|
+
- `'entry'` — the phase while the element is entering the viewport.
|
|
58
|
+
- `'exit'` — the phase while the element is exiting the viewport.
|
|
59
|
+
- `'contain'` — while the element is fully contained in the viewport. Typically used with a `position: sticky` container.
|
|
60
|
+
- `'entry-crossing'` — from the element's leading edge entering to its leading edge reaching the opposite side.
|
|
61
|
+
- `'exit-crossing'` — from the element's trailing edge reaching the start to its trailing edge leaving.
|
|
62
|
+
- `[START_PERCENTAGE]` — 0–100, starting point within the named range.
|
|
63
|
+
- `[END_PERCENTAGE]` — 0–100, end point within the named range.
|
|
64
|
+
- `[EASING_FUNCTION]` - CSS easing string or named easing from `@wix/motion`. Typically `'linear'` for scrolling effects.
|
|
65
|
+
- `[UNIQUE_EFFECT_ID]` — optional identifier for referencing the effect externally.
|
|
134
66
|
|
|
135
|
-
|
|
136
|
-
element.style.transform = `translateY(${(1 - progress) * 30}px)`;
|
|
137
|
-
},
|
|
138
|
-
rangeStart: { name: 'entry', offset: { unit: 'percentage', value: 0 } },
|
|
139
|
-
rangeEnd: { name: 'entry', offset: { unit: 'percentage', value: 80 } },
|
|
140
|
-
fill: 'both',
|
|
141
|
-
effectId: 'text-reveal'
|
|
142
|
-
}
|
|
143
|
-
]
|
|
144
|
-
}
|
|
145
|
-
```
|
|
67
|
+
---
|
|
146
68
|
|
|
147
|
-
|
|
69
|
+
## Rule 2: ViewProgress with customEffect
|
|
148
70
|
|
|
149
|
-
|
|
71
|
+
**Use Case**: Scroll-driven effects requiring JavaScript logic (e.g., changing SVG attributes, controlling WebGL/WebGPU effects).
|
|
72
|
+
|
|
73
|
+
### Template
|
|
150
74
|
|
|
151
75
|
```typescript
|
|
152
76
|
{
|
|
153
|
-
key: '
|
|
77
|
+
key: '[SOURCE_KEY]',
|
|
154
78
|
trigger: 'viewProgress',
|
|
155
79
|
effects: [
|
|
156
|
-
// Animate IN as element enters viewport
|
|
157
80
|
{
|
|
158
|
-
key: '
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
},
|
|
166
|
-
rangeStart: { name: 'entry', offset: { unit: 'percentage', value: 0 } },
|
|
167
|
-
rangeEnd: { name: 'entry', offset: { unit: 'percentage', value: 60 } },
|
|
168
|
-
easing: 'ease-out',
|
|
169
|
-
fill: 'both'
|
|
81
|
+
key: '[TARGET_KEY]',
|
|
82
|
+
customEffect: [CUSTOM_EFFECT_CALLBACK],
|
|
83
|
+
rangeStart: { name: '[RANGE_NAME]', offset: { unit: 'percentage', value: [START_PERCENTAGE] } },
|
|
84
|
+
rangeEnd: { name: '[RANGE_NAME]', offset: { unit: 'percentage', value: [END_PERCENTAGE] } },
|
|
85
|
+
easing: `'[EASING_FUNCTION]'`, // usually 'linear'
|
|
86
|
+
fill: 'both',
|
|
87
|
+
effectId: '[UNIQUE_EFFECT_ID]'
|
|
170
88
|
},
|
|
171
|
-
//
|
|
172
|
-
{
|
|
173
|
-
key: 'feature-card',
|
|
174
|
-
keyframeEffect: {
|
|
175
|
-
name: 'card-out',
|
|
176
|
-
keyframes: [
|
|
177
|
-
{ opacity: '1', transform: 'translateY(0)' },
|
|
178
|
-
{ opacity: '0', transform: 'translateY(-40px)' }
|
|
179
|
-
]
|
|
180
|
-
},
|
|
181
|
-
rangeStart: { name: 'exit', offset: { unit: 'percentage', value: 40 } },
|
|
182
|
-
rangeEnd: { name: 'exit', offset: { unit: 'percentage', value: 100 } },
|
|
183
|
-
easing: 'ease-in',
|
|
184
|
-
fill: 'both'
|
|
185
|
-
}
|
|
89
|
+
// additional effects targeting other elements can be added here
|
|
186
90
|
]
|
|
187
91
|
}
|
|
188
92
|
```
|
|
189
93
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
### Multi-Range ViewProgress Effects
|
|
94
|
+
### Variables
|
|
193
95
|
|
|
194
|
-
|
|
96
|
+
- `[SOURCE_KEY]` / `[TARGET_KEY]` — same as Rule 1.
|
|
97
|
+
- `[CUSTOM_EFFECT_CALLBACK]` — function with signature `(element: HTMLElement, progress: number) => void`. Called on each animation frame with `progress` from 0 to 1.
|
|
98
|
+
- `[RANGE_NAME]` / `[START_PERCENTAGE]` / `[END_PERCENTAGE]` — same as Rule 1.
|
|
99
|
+
- `[EASING_FUNCTION]` — CSS easing string or named easing from `@wix/motion`. Typically `'linear'` for scrolling effects.
|
|
100
|
+
- `[UNIQUE_EFFECT_ID]` — optional identifier for referencing the effect externally.
|
|
195
101
|
|
|
196
|
-
|
|
197
|
-
{
|
|
198
|
-
key: 'complex-section',
|
|
199
|
-
trigger: 'viewProgress',
|
|
200
|
-
effects: [
|
|
201
|
-
// Entry phase
|
|
202
|
-
{
|
|
203
|
-
key: 'section-content',
|
|
204
|
-
keyframeEffect: {
|
|
205
|
-
name: 'content-entrance',
|
|
206
|
-
keyframes: [
|
|
207
|
-
{ opacity: '0', transform: 'translateY(50px)' },
|
|
208
|
-
{ opacity: '1', transform: 'translateY(0)' }
|
|
209
|
-
]
|
|
210
|
-
},
|
|
211
|
-
rangeStart: { name: 'entry', offset: { unit: 'percentage', value: 0 } },
|
|
212
|
-
rangeEnd: { name: 'entry', offset: { unit: 'percentage', value: 50 } },
|
|
213
|
-
easing: 'ease-out',
|
|
214
|
-
fill: 'backwards'
|
|
215
|
-
},
|
|
216
|
-
// Cover phase
|
|
217
|
-
{
|
|
218
|
-
key: 'background-element',
|
|
219
|
-
keyframeEffect: {
|
|
220
|
-
name: 'background-parallax-hue',
|
|
221
|
-
keyframes: [
|
|
222
|
-
{ transform: 'translateY(0)', filter: 'hue-rotate(0deg)' },
|
|
223
|
-
{ transform: 'translateY(-100px)', filter: 'hue-rotate(180deg)' }
|
|
224
|
-
]
|
|
225
|
-
},
|
|
226
|
-
rangeStart: { name: 'cover', offset: { unit: 'percentage', value: 0 } },
|
|
227
|
-
rangeEnd: { name: 'cover', offset: { unit: 'percentage', value: 100 } },
|
|
228
|
-
easing: 'linear',
|
|
229
|
-
fill: 'both'
|
|
230
|
-
},
|
|
231
|
-
// Exit phase
|
|
232
|
-
{
|
|
233
|
-
key: 'section-content',
|
|
234
|
-
keyframeEffect: {
|
|
235
|
-
name: 'content-exit',
|
|
236
|
-
keyframes: [
|
|
237
|
-
{ opacity: '1', transform: 'scale(1)' },
|
|
238
|
-
{ opacity: '0', transform: 'scale(0.8)' }
|
|
239
|
-
]
|
|
240
|
-
},
|
|
241
|
-
rangeStart: { name: 'exit', offset: { unit: 'percentage', value: 50 } },
|
|
242
|
-
rangeEnd: { name: 'exit', offset: { unit: 'percentage', value: 100 } },
|
|
243
|
-
easing: 'ease-in',
|
|
244
|
-
fill: 'forwards'
|
|
245
|
-
}
|
|
246
|
-
]
|
|
247
|
-
}
|
|
248
|
-
```
|
|
102
|
+
---
|
|
249
103
|
|
|
250
|
-
|
|
104
|
+
## Rule 3: ViewProgress with Tall Wrapper + Sticky Container (contain range)
|
|
251
105
|
|
|
252
|
-
Use
|
|
106
|
+
**Use Case**: Scroll-driven animations inside a sticky-positioned container, where the source element is a tall wrapper and the effect applies during the "stuck" phase using `position: sticky` to lock a container and `contain` range to animate only during the stuck phase. Good for heavy effects on large media elements or scrolly-telling effects.
|
|
253
107
|
|
|
254
|
-
|
|
255
|
-
{
|
|
256
|
-
conditions: {
|
|
257
|
-
'desktop-only': { type: 'media', predicate: '(min-width: 768px)' },
|
|
258
|
-
'prefers-motion': { type: 'media', predicate: '(prefers-reduced-motion: no-preference)' },
|
|
259
|
-
'mobile-only': { type: 'media', predicate: '(max-width: 767px)' },
|
|
260
|
-
},
|
|
261
|
-
interactions: [
|
|
262
|
-
{
|
|
263
|
-
key: 'responsive-parallax',
|
|
264
|
-
trigger: 'viewProgress',
|
|
265
|
-
conditions: ['desktop-only', 'prefers-motion'],
|
|
266
|
-
effects: [
|
|
267
|
-
{
|
|
268
|
-
key: 'parallax-bg',
|
|
269
|
-
keyframeEffect: {
|
|
270
|
-
name: 'parallax-bg',
|
|
271
|
-
keyframes: [
|
|
272
|
-
{ transform: 'translateY(0)' },
|
|
273
|
-
{ transform: 'translateY(-300px)' }
|
|
274
|
-
]
|
|
275
|
-
},
|
|
276
|
-
rangeStart: { name: 'cover', offset: { unit: 'percentage', value: 0 } },
|
|
277
|
-
rangeEnd: { name: 'cover', offset: { unit: 'percentage', value: 100 } },
|
|
278
|
-
easing: 'linear',
|
|
279
|
-
fill: 'both'
|
|
280
|
-
}
|
|
281
|
-
]
|
|
282
|
-
},
|
|
283
|
-
// Simplified fallback for mobile
|
|
284
|
-
{
|
|
285
|
-
key: 'responsive-parallax',
|
|
286
|
-
trigger: 'viewProgress',
|
|
287
|
-
conditions: ['mobile-only'],
|
|
288
|
-
effects: [
|
|
289
|
-
{
|
|
290
|
-
key: 'parallax-bg',
|
|
291
|
-
keyframeEffect: {
|
|
292
|
-
name: 'fade-out-bg',
|
|
293
|
-
keyframes: [
|
|
294
|
-
{ opacity: '1' },
|
|
295
|
-
{ opacity: '0.7' }
|
|
296
|
-
]
|
|
297
|
-
},
|
|
298
|
-
rangeStart: { name: 'exit', offset: { unit: 'percentage', value: 0 } },
|
|
299
|
-
rangeEnd: { name: 'exit', offset: { unit: 'percentage', value: 100 } },
|
|
300
|
-
easing: 'linear',
|
|
301
|
-
fill: 'both'
|
|
302
|
-
}
|
|
303
|
-
]
|
|
304
|
-
}
|
|
305
|
-
]
|
|
306
|
-
}
|
|
307
|
-
```
|
|
108
|
+
**Layout Structure**:
|
|
308
109
|
|
|
309
|
-
|
|
110
|
+
- **Tall wrapper** (`[TALL_WRAPPER_KEY]`): An element with enough height to create scroll distance (e.g., `height: 300vh`). This is the ViewTimeline source. The taller it is relative to the viewport, the longer the scroll distance and the more "duration" the animation has.
|
|
111
|
+
- **Sticky container**: A direct child with `position: sticky; top: 0; height: 100vh` that stays fixed in the viewport while the wrapper scrolls past.
|
|
112
|
+
- **Animated elements** (`[STICKY_CHILD_KEY]`): Children of the sticky container that receive the effects.
|
|
310
113
|
|
|
311
|
-
|
|
114
|
+
### Template
|
|
312
115
|
|
|
313
116
|
```typescript
|
|
314
117
|
{
|
|
315
|
-
key: '
|
|
118
|
+
key: '[TALL_WRAPPER_KEY]',
|
|
316
119
|
trigger: 'viewProgress',
|
|
317
120
|
effects: [
|
|
318
121
|
{
|
|
319
|
-
key: '
|
|
320
|
-
keyframeEffect
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
rangeStart: { name: 'cover', offset: { unit: 'percentage', value: 0 } },
|
|
328
|
-
rangeEnd: { name: 'cover', offset: { unit: 'percentage', value: 100 } },
|
|
329
|
-
easing: 'linear',
|
|
330
|
-
fill: 'both'
|
|
331
|
-
},
|
|
332
|
-
{
|
|
333
|
-
key: 'bg-layer-2',
|
|
334
|
-
keyframeEffect: {
|
|
335
|
-
name: 'layer-2-parallax',
|
|
336
|
-
keyframes: [
|
|
337
|
-
{ transform: 'translateY(0)' },
|
|
338
|
-
{ transform: 'translateY(-100px)' }
|
|
339
|
-
]
|
|
340
|
-
},
|
|
341
|
-
rangeStart: { name: 'cover', offset: { unit: 'percentage', value: 0 } },
|
|
342
|
-
rangeEnd: { name: 'cover', offset: { unit: 'percentage', value: 100 } },
|
|
343
|
-
easing: 'linear',
|
|
344
|
-
fill: 'both'
|
|
122
|
+
key: '[STICKY_CHILD_KEY]',
|
|
123
|
+
// Use keyframeEffect, namedEffect, or customEffect as in Rules 1–2
|
|
124
|
+
keyframeEffect: { name: '[EFFECT_NAME]', keyframes: [EFFECT_KEYFRAMES] },
|
|
125
|
+
rangeStart: { name: 'contain', offset: { unit: 'percentage', value: [START_PERCENTAGE] } },
|
|
126
|
+
rangeEnd: { name: 'contain', offset: { unit: 'percentage', value: [END_PERCENTAGE] } },
|
|
127
|
+
easing: '[EASING_FUNCTION]', // usually 'linear'
|
|
128
|
+
fill: 'both',
|
|
129
|
+
effectId: '[UNIQUE_EFFECT_ID]'
|
|
345
130
|
},
|
|
346
|
-
|
|
347
|
-
key: 'fg-content',
|
|
348
|
-
keyframeEffect: {
|
|
349
|
-
name: 'layer-3-parallax',
|
|
350
|
-
keyframes: [
|
|
351
|
-
{ transform: 'translateY(0)' },
|
|
352
|
-
{ transform: 'translateY(-150px)' }
|
|
353
|
-
]
|
|
354
|
-
},
|
|
355
|
-
rangeStart: { name: 'cover', offset: { unit: 'percentage', value: 0 } },
|
|
356
|
-
rangeEnd: { name: 'cover', offset: { unit: 'percentage', value: 100 } },
|
|
357
|
-
easing: 'linear',
|
|
358
|
-
fill: 'both'
|
|
359
|
-
}
|
|
131
|
+
// additional effects targeting other elements can be added here
|
|
360
132
|
]
|
|
361
133
|
}
|
|
362
134
|
```
|
|
363
135
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
### Interact-Specific
|
|
367
|
-
|
|
368
|
-
1. **Respect `prefers-reduced-motion`** via interact `conditions`: use `'prefers-motion'` so scroll animations run only when the user has not requested reduced motion.
|
|
369
|
-
2. **Use `linear` easing** for most scroll effects; non-linear easing can feel jarring as scroll position changes.
|
|
370
|
-
3. **Range configuration:** Verify source element remains visible throughout the scroll range. If the source is hidden or in a frozen stacking context, the ViewTimeline constraint may not update correctly.
|
|
371
|
-
4. **Avoid overlapping ranges** on the same target to prevent conflicting animations.
|
|
372
|
-
5. **Entry/exit timing:** Use 0–50% cover or 0–100% entry for entrances; 50–100% cover or 0–100% exit for exits. Start with broad ranges (0–100) then refine.
|
|
373
|
-
6. **customEffect:** Use `element.closest('interact-element')` when querying related DOM within the callback; target elements must exist when the effect runs.
|
|
374
|
-
|
|
375
|
-
### Troubleshooting
|
|
136
|
+
### Variables
|
|
376
137
|
|
|
377
|
-
-
|
|
378
|
-
-
|
|
138
|
+
- `[TALL_WRAPPER_KEY]` — key for the tall outer element that defines the scroll distance — this is the ViewTimeline source.
|
|
139
|
+
- `[STICKY_CHILD_KEY]` — key for the animated element inside the sticky container.
|
|
140
|
+
- `[EFFECT_NAME]` / `[EFFECT_KEYFRAMES]` — same as Rule 1.
|
|
141
|
+
- `[START_PERCENTAGE]` — 0–100, starting point within the `contain` range (the stuck phase).
|
|
142
|
+
- `[END_PERCENTAGE]` — 0–100, end point within the `contain` range.
|
|
143
|
+
- `[UNIQUE_EFFECT_ID]` — same as Rule 1.
|
|
144
|
+
- `[EASING_FUNCTION]` — CSS easing string or named easing from `@wix/motion`. Typically `'linear'` for scrolling effects.
|