animotionjs-plus 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/README.md +0 -470
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "animotionjs-plus",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "An advanced custom web animation engine for Vanilla JS, React, and Next.js with CSS, Three.js, Lottie, and dotLottie support.",
|
|
5
5
|
"main": "dist/animotion.min.js",
|
|
6
6
|
"module": "src/index.core.js",
|
package/README.md
DELETED
|
@@ -1,470 +0,0 @@
|
|
|
1
|
-
# Animotion-js
|
|
2
|
-
|
|
3
|
-
Animotion is a custom web animation engine for Vanilla JS, React, and Next.js.
|
|
4
|
-
|
|
5
|
-
It now supports:
|
|
6
|
-
|
|
7
|
-
- direct JS tweens and timelines
|
|
8
|
-
- declarative `am-*` custom attributes
|
|
9
|
-
- DOM, CSS, CSS variables, transforms, filters, and scroll properties
|
|
10
|
-
- plain objects and nested property paths
|
|
11
|
-
- Three.js objects and scene state
|
|
12
|
-
- Lottie and dotLottie playback control
|
|
13
|
-
- scoped animation contexts for framework apps
|
|
14
|
-
|
|
15
|
-
## Core Setup Modes
|
|
16
|
-
|
|
17
|
-
You can use Animotion in 3 main ways:
|
|
18
|
-
|
|
19
|
-
1. Imperative JS with `Animotion.to()`, `Animotion.from()`, `Animotion.timeline()`
|
|
20
|
-
2. Declarative custom attributes with `am-*`
|
|
21
|
-
3. Scoped attribute hydration in React/Next with hooks
|
|
22
|
-
|
|
23
|
-
## Installation
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npm install animotion-js
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Optional peer integrations:
|
|
30
|
-
|
|
31
|
-
- `three`
|
|
32
|
-
- `@lottiefiles/dotlottie-web`
|
|
33
|
-
|
|
34
|
-
## Main API
|
|
35
|
-
|
|
36
|
-
```js
|
|
37
|
-
import Animotion from 'animotion-js';
|
|
38
|
-
import 'animotion-js/styles.css';
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Available top-level methods:
|
|
42
|
-
|
|
43
|
-
- `Animotion.init()`
|
|
44
|
-
- `Animotion.initAttributes()`
|
|
45
|
-
- `Animotion.to()`
|
|
46
|
-
- `Animotion.from()`
|
|
47
|
-
- `Animotion.fromTo()`
|
|
48
|
-
- `Animotion.set()`
|
|
49
|
-
- `Animotion.tween()`
|
|
50
|
-
- `Animotion.timeline()`
|
|
51
|
-
- `Animotion.spring()`
|
|
52
|
-
- `Animotion.keyframes()`
|
|
53
|
-
- `Animotion.motionPath()`
|
|
54
|
-
- `Animotion.sequence()`
|
|
55
|
-
- `Animotion.context()`
|
|
56
|
-
- `Animotion.interactions()`
|
|
57
|
-
- `Animotion.video()`
|
|
58
|
-
- `Animotion.lottie()`
|
|
59
|
-
- `Animotion.dotLottie()`
|
|
60
|
-
- `Animotion.threeStateMachine()`
|
|
61
|
-
- `Animotion.animotionAttrs()`
|
|
62
|
-
|
|
63
|
-
## Supported Property Scenarios
|
|
64
|
-
|
|
65
|
-
Animotion can tween:
|
|
66
|
-
|
|
67
|
-
- regular CSS properties like `opacity`, `backgroundColor`, `boxShadow`, `clipPath`, `borderRadius`
|
|
68
|
-
- transform aliases like `x`, `y`, `z`, `scale`, `scaleX`, `scaleY`, `rotate`, `rotateX`, `rotateY`, `rotateZ`
|
|
69
|
-
- filter aliases like `blur`, `brightness`, `contrast`, `grayscale`, `hueRotate`, `invert`, `saturate`, `sepia`
|
|
70
|
-
- CSS custom properties like `--brand-hue`
|
|
71
|
-
- DOM properties like `scrollTop`, `scrollLeft`, `value`
|
|
72
|
-
- attributes with `attr.data-state`
|
|
73
|
-
- nested object paths like `position.x`, `rotation.y`, `material.opacity`, `camera.position.z`
|
|
74
|
-
- plain JS state objects used for counters, controllers, and render loops
|
|
75
|
-
- Three.js object trees
|
|
76
|
-
- Lottie and dotLottie playhead/frame/progress control
|
|
77
|
-
|
|
78
|
-
Interpolation currently covers:
|
|
79
|
-
|
|
80
|
-
- numbers
|
|
81
|
-
- unit strings
|
|
82
|
-
- colors
|
|
83
|
-
- arrays
|
|
84
|
-
- nested objects
|
|
85
|
-
- complex CSS-like strings containing numbers
|
|
86
|
-
|
|
87
|
-
## Vanilla JS
|
|
88
|
-
|
|
89
|
-
```js
|
|
90
|
-
Animotion.to('.card', {
|
|
91
|
-
opacity: 1,
|
|
92
|
-
y: '0px',
|
|
93
|
-
rotateY: '0deg',
|
|
94
|
-
backgroundColor: '#111827',
|
|
95
|
-
boxShadow: '0 24px 80px rgba(0, 0, 0, 0.35)'
|
|
96
|
-
}, {
|
|
97
|
-
duration: 1.2,
|
|
98
|
-
ease: 'expo-out',
|
|
99
|
-
stagger: 0.08
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
Animotion.fromTo('.meter', {
|
|
103
|
-
'--fill': '0%'
|
|
104
|
-
}, {
|
|
105
|
-
'--fill': '100%'
|
|
106
|
-
}, {
|
|
107
|
-
duration: 1.4
|
|
108
|
-
});
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## Timelines
|
|
112
|
-
|
|
113
|
-
```js
|
|
114
|
-
const timeline = Animotion.timeline({ autoplay: false })
|
|
115
|
-
.addLabel('intro')
|
|
116
|
-
.from('.hero-title', { opacity: 0, y: '60px' }, 0.9, 'expo-out', 'intro')
|
|
117
|
-
.from('.hero-copy', { opacity: 0, y: '30px' }, 0.7, 'expo-out', 'intro+=0.15')
|
|
118
|
-
.to('.hero-card', { rotateY: '14deg', z: '24px' }, 1.2, 'ease-in-out', 'intro+=0.2')
|
|
119
|
-
.set('.badge', { opacity: 1 }, 'intro+=0.4')
|
|
120
|
-
.call(() => console.log('intro complete'), 'intro+=1');
|
|
121
|
-
|
|
122
|
-
timeline.play();
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
## Higher-Level Motion
|
|
126
|
-
|
|
127
|
-
```js
|
|
128
|
-
Animotion.spring('.chip', { x: 240, opacity: 1 }, {
|
|
129
|
-
stiffness: 220,
|
|
130
|
-
damping: 24
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
Animotion.keyframes('.panel', [
|
|
134
|
-
{ to: { opacity: 1, y: '0px' }, duration: 0.5 },
|
|
135
|
-
{ to: { rotateY: '12deg' }, duration: 0.8, at: '+=0.1' },
|
|
136
|
-
{ to: { rotateY: '0deg' }, duration: 0.5 }
|
|
137
|
-
]);
|
|
138
|
-
|
|
139
|
-
Animotion.motionPath('.orb', {
|
|
140
|
-
points: [{ x: 0, y: 0 }, { x: 140, y: -40 }, { x: 260, y: 80 }],
|
|
141
|
-
autoRotate: true,
|
|
142
|
-
duration: 2
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
Animotion.sequence([
|
|
146
|
-
{ id: 'intro', enter: { target: '.title', to: { opacity: 1, y: '0px' }, duration: 0.8 } },
|
|
147
|
-
{ id: 'detail', enter: { target: '.card', to: { opacity: 1, scale: 1 }, duration: 0.6 } }
|
|
148
|
-
]);
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## The Declarative `am-*` Attribute System
|
|
152
|
-
|
|
153
|
-
Animotion now supports a custom attribute workflow built around the `am-*` prefix.
|
|
154
|
-
Every `am-*` declaration also has a matching `data-anim-*` alias. For example, `am-to` can be written as `data-anim-to`, `am-video-frames` can be written as `data-anim-video-frames`, and `am-motion-path` can be written as `data-anim-motion-path`.
|
|
155
|
-
|
|
156
|
-
Legacy aliases still work too:
|
|
157
|
-
|
|
158
|
-
- `data-anim` maps to `am`
|
|
159
|
-
- `data-anim-scroll-trigger` maps to `am-scroll`
|
|
160
|
-
- `data-anim-split-text` maps to `am-split`
|
|
161
|
-
|
|
162
|
-
You can hydrate it with:
|
|
163
|
-
|
|
164
|
-
```js
|
|
165
|
-
Animotion.initAttributes();
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
or:
|
|
169
|
-
|
|
170
|
-
```js
|
|
171
|
-
Animotion.init({ root: document, attributePrefix: 'am' });
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### Base Motion Attributes
|
|
175
|
-
|
|
176
|
-
- `am`
|
|
177
|
-
- `data-anim`
|
|
178
|
-
- `am-id`
|
|
179
|
-
- `am-target`
|
|
180
|
-
- `am-to`
|
|
181
|
-
- `am-from`
|
|
182
|
-
- `am-set`
|
|
183
|
-
- `am-options`
|
|
184
|
-
- `am-duration`
|
|
185
|
-
- `am-delay`
|
|
186
|
-
- `am-ease`
|
|
187
|
-
- `am-repeat`
|
|
188
|
-
- `am-yoyo`
|
|
189
|
-
- `am-stagger`
|
|
190
|
-
|
|
191
|
-
All of the above also work as `data-anim-id`, `data-anim-target`, `data-anim-to`, and so on.
|
|
192
|
-
|
|
193
|
-
### Trigger Attributes
|
|
194
|
-
|
|
195
|
-
- `am-on="load"`
|
|
196
|
-
- `am-on="click"`
|
|
197
|
-
- `am-on="mouseenter"`
|
|
198
|
-
- `am-on="focus"`
|
|
199
|
-
- `am-on="pointerdown"`
|
|
200
|
-
- `am-on="inview"`
|
|
201
|
-
- `am-on="click,mouseenter"`
|
|
202
|
-
- `am-once="true"`
|
|
203
|
-
- `am-prevent-default="true"`
|
|
204
|
-
|
|
205
|
-
### Timeline Attributes
|
|
206
|
-
|
|
207
|
-
- `am-timeline="hero"`
|
|
208
|
-
- `am-timeline-auto="true"`
|
|
209
|
-
- `am-timeline-options='{"repeat":1}'`
|
|
210
|
-
- `am-position=">"`
|
|
211
|
-
- `am-position="intro+=0.2"`
|
|
212
|
-
- `am-label="intro"`
|
|
213
|
-
- `am-control="hero"`
|
|
214
|
-
- `am-action="play"`
|
|
215
|
-
|
|
216
|
-
### Scroll / Scene Attributes
|
|
217
|
-
|
|
218
|
-
- `am-scroll='{"start":"top center","once":true}'`
|
|
219
|
-
- `am-scroll='{"scrub":true}'`
|
|
220
|
-
- `am-mouse='{"movement":24,"duration":0.35}'`
|
|
221
|
-
- `am-parallax="0.35"`
|
|
222
|
-
- `am-parallax-options='{"axis":"x","speed":0.2}'`
|
|
223
|
-
- `am-draggable='{"lockAxis":"x"}'`
|
|
224
|
-
- `am-spring='{"to":{"x":240,"opacity":1},"stiffness":220,"damping":24}'`
|
|
225
|
-
- `am-keyframes='[{"to":{"opacity":1},"duration":0.4},{"to":{"x":"80px"},"duration":0.6}]'`
|
|
226
|
-
- `am-motion-path='{"points":[{"x":0,"y":0},{"x":140,"y":-40},{"x":260,"y":80}],"autoRotate":true}'`
|
|
227
|
-
- `am-path='{"points":[{"x":0,"y":0},{"x":120,"y":60}]}'`
|
|
228
|
-
- `am-sequence='[{"id":"intro","enter":{"target":".title","to":{"opacity":1}}}]'`
|
|
229
|
-
|
|
230
|
-
Each scene-level attribute has the same `data-anim-*` form, including `data-anim-spring`, `data-anim-keyframes`, `data-anim-motion-path`, `data-anim-path`, and `data-anim-sequence`.
|
|
231
|
-
|
|
232
|
-
### Text / Media Attributes
|
|
233
|
-
|
|
234
|
-
- `am-split="chars"`
|
|
235
|
-
- `am-split="words"`
|
|
236
|
-
- `am-split="lines"`
|
|
237
|
-
- `am-split-target="chars"`
|
|
238
|
-
- `am-lottie="/animations/hero.json"`
|
|
239
|
-
- `am-lottie-options='{"loop":false,"renderer":"svg"}'`
|
|
240
|
-
- `am-lottie-on="inview"`
|
|
241
|
-
- `am-lottie-action="play"`
|
|
242
|
-
- `am-lottie-progress="0.65"`
|
|
243
|
-
- `am-lottie-frame="120"`
|
|
244
|
-
- `am-lottie-segment="40,120"`
|
|
245
|
-
- `am-dotlottie="/animations/hero.lottie"`
|
|
246
|
-
- `am-dotlottie-options='{"loop":true}'`
|
|
247
|
-
- `am-dotlottie-on="click"`
|
|
248
|
-
- `am-video="/video/scene.mp4"`
|
|
249
|
-
- `am-video-autoplay="inview"`
|
|
250
|
-
- `am-video-action="play"`
|
|
251
|
-
- `am-video-action="scrub"`
|
|
252
|
-
- `am-video-segment="4.5,9.25"`
|
|
253
|
-
- `am-video-frames="120,220"`
|
|
254
|
-
- `am-video-frame-rate="24"`
|
|
255
|
-
- `am-video-pause-on-leave="true"`
|
|
256
|
-
- `am-three-state="Walk"`
|
|
257
|
-
- `am-three-machine="hero-character"`
|
|
258
|
-
- `am-three-action="play"`
|
|
259
|
-
- `am-three-on="click"`
|
|
260
|
-
|
|
261
|
-
Media and Three.js declarations also work as `data-anim-video`, `data-anim-video-autoplay`, `data-anim-video-frames`, `data-anim-three-state`, `data-anim-three-machine`, and the rest of the systematic aliases.
|
|
262
|
-
|
|
263
|
-
## HTML Example
|
|
264
|
-
|
|
265
|
-
```html
|
|
266
|
-
<section am am-target=".card" am-from='{"opacity":0,"y":"60px","scale":0.92}' am-to='{"opacity":1,"y":"0px","scale":1}' am-duration="1" am-stagger="0.08">
|
|
267
|
-
<article class="card">One</article>
|
|
268
|
-
<article class="card">Two</article>
|
|
269
|
-
<article class="card">Three</article>
|
|
270
|
-
</section>
|
|
271
|
-
|
|
272
|
-
<button am-control="hero" am-action="play" am-on="click">Play Timeline</button>
|
|
273
|
-
|
|
274
|
-
<div am-scroll='{"scrub":true}' am-to='{"rotateY":"20deg","x":"80px"}'></div>
|
|
275
|
-
|
|
276
|
-
<h1 am am-split="chars" am-split-target="chars" am-from='{"opacity":0,"y":"40px"}' am-to='{"opacity":1,"y":"0px"}' am-stagger="0.03"></h1>
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
## React Setup
|
|
280
|
-
|
|
281
|
-
Use scoped hydration:
|
|
282
|
-
|
|
283
|
-
```jsx
|
|
284
|
-
import { useAnimotionAttributes, animotionAttrs } from 'animotion-js/react';
|
|
285
|
-
import 'animotion-js/styles.css';
|
|
286
|
-
|
|
287
|
-
export function Hero() {
|
|
288
|
-
const scopeRef = useAnimotionAttributes({}, []);
|
|
289
|
-
|
|
290
|
-
return (
|
|
291
|
-
<section ref={scopeRef}>
|
|
292
|
-
<h1
|
|
293
|
-
{...animotionAttrs({
|
|
294
|
-
split: 'chars',
|
|
295
|
-
splitTarget: 'chars',
|
|
296
|
-
from: { opacity: 0, y: '48px' },
|
|
297
|
-
to: { opacity: 1, y: '0px' },
|
|
298
|
-
duration: 0.9,
|
|
299
|
-
stagger: 0.03
|
|
300
|
-
})}
|
|
301
|
-
>
|
|
302
|
-
Animotion
|
|
303
|
-
</h1>
|
|
304
|
-
|
|
305
|
-
<div
|
|
306
|
-
{...animotionAttrs({
|
|
307
|
-
on: 'mouseenter',
|
|
308
|
-
from: { scale: 1 },
|
|
309
|
-
to: { scale: 1.08, rotateY: '8deg' },
|
|
310
|
-
duration: 0.4
|
|
311
|
-
})}
|
|
312
|
-
/>
|
|
313
|
-
</section>
|
|
314
|
-
);
|
|
315
|
-
}
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
## Next.js Setup
|
|
319
|
-
|
|
320
|
-
```jsx
|
|
321
|
-
'use client';
|
|
322
|
-
|
|
323
|
-
import { useAnimotionAttributes, animotionAttrs } from 'animotion-js/next';
|
|
324
|
-
import 'animotion-js/styles.css';
|
|
325
|
-
|
|
326
|
-
export default function Page() {
|
|
327
|
-
const scopeRef = useAnimotionAttributes({}, []);
|
|
328
|
-
|
|
329
|
-
return (
|
|
330
|
-
<main ref={scopeRef}>
|
|
331
|
-
<canvas
|
|
332
|
-
{...animotionAttrs({
|
|
333
|
-
dotlottie: '/animations/hero.lottie',
|
|
334
|
-
dotlottieOn: 'inview',
|
|
335
|
-
dotlottieAction: 'play'
|
|
336
|
-
})}
|
|
337
|
-
/>
|
|
338
|
-
</main>
|
|
339
|
-
);
|
|
340
|
-
}
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
## Three.js
|
|
344
|
-
|
|
345
|
-
```js
|
|
346
|
-
Animotion.to(mesh, {
|
|
347
|
-
position: { x: 3, y: 1.5, z: -2 },
|
|
348
|
-
rotation: { y: Math.PI * 1.5 },
|
|
349
|
-
material: { opacity: 0.4, color: '#22c55e' }
|
|
350
|
-
}, {
|
|
351
|
-
duration: 1.6,
|
|
352
|
-
ease: 'ease-in-out',
|
|
353
|
-
render: () => renderer.render(scene, camera)
|
|
354
|
-
});
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
GLTF files can expose multiple animation clips. Animotion can wrap those clips as a small action state machine:
|
|
358
|
-
|
|
359
|
-
```js
|
|
360
|
-
const actor = Animotion.threeStateMachine(gltf, {
|
|
361
|
-
THREE,
|
|
362
|
-
renderer,
|
|
363
|
-
scene,
|
|
364
|
-
camera,
|
|
365
|
-
initialState: 'Idle',
|
|
366
|
-
fade: 0.25
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
actor.play('Walk');
|
|
370
|
-
actor.play('Jump', { fade: 0.1, loop: 'LoopOnce', clampWhenFinished: true });
|
|
371
|
-
actor.update(delta);
|
|
372
|
-
actor.stopLoop();
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
For declarative Three.js state controls, register the machine with an id and point an element at it:
|
|
376
|
-
|
|
377
|
-
```js
|
|
378
|
-
Animotion.threeStateMachine(gltf, {
|
|
379
|
-
id: 'hero-character',
|
|
380
|
-
THREE,
|
|
381
|
-
renderer,
|
|
382
|
-
scene,
|
|
383
|
-
camera,
|
|
384
|
-
initialState: 'Idle'
|
|
385
|
-
});
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
```html
|
|
389
|
-
<button data-anim-three-machine="hero-character" data-anim-three-state="Walk" data-anim-three-action="play" data-anim-three-on="click">
|
|
390
|
-
Walk
|
|
391
|
-
</button>
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
## Video Sections
|
|
395
|
-
|
|
396
|
-
Use one video as a cinematic source and play different time or frame ranges per section:
|
|
397
|
-
|
|
398
|
-
```js
|
|
399
|
-
const reel = Animotion.video(document.querySelector('.scene-a'), {
|
|
400
|
-
src: '/video/reel.mp4',
|
|
401
|
-
autoplay: false,
|
|
402
|
-
frameRate: 24,
|
|
403
|
-
sections: {
|
|
404
|
-
opening: { frames: [0, 96] },
|
|
405
|
-
reveal: { start: 8.5, end: 14.2 }
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
reel.playSegment('opening');
|
|
410
|
-
reel.playFrames(144, 220);
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
Declarative sections can autoplay on viewport entry or scrub only the selected slice:
|
|
414
|
-
|
|
415
|
-
```html
|
|
416
|
-
<section am-video="/video/reel.mp4" am-video-autoplay="inview" am-video-frames="0,96" am-video-frame-rate="24"></section>
|
|
417
|
-
<section am-video="/video/reel.mp4" am-video-on="inview" am-video-action="scrub" am-video-segment="8.5,14.2"></section>
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
The same setup with complete `data-anim-*` aliases:
|
|
421
|
-
|
|
422
|
-
```html
|
|
423
|
-
<section data-anim-video="/video/reel.mp4" data-anim-video-autoplay="inview" data-anim-video-frames="0,96" data-anim-video-frame-rate="24"></section>
|
|
424
|
-
<section data-anim-video="/video/reel.mp4" data-anim-video-on="inview" data-anim-video-action="scrub" data-anim-video-segment="8.5,14.2"></section>
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
## Lottie
|
|
428
|
-
|
|
429
|
-
```js
|
|
430
|
-
const lottie = Animotion.lottie({
|
|
431
|
-
container: document.querySelector('#lottie'),
|
|
432
|
-
renderer: 'svg',
|
|
433
|
-
loop: false,
|
|
434
|
-
autoplay: false,
|
|
435
|
-
path: '/animations/hero.json'
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
lottie.tweenToProgress(0.75, {
|
|
439
|
-
duration: 1.2,
|
|
440
|
-
ease: 'ease-in-out'
|
|
441
|
-
});
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
## dotLottie
|
|
445
|
-
|
|
446
|
-
```js
|
|
447
|
-
const dotLottie = Animotion.dotLottie({
|
|
448
|
-
canvas: document.querySelector('#dotlottie'),
|
|
449
|
-
src: '/animations/hero.lottie',
|
|
450
|
-
autoplay: false,
|
|
451
|
-
loop: true
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
dotLottie.setSpeed(1.2).play();
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
## Notes
|
|
458
|
-
|
|
459
|
-
- Legacy `data-anim-*` attributes still work.
|
|
460
|
-
- The new recommended declarative setup is `am-*`.
|
|
461
|
-
- React and Next can use the same attribute model via `animotionAttrs()`.
|
|
462
|
-
- `npm test` currently passes with no tests because the repo still has no actual Jest test suite.
|
|
463
|
-
|
|
464
|
-
## Commands
|
|
465
|
-
|
|
466
|
-
```bash
|
|
467
|
-
npm run lint
|
|
468
|
-
npm test
|
|
469
|
-
npm run build
|
|
470
|
-
```
|