@pixerate/editor 0.27.0 → 0.28.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 +25 -2
- package/dist/animation/index.cjs +62 -0
- package/dist/animation/index.cjs.map +1 -0
- package/dist/animation/index.d.cts +296 -0
- package/dist/animation/index.d.ts +296 -0
- package/dist/animation/index.js +62 -0
- package/dist/animation/index.js.map +1 -0
- package/dist/canvas/index.cjs +177 -743
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +3 -288
- package/dist/canvas/index.d.ts +3 -288
- package/dist/canvas/index.js +49 -615
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-JT7AXQTE.js → chunk-3RPOW4CS.js} +7 -7
- package/dist/chunk-A6PHCAGX.cjs +87 -0
- package/dist/chunk-A6PHCAGX.cjs.map +1 -0
- package/dist/{chunk-HRMEDT2L.js → chunk-D6AVOTSD.js} +6 -85
- package/dist/chunk-D6AVOTSD.js.map +1 -0
- package/dist/{chunk-4BVP64JJ.cjs → chunk-K2UYKJ6M.cjs} +24 -103
- package/dist/chunk-K2UYKJ6M.cjs.map +1 -0
- package/dist/{chunk-6IO7WUSU.js → chunk-MXZJ4PKN.js} +14 -14
- package/dist/{chunk-AGR7EVRW.cjs → chunk-OYEFRO3D.cjs} +6 -6
- package/dist/{chunk-AGR7EVRW.cjs.map → chunk-OYEFRO3D.cjs.map} +1 -1
- package/dist/chunk-PWJARCI4.js +637 -0
- package/dist/chunk-PWJARCI4.js.map +1 -0
- package/dist/chunk-TGD52FEZ.js +87 -0
- package/dist/chunk-TGD52FEZ.js.map +1 -0
- package/dist/chunk-TTYCN6ZH.cjs +637 -0
- package/dist/chunk-TTYCN6ZH.cjs.map +1 -0
- package/dist/{chunk-YK5TATOF.cjs → chunk-U7VGDSNY.cjs} +3 -3
- package/dist/{chunk-YK5TATOF.cjs.map → chunk-U7VGDSNY.cjs.map} +1 -1
- package/dist/extensions/index.cjs +7 -7
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.js +12 -12
- package/dist/generation/index.cjs +3 -3
- package/dist/generation/index.cjs.map +1 -1
- package/dist/generation/index.js +3 -3
- package/dist/index.cjs +20 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +103 -103
- package/dist/spreadsheet/index.cjs +4 -4
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.js +8 -8
- package/dist/tokens/index.cjs +4 -2
- package/dist/tokens/index.cjs.map +1 -1
- package/dist/tokens/index.js +6 -4
- package/package.json +6 -1
- package/dist/chunk-4BVP64JJ.cjs.map +0 -1
- package/dist/chunk-HRMEDT2L.js.map +0 -1
- /package/dist/{chunk-JT7AXQTE.js.map → chunk-3RPOW4CS.js.map} +0 -0
- /package/dist/{chunk-6IO7WUSU.js.map → chunk-MXZJ4PKN.js.map} +0 -0
package/README.md
CHANGED
|
@@ -399,7 +399,8 @@ Each module is also available as a subpath import:
|
|
|
399
399
|
| `@pixerate/editor/history` | `HistoryManager`: a command-pattern undo/redo stack with gesture merge keys, undo marks, a byte budget and a History-panel listing; `DirtyTracker` / `bindDirtyToHistory` |
|
|
400
400
|
| `@pixerate/editor/spreadsheet` | `SpreadsheetController`, formula parser/evaluator and dependency graph, formula function registry (`registerFormulaFunction`, `listFormulaFunctions`, `searchFormulaFunctions`, `getFormulaSignature`) and autocomplete helpers (`getFormulaHints`, `applyFormulaSuggestion`) |
|
|
401
401
|
| `@pixerate/editor/image-editor` | `ImageEditorController` and Canvas 2D renderer: crop, adjustments, annotations, depth masks, selections and layer masks, and AI hooks. Needs a DOM/canvas environment (the selection algorithms themselves are pure). |
|
|
402
|
-
| `@pixerate/editor/
|
|
402
|
+
| `@pixerate/editor/animation` | The keyframe model without canvas nodes: `AnimationTrack` / `AnimationKeyframe`, easing (`resolveEasing`, `evaluateEasing`, `cubicBezierAt`, `springAt`, presets, `parseCssEasing`, `easingToCss`), `evaluateTrack`, `interpolateAnimationValue`, `normalizeKeyframes`, OKLab colour mixing, `AnimationPlayer` and the `Clock` / `ManualClock` / `realClock` time sources (no third-party imports) |
|
|
403
|
+
| `@pixerate/editor/canvas` | Node-graph layout (needs the optional `@dagrejs/dagre` peer), placement, trajectories, displacement, clipboard and streaming layout helpers, and node keyframe animation (re-exports everything in `/animation`) |
|
|
403
404
|
| `@pixerate/editor/agent` | MCP tool schemas, a planner for agent-driven canvas edits, and the dynamic `ToolRegistry` with editor/spreadsheet tool providers |
|
|
404
405
|
| `@pixerate/editor/commands` | `CommandRegistry`, `ShortcutMap`, palette ranking, `createCommandToolProvider` and built-in history / arrange / spreadsheet commands (no third-party imports) |
|
|
405
406
|
| `@pixerate/editor/persistence` | Autosave and crash recovery (`createAutosaveController`, `createRecoveryPolicy`, `createRevisionTracker`), storage adapters (memory, localStorage, IndexedDB, OPFS) and document migration (`migrateDocument`, `loadSections`, `LoadReport`) (no third-party imports) |
|
|
@@ -408,7 +409,29 @@ Each module is also available as a subpath import:
|
|
|
408
409
|
| `@pixerate/editor/export` | Word export: `exportDocx`, `exportDocxBlob`, `createDocxParts`, `DocxExportController`, plus the zip writer and XML escapers it uses (no third-party imports; also re-exported from the root entry) |
|
|
409
410
|
| `@pixerate/editor/tokens` | Design tokens: collections, modes, aliases, `TokenStore`, `resolveToken`, W3C Design Tokens JSON and CSS custom-property export (no third-party imports) |
|
|
410
411
|
|
|
411
|
-
The root entry (`@pixerate/editor`) re-exports everything except canvas, agent, commands, persistence, generation, tokens and image editor, including TipTap. Import from the narrowest subpath you need: `grammar`, `history`, `spreadsheet`, `commands`, `persistence` and `image-editor` have no third-party imports, so a spreadsheet-only app bundles no TipTap, markdown or dagre code. The package is marked `sideEffects: false`, so unused root exports are also tree-shaken.
|
|
412
|
+
The root entry (`@pixerate/editor`) re-exports everything except animation, canvas, agent, commands, persistence, generation, tokens and image editor, including TipTap. Import from the narrowest subpath you need: `grammar`, `history`, `animation`, `spreadsheet`, `commands`, `persistence` and `image-editor` have no third-party imports, so a spreadsheet-only app bundles no TipTap, markdown or dagre code. The package is marked `sideEffects: false`, so unused root exports are also tree-shaken.
|
|
413
|
+
|
|
414
|
+
## Keyframe animation without the canvas
|
|
415
|
+
|
|
416
|
+
`@pixerate/editor/animation` is the keyframe model on its own: no dagre, TipTap or canvas nodes. Use it to animate anything you can describe as a track of numbers or CSS colours.
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
import { evaluateTrack, createAnimationPlayer, ManualClock, type AnimationTrack } from "@pixerate/editor/animation";
|
|
420
|
+
|
|
421
|
+
const opacity: AnimationTrack = {
|
|
422
|
+
keyframes: [
|
|
423
|
+
{ time: 0, value: 0, easing: "ease-out" },
|
|
424
|
+
{ time: 600, value: 1, easing: { type: "spring", stiffness: 170, damping: 26 } },
|
|
425
|
+
{ time: 1200, value: 0.5 },
|
|
426
|
+
],
|
|
427
|
+
};
|
|
428
|
+
evaluateTrack(opacity, 300); // eased value at 300 ms
|
|
429
|
+
evaluateTrack({ keyframes: [{ time: 0, value: "#ff0000" }, { time: 1000, value: "transparent" }] }, 500, "color"); // OKLab mix
|
|
430
|
+
|
|
431
|
+
const player = createAnimationPlayer({ clock: new ManualClock(), duration: 1200, loop: "ping-pong", onTime: (t) => console.log(evaluateTrack(opacity, t)) });
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
`@pixerate/editor/canvas` re-exports all of it, and adds node tracks (`evaluateAnimation`, `applyAnimation`), editing, timeline and export helpers on top.
|
|
412
435
|
|
|
413
436
|
## Autosave, crash recovery and document migration
|
|
414
437
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
var _chunkTTYCN6ZHcjs = require('../chunk-TTYCN6ZH.cjs');
|
|
31
|
+
require('../chunk-A6PHCAGX.cjs');
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
exports.ANIMATION_EASING_LABELS = _chunkTTYCN6ZHcjs.ANIMATION_EASING_LABELS; exports.ANIMATION_EASING_PRESETS = _chunkTTYCN6ZHcjs.ANIMATION_EASING_PRESETS; exports.ANIMATION_TIME_EPSILON = _chunkTTYCN6ZHcjs.ANIMATION_TIME_EPSILON; exports.AnimationPlayer = _chunkTTYCN6ZHcjs.AnimationPlayer; exports.CUBIC_BEZIER_PRESETS = _chunkTTYCN6ZHcjs.CUBIC_BEZIER_PRESETS; exports.ManualClock = _chunkTTYCN6ZHcjs.ManualClock; exports.createAnimationPlayer = _chunkTTYCN6ZHcjs.createAnimationPlayer; exports.cubicBezierAt = _chunkTTYCN6ZHcjs.cubicBezierAt; exports.easingFromInfluence = _chunkTTYCN6ZHcjs.easingFromInfluence; exports.easingLabel = _chunkTTYCN6ZHcjs.easingLabel; exports.easingToCss = _chunkTTYCN6ZHcjs.easingToCss; exports.evaluateEasing = _chunkTTYCN6ZHcjs.evaluateEasing; exports.evaluateTrack = _chunkTTYCN6ZHcjs.evaluateTrack; exports.formatOklab = _chunkTTYCN6ZHcjs.formatOklab; exports.interpolateAnimationValue = _chunkTTYCN6ZHcjs.interpolateAnimationValue; exports.isAnimationEasing = _chunkTTYCN6ZHcjs.isAnimationEasing; exports.isAnimationKeyframe = _chunkTTYCN6ZHcjs.isAnimationKeyframe; exports.mixColorsOklab = _chunkTTYCN6ZHcjs.mixColorsOklab; exports.normalizeKeyframes = _chunkTTYCN6ZHcjs.normalizeKeyframes; exports.oklabToRgb = _chunkTTYCN6ZHcjs.oklabToRgb; exports.pageHidden = _chunkTTYCN6ZHcjs.pageHidden; exports.parseCssEasing = _chunkTTYCN6ZHcjs.parseCssEasing; exports.parseOklab = _chunkTTYCN6ZHcjs.parseOklab; exports.realClock = _chunkTTYCN6ZHcjs.realClock; exports.resolveEasing = _chunkTTYCN6ZHcjs.resolveEasing; exports.rgbToOklab = _chunkTTYCN6ZHcjs.rgbToOklab; exports.springAt = _chunkTTYCN6ZHcjs.springAt; exports.wrapAnimationTime = _chunkTTYCN6ZHcjs.wrapAnimationTime;
|
|
62
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/animation/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B,iCAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,+qDAAC","file":"/home/runner/work/editor/editor/packages/core/dist/animation/index.cjs"}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyframe easing: the curve a segment follows from one keyframe to the next.
|
|
3
|
+
*
|
|
4
|
+
* - `hold` keeps the first keyframe's value until the next one (a step).
|
|
5
|
+
* - `linear` and the CSS presets (`ease`, `ease-in`, `ease-out`, `ease-in-out`) are
|
|
6
|
+
* CSS-compatible `cubic-bezier()` curves; `{ type: 'cubic-bezier', x1, y1, x2, y2 }` is any
|
|
7
|
+
* such curve (x1 / y1 is the leaving keyframe's out handle, x2 / y2 the next one's in handle).
|
|
8
|
+
* - `spring` is a damped spring settling on the next value (it may overshoot).
|
|
9
|
+
*/
|
|
10
|
+
/** Named easing presets. */
|
|
11
|
+
type AnimationEasingPreset = 'linear' | 'hold' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'ease-in-back' | 'ease-out-back' | 'spring';
|
|
12
|
+
interface CubicBezierEasing {
|
|
13
|
+
type: 'cubic-bezier';
|
|
14
|
+
x1: number;
|
|
15
|
+
y1: number;
|
|
16
|
+
x2: number;
|
|
17
|
+
y2: number;
|
|
18
|
+
}
|
|
19
|
+
interface SpringEasing {
|
|
20
|
+
type: 'spring';
|
|
21
|
+
/** Spring stiffness (default 170). */
|
|
22
|
+
stiffness?: number;
|
|
23
|
+
/** Damping (default 26). */
|
|
24
|
+
damping?: number;
|
|
25
|
+
/** Mass (default 1). */
|
|
26
|
+
mass?: number;
|
|
27
|
+
/** Initial velocity in units of the segment's value change per second (default 0). */
|
|
28
|
+
velocity?: number;
|
|
29
|
+
}
|
|
30
|
+
type AnimationEasing = AnimationEasingPreset | CubicBezierEasing | SpringEasing;
|
|
31
|
+
/** Preset names, in picker order. */
|
|
32
|
+
declare const ANIMATION_EASING_PRESETS: readonly AnimationEasingPreset[];
|
|
33
|
+
/** Picker labels for the presets. */
|
|
34
|
+
declare const ANIMATION_EASING_LABELS: Readonly<Record<AnimationEasingPreset, string>>;
|
|
35
|
+
/** The CSS control points of the bezier presets (CSS Easing Functions Level 1 values for the CSS keywords). */
|
|
36
|
+
declare const CUBIC_BEZIER_PRESETS: Readonly<Record<string, readonly [number, number, number, number]>>;
|
|
37
|
+
/**
|
|
38
|
+
* Solves a CSS `cubic-bezier(x1, y1, x2, y2)` for y at progress x (Newton steps with a
|
|
39
|
+
* bisection fallback). x1 / x2 are clamped to 0–1 as CSS requires.
|
|
40
|
+
*/
|
|
41
|
+
declare function cubicBezierAt(x1: number, y1: number, x2: number, y2: number, x: number): number;
|
|
42
|
+
/**
|
|
43
|
+
* Normalised position of a damped spring released from 0 towards 1, `seconds` after release.
|
|
44
|
+
* Closed form for under-, critically and over-damped springs.
|
|
45
|
+
*/
|
|
46
|
+
declare function springAt(spring: Omit<SpringEasing, 'type'>, seconds: number): number;
|
|
47
|
+
/** Resolves an easing to a cubic-bezier, spring or hold descriptor (unknown input → linear). */
|
|
48
|
+
declare function resolveEasing(easing: AnimationEasing | string | undefined | null): CubicBezierEasing | Required<SpringEasing> | 'hold';
|
|
49
|
+
/**
|
|
50
|
+
* Eased progress for linear progress `u` (0–1) through a segment lasting `durationMs`
|
|
51
|
+
* (springs depend on real time; other curves ignore it). `hold` returns 0 until `u` reaches 1.
|
|
52
|
+
*/
|
|
53
|
+
declare function evaluateEasing(easing: AnimationEasing | string | undefined | null, u: number, durationMs?: number): number;
|
|
54
|
+
/**
|
|
55
|
+
* The easing filmcraft (and Premiere) derive from temporal "influence" handles: flat handles of
|
|
56
|
+
* the given influences (0.01–1, default 1/3) on the leaving and arriving keyframe.
|
|
57
|
+
*/
|
|
58
|
+
declare function easingFromInfluence(outInfluence?: number, inInfluence?: number): CubicBezierEasing;
|
|
59
|
+
/**
|
|
60
|
+
* Parses a CSS easing (`linear`, `ease…`, `cubic-bezier(…)`, `steps(1, end)` / `step-end` →
|
|
61
|
+
* hold) or a preset name. Returns `null` for anything else.
|
|
62
|
+
*/
|
|
63
|
+
declare function parseCssEasing(text: string): AnimationEasing | null;
|
|
64
|
+
/** Whether a value is a usable easing (preset name, CSS easing string or descriptor). */
|
|
65
|
+
declare function isAnimationEasing(value: unknown): value is AnimationEasing;
|
|
66
|
+
/**
|
|
67
|
+
* The CSS `animation-timing-function` for an easing: a keyword or `cubic-bezier()`,
|
|
68
|
+
* `steps(1, end)` for hold, and a sampled `linear(…)` for springs over `durationMs`.
|
|
69
|
+
*/
|
|
70
|
+
declare function easingToCss(easing: AnimationEasing | string | undefined | null, durationMs?: number, samples?: number): string;
|
|
71
|
+
/** Short label for an easing (a preset's label, or `Custom` / `Spring`). */
|
|
72
|
+
declare function easingLabel(easing: AnimationEasing | undefined | null): string;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Colour interpolation in OKLab (Björn Ottosson's perceptual space, as CSS Color 4 uses for
|
|
76
|
+
* `color-mix(in oklab, …)`), with premultiplied alpha so a fade to `transparent` does not
|
|
77
|
+
* darken through black.
|
|
78
|
+
*/
|
|
79
|
+
interface OklabColor {
|
|
80
|
+
/** Lightness, 0–1. */
|
|
81
|
+
l: number;
|
|
82
|
+
a: number;
|
|
83
|
+
b: number;
|
|
84
|
+
/** Alpha, 0–1. */
|
|
85
|
+
alpha: number;
|
|
86
|
+
}
|
|
87
|
+
/** sRGB channels (0–1) to OKLab. */
|
|
88
|
+
declare function rgbToOklab(r: number, g: number, b: number, alpha?: number): OklabColor;
|
|
89
|
+
/** OKLab to sRGB channels (0–1, clamped into gamut). */
|
|
90
|
+
declare function oklabToRgb(color: OklabColor): {
|
|
91
|
+
r: number;
|
|
92
|
+
g: number;
|
|
93
|
+
b: number;
|
|
94
|
+
a: number;
|
|
95
|
+
};
|
|
96
|
+
/** Parses a CSS colour (hex, `rgb()` / `rgba()`, `transparent`, `black`, `white`) to OKLab, or `null`. */
|
|
97
|
+
declare function parseOklab(input: unknown): OklabColor | null;
|
|
98
|
+
/** Formats OKLab as `#rrggbb` (or `#rrggbbaa` when translucent). */
|
|
99
|
+
declare function formatOklab(color: OklabColor): string;
|
|
100
|
+
/**
|
|
101
|
+
* Mixes two colours at `t` (0 = `from`, 1 = `to`) in OKLab with premultiplied alpha.
|
|
102
|
+
* Returns `null` when either is not a readable colour.
|
|
103
|
+
*/
|
|
104
|
+
declare function mixColorsOklab(from: unknown, to: unknown, t: number): string | null;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Keyframe tracks, independent of what they animate: each track is a list of keyframes
|
|
108
|
+
* `{ time (ms), value, easing }`, where the easing governs the segment *leaving* the keyframe
|
|
109
|
+
* (filmcraft / After Effects convention).
|
|
110
|
+
*/
|
|
111
|
+
/** Keyframe times closer than this (ms) are the same time. */
|
|
112
|
+
declare const ANIMATION_TIME_EPSILON = 0.000001;
|
|
113
|
+
/** A keyframe value: a number, or a CSS colour for colour properties. */
|
|
114
|
+
type AnimationValue = number | string;
|
|
115
|
+
interface AnimationKeyframe {
|
|
116
|
+
/** Time in milliseconds from the start of the timeline. */
|
|
117
|
+
time: number;
|
|
118
|
+
value: AnimationValue;
|
|
119
|
+
/** Easing of the segment from this keyframe to the next (default `linear`). */
|
|
120
|
+
easing?: AnimationEasing;
|
|
121
|
+
}
|
|
122
|
+
interface AnimationTrack {
|
|
123
|
+
keyframes: AnimationKeyframe[];
|
|
124
|
+
/** Disabled tracks keep their keyframes but do not animate (default `true`). */
|
|
125
|
+
enabled?: boolean;
|
|
126
|
+
}
|
|
127
|
+
/** How a track's values interpolate: numbers linearly, colours in OKLab. */
|
|
128
|
+
type AnimationValueType = 'number' | 'color';
|
|
129
|
+
/** Whether `value` is a well-formed keyframe. */
|
|
130
|
+
declare function isAnimationKeyframe(value: unknown): value is AnimationKeyframe;
|
|
131
|
+
/**
|
|
132
|
+
* Keyframes sorted by time, invalid entries dropped and duplicate times merged (the *later*
|
|
133
|
+
* entry in the array wins, so appending a keyframe replaces one at the same time). Cached per
|
|
134
|
+
* array (revalidated by element identity), so evaluating every frame does not re-sort; treat
|
|
135
|
+
* keyframe objects as immutable.
|
|
136
|
+
*/
|
|
137
|
+
declare function normalizeKeyframes(keyframes: readonly AnimationKeyframe[] | undefined | null): AnimationKeyframe[];
|
|
138
|
+
|
|
139
|
+
/** How time past the end of the timeline maps back into it. */
|
|
140
|
+
type AnimationLoopMode = 'none' | 'loop' | 'ping-pong';
|
|
141
|
+
/**
|
|
142
|
+
* Interpolates between two keyframe values: numbers linearly, colours in OKLab (premultiplied
|
|
143
|
+
* alpha). Mismatched or unreadable values hold `from` until `t` reaches 1.
|
|
144
|
+
*/
|
|
145
|
+
declare function interpolateAnimationValue(from: AnimationValue, to: AnimationValue, t: number, type?: AnimationValueType): AnimationValue;
|
|
146
|
+
/**
|
|
147
|
+
* A track's value at `time`. Before the first keyframe it holds the first value, after the
|
|
148
|
+
* last the last value. Keyframes may be unsorted or share times (see `normalizeKeyframes`).
|
|
149
|
+
* Returns `undefined` for a track without valid keyframes.
|
|
150
|
+
*/
|
|
151
|
+
declare function evaluateTrack(track: AnimationTrack | readonly AnimationKeyframe[] | undefined | null, time: number, type?: AnimationValueType): AnimationValue | undefined;
|
|
152
|
+
/**
|
|
153
|
+
* Maps a running time onto the timeline `[0, duration]`: clamped (`none`), wrapped (`loop`)
|
|
154
|
+
* or bounced (`ping-pong`).
|
|
155
|
+
*/
|
|
156
|
+
declare function wrapAnimationTime(time: number, duration: number, loop?: AnimationLoopMode): number;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* The time source that animations (and canvas agent performances) play on.
|
|
160
|
+
*
|
|
161
|
+
* Defaults to `realClock` (requestAnimationFrame and setTimeout).
|
|
162
|
+
* A `ManualClock` moves only when told to via `advance(ms)` or `tick(fps)`,
|
|
163
|
+
* enabling deterministic frame-by-frame stepping for testing, video generation,
|
|
164
|
+
* or headless server environments.
|
|
165
|
+
*/
|
|
166
|
+
interface Clock {
|
|
167
|
+
/** Current time in milliseconds. */
|
|
168
|
+
now(): number;
|
|
169
|
+
/** Resolves on the next animation frame. */
|
|
170
|
+
frame(): Promise<void>;
|
|
171
|
+
/** Resolves after `ms` milliseconds of this clock's time. */
|
|
172
|
+
sleep(ms: number): Promise<void>;
|
|
173
|
+
/**
|
|
174
|
+
* Whether the clock follows wall time. Live clocks stop or degrade when the
|
|
175
|
+
* tab is in the background (browsers pause animation frames), so transitions
|
|
176
|
+
* can commit immediately rather than leaving operations hanging.
|
|
177
|
+
*/
|
|
178
|
+
readonly live: boolean;
|
|
179
|
+
}
|
|
180
|
+
/** Whether the browser tab is hidden (where RAF pauses). */
|
|
181
|
+
declare const pageHidden: () => boolean;
|
|
182
|
+
/** Real-time clock using requestAnimationFrame and setTimeout. */
|
|
183
|
+
declare const realClock: Clock;
|
|
184
|
+
/**
|
|
185
|
+
* A deterministic clock that only moves forward when `advance` or `tick` is called.
|
|
186
|
+
* Allows step-by-step frame testing and video rendering without waiting for real time.
|
|
187
|
+
*/
|
|
188
|
+
declare class ManualClock implements Clock {
|
|
189
|
+
readonly live = false;
|
|
190
|
+
private time;
|
|
191
|
+
private frames;
|
|
192
|
+
private sleepers;
|
|
193
|
+
private seq;
|
|
194
|
+
constructor(start?: number);
|
|
195
|
+
now(): number;
|
|
196
|
+
frame(): Promise<void>;
|
|
197
|
+
sleep(ms: number): Promise<void>;
|
|
198
|
+
/** Whether any frames or sleep timers are currently pending. */
|
|
199
|
+
get pending(): boolean;
|
|
200
|
+
/** Advances time by `ms`, resolving due sleep timers in order, followed by queued frames. */
|
|
201
|
+
advance(ms: number): Promise<void>;
|
|
202
|
+
/** Convenience method to advance by 1 frame at a given fps (default: 60fps = 16.67ms). */
|
|
203
|
+
tick(fps?: number): Promise<void>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
interface AnimationPlayerState {
|
|
207
|
+
/** Playhead time in ms, inside `[0, duration]`. */
|
|
208
|
+
time: number;
|
|
209
|
+
playing: boolean;
|
|
210
|
+
/** True between `scrub` and `endScrub`. */
|
|
211
|
+
scrubbing: boolean;
|
|
212
|
+
loop: AnimationLoopMode;
|
|
213
|
+
/** Speed multiplier (negative plays backwards). */
|
|
214
|
+
playbackRate: number;
|
|
215
|
+
duration: number;
|
|
216
|
+
}
|
|
217
|
+
interface AnimationPlayerOptions {
|
|
218
|
+
/** Time source (default `realClock`: requestAnimationFrame). Pass a `ManualClock` in tests or for rendering. */
|
|
219
|
+
clock?: Clock;
|
|
220
|
+
/** Timeline length in ms, or a getter (e.g. the last keyframe time). Default 1000. */
|
|
221
|
+
duration?: number | (() => number);
|
|
222
|
+
loop?: AnimationLoopMode;
|
|
223
|
+
playbackRate?: number;
|
|
224
|
+
/** Initial playhead time (default 0). */
|
|
225
|
+
time?: number;
|
|
226
|
+
/** Called whenever the playhead moves (playback, seek, scrub). */
|
|
227
|
+
onTime?: (time: number) => void;
|
|
228
|
+
/** Called when non-looping playback reaches the end (or the start, playing backwards). */
|
|
229
|
+
onEnd?: () => void;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Plays a timeline on an injectable `Clock`: play / pause / seek / scrub with looping,
|
|
233
|
+
* ping-pong and playback rate. It only asks the clock for frames while playing, so a
|
|
234
|
+
* `ManualClock` steps it deterministically and the real clock's requestAnimationFrame is the
|
|
235
|
+
* only place wall time enters.
|
|
236
|
+
*
|
|
237
|
+
* `getState()` returns a cached snapshot replaced on change (usable with `useSyncExternalStore`).
|
|
238
|
+
*/
|
|
239
|
+
declare class AnimationPlayer {
|
|
240
|
+
private readonly clock;
|
|
241
|
+
private durationSource;
|
|
242
|
+
private onTime?;
|
|
243
|
+
private onEnd?;
|
|
244
|
+
private time;
|
|
245
|
+
private playing;
|
|
246
|
+
private scrubbing;
|
|
247
|
+
private resumeAfterScrub;
|
|
248
|
+
private loop;
|
|
249
|
+
private rate;
|
|
250
|
+
/** Unwrapped time at `anchorAt` (keeps the ping-pong direction across frames). */
|
|
251
|
+
private anchorRaw;
|
|
252
|
+
private anchorAt;
|
|
253
|
+
private generation;
|
|
254
|
+
private cached;
|
|
255
|
+
private listeners;
|
|
256
|
+
constructor(options?: AnimationPlayerOptions);
|
|
257
|
+
/** Current timeline length (ms). */
|
|
258
|
+
get duration(): number;
|
|
259
|
+
get currentTime(): number;
|
|
260
|
+
get isPlaying(): boolean;
|
|
261
|
+
getState(): AnimationPlayerState;
|
|
262
|
+
subscribe(listener: (state: AnimationPlayerState) => void): () => void;
|
|
263
|
+
/** Replaces the callbacks (hooks keep them current without recreating the player). */
|
|
264
|
+
setCallbacks(callbacks: {
|
|
265
|
+
onTime?: (time: number) => void;
|
|
266
|
+
onEnd?: () => void;
|
|
267
|
+
}): void;
|
|
268
|
+
setDuration(duration: number | (() => number)): void;
|
|
269
|
+
setLoop(loop: AnimationLoopMode): void;
|
|
270
|
+
setPlaybackRate(rate: number): void;
|
|
271
|
+
/** Starts playing from the playhead (from the start again when a one-shot play had ended). */
|
|
272
|
+
play(): void;
|
|
273
|
+
pause(): void;
|
|
274
|
+
toggle(): void;
|
|
275
|
+
/** Pauses and returns to the start. */
|
|
276
|
+
stop(): void;
|
|
277
|
+
/** Moves the playhead (clamped to the timeline); playback continues from there. */
|
|
278
|
+
seek(time: number): void;
|
|
279
|
+
/** Seeks while dragging the playhead: playback pauses until `endScrub`. */
|
|
280
|
+
scrub(time: number): void;
|
|
281
|
+
/** Ends a scrub, resuming playback if it was playing when the scrub began. */
|
|
282
|
+
endScrub(): void;
|
|
283
|
+
/** Stops scheduling frames and drops listeners. */
|
|
284
|
+
destroy(): void;
|
|
285
|
+
private clamp;
|
|
286
|
+
private reanchor;
|
|
287
|
+
private rawNow;
|
|
288
|
+
private schedule;
|
|
289
|
+
/** Advances the playhead to the clock's time; `notify` emits the change. */
|
|
290
|
+
private tick;
|
|
291
|
+
private snapshot;
|
|
292
|
+
private emit;
|
|
293
|
+
}
|
|
294
|
+
declare function createAnimationPlayer(options?: AnimationPlayerOptions): AnimationPlayer;
|
|
295
|
+
|
|
296
|
+
export { ANIMATION_EASING_LABELS, ANIMATION_EASING_PRESETS, ANIMATION_TIME_EPSILON, type AnimationEasing, type AnimationEasingPreset, type AnimationKeyframe, type AnimationLoopMode, AnimationPlayer, type AnimationPlayerOptions, type AnimationPlayerState, type AnimationTrack, type AnimationValue, type AnimationValueType, CUBIC_BEZIER_PRESETS, type Clock, type CubicBezierEasing, ManualClock, type OklabColor, type SpringEasing, createAnimationPlayer, cubicBezierAt, easingFromInfluence, easingLabel, easingToCss, evaluateEasing, evaluateTrack, formatOklab, interpolateAnimationValue, isAnimationEasing, isAnimationKeyframe, mixColorsOklab, normalizeKeyframes, oklabToRgb, pageHidden, parseCssEasing, parseOklab, realClock, resolveEasing, rgbToOklab, springAt, wrapAnimationTime };
|