@pixerate/editor 0.57.0 → 0.58.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/dist/animation/index.cjs +15 -1
- package/dist/animation/index.cjs.map +1 -1
- package/dist/animation/index.d.cts +1 -0
- package/dist/animation/index.d.ts +1 -0
- package/dist/animation/index.js +14 -0
- package/dist/animation-editor/index.cjs +432 -127
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +297 -33
- package/dist/animation-editor/index.d.ts +297 -33
- package/dist/animation-editor/index.js +390 -85
- package/dist/animation-editor/index.js.map +1 -1
- package/dist/behavior-Ymbld6jL.d.cts +60 -0
- package/dist/behavior-Ymbld6jL.d.ts +60 -0
- package/dist/chunk-3NYXDBBW.js +122 -0
- package/dist/chunk-3NYXDBBW.js.map +1 -0
- package/dist/{chunk-XCXQDPID.cjs → chunk-FKONE6AO.cjs} +23 -8
- package/dist/chunk-FKONE6AO.cjs.map +1 -0
- package/dist/{chunk-NONDTTH7.js → chunk-PYMV7HLI.js} +16 -1
- package/dist/{chunk-NONDTTH7.js.map → chunk-PYMV7HLI.js.map} +1 -1
- package/dist/chunk-ZCNLBRT6.cjs +122 -0
- package/dist/chunk-ZCNLBRT6.cjs.map +1 -0
- package/dist/{svg-CPK82TtU.d.ts → svg-Dh17jCyA.d.ts} +22 -1
- package/dist/{svg-CLg2zqZA.d.cts → svg-ymShkNtu.d.cts} +22 -1
- package/dist/vector/index.cjs +471 -471
- package/dist/vector/index.d.cts +2 -2
- package/dist/vector/index.d.ts +2 -2
- package/dist/vector/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-XCXQDPID.cjs.map +0 -1
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
var
|
|
20
|
+
var _chunkFKONE6AOcjs = require('../chunk-FKONE6AO.cjs');
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
|
|
@@ -29,6 +29,10 @@ var _chunkO2UH7LZEcjs = require('../chunk-O2UH7LZE.cjs');
|
|
|
29
29
|
var _chunkQKLRAA4Tcjs = require('../chunk-QKLRAA4T.cjs');
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
|
|
33
|
+
var _chunkZCNLBRT6cjs = require('../chunk-ZCNLBRT6.cjs');
|
|
34
|
+
|
|
35
|
+
|
|
32
36
|
var _chunkO4ONBPZWcjs = require('../chunk-O4ONBPZW.cjs');
|
|
33
37
|
|
|
34
38
|
|
|
@@ -59,11 +63,17 @@ var MOTION_COMMAND_TYPES = [
|
|
|
59
63
|
"follow",
|
|
60
64
|
"pulse",
|
|
61
65
|
"shake",
|
|
66
|
+
"teeter",
|
|
67
|
+
"wave",
|
|
68
|
+
"wiggle",
|
|
69
|
+
"color-pulse",
|
|
62
70
|
"effect",
|
|
63
71
|
"wait"
|
|
64
72
|
];
|
|
65
|
-
var MOTION_ENTER_STYLES = ["fade", "pop", "grow", "slide", "draw"];
|
|
66
|
-
var MOTION_EXIT_STYLES = ["fade", "shrink", "slide", "undraw"];
|
|
73
|
+
var MOTION_ENTER_STYLES = ["fade", "pop", "grow", "slide", "draw", "zoom", "rise", "wipe", "iris", "split"];
|
|
74
|
+
var MOTION_EXIT_STYLES = ["fade", "shrink", "slide", "undraw", "wipe"];
|
|
75
|
+
var MOTION_IRIS_SHAPES = ["circle", "box"];
|
|
76
|
+
var MOTION_SPLIT_ORIENTATIONS = ["horizontal", "vertical"];
|
|
67
77
|
var MOTION_DIRECTIONS = ["up", "down", "left", "right"];
|
|
68
78
|
var MOTION_DEFAULT_DURATIONS = {
|
|
69
79
|
enter: 600,
|
|
@@ -77,12 +87,37 @@ var MOTION_DEFAULT_DURATIONS = {
|
|
|
77
87
|
follow: 1400,
|
|
78
88
|
pulse: 600,
|
|
79
89
|
shake: 500,
|
|
90
|
+
teeter: 600,
|
|
91
|
+
wave: 1e3,
|
|
92
|
+
wiggle: 1500,
|
|
93
|
+
"color-pulse": 600,
|
|
80
94
|
effect: 900
|
|
81
95
|
};
|
|
82
96
|
var MOTION_DEFAULT_HOLD = 600;
|
|
83
97
|
var MOTION_CAMERA_MS = 1e3;
|
|
84
98
|
var MOTION_DRAW_MS_PER_UNIT = 1.5;
|
|
85
99
|
var MOTION_DRAW_RANGE = [500, 2500];
|
|
100
|
+
function motionFlairPrimitive(command2) {
|
|
101
|
+
switch (command2.type) {
|
|
102
|
+
case "enter":
|
|
103
|
+
return `entrance.${_nullishCoalesce(command2.style, () => ( "fade"))}`;
|
|
104
|
+
case "exit":
|
|
105
|
+
return `exit.${_nullishCoalesce(command2.style, () => ( "fade"))}`;
|
|
106
|
+
case "pulse":
|
|
107
|
+
case "shake":
|
|
108
|
+
case "teeter":
|
|
109
|
+
case "wave":
|
|
110
|
+
case "wiggle":
|
|
111
|
+
case "color-pulse":
|
|
112
|
+
return `emphasis.${command2.type}`;
|
|
113
|
+
case "rotate":
|
|
114
|
+
return command2.by !== void 0 ? "emphasis.spin" : void 0;
|
|
115
|
+
case "follow":
|
|
116
|
+
return "path.follow";
|
|
117
|
+
default:
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
86
121
|
|
|
87
122
|
// src/animation-editor/issues.ts
|
|
88
123
|
var MOTION_ISSUE_CODES = {
|
|
@@ -91,13 +126,14 @@ var MOTION_ISSUE_CODES = {
|
|
|
91
126
|
"unknown-target": { severity: "error", wording: "A command names a node the artwork does not have." },
|
|
92
127
|
"unknown-path": { severity: "error", wording: "A follow command names a path the artwork does not have." },
|
|
93
128
|
"not-a-path": { severity: "error", wording: "A follow path must be a path node, not a group." },
|
|
129
|
+
"reveal-no-box": { severity: "warning", wording: "A wipe, iris or split cannot clip a node with no width or height (a lone straight line), so it fades instead." },
|
|
94
130
|
"unknown-shape": { severity: "error", wording: "A morph names a shape the artwork does not have." },
|
|
95
131
|
"unknown-effect": { severity: "error", wording: "An effect command names an effect the node does not have." },
|
|
96
132
|
"unknown-effect-param": { severity: "error", wording: "An effect command names a parameter that is not a number of that effect." },
|
|
97
133
|
"unknown-frame": { severity: "error", wording: "A camera frames a node the artwork does not have." },
|
|
98
134
|
"invalid-camera": { severity: "error", wording: "A camera rectangle has no area." },
|
|
99
135
|
"invalid-color": { severity: "error", wording: "A colour cannot be read." },
|
|
100
|
-
"paint-not-color": { severity: "warning", wording: "A style command recolours a gradient or empty paint, which only switches at the end." },
|
|
136
|
+
"paint-not-color": { severity: "warning", wording: "A style command recolours a gradient or empty paint, which only switches at the end, or a colour pulse has no solid paint to tint." },
|
|
101
137
|
"overlap": { severity: "warning", wording: "Two commands change the same property of a node at the same time; the later one wins." },
|
|
102
138
|
"enter-visible": { severity: "warning", wording: "A node enters while it is already showing, so it blinks out first." },
|
|
103
139
|
"exit-hidden": { severity: "warning", wording: "A node exits or animates while it is hidden." },
|
|
@@ -165,7 +201,7 @@ var SHOT_KEYS = ["id", "label", "camera", "run", "hold"];
|
|
|
165
201
|
var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms"];
|
|
166
202
|
var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note"];
|
|
167
203
|
var COMMAND_KEYS = {
|
|
168
|
-
enter: [...BASE_KEYS, "style", "direction", "distance"],
|
|
204
|
+
enter: [...BASE_KEYS, "style", "direction", "distance", "scale", "shape", "orientation"],
|
|
169
205
|
exit: [...BASE_KEYS, "style", "direction", "distance"],
|
|
170
206
|
draw: [...BASE_KEYS, "from", "to"],
|
|
171
207
|
move: [...BASE_KEYS, "by", "to"],
|
|
@@ -176,7 +212,11 @@ var COMMAND_KEYS = {
|
|
|
176
212
|
morph: [...BASE_KEYS, "into"],
|
|
177
213
|
follow: [...BASE_KEYS, "path", "rotate", "from", "to"],
|
|
178
214
|
pulse: [...BASE_KEYS, "amount", "count"],
|
|
179
|
-
shake: [...BASE_KEYS, "amount", "count"],
|
|
215
|
+
shake: [...BASE_KEYS, "amount", "count", "axis"],
|
|
216
|
+
teeter: [...BASE_KEYS, "angle", "count"],
|
|
217
|
+
wave: [...BASE_KEYS, "amount", "count"],
|
|
218
|
+
wiggle: [...BASE_KEYS, "amount", "frequency", "octaves", "rotate", "seed"],
|
|
219
|
+
"color-pulse": [...BASE_KEYS, "color", "paint", "count"],
|
|
180
220
|
effect: [...BASE_KEYS, "effect", "param", "to"],
|
|
181
221
|
wait: ["type", "duration", "with", "note"]
|
|
182
222
|
};
|
|
@@ -223,6 +263,9 @@ function commandShapeProblems(command2, where) {
|
|
|
223
263
|
p(`"style" must be one of ${styles.join(", ")}${typeof command2.style === "string" ? ` (got ${namedWithSuggestion(command2.style, styles)})` : ""}.`);
|
|
224
264
|
if (command2.direction !== void 0 && !MOTION_DIRECTIONS.includes(command2.direction)) p(`"direction" must be one of ${MOTION_DIRECTIONS.join(", ")}.`);
|
|
225
265
|
optionalNumber("distance");
|
|
266
|
+
if (command2.scale !== void 0 && !(isNum(command2.scale) && command2.scale >= 0)) p(`"scale" must be a number \u2265 0 (the starting scale for pop and zoom).`);
|
|
267
|
+
if (command2.shape !== void 0 && !MOTION_IRIS_SHAPES.includes(command2.shape)) p(`"shape" must be one of ${MOTION_IRIS_SHAPES.join(", ")} (the opening of an iris).`);
|
|
268
|
+
if (command2.orientation !== void 0 && !MOTION_SPLIT_ORIENTATIONS.includes(command2.orientation)) p(`"orientation" must be one of ${MOTION_SPLIT_ORIENTATIONS.join(", ")} (the line a split opens from).`);
|
|
226
269
|
break;
|
|
227
270
|
}
|
|
228
271
|
case "draw":
|
|
@@ -264,8 +307,22 @@ function commandShapeProblems(command2, where) {
|
|
|
264
307
|
break;
|
|
265
308
|
case "pulse":
|
|
266
309
|
case "shake":
|
|
310
|
+
case "teeter":
|
|
311
|
+
case "wave":
|
|
312
|
+
case "color-pulse":
|
|
267
313
|
optionalNumber("amount");
|
|
314
|
+
optionalNumber("angle");
|
|
268
315
|
if (command2.count !== void 0 && !(Number.isInteger(command2.count) && command2.count >= 1)) p(`"count" must be a whole number \u2265 1.`);
|
|
316
|
+
if (command2.axis !== void 0 && command2.axis !== "horizontal" && command2.axis !== "vertical") p(`"axis" must be "horizontal" or "vertical".`);
|
|
317
|
+
if (command2.color !== void 0 && typeof command2.color !== "string") p(`"color" must be a CSS colour.`);
|
|
318
|
+
if (command2.paint !== void 0 && command2.paint !== "fill" && command2.paint !== "stroke") p(`"paint" must be "fill" or "stroke".`);
|
|
319
|
+
break;
|
|
320
|
+
case "wiggle":
|
|
321
|
+
optionalNumber("amount");
|
|
322
|
+
optionalNumber("rotate");
|
|
323
|
+
if (command2.frequency !== void 0 && !(isNum(command2.frequency) && command2.frequency > 0)) p(`"frequency" must be a number of Hz > 0.`);
|
|
324
|
+
if (command2.octaves !== void 0 && !(Number.isInteger(command2.octaves) && command2.octaves >= 1 && command2.octaves <= 8)) p(`"octaves" must be a whole number from 1 to 8.`);
|
|
325
|
+
if (command2.seed !== void 0 && !(Number.isInteger(command2.seed) && command2.seed >= 0)) p(`"seed" must be a whole number \u2265 0.`);
|
|
269
326
|
break;
|
|
270
327
|
case "effect":
|
|
271
328
|
if (typeof command2.effect !== "string" || !command2.effect) p(`"effect" must be the id of one of the node's effects.`);
|
|
@@ -355,26 +412,76 @@ function indexMotionNodes(nodes) {
|
|
|
355
412
|
const out = /* @__PURE__ */ new Map();
|
|
356
413
|
const walk = (list, parentWorld, ancestors) => {
|
|
357
414
|
for (const node of list) {
|
|
358
|
-
const local =
|
|
359
|
-
const bounds =
|
|
415
|
+
const local = _chunkFKONE6AOcjs.vectorNodeBounds.call(void 0, node);
|
|
416
|
+
const bounds = _chunkFKONE6AOcjs.vectorNodeBounds.call(void 0, node, parentWorld);
|
|
360
417
|
const center = local ? { x: local.x + local.width / 2, y: local.y + local.height / 2 } : { x: 0, y: 0 };
|
|
361
|
-
if (!out.has(node.id)) out.set(node.id, { node, ancestors, parentWorld, center, bounds });
|
|
362
|
-
if (node.type === "group") walk(node.children,
|
|
418
|
+
if (!out.has(node.id)) out.set(node.id, { node, ancestors, parentWorld, center, bounds, box: local });
|
|
419
|
+
if (node.type === "group") walk(node.children, _chunkFKONE6AOcjs.multiplyMatrices.call(void 0, _chunkFKONE6AOcjs.nodeMatrix.call(void 0, node), parentWorld), [...ancestors, node.id]);
|
|
363
420
|
}
|
|
364
421
|
};
|
|
365
|
-
walk(nodes,
|
|
422
|
+
walk(nodes, _chunkFKONE6AOcjs.IDENTITY_MATRIX, []);
|
|
366
423
|
indexCache.set(nodes, out);
|
|
367
424
|
return out;
|
|
368
425
|
}
|
|
369
426
|
var solid = (paint) => typeof paint === "string" && paint !== "none" ? paint : void 0;
|
|
370
427
|
function firstPaint(node, key) {
|
|
371
428
|
if (node.type === "path") return solid(node[key]);
|
|
372
|
-
for (const p of
|
|
429
|
+
for (const p of _chunkFKONE6AOcjs.collectPathNodes.call(void 0, node)) {
|
|
373
430
|
const s = solid(p[key]);
|
|
374
431
|
if (s) return s;
|
|
375
432
|
}
|
|
376
433
|
return void 0;
|
|
377
434
|
}
|
|
435
|
+
function strokeReach(node) {
|
|
436
|
+
let reach = 0;
|
|
437
|
+
for (const p of node.type === "path" ? [node] : _chunkFKONE6AOcjs.collectPathNodes.call(void 0, node)) {
|
|
438
|
+
if (p.stroke == null || p.stroke === "none") continue;
|
|
439
|
+
const width = _nullishCoalesce(p.strokeWidth, () => ( 1));
|
|
440
|
+
reach = Math.max(reach, p.strokeAlign === "outside" ? width : p.strokeAlign === "inside" ? 0 : width / 2);
|
|
441
|
+
}
|
|
442
|
+
return reach;
|
|
443
|
+
}
|
|
444
|
+
function motionRevealPadding(entry) {
|
|
445
|
+
const box = entry.box;
|
|
446
|
+
if (!box || !(box.width > 0) || !(box.height > 0)) return null;
|
|
447
|
+
const s = strokeReach(entry.node);
|
|
448
|
+
return [Math.min(1, s / box.width + 0.02), Math.min(1, s / box.height + 0.02)];
|
|
449
|
+
}
|
|
450
|
+
var clipRound = (n) => Math.round(n * 1e4) / 1e4 || 0;
|
|
451
|
+
function revealFull(property, [px, py]) {
|
|
452
|
+
return (property === "clipRect" ? [-px, -py, 1 + 2 * px, 1 + 2 * py] : [0.5, 0.5, Math.hypot(0.5 + px, 0.5 + py)]).map(clipRound);
|
|
453
|
+
}
|
|
454
|
+
var OPPOSITE = { up: "down", down: "up", left: "right", right: "left" };
|
|
455
|
+
function motionRevealClip(entry, reveal) {
|
|
456
|
+
const pad = motionRevealPadding(entry);
|
|
457
|
+
if (!pad) return null;
|
|
458
|
+
const [px, py] = pad;
|
|
459
|
+
const [w, h] = [1 + 2 * px, 1 + 2 * py];
|
|
460
|
+
const rect = (from, to) => ({ property: "clipRect", from: from.map(clipRound), to: to.map(clipRound) });
|
|
461
|
+
if (reveal.style === "iris") {
|
|
462
|
+
if (reveal.shape === "box") return rect([0.5, 0.5, 0, 0], [-px, -py, w, h]);
|
|
463
|
+
return { property: "clipCircle", from: [0.5, 0.5, 0], to: revealFull("clipCircle", pad) };
|
|
464
|
+
}
|
|
465
|
+
if (reveal.style === "split") {
|
|
466
|
+
if (reveal.orientation === "vertical") return rect([0.5, -py, 0, h], [-px, -py, w, h]);
|
|
467
|
+
return rect([-px, 0.5, w, 0], [-px, -py, w, h]);
|
|
468
|
+
}
|
|
469
|
+
const direction = _nullishCoalesce(reveal.direction, () => ( "right"));
|
|
470
|
+
if (reveal.hide) {
|
|
471
|
+
const shown = motionRevealClip(entry, { style: "wipe", direction: OPPOSITE[direction] });
|
|
472
|
+
return { ...shown, from: shown.to, to: shown.from };
|
|
473
|
+
}
|
|
474
|
+
switch (direction) {
|
|
475
|
+
case "right":
|
|
476
|
+
return rect([-px, -py, 0, h], [-px, -py, w, h]);
|
|
477
|
+
case "left":
|
|
478
|
+
return rect([1 + px, -py, 0, h], [-px, -py, w, h]);
|
|
479
|
+
case "down":
|
|
480
|
+
return rect([-px, -py, w, 0], [-px, -py, w, h]);
|
|
481
|
+
case "up":
|
|
482
|
+
return rect([-px, 1 + py, w, 0], [-px, -py, w, h]);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
378
485
|
function motionRestValue(entry, property, artwork) {
|
|
379
486
|
const node = _optionalChain([entry, 'optionalAccess', _4 => _4.node]);
|
|
380
487
|
switch (property) {
|
|
@@ -397,11 +504,16 @@ function motionRestValue(entry, property, artwork) {
|
|
|
397
504
|
case "stroke":
|
|
398
505
|
return _nullishCoalesce((node && firstPaint(node, property)), () => ( "transparent"));
|
|
399
506
|
case "strokeWidth": {
|
|
400
|
-
const path = _optionalChain([node, 'optionalAccess', _6 => _6.type]) === "path" ? node : node ?
|
|
507
|
+
const path = _optionalChain([node, 'optionalAccess', _6 => _6.type]) === "path" ? node : node ? _chunkFKONE6AOcjs.collectPathNodes.call(void 0, node)[0] : void 0;
|
|
401
508
|
return _nullishCoalesce(_optionalChain([path, 'optionalAccess', _7 => _7.strokeWidth]), () => ( 1));
|
|
402
509
|
}
|
|
403
510
|
case "shape":
|
|
404
511
|
return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _8 => _8.id]), () => ( ""));
|
|
512
|
+
case "clipRect":
|
|
513
|
+
case "clipCircle": {
|
|
514
|
+
const pad = entry && motionRevealPadding(entry);
|
|
515
|
+
return pad ? revealFull(property, pad) : [];
|
|
516
|
+
}
|
|
405
517
|
case "camera":
|
|
406
518
|
return [0, 0, artwork.width, artwork.height];
|
|
407
519
|
}
|
|
@@ -424,15 +536,13 @@ function interpolateMotionValue(from, to, u) {
|
|
|
424
536
|
function segmentProgress(segment, time) {
|
|
425
537
|
const span = segment.end - segment.start;
|
|
426
538
|
const u = span <= 0 ? 1 : Math.min(1, Math.max(0, (time - segment.start) / span));
|
|
427
|
-
return { u, eased:
|
|
539
|
+
return { u, eased: _chunkXZ4L3R4Kcjs.evaluateEasing.call(void 0, segment.ease, u, span) };
|
|
428
540
|
}
|
|
429
|
-
function segmentValue(segment, time) {
|
|
430
|
-
const {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
if (kind === "pulse") return v * (1 + amount * Math.sin(Math.PI * u * count) ** 2);
|
|
435
|
-
return v + amount * Math.sin(2 * Math.PI * u * count) * (1 - u);
|
|
541
|
+
function segmentValue(segment, time, raw = false) {
|
|
542
|
+
const { eased } = segmentProgress(segment, time);
|
|
543
|
+
if (!segment.behavior || raw) return interpolateMotionValue(segment.from, segment.to, eased);
|
|
544
|
+
const p = _chunkZCNLBRT6cjs.behaviorProgress.call(void 0, segment.behavior, eased, _nullishCoalesce(segment.index, () => ( 0)), segment.end - segment.start);
|
|
545
|
+
return typeof segment.from === "string" ? interpolateMotionValue(segment.from, segment.to, Math.min(1, Math.max(0, p))) : interpolateMotionValue(segment.from, segment.to, p);
|
|
436
546
|
}
|
|
437
547
|
function activeSegment(track, time) {
|
|
438
548
|
if (!_optionalChain([track, 'optionalAccess', _12 => _12.length])) return void 0;
|
|
@@ -440,10 +550,10 @@ function activeSegment(track, time) {
|
|
|
440
550
|
for (const s of track) if (s.start <= time && (!found || s.start >= found.start)) found = s;
|
|
441
551
|
return found;
|
|
442
552
|
}
|
|
443
|
-
function trackValue(track, time) {
|
|
553
|
+
function trackValue(track, time, raw = false) {
|
|
444
554
|
if (!_optionalChain([track, 'optionalAccess', _13 => _13.length])) return void 0;
|
|
445
555
|
const s = activeSegment(track, time);
|
|
446
|
-
if (s) return segmentValue(s, time);
|
|
556
|
+
if (s) return segmentValue(s, time, raw);
|
|
447
557
|
let first = track[0];
|
|
448
558
|
for (const t of track) if (t.start < first.start) first = t;
|
|
449
559
|
return first.from;
|
|
@@ -469,12 +579,12 @@ function resolveMotionCamera(camera, scene) {
|
|
|
469
579
|
const r = camera;
|
|
470
580
|
return { x: r.x, y: r.y, width: r.width, height: r.height };
|
|
471
581
|
}
|
|
472
|
-
function motionPathLength(node, parentWorld =
|
|
582
|
+
function motionPathLength(node, parentWorld = _chunkFKONE6AOcjs.IDENTITY_MATRIX) {
|
|
473
583
|
let longest = 0;
|
|
474
|
-
const paths = node.type === "path" ? [node] :
|
|
584
|
+
const paths = node.type === "path" ? [node] : _chunkFKONE6AOcjs.collectPathNodes.call(void 0, node);
|
|
475
585
|
for (const p of paths) {
|
|
476
586
|
try {
|
|
477
|
-
longest = Math.max(longest, _chunkO2UH7LZEcjs.bezierPathLength.call(void 0,
|
|
587
|
+
longest = Math.max(longest, _chunkO2UH7LZEcjs.bezierPathLength.call(void 0, _chunkFKONE6AOcjs.vectorPathWorldBezier.call(void 0, p, parentWorld, { effects: false })));
|
|
478
588
|
} catch (e2) {
|
|
479
589
|
}
|
|
480
590
|
}
|
|
@@ -582,15 +692,27 @@ function compileMotionScene(scene) {
|
|
|
582
692
|
case "enter": {
|
|
583
693
|
const style = _nullishCoalesce(command2.style, () => ( "fade"));
|
|
584
694
|
const opacity = rest("opacity");
|
|
695
|
+
const reveal = style === "wipe" ? motionRevealClip(entry, { style, direction: command2.direction }) : style === "iris" ? motionRevealClip(entry, { style, shape: command2.shape }) : style === "split" ? motionRevealClip(entry, { style, orientation: command2.orientation }) : null;
|
|
696
|
+
for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _15 => _15.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
|
|
697
|
+
if (reveal) {
|
|
698
|
+
seg("opacity", opacity, "linear", start, start);
|
|
699
|
+
seg(reveal.property, reveal.to, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: reveal.from });
|
|
700
|
+
break;
|
|
701
|
+
}
|
|
585
702
|
if (style === "draw") {
|
|
586
703
|
seg("drawEnd", 1, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, start + duration2 * 0.75, { from: 0 });
|
|
587
704
|
seg("fillOpacity", 1, MOTION_EASE_OUT, start + duration2 * 0.6, end, { from: 0 });
|
|
588
705
|
break;
|
|
589
706
|
}
|
|
590
|
-
if (style === "pop") {
|
|
591
|
-
|
|
592
|
-
seg("
|
|
593
|
-
seg("
|
|
707
|
+
if (style === "pop" || style === "zoom") {
|
|
708
|
+
const from = _nullishCoalesce(command2.scale, () => ( (style === "pop" ? 0.5 : 1.6)));
|
|
709
|
+
seg("opacity", opacity, MOTION_EASE_OUT, start, start + duration2 * (style === "pop" ? 0.4 : 0.5), { from: 0 });
|
|
710
|
+
seg("scaleX", 1, _nullishCoalesce(ease, () => ( (style === "pop" ? "ease-out-back" : MOTION_EASE_OUT))), start, end, { from });
|
|
711
|
+
seg("scaleY", 1, _nullishCoalesce(ease, () => ( (style === "pop" ? "ease-out-back" : MOTION_EASE_OUT))), start, end, { from });
|
|
712
|
+
} else if (style === "rise") {
|
|
713
|
+
const y = num("y");
|
|
714
|
+
seg("opacity", opacity, MOTION_EASE_OUT, start, start + duration2 * 0.5, { from: 0 });
|
|
715
|
+
seg("y", y, _nullishCoalesce(ease, () => ( "ease-out-back")), start, end, { from: y + (_nullishCoalesce(command2.distance, () => ( 20))) });
|
|
594
716
|
} else if (style === "grow") {
|
|
595
717
|
seg("opacity", opacity, MOTION_EASE_OUT, start, start + duration2 * 0.3, { from: 0 });
|
|
596
718
|
seg("scaleX", 1, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: 0 });
|
|
@@ -608,7 +730,9 @@ function compileMotionScene(scene) {
|
|
|
608
730
|
}
|
|
609
731
|
case "exit": {
|
|
610
732
|
const style = _nullishCoalesce(command2.style, () => ( "fade"));
|
|
611
|
-
|
|
733
|
+
const wipe = style === "wipe" ? motionRevealClip(entry, { style, direction: command2.direction, hide: true }) : null;
|
|
734
|
+
if (wipe) seg(wipe.property, wipe.to, _nullishCoalesce(ease, () => ( "ease-in")), start, end, { from: wipe.from });
|
|
735
|
+
else if (style === "undraw") {
|
|
612
736
|
seg("fillOpacity", 0, "ease-in", start, start + duration2 * 0.4);
|
|
613
737
|
seg("drawEnd", 0, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
|
|
614
738
|
} else if (style === "shrink") {
|
|
@@ -624,20 +748,18 @@ function compileMotionScene(scene) {
|
|
|
624
748
|
} else seg("opacity", 0, _nullishCoalesce(ease, () => ( "ease-in")));
|
|
625
749
|
break;
|
|
626
750
|
}
|
|
627
|
-
case "draw":
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
seg("drawEnd", _nullishCoalesce(command2.to, () => ( 1)), _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, command2.from !== void 0 ? { from: command2.from } : drawn ? {} : { from: 0 });
|
|
631
|
-
break;
|
|
632
|
-
}
|
|
751
|
+
case "draw": {
|
|
752
|
+
const drawn = tracks.has(motionTrackKey(node, "drawEnd"));
|
|
753
|
+
seg("drawEnd", _nullishCoalesce(command2.to, () => ( 1)), _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, command2.from !== void 0 ? { from: command2.from } : drawn ? {} : { from: 0 });
|
|
633
754
|
break;
|
|
755
|
+
}
|
|
634
756
|
case "move": {
|
|
635
757
|
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
636
|
-
let dx = _nullishCoalesce(_optionalChain([command2, 'access',
|
|
637
|
-
let dy = _nullishCoalesce(_optionalChain([command2, 'access',
|
|
758
|
+
let dx = _nullishCoalesce(_optionalChain([command2, 'access', _16 => _16.by, 'optionalAccess', _17 => _17.x]), () => ( 0));
|
|
759
|
+
let dy = _nullishCoalesce(_optionalChain([command2, 'access', _18 => _18.by, 'optionalAccess', _19 => _19.y]), () => ( 0));
|
|
638
760
|
if (command2.to) {
|
|
639
|
-
const inv =
|
|
640
|
-
const target =
|
|
761
|
+
const inv = _chunkFKONE6AOcjs.invertMatrix.call(void 0, entry.parentWorld);
|
|
762
|
+
const target = _chunkFKONE6AOcjs.applyMatrix.call(void 0, inv, command2.to);
|
|
641
763
|
dx = target.x - (entry.center.x + num("x"));
|
|
642
764
|
dy = target.y - (entry.center.y + num("y"));
|
|
643
765
|
}
|
|
@@ -668,14 +790,35 @@ function compileMotionScene(scene) {
|
|
|
668
790
|
case "follow":
|
|
669
791
|
seg("follow", _nullishCoalesce(command2.to, () => ( 1)), _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, { from: _nullishCoalesce(command2.from, () => ( 0)), path: command2.path, rotate: _nullishCoalesce(command2.rotate, () => ( false)) });
|
|
670
792
|
break;
|
|
793
|
+
// Emphasis: a change toward a peak that a behaviour swings round (as Flair's primitives do).
|
|
671
794
|
case "pulse": {
|
|
672
|
-
const
|
|
673
|
-
|
|
674
|
-
seg("
|
|
795
|
+
const behavior = { type: "pulse", count: _nullishCoalesce(command2.count, () => ( 1)) };
|
|
796
|
+
const k = 1 + (_nullishCoalesce(command2.amount, () => ( 0.15)));
|
|
797
|
+
seg("scaleX", num("scaleX") * k, _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior });
|
|
798
|
+
seg("scaleY", num("scaleY") * k, _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior });
|
|
799
|
+
break;
|
|
800
|
+
}
|
|
801
|
+
case "shake": {
|
|
802
|
+
const p = command2.axis === "vertical" ? "y" : "x";
|
|
803
|
+
seg(p, num(p) + (_nullishCoalesce(command2.amount, () => ( 8))), _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 3)), decay: 1 } });
|
|
675
804
|
break;
|
|
676
805
|
}
|
|
677
|
-
case "
|
|
678
|
-
seg("
|
|
806
|
+
case "teeter":
|
|
807
|
+
seg("rotation", num("rotation") + (_nullishCoalesce(command2.angle, () => ( 8))), _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 3)), decay: 1 } });
|
|
808
|
+
break;
|
|
809
|
+
case "wave":
|
|
810
|
+
seg("y", num("y") - (_nullishCoalesce(command2.amount, () => ( 6))), _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 2)) } });
|
|
811
|
+
break;
|
|
812
|
+
case "wiggle": {
|
|
813
|
+
const behavior = { type: "wriggle", frequency: _nullishCoalesce(command2.frequency, () => ( 3)), octaves: _nullishCoalesce(command2.octaves, () => ( 2)), seed: command2.seed || _chunkZCNLBRT6cjs.motionSeedFromId.call(void 0, node) };
|
|
814
|
+
const amount = _nullishCoalesce(command2.amount, () => ( 6));
|
|
815
|
+
seg("x", num("x") + amount, _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior, index: 0 });
|
|
816
|
+
seg("y", num("y") + amount, _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior, index: 1 });
|
|
817
|
+
if (command2.rotate) seg("rotation", num("rotation") + command2.rotate, _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior, index: 2 });
|
|
818
|
+
break;
|
|
819
|
+
}
|
|
820
|
+
case "color-pulse":
|
|
821
|
+
seg(_nullishCoalesce(command2.paint, () => ( "fill")), _nullishCoalesce(command2.color, () => ( "#f59e0b")), _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior: { type: "pulse", count: _nullishCoalesce(command2.count, () => ( 1)) } });
|
|
679
822
|
break;
|
|
680
823
|
case "effect":
|
|
681
824
|
seg(`effect:${command2.effect}:${command2.param}`, command2.to, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
|
|
@@ -698,7 +841,7 @@ var MOTION_DRAW_EFFECT_ID = "~draw";
|
|
|
698
841
|
var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
|
|
699
842
|
var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
|
|
700
843
|
function applyMotionControlValues(scene, values) {
|
|
701
|
-
if (!values || !_optionalChain([scene, 'access',
|
|
844
|
+
if (!values || !_optionalChain([scene, 'access', _20 => _20.controls, 'optionalAccess', _21 => _21.length])) return scene;
|
|
702
845
|
const map = /* @__PURE__ */ new Map();
|
|
703
846
|
for (const control of scene.controls) {
|
|
704
847
|
const value = values[control.name];
|
|
@@ -734,17 +877,17 @@ function morphBetween(a, b) {
|
|
|
734
877
|
let inner = morphCache.get(a);
|
|
735
878
|
if (!inner) morphCache.set(a, inner = /* @__PURE__ */ new WeakMap());
|
|
736
879
|
let morph = inner.get(b);
|
|
737
|
-
if (!morph) inner.set(b, morph =
|
|
880
|
+
if (!morph) inner.set(b, morph = _chunkFKONE6AOcjs.createVectorMorph.call(void 0, a, b, { id: a.id }));
|
|
738
881
|
return morph;
|
|
739
882
|
}
|
|
740
883
|
function shapeIn(entry, shape) {
|
|
741
884
|
if (shape === entry) return entry.node;
|
|
742
|
-
const m =
|
|
743
|
-
return { ...shape.node, ...
|
|
885
|
+
const m = _chunkFKONE6AOcjs.multiplyMatrices.call(void 0, _chunkFKONE6AOcjs.multiplyMatrices.call(void 0, _chunkFKONE6AOcjs.nodeMatrix.call(void 0, shape.node), shape.parentWorld), _chunkFKONE6AOcjs.invertMatrix.call(void 0, entry.parentWorld));
|
|
886
|
+
return { ...shape.node, ..._chunkFKONE6AOcjs.isIdentityMatrix.call(void 0, m) ? { transform: void 0 } : { transform: m } };
|
|
744
887
|
}
|
|
745
888
|
function shapeAt(entry, timeline, nodes, time) {
|
|
746
889
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
|
|
747
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
890
|
+
if (!_optionalChain([track, 'optionalAccess', _22 => _22.length])) return null;
|
|
748
891
|
const s = activeSegment(track, time);
|
|
749
892
|
const fromId = String(s ? s.from : track[0].from);
|
|
750
893
|
if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
|
|
@@ -757,44 +900,53 @@ function shapeAt(entry, timeline, nodes, time) {
|
|
|
757
900
|
if (u >= 1) return b === entry ? null : shapeIn(entry, b);
|
|
758
901
|
return morphBetween(shapeIn(entry, a), shapeIn(entry, b)).at(u);
|
|
759
902
|
}
|
|
903
|
+
function motionFollowRoute(entry, path) {
|
|
904
|
+
if (!path || path.node.type !== "path") return null;
|
|
905
|
+
try {
|
|
906
|
+
return _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkFKONE6AOcjs.vectorPathWorldBezier.call(void 0, path.node, path.parentWorld, { effects: false }), _chunkFKONE6AOcjs.invertMatrix.call(void 0, entry.parentWorld));
|
|
907
|
+
} catch (e3) {
|
|
908
|
+
return null;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
760
911
|
function followAt(entry, timeline, nodes, time) {
|
|
761
912
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "follow"));
|
|
762
|
-
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess',
|
|
763
|
-
if (!_optionalChain([s, 'optionalAccess',
|
|
764
|
-
const
|
|
765
|
-
if (!path || path.node.type !== "path") return null;
|
|
913
|
+
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _23 => _23[0]])));
|
|
914
|
+
if (!_optionalChain([s, 'optionalAccess', _24 => _24.path])) return null;
|
|
915
|
+
const route = motionFollowRoute(entry, nodes.get(s.path));
|
|
766
916
|
const progress = Number(trackValue(track, time));
|
|
767
|
-
if (!(progress >= 0)) return null;
|
|
917
|
+
if (!route || !(progress >= 0)) return null;
|
|
768
918
|
try {
|
|
769
|
-
const
|
|
770
|
-
const at = _chunkO2UH7LZEcjs.bezierPathPointAtLength.call(void 0, bezier, Math.min(1, Math.max(0, progress)) * _chunkO2UH7LZEcjs.bezierPathLength.call(void 0, bezier));
|
|
919
|
+
const at = _chunkO2UH7LZEcjs.bezierPathPointAtLength.call(void 0, route, Math.min(1, Math.max(0, progress)) * _chunkO2UH7LZEcjs.bezierPathLength.call(void 0, route));
|
|
771
920
|
if (!at) return null;
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
} catch (e3) {
|
|
921
|
+
return { x: at.point[0], y: at.point[1], angle: s.rotate ? at.angle * 180 / Math.PI : 0 };
|
|
922
|
+
} catch (e4) {
|
|
775
923
|
return null;
|
|
776
924
|
}
|
|
777
925
|
}
|
|
778
|
-
function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry.node])) {
|
|
926
|
+
function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry.node]), raw = false, follow = true) {
|
|
779
927
|
const read = (p, rest) => {
|
|
780
|
-
const v = trackValue(timeline.tracks.get(motionTrackKey(entry.node.id, p)), time);
|
|
928
|
+
const v = trackValue(timeline.tracks.get(motionTrackKey(entry.node.id, p)), time, raw);
|
|
781
929
|
return typeof v === "number" ? v : rest;
|
|
782
930
|
};
|
|
783
|
-
if (!TRANSFORM_PROPS.some((p) => timeline.tracks.has(motionTrackKey(entry.node.id, p)))) return null;
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
931
|
+
if (!TRANSFORM_PROPS.some((p) => (follow || p !== "follow") && timeline.tracks.has(motionTrackKey(entry.node.id, p)))) return null;
|
|
932
|
+
const dx = read("x", 0);
|
|
933
|
+
const dy = read("y", 0);
|
|
934
|
+
const rotation = read("rotation", 0);
|
|
787
935
|
const scaleX = read("scaleX", 1);
|
|
788
936
|
const scaleY = read("scaleY", 1);
|
|
789
|
-
const follow = followAt(entry, timeline, nodes, time);
|
|
790
|
-
if (follow) {
|
|
791
|
-
dx += follow.x - entry.center.x;
|
|
792
|
-
dy += follow.y - entry.center.y;
|
|
793
|
-
rotation += follow.angle;
|
|
794
|
-
}
|
|
795
937
|
const c = entry.center;
|
|
796
|
-
|
|
797
|
-
|
|
938
|
+
let matrix = _chunkFKONE6AOcjs.multiplyMatrices.call(void 0, _chunkFKONE6AOcjs.multiplyMatrices.call(void 0, _chunkFKONE6AOcjs.scaleMatrix.call(void 0, scaleX, scaleY, c), _chunkFKONE6AOcjs.rotateMatrix.call(void 0, rotation, c)), _chunkFKONE6AOcjs.translateMatrix.call(void 0, dx, dy));
|
|
939
|
+
const along = follow ? followAt(entry, timeline, nodes, time) : null;
|
|
940
|
+
if (along) matrix = _chunkFKONE6AOcjs.multiplyMatrices.call(void 0, matrix, _chunkFKONE6AOcjs.multiplyMatrices.call(void 0, _chunkFKONE6AOcjs.multiplyMatrices.call(void 0, _chunkFKONE6AOcjs.translateMatrix.call(void 0, -c.x, -c.y), _chunkFKONE6AOcjs.rotateMatrix.call(void 0, along.angle)), _chunkFKONE6AOcjs.translateMatrix.call(void 0, along.x, along.y)));
|
|
941
|
+
return { matrix, dx, dy, rotation, scaleX, scaleY, follow: along };
|
|
942
|
+
}
|
|
943
|
+
function motionNodeClips(id, timeline, time) {
|
|
944
|
+
const out = [];
|
|
945
|
+
const rect = trackValue(timeline.tracks.get(motionTrackKey(id, "clipRect")), time);
|
|
946
|
+
if (Array.isArray(rect) && rect.length === 4) out.push({ shape: "rect", x: tidy(rect[0]), y: tidy(rect[1]), width: Math.max(0, tidy(rect[2])), height: Math.max(0, tidy(rect[3])) });
|
|
947
|
+
const circle = trackValue(timeline.tracks.get(motionTrackKey(id, "clipCircle")), time);
|
|
948
|
+
if (Array.isArray(circle) && circle.length === 3) out.push({ shape: "circle", cx: tidy(circle[0]), cy: tidy(circle[1]), r: Math.max(0, tidy(circle[2])) });
|
|
949
|
+
return out;
|
|
798
950
|
}
|
|
799
951
|
function motionFrameAt(scene, time, options = {}) {
|
|
800
952
|
const s = applyMotionControlValues(scene, options.values);
|
|
@@ -803,12 +955,15 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
803
955
|
const drawOn = options.draw !== false;
|
|
804
956
|
const value = (id, p) => trackValue(timeline.tracks.get(motionTrackKey(id, p)), time);
|
|
805
957
|
const animated = new Set(timeline.segments.map((seg) => seg.node));
|
|
958
|
+
const clips = {};
|
|
806
959
|
const visit = (node) => {
|
|
807
960
|
let out = node.type === "group" ? { ...node, children: node.children.map(visit) } : node;
|
|
808
961
|
if (!animated.has(node.id)) return out;
|
|
809
962
|
const entry = nodes.get(node.id);
|
|
810
963
|
if (!entry) return out;
|
|
811
964
|
const id = node.id;
|
|
965
|
+
const clip = motionNodeClips(id, timeline, time);
|
|
966
|
+
if (clip.length) clips[id] = clip;
|
|
812
967
|
const shape = shapeAt(entry, timeline, nodes, time);
|
|
813
968
|
if (shape) {
|
|
814
969
|
const { name, visible, opacity: opacity2, locked } = node;
|
|
@@ -816,7 +971,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
816
971
|
if (out.visible === void 0) delete out.visible;
|
|
817
972
|
}
|
|
818
973
|
const effectTracks = [...timeline.tracks.keys()].filter((k) => k.startsWith(`${id}\0effect:`));
|
|
819
|
-
if (effectTracks.length && _optionalChain([out, 'access',
|
|
974
|
+
if (effectTracks.length && _optionalChain([out, 'access', _25 => _25.effects, 'optionalAccess', _26 => _26.length])) {
|
|
820
975
|
out = {
|
|
821
976
|
...out,
|
|
822
977
|
effects: out.effects.map((effect) => {
|
|
@@ -849,7 +1004,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
849
1004
|
const start = Math.min(1, Math.max(0, typeof drawStart === "number" ? drawStart : 0));
|
|
850
1005
|
const end = Math.min(1, Math.max(0, typeof drawEnd === "number" ? drawEnd : 1));
|
|
851
1006
|
if (start > 0 || end < 1) {
|
|
852
|
-
const trim =
|
|
1007
|
+
const trim = _chunkFKONE6AOcjs.createVectorEffect.call(void 0, "trim", MOTION_DRAW_EFFECT_ID, { start: tidy(start * 100), end: tidy(end * 100) });
|
|
853
1008
|
p = { ...p, effects: [trim, ...(_nullishCoalesce(p.effects, () => ( []))).filter((e) => e.id !== MOTION_DRAW_EFFECT_ID)] };
|
|
854
1009
|
}
|
|
855
1010
|
}
|
|
@@ -863,8 +1018,8 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
863
1018
|
if (o >= 1) delete out.opacity;
|
|
864
1019
|
}
|
|
865
1020
|
const offset = options.offsets === false ? null : motionNodeOffset(entry, timeline, time, nodes);
|
|
866
|
-
if (offset && !
|
|
867
|
-
const m =
|
|
1021
|
+
if (offset && !_chunkFKONE6AOcjs.isIdentityMatrix.call(void 0, offset.matrix)) {
|
|
1022
|
+
const m = _chunkFKONE6AOcjs.multiplyMatrices.call(void 0, _chunkFKONE6AOcjs.nodeMatrix.call(void 0, out), offset.matrix).map(tidy);
|
|
868
1023
|
out = { ...out, transform: m };
|
|
869
1024
|
}
|
|
870
1025
|
return out;
|
|
@@ -872,11 +1027,19 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
872
1027
|
const document = { ...s.artwork, nodes: s.artwork.nodes.map(visit) };
|
|
873
1028
|
const cam = trackValue(timeline.tracks.get(motionTrackKey("", "camera")), time);
|
|
874
1029
|
const box = Array.isArray(cam) ? cam : [0, 0, s.artwork.width, s.artwork.height];
|
|
875
|
-
return { time, document, camera: { x: tidy(box[0]), y: tidy(box[1]), width: tidy(box[2]), height: tidy(box[3]) } };
|
|
1030
|
+
return { time, document, camera: { x: tidy(box[0]), y: tidy(box[1]), width: tidy(box[2]), height: tidy(box[3]) }, clips };
|
|
1031
|
+
}
|
|
1032
|
+
function motionClipAttrs(clip) {
|
|
1033
|
+
const { shape: _shape, ...attrs } = clip;
|
|
1034
|
+
return attrs;
|
|
876
1035
|
}
|
|
877
1036
|
function motionFrameToSvg(scene, time, options = {}) {
|
|
878
1037
|
const frame = motionFrameAt(scene, time, options);
|
|
879
|
-
|
|
1038
|
+
const prefix = _nullishCoalesce(options.idPrefix, () => ( "vg-"));
|
|
1039
|
+
const wrap = { ...options.wrap };
|
|
1040
|
+
for (const [id, clips] of Object.entries(frame.clips))
|
|
1041
|
+
wrap[id] = [..._nullishCoalesce(wrap[id], () => ( [])), ...clips.map((clip, i) => ({ clip: { id: `${prefix}reveal-${id}-${i}`, shape: clip.shape, attrs: motionClipAttrs(clip) } }))];
|
|
1042
|
+
return withViewBox(_chunkFKONE6AOcjs.vectorDocumentToSvg.call(void 0, frame.document, { ...options, wrap }), frame.camera);
|
|
880
1043
|
}
|
|
881
1044
|
function withViewBox(svg, box) {
|
|
882
1045
|
const f = (n) => String(Math.round(n * 1e3) / 1e3);
|
|
@@ -886,7 +1049,7 @@ function withViewBox(svg, box) {
|
|
|
886
1049
|
// src/animation-editor/check.ts
|
|
887
1050
|
var MOTION_MIN_CHANGE_MS = 120;
|
|
888
1051
|
var NUMERIC_PARAMS = (node, effectId) => {
|
|
889
|
-
const effect = _optionalChain([node, 'access',
|
|
1052
|
+
const effect = _optionalChain([node, 'access', _27 => _27.effects, 'optionalAccess', _28 => _28.find, 'call', _29 => _29((e) => e.id === effectId)]);
|
|
890
1053
|
if (!effect) return null;
|
|
891
1054
|
return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
|
|
892
1055
|
};
|
|
@@ -911,7 +1074,12 @@ function visibleAt(timeline, id, time, node) {
|
|
|
911
1074
|
if (node.visible === false) return false;
|
|
912
1075
|
if (num("opacity", _nullishCoalesce(node.opacity, () => ( 1))) <= 0.01) return false;
|
|
913
1076
|
if (Math.abs(num("scaleX", 1) * num("scaleY", 1)) <= 1e-4) return false;
|
|
914
|
-
const
|
|
1077
|
+
const clip = (p) => trackValue(timeline.tracks.get(motionTrackKey(id, p)), time);
|
|
1078
|
+
const rect = clip("clipRect");
|
|
1079
|
+
if (Array.isArray(rect) && (rect[2] <= 1e-4 || rect[3] <= 1e-4)) return false;
|
|
1080
|
+
const circle = clip("clipCircle");
|
|
1081
|
+
if (Array.isArray(circle) && circle[2] <= 1e-4) return false;
|
|
1082
|
+
const hasFill = node.type === "path" ? !!node.fill && node.fill !== "none" : _chunkFKONE6AOcjs.collectPathNodes.call(void 0, node).some((p) => p.fill && p.fill !== "none");
|
|
915
1083
|
return num("drawEnd", 1) > 0.01 || hasFill && num("fillOpacity", 1) > 0.01;
|
|
916
1084
|
}
|
|
917
1085
|
function checkMotionScene(scene) {
|
|
@@ -950,6 +1118,12 @@ function checkMotionScene(scene) {
|
|
|
950
1118
|
if (command2.type === "follow" && known(command2.path, "unknown-path", "path", where) && nodes.get(command2.path).node.type !== "path")
|
|
951
1119
|
issues.push(motionIssue("not-a-path", `"${command2.path}" is a group; follow a single path node.`, { ...where, ids: [command2.path] }));
|
|
952
1120
|
if (command2.type === "morph") known(command2.into, "unknown-shape", "shape", where);
|
|
1121
|
+
const style = command2.type === "enter" || command2.type === "exit" ? command2.style : void 0;
|
|
1122
|
+
if (style === "wipe" || style === "iris" || style === "split") {
|
|
1123
|
+
for (const id of targets)
|
|
1124
|
+
if (!motionRevealPadding(nodes.get(id)))
|
|
1125
|
+
issues.push(motionIssue("reveal-no-box", `"${id}" has no width or height (a straight line), so a ${style} cannot clip it and it fades instead; use style "${command2.type === "enter" ? "draw" : "undraw"}" for a line.`, { ...where, ids: [id] }));
|
|
1126
|
+
}
|
|
953
1127
|
if (command2.type === "style") {
|
|
954
1128
|
for (const key of ["fill", "stroke"]) {
|
|
955
1129
|
const color = command2[key];
|
|
@@ -960,12 +1134,24 @@ function checkMotionScene(scene) {
|
|
|
960
1134
|
}
|
|
961
1135
|
for (const id of targets) {
|
|
962
1136
|
const node = nodes.get(id).node;
|
|
963
|
-
const paths = node.type === "path" ? [node] :
|
|
1137
|
+
const paths = node.type === "path" ? [node] : _chunkFKONE6AOcjs.collectPathNodes.call(void 0, node);
|
|
964
1138
|
if (paths.some((p) => p[key] !== void 0 && p[key] !== null && typeof p[key] !== "string"))
|
|
965
1139
|
issues.push(motionIssue("paint-not-color", `"${id}" has a gradient ${key}; it switches to ${color} at the end instead of blending.`, { ...where, ids: [id] }));
|
|
966
1140
|
}
|
|
967
1141
|
}
|
|
968
1142
|
}
|
|
1143
|
+
if (command2.type === "color-pulse") {
|
|
1144
|
+
const key = _nullishCoalesce(command2.paint, () => ( "fill"));
|
|
1145
|
+
const color = _nullishCoalesce(command2.color, () => ( "#f59e0b"));
|
|
1146
|
+
if (_chunkA6PHCAGXcjs.normalizeTokenColor.call(void 0, color) === null) issues.push(motionIssue("invalid-color", `color "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
|
|
1147
|
+
else
|
|
1148
|
+
for (const id of targets) {
|
|
1149
|
+
const node = nodes.get(id).node;
|
|
1150
|
+
const paths = node.type === "path" ? [node] : _chunkFKONE6AOcjs.collectPathNodes.call(void 0, node);
|
|
1151
|
+
if (paths.some((p) => typeof p[key] !== "string"))
|
|
1152
|
+
issues.push(motionIssue("paint-not-color", `"${id}" has a gradient or no ${key}, so a colour pulse cannot tint it; give it a solid ${key} or pulse the ${key === "fill" ? "stroke" : "fill"}.`, { ...where, ids: [id] }));
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
969
1155
|
if (command2.type === "effect") {
|
|
970
1156
|
for (const id of targets) {
|
|
971
1157
|
const node = nodes.get(id).node;
|
|
@@ -1016,7 +1202,7 @@ function checkMotionScene(scene) {
|
|
|
1016
1202
|
const cam = frame.camera;
|
|
1017
1203
|
const docIndex = indexMotionNodes(frame.document.nodes);
|
|
1018
1204
|
for (const id of command2.targets) {
|
|
1019
|
-
const b = _optionalChain([docIndex, 'access',
|
|
1205
|
+
const b = _optionalChain([docIndex, 'access', _30 => _30.get, 'call', _31 => _31(id), 'optionalAccess', _32 => _32.bounds]);
|
|
1020
1206
|
if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
|
|
1021
1207
|
const outside = b.x + b.width < cam.x || b.y + b.height < cam.y || b.x > cam.x + cam.width || b.y > cam.y + cam.height;
|
|
1022
1208
|
if (outside) {
|
|
@@ -1193,9 +1379,9 @@ function applyMotionEdits(scene, edits) {
|
|
|
1193
1379
|
let next = scene;
|
|
1194
1380
|
for (let i = 0; i < list.length; i++) {
|
|
1195
1381
|
const edit = list[i];
|
|
1196
|
-
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess',
|
|
1382
|
+
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _33 => _33.op])}): ` : "";
|
|
1197
1383
|
if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
|
|
1198
|
-
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess',
|
|
1384
|
+
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _34 => _34.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
|
|
1199
1385
|
try {
|
|
1200
1386
|
next = applyOne(next, edit);
|
|
1201
1387
|
} catch (error) {
|
|
@@ -1250,6 +1436,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1250
1436
|
const fps = _nullishCoalesce(_nullishCoalesce(options.fps, () => ( scene.fps)), () => ( 30));
|
|
1251
1437
|
const precision = _nullishCoalesce(options.precision, () => ( 3));
|
|
1252
1438
|
const curves = _nullishCoalesce(options.curves, () => ( true));
|
|
1439
|
+
const behaviors = _nullishCoalesce(options.behaviors, () => ( true));
|
|
1440
|
+
const plays = (s) => !s.behavior || behaviors;
|
|
1253
1441
|
const round2 = (n) => Math.round(n * 10 ** precision) / 10 ** precision;
|
|
1254
1442
|
const f = (n) => String(round2(n));
|
|
1255
1443
|
const timeline = compileMotionScene(scene);
|
|
@@ -1264,35 +1452,81 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1264
1452
|
};
|
|
1265
1453
|
const animatedNodes = new Set(timeline.segments.map((s) => s.node).filter(Boolean));
|
|
1266
1454
|
const pathsSeen = /* @__PURE__ */ new Set();
|
|
1455
|
+
const wrap = {};
|
|
1456
|
+
const routes = [];
|
|
1457
|
+
const follows = [];
|
|
1458
|
+
const usedIds = new Set(nodes.keys());
|
|
1459
|
+
const freshId = (base) => {
|
|
1460
|
+
let id = base;
|
|
1461
|
+
for (let n = 2; usedIds.has(id); n++) id = `${base}-${n}`;
|
|
1462
|
+
usedIds.add(id);
|
|
1463
|
+
return id;
|
|
1464
|
+
};
|
|
1267
1465
|
for (const id of animatedNodes) {
|
|
1268
1466
|
const entry = nodes.get(id);
|
|
1269
1467
|
const node = entry.node;
|
|
1468
|
+
const drawn = [...entry.ancestors.map((a) => nodes.get(a).node), node].every((n) => n.visible !== false);
|
|
1469
|
+
for (const [p, name] of [["clipRect", "reveal"], ["clipCircle", "iris"]]) {
|
|
1470
|
+
if (!drawn || !timeline.tracks.has(motionTrackKey(id, p))) continue;
|
|
1471
|
+
const wrapper = freshId(`${id}--${name}`);
|
|
1472
|
+
const clipId = freshId(`${wrapper}-clip`);
|
|
1473
|
+
const shapeId = freshId(`${wrapper}-clip-shape`);
|
|
1474
|
+
const clipAt = (t) => motionNodeClips(id, timeline, t).find((c) => c.shape === (p === "clipRect" ? "rect" : "circle"));
|
|
1475
|
+
const rest = clipAt(0);
|
|
1476
|
+
(wrap[id] ??= []).push({ id: wrapper, clip: { id: clipId, shapeId, shape: rest.shape, attrs: motionClipAttrs(rest) } });
|
|
1477
|
+
channels.push({ id: shapeId, kind: "attrs", attrs: Object.keys(motionClipAttrs(rest)), segments: [...track(id, p)], exact: () => true, value: (t) => Object.values(motionClipAttrs(clipAt(t))).map((v) => Math.round(v * 1e4) / 1e4) });
|
|
1478
|
+
}
|
|
1479
|
+
const followSegments = track(id, "follow");
|
|
1480
|
+
if (drawn && followSegments.length) {
|
|
1481
|
+
const ids = /* @__PURE__ */ new Map();
|
|
1482
|
+
for (const seg of followSegments) {
|
|
1483
|
+
if (!seg.path || ids.has(seg.path)) continue;
|
|
1484
|
+
const route = motionFollowRoute(entry, nodes.get(seg.path));
|
|
1485
|
+
if (!route) continue;
|
|
1486
|
+
const routeId = freshId(`${id}--follow-route`);
|
|
1487
|
+
ids.set(seg.path, routeId);
|
|
1488
|
+
routes.push(`<path id="${routeId}" d="${_chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, route, { precision })}" fill="none"/>`);
|
|
1489
|
+
}
|
|
1490
|
+
if (ids.size) {
|
|
1491
|
+
const wrapper = freshId(`${id}--follow`);
|
|
1492
|
+
const centre = freshId(`${id}--follow-centre`);
|
|
1493
|
+
const c = entry.center;
|
|
1494
|
+
const at = _optionalChain([motionNodeOffset, 'call', _35 => _35(entry, timeline, 0, nodes), 'optionalAccess', _36 => _36.follow]);
|
|
1495
|
+
const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
|
|
1496
|
+
(wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
|
|
1497
|
+
follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1270
1500
|
if (timeline.tracks.has(motionTrackKey(id, "opacity")))
|
|
1271
|
-
channels.push({ id, kind: "attr", attr: "opacity", segments: [...track(id, "opacity")], exact:
|
|
1272
|
-
const
|
|
1501
|
+
channels.push({ id, kind: "attr", attr: "opacity", segments: [...track(id, "opacity")], exact: plays, value: (t) => round2(Math.min(1, Math.max(0, Number(trackValue(track(id, "opacity"), t))))) });
|
|
1502
|
+
const followed = follows.some((x) => x.id === id);
|
|
1503
|
+
const transformSegments = TRANSFORM_PROPS2.flatMap((p) => followed && p === "follow" ? [] : track(id, p));
|
|
1273
1504
|
if (transformSegments.length) {
|
|
1274
1505
|
const base = node.transform ? ` matrix(${node.transform.map(f).join(" ")})` : "";
|
|
1275
1506
|
const c = entry.center;
|
|
1507
|
+
const transformAt = (t, raw) => {
|
|
1508
|
+
const o = motionNodeOffset(entry, timeline, t, nodes, raw, !followed);
|
|
1509
|
+
return `translate(${f(o.dx)} ${f(o.dy)}) rotate(${f(o.rotation)} ${f(c.x)} ${f(c.y)}) translate(${f(c.x)} ${f(c.y)}) scale(${f(o.scaleX)} ${f(o.scaleY)}) translate(${f(-c.x)} ${f(-c.y)})${base}`;
|
|
1510
|
+
};
|
|
1276
1511
|
channels.push({
|
|
1277
1512
|
id,
|
|
1278
1513
|
kind: "attr",
|
|
1279
1514
|
attr: "transform",
|
|
1280
1515
|
segments: transformSegments,
|
|
1281
|
-
exact: (s) => LINEAR_TRANSFORM.has(s.property) &&
|
|
1516
|
+
exact: (s) => LINEAR_TRANSFORM.has(s.property) && plays(s),
|
|
1282
1517
|
overshoot: true,
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
}
|
|
1518
|
+
// x, y and the angle are the transform's numbers 0, 1 and 2 (`MotionSegment.index`).
|
|
1519
|
+
value: (t) => transformAt(t, false),
|
|
1520
|
+
raw: (t) => transformAt(t, true)
|
|
1287
1521
|
});
|
|
1288
1522
|
}
|
|
1289
|
-
const paths = node.type === "path" ? [node] :
|
|
1523
|
+
const paths = node.type === "path" ? [node] : _chunkFKONE6AOcjs.collectPathNodes.call(void 0, node);
|
|
1290
1524
|
for (const path of paths) {
|
|
1291
1525
|
if (pathsSeen.has(path.id)) continue;
|
|
1292
1526
|
pathsSeen.add(path.id);
|
|
1293
1527
|
const paint = (p, attr) => {
|
|
1294
1528
|
const from = owner(path, p);
|
|
1295
|
-
if (from) channels.push({ id: path.id, kind: "attr", attr, segments: [...track(from, p)], exact: () =>
|
|
1529
|
+
if (from) channels.push({ id: path.id, kind: "attr", attr, segments: [...track(from, p)], exact: plays, value: (t) => hex6(trackValue(track(from, p), t)), raw: (t) => hex6(trackValue(track(from, p), t, true)) });
|
|
1296
1530
|
};
|
|
1297
1531
|
paint("fill", "fill");
|
|
1298
1532
|
paint("stroke", "stroke");
|
|
@@ -1308,7 +1542,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1308
1542
|
if (shapeSegments.length) {
|
|
1309
1543
|
if (node.type !== "path") notes.push(`"${id}" is a group: its morph or effect animation is not exported (Flair tweens one path's "d").`);
|
|
1310
1544
|
else {
|
|
1311
|
-
const inverse =
|
|
1545
|
+
const inverse = _chunkFKONE6AOcjs.invertMatrix.call(void 0, _chunkFKONE6AOcjs.nodeMatrix.call(void 0, node));
|
|
1312
1546
|
channels.push({
|
|
1313
1547
|
id,
|
|
1314
1548
|
kind: "attr",
|
|
@@ -1317,9 +1551,9 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1317
1551
|
exact: () => false,
|
|
1318
1552
|
value: (t) => {
|
|
1319
1553
|
const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
|
|
1320
|
-
const now =
|
|
1554
|
+
const now = _chunkFKONE6AOcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _37 => _37(frame.document.nodes), 'access', _38 => _38.get, 'call', _39 => _39(id), 'optionalAccess', _40 => _40.node]));
|
|
1321
1555
|
if (!now || now.type !== "path") return "";
|
|
1322
|
-
const bezier = _chunkO2UH7LZEcjs.transformBezierPath.call(void 0,
|
|
1556
|
+
const bezier = _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkFKONE6AOcjs.vectorPathWorldBezier.call(void 0, now, _chunkFKONE6AOcjs.IDENTITY_MATRIX, { effects: false }), inverse);
|
|
1323
1557
|
return _chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
|
|
1324
1558
|
}
|
|
1325
1559
|
});
|
|
@@ -1331,15 +1565,22 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1331
1565
|
const animate = [];
|
|
1332
1566
|
let sampled = 0;
|
|
1333
1567
|
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
1334
|
-
const emit = (channel, delay, ms, from, to, ease) => {
|
|
1335
|
-
const base = { ...channel.id ? { id: channel.id } : {}, ...delay > 0 ? { delay: round2(delay) } : {}, ms: round2(ms), ease: typeof ease === "string" ? ease : ease.map(round2) };
|
|
1568
|
+
const emit = (channel, delay, ms, from, to, ease, behavior) => {
|
|
1569
|
+
const base = { ...channel.id ? { id: channel.id } : {}, ...delay > 0 ? { delay: round2(delay) } : {}, ms: round2(ms), ease: typeof ease === "string" ? ease : ease.map(round2), ...behavior ? { behavior } : {} };
|
|
1336
1570
|
if (channel.kind === "view") animate.push({ ...base, view: to });
|
|
1337
1571
|
else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
|
|
1338
|
-
else
|
|
1572
|
+
else if (channel.kind === "attrs") {
|
|
1573
|
+
const [a, b] = [from, to];
|
|
1574
|
+
const attrs = Object.fromEntries(channel.attrs.flatMap((name, k) => a[k] !== b[k] ? [[name, [a[k], b[k]]]] : []));
|
|
1575
|
+
animate.push({ ...base, attrs });
|
|
1576
|
+
} else animate.push({ ...base, attrs: { [channel.attr]: [from, to] } });
|
|
1339
1577
|
};
|
|
1340
1578
|
for (const channel of channels) {
|
|
1341
1579
|
const cuts = channel.segments.filter((s) => s.end <= s.start);
|
|
1342
|
-
for (const cut of cuts)
|
|
1580
|
+
for (const cut of cuts) {
|
|
1581
|
+
const [from, to] = [channel.value(Math.max(0, cut.start - 1e-3)), channel.value(cut.start)];
|
|
1582
|
+
if (cut.start <= 0 || !same(from, to) || channel.kind === "view") emit(channel, cut.start, 0, from, to, "linear");
|
|
1583
|
+
}
|
|
1343
1584
|
const times = [...new Set(channel.segments.flatMap((s) => [s.start, s.end]))].sort((a, b) => a - b);
|
|
1344
1585
|
for (let i = 0; i + 1 < times.length; i++) {
|
|
1345
1586
|
const a = times[i];
|
|
@@ -1347,13 +1588,15 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1347
1588
|
const active = channel.segments.filter((s) => s.start < b && s.end > a);
|
|
1348
1589
|
if (!active.length) continue;
|
|
1349
1590
|
const first = active[0];
|
|
1350
|
-
const together = active.every(
|
|
1591
|
+
const together = active.every(
|
|
1592
|
+
(x) => x.start === a && x.end === b && channel.exact(x) && JSON.stringify(x.ease) === JSON.stringify(first.ease) && JSON.stringify(x.behavior) === JSON.stringify(first.behavior)
|
|
1593
|
+
);
|
|
1351
1594
|
const curve = together ? flairCurveFor(first.ease, curves) : void 0;
|
|
1352
1595
|
const ease = curve && (!overshoots(curve) || channel.overshoot) ? curve : void 0;
|
|
1353
1596
|
if (ease) {
|
|
1354
1597
|
const from = channel.value(a);
|
|
1355
|
-
const to = channel.value(b);
|
|
1356
|
-
if (!same(from, to) || channel.kind === "view") emit(channel, a, b - a, from, to, ease);
|
|
1598
|
+
const to = first.behavior ? (_nullishCoalesce(channel.raw, () => ( channel.value)))(b) : channel.value(b);
|
|
1599
|
+
if (!same(from, to) || channel.kind === "view") emit(channel, a, b - a, from, to, ease, first.behavior);
|
|
1357
1600
|
continue;
|
|
1358
1601
|
}
|
|
1359
1602
|
const n = Math.max(1, Math.ceil((b - a) * fps / 1e3));
|
|
@@ -1370,11 +1613,32 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1370
1613
|
}
|
|
1371
1614
|
}
|
|
1372
1615
|
}
|
|
1616
|
+
for (const follow of follows) {
|
|
1617
|
+
const starts = follow.segments.map((seg) => seg.start);
|
|
1618
|
+
for (const seg of follow.segments) {
|
|
1619
|
+
const along = { id: follow.wrapper, along: follow.routes.get(seg.path), ...seg.rotate ? { orient: true } : {} };
|
|
1620
|
+
const progress = (t) => round2(Math.min(1, Math.max(0, Number(segmentValue(seg, t)))));
|
|
1621
|
+
const curve = seg.end > seg.start ? flairCurveFor(seg.ease, curves) : "linear";
|
|
1622
|
+
if (curve && !(overshoots(curve) && seg.rotate)) {
|
|
1623
|
+
animate.push({ ...along, ...seg.start > 0 ? { delay: round2(seg.start) } : {}, ms: round2(seg.end - seg.start), ease: typeof curve === "string" ? curve : curve.map(round2), at: [round2(Number(seg.from)), round2(Number(seg.to))] });
|
|
1624
|
+
continue;
|
|
1625
|
+
}
|
|
1626
|
+
const until = Math.min(seg.end, ...starts.filter((t) => t > seg.start));
|
|
1627
|
+
const n = Math.max(1, Math.ceil((until - seg.start) * fps / 1e3));
|
|
1628
|
+
for (let k = 1; k <= n; k++) {
|
|
1629
|
+
const t0 = seg.start + (until - seg.start) * (k - 1) / n;
|
|
1630
|
+
const t1 = seg.start + (until - seg.start) * k / n;
|
|
1631
|
+
animate.push({ ...along, ...t0 > 0 ? { delay: round2(t0) } : {}, ms: round2(t1 - t0), ease: "linear", at: [progress(t0), progress(t1)] });
|
|
1632
|
+
sampled++;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1373
1636
|
animate.sort((x, y) => (_nullishCoalesce(x.delay, () => ( 0))) - (_nullishCoalesce(y.delay, () => ( 0))));
|
|
1374
|
-
let svg =
|
|
1637
|
+
let svg = _chunkFKONE6AOcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunkFKONE6AOcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
|
|
1638
|
+
if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
|
|
1375
1639
|
const lastChange = animate.reduce((m, a) => Math.max(m, (_nullishCoalesce(a.delay, () => ( 0))) + (_nullishCoalesce(a.ms, () => ( 0)))), 0);
|
|
1376
1640
|
let motion = { svg, animate };
|
|
1377
|
-
if (_optionalChain([scene, 'access',
|
|
1641
|
+
if (_optionalChain([scene, 'access', _41 => _41.controls, 'optionalAccess', _42 => _42.length])) {
|
|
1378
1642
|
const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
|
|
1379
1643
|
const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
|
|
1380
1644
|
svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
|
|
@@ -1396,7 +1660,7 @@ function toFlairVectorEffect(scene, options = {}) {
|
|
|
1396
1660
|
tags: _nullishCoalesce(options.tags, () => ( [])),
|
|
1397
1661
|
motion: out.motion,
|
|
1398
1662
|
hold: out.hold,
|
|
1399
|
-
..._optionalChain([scene, 'access',
|
|
1663
|
+
..._optionalChain([scene, 'access', _43 => _43.presets, 'optionalAccess', _44 => _44.length]) ? { presets: scene.presets } : {},
|
|
1400
1664
|
...options.trigger ? { trigger: options.trigger } : {}
|
|
1401
1665
|
};
|
|
1402
1666
|
}
|
|
@@ -1481,7 +1745,7 @@ var AnimationEditorController = (_class = class {
|
|
|
1481
1745
|
time: p.time,
|
|
1482
1746
|
playing: p.playing,
|
|
1483
1747
|
loop: p.loop,
|
|
1484
|
-
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call',
|
|
1748
|
+
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _45 => _45(timeline, p.time), 'optionalAccess', _46 => _46.id]), () => ( null)),
|
|
1485
1749
|
selection: this.selection,
|
|
1486
1750
|
readOnly: this.readOnly,
|
|
1487
1751
|
error: this.error,
|
|
@@ -1520,7 +1784,7 @@ var AnimationEditorController = (_class = class {
|
|
|
1520
1784
|
this.applying = false;
|
|
1521
1785
|
}
|
|
1522
1786
|
this.notify();
|
|
1523
|
-
_optionalChain([this, 'access',
|
|
1787
|
+
_optionalChain([this, 'access', _47 => _47.onChange, 'optionalCall', _48 => _48(scene)]);
|
|
1524
1788
|
}
|
|
1525
1789
|
commit(label, next) {
|
|
1526
1790
|
const before = this.scene;
|
|
@@ -1680,13 +1944,20 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
1680
1944
|
description: `A command (one of ${MOTION_COMMAND_TYPES.join(", ")}). Commands in a shot play one after another unless "with": "previous".`,
|
|
1681
1945
|
oneOf: [
|
|
1682
1946
|
command("enter", "Brings hidden targets in; they are hidden before this shot.", {
|
|
1683
|
-
style: {
|
|
1684
|
-
|
|
1685
|
-
|
|
1947
|
+
style: {
|
|
1948
|
+
type: "string",
|
|
1949
|
+
enum: [...MOTION_ENTER_STYLES],
|
|
1950
|
+
description: "fade (default), pop (scales up past full size and settles), grow (from nothing), slide, draw (outline drawn on, then the fill fades in), zoom (settles from larger), rise (rises a short way, overshooting a touch), or a reveal through a clip over the target's box: wipe (behind a travelling edge), iris (from the centre outwards) or split (from a line through the middle). Reveals need a box with a width and a height (not a lone straight line)."
|
|
1951
|
+
},
|
|
1952
|
+
direction: { type: "string", enum: [...MOTION_DIRECTIONS], description: "For slide: direction of travel (default up). For wipe: the way the edge travels (default right, revealing from the left)." },
|
|
1953
|
+
distance: { type: "number", description: "For slide (default 40) and rise (default 20): document units." },
|
|
1954
|
+
scale: { type: "number", minimum: 0, description: "For pop (default 0.5) and zoom (default 1.6): the starting scale (1 = rest size)." },
|
|
1955
|
+
shape: { type: "string", enum: [...MOTION_IRIS_SHAPES], description: "For iris: open through a circle (default; an ellipse on a box that is not square) or a box." },
|
|
1956
|
+
orientation: { type: "string", enum: [...MOTION_SPLIT_ORIENTATIONS], description: "For split: horizontal (default) opens up and down from a horizontal line through the middle; vertical opens left and right." }
|
|
1686
1957
|
}),
|
|
1687
1958
|
command("exit", "Takes targets out.", {
|
|
1688
|
-
style: { type: "string", enum: [...MOTION_EXIT_STYLES], description: "fade (default), shrink, slide or
|
|
1689
|
-
direction: { type: "string", enum: [...MOTION_DIRECTIONS], description: "For slide: direction of travel (default down)." },
|
|
1959
|
+
style: { type: "string", enum: [...MOTION_EXIT_STYLES], description: "fade (default), shrink, slide, undraw, or wipe (hides behind a travelling edge through a clip over the target's box: a wipe in, reversed)." },
|
|
1960
|
+
direction: { type: "string", enum: [...MOTION_DIRECTIONS], description: "For slide: direction of travel (default down). For wipe: the way the edge travels (default right, hiding from the left)." },
|
|
1690
1961
|
distance: { type: "number", description: "For slide: document units (default 40)." }
|
|
1691
1962
|
}),
|
|
1692
1963
|
command("draw", "Draws strokes on (or off) to a fraction of their length.", { to: FRACTION("Fraction drawn at the end (default 1)."), from: FRACTION("Fraction drawn at the start (default: what is drawn now).") }),
|
|
@@ -1702,12 +1973,30 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
1702
1973
|
command("morph", "Morphs each target into the shape (and paint) of another node, which usually stays hidden.", { into: { type: "string", minLength: 1, description: "Id of the node whose shape to take." } }, ["into"]),
|
|
1703
1974
|
command("follow", "Moves targets along a path node, centre on the path.", {
|
|
1704
1975
|
path: { type: "string", minLength: 1, description: "Id of a path node (it can be hidden)." },
|
|
1705
|
-
rotate: { type: "boolean", description: "Turn with the path (default false)." },
|
|
1976
|
+
rotate: { type: "boolean", description: "Turn with the path (default false); moves and shakes made meanwhile turn with it too." },
|
|
1706
1977
|
from: FRACTION("Where to start along the path (default 0)."),
|
|
1707
1978
|
to: FRACTION("Where to end along the path (default 1).")
|
|
1708
1979
|
}, ["path"]),
|
|
1709
1980
|
command("pulse", "Scales up and back to draw the eye.", { amount: { type: "number", description: "Extra scale at the peak (default 0.15)." }, count: { type: "integer", minimum: 1, description: "Pulses (default 1)." } }),
|
|
1710
|
-
command("shake", "Shakes side to side
|
|
1981
|
+
command("shake", "Shakes side to side (or up and down), settling.", {
|
|
1982
|
+
amount: { type: "number", description: "Document units (default 8)." },
|
|
1983
|
+
count: { type: "integer", minimum: 1, description: "Shakes (default 3)." },
|
|
1984
|
+
axis: { type: "string", enum: ["horizontal", "vertical"], description: "Default horizontal." }
|
|
1985
|
+
}),
|
|
1986
|
+
command("teeter", "Rocks about the centre either way, settling.", { angle: { type: "number", description: "Degrees either way (default 8)." }, count: { type: "integer", minimum: 1, description: "Rocks (default 3)." } }),
|
|
1987
|
+
command("wave", "Bobs up and down without settling, like something floating (default 1000 ms).", { amount: { type: "number", description: "Height in document units (default 6)." }, count: { type: "integer", minimum: 1, description: "Bobs (default 2)." } }),
|
|
1988
|
+
command("wiggle", "Wanders about its place as smooth seeded noise, easing out of and back to rest (default 1500 ms). The same seed always wanders the same way.", {
|
|
1989
|
+
amount: { type: "number", description: "Up to about this far, in document units (default 6)." },
|
|
1990
|
+
frequency: { type: "number", exclusiveMinimum: 0, description: "Wanders per second, in Hz (default 3)." },
|
|
1991
|
+
octaves: { type: "integer", minimum: 1, maximum: 8, description: "Layers of finer detail (default 2)." },
|
|
1992
|
+
rotate: { type: "number", description: "Also turns about the centre by up to about this many degrees (default 0)." },
|
|
1993
|
+
seed: { type: "integer", minimum: 0, description: "Default: one picked from the target id, so each target wanders its own way." }
|
|
1994
|
+
}),
|
|
1995
|
+
command("color-pulse", "Tints solid paint toward a colour and back (mixed in OKLab). On a group it tints every path in it.", {
|
|
1996
|
+
color: { type: "string", description: 'The tint, a CSS colour (default "#f59e0b").' },
|
|
1997
|
+
paint: { type: "string", enum: ["fill", "stroke"], description: "Which paint (default fill)." },
|
|
1998
|
+
count: { type: "integer", minimum: 1, description: "Pulses (default 1)." }
|
|
1999
|
+
}),
|
|
1711
2000
|
command("effect", "Tweens a numeric parameter of a live path effect on the targets (twist angle, wiggle time, zig zag size, trim offset\u2026).", {
|
|
1712
2001
|
effect: { type: "string", minLength: 1, description: `Effect id from get_animation's element "effects".` },
|
|
1713
2002
|
param: { type: "string", minLength: 1, description: "A numeric parameter of that effect (listed with it)." },
|
|
@@ -1804,7 +2093,8 @@ function describeMotionShots(scene) {
|
|
|
1804
2093
|
...shot.hold !== void 0 ? { hold: shot.hold } : {},
|
|
1805
2094
|
commands: shot.run.map((c, index) => {
|
|
1806
2095
|
const ct = timeline.commands.find((x) => x.shotIndex === i && x.command === index);
|
|
1807
|
-
|
|
2096
|
+
const primitive = motionFlairPrimitive(c);
|
|
2097
|
+
return { index, ...c, start: ct.start, end: ct.end, ...primitive ? { flairPrimitive: primitive } : {} };
|
|
1808
2098
|
})
|
|
1809
2099
|
};
|
|
1810
2100
|
});
|
|
@@ -1840,7 +2130,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
1840
2130
|
const getAnimation = {
|
|
1841
2131
|
name: "get_animation",
|
|
1842
2132
|
title: "Read the animation",
|
|
1843
|
-
description:
|
|
2133
|
+
description: `Returns the vector animation: its name, artwork size, length (ms), loop mode, the artwork's elements (id, type, name, parent, bounds, solid paints, live effects with their numeric parameters), every shot with its commands and their start/end times (and, where Flair has one, the Flair motion primitive a command plays as "flairPrimitive", e.g. "entrance.pop"), Flair controls, and a summary of issues. Use the ids it returns with the write tools.`,
|
|
1844
2134
|
inputSchema: object({ includeElements: { type: "boolean", description: "Include the artwork's elements (default true)." } }),
|
|
1845
2135
|
annotations: { title: "Read the animation", ...READ },
|
|
1846
2136
|
handler: ({ includeElements = true }) => {
|
|
@@ -1927,16 +2217,18 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
1927
2217
|
}
|
|
1928
2218
|
};
|
|
1929
2219
|
const CURVES_DESCRIPTION = "Write cubic-bezier easings (ease, ease-in, ease-out, ease-in-out, back eases, custom curves) as one change with ease: [x1, y1, x2, y2] (default true). Needs Flair 0.36 or later; false samples them into linear steps for older Flair.";
|
|
2220
|
+
const BEHAVIORS_DESCRIPTION = "Write pulses, shakes, teeters, waves, wiggles and colour pulses as one change with a Flair behavior, so they play exactly (default true; needs Flair 0.38 or later). False samples them into linear steps for older Flair.";
|
|
1930
2221
|
const exportFlairMotion = {
|
|
1931
2222
|
name: "export_flair_motion",
|
|
1932
2223
|
title: "Export as Flair vector motion",
|
|
1933
2224
|
description: "Returns the animation as a Flair SvgMotion ({ svg, animate }) that Flair's SvgPlayer plays, plus its hold, how many changes were sampled into linear steps, and notes on anything not carried over.",
|
|
1934
2225
|
inputSchema: object({
|
|
1935
2226
|
fps: { type: "number", minimum: 1, maximum: 120, description: "Sampling rate for changes Flair cannot express exactly (default: the scene's fps, else 30)." },
|
|
1936
|
-
curves: { type: "boolean", description: CURVES_DESCRIPTION }
|
|
2227
|
+
curves: { type: "boolean", description: CURVES_DESCRIPTION },
|
|
2228
|
+
behaviors: { type: "boolean", description: BEHAVIORS_DESCRIPTION }
|
|
1937
2229
|
}),
|
|
1938
2230
|
annotations: { title: "Export as Flair vector motion", ...READ },
|
|
1939
|
-
handler: ({ fps, curves }) => controller.toFlairMotion({ ...fps ? { fps } : {}, ...curves === void 0 ? {} : { curves } })
|
|
2231
|
+
handler: ({ fps, curves, behaviors }) => controller.toFlairMotion({ ...fps ? { fps } : {}, ...curves === void 0 ? {} : { curves }, ...behaviors === void 0 ? {} : { behaviors } })
|
|
1940
2232
|
};
|
|
1941
2233
|
const exportFlairEffect = {
|
|
1942
2234
|
name: "export_flair_effect",
|
|
@@ -1948,7 +2240,8 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
1948
2240
|
description: { type: "string", description: "One sentence (default: the scene's description)." },
|
|
1949
2241
|
category: { type: "string", minLength: 1, description: "Flair catalog category, e.g. icon, loader, ui, data, text, morph (default icon)." },
|
|
1950
2242
|
tags: { type: "array", items: { type: "string" }, description: "Search tags (default none)." },
|
|
1951
|
-
curves: { type: "boolean", description: CURVES_DESCRIPTION }
|
|
2243
|
+
curves: { type: "boolean", description: CURVES_DESCRIPTION },
|
|
2244
|
+
behaviors: { type: "boolean", description: BEHAVIORS_DESCRIPTION }
|
|
1952
2245
|
}),
|
|
1953
2246
|
annotations: { title: "Export as a Flair effect", ...READ },
|
|
1954
2247
|
handler: (args) => controller.toFlairEffect(args)
|
|
@@ -1962,7 +2255,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
1962
2255
|
handler: ({ svg }) => {
|
|
1963
2256
|
let artwork;
|
|
1964
2257
|
try {
|
|
1965
|
-
artwork =
|
|
2258
|
+
artwork = _chunkFKONE6AOcjs.parseVectorSvg.call(void 0, svg);
|
|
1966
2259
|
} catch (error) {
|
|
1967
2260
|
throw new Error(`The SVG could not be read: ${error.message}. Nothing was changed.`);
|
|
1968
2261
|
}
|
|
@@ -2015,7 +2308,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
2015
2308
|
inputSchema: object({ shot: SHOT_ID, commands: { type: "array", items: MOTION_COMMAND_SCHEMA, minItems: 1, description: "Commands to add." }, at: { type: "integer", minimum: 0, description: "Index in the run (default: the end)." } }, ["shot", "commands"]),
|
|
2016
2309
|
annotations: { title: "Add commands to a shot", ...WRITE },
|
|
2017
2310
|
handler: ({ shot, commands, at }) => {
|
|
2018
|
-
const before = _nullishCoalesce(_optionalChain([scene, 'call',
|
|
2311
|
+
const before = _nullishCoalesce(_optionalChain([scene, 'call', _49 => _49(), 'access', _50 => _50.shots, 'access', _51 => _51.find, 'call', _52 => _52((s) => s.id === shot), 'optionalAccess', _53 => _53.run, 'access', _54 => _54.length]), () => ( 0));
|
|
2019
2312
|
const first = _nullishCoalesce(at, () => ( before));
|
|
2020
2313
|
return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
|
|
2021
2314
|
const shots = describeMotionShots(s);
|
|
@@ -2160,8 +2453,12 @@ How it plays
|
|
|
2160
2453
|
|
|
2161
2454
|
Commands
|
|
2162
2455
|
- enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.
|
|
2456
|
+
- enter also reveals through a clip over the target's box: wipe (behind an edge travelling "direction", default right), iris (from the centre; "shape": circle or box) and split (from a line through the middle; "orientation": horizontal or vertical). exit wipe hides the same way. Reveals need a width and a height: use draw / undraw for a straight line.
|
|
2163
2457
|
- draw draws strokes on to a fraction; move, rotate, scale and fade change the pose (about the centre); style blends solid colours and stroke width.
|
|
2164
|
-
-
|
|
2458
|
+
- enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting "scale".
|
|
2459
|
+
- morph turns a shape into another node's shape (keep the target hidden); follow moves along a path node (with "rotate", moves made meanwhile turn with the path).
|
|
2460
|
+
- Emphasis draws the eye and returns to rest: pulse (swell), shake (side to side, or "axis": "vertical"), teeter (rock), wave (bob, no settling), wiggle (seeded wander; the same seed wanders the same way) and color-pulse (tint and back).
|
|
2461
|
+
- Commands share their names and defaults with Flair's motion primitives (get_animation shows each one's "flairPrimitive"), and emphasis, reveals and follows export to Flair exactly.
|
|
2165
2462
|
- effect tweens a numeric parameter of a live path effect already on the node (twist angle, wiggle time, zig zag size).
|
|
2166
2463
|
|
|
2167
2464
|
Working method
|
|
@@ -2235,5 +2532,13 @@ Keep motion purposeful: one thing moving at a time reads best, ease-out for arri
|
|
|
2235
2532
|
|
|
2236
2533
|
|
|
2237
2534
|
|
|
2238
|
-
|
|
2535
|
+
|
|
2536
|
+
|
|
2537
|
+
|
|
2538
|
+
|
|
2539
|
+
|
|
2540
|
+
|
|
2541
|
+
|
|
2542
|
+
|
|
2543
|
+
exports.ANIMATION_EDITOR_AGENT_INSTRUCTIONS = ANIMATION_EDITOR_AGENT_INSTRUCTIONS; exports.AnimationEditorController = AnimationEditorController; exports.FLAIR_EASES = FLAIR_EASES; exports.MOTION_CAMERA_MS = MOTION_CAMERA_MS; exports.MOTION_COMMAND_SCHEMA = MOTION_COMMAND_SCHEMA; exports.MOTION_COMMAND_TYPES = MOTION_COMMAND_TYPES; exports.MOTION_DEFAULT_DURATIONS = MOTION_DEFAULT_DURATIONS; exports.MOTION_DEFAULT_HOLD = MOTION_DEFAULT_HOLD; exports.MOTION_DIRECTIONS = MOTION_DIRECTIONS; exports.MOTION_DRAW_EFFECT_ID = MOTION_DRAW_EFFECT_ID; exports.MOTION_DRAW_MS_PER_UNIT = MOTION_DRAW_MS_PER_UNIT; exports.MOTION_DRAW_RANGE = MOTION_DRAW_RANGE; exports.MOTION_EASE_IN_OUT = MOTION_EASE_IN_OUT; exports.MOTION_EASE_OUT = MOTION_EASE_OUT; exports.MOTION_EDIT_OPS = MOTION_EDIT_OPS; exports.MOTION_ENTER_STYLES = MOTION_ENTER_STYLES; exports.MOTION_EXIT_STYLES = MOTION_EXIT_STYLES; exports.MOTION_IRIS_SHAPES = MOTION_IRIS_SHAPES; exports.MOTION_ISSUE_CODES = MOTION_ISSUE_CODES; exports.MOTION_MIN_CHANGE_MS = MOTION_MIN_CHANGE_MS; exports.MOTION_SPLIT_ORIENTATIONS = MOTION_SPLIT_ORIENTATIONS; exports.MotionSceneFormatError = MotionSceneFormatError; exports.activeSegment = activeSegment; exports.applyMotionControlValues = applyMotionControlValues; exports.applyMotionEdits = applyMotionEdits; exports.checkMotionScene = checkMotionScene; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createMotionScene = createMotionScene; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.fitMotionRect = fitMotionRect; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.freshShotId = freshShotId; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.motionClipAttrs = motionClipAttrs; exports.motionCommandDuration = motionCommandDuration; exports.motionFlairPrimitive = motionFlairPrimitive; exports.motionFollowRoute = motionFollowRoute; exports.motionFrameAt = motionFrameAt; exports.motionFrameToSvg = motionFrameToSvg; exports.motionIssue = motionIssue; exports.motionIssueKey = motionIssueKey; exports.motionIssueLine = motionIssueLine; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionPathLength = motionPathLength; exports.motionRestValue = motionRestValue; exports.motionRevealClip = motionRevealClip; exports.motionRevealPadding = motionRevealPadding; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = namedWithSuggestion; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.suggestName = suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.trackValue = trackValue; exports.withViewBox = withViewBox;
|
|
2239
2544
|
//# sourceMappingURL=index.cjs.map
|