@pixerate/editor 0.59.0 → 0.61.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/THIRD_PARTY_NOTICES.md +2 -0
- package/dist/agent/index.cjs +111 -38
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +30 -2
- package/dist/agent/index.d.ts +30 -2
- package/dist/agent/index.js +96 -23
- package/dist/agent/index.js.map +1 -1
- package/dist/agent-caret-BmYhQF7L.d.cts +106 -0
- package/dist/agent-caret-BmYhQF7L.d.ts +106 -0
- package/dist/animation-editor/index.cjs +197 -82
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +136 -3
- package/dist/animation-editor/index.d.ts +136 -3
- package/dist/animation-editor/index.js +163 -48
- package/dist/animation-editor/index.js.map +1 -1
- package/dist/{chunk-LMUDHBWR.js → chunk-4YFMSPBU.js} +2 -2
- package/dist/{chunk-3I6V7PI4.cjs → chunk-7ZSU4MQZ.cjs} +45 -45
- package/dist/{chunk-3I6V7PI4.cjs.map → chunk-7ZSU4MQZ.cjs.map} +1 -1
- package/dist/{chunk-WLVZ235X.js → chunk-OK7T2LHK.js} +229 -2
- package/dist/chunk-OK7T2LHK.js.map +1 -0
- package/dist/{chunk-AHCENCU4.cjs → chunk-T4XWVPJK.cjs} +253 -26
- package/dist/chunk-T4XWVPJK.cjs.map +1 -0
- package/dist/extensions/index.cjs +27 -3
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +2 -1
- package/dist/extensions/index.d.ts +2 -1
- package/dist/extensions/index.js +26 -2
- package/dist/{index-CTCc3m3C.d.ts → index-B16wbOn_.d.ts} +1 -0
- package/dist/{index-BcHyG0Wq.d.cts → index-BAt14aIU.d.cts} +1 -0
- package/dist/index.cjs +32 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +26 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-AHCENCU4.cjs.map +0 -1
- package/dist/chunk-WLVZ235X.js.map +0 -1
- /package/dist/{chunk-LMUDHBWR.js.map → chunk-4YFMSPBU.js.map} +0 -0
|
@@ -63,6 +63,7 @@ var MOTION_COMMAND_TYPES = [
|
|
|
63
63
|
"fade",
|
|
64
64
|
"style",
|
|
65
65
|
"morph",
|
|
66
|
+
"match",
|
|
66
67
|
"follow",
|
|
67
68
|
"pulse",
|
|
68
69
|
"shake",
|
|
@@ -74,6 +75,7 @@ var MOTION_COMMAND_TYPES = [
|
|
|
74
75
|
"wait"
|
|
75
76
|
];
|
|
76
77
|
var MOTION_ENTER_STYLES = ["fade", "pop", "grow", "slide", "draw", "zoom", "rise", "wipe", "iris", "split"];
|
|
78
|
+
var MOTION_BLENDS = ["replace", "add"];
|
|
77
79
|
var MOTION_REPEAT_MODES = ["loop", "mirror", "offset"];
|
|
78
80
|
var MOTION_EXIT_STYLES = ["fade", "shrink", "slide", "undraw", "wipe"];
|
|
79
81
|
var MOTION_IRIS_SHAPES = ["circle", "box"];
|
|
@@ -88,6 +90,7 @@ var MOTION_DEFAULT_DURATIONS = {
|
|
|
88
90
|
fade: 400,
|
|
89
91
|
style: 500,
|
|
90
92
|
morph: 900,
|
|
93
|
+
match: 900,
|
|
91
94
|
follow: 1400,
|
|
92
95
|
pulse: 600,
|
|
93
96
|
shake: 500,
|
|
@@ -132,6 +135,8 @@ var MOTION_ISSUE_CODES = {
|
|
|
132
135
|
"not-a-path": { severity: "error", wording: "A follow path must be a path node, not a group." },
|
|
133
136
|
"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." },
|
|
134
137
|
"unknown-shape": { severity: "error", wording: "A morph names a shape the artwork does not have." },
|
|
138
|
+
"match-self": { severity: "error", wording: "A match turns a group into itself or into a group it holds (or that holds it)." },
|
|
139
|
+
"match-unpaired": { severity: "note", wording: `Parts of a match's "into" group have no partner in the target, so they do not appear.` },
|
|
135
140
|
"unknown-effect": { severity: "error", wording: "An effect command names an effect the node does not have." },
|
|
136
141
|
"unknown-effect-param": { severity: "error", wording: "An effect command names a parameter that is not a number of that effect." },
|
|
137
142
|
"unknown-frame": { severity: "error", wording: "A camera frames a node the artwork does not have." },
|
|
@@ -209,18 +214,19 @@ var COMMAND_KEYS = {
|
|
|
209
214
|
enter: [...BASE_KEYS, "style", "direction", "distance", "scale", "shape", "orientation"],
|
|
210
215
|
exit: [...BASE_KEYS, "style", "direction", "distance"],
|
|
211
216
|
draw: [...BASE_KEYS, "from", "to"],
|
|
212
|
-
move: [...BASE_KEYS, "by", "to"],
|
|
213
|
-
rotate: [...BASE_KEYS, "by", "to"],
|
|
214
|
-
scale: [...BASE_KEYS, "to", "geometric"],
|
|
217
|
+
move: [...BASE_KEYS, "by", "to", "blend"],
|
|
218
|
+
rotate: [...BASE_KEYS, "by", "to", "blend"],
|
|
219
|
+
scale: [...BASE_KEYS, "to", "geometric", "blend"],
|
|
215
220
|
fade: [...BASE_KEYS, "to"],
|
|
216
221
|
style: [...BASE_KEYS, "fill", "stroke", "strokeWidth"],
|
|
217
222
|
morph: [...BASE_KEYS, "into"],
|
|
223
|
+
match: [...BASE_KEYS, "into"],
|
|
218
224
|
follow: [...BASE_KEYS, "path", "rotate", "from", "to"],
|
|
219
|
-
pulse: [...BASE_KEYS, "amount", "count"],
|
|
220
|
-
shake: [...BASE_KEYS, "amount", "count", "axis"],
|
|
221
|
-
teeter: [...BASE_KEYS, "angle", "count"],
|
|
222
|
-
wave: [...BASE_KEYS, "amount", "count"],
|
|
223
|
-
wiggle: [...BASE_KEYS, "amount", "frequency", "octaves", "rotate", "seed"],
|
|
225
|
+
pulse: [...BASE_KEYS, "amount", "count", "blend"],
|
|
226
|
+
shake: [...BASE_KEYS, "amount", "count", "axis", "blend"],
|
|
227
|
+
teeter: [...BASE_KEYS, "angle", "count", "blend"],
|
|
228
|
+
wave: [...BASE_KEYS, "amount", "count", "blend"],
|
|
229
|
+
wiggle: [...BASE_KEYS, "amount", "frequency", "octaves", "rotate", "seed", "blend"],
|
|
224
230
|
"color-pulse": [...BASE_KEYS, "color", "paint", "count"],
|
|
225
231
|
effect: [...BASE_KEYS, "effect", "param", "to"],
|
|
226
232
|
wait: ["type", "duration", "with", "note"]
|
|
@@ -264,6 +270,7 @@ function commandShapeProblems(command2, where) {
|
|
|
264
270
|
if (type === "enter" || type === "exit") p(`"repeat" is not for ${type} (it brings things in or out once); repeat an emphasis or a move instead.`);
|
|
265
271
|
else if (!(Number.isInteger(command2.repeat) && command2.repeat >= 1 && command2.repeat <= 1e3)) p(`"repeat" must be a whole number from 1 to 1000.`);
|
|
266
272
|
}
|
|
273
|
+
if (command2.blend !== void 0 && !MOTION_BLENDS.includes(command2.blend)) p(`"blend" must be "replace" (the change takes over) or "add" (a layer on top).`);
|
|
267
274
|
if (command2.repeatMode !== void 0 && !MOTION_REPEAT_MODES.includes(command2.repeatMode)) p(`"repeatMode" must be one of ${MOTION_REPEAT_MODES.join(", ")}.`);
|
|
268
275
|
if (command2.steps !== void 0 && !(isNum(command2.steps) && command2.steps > 0 && command2.steps <= 120)) p(`"steps" must be frames per second from above 0 to 120 (12 holds each pose for two frames at 24 fps).`);
|
|
269
276
|
switch (type) {
|
|
@@ -309,7 +316,8 @@ function commandShapeProblems(command2, where) {
|
|
|
309
316
|
if (command2.strokeWidth !== void 0 && !(isNum(command2.strokeWidth) && command2.strokeWidth >= 0)) p(`"strokeWidth" must be a number \u2265 0.`);
|
|
310
317
|
break;
|
|
311
318
|
case "morph":
|
|
312
|
-
|
|
319
|
+
case "match":
|
|
320
|
+
if (typeof command2.into !== "string" || !command2.into) p(`"into" must be the id of a ${type === "match" ? "group to become" : "node whose shape to take"}.`);
|
|
313
321
|
break;
|
|
314
322
|
case "follow":
|
|
315
323
|
if (typeof command2.path !== "string" || !command2.path) p(`"path" must be the id of a path node.`);
|
|
@@ -418,6 +426,53 @@ function motionSceneToJson(scene, space = 2) {
|
|
|
418
426
|
var isMotionShot = (shot) => shotShapeProblems(shot, "Shot").length === 0;
|
|
419
427
|
var isMotionCommand = (command2) => commandShapeProblems(command2, "Command").length === 0;
|
|
420
428
|
|
|
429
|
+
// src/animation-editor/match.ts
|
|
430
|
+
var SEPARATOR = /[-_/.:]/;
|
|
431
|
+
function localId(id, groupId) {
|
|
432
|
+
if (groupId && id.includes(groupId)) return id.split(groupId).join("").replace(/^[-_/.:]+|[-_/.:]+$/g, "");
|
|
433
|
+
const parts = id.split(SEPARATOR);
|
|
434
|
+
return _nullishCoalesce(parts[parts.length - 1], () => ( id));
|
|
435
|
+
}
|
|
436
|
+
function matchMotionNodes(from, into) {
|
|
437
|
+
const out = { pairs: [], unpairedFrom: [], unpairedInto: [] };
|
|
438
|
+
const visit = (a, b) => {
|
|
439
|
+
const aKids = a.type === "group" ? a.children : [];
|
|
440
|
+
const bKids = b.type === "group" ? b.children : [];
|
|
441
|
+
if (!aKids.length || !bKids.length) {
|
|
442
|
+
out.pairs.push([a.id, b.id]);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
const left = new Set(aKids);
|
|
446
|
+
const right = new Set(bKids);
|
|
447
|
+
const pair = (key) => {
|
|
448
|
+
for (const x of [...left]) {
|
|
449
|
+
const k = key(x, a);
|
|
450
|
+
if (!k) continue;
|
|
451
|
+
const y = [...right].find((n) => key(n, b) === k);
|
|
452
|
+
if (!y) continue;
|
|
453
|
+
left.delete(x);
|
|
454
|
+
right.delete(y);
|
|
455
|
+
if (x.type === "group" && y.type === "group") visit(x, y);
|
|
456
|
+
else out.pairs.push([x.id, y.id]);
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
pair((n) => _optionalChain([n, 'access', _4 => _4.name, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]) || void 0);
|
|
460
|
+
pair((n, g) => localId(n.id, g.id) || void 0);
|
|
461
|
+
for (const x of [...left]) {
|
|
462
|
+
const y = [...right].find((n) => n.type === x.type);
|
|
463
|
+
if (!y) continue;
|
|
464
|
+
left.delete(x);
|
|
465
|
+
right.delete(y);
|
|
466
|
+
if (x.type === "group" && y.type === "group") visit(x, y);
|
|
467
|
+
else out.pairs.push([x.id, y.id]);
|
|
468
|
+
}
|
|
469
|
+
out.unpairedFrom.push(...[...left].map((n) => n.id));
|
|
470
|
+
out.unpairedInto.push(...[...right].map((n) => n.id));
|
|
471
|
+
};
|
|
472
|
+
visit(from, into);
|
|
473
|
+
return out;
|
|
474
|
+
}
|
|
475
|
+
|
|
421
476
|
// src/animation-editor/compile.ts
|
|
422
477
|
var indexCache = /* @__PURE__ */ new WeakMap();
|
|
423
478
|
function indexMotionNodes(nodes) {
|
|
@@ -497,10 +552,10 @@ function motionRevealClip(entry, reveal) {
|
|
|
497
552
|
}
|
|
498
553
|
}
|
|
499
554
|
function motionRestValue(entry, property, artwork) {
|
|
500
|
-
const node = _optionalChain([entry, 'optionalAccess',
|
|
555
|
+
const node = _optionalChain([entry, 'optionalAccess', _7 => _7.node]);
|
|
501
556
|
switch (property) {
|
|
502
557
|
case "opacity":
|
|
503
|
-
return _nullishCoalesce(_optionalChain([node, 'optionalAccess',
|
|
558
|
+
return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _8 => _8.opacity]), () => ( 1));
|
|
504
559
|
case "x":
|
|
505
560
|
case "y":
|
|
506
561
|
case "rotation":
|
|
@@ -518,11 +573,11 @@ function motionRestValue(entry, property, artwork) {
|
|
|
518
573
|
case "stroke":
|
|
519
574
|
return _nullishCoalesce((node && firstPaint(node, property)), () => ( "transparent"));
|
|
520
575
|
case "strokeWidth": {
|
|
521
|
-
const path = _optionalChain([node, 'optionalAccess',
|
|
522
|
-
return _nullishCoalesce(_optionalChain([path, 'optionalAccess',
|
|
576
|
+
const path = _optionalChain([node, 'optionalAccess', _9 => _9.type]) === "path" ? node : node ? _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node)[0] : void 0;
|
|
577
|
+
return _nullishCoalesce(_optionalChain([path, 'optionalAccess', _10 => _10.strokeWidth]), () => ( 1));
|
|
523
578
|
}
|
|
524
579
|
case "shape":
|
|
525
|
-
return _nullishCoalesce(_optionalChain([node, 'optionalAccess',
|
|
580
|
+
return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _11 => _11.id]), () => ( ""));
|
|
526
581
|
case "clipRect":
|
|
527
582
|
case "clipCircle": {
|
|
528
583
|
const pad = entry && motionRevealPadding(entry);
|
|
@@ -532,7 +587,7 @@ function motionRestValue(entry, property, artwork) {
|
|
|
532
587
|
return [0, 0, artwork.width, artwork.height];
|
|
533
588
|
}
|
|
534
589
|
const [, effectId, param] = property.split(":");
|
|
535
|
-
const effect = _optionalChain([node, 'optionalAccess',
|
|
590
|
+
const effect = _optionalChain([node, 'optionalAccess', _12 => _12.effects, 'optionalAccess', _13 => _13.find, 'call', _14 => _14((e) => e.id === effectId)]);
|
|
536
591
|
const v = effect ? effect.params[param] : void 0;
|
|
537
592
|
return typeof v === "number" ? v : 0;
|
|
538
593
|
}
|
|
@@ -581,13 +636,13 @@ function segmentValue(segment, time, raw = false) {
|
|
|
581
636
|
return typeof segment.from === "string" ? interpolateMotionValue(segment.from, segment.to, Math.min(1, Math.max(0, p))) : interpolateMotionValue(segment.from, segment.to, p);
|
|
582
637
|
}
|
|
583
638
|
function activeSegment(track, time) {
|
|
584
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
639
|
+
if (!_optionalChain([track, 'optionalAccess', _15 => _15.length])) return void 0;
|
|
585
640
|
let found;
|
|
586
641
|
for (const s of track) if (s.start <= time && (!found || s.start >= found.start)) found = s;
|
|
587
642
|
return found;
|
|
588
643
|
}
|
|
589
644
|
function trackValue(track, time, raw = false) {
|
|
590
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
645
|
+
if (!_optionalChain([track, 'optionalAccess', _16 => _16.length])) return void 0;
|
|
591
646
|
const s = activeSegment(track, time);
|
|
592
647
|
if (s) return segmentValue(s, time, raw);
|
|
593
648
|
let first = track[0];
|
|
@@ -595,6 +650,20 @@ function trackValue(track, time, raw = false) {
|
|
|
595
650
|
return first.from;
|
|
596
651
|
}
|
|
597
652
|
var motionTrackKey = (node, property) => `${node}\0${property}`;
|
|
653
|
+
var motionAddTrackKey = (node, property) => `${node}\0${property}\0add`;
|
|
654
|
+
var MOTION_ADDITIVE_PROPERTIES = ["x", "y", "rotation", "scaleX", "scaleY"];
|
|
655
|
+
function withMotionLayers(timeline, node, property, base, time, raw = false) {
|
|
656
|
+
const layers = timeline.tracks.get(motionAddTrackKey(node, property));
|
|
657
|
+
if (!layers) return base;
|
|
658
|
+
const scale = property === "scaleX" || property === "scaleY";
|
|
659
|
+
let v = base;
|
|
660
|
+
for (const layer of layers) {
|
|
661
|
+
if (layer.start > time) continue;
|
|
662
|
+
const x = Number(segmentValue(layer, time, raw));
|
|
663
|
+
if (Number.isFinite(x)) v = scale ? v * x : v + x;
|
|
664
|
+
}
|
|
665
|
+
return v;
|
|
666
|
+
}
|
|
598
667
|
function fitMotionRect(rect, aspect) {
|
|
599
668
|
const cx = rect.x + rect.width / 2;
|
|
600
669
|
const cy = rect.y + rect.height / 2;
|
|
@@ -606,7 +675,7 @@ function fitMotionRect(rect, aspect) {
|
|
|
606
675
|
function resolveMotionCamera(camera, scene) {
|
|
607
676
|
if ("frame" in camera && typeof camera.frame === "string") {
|
|
608
677
|
const entry = indexMotionNodes(scene.artwork.nodes).get(camera.frame);
|
|
609
|
-
if (!_optionalChain([entry, 'optionalAccess',
|
|
678
|
+
if (!_optionalChain([entry, 'optionalAccess', _17 => _17.bounds])) return null;
|
|
610
679
|
const pad = _nullishCoalesce(camera.padding, () => ( 24));
|
|
611
680
|
const b = entry.bounds;
|
|
612
681
|
const rect = { x: b.x - pad, y: b.y - pad, width: Math.max(1, b.width + pad * 2), height: Math.max(1, b.height + pad * 2) };
|
|
@@ -698,7 +767,7 @@ function compileMotionScene(scene) {
|
|
|
698
767
|
return _nullishCoalesce(v, () => ( motionRestValue(nodes.get(node), property, artwork)));
|
|
699
768
|
};
|
|
700
769
|
const push = (segment) => {
|
|
701
|
-
const key = motionTrackKey(segment.node, segment.property);
|
|
770
|
+
const key = segment.blend === "add" ? motionAddTrackKey(segment.node, segment.property) : motionTrackKey(segment.node, segment.property);
|
|
702
771
|
let track = tracks.get(key);
|
|
703
772
|
if (!track) tracks.set(key, track = []);
|
|
704
773
|
track.push(segment);
|
|
@@ -767,7 +836,7 @@ function compileMotionScene(scene) {
|
|
|
767
836
|
const style = _nullishCoalesce(command2.style, () => ( "fade"));
|
|
768
837
|
const opacity = rest("opacity");
|
|
769
838
|
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;
|
|
770
|
-
for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess',
|
|
839
|
+
for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _18 => _18.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
|
|
771
840
|
if (reveal) {
|
|
772
841
|
seg("opacity", opacity, "linear", start, start);
|
|
773
842
|
seg(reveal.property, reveal.to, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: reveal.from });
|
|
@@ -829,26 +898,34 @@ function compileMotionScene(scene) {
|
|
|
829
898
|
}
|
|
830
899
|
case "move": {
|
|
831
900
|
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
832
|
-
let dx = _nullishCoalesce(_optionalChain([command2, 'access',
|
|
833
|
-
let dy = _nullishCoalesce(_optionalChain([command2, 'access',
|
|
901
|
+
let dx = _nullishCoalesce(_optionalChain([command2, 'access', _19 => _19.by, 'optionalAccess', _20 => _20.x]), () => ( 0));
|
|
902
|
+
let dy = _nullishCoalesce(_optionalChain([command2, 'access', _21 => _21.by, 'optionalAccess', _22 => _22.y]), () => ( 0));
|
|
834
903
|
if (command2.to) {
|
|
835
904
|
const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
|
|
836
905
|
const target = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, command2.to);
|
|
837
906
|
dx = target.x - (entry.center.x + num("x"));
|
|
838
907
|
dy = target.y - (entry.center.y + num("y"));
|
|
839
908
|
}
|
|
840
|
-
|
|
841
|
-
|
|
909
|
+
if (command2.blend === "add") {
|
|
910
|
+
seg("x", dx, e, start, end, { from: 0, blend: "add" });
|
|
911
|
+
seg("y", dy, e, start, end, { from: 0, blend: "add" });
|
|
912
|
+
} else {
|
|
913
|
+
seg("x", num("x") + dx, e);
|
|
914
|
+
seg("y", num("y") + dy, e);
|
|
915
|
+
}
|
|
842
916
|
break;
|
|
843
917
|
}
|
|
844
|
-
case "rotate":
|
|
845
|
-
|
|
918
|
+
case "rotate": {
|
|
919
|
+
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
920
|
+
if (command2.blend === "add") seg("rotation", command2.to !== void 0 ? command2.to - num("rotation") : _nullishCoalesce(command2.by, () => ( 0)), e, start, end, { from: 0, blend: "add" });
|
|
921
|
+
else seg("rotation", _nullishCoalesce(command2.to, () => ( num("rotation") + (_nullishCoalesce(command2.by, () => ( 0))))), e);
|
|
846
922
|
break;
|
|
923
|
+
}
|
|
847
924
|
case "scale": {
|
|
848
925
|
const to = typeof command2.to === "number" ? { x: command2.to, y: command2.to } : command2.to;
|
|
849
|
-
const
|
|
850
|
-
seg("scaleX", to.x, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end,
|
|
851
|
-
seg("scaleY", to.y, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end,
|
|
926
|
+
const extra = { ...command2.geometric ? { geometric: true } : {}, ...command2.blend === "add" ? { from: 1, blend: "add" } : {} };
|
|
927
|
+
seg("scaleX", to.x, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, extra);
|
|
928
|
+
seg("scaleY", to.y, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, extra);
|
|
852
929
|
break;
|
|
853
930
|
}
|
|
854
931
|
case "fade":
|
|
@@ -862,34 +939,44 @@ function compileMotionScene(scene) {
|
|
|
862
939
|
case "morph":
|
|
863
940
|
seg("shape", command2.into, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
|
|
864
941
|
break;
|
|
942
|
+
case "match": {
|
|
943
|
+
const into = nodes.get(command2.into);
|
|
944
|
+
if (!into || command2.into === node) break;
|
|
945
|
+
const match = matchMotionNodes(entry.node, into.node);
|
|
946
|
+
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
947
|
+
for (const [a, b] of match.pairs) push({ node: a, property: "shape", start, end, from: valueAt(a, "shape", start), to: b, ease: e, ...where });
|
|
948
|
+
for (const a of match.unpairedFrom) push({ node: a, property: "opacity", start, end, from: valueAt(a, "opacity", start), to: 0, ease: e, ...where });
|
|
949
|
+
break;
|
|
950
|
+
}
|
|
865
951
|
case "follow":
|
|
866
952
|
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)) });
|
|
867
953
|
break;
|
|
868
954
|
// Emphasis: a change toward a peak that a behaviour swings round (as Flair's primitives do).
|
|
869
|
-
case "pulse":
|
|
870
|
-
|
|
871
|
-
const k = 1 + (_nullishCoalesce(command2.amount, () => ( 0.15)));
|
|
872
|
-
seg("scaleX", num("scaleX") * k, _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior });
|
|
873
|
-
seg("scaleY", num("scaleY") * k, _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior });
|
|
874
|
-
break;
|
|
875
|
-
}
|
|
876
|
-
case "shake": {
|
|
877
|
-
const p = command2.axis === "vertical" ? "y" : "x";
|
|
878
|
-
seg(p, num(p) + (_nullishCoalesce(command2.amount, () => ( 8))), _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 3)), decay: 1 } });
|
|
879
|
-
break;
|
|
880
|
-
}
|
|
955
|
+
case "pulse":
|
|
956
|
+
case "shake":
|
|
881
957
|
case "teeter":
|
|
882
|
-
seg("rotation", num("rotation") + (_nullishCoalesce(command2.angle, () => ( 8))), _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 3)), decay: 1 } });
|
|
883
|
-
break;
|
|
884
958
|
case "wave":
|
|
885
|
-
seg("y", num("y") - (_nullishCoalesce(command2.amount, () => ( 6))), _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 2)) } });
|
|
886
|
-
break;
|
|
887
959
|
case "wiggle": {
|
|
888
|
-
const
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
960
|
+
const add = (_nullishCoalesce(command2.blend, () => ( "add"))) === "add";
|
|
961
|
+
const swing = (p, by, extra) => {
|
|
962
|
+
const scale = p === "scaleX" || p === "scaleY";
|
|
963
|
+
if (add) seg(p, by, _nullishCoalesce(ease, () => ( "linear")), start, end, { from: scale ? 1 : 0, blend: "add", ...extra });
|
|
964
|
+
else seg(p, scale ? num(p) * by : num(p) + by, _nullishCoalesce(ease, () => ( "linear")), start, end, extra);
|
|
965
|
+
};
|
|
966
|
+
if (command2.type === "pulse") {
|
|
967
|
+
const behavior = { type: "pulse", count: _nullishCoalesce(command2.count, () => ( 1)) };
|
|
968
|
+
swing("scaleX", 1 + (_nullishCoalesce(command2.amount, () => ( 0.15))), { behavior });
|
|
969
|
+
swing("scaleY", 1 + (_nullishCoalesce(command2.amount, () => ( 0.15))), { behavior });
|
|
970
|
+
} else if (command2.type === "shake") swing(command2.axis === "vertical" ? "y" : "x", _nullishCoalesce(command2.amount, () => ( 8)), { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 3)), decay: 1 } });
|
|
971
|
+
else if (command2.type === "teeter") swing("rotation", _nullishCoalesce(command2.angle, () => ( 8)), { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 3)), decay: 1 } });
|
|
972
|
+
else if (command2.type === "wave") swing("y", -(_nullishCoalesce(command2.amount, () => ( 6))), { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 2)) } });
|
|
973
|
+
else {
|
|
974
|
+
const behavior = { type: "wriggle", frequency: _nullishCoalesce(command2.frequency, () => ( 3)), octaves: _nullishCoalesce(command2.octaves, () => ( 2)), seed: command2.seed || _chunkZCNLBRT6cjs.motionSeedFromId.call(void 0, node) };
|
|
975
|
+
const amount = _nullishCoalesce(command2.amount, () => ( 6));
|
|
976
|
+
swing("x", amount, { behavior, index: 0 });
|
|
977
|
+
swing("y", amount, { behavior, index: 1 });
|
|
978
|
+
if (command2.rotate) swing("rotation", command2.rotate, { behavior, index: 2 });
|
|
979
|
+
}
|
|
893
980
|
break;
|
|
894
981
|
}
|
|
895
982
|
case "color-pulse":
|
|
@@ -916,7 +1003,7 @@ var MOTION_DRAW_EFFECT_ID = "~draw";
|
|
|
916
1003
|
var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
|
|
917
1004
|
var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
|
|
918
1005
|
function applyMotionControlValues(scene, values) {
|
|
919
|
-
if (!values || !_optionalChain([scene, 'access',
|
|
1006
|
+
if (!values || !_optionalChain([scene, 'access', _23 => _23.controls, 'optionalAccess', _24 => _24.length])) return scene;
|
|
920
1007
|
const map = /* @__PURE__ */ new Map();
|
|
921
1008
|
for (const control of scene.controls) {
|
|
922
1009
|
const value = values[control.name];
|
|
@@ -962,7 +1049,7 @@ function shapeIn(entry, shape) {
|
|
|
962
1049
|
}
|
|
963
1050
|
function shapeAt(entry, timeline, nodes, time) {
|
|
964
1051
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
|
|
965
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
1052
|
+
if (!_optionalChain([track, 'optionalAccess', _25 => _25.length])) return null;
|
|
966
1053
|
const s = activeSegment(track, time);
|
|
967
1054
|
const fromId = String(s ? s.from : track[0].from);
|
|
968
1055
|
if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
|
|
@@ -985,8 +1072,8 @@ function motionFollowRoute(entry, path) {
|
|
|
985
1072
|
}
|
|
986
1073
|
function followAt(entry, timeline, nodes, time) {
|
|
987
1074
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "follow"));
|
|
988
|
-
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess',
|
|
989
|
-
if (!_optionalChain([s, 'optionalAccess',
|
|
1075
|
+
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _26 => _26[0]])));
|
|
1076
|
+
if (!_optionalChain([s, 'optionalAccess', _27 => _27.path])) return null;
|
|
990
1077
|
const route = motionFollowRoute(entry, nodes.get(s.path));
|
|
991
1078
|
const progress = Number(trackValue(track, time));
|
|
992
1079
|
if (!route || !(progress >= 0)) return null;
|
|
@@ -1001,9 +1088,9 @@ function followAt(entry, timeline, nodes, time) {
|
|
|
1001
1088
|
function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry.node]), raw = false, follow = true) {
|
|
1002
1089
|
const read = (p, rest) => {
|
|
1003
1090
|
const v = trackValue(timeline.tracks.get(motionTrackKey(entry.node.id, p)), time, raw);
|
|
1004
|
-
return typeof v === "number" ? v : rest;
|
|
1091
|
+
return withMotionLayers(timeline, entry.node.id, p, typeof v === "number" ? v : rest, time, raw);
|
|
1005
1092
|
};
|
|
1006
|
-
if (!TRANSFORM_PROPS.some((p) => (follow || p !== "follow") && timeline.tracks.has(motionTrackKey(entry.node.id, p)))) return null;
|
|
1093
|
+
if (!TRANSFORM_PROPS.some((p) => (follow || p !== "follow") && (timeline.tracks.has(motionTrackKey(entry.node.id, p)) || timeline.tracks.has(motionAddTrackKey(entry.node.id, p))))) return null;
|
|
1007
1094
|
const dx = read("x", 0);
|
|
1008
1095
|
const dy = read("y", 0);
|
|
1009
1096
|
const rotation = read("rotation", 0);
|
|
@@ -1046,7 +1133,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1046
1133
|
if (out.visible === void 0) delete out.visible;
|
|
1047
1134
|
}
|
|
1048
1135
|
const effectTracks = [...timeline.tracks.keys()].filter((k) => k.startsWith(`${id}\0effect:`));
|
|
1049
|
-
if (effectTracks.length && _optionalChain([out, 'access',
|
|
1136
|
+
if (effectTracks.length && _optionalChain([out, 'access', _28 => _28.effects, 'optionalAccess', _29 => _29.length])) {
|
|
1050
1137
|
out = {
|
|
1051
1138
|
...out,
|
|
1052
1139
|
effects: out.effects.map((effect) => {
|
|
@@ -1124,7 +1211,7 @@ function withViewBox(svg, box) {
|
|
|
1124
1211
|
// src/animation-editor/check.ts
|
|
1125
1212
|
var MOTION_MIN_CHANGE_MS = 120;
|
|
1126
1213
|
var NUMERIC_PARAMS = (node, effectId) => {
|
|
1127
|
-
const effect = _optionalChain([node, 'access',
|
|
1214
|
+
const effect = _optionalChain([node, 'access', _30 => _30.effects, 'optionalAccess', _31 => _31.find, 'call', _32 => _32((e) => e.id === effectId)]);
|
|
1128
1215
|
if (!effect) return null;
|
|
1129
1216
|
return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
|
|
1130
1217
|
};
|
|
@@ -1201,6 +1288,19 @@ function checkMotionScene(scene) {
|
|
|
1201
1288
|
if (command2.type === "follow" && known(command2.path, "unknown-path", "path", where) && nodes.get(command2.path).node.type !== "path")
|
|
1202
1289
|
issues.push(motionIssue("not-a-path", `"${command2.path}" is a group; follow a single path node.`, { ...where, ids: [command2.path] }));
|
|
1203
1290
|
if (command2.type === "morph") known(command2.into, "unknown-shape", "shape", where);
|
|
1291
|
+
if (command2.type === "match" && known(command2.into, "unknown-shape", "group", where)) {
|
|
1292
|
+
const into = nodes.get(command2.into);
|
|
1293
|
+
for (const id of targets) {
|
|
1294
|
+
const entry = nodes.get(id);
|
|
1295
|
+
if (id === command2.into || into.ancestors.includes(id) || entry.ancestors.includes(command2.into)) {
|
|
1296
|
+
issues.push(motionIssue("match-self", `"${id}" cannot match "${command2.into}": one is the other or holds it. Match two separate groups (the second usually hidden).`, { ...where, ids: [id, command2.into] }));
|
|
1297
|
+
continue;
|
|
1298
|
+
}
|
|
1299
|
+
const m = matchMotionNodes(entry.node, into.node);
|
|
1300
|
+
if (m.unpairedInto.length)
|
|
1301
|
+
issues.push(motionIssue("match-unpaired", `${m.unpairedInto.map((x) => `"${x}"`).join(", ")} in "${command2.into}" ${m.unpairedInto.length > 1 ? "have" : "has"} no partner in "${id}", so ${m.unpairedInto.length > 1 ? "they do" : "it does"} not appear; add a part with the same name or id to "${id}" (it can start hidden or tiny).`, { ...where, ids: m.unpairedInto }));
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1204
1304
|
const style = command2.type === "enter" || command2.type === "exit" ? command2.style : void 0;
|
|
1205
1305
|
if (style === "wipe" || style === "iris" || style === "split") {
|
|
1206
1306
|
for (const id of targets)
|
|
@@ -1261,6 +1361,7 @@ function checkMotionScene(scene) {
|
|
|
1261
1361
|
});
|
|
1262
1362
|
});
|
|
1263
1363
|
for (const [key, track] of timeline.tracks) {
|
|
1364
|
+
if (key.endsWith("\0add")) continue;
|
|
1264
1365
|
for (let i = 1; i < track.length; i++) {
|
|
1265
1366
|
const a = track[i - 1];
|
|
1266
1367
|
const b = track[i];
|
|
@@ -1285,7 +1386,7 @@ function checkMotionScene(scene) {
|
|
|
1285
1386
|
const cam = frame.camera;
|
|
1286
1387
|
const docIndex = indexMotionNodes(frame.document.nodes);
|
|
1287
1388
|
for (const id of command2.targets) {
|
|
1288
|
-
const b = _optionalChain([docIndex, 'access',
|
|
1389
|
+
const b = _optionalChain([docIndex, 'access', _33 => _33.get, 'call', _34 => _34(id), 'optionalAccess', _35 => _35.bounds]);
|
|
1289
1390
|
if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
|
|
1290
1391
|
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;
|
|
1291
1392
|
if (outside) {
|
|
@@ -1467,9 +1568,9 @@ function applyMotionEdits(scene, edits) {
|
|
|
1467
1568
|
let next = scene;
|
|
1468
1569
|
for (let i = 0; i < list.length; i++) {
|
|
1469
1570
|
const edit = list[i];
|
|
1470
|
-
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess',
|
|
1571
|
+
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _36 => _36.op])}): ` : "";
|
|
1471
1572
|
if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
|
|
1472
|
-
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess',
|
|
1573
|
+
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _37 => _37.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
|
|
1473
1574
|
try {
|
|
1474
1575
|
next = applyOne(next, edit);
|
|
1475
1576
|
} catch (error) {
|
|
@@ -1601,7 +1702,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1601
1702
|
const wrapper = freshId(`${id}--follow`);
|
|
1602
1703
|
const centre = freshId(`${id}--follow-centre`);
|
|
1603
1704
|
const c = entry.center;
|
|
1604
|
-
const at = _optionalChain([motionNodeOffset, 'call',
|
|
1705
|
+
const at = _optionalChain([motionNodeOffset, 'call', _38 => _38(entry, timeline, 0, nodes), 'optionalAccess', _39 => _39.follow]);
|
|
1605
1706
|
const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
|
|
1606
1707
|
(wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
|
|
1607
1708
|
follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
|
|
@@ -1610,7 +1711,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1610
1711
|
if (timeline.tracks.has(motionTrackKey(id, "opacity")))
|
|
1611
1712
|
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))))) });
|
|
1612
1713
|
const followed = follows.some((x) => x.id === id);
|
|
1613
|
-
const transformSegments = TRANSFORM_PROPS2.flatMap((p) => followed && p === "follow" ? [] : track(id, p));
|
|
1714
|
+
const transformSegments = TRANSFORM_PROPS2.flatMap((p) => followed && p === "follow" ? [] : [...track(id, p), ..._nullishCoalesce(timeline.tracks.get(motionAddTrackKey(id, p)), () => ( []))]);
|
|
1614
1715
|
if (transformSegments.length) {
|
|
1615
1716
|
const base = node.transform ? ` matrix(${node.transform.map(f).join(" ")})` : "";
|
|
1616
1717
|
const c = entry.center;
|
|
@@ -1661,7 +1762,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1661
1762
|
exact: () => false,
|
|
1662
1763
|
value: (t) => {
|
|
1663
1764
|
const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
|
|
1664
|
-
const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call',
|
|
1765
|
+
const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _40 => _40(frame.document.nodes), 'access', _41 => _41.get, 'call', _42 => _42(id), 'optionalAccess', _43 => _43.node]));
|
|
1665
1766
|
if (!now || now.type !== "path") return "";
|
|
1666
1767
|
const bezier = _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, now, _chunkYJLCBA7Vcjs.IDENTITY_MATRIX, { effects: false }), inverse);
|
|
1667
1768
|
return _chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
|
|
@@ -1682,8 +1783,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1682
1783
|
...delay > 0 ? { delay: round2(delay) } : {},
|
|
1683
1784
|
ms: round2(ms),
|
|
1684
1785
|
ease: written,
|
|
1685
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
1686
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
1786
|
+
..._optionalChain([segment, 'optionalAccess', _44 => _44.behavior]) ? { behavior: segment.behavior } : {},
|
|
1787
|
+
..._optionalChain([segment, 'optionalAccess', _45 => _45.steps]) ? { strobe: segment.steps } : {}
|
|
1687
1788
|
};
|
|
1688
1789
|
if (channel.kind === "view") animate.push({ ...base, view: to });
|
|
1689
1790
|
else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
|
|
@@ -1756,7 +1857,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1756
1857
|
if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
|
|
1757
1858
|
const lastChange = animate.reduce((m, a) => Math.max(m, (_nullishCoalesce(a.delay, () => ( 0))) + (_nullishCoalesce(a.ms, () => ( 0)))), 0);
|
|
1758
1859
|
let motion = { svg, animate };
|
|
1759
|
-
if (_optionalChain([scene, 'access',
|
|
1860
|
+
if (_optionalChain([scene, 'access', _46 => _46.controls, 'optionalAccess', _47 => _47.length])) {
|
|
1760
1861
|
const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
|
|
1761
1862
|
const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
|
|
1762
1863
|
svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
|
|
@@ -1778,7 +1879,7 @@ function toFlairVectorEffect(scene, options = {}) {
|
|
|
1778
1879
|
tags: _nullishCoalesce(options.tags, () => ( [])),
|
|
1779
1880
|
motion: out.motion,
|
|
1780
1881
|
hold: out.hold,
|
|
1781
|
-
..._optionalChain([scene, 'access',
|
|
1882
|
+
..._optionalChain([scene, 'access', _48 => _48.presets, 'optionalAccess', _49 => _49.length]) ? { presets: scene.presets } : {},
|
|
1782
1883
|
...options.trigger ? { trigger: options.trigger } : {}
|
|
1783
1884
|
};
|
|
1784
1885
|
}
|
|
@@ -1821,7 +1922,7 @@ function resolvePlaceholders(motion, notes) {
|
|
|
1821
1922
|
const filled = text.replace(PLACEHOLDER, (_, name) => {
|
|
1822
1923
|
const d = declared.get(name);
|
|
1823
1924
|
if (!d) unknown.add(name);
|
|
1824
|
-
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess',
|
|
1925
|
+
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _50 => _50.value]), () => ( ""))).replace(/"/g, '\\"');
|
|
1825
1926
|
});
|
|
1826
1927
|
for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
|
|
1827
1928
|
return { motion: JSON.parse(filled), controls };
|
|
@@ -1875,7 +1976,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
1875
1976
|
if (anim.along) {
|
|
1876
1977
|
const path = nodes.get(anim.along);
|
|
1877
1978
|
if (!path || path.node.type !== "path") notes.push(`${where} follows "${anim.along}", which is not a path in the artwork; the follow was skipped.`);
|
|
1878
|
-
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access',
|
|
1979
|
+
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _51 => _51.at, 'optionalAccess', _52 => _52[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _53 => _53.at, 'optionalAccess', _54 => _54[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
1879
1980
|
}
|
|
1880
1981
|
for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
|
|
1881
1982
|
if (attr === "opacity") {
|
|
@@ -1886,7 +1987,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
1886
1987
|
out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
|
|
1887
1988
|
} else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
1888
1989
|
} else if (attr === "fill" || attr === "stroke") {
|
|
1889
|
-
if (_optionalChain([behavior, 'optionalAccess',
|
|
1990
|
+
if (_optionalChain([behavior, 'optionalAccess', _55 => _55.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
|
|
1890
1991
|
else {
|
|
1891
1992
|
if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
|
|
1892
1993
|
out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
@@ -2053,7 +2154,7 @@ var AnimationEditorController = (_class = class {
|
|
|
2053
2154
|
time: p.time,
|
|
2054
2155
|
playing: p.playing,
|
|
2055
2156
|
loop: p.loop,
|
|
2056
|
-
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call',
|
|
2157
|
+
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _56 => _56(timeline, p.time), 'optionalAccess', _57 => _57.id]), () => ( null)),
|
|
2057
2158
|
selection: this.selection,
|
|
2058
2159
|
readOnly: this.readOnly,
|
|
2059
2160
|
error: this.error,
|
|
@@ -2092,7 +2193,7 @@ var AnimationEditorController = (_class = class {
|
|
|
2092
2193
|
this.applying = false;
|
|
2093
2194
|
}
|
|
2094
2195
|
this.notify();
|
|
2095
|
-
_optionalChain([this, 'access',
|
|
2196
|
+
_optionalChain([this, 'access', _58 => _58.onChange, 'optionalCall', _59 => _59(scene)]);
|
|
2096
2197
|
}
|
|
2097
2198
|
commit(label, next) {
|
|
2098
2199
|
const before = this.scene;
|
|
@@ -2269,6 +2370,11 @@ var BASE = {
|
|
|
2269
2370
|
repeatMode: { type: "string", enum: [...MOTION_REPEAT_MODES], description: "loop (default) restarts each cycle, mirror plays every other one backwards, offset carries on from where the last ended (rotate by 90 with repeat 4 makes a full turn)." },
|
|
2270
2371
|
steps: { type: "number", exclusiveMinimum: 0, maximum: 120, description: `Stepped time: hold on a grid of this many frames per second (12 = "on twos"). Default: the scene's steps, else smooth.` }
|
|
2271
2372
|
};
|
|
2373
|
+
var BLEND = (fallback) => ({
|
|
2374
|
+
type: "string",
|
|
2375
|
+
enum: [...MOTION_BLENDS],
|
|
2376
|
+
description: `"add" makes it a layer over the pose that stacks with other changes (a shake on a slide); "replace" makes it a change the next one takes over from (default ${fallback}).`
|
|
2377
|
+
});
|
|
2272
2378
|
var command = (type, description, extra = {}, required = []) => object({ type: { const: type, description }, ...BASE, ...extra }, ["type", "targets", ...required], description);
|
|
2273
2379
|
var MOTION_COMMAND_SCHEMA = {
|
|
2274
2380
|
description: `A command (one of ${MOTION_COMMAND_TYPES.join(", ")}). Commands in a shot play one after another unless "with": "previous".`,
|
|
@@ -2291,15 +2397,16 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
2291
2397
|
distance: { type: "number", description: "For slide: document units (default 40)." }
|
|
2292
2398
|
}),
|
|
2293
2399
|
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).") }),
|
|
2294
|
-
command("move", "Moves targets by an offset or so their centre lands on a point.", { by: POINT("Offset in document units."), to: POINT("Point (document coordinates) for the centre.") }),
|
|
2295
|
-
command("rotate", "Turns targets about their centre (degrees, clockwise).", { by: { type: "number", description: "Degrees to turn by." }, to: { type: "number", description: "Angle to turn to, in degrees from rest." } }),
|
|
2296
|
-
command("scale", "Scales targets about their centre (1 = rest size).", { to: { description: "A factor, or { x, y } factors.", anyOf: [{ type: "number" }, POINT("Factors per axis.")] }, geometric: { type: "boolean", description: "Grow by a steady factor, which reads as an even zoom (default false)." } }, ["to"]),
|
|
2400
|
+
command("move", "Moves targets by an offset or so their centre lands on a point.", { blend: BLEND("replace"), by: POINT("Offset in document units."), to: POINT("Point (document coordinates) for the centre.") }),
|
|
2401
|
+
command("rotate", "Turns targets about their centre (degrees, clockwise).", { blend: BLEND("replace"), by: { type: "number", description: "Degrees to turn by." }, to: { type: "number", description: "Angle to turn to, in degrees from rest." } }),
|
|
2402
|
+
command("scale", "Scales targets about their centre (1 = rest size).", { blend: BLEND("replace"), to: { description: "A factor, or { x, y } factors.", anyOf: [{ type: "number" }, POINT("Factors per axis.")] }, geometric: { type: "boolean", description: "Grow by a steady factor, which reads as an even zoom (default false)." } }, ["to"]),
|
|
2297
2403
|
command("fade", "Changes opacity.", { to: FRACTION("Opacity at the end (0\u20131).") }, ["to"]),
|
|
2298
2404
|
command("style", "Blends solid fill / stroke colours (in OKLab) and stroke width. On a group it changes every path in it.", {
|
|
2299
2405
|
fill: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
|
|
2300
2406
|
stroke: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
|
|
2301
2407
|
strokeWidth: { type: "number", minimum: 0, description: "Document units." }
|
|
2302
2408
|
}),
|
|
2409
|
+
command("match", `Smart Animate: tweens a group into another group (usually hidden), part by part. Parts pair by name, then by id with the group ids taken out (card-a-title \u2194 card-b-title), then by kind in order; each takes its partner's shape, paint and place. Unpaired parts fade out; parts of "into" with no partner do not appear (check_animation lists them).`, { into: { type: "string", minLength: 1, description: "Id of the group to become." } }, ["into"]),
|
|
2303
2410
|
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"]),
|
|
2304
2411
|
command("follow", "Moves targets along a path node, centre on the path.", {
|
|
2305
2412
|
path: { type: "string", minLength: 1, description: "Id of a path node (it can be hidden)." },
|
|
@@ -2307,15 +2414,17 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
2307
2414
|
from: FRACTION("Where to start along the path (default 0)."),
|
|
2308
2415
|
to: FRACTION("Where to end along the path (default 1).")
|
|
2309
2416
|
}, ["path"]),
|
|
2310
|
-
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)." } }),
|
|
2417
|
+
command("pulse", "Scales up and back to draw the eye.", { blend: BLEND("add"), amount: { type: "number", description: "Extra scale at the peak (default 0.15)." }, count: { type: "integer", minimum: 1, description: "Pulses (default 1)." } }),
|
|
2311
2418
|
command("shake", "Shakes side to side (or up and down), settling.", {
|
|
2419
|
+
blend: BLEND("add"),
|
|
2312
2420
|
amount: { type: "number", description: "Document units (default 8)." },
|
|
2313
2421
|
count: { type: "integer", minimum: 1, description: "Shakes (default 3)." },
|
|
2314
2422
|
axis: { type: "string", enum: ["horizontal", "vertical"], description: "Default horizontal." }
|
|
2315
2423
|
}),
|
|
2316
|
-
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)." } }),
|
|
2317
|
-
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)." } }),
|
|
2424
|
+
command("teeter", "Rocks about the centre either way, settling.", { blend: BLEND("add"), angle: { type: "number", description: "Degrees either way (default 8)." }, count: { type: "integer", minimum: 1, description: "Rocks (default 3)." } }),
|
|
2425
|
+
command("wave", "Bobs up and down without settling, like something floating (default 1000 ms).", { blend: BLEND("add"), amount: { type: "number", description: "Height in document units (default 6)." }, count: { type: "integer", minimum: 1, description: "Bobs (default 2)." } }),
|
|
2318
2426
|
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.", {
|
|
2427
|
+
blend: BLEND("add"),
|
|
2319
2428
|
amount: { type: "number", description: "Up to about this far, in document units (default 6)." },
|
|
2320
2429
|
frequency: { type: "number", exclusiveMinimum: 0, description: "Wanders per second, in Hz (default 3)." },
|
|
2321
2430
|
octaves: { type: "integer", minimum: 1, maximum: 8, description: "Layers of finer detail (default 2)." },
|
|
@@ -2671,7 +2780,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
2671
2780
|
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"]),
|
|
2672
2781
|
annotations: { title: "Add commands to a shot", ...WRITE },
|
|
2673
2782
|
handler: ({ shot, commands, at }) => {
|
|
2674
|
-
const before = _nullishCoalesce(_optionalChain([scene, 'call',
|
|
2783
|
+
const before = _nullishCoalesce(_optionalChain([scene, 'call', _60 => _60(), 'access', _61 => _61.shots, 'access', _62 => _62.find, 'call', _63 => _63((s) => s.id === shot), 'optionalAccess', _64 => _64.run, 'access', _65 => _65.length]), () => ( 0));
|
|
2675
2784
|
const first = _nullishCoalesce(at, () => ( before));
|
|
2676
2785
|
return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
|
|
2677
2786
|
const shots = describeMotionShots(s);
|
|
@@ -2819,8 +2928,9 @@ Commands
|
|
|
2819
2928
|
- 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.
|
|
2820
2929
|
- 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.
|
|
2821
2930
|
- enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting "scale".
|
|
2822
|
-
- 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).
|
|
2931
|
+
- morph turns a shape into another node's shape (keep the target hidden); match does the same for a whole group, part by part (Smart Animate: draw the end state as a second, hidden group whose parts share names with the first); follow moves along a path node (with "rotate", moves made meanwhile turn with the path).
|
|
2823
2932
|
- 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).
|
|
2933
|
+
- Emphasis stacks on other motion: a shake during a slide shakes as it slides. Give move, rotate or scale "blend": "add" to stack them too (what they add stays); "blend": "replace" makes a change take over instead.
|
|
2824
2934
|
- Any command but enter and exit can "repeat" (loop, mirror back and forth, or offset to carry on: rotate by 90, repeat 4 is a full turn); "duration" is one cycle.
|
|
2825
2935
|
- Springs ("spring-gentle", "spring-quick", "spring-bouncy", "spring-slow" or { "type": "spring", \u2026 }) feel physical; leave "duration" out and the spring sets it.
|
|
2826
2936
|
- "steps": 12 (on a command, or for the whole scene with set_animation_settings) holds poses "on twos" for a hand-drawn look. "geometric": true on scale or a camera zooms at an even rate.
|
|
@@ -2913,5 +3023,10 @@ Keep motion purposeful: one thing moving at a time reads best, ease-out for arri
|
|
|
2913
3023
|
|
|
2914
3024
|
|
|
2915
3025
|
|
|
2916
|
-
|
|
3026
|
+
|
|
3027
|
+
|
|
3028
|
+
|
|
3029
|
+
|
|
3030
|
+
|
|
3031
|
+
exports.ANIMATION_EDITOR_AGENT_INSTRUCTIONS = ANIMATION_EDITOR_AGENT_INSTRUCTIONS; exports.AnimationEditorController = AnimationEditorController; exports.FLAIR_EASES = FLAIR_EASES; exports.FLAIR_EXPORT_VERSION = FLAIR_EXPORT_VERSION; exports.MOTION_ADDITIVE_PROPERTIES = MOTION_ADDITIVE_PROPERTIES; exports.MOTION_BLENDS = MOTION_BLENDS; 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_REPEAT_MODES = MOTION_REPEAT_MODES; 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.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionClipAttrs = motionClipAttrs; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCycleDuration = motionCycleDuration; 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.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
|
|
2917
3032
|
//# sourceMappingURL=index.cjs.map
|