svg-scroll-draw 1.6.0 → 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/README.md +394 -94
- package/dist/astro/index.cjs +3 -3
- package/dist/astro/index.mjs +3 -3
- package/dist/cdn/svg-scroll-draw.global.js +3 -3
- package/dist/devtools/index.cjs +1 -0
- package/dist/devtools/index.mjs +1 -0
- package/dist/index.cjs +4 -4
- package/dist/index.d.mts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.mjs +4 -4
- package/dist/react/index.cjs +3 -3
- package/dist/react/index.d.mts +84 -1
- package/dist/react/index.d.ts +84 -1
- package/dist/react/index.mjs +3 -3
- package/dist/text/index.cjs +1 -0
- package/dist/text/index.d.mts +37 -0
- package/dist/text/index.d.ts +37 -0
- package/dist/text/index.mjs +1 -0
- package/dist/timeline/index.cjs +7 -7
- package/dist/timeline/index.d.mts +11 -0
- package/dist/timeline/index.d.ts +11 -0
- package/dist/timeline/index.mjs +7 -7
- package/dist/video/index.cjs +1 -0
- package/dist/video/index.d.mts +34 -0
- package/dist/video/index.d.ts +34 -0
- package/dist/video/index.mjs +1 -0
- package/package.json +16 -1
package/README.md
CHANGED
|
@@ -7,11 +7,25 @@
|
|
|
7
7
|
[](./LICENSE)
|
|
8
8
|
[](https://github.com/DhruvilChauahan0210/ink-scroll/stargazers)
|
|
9
9
|
|
|
10
|
-
>
|
|
10
|
+
> The scroll animation platform. Animate SVG paths, CSS properties, counters, video, and text — all scroll-driven, all MIT, all under 10 KB. GSAP is overkill.
|
|
11
11
|
|
|
12
|
-
**[Live Demo](https://
|
|
12
|
+
**[Live Demo](https://svg-scroll-draw.vercel.app)** · [npm](https://www.npmjs.com/package/svg-scroll-draw) · [Docs](https://svg-scroll-draw.vercel.app/docs) · [Examples](https://svg-scroll-draw.vercel.app/examples) · [Report a bug](https://github.com/DhruvilChauahan0210/ink-scroll/issues)
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## What's in v2
|
|
17
|
+
|
|
18
|
+
| API | Import | What it does |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `scrollAnimate` | `svg-scroll-draw` | Animate **any CSS property** on any element driven by scroll. Replaces `gsap.to + ScrollTrigger`. |
|
|
21
|
+
| `scrollCounter` | `svg-scroll-draw` | Animate a number from `from` to `to` as it scrolls into view. Custom format, decimals, easing. |
|
|
22
|
+
| `scrollParallax` | `svg-scroll-draw` | Move any element at a different rate than scroll. Speed multiplier, reverse direction. |
|
|
23
|
+
| `scrollDraw` | `svg-scroll-draw` | The original — scroll-driven SVG path drawing via `stroke-dashoffset`. |
|
|
24
|
+
| `scrollVideo` | `svg-scroll-draw/video` | Tie `<video>.currentTime` to scroll. The Apple/Stripe product-page pattern. |
|
|
25
|
+
| `scrollText` | `svg-scroll-draw/text` | Split text into chars/words/lines and stagger-animate each on scroll. Free GSAP SplitText. |
|
|
26
|
+
| `devtools` | `svg-scroll-draw/devtools` | Visual overlay showing every active animation's triggers and progress. Dev-only. |
|
|
27
|
+
|
|
28
|
+
All APIs return the same instance object: `{ destroy, replay, pause, resume, seek, getProgress }`.
|
|
15
29
|
|
|
16
30
|
---
|
|
17
31
|
|
|
@@ -19,56 +33,263 @@
|
|
|
19
33
|
|
|
20
34
|
```bash
|
|
21
35
|
npm i svg-scroll-draw
|
|
22
|
-
#
|
|
23
|
-
|
|
24
|
-
#
|
|
25
|
-
yarn add svg-scroll-draw
|
|
26
|
-
# or
|
|
27
|
-
bun add svg-scroll-draw
|
|
36
|
+
# pnpm add svg-scroll-draw
|
|
37
|
+
# yarn add svg-scroll-draw
|
|
38
|
+
# bun add svg-scroll-draw
|
|
28
39
|
```
|
|
29
40
|
|
|
30
41
|
---
|
|
31
42
|
|
|
32
|
-
##
|
|
43
|
+
## scrollAnimate — any CSS property on scroll
|
|
33
44
|
|
|
34
|
-
|
|
45
|
+
```js
|
|
46
|
+
import { scrollAnimate } from 'svg-scroll-draw';
|
|
47
|
+
|
|
48
|
+
// Fade + slide in
|
|
49
|
+
scrollAnimate('#hero-text', {
|
|
50
|
+
props: {
|
|
51
|
+
opacity: [0, 1],
|
|
52
|
+
transform: ['translateY(40px)', 'translateY(0px)'],
|
|
53
|
+
},
|
|
54
|
+
easing: 'ease-out',
|
|
55
|
+
once: true,
|
|
56
|
+
});
|
|
35
57
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
58
|
+
// Color transition
|
|
59
|
+
scrollAnimate('#section', {
|
|
60
|
+
props: {
|
|
61
|
+
backgroundColor: ['#ffffff', '#0d0d0d'],
|
|
62
|
+
color: ['#000000', '#ffffff'],
|
|
63
|
+
},
|
|
64
|
+
trigger: { start: 'top 60%', end: 'top 20%' },
|
|
65
|
+
});
|
|
41
66
|
|
|
42
|
-
|
|
67
|
+
// Multiple elements with stagger
|
|
68
|
+
document.querySelectorAll('.card').forEach((el, i) => {
|
|
69
|
+
scrollAnimate(el, {
|
|
70
|
+
props: { opacity: [0, 1], transform: ['translateY(32px)', 'translateY(0)'] },
|
|
71
|
+
trigger: { start: `top ${85 - i * 5}%`, end: `top ${50 - i * 5}%` },
|
|
72
|
+
easing: 'ease-out',
|
|
73
|
+
once: true,
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
```
|
|
43
77
|
|
|
44
|
-
|
|
78
|
+
#### React
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { ScrollAnimate } from 'svg-scroll-draw/react';
|
|
82
|
+
|
|
83
|
+
<ScrollAnimate
|
|
84
|
+
props={{ opacity: [0, 1], transform: ['translateY(24px)', 'translateY(0)'] }}
|
|
85
|
+
easing="ease-out"
|
|
86
|
+
once
|
|
87
|
+
>
|
|
88
|
+
<div>Any content — HTML or SVG</div>
|
|
89
|
+
</ScrollAnimate>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### scrollAnimate options
|
|
93
|
+
|
|
94
|
+
| Option | Type | Default | Description |
|
|
95
|
+
|---|---|---|---|
|
|
96
|
+
| `props` | `Record<string, [from, to]>` | — | CSS properties to animate. Supports numbers, hex/rgb colors, transform functions, and unit values like `40px`. |
|
|
97
|
+
| `trigger.start` | `string` | `"top bottom"` | When animation begins |
|
|
98
|
+
| `trigger.end` | `string` | `"bottom top"` | When animation ends |
|
|
99
|
+
| `easing` | `string \| fn` | `"ease-out"` | Same easing system as `scrollDraw` |
|
|
100
|
+
| `speed` | `number` | `1` | Animation scale factor |
|
|
101
|
+
| `once` | `boolean` | `false` | Freeze at max progress — doesn't reverse on scroll back |
|
|
102
|
+
| `axis` | `"x" \| "y"` | `"y"` | Scroll axis |
|
|
103
|
+
| `native` | `boolean` | `true` | Use CSS `animation-timeline: view()` fast path when eligible |
|
|
104
|
+
| `onProgress` | `(n: number) => void` | — | Called every frame with alpha 0–1 |
|
|
105
|
+
| `onComplete` | `() => void` | — | Fires when alpha reaches 1 |
|
|
45
106
|
|
|
46
|
-
|
|
107
|
+
---
|
|
47
108
|
|
|
48
|
-
|
|
109
|
+
## scrollCounter — animated number on scroll
|
|
49
110
|
|
|
50
111
|
```js
|
|
51
|
-
import {
|
|
112
|
+
import { scrollCounter } from 'svg-scroll-draw';
|
|
113
|
+
|
|
114
|
+
// Simple count-up
|
|
115
|
+
scrollCounter('#users', { to: 50_000, once: true });
|
|
52
116
|
|
|
53
|
-
|
|
117
|
+
// Formatted currency
|
|
118
|
+
scrollCounter('#revenue', {
|
|
119
|
+
to: 1_250_000,
|
|
120
|
+
format: n => '$' + Math.round(n).toLocaleString(),
|
|
54
121
|
easing: 'ease-out',
|
|
55
|
-
|
|
122
|
+
once: true,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Percentage with decimal
|
|
126
|
+
scrollCounter('#rate', {
|
|
127
|
+
from: 0,
|
|
128
|
+
to: 94.7,
|
|
129
|
+
decimals: 1,
|
|
130
|
+
format: n => n.toFixed(1) + '%',
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### React
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import { ScrollCounter } from 'svg-scroll-draw/react';
|
|
138
|
+
|
|
139
|
+
<ScrollCounter to={50000} format={n => n.toLocaleString()} once />
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### scrollCounter options
|
|
143
|
+
|
|
144
|
+
| Option | Type | Default | Description |
|
|
145
|
+
|---|---|---|---|
|
|
146
|
+
| `to` | `number` | — | Target value **(required)** |
|
|
147
|
+
| `from` | `number` | `0` | Starting value. Set higher than `to` to count down. |
|
|
148
|
+
| `format` | `(n: number) => string` | `String(Math.round(n))` | Custom formatter |
|
|
149
|
+
| `decimals` | `number` | — | Shorthand for `format: n => n.toFixed(decimals)` |
|
|
150
|
+
| `easing` | `string \| fn` | `"ease-out"` | — |
|
|
151
|
+
| `trigger` | `TriggerConfig` | `{ start: 'top 80%', end: 'top 20%' }` | — |
|
|
152
|
+
| `once` | `boolean` | `true` | — |
|
|
153
|
+
| `onComplete` | `() => void` | — | — |
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## scrollParallax — parallax in one line
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
import { scrollParallax } from 'svg-scroll-draw';
|
|
161
|
+
|
|
162
|
+
scrollParallax('#hero-bg', { speed: 0.4 }); // 40% of scroll rate
|
|
163
|
+
scrollParallax('#floating-badge', { speed: -0.3 }); // opposite direction
|
|
164
|
+
scrollParallax('#sidebar', { speed: 0.3, axis: 'x' }); // horizontal
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`speed` is a multiplier relative to element height. `0.5` = half scroll speed, `-0.2` = opposite direction.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## scrollVideo — video scrubbing on scroll
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
import { scrollVideo } from 'svg-scroll-draw/video';
|
|
175
|
+
|
|
176
|
+
// Scrub the full video as user scrolls through the section
|
|
177
|
+
scrollVideo('#hero-video', {
|
|
178
|
+
trigger: { start: 'top top', end: 'bottom top' },
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Scrub only the first 3 seconds
|
|
182
|
+
scrollVideo('#product-reveal', {
|
|
183
|
+
from: 0,
|
|
184
|
+
to: 3,
|
|
185
|
+
trigger: { start: 'top 80%', end: 'top 20%' },
|
|
186
|
+
easing: 'ease-in-out',
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```html
|
|
191
|
+
<!-- Recommended attributes for smooth scrubbing -->
|
|
192
|
+
<video id="hero-video" src="hero.mp4" muted playsinline preload="auto"></video>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### React
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
import { ScrollVideo } from 'svg-scroll-draw/react';
|
|
199
|
+
|
|
200
|
+
<ScrollVideo src="/hero.mp4" trigger={{ start: 'top top', end: 'bottom top' }} />
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### scrollVideo options
|
|
204
|
+
|
|
205
|
+
| Option | Type | Default | Description |
|
|
206
|
+
|---|---|---|---|
|
|
207
|
+
| `from` | `number` | `0` | Start time in seconds |
|
|
208
|
+
| `to` | `number` | `video.duration` | End time in seconds |
|
|
209
|
+
| `trigger` | `TriggerConfig` | `{ start: 'top top', end: 'bottom top' }` | — |
|
|
210
|
+
| `easing` | `string \| fn` | `"linear"` | — |
|
|
211
|
+
| `once` | `boolean` | `false` | — |
|
|
212
|
+
| `preload` | `"auto" \| "metadata"` | `"auto"` | Sets `preload` attribute if not already present |
|
|
213
|
+
| `onReady` | `() => void` | — | Fires when video metadata is loaded |
|
|
214
|
+
| `onProgress` | `(n: number) => void` | — | — |
|
|
215
|
+
| `onComplete` | `() => void` | — | — |
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## scrollText — text reveal on scroll
|
|
220
|
+
|
|
221
|
+
Free replacement for GSAP SplitText (which requires a $150+/yr Club GreenSock subscription).
|
|
222
|
+
|
|
223
|
+
```js
|
|
224
|
+
import { scrollText } from 'svg-scroll-draw/text';
|
|
225
|
+
|
|
226
|
+
// Words fade up one by one
|
|
227
|
+
scrollText('#headline', {
|
|
228
|
+
split: 'words',
|
|
229
|
+
stagger: 0.05,
|
|
230
|
+
from: { opacity: 0, y: 24 },
|
|
231
|
+
easing: 'ease-out',
|
|
232
|
+
once: true,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Characters with rotation
|
|
236
|
+
scrollText('#tagline', {
|
|
237
|
+
split: 'chars',
|
|
238
|
+
stagger: 0.025,
|
|
239
|
+
from: { opacity: 0, y: 32, rotate: 8 },
|
|
240
|
+
once: true,
|
|
56
241
|
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### React
|
|
57
245
|
|
|
58
|
-
|
|
59
|
-
|
|
246
|
+
```tsx
|
|
247
|
+
import { ScrollText } from 'svg-scroll-draw/react';
|
|
248
|
+
|
|
249
|
+
<ScrollText split="words" stagger={0.05} from={{ opacity: 0, y: 24 }} once>
|
|
250
|
+
Animate this headline word by word.
|
|
251
|
+
</ScrollText>
|
|
60
252
|
```
|
|
61
253
|
|
|
62
|
-
|
|
254
|
+
#### scrollText options
|
|
255
|
+
|
|
256
|
+
| Option | Type | Default | Description |
|
|
257
|
+
|---|---|---|---|
|
|
258
|
+
| `split` | `"chars" \| "words" \| "lines"` | `"words"` | How to split the text |
|
|
259
|
+
| `stagger` | `number` | `0.04` | Delay between each unit (0–1 fraction of the animation range) |
|
|
260
|
+
| `from` | `{ opacity?, y?, x?, rotate?, scale? }` | `{ opacity: 0, y: 24 }` | Starting state of each unit |
|
|
261
|
+
| `easing` | `string \| fn` | `"ease-out"` | — |
|
|
262
|
+
| `trigger` | `TriggerConfig` | `{ start: 'top 85%', end: 'top 40%' }` | — |
|
|
263
|
+
| `once` | `boolean` | `true` | — |
|
|
264
|
+
| `onComplete` | `() => void` | — | — |
|
|
265
|
+
|
|
266
|
+
> **Accessibility:** `scrollText` preserves the original text in `aria-label` on the container and adds `aria-hidden="true"` to all split spans. `destroy()` fully restores the original HTML.
|
|
267
|
+
|
|
268
|
+
---
|
|
63
269
|
|
|
64
|
-
|
|
270
|
+
## scrollDraw — SVG path drawing (v1 API, unchanged)
|
|
271
|
+
|
|
272
|
+
```js
|
|
273
|
+
import { scrollDraw } from 'svg-scroll-draw';
|
|
274
|
+
|
|
275
|
+
scrollDraw('#my-svg', {
|
|
276
|
+
easing: 'ease-out',
|
|
277
|
+
speed: 1.2,
|
|
278
|
+
fade: true,
|
|
279
|
+
once: true,
|
|
280
|
+
stagger: 0.15,
|
|
281
|
+
trigger: { start: 'top 80%', end: 'top 20%' },
|
|
282
|
+
});
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### React / Next.js
|
|
65
286
|
|
|
66
287
|
```tsx
|
|
67
288
|
import { ScrollDraw } from 'svg-scroll-draw/react';
|
|
68
289
|
|
|
69
290
|
export default function Hero() {
|
|
70
291
|
return (
|
|
71
|
-
<ScrollDraw speed={1.2} fade easing="ease-out">
|
|
292
|
+
<ScrollDraw speed={1.2} fade easing="ease-out" once>
|
|
72
293
|
<svg width="500" height="500" viewBox="0 0 500 500">
|
|
73
294
|
<path d="M10 80 C 40 10, 60 10, 95 80" stroke="black" fill="none" />
|
|
74
295
|
</svg>
|
|
@@ -77,11 +298,9 @@ export default function Hero() {
|
|
|
77
298
|
}
|
|
78
299
|
```
|
|
79
300
|
|
|
80
|
-
> **Next.js App Router:** add `'use client'` to any component that uses
|
|
301
|
+
> **Next.js App Router:** add `'use client'` to any component that uses these wrappers.
|
|
81
302
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
### Vue 3
|
|
303
|
+
#### Vue 3
|
|
85
304
|
|
|
86
305
|
```vue
|
|
87
306
|
<script setup>
|
|
@@ -95,97 +314,176 @@ import { ScrollDraw } from 'svg-scroll-draw/vue';
|
|
|
95
314
|
</template>
|
|
96
315
|
```
|
|
97
316
|
|
|
98
|
-
|
|
317
|
+
#### scrollDraw options
|
|
99
318
|
|
|
100
|
-
|
|
101
|
-
|
|
319
|
+
| Option | Type | Default | Description |
|
|
320
|
+
|---|---|---|---|
|
|
321
|
+
| `selector` | `string` | `"path, polyline…"` | CSS selector for child elements to animate |
|
|
322
|
+
| `speed` | `number` | `1` | Scale factor relative to scroll distance |
|
|
323
|
+
| `fade` | `boolean` | `false` | Animate `opacity 0 → 1` simultaneously |
|
|
324
|
+
| `easing` | `string \| fn` | `"linear"` | `linear`, `ease-in`, `ease-out`, `ease-in-out`, `spring`, `bounce`, `elastic`, or `(t) => t` |
|
|
325
|
+
| `stagger` | `number` | `0` | Offset between each path starting (fraction of scroll range) |
|
|
326
|
+
| `direction` | `"forward" \| "reverse"` | `"forward"` | `reverse` erases the path as you scroll |
|
|
327
|
+
| `trigger.start` | `string` | `"top bottom"` | When animation begins |
|
|
328
|
+
| `trigger.end` | `string` | `"bottom top"` | When animation ends |
|
|
329
|
+
| `once` | `boolean` | `false` | Lock at max progress |
|
|
330
|
+
| `debug` | `boolean` | `false` | Show trigger zone overlay (dev only) |
|
|
331
|
+
| `axis` | `"x" \| "y"` | `"y"` | Scroll axis |
|
|
332
|
+
| `scrollContainer` | `string \| Element` | `window` | Custom scroll container |
|
|
333
|
+
| `autoReverse` | `boolean` | `false` | Reverse when scrolling back up |
|
|
334
|
+
| `delay` | `number` | `0` | ms before the engine starts observing |
|
|
335
|
+
| `strokeColor` | `string \| [string, string]` | — | Static color or `[from, to]` animation |
|
|
336
|
+
| `strokeWidth` | `number \| [number, number]` | — | Static width or `[from, to]` animation |
|
|
337
|
+
| `fillOpacity` | `number \| [number, number]` | — | Animate fill opacity in sync with the draw |
|
|
338
|
+
| `clip` | `boolean \| "left" \| "right" \| "top" \| "bottom" \| "center"` | `false` | Reveal via CSS `clip-path` instead of stroke-dashoffset |
|
|
339
|
+
| `morphTo` | `string` | — | SVG path `d` value to morph toward |
|
|
340
|
+
| `waypoints` | `Record<number, () => void>` | — | Callbacks at specific progress thresholds (0–1) |
|
|
341
|
+
| `velocityScale` | `boolean \| number` | `false` | Scale draw speed by scroll velocity |
|
|
342
|
+
| `repeat` | `number \| "infinite"` | `0` | Replay N times after completion |
|
|
343
|
+
| `repeatDelay` | `number` | `0` | ms between repeats |
|
|
344
|
+
| `autoplay` | `boolean` | `false` | Trigger on viewport entry instead of scroll |
|
|
345
|
+
| `duration` | `number` | `1000` | Duration in ms for `autoplay` mode |
|
|
346
|
+
| `native` | `boolean` | `true` | Use CSS `animation-timeline: view()` when eligible |
|
|
347
|
+
| `preset` | `"sketch" \| "reveal" \| "typewriter" \| "cinematic" \| "spring"` | — | Apply a named option preset as the base config |
|
|
348
|
+
| `onProgress` | `(alpha: number) => void` | — | Called every frame with draw progress (0–1) |
|
|
349
|
+
| `onStart` | `() => void` | — | Fires on the first frame |
|
|
350
|
+
| `onComplete` | `() => void` | — | Fires when all paths reach 100% |
|
|
351
|
+
|
|
352
|
+
---
|
|
102
353
|
|
|
103
|
-
|
|
354
|
+
## Instance API
|
|
355
|
+
|
|
356
|
+
Every function returns the same instance object:
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
const inst = scrollAnimate('#el', { props: { opacity: [0, 1] } });
|
|
360
|
+
// Same for scrollDraw, scrollCounter, scrollVideo, scrollText, scrollParallax
|
|
361
|
+
|
|
362
|
+
inst.pause(); // pause at current frame
|
|
363
|
+
inst.resume(); // resume from paused state
|
|
364
|
+
inst.seek(0.5); // jump to 50% and pause
|
|
365
|
+
inst.replay(); // reset and replay from the beginning
|
|
366
|
+
inst.getProgress(); // → number 0–1
|
|
367
|
+
inst.destroy(); // remove all listeners and clean up
|
|
104
368
|
```
|
|
105
369
|
|
|
106
|
-
|
|
370
|
+
---
|
|
107
371
|
|
|
108
|
-
|
|
372
|
+
## Easing
|
|
109
373
|
|
|
110
|
-
|
|
111
|
-
<script src="https://unpkg.com/svg-scroll-draw/dist/cdn/svg-scroll-draw.global.js"></script>
|
|
374
|
+
All APIs share the same easing system:
|
|
112
375
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
</scroll-draw>
|
|
376
|
+
```js
|
|
377
|
+
// Named strings
|
|
378
|
+
easing: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring' | 'bounce' | 'elastic'
|
|
117
379
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
380
|
+
// Custom function
|
|
381
|
+
easing: (t: number) => number
|
|
382
|
+
|
|
383
|
+
// Factory functions for parameterized physics easings
|
|
384
|
+
import { createSpring, createBounce, createElastic } from 'svg-scroll-draw';
|
|
385
|
+
|
|
386
|
+
easing: createSpring({ tension: 3, friction: 1.8 })
|
|
387
|
+
easing: createBounce({ bounces: 4, decay: 0.4 })
|
|
388
|
+
easing: createElastic({ amplitude: 1.5, period: 0.3 })
|
|
122
389
|
```
|
|
123
390
|
|
|
124
391
|
---
|
|
125
392
|
|
|
126
|
-
##
|
|
393
|
+
## Presets
|
|
127
394
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
| `fade` | `boolean` | `false` | Simultaneously animate `opacity 0 → 1` while drawing |
|
|
133
|
-
| `easing` | `string \| fn` | `"linear"` | `linear`, `ease-in`, `ease-out`, `ease-in-out`, or a custom `(t: number) => number` |
|
|
134
|
-
| `stagger` | `number` | `0` | Normalized offset between each path starting. `0.15` = each path begins 15% of the scroll range after the previous |
|
|
135
|
-
| `direction` | `"forward" \| "reverse"` | `"forward"` | `reverse` starts fully drawn and erases as you scroll |
|
|
136
|
-
| `trigger.start` | `string` | `"top bottom"` | When animation begins. Accepts anchor strings (`"top bottom"`) or viewport percentages (`"20%"`) |
|
|
137
|
-
| `trigger.end` | `string` | `"bottom top"` | When animation ends |
|
|
138
|
-
| `onProgress` | `(alpha: number) => void` | — | Called every animation frame with current draw progress (0–1) |
|
|
139
|
-
| `onComplete` | `() => void` | — | Fires once when all paths reach 100% draw progress |
|
|
140
|
-
| `native` | `boolean` | `true` | Run the draw as a native CSS scroll-driven animation when the browser supports it and the config is simple. Falls back to the JS engine automatically. Set `false` to always use the JS engine |
|
|
395
|
+
Named option bags for `scrollDraw`:
|
|
396
|
+
|
|
397
|
+
```js
|
|
398
|
+
import { scrollDraw, PRESETS } from 'svg-scroll-draw';
|
|
141
399
|
|
|
142
|
-
|
|
400
|
+
scrollDraw('#logo', { preset: 'sketch' }); // staggered ease-in, pencil feel
|
|
401
|
+
scrollDraw('#hero', { preset: 'reveal' }); // fade + ease-out, once
|
|
402
|
+
scrollDraw('#type', { preset: 'typewriter' }); // fast linear stagger
|
|
403
|
+
scrollDraw('#film', { preset: 'cinematic' }); // slow ease-in-out + fade
|
|
404
|
+
scrollDraw('#icon', { preset: 'spring' }); // spring easing
|
|
143
405
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
The draw then runs on the compositor with **zero per-frame JavaScript and no scroll or
|
|
148
|
-
resize listeners**.
|
|
406
|
+
// Inspect or extend
|
|
407
|
+
console.log(PRESETS.sketch);
|
|
408
|
+
```
|
|
149
409
|
|
|
150
|
-
|
|
151
|
-
config uses something CSS can't express declaratively — callbacks (`onProgress` /
|
|
152
|
-
`onComplete` / `waypoints`), `stagger`, `morphTo`, `velocityScale`, `autoReverse`,
|
|
153
|
-
`once`, `repeat`, a custom trigger, a custom scroll container, `speed ≠ 1`, a
|
|
154
|
-
custom-function or `spring` easing, or animated color/width/fill. The full instance API
|
|
155
|
-
(`pause`, `resume`, `seek`, `replay`, `getProgress`, `destroy`) works on both paths.
|
|
410
|
+
---
|
|
156
411
|
|
|
157
|
-
|
|
412
|
+
## DevTools
|
|
158
413
|
|
|
159
|
-
|
|
414
|
+
Visual debug overlay — shows every active animation's trigger window, progress bar, and type. Zero production bytes.
|
|
160
415
|
|
|
161
416
|
```js
|
|
162
|
-
|
|
163
|
-
trigger: {
|
|
164
|
-
start: 'top bottom', // when top of element hits bottom of viewport
|
|
165
|
-
end: 'bottom top', // when bottom of element hits top of viewport
|
|
166
|
-
}
|
|
167
|
-
});
|
|
417
|
+
import { devtools } from 'svg-scroll-draw/devtools';
|
|
168
418
|
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
});
|
|
419
|
+
devtools.enable(); // Cmd/Ctrl+Shift+S to toggle
|
|
420
|
+
devtools.disable();
|
|
421
|
+
devtools.highlight('#my-element'); // outline for 2 seconds
|
|
173
422
|
```
|
|
174
423
|
|
|
175
|
-
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Sub-path exports
|
|
427
|
+
|
|
428
|
+
| Import | Contents |
|
|
429
|
+
|---|---|
|
|
430
|
+
| `svg-scroll-draw` | `scrollDraw`, `scrollAnimate`, `scrollCounter`, `scrollParallax`, `PRESETS`, easing factories |
|
|
431
|
+
| `svg-scroll-draw/react` | `ScrollDraw`, `ScrollAnimate`, `ScrollCounter`, `ScrollVideo`, `ScrollText`, `useScrollDrawProgress` |
|
|
432
|
+
| `svg-scroll-draw/vue` | `ScrollDraw`, `useScrollDraw` |
|
|
433
|
+
| `svg-scroll-draw/svelte` | `scrollDraw` action, `createScrollDraw` |
|
|
434
|
+
| `svg-scroll-draw/solid` | `useScrollDraw`, `createScrollDraw` |
|
|
435
|
+
| `svg-scroll-draw/angular` | `ScrollDrawRef` |
|
|
436
|
+
| `svg-scroll-draw/astro` | `initScrollDraw()` |
|
|
437
|
+
| `svg-scroll-draw/nuxt` | `useScrollDraw()` composable |
|
|
438
|
+
| `svg-scroll-draw/video` | `scrollVideo` |
|
|
439
|
+
| `svg-scroll-draw/text` | `scrollText` |
|
|
440
|
+
| `svg-scroll-draw/group` | `scrollDrawGroup`, `scrollDrawSequence` |
|
|
441
|
+
| `svg-scroll-draw/timeline` | `scrollDrawTimeline` |
|
|
442
|
+
| `svg-scroll-draw/cinematic` | `Cinematic` |
|
|
443
|
+
| `svg-scroll-draw/devtools` | `devtools` (dev-only) |
|
|
176
444
|
|
|
177
445
|
---
|
|
178
446
|
|
|
179
447
|
## Bundle sizes
|
|
180
448
|
|
|
181
|
-
|
|
|
182
|
-
|
|
183
|
-
|
|
|
184
|
-
|
|
|
185
|
-
|
|
|
186
|
-
|
|
|
449
|
+
| Entry | Gzipped |
|
|
450
|
+
|---|---|
|
|
451
|
+
| `svg-scroll-draw` (main) | ~9 KB |
|
|
452
|
+
| `svg-scroll-draw/react` | ~3 KB |
|
|
453
|
+
| `svg-scroll-draw/video` | ~1.5 KB |
|
|
454
|
+
| `svg-scroll-draw/text` | ~2 KB |
|
|
455
|
+
| `svg-scroll-draw/devtools` | ~4 KB (dev only) |
|
|
187
456
|
|
|
188
|
-
|
|
457
|
+
GSAP core + ScrollTrigger = ~40 KB gzipped. **svg-scroll-draw v2 covers 95% of those use cases at ~9 KB.**
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## CDN / Web Component
|
|
462
|
+
|
|
463
|
+
```html
|
|
464
|
+
<script src="https://unpkg.com/svg-scroll-draw/dist/cdn/svg-scroll-draw.global.js"></script>
|
|
465
|
+
|
|
466
|
+
<scroll-draw easing="ease-out" speed="1.2">
|
|
467
|
+
<svg>...</svg>
|
|
468
|
+
</scroll-draw>
|
|
469
|
+
|
|
470
|
+
<script>
|
|
471
|
+
SvgScrollDraw.scrollDraw('#container', { easing: 'ease-out' });
|
|
472
|
+
SvgScrollDraw.scrollAnimate('#hero', {
|
|
473
|
+
props: { opacity: [0, 1] }, easing: 'ease-out', once: true,
|
|
474
|
+
});
|
|
475
|
+
</script>
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## CLI
|
|
481
|
+
|
|
482
|
+
```bash
|
|
483
|
+
npx svg-scroll-draw init
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
Scaffolds a ready-to-use starter file for React, Vue, Svelte, Solid, or Vanilla JS.
|
|
189
487
|
|
|
190
488
|
---
|
|
191
489
|
|
|
@@ -193,6 +491,8 @@ Still 8–9× smaller than Framer Motion (~35 KB) or GSAP DrawSVG (~40 KB), and
|
|
|
193
491
|
|
|
194
492
|
Chrome 80+, Safari 14+, Firefox 75+, Edge 80+
|
|
195
493
|
|
|
494
|
+
Native CSS `animation-timeline: view()` fast path: Chrome 115+, Safari 18+, Firefox 110+. Automatically falls back to the JS engine on older browsers.
|
|
495
|
+
|
|
196
496
|
---
|
|
197
497
|
|
|
198
498
|
## License
|