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 CHANGED
@@ -7,11 +7,25 @@
7
7
  [![license](https://img.shields.io/npm/l/svg-scroll-draw)](./LICENSE)
8
8
  [![GitHub stars](https://img.shields.io/github/stars/DhruvilChauahan0210/ink-scroll?style=flat)](https://github.com/DhruvilChauahan0210/ink-scroll/stargazers)
9
9
 
10
- > Scroll-driven SVG path animation. Zero dependencies. ~4.4 KB gzippedvs 35–40 KB for Framer Motion / GSAP DrawSVG.
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://ink-scroll.vercel.app)** · [npm](https://www.npmjs.com/package/svg-scroll-draw) · [Report a bug](https://github.com/DhruvilChauahan0210/ink-scroll/issues)
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
- ![svg-scroll-draw demo](https://raw.githubusercontent.com/DhruvilChauahan0210/ink-scroll/main/demo.gif)
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
- # or
23
- pnpm add svg-scroll-draw
24
- # or
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
- ## Why this exists
43
+ ## scrollAnimate any CSS property on scroll
33
44
 
34
- The `stroke-dashoffset` trick for drawing SVG lines on scroll is well-known — but every existing tool that implements it is broken in a different way:
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
- | Tool | Problem |
37
- |---|---|
38
- | **GSAP DrawSVG** | 40KB+, requires a paid Club GreenSock license for commercial use |
39
- | **Framer Motion** | 35KB+, React-only, heavy runtime for a single animation effect |
40
- | **scroll-svg** | ~2KB but abandoned — forces you to target individual path IDs manually, crashes in Next.js |
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
- `svg-scroll-draw` fixes all three pain points in one package.
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
- ## Quick start
107
+ ---
47
108
 
48
- ### Vanilla JS
109
+ ## scrollCounter — animated number on scroll
49
110
 
50
111
  ```js
51
- import { scrollDraw } from 'svg-scroll-draw';
112
+ import { scrollCounter } from 'svg-scroll-draw';
113
+
114
+ // Simple count-up
115
+ scrollCounter('#users', { to: 50_000, once: true });
52
116
 
53
- const instance = scrollDraw('#my-svg-container', {
117
+ // Formatted currency
118
+ scrollCounter('#revenue', {
119
+ to: 1_250_000,
120
+ format: n => '$' + Math.round(n).toLocaleString(),
54
121
  easing: 'ease-out',
55
- speed: 1.2,
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
- // Clean up on SPA navigation / unmount
59
- instance.destroy();
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
- **[Try the Playground →](https://svg-scroll-draw.vercel.app/playground)**
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
- ### React / Next.js
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 `ScrollDraw`.
301
+ > **Next.js App Router:** add `'use client'` to any component that uses these wrappers.
81
302
 
82
- **[Try the Playground →](https://svg-scroll-draw.vercel.app/playground)**
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
- Or use the composable directly:
317
+ #### scrollDraw options
99
318
 
100
- ```ts
101
- import { useScrollDraw } from 'svg-scroll-draw/vue';
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
- const containerRef = useScrollDraw({ easing: 'ease-out', speed: 1.2 });
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
- **[Try the Playground →](https://svg-scroll-draw.vercel.app/playground)**
370
+ ---
107
371
 
108
- ### CDN / Web Component
372
+ ## Easing
109
373
 
110
- ```html
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
- <!-- Web Component (auto-registered) -->
114
- <scroll-draw easing="ease-out" speed="1.2">
115
- <svg>...</svg>
116
- </scroll-draw>
376
+ ```js
377
+ // Named strings
378
+ easing: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring' | 'bounce' | 'elastic'
117
379
 
118
- <!-- Or vanilla JS API -->
119
- <script>
120
- SvgScrollDraw.scrollDraw('#my-container', { easing: 'ease-out' });
121
- </script>
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
- ## Options
393
+ ## Presets
127
394
 
128
- | Option | Type | Default | Description |
129
- |---|---|---|---|
130
- | `selector` | `string` | `"path, polyline, line, polygon, rect, circle"` | CSS selector for child elements to animate |
131
- | `speed` | `number` | `1` | Scale factor — values above 1 complete faster relative to scroll distance |
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
- ### Native CSS rendering
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
- For the common case — a default trigger, a named easing, optional `fade`, forward or
145
- reverse — `svg-scroll-draw` hands the animation to the browser's native
146
- [`animation-timeline: view()`](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline).
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
- It falls back to the JS engine automatically when the browser lacks support, or when the
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
- Pass `native: false` to force the JS engine regardless.
412
+ ## DevTools
158
413
 
159
- ### Trigger anchors
414
+ Visual debug overlay — shows every active animation's trigger window, progress bar, and type. Zero production bytes.
160
415
 
161
416
  ```js
162
- scrollDraw('#logo', {
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
- // Or use viewport percentages
170
- scrollDraw('#logo', {
171
- trigger: { start: '20%', end: '80%' }
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
- Available named anchors: `top`, `center`, `bottom`.
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
- | Format | Minified | Gzipped |
182
- |---|---|---|
183
- | ESM (`.mjs`) | 11.9 KB | ~4.4 KB |
184
- | CJS (`.cjs`) | 11.9 KB | ~4.4 KB |
185
- | React (`/react`) | 13.4 KB | ~4.8 KB |
186
- | IIFE / CDN (`.global.js`) | 12.9 KB | ~4.8 KB (includes Web Component) |
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
- Still 8–9× smaller than Framer Motion (~35 KB) or GSAP DrawSVG (~40 KB), and on supporting browsers the simple case runs as a native CSS scroll animation with zero per-frame JavaScript.
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