@motion.page/sdk 0.1.1 → 0.1.3
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/LICENSE +113 -0
- package/README.md +143 -43
- package/llms.txt +64 -0
- package/package.json +4 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Functional Source License, Version 1.1, Apache 2.0 Future License
|
|
2
|
+
|
|
3
|
+
Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-Apache-2.0
|
|
6
|
+
|
|
7
|
+
Notice
|
|
8
|
+
|
|
9
|
+
Copyright © 2025 Motion.page (David Babinec)
|
|
10
|
+
|
|
11
|
+
Terms and Conditions
|
|
12
|
+
|
|
13
|
+
Licensor: Motion.page (David Babinec)
|
|
14
|
+
Licensed Work: @motion.page/sdk
|
|
15
|
+
The Licensed Work is copyright © 2025 Motion.page (David Babinec).
|
|
16
|
+
Additional Use Grant: None
|
|
17
|
+
Change Date: The earlier of the date two years after the date the Licensed Work
|
|
18
|
+
is made available under this License, or a date specified by the
|
|
19
|
+
Licensor.
|
|
20
|
+
Change License: Apache License, Version 2.0
|
|
21
|
+
|
|
22
|
+
For information about alternative licensing arrangements for the Licensed Work,
|
|
23
|
+
please contact: hello@motion.page
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
Functional Source License, Version 1.1, Apache 2.0 Future License
|
|
28
|
+
|
|
29
|
+
Purpose
|
|
30
|
+
|
|
31
|
+
This license gives you broad permission to use, modify, and share the software
|
|
32
|
+
for any purpose, with one condition: you may not use it to compete with us.
|
|
33
|
+
Once the change date passes, this software converts to the Apache 2.0 license.
|
|
34
|
+
|
|
35
|
+
Acceptance
|
|
36
|
+
|
|
37
|
+
To use the Licensed Work, you must agree to all the terms of this license.
|
|
38
|
+
The license is between you and the Licensor.
|
|
39
|
+
|
|
40
|
+
Copyright License
|
|
41
|
+
|
|
42
|
+
The Licensor grants you a non-exclusive, worldwide, royalty-free copyright license
|
|
43
|
+
to use, copy, distribute, make available, and prepare derivative works of the
|
|
44
|
+
Licensed Work, with the condition that you exercise these rights only for
|
|
45
|
+
Permitted Purposes.
|
|
46
|
+
|
|
47
|
+
Patent License
|
|
48
|
+
|
|
49
|
+
The Licensor grants you a non-exclusive, worldwide, royalty-free patent license
|
|
50
|
+
under patents that the Licensor can license, or becomes able to license, to make,
|
|
51
|
+
have made, use, sell, offer for sale, import, and have imported the Licensed Work,
|
|
52
|
+
with the condition that you exercise these rights only for Permitted Purposes.
|
|
53
|
+
|
|
54
|
+
Permitted Purposes
|
|
55
|
+
|
|
56
|
+
A Permitted Purpose is any purpose other than a Competing Use.
|
|
57
|
+
|
|
58
|
+
A Competing Use means use of the Licensed Work in or for a commercial product or
|
|
59
|
+
service that competes with the Licensed Work or any other product or service the
|
|
60
|
+
Licensor or any of its affiliates provides using the Licensed Work. Competing
|
|
61
|
+
products and services include, but are not limited to, no-code animation builders,
|
|
62
|
+
visual animation editors, visual timeline editors, or similar software tools that
|
|
63
|
+
enable users to create, edit, or manage animations through a visual interface,
|
|
64
|
+
which compete with the Licensed Work or any product or service the Licensor
|
|
65
|
+
provides using the Licensed Work.
|
|
66
|
+
|
|
67
|
+
Goods and services compete even when they provide functionality through different
|
|
68
|
+
kinds of interfaces or for different technical platforms. Applications can compete
|
|
69
|
+
with services, libraries with plugins, frameworks with development tools, and so
|
|
70
|
+
on, even if they are written in different programming languages or for different
|
|
71
|
+
computer architectures. Goods and services compete even when provided free of
|
|
72
|
+
charge.
|
|
73
|
+
|
|
74
|
+
If you have questions about whether your use qualifies as a Permitted Purpose,
|
|
75
|
+
or if you would like to negotiate an alternative licensing arrangement, please
|
|
76
|
+
contact the Licensor at hello@motion.page.
|
|
77
|
+
|
|
78
|
+
Notices
|
|
79
|
+
|
|
80
|
+
You must ensure that anyone who receives a copy of any part of the Licensed Work
|
|
81
|
+
from you also receives a copy of this license, and that anyone who modifies the
|
|
82
|
+
Licensed Work provides reasonable notice that they have modified it.
|
|
83
|
+
|
|
84
|
+
No Other Rights
|
|
85
|
+
|
|
86
|
+
This license does not grant you any right in any trademark or logo of the
|
|
87
|
+
Licensor or its affiliates.
|
|
88
|
+
|
|
89
|
+
Termination
|
|
90
|
+
|
|
91
|
+
If you violate any term of this license, your rights under it terminate
|
|
92
|
+
immediately.
|
|
93
|
+
|
|
94
|
+
No Liability
|
|
95
|
+
|
|
96
|
+
As far as the law allows, the Licensed Work comes as-is, without any warranty
|
|
97
|
+
or condition, and the Licensor will not be liable to you for any damages arising
|
|
98
|
+
out of these terms or the use or nature of the Licensed Work, under any kind of
|
|
99
|
+
legal claim.
|
|
100
|
+
|
|
101
|
+
Change Date
|
|
102
|
+
|
|
103
|
+
On the Change Date, the Licensed Work will become available under the Change
|
|
104
|
+
License. The Change Date is the earlier of:
|
|
105
|
+
- Two years after the date the Licensed Work was first made available under
|
|
106
|
+
this License, or
|
|
107
|
+
- A date the Licensor specifies.
|
|
108
|
+
|
|
109
|
+
Change License
|
|
110
|
+
|
|
111
|
+
On and after the Change Date, you may use the Licensed Work under the terms of
|
|
112
|
+
the Apache License, Version 2.0 (the "Change License"), as published by the
|
|
113
|
+
Apache Software Foundation.
|
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
A high-performance animation SDK with a declarative API. Scroll-triggered animations, page transitions, custom cursors, gesture controls, text splitting, and more — zero runtime dependencies.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@motion.page/sdk)
|
|
6
|
-

