anim-engine 0.1.2 → 0.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 +152 -103
- package/dist/animation/create-animation.d.ts +3 -3
- package/dist/animation/create-animation.js +90 -201
- package/dist/animation/runner.d.ts +37 -0
- package/dist/animation/runner.js +220 -0
- package/dist/shared/types.d.ts +0 -1
- package/dist/timeline/create-timeline.d.ts +5 -4
- package/dist/timeline/create-timeline.js +101 -76
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center">anim-engine</h1>
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/anim-engine)
|
|
6
|
+
[](https://github.com/LukeCarlThompson/anim-engine/blob/main/packages/anim-engine/LICENSE)
|
|
7
|
+
[](https://github.com/LukeCarlThompson/anim-engine/actions)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
|
|
10
|
+
</div>
|
|
2
11
|
|
|
3
12
|
**Renderer-agnostic animation for JavaScript runtimes.** A fast, lightweight, pure-numeric animation engine.
|
|
4
13
|
|
|
@@ -33,7 +42,7 @@ ESM only. Tree-shakeable — import only what you use.
|
|
|
33
42
|
```ts
|
|
34
43
|
import { createAnimation, getTicker } from "anim-engine";
|
|
35
44
|
|
|
36
|
-
// The ticker drives all animations. Start it once.
|
|
45
|
+
// The ticker drives all animations. Start it once or drive it with an external ticker.
|
|
37
46
|
getTicker().start();
|
|
38
47
|
|
|
39
48
|
const anim = createAnimation({
|
|
@@ -63,28 +72,28 @@ By restricting itself to numeric values, the engine eliminates string parsing, c
|
|
|
63
72
|
|
|
64
73
|
## Key advantages
|
|
65
74
|
|
|
66
|
-
| |
|
|
67
|
-
| ---------------------------- |
|
|
68
|
-
| ⚡ **Fast** | 1.7–
|
|
69
|
-
| 🪶 **Lightweight** | Tree-shakeable ESM — import only what you use. No DOM, no canvas, no dependencies.
|
|
70
|
-
| 🎯 **Numbers only** | A single numeric type for all values. No strings, no transforms, no branches. Predictable performance.
|
|
71
|
-
| 🔌 **Renderer-agnostic** | Feed values to PixiJS, ThreeJS, DOM, canvas2d, or WebGL. Same API everywhere.
|
|
72
|
-
| 🧩 **Composable models** | Animations, keyframes, and timelines compose cleanly — put tweens inside timelines, nest keyframes anywhere.
|
|
73
|
-
| 🔄 **Continuous primitives** | Spring, smooth damp, and lerp chase live targets with zero setup — pass `() => value` for dynamic targets.
|
|
74
|
-
| 🚫 **No GC pressure** | Zero object allocations in hot update paths. State is mutated in place.
|
|
75
|
-
| 🎨 **Perceptual color** | Oklab interpolation via `lerpOklab` — no muddy browns. Compose it into any `onUpdate`.
|
|
76
|
-
| 📐 **TypeScript-first** | Full type exports, exhaustive discriminated unions, no `any`.
|
|
77
|
-
| 🔧 **Ticker control** | Bring your own game loop or use the built-in rAF ticker. Explicit — never auto-starts.
|
|
75
|
+
| | |
|
|
76
|
+
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
77
|
+
| ⚡ **Fast** | 1.7–7.5× faster than GSAP overall; 3.0–6.2× when comparing equivalent `onUpdate` callback dispatch (see [benchmarks](#benchmarks)). |
|
|
78
|
+
| 🪶 **Lightweight** | Tree-shakeable ESM — import only what you use. No DOM, no canvas, no dependencies. |
|
|
79
|
+
| 🎯 **Numbers only** | A single numeric type for all values. No strings, no transforms, no branches. Predictable performance. |
|
|
80
|
+
| 🔌 **Renderer-agnostic** | Feed values to PixiJS, ThreeJS, DOM, canvas2d, or WebGL. Same API everywhere. |
|
|
81
|
+
| 🧩 **Composable models** | Animations, keyframes, and timelines compose cleanly — put tweens inside timelines, nest keyframes anywhere. |
|
|
82
|
+
| 🔄 **Continuous primitives** | Spring, smooth damp, and lerp chase live targets with zero setup — pass `() => value` for dynamic targets. |
|
|
83
|
+
| 🚫 **No GC pressure** | Zero object allocations in hot update paths. State is mutated in place. |
|
|
84
|
+
| 🎨 **Perceptual color** | Oklab interpolation via `lerpOklab` — no muddy browns. Compose it into any `onUpdate`. |
|
|
85
|
+
| 📐 **TypeScript-first** | Full type exports, exhaustive discriminated unions, no `any`. |
|
|
86
|
+
| 🔧 **Ticker control** | Bring your own game loop or use the built-in rAF ticker. Explicit — never auto-starts. |
|
|
78
87
|
|
|
79
88
|
## Primitives
|
|
80
89
|
|
|
81
90
|
### Timed (return `Animation`)
|
|
82
91
|
|
|
83
|
-
| Primitive | Returns
|
|
84
|
-
| ------------------------------------------- |
|
|
85
|
-
| [`createAnimation`](#createanimation) | `Animation`
|
|
86
|
-
| [`createAnimation` (keyframes)](#keyframes) | `Animation`
|
|
87
|
-
| [`createTimeline`](#createtimeline) | `Timeline`
|
|
92
|
+
| Primitive | Returns | Description |
|
|
93
|
+
| ------------------------------------------- | ----------- | ---------------------------------------------------- |
|
|
94
|
+
| [`createAnimation`](#createanimation) | `Animation` | Timed tween from A to B with easing and delay |
|
|
95
|
+
| [`createAnimation` (keyframes)](#keyframes) | `Animation` | Multi-segment interpolation with per-segment easing |
|
|
96
|
+
| [`createTimeline`](#createtimeline) | `Timeline` | Orchestrate multiple animations on a shared timeline |
|
|
88
97
|
|
|
89
98
|
Animations have `play()`/`pause()`/`resume()`/`stop()`/`skipToEnd()`/`kill()` controls, return a `Promise` from `play()`, and emit `onUpdate`/`onEnded`/`onProgress` callbacks.
|
|
90
99
|
|
|
@@ -135,47 +144,48 @@ anim.skipToEnd(); // jumps to end, resolves promise
|
|
|
135
144
|
|
|
136
145
|
**Single-tween options:**
|
|
137
146
|
|
|
138
|
-
| Option | Type
|
|
139
|
-
| ------------ |
|
|
140
|
-
| `from` | `number \| () => number`
|
|
141
|
-
| `to` | `number \| () => number`
|
|
142
|
-
| `durationMs` | `number`
|
|
143
|
-
| `ease` | `EaseName \| EaseFunction`
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
|
|
147
|
+
| Option | Type | Default | Description |
|
|
148
|
+
| ------------ | ------------------------------------------- | ------------- | ------------------------------------------------------------ |
|
|
149
|
+
| `from` | `number \| () => number` | — | Start value |
|
|
150
|
+
| `to` | `number \| () => number` | — | End value |
|
|
151
|
+
| `durationMs` | `number \| () => number` | — | Duration in milliseconds |
|
|
152
|
+
| `ease` | `EaseName \| EaseFunction` | `"inOutSine"` | Easing function or name |
|
|
153
|
+
| `onStarted` | `() => void` | — | Called when playback begins |
|
|
154
|
+
| `onUpdate` | `(value: number, velocity: number) => void` | — | Called every frame with current value and velocity (units/s) |
|
|
155
|
+
| `onEnded` | `() => void` | — | Called when animation completes |
|
|
156
|
+
|
|
148
157
|
**Returns:** `Animation`
|
|
149
158
|
|
|
150
159
|
### Keyframes
|
|
151
160
|
|
|
152
|
-
Multi-segment animation with per-keyframe easing. The
|
|
161
|
+
Multi-segment animation with per-keyframe easing. The first keyframe is the starting point (no gap/ease). Each subsequent keyframe specifies the gap from the previous one and an optional easing. Total duration is the sum of all gaps.
|
|
153
162
|
|
|
154
163
|
```ts
|
|
155
164
|
import { createAnimation } from "anim-engine";
|
|
156
165
|
|
|
157
166
|
const anim = createAnimation({
|
|
158
167
|
keyframes: [
|
|
159
|
-
{
|
|
160
|
-
{
|
|
161
|
-
{
|
|
162
|
-
{
|
|
168
|
+
{ value: 0 },
|
|
169
|
+
{ value: 50, gap: 300, ease: "outCubic" },
|
|
170
|
+
{ value: 80, gap: 400, ease: "inOutQuad" },
|
|
171
|
+
{ value: 100, gap: 300 },
|
|
163
172
|
],
|
|
164
173
|
onUpdate: (value) => (sprite.x = value),
|
|
165
174
|
onProgress: (progress) => console.log(`${Math.round(progress * 100)}%`),
|
|
166
175
|
});
|
|
167
176
|
```
|
|
168
177
|
|
|
169
|
-
Each keyframe's `
|
|
178
|
+
Each keyframe's `gap` is in milliseconds from the previous keyframe. Total duration is the sum of all gaps (1000ms in this example). If no `ease` is specified on a keyframe, `"inOutSine"` is used as the default.
|
|
170
179
|
|
|
171
180
|
**Keyframe options:**
|
|
172
181
|
|
|
173
|
-
| Option | Type | Description
|
|
174
|
-
| ------------ | ------------------------------------------- |
|
|
175
|
-
| `keyframes` | `Keyframe[]` | Array of `{
|
|
176
|
-
| `
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
182
|
+
| Option | Type | Description |
|
|
183
|
+
| ------------ | ------------------------------------------- | -------------------------------------------------- |
|
|
184
|
+
| `keyframes` | `Keyframe[]` | Array of `{ value, gap?, ease? }` keyframes |
|
|
185
|
+
| `onStarted` | `() => void` | Called when playback begins |
|
|
186
|
+
| `onUpdate` | `(value: number, velocity: number) => void` | Called every frame with current value and velocity |
|
|
187
|
+
| `onProgress` | `(progress: number) => void` | Called every frame with 0–1 global progress |
|
|
188
|
+
| `onEnded` | `() => void` | Called when the keyframe animation completes |
|
|
179
189
|
|
|
180
190
|
**Returns:** `Animation`
|
|
181
191
|
|
|
@@ -218,45 +228,38 @@ for (let i = 0; i < 6; i++) {
|
|
|
218
228
|
For more complex sequences, use `createTimeline`:
|
|
219
229
|
|
|
220
230
|
```ts
|
|
221
|
-
import {
|
|
222
|
-
|
|
223
|
-
const fadeIn = createAnimation({ from: 0, to: 1, durationMs: 300 });
|
|
224
|
-
const fadeOut = createAnimation({ from: 1, to: 0, durationMs: 300 });
|
|
231
|
+
import { createTimeline } from "anim-engine";
|
|
225
232
|
|
|
226
233
|
const flash = createTimeline([
|
|
227
|
-
{ at: 0,
|
|
228
|
-
{ gap: 0,
|
|
234
|
+
{ at: 0, keyframe: { keyframes: [{ value: 0 }, { value: 1, gap: 300 }] } },
|
|
235
|
+
{ gap: 0, keyframe: { keyframes: [{ value: 1 }, { value: 0, gap: 300 }] } },
|
|
229
236
|
]);
|
|
230
237
|
await flash.play();
|
|
231
238
|
```
|
|
232
239
|
|
|
233
|
-
|
|
234
240
|
### createTimeline
|
|
235
241
|
|
|
236
|
-
Compose multiple animations on a shared timeline with `at` or `gap` positions.
|
|
242
|
+
Compose multiple keyframe animations on a shared timeline with `at` or `gap` positions. Parallelism comes from multiple layers at the same `at`.
|
|
237
243
|
|
|
238
244
|
```ts
|
|
239
|
-
import {
|
|
240
|
-
|
|
241
|
-
const fadeIn = createAnimation({
|
|
242
|
-
from: 0,
|
|
243
|
-
to: 1,
|
|
244
|
-
durationMs: 500,
|
|
245
|
-
onUpdate: (v) => (sprite.alpha = v),
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
const slideIn = createAnimation({
|
|
249
|
-
from: -100,
|
|
250
|
-
to: 0,
|
|
251
|
-
durationMs: 800,
|
|
252
|
-
ease: "outBack",
|
|
253
|
-
onUpdate: (v) => (sprite.x = v),
|
|
254
|
-
});
|
|
245
|
+
import { createTimeline } from "anim-engine";
|
|
255
246
|
|
|
256
247
|
const timeline = createTimeline(
|
|
257
248
|
[
|
|
258
|
-
{
|
|
259
|
-
|
|
249
|
+
{
|
|
250
|
+
at: 0,
|
|
251
|
+
keyframe: {
|
|
252
|
+
keyframes: [{ value: 0 }, { value: 1, gap: 500 }],
|
|
253
|
+
onUpdate: (v) => (sprite.alpha = v),
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
at: 0,
|
|
258
|
+
keyframe: {
|
|
259
|
+
keyframes: [{ value: -100 }, { value: 0, gap: 800, ease: "outBack" }],
|
|
260
|
+
onUpdate: (v) => (sprite.x = v),
|
|
261
|
+
},
|
|
262
|
+
},
|
|
260
263
|
],
|
|
261
264
|
{
|
|
262
265
|
onProgress: (progress) => console.log(`overall: ${progress}`),
|
|
@@ -270,8 +273,8 @@ timeline.play();
|
|
|
270
273
|
|
|
271
274
|
```ts
|
|
272
275
|
type TimelineLayer =
|
|
273
|
-
| {
|
|
274
|
-
| {
|
|
276
|
+
| { keyframe: KeyframedAnimationOptions; at: DynamicValue }
|
|
277
|
+
| { keyframe: KeyframedAnimationOptions; gap: number };
|
|
275
278
|
```
|
|
276
279
|
|
|
277
280
|
| Parameter | Type | Description |
|
|
@@ -281,7 +284,7 @@ type TimelineLayer =
|
|
|
281
284
|
| `options.onProgress` | `(progress) => void` | Called every frame with overall 0–1 progress |
|
|
282
285
|
| `options.onEnded` | `() => void` | Called when timeline finishes |
|
|
283
286
|
|
|
284
|
-
`gap` is relative to the end of
|
|
287
|
+
`gap` is relative to the end of the previous layer. Use multiple layers at the same `at` for parallel animations. A simple tween is expressed as a 2-keyframe sequence: `{ value: from }, { value: to, gap: durationMs }`.
|
|
285
288
|
|
|
286
289
|
### Continuous primitives
|
|
287
290
|
|
|
@@ -380,8 +383,8 @@ Perceptually uniform Oklab interpolation. Straight RGB lerp produces muddy trans
|
|
|
380
383
|
```ts
|
|
381
384
|
import { lerpOklab, hexToRgba } from "anim-engine";
|
|
382
385
|
|
|
383
|
-
hexToRgba("#ff6b6b");
|
|
384
|
-
hexToRgba("#f80");
|
|
386
|
+
hexToRgba("#ff6b6b"); // → [1, 0.42, 0.42, 1]
|
|
387
|
+
hexToRgba("#f80"); // → [1, 0.533, 0, 1] (shorthand)
|
|
385
388
|
hexToRgba("#ff804080"); // → [1, 0.502, 0.251, 0.502] (with alpha)
|
|
386
389
|
|
|
387
390
|
const fromColor = hexToRgba("#ff6b6b");
|
|
@@ -484,32 +487,77 @@ You can pass the result directly to any `ease` option — it's an `EaseFunction`
|
|
|
484
487
|
|
|
485
488
|
## Dynamic values
|
|
486
489
|
|
|
487
|
-
|
|
490
|
+
The `DynamicValue` type (`number | (() => number)`) lets you provide values that are resolved at runtime. How often they're resolved depends on the primitive:
|
|
491
|
+
|
|
492
|
+
### Timed animations (per-play)
|
|
493
|
+
|
|
494
|
+
In `createAnimation` — tweens and keyframes — all dynamic values are resolved **once when `play()` is called** and cached for the duration of that run. The frame-hot update path reads from the cache with zero overhead:
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
const anim = createAnimation({
|
|
498
|
+
from: () => getLayoutStart(),
|
|
499
|
+
to: () => getLayoutEnd(),
|
|
500
|
+
durationMs: () => 500 / speedMultiplier,
|
|
501
|
+
keyframes: [
|
|
502
|
+
{ at: 0, value: 0 },
|
|
503
|
+
{ at: () => scrollHeight * 0.3, value: 50 },
|
|
504
|
+
{ at: () => scrollHeight, value: 100 },
|
|
505
|
+
],
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
// Values resolved here, cached for duration
|
|
509
|
+
await anim.play();
|
|
510
|
+
|
|
511
|
+
// On re-play, values are re-resolved
|
|
512
|
+
await anim.play();
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
This means `from`, `to`, `durationMs`, `keyframe.at`, and `keyframe.value` are all evaluated at play time and remain stable throughout the animation. If you need truly per-frame dynamic values, that's the domain of continuous primitives.
|
|
516
|
+
|
|
517
|
+
### Continuous primitives (per-frame)
|
|
518
|
+
|
|
519
|
+
In `createSpring`, `createSmoothDamp`, and `createLerp`, dynamic values are resolved **every frame** — these primitives are designed to chase live targets:
|
|
488
520
|
|
|
489
521
|
```ts
|
|
490
522
|
const spring = createSpring({
|
|
491
|
-
to: () => getMousePosition(), //
|
|
523
|
+
to: () => getMousePosition(), // re-read every frame
|
|
492
524
|
stiffness: () => sliderValue, // dynamic stiffness
|
|
493
525
|
damping: () => dampingValue,
|
|
494
526
|
});
|
|
495
527
|
```
|
|
496
528
|
|
|
497
|
-
|
|
529
|
+
This distinction reflects the two use-cases: timed animations describe a fixed motion path evaluated at start, while continuous primitives describe ongoing behaviour that adapts to changing input.
|
|
498
530
|
|
|
499
531
|
## Benchmarks
|
|
500
532
|
|
|
501
|
-
Performance comparison against GSAP (vitest bench, Apple Silicon M-series, Node 24).
|
|
533
|
+
Performance comparison against GSAP (vitest bench, Apple Silicon M-series, Node 24). All easing functions are matched between libraries.
|
|
534
|
+
|
|
535
|
+
### vs GSAP internal mutation
|
|
536
|
+
|
|
537
|
+
GSAP defaults to mutating target properties directly. This is faster than dispatching callbacks but couples GSAP to the mutation pattern. Anim-engine always dispatches via `onUpdate` (renderer-agnostic).
|
|
538
|
+
|
|
539
|
+
| Benchmark | anim-engine | GSAP | Ratio |
|
|
540
|
+
| --------------------------------------------- | ------------ | ------------ | ----------- |
|
|
541
|
+
| **Single tween** (cubic, 1000 frames) | 40,814 ops/s | 10,776 ops/s | 3.8× faster |
|
|
542
|
+
| **Single tween** (linear, 1000 frames) | 28,590 ops/s | 14,499 ops/s | 2.0× faster |
|
|
543
|
+
| **Single tween** (cubic bezier, 1000 frames) | 21,449 ops/s | 12,637 ops/s | 1.7× faster |
|
|
544
|
+
| **Keyframe** (3 segments, 1000 frames) | 26,741 ops/s | 3,549 ops/s | 7.5× faster |
|
|
545
|
+
| **50 concurrent tweens** (500 frames) | 892 ops/s | 438 ops/s | 2.0× faster |
|
|
546
|
+
| **200 concurrent tweens** (500 frames) | 200 ops/s | 106 ops/s | 1.9× faster |
|
|
547
|
+
| **1000 concurrent tweens** (500 frames) | 38 ops/s | 22 ops/s | 1.7× faster |
|
|
548
|
+
| **50 concurrent keyframes** (500 frames) | 934 ops/s | 174 ops/s | 5.4× faster |
|
|
549
|
+
| **50-layer timeline** (staggered, 500 frames) | 710 ops/s | 404 ops/s | 1.8× faster |
|
|
550
|
+
| **50 tweens re-play** (2 cycles, 500 frames) | 558 ops/s | 128 ops/s | 4.4× faster |
|
|
551
|
+
|
|
552
|
+
### vs GSAP onUpdate (fair comparison)
|
|
502
553
|
|
|
503
|
-
|
|
504
|
-
| -------------------------------------------- | ------------ | ------------ | ------------ |
|
|
505
|
-
| **Single tween** (cubic, 1000 frames) | 43,265 ops/s | 9,542 ops/s | 4.53× faster |
|
|
506
|
-
| **Single tween** (linear, 1000 frames) | 30,461 ops/s | 16,195 ops/s | 1.88× faster |
|
|
507
|
-
| **Single tween** (cubic bezier, 1000 frames) | 21,439 ops/s | 12,869 ops/s | 1.67× faster |
|
|
508
|
-
| **Keyframe** (3 segments, 1000 frames) | 35,307 ops/s | 3,560 ops/s | 9.92× faster |
|
|
509
|
-
| **50 concurrent tweens** (500 frames) | 942 ops/s | 473 ops/s | 1.99× faster |
|
|
510
|
-
| **50 concurrent keyframes** (500 frames) | 918 ops/s | 171 ops/s | 5.38× faster |
|
|
554
|
+
gsap also supports `onUpdate` callbacks, which is equivalent to anim-engine's renderer-agnostic model. This is the apples-to-apples comparison.
|
|
511
555
|
|
|
512
|
-
|
|
556
|
+
| Benchmark | anim-engine | GSAP (onUpdate) | Ratio |
|
|
557
|
+
| -------------------------------------- | ------------ | --------------- | ----------- |
|
|
558
|
+
| **Single tween** (cubic, 1000 frames) | 40,814 ops/s | 6,618 ops/s | 6.2× faster |
|
|
559
|
+
| **50 concurrent tweens** (500 frames) | 892 ops/s | 273 ops/s | 3.3× faster |
|
|
560
|
+
| **200 concurrent tweens** (500 frames) | 200 ops/s | 66 ops/s | 3.0× faster |
|
|
513
561
|
|
|
514
562
|
Run locally: `npm run bench`
|
|
515
563
|
|
|
@@ -615,24 +663,25 @@ requestAnimationFrame(gameLoop);
|
|
|
615
663
|
|
|
616
664
|
### Type exports
|
|
617
665
|
|
|
618
|
-
| Type
|
|
619
|
-
|
|
|
620
|
-
| `Animation`
|
|
621
|
-
| `Interpolation`
|
|
622
|
-
| `Timeline`
|
|
623
|
-
| `EaseName`
|
|
624
|
-
| `EaseFunction`
|
|
625
|
-
| `DynamicValue`
|
|
626
|
-
| `AnimationStatus`
|
|
627
|
-
| `InterpolationStatus`
|
|
628
|
-
| `AnimationOptions`
|
|
629
|
-
| `Keyframe`
|
|
630
|
-
| `
|
|
631
|
-
| `
|
|
632
|
-
| `
|
|
633
|
-
| `
|
|
634
|
-
| `
|
|
635
|
-
| `
|
|
666
|
+
| Type | Description |
|
|
667
|
+
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
668
|
+
| `Animation` | `play`, `pause`, `resume`, `stop`, `skipToEnd`, `kill`, `setProgress`, `currentValue`, `velocity`, `progress`, `status` |
|
|
669
|
+
| `Interpolation` | `start`, `stop`, `kill`, `setCurrentValue`, `currentValue`, `velocity`, `status` |
|
|
670
|
+
| `Timeline` | `play`, `pause`, `resume`, `stop`, `skipToEnd`, `kill`, `setProgress`, `progress`, `status` |
|
|
671
|
+
| `EaseName` | Union of 31 ease name strings |
|
|
672
|
+
| `EaseFunction` | `(t: number) => number` |
|
|
673
|
+
| `DynamicValue` | `number \| (() => number)` |
|
|
674
|
+
| `AnimationStatus` | `"playing" \| "paused" \| "stopped" \| "dead"` (for `Animation` / `Timeline`) |
|
|
675
|
+
| `InterpolationStatus` | `"active" \| "inactive" \| "dead"` (for `Interpolation`) |
|
|
676
|
+
| `AnimationOptions` | Single tween or keyframe animation options (discriminated union) |
|
|
677
|
+
| `Keyframe` | `{ value, gap?, ease? }` |
|
|
678
|
+
| `KeyframedAnimationOptions` | `{ keyframes: Keyframe[], onStarted?, onUpdate?, onProgress?, onEnded? }` |
|
|
679
|
+
| `TimelineLayer` | `{ keyframe: KeyframedAnimationOptions; at: DynamicValue } \| { keyframe: KeyframedAnimationOptions; gap: number }` |
|
|
680
|
+
| `SpringOptions` | `to`, `stiffness`, `damping`, `mass`, `precision?`, `onUpdate`, `onEnded` |
|
|
681
|
+
| `SmoothDampOptions` | `to`, `smoothTimeMs`, `maxSpeed?`, `precision?`, `onUpdate`, `onEnded` |
|
|
682
|
+
| `LerpOptions` | `to`, `smoothTimeMs`, `precision?`, `onUpdate`, `onEnded` |
|
|
683
|
+
| `RgbaTuple` | `readonly [number, number, number, number]` |
|
|
684
|
+
| `TickerControls` | `start`, `stop`, `update`, `add`, `remove` |
|
|
636
685
|
|
|
637
686
|
## License
|
|
638
687
|
|
|
@@ -2,20 +2,20 @@ import { Animation, DynamicValue, EaseFunction, EaseName } from '../shared/types
|
|
|
2
2
|
export type SingleTweenOptions = {
|
|
3
3
|
from: DynamicValue;
|
|
4
4
|
to: DynamicValue;
|
|
5
|
-
durationMs:
|
|
5
|
+
durationMs: DynamicValue;
|
|
6
6
|
ease?: EaseName | EaseFunction;
|
|
7
|
-
delayMs?: number;
|
|
8
7
|
onStarted?: () => void;
|
|
9
8
|
onUpdate?: (value: number, velocity: number) => void;
|
|
10
9
|
onEnded?: () => void;
|
|
11
10
|
};
|
|
12
11
|
export type Keyframe = {
|
|
13
|
-
at: number;
|
|
14
12
|
value: DynamicValue;
|
|
15
13
|
ease?: EaseName | EaseFunction;
|
|
14
|
+
gap?: DynamicValue;
|
|
16
15
|
};
|
|
17
16
|
export type KeyframedAnimationOptions = {
|
|
18
17
|
keyframes: Keyframe[];
|
|
18
|
+
onStarted?: () => void;
|
|
19
19
|
onUpdate?: (value: number, velocity: number) => void;
|
|
20
20
|
onProgress?: (progress: number) => void;
|
|
21
21
|
onEnded?: () => void;
|