|
|
7
|
-
](https://bundlephobia.com/package/@motion.page/sdk)
|
|
7
|
+
[](./LICENSE)
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -13,6 +13,7 @@ A high-performance animation SDK with a declarative API. Scroll-triggered animat
|
|
|
13
13
|
- [Installation](#installation)
|
|
14
14
|
- [Quick Start](#quick-start)
|
|
15
15
|
- [Core Concept](#core-concept)
|
|
16
|
+
- [Implicit Values](#implicit-values)
|
|
16
17
|
- [API Reference](#api-reference)
|
|
17
18
|
- [Motion()](#motion-function)
|
|
18
19
|
- [Motion Static Methods](#motion-static-methods)
|
|
@@ -41,6 +42,10 @@ yarn add @motion.page/sdk
|
|
|
41
42
|
pnpm add @motion.page/sdk
|
|
42
43
|
```
|
|
43
44
|
|
|
45
|
+
📖 Full documentation and interactive examples: [motion.page](https://motion.page)
|
|
46
|
+
|
|
47
|
+
> **⚠️ Browser-only:** This SDK requires a browser environment (`document`, `window`). In SSR frameworks (Next.js, Nuxt, Astro), wrap SDK calls in `useEffect`, `onMounted`, or client-side scripts.
|
|
48
|
+
|
|
44
49
|
For direct browser use without a bundler, see [Browser Build](#browser-build).
|
|
45
50
|
|
|
46
51
|
---
|
|
@@ -55,7 +60,6 @@ import { Motion } from '@motion.page/sdk';
|
|
|
55
60
|
// Fade in and slide up
|
|
56
61
|
Motion('hero-intro', '#hero', {
|
|
57
62
|
from: { opacity: 0, y: 50 },
|
|
58
|
-
to: { opacity: 1, y: 0 },
|
|
59
63
|
duration: 0.8,
|
|
60
64
|
ease: 'power2.out',
|
|
61
65
|
}).play();
|
|
@@ -67,7 +71,6 @@ Motion('hero-intro', '#hero', {
|
|
|
67
71
|
// Scrub animation progress to scroll position
|
|
68
72
|
Motion('scroll-reveal', '.card', {
|
|
69
73
|
from: { opacity: 0, y: 40 },
|
|
70
|
-
to: { opacity: 1, y: 0 },
|
|
71
74
|
duration: 0.6,
|
|
72
75
|
}).onScroll({ scrub: true, start: 'top 80%', end: 'top 30%' });
|
|
73
76
|
```
|
|
@@ -91,13 +94,11 @@ Motion('intro-sequence', [
|
|
|
91
94
|
{
|
|
92
95
|
target: '.title',
|
|
93
96
|
from: { opacity: 0, y: -30 },
|
|
94
|
-
to: { opacity: 1, y: 0 },
|
|
95
97
|
duration: 0.6,
|
|
96
98
|
},
|
|
97
99
|
{
|
|
98
100
|
target: '.cards',
|
|
99
101
|
from: { opacity: 0, y: 20 },
|
|
100
|
-
to: { opacity: 1, y: 0 },
|
|
101
102
|
duration: 0.5,
|
|
102
103
|
stagger: { each: 0.1, from: 'start' },
|
|
103
104
|
position: '+=0.1', // starts 0.1s after the previous entry ends
|
|
@@ -105,7 +106,6 @@ Motion('intro-sequence', [
|
|
|
105
106
|
{
|
|
106
107
|
target: '.cta',
|
|
107
108
|
from: { opacity: 0, scale: 0.9 },
|
|
108
|
-
to: { opacity: 1, scale: 1 },
|
|
109
109
|
duration: 0.4,
|
|
110
110
|
position: '<', // starts at the same time as the previous entry
|
|
111
111
|
},
|
|
@@ -147,9 +147,86 @@ If `Motion('name', target, config)` is called when `'name'` already has a timeli
|
|
|
147
147
|
|
|
148
148
|
```ts
|
|
149
149
|
Motion('hero').kill();
|
|
150
|
-
Motion('hero', '#hero', { from: { opacity: 0 },
|
|
150
|
+
Motion('hero', '#hero', { from: { opacity: 0 }, duration: 0.8 }).onPageLoad();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Implicit Values
|
|
156
|
+
|
|
157
|
+
The SDK automatically resolves a missing `from` or `to` by reading the element's **current computed CSS** at build time (i.e. when `Motion()` is first called). This means you rarely need to specify both ends of an animation.
|
|
158
|
+
|
|
159
|
+
### Three cases
|
|
160
|
+
|
|
161
|
+
| Config | SDK behaviour |
|
|
162
|
+
|--------|--------------|
|
|
163
|
+
| `from` only | Reads current CSS as the `to` target. Animate **from** custom values **into** the element's natural state. |
|
|
164
|
+
| `to` only | Reads current CSS as the `from` starting point. Animate **from** the natural state **to** custom values. |
|
|
165
|
+
| Both | Both endpoints are explicit. Only needed when **neither** endpoint matches the element's natural CSS. |
|
|
166
|
+
|
|
167
|
+
### Common pattern — reveal animations only need `from`
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
// ❌ Redundant — opacity:1 and y:0 are the element's natural CSS defaults
|
|
171
|
+
Motion('reveal', '.card', {
|
|
172
|
+
from: { opacity: 0, y: 40 },
|
|
173
|
+
to: { opacity: 1, y: 0 },
|
|
174
|
+
duration: 0.6,
|
|
175
|
+
}).onScroll({ scrub: true });
|
|
176
|
+
|
|
177
|
+
// ✅ Correct — SDK reads opacity:1 and y:0 from computed CSS automatically
|
|
178
|
+
Motion('reveal', '.card', {
|
|
179
|
+
from: { opacity: 0, y: 40 },
|
|
180
|
+
duration: 0.6,
|
|
181
|
+
}).onScroll({ scrub: true });
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### When `to` only is correct
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
// Animate FROM the element's current state TO a hover state
|
|
188
|
+
Motion('btn-hover', '.btn', {
|
|
189
|
+
to: { scale: 1.05, backgroundColor: '#0099ff' },
|
|
190
|
+
duration: 0.3,
|
|
191
|
+
}).onHover({ onLeave: 'reverse' });
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### When you need both
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
// Neither endpoint is the element's natural state
|
|
198
|
+
Motion('parallax', '.layer', {
|
|
199
|
+
from: { x: -20, y: -20 },
|
|
200
|
+
to: { x: 20, y: 20 },
|
|
201
|
+
}).onMouseMove({ type: 'axis' });
|
|
202
|
+
|
|
203
|
+
// Animating between two non-default positions
|
|
204
|
+
Motion('swipe', '.panel', {
|
|
205
|
+
from: { x: -100 },
|
|
206
|
+
to: { x: 100 },
|
|
207
|
+
}).onGesture({ types: ['touch'], events: { Left: 'play', Right: 'reverse' } });
|
|
151
208
|
```
|
|
152
209
|
|
|
210
|
+
### Natural CSS defaults (common values the SDK resolves automatically)
|
|
211
|
+
|
|
212
|
+
| Property | Natural default |
|
|
213
|
+
|----------|----------------|
|
|
214
|
+
| `opacity` | `1` |
|
|
215
|
+
| `x`, `y`, `z` | `0` |
|
|
216
|
+
| `scale`, `scaleX`, `scaleY` | `1` |
|
|
217
|
+
| `rotate`, `rotateX`, `rotateY` | `0` |
|
|
218
|
+
| `skewX`, `skewY` | `0` |
|
|
219
|
+
|
|
220
|
+
> **Note:** `height: 'auto'` is **not** a natural default for the animation engine — it must be specified explicitly in `to` when needed (e.g. accordion reveals).
|
|
221
|
+
|
|
222
|
+
### Build-time vs. play-time
|
|
223
|
+
|
|
224
|
+
The SDK reads computed CSS **at build time** (when `Motion()` is called), not at play time. If the element's styles change after the timeline is created, call `.kill()` and rebuild the timeline.
|
|
225
|
+
|
|
226
|
+
### Edge case — transform cache
|
|
227
|
+
|
|
228
|
+
Transform properties (`x`, `y`, `scale`, `rotate`, etc.) are read from the SDK's **internal transform cache** rather than `getComputedStyle`. This ensures composited transforms remain consistent across animations. Plain CSS properties (`opacity`, `color`, `width`, etc.) are read directly from `getComputedStyle`.
|
|
229
|
+
|
|
153
230
|
---
|
|
154
231
|
|
|
155
232
|
## API Reference
|
|
@@ -338,7 +415,7 @@ tl.call(
|
|
|
338
415
|
| `">-0.1"` | 0.1 s before the end of the previous entry |
|
|
339
416
|
|
|
340
417
|
```ts
|
|
341
|
-
Motion('demo', '.box', { from: { opacity: 0 },
|
|
418
|
+
Motion('demo', '.box', { from: { opacity: 0 }, duration: 1 })
|
|
342
419
|
.call(() => console.log('halfway'), [], 0.5)
|
|
343
420
|
.call(() => console.log('done'), [], '>');
|
|
344
421
|
```
|
|
@@ -413,7 +490,7 @@ interface ClickConfig {
|
|
|
413
490
|
```ts
|
|
414
491
|
Motion('menu-toggle', '#menu', {
|
|
415
492
|
from: { height: 0, opacity: 0 },
|
|
416
|
-
to: { height: 'auto',
|
|
493
|
+
to: { height: 'auto' }, // height: 'auto' must be explicit
|
|
417
494
|
duration: 0.4,
|
|
418
495
|
ease: 'power2.inOut',
|
|
419
496
|
}).onClick({ target: '#menu-btn', toggle: 'reverse' });
|
|
@@ -456,12 +533,11 @@ interface ScrollConfig {
|
|
|
456
533
|
// Pin the parent section while the child content animates
|
|
457
534
|
Motion('content-reveal', '.content', {
|
|
458
535
|
from: { opacity: 0, y: 40 },
|
|
459
|
-
to: { opacity: 1, y: 0 },
|
|
460
536
|
duration: 1,
|
|
461
537
|
}).onScroll({ scrub: true, pin: '.section-wrapper', start: 'top top', end: '+=600' });
|
|
462
538
|
```
|
|
463
539
|
|
|
464
|
-
**`toggleActions`** controls what happens at each scroll boundary. Format: `"onEnter onLeave onEnterBack onLeaveBack"`. Default: `"play reverse play reverse"`. Valid actions: `play`, `pause`, `reverse`, `restart`, `reset`, `complete`, `
|
|
540
|
+
**`toggleActions`** controls what happens at each scroll boundary. Format: `"onEnter onLeave onEnterBack onLeaveBack"`. Default: `"play reverse play reverse"`. Valid actions: `play`, `pause`, `resume`, `reverse`, `restart`, `reset`, `complete`, `none`.
|
|
465
541
|
|
|
466
542
|
```ts
|
|
467
543
|
// Play once — never reverse (common for reveal animations)
|
|
@@ -507,8 +583,7 @@ Motion('h-scroll', '.panel', {
|
|
|
507
583
|
|
|
508
584
|
```ts
|
|
509
585
|
Motion('parallax', '.hero-bg', {
|
|
510
|
-
|
|
511
|
-
to: { y: -100 },
|
|
586
|
+
to: { y: -100 },
|
|
512
587
|
}).onScroll({ scrub: 1, start: 'top top', end: 'bottom top' });
|
|
513
588
|
```
|
|
514
589
|
|
|
@@ -550,8 +625,8 @@ Play the animation automatically when the page finishes loading. If called after
|
|
|
550
625
|
|
|
551
626
|
```ts
|
|
552
627
|
Motion('page-intro', [
|
|
553
|
-
{ target: '.logo', from: { opacity: 0 },
|
|
554
|
-
{ target: '.nav', from: { y: -20, opacity: 0 },
|
|
628
|
+
{ target: '.logo', from: { opacity: 0 }, duration: 0.5 },
|
|
629
|
+
{ target: '.nav', from: { y: -20, opacity: 0 }, duration: 0.4 },
|
|
555
630
|
]).onPageLoad();
|
|
556
631
|
```
|
|
557
632
|
|
|
@@ -660,8 +735,7 @@ animationStep: { Up: 0.2, Down: 0.1 } // different step size per direction
|
|
|
660
735
|
|
|
661
736
|
```ts
|
|
662
737
|
Motion('swipe-gallery', '.gallery', {
|
|
663
|
-
|
|
664
|
-
to: { x: -100 },
|
|
738
|
+
to: { x: -100 },
|
|
665
739
|
}).onGesture({
|
|
666
740
|
types: ['pointer', 'touch'],
|
|
667
741
|
events: {
|
|
@@ -770,7 +844,6 @@ Attach callbacks via the `AnimationConfig` object or directly on the `Timeline`
|
|
|
770
844
|
```ts
|
|
771
845
|
Motion('slide-in', '.card', {
|
|
772
846
|
from: { opacity: 0, x: -40 },
|
|
773
|
-
to: { opacity: 1, x: 0 },
|
|
774
847
|
duration: 0.6,
|
|
775
848
|
onStart: () => console.log('started'),
|
|
776
849
|
onUpdate: (progress) => console.log('progress:', progress),
|
|
@@ -784,7 +857,7 @@ Motion('slide-in', '.card', {
|
|
|
784
857
|
#### Via `Timeline` Methods
|
|
785
858
|
|
|
786
859
|
```ts
|
|
787
|
-
Motion('slide-in', '.card', { from: { opacity: 0 },
|
|
860
|
+
Motion('slide-in', '.card', { from: { opacity: 0 }, duration: 0.6 })
|
|
788
861
|
.onStart(() => console.log('started'))
|
|
789
862
|
.onUpdate((progress, time) => console.log(progress, time))
|
|
790
863
|
.onComplete(() => console.log('done'));
|
|
@@ -867,7 +940,7 @@ drawSVG // string | { start?: number; end?: n
|
|
|
867
940
|
|
|
868
941
|
// Motion path
|
|
869
942
|
path: {
|
|
870
|
-
target: string | Element
|
|
943
|
+
target: string | Element; // SVG <path> selector, element, or raw path data (starts with M/m)
|
|
871
944
|
align?: string | Element; // Align bounding box to this element
|
|
872
945
|
alignAt?: [number, number]; // Origin point [x%, y%], default [50, 50]
|
|
873
946
|
start?: number; // Path start (0–1), default 0
|
|
@@ -991,7 +1064,6 @@ Split elements receive data attributes for CSS targeting:
|
|
|
991
1064
|
```ts
|
|
992
1065
|
Motion('text-reveal', '.headline', {
|
|
993
1066
|
from: { opacity: 0, y: 20 },
|
|
994
|
-
to: { opacity: 1, y: 0 },
|
|
995
1067
|
duration: 0.5,
|
|
996
1068
|
split: 'chars',
|
|
997
1069
|
stagger: { each: 0.03, from: 'start' },
|
|
@@ -1007,7 +1079,6 @@ Motion('reveal', 'h1', {
|
|
|
1007
1079
|
split: 'lines',
|
|
1008
1080
|
mask: true,
|
|
1009
1081
|
from: { y: '100%' },
|
|
1010
|
-
to: { y: 0 },
|
|
1011
1082
|
stagger: 0.1,
|
|
1012
1083
|
}).onPageLoad();
|
|
1013
1084
|
```
|
|
@@ -1049,23 +1120,22 @@ Easing names are **case-insensitive** strings. Pass them to `AnimationConfig.eas
|
|
|
1049
1120
|
| Family | Variants |
|
|
1050
1121
|
|--------|----------|
|
|
1051
1122
|
| `linear`, `none` | — |
|
|
1052
|
-
| `power1` | `power1.in` · `power1.out` · `power1.
|
|
1053
|
-
| `power2` | `power2.in` · `power2.out` · `power2.
|
|
1054
|
-
| `power3` | `power3.in` · `power3.out` · `power3.
|
|
1055
|
-
| `power4` | `power4.in` · `power4.out` · `power4.
|
|
1056
|
-
| `sine` | `sine.in` · `sine.out` · `sine.
|
|
1057
|
-
| `expo` | `expo.in` · `expo.out` · `expo.
|
|
1058
|
-
| `circ` | `circ.in` · `circ.out` · `circ.
|
|
1059
|
-
| `back` | `back.in` · `back.out` · `back.
|
|
1060
|
-
| `elastic` | `elastic.in` · `elastic.out` · `elastic.
|
|
1061
|
-
| `bounce` | `bounce.in` · `bounce.out` · `bounce.
|
|
1123
|
+
| `power1` | `power1.in` · `power1.out` · `power1.inOut` |
|
|
1124
|
+
| `power2` | `power2.in` · `power2.out` · `power2.inOut` |
|
|
1125
|
+
| `power3` | `power3.in` · `power3.out` · `power3.inOut` |
|
|
1126
|
+
| `power4` | `power4.in` · `power4.out` · `power4.inOut` |
|
|
1127
|
+
| `sine` | `sine.in` · `sine.out` · `sine.inOut` |
|
|
1128
|
+
| `expo` | `expo.in` · `expo.out` · `expo.inOut` |
|
|
1129
|
+
| `circ` | `circ.in` · `circ.out` · `circ.inOut` |
|
|
1130
|
+
| `back` | `back.in` · `back.out` · `back.inOut` |
|
|
1131
|
+
| `elastic` | `elastic.in` · `elastic.out` · `elastic.inOut` |
|
|
1132
|
+
| `bounce` | `bounce.in` · `bounce.out` · `bounce.inOut` |
|
|
1062
1133
|
|
|
1063
1134
|
Unknown strings fall back to `power1.out`.
|
|
1064
1135
|
|
|
1065
1136
|
```ts
|
|
1066
1137
|
Motion('spring-in', '.box', {
|
|
1067
1138
|
from: { scale: 0 },
|
|
1068
|
-
to: { scale: 1 },
|
|
1069
1139
|
duration: 0.8,
|
|
1070
1140
|
ease: 'elastic.out',
|
|
1071
1141
|
}).play();
|
|
@@ -1110,7 +1180,6 @@ import type {
|
|
|
1110
1180
|
GestureEvent,
|
|
1111
1181
|
GestureAction,
|
|
1112
1182
|
GestureInputType,
|
|
1113
|
-
TimelineAction,
|
|
1114
1183
|
|
|
1115
1184
|
// Cursor
|
|
1116
1185
|
CursorConfig,
|
|
@@ -1124,21 +1193,44 @@ import { Types } from '@motion.page/sdk';
|
|
|
1124
1193
|
|
|
1125
1194
|
---
|
|
1126
1195
|
|
|
1196
|
+
## AI Agent Support
|
|
1197
|
+
|
|
1198
|
+
This package includes built-in support for AI coding assistants.
|
|
1199
|
+
|
|
1200
|
+
**`llms.txt` included** — An `llms.txt` file (per the [llmstxt.org](https://llmstxt.org) standard) ships with the package and is automatically discoverable by AI assistants when `@motion.page/sdk` is installed in `node_modules`. It provides a structured index of the entire SDK API so agents can answer questions and generate correct code without hallucinating APIs.
|
|
1201
|
+
|
|
1202
|
+
**Full skill plugin** — For comprehensive AI-assisted development — complete API reference, 50+ examples, and GSAP / Framer Motion migration guides — install the official plugin:
|
|
1203
|
+
|
|
1204
|
+
```bash
|
|
1205
|
+
# Universal (40+ agents)
|
|
1206
|
+
npx skills add motion-page/claude-plugin
|
|
1207
|
+
|
|
1208
|
+
# Claude Code
|
|
1209
|
+
/install-plugin npm:@motion.page/claude-plugin
|
|
1210
|
+
```
|
|
1211
|
+
|
|
1212
|
+
---
|
|
1213
|
+
|
|
1127
1214
|
## Browser Build
|
|
1128
1215
|
|
|
1129
|
-
|
|
1216
|
+
### Browser Build (IIFE)
|
|
1217
|
+
|
|
1218
|
+
An IIFE build script is included but not part of the default build output. To generate a browser bundle:
|
|
1219
|
+
|
|
1220
|
+
```bash
|
|
1221
|
+
bun run packages/sdk/scripts/build-iife.ts
|
|
1222
|
+
```
|
|
1223
|
+
|
|
1224
|
+
This creates a self-contained script that exposes `window.Motion` and `window.MotionTimeline`:
|
|
1130
1225
|
|
|
1131
1226
|
```html
|
|
1132
|
-
<!-- From your own server / CDN -->
|
|
1133
1227
|
<script src="motion-sdk.browser.js"></script>
|
|
1134
1228
|
<script>
|
|
1135
|
-
// Globals are exposed on window:
|
|
1136
1229
|
const { Motion, MotionTimeline } = window;
|
|
1137
1230
|
|
|
1138
|
-
Motion('fade
|
|
1139
|
-
from: { opacity: 0 },
|
|
1140
|
-
|
|
1141
|
-
duration: 1,
|
|
1231
|
+
Motion('fade', '.hero', {
|
|
1232
|
+
from: { opacity: 0, y: 30 },
|
|
1233
|
+
duration: 0.8,
|
|
1142
1234
|
}).onPageLoad();
|
|
1143
1235
|
</script>
|
|
1144
1236
|
```
|
|
@@ -1160,4 +1252,12 @@ Modern evergreen browsers:
|
|
|
1160
1252
|
|
|
1161
1253
|
## License
|
|
1162
1254
|
|
|
1163
|
-
|
|
1255
|
+
**FSL-1.1-Apache-2.0** — [Functional Source License, Version 1.1, Apache 2.0 Future License](./LICENSE)
|
|
1256
|
+
|
|
1257
|
+
**TL;DR:** Free for everyone. Use it in your websites, apps, SaaS products, client projects — commercial or not. No restrictions.
|
|
1258
|
+
|
|
1259
|
+
**The one exception:** You cannot use this SDK to build a product that competes with Motion.page (e.g., a no-code animation builder, visual animation editor, or similar tool). If you're building something like that, [contact us](mailto:hello@motion.page) for an enterprise license.
|
|
1260
|
+
|
|
1261
|
+
After 2 years from each release, the code converts to the [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) license with no restrictions at all.
|
|
1262
|
+
|
|
1263
|
+
See [LICENSE](./LICENSE) for the full legal text.
|
package/llms.txt
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @motion.page/sdk
|
|
2
|
+
|
|
3
|
+
> Zero-dependency animation SDK with named timelines, 8 trigger types, text splitting, FLIP morphing, custom cursors, and SVG drawing. Browser-only (requires document/window).
|
|
4
|
+
|
|
5
|
+
For complete SDK documentation, install the motion-page skill: `npx skills add motion-page/claude-plugin`
|
|
6
|
+
|
|
7
|
+
## Getting Started
|
|
8
|
+
|
|
9
|
+
- **Installation**: npm install @motion.page/sdk; ESM, CJS, and browser IIFE builds
|
|
10
|
+
- **Quick Start**: Basic fade-in, scroll-triggered, and multi-step timeline examples
|
|
11
|
+
- **Core Concept**: Named timelines — Motion(name) retrieves or creates; same name = same instance
|
|
12
|
+
- **Implicit Values**: from-only resolves current CSS as to; to-only resolves current CSS as from; natural defaults (opacity:1, x:0, y:0, scale:1) are auto-filled
|
|
13
|
+
|
|
14
|
+
## Core API
|
|
15
|
+
|
|
16
|
+
- **Motion()**: Factory with 3 overloads — retrieve timeline, single animation, multi-step array
|
|
17
|
+
- **Motion.set()**: Instant property setting (zero duration)
|
|
18
|
+
- **Motion.kill() / killAll()**: Destroy named timelines; killAll for SPA cleanup
|
|
19
|
+
- **Motion.reset()**: Kill tweens on targets and revert text splits
|
|
20
|
+
- **Motion.refreshScrollTriggers()**: Recalculate scroll positions after DOM changes
|
|
21
|
+
- **Motion.cleanup()**: Remove ScrollTrigger spacer/marker DOM nodes
|
|
22
|
+
- **Motion.utils**: toArray, clamp, random, snap, interpolate, mapRange, normalize, wrap — all support currying
|
|
23
|
+
|
|
24
|
+
## Timeline
|
|
25
|
+
|
|
26
|
+
- **Playback Control**: play, pause, reverse, restart, seek
|
|
27
|
+
- **State**: progress, time, timeScale, duration, isActive — getter/setter pattern
|
|
28
|
+
- **Lifecycle Callbacks**: onStart, onUpdate(progress, time), onComplete
|
|
29
|
+
- **Sequencing**: tl.call(fn, params, position) — fire functions at timeline positions
|
|
30
|
+
|
|
31
|
+
## Triggers
|
|
32
|
+
|
|
33
|
+
- **.onPageLoad()**: Auto-play when DOM ready
|
|
34
|
+
- **.onScroll(config)**: start, end, scrub, pin, pinSpacing, markers, toggleActions, snap, scroller
|
|
35
|
+
- **.onHover(config)**: target, each, onLeave (reverse/pause/stop/restart/none), leaveDelay
|
|
36
|
+
- **.onClick(config)**: target, each, toggle (reverse/restart/play), secondTarget, preventDefault
|
|
37
|
+
- **.onMouseMove(config)**: type (distance/axis), smooth, startProgress, leaveProgress
|
|
38
|
+
- **.onGesture(config)**: types (pointer/touch/wheel/scroll), events map, tolerance, dragMinimum, lockAxis
|
|
39
|
+
- **.onCursor(config)**: type (basic/text/media), smooth, squeeze, hideNative, default/hover/click states
|
|
40
|
+
- **.onPageExit(config)**: mode (all/include/exclude), selectors, skipHref
|
|
41
|
+
|
|
42
|
+
## Animation Config
|
|
43
|
+
|
|
44
|
+
- **AnimationConfig**: from, to, duration, delay, ease, stagger, repeat, split, mask, fit, axis, callbacks
|
|
45
|
+
- **AnimationVars**: Transforms, opacity, colors, CSS properties, filter, drawSVG, path, custom properties
|
|
46
|
+
- **Easing**: power1-4, sine, expo, circ, back, elastic, bounce — .in/.out/.inOut
|
|
47
|
+
- **Stagger**: each, amount, from (start/center/edges/random/end/index), grid, axis, ease
|
|
48
|
+
- **Position Parameter**: Absolute (number), relative (+=/-=), anchored (<, >, <0.2, >-0.1)
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
- **Text Splitting**: split: chars/words/lines; mask: true for clip reveals; data-split-* attributes
|
|
53
|
+
- **FLIP Morphing**: fit: { target, scale, resize, absolute } — animate between element states
|
|
54
|
+
- **DrawSVG**: String format ("0% 100%") or object ({ start, end } as 0-100 percentages)
|
|
55
|
+
- **Motion Path**: path: { target, align, start, end, rotate }
|
|
56
|
+
- **Custom Cursors**: type: basic/text/media; mp-cursor-text and mp-cursor-media HTML attributes
|
|
57
|
+
|
|
58
|
+
## Optional
|
|
59
|
+
|
|
60
|
+
- **Types Reference**: All exported TypeScript types and interfaces
|
|
61
|
+
- **Browser Build**: IIFE bundle exposing window.Motion and window.MotionTimeline
|
|
62
|
+
- **SPA Cleanup**: Motion.killAll() + Motion.cleanup() on route change
|
|
63
|
+
- **Migration from GSAP**: gsap.to → Motion(name, target, {to}).play(); ScrollTrigger → .onScroll()
|
|
64
|
+
- **Migration from Framer Motion**: motion.div → Motion(name, selector, config); whileHover → .onHover()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motion.page/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "High-performance CSS animation SDK with scroll, hover, gesture, and cursor triggers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"llms.txt"
|
|
18
19
|
],
|
|
19
20
|
"scripts": {
|
|
20
21
|
"build": "rm -rf dist && tsc -p tsconfig.build.json && bun build src/index.ts --outdir dist --minify --sourcemap=linked && mkdir -p dist/.cjs-tmp && bun build src/index.ts --outdir dist/.cjs-tmp --format=cjs --minify --sourcemap=linked && mv dist/.cjs-tmp/index.js dist/index.cjs && mv dist/.cjs-tmp/index.js.map dist/index.cjs.map && rm -rf dist/.cjs-tmp",
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
"transform"
|
|
43
44
|
],
|
|
44
45
|
"author": "Motion.page",
|
|
45
|
-
"license": "
|
|
46
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
46
47
|
"homepage": "https://motion.page",
|
|
47
48
|
"engines": {
|
|
48
49
|
"node": ">=18"
|