@pixerate/editor 0.67.1 → 0.69.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-editor/index.cjs +290 -46
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +102 -3
- package/dist/animation-editor/index.d.ts +102 -3
- package/dist/animation-editor/index.js +248 -4
- package/dist/animation-editor/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -56,6 +56,7 @@ var _chunk2FHLHZALcjs = require('../chunk-2FHLHZAL.cjs');
|
|
|
56
56
|
|
|
57
57
|
// src/animation-editor/types.ts
|
|
58
58
|
var MOTION_TRIGGERS = ["click", "hover", "press", "scroll"];
|
|
59
|
+
var MOTION_CLIP_TARGET = "$";
|
|
59
60
|
var MOTION_COMMAND_TYPES = [
|
|
60
61
|
"enter",
|
|
61
62
|
"exit",
|
|
@@ -67,6 +68,7 @@ var MOTION_COMMAND_TYPES = [
|
|
|
67
68
|
"style",
|
|
68
69
|
"morph",
|
|
69
70
|
"match",
|
|
71
|
+
"play",
|
|
70
72
|
"follow",
|
|
71
73
|
"pulse",
|
|
72
74
|
"shake",
|
|
@@ -94,6 +96,8 @@ var MOTION_DEFAULT_DURATIONS = {
|
|
|
94
96
|
style: 500,
|
|
95
97
|
morph: 900,
|
|
96
98
|
match: 900,
|
|
99
|
+
/** A clip's length comes from its commands (this is only a fallback). */
|
|
100
|
+
play: 600,
|
|
97
101
|
follow: 1400,
|
|
98
102
|
pulse: 600,
|
|
99
103
|
shake: 500,
|
|
@@ -137,6 +141,7 @@ var MOTION_ISSUE_CODES = {
|
|
|
137
141
|
"unknown-path": { severity: "error", wording: "A follow command names a path the artwork does not have." },
|
|
138
142
|
"not-a-path": { severity: "error", wording: "A follow path must be a path node, not a group." },
|
|
139
143
|
"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." },
|
|
144
|
+
"unknown-clip": { severity: "error", wording: "A play command names a clip the scene does not have." },
|
|
140
145
|
"unknown-shape": { severity: "error", wording: "A morph names a shape the artwork does not have." },
|
|
141
146
|
"match-self": { severity: "error", wording: "A match turns a group into itself or into a group it holds (or that holds it)." },
|
|
142
147
|
"match-unpaired": { severity: "note", wording: `Parts of a match's "into" group have no partner in the target, so they do not appear.` },
|
|
@@ -214,7 +219,7 @@ ${problems.map((p) => `- ${p}`).join("\n")}`);
|
|
|
214
219
|
this.problems = problems;
|
|
215
220
|
}
|
|
216
221
|
};
|
|
217
|
-
var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
|
|
222
|
+
var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
|
|
218
223
|
var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
|
|
219
224
|
var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric"];
|
|
220
225
|
var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps"];
|
|
@@ -222,13 +227,14 @@ var COMMAND_KEYS = {
|
|
|
222
227
|
enter: [...BASE_KEYS, "style", "direction", "distance", "scale", "shape", "orientation"],
|
|
223
228
|
exit: [...BASE_KEYS, "style", "direction", "distance"],
|
|
224
229
|
draw: [...BASE_KEYS, "from", "to"],
|
|
225
|
-
move: [...BASE_KEYS, "by", "to", "blend"],
|
|
230
|
+
move: [...BASE_KEYS, "by", "to", "via", "pacing", "blend"],
|
|
226
231
|
rotate: [...BASE_KEYS, "by", "to", "blend"],
|
|
227
232
|
scale: [...BASE_KEYS, "to", "geometric", "blend"],
|
|
228
233
|
fade: [...BASE_KEYS, "to"],
|
|
229
234
|
style: [...BASE_KEYS, "fill", "stroke", "strokeWidth"],
|
|
230
235
|
morph: [...BASE_KEYS, "into"],
|
|
231
236
|
match: [...BASE_KEYS, "into"],
|
|
237
|
+
play: ["type", "targets", "delay", "stagger", "with", "note", "clip", "speed"],
|
|
232
238
|
follow: [...BASE_KEYS, "path", "rotate", "from", "to"],
|
|
233
239
|
pulse: [...BASE_KEYS, "amount", "count", "blend"],
|
|
234
240
|
shake: [...BASE_KEYS, "amount", "count", "axis", "blend"],
|
|
@@ -303,6 +309,9 @@ function commandShapeProblems(command2, where) {
|
|
|
303
309
|
if (command2.by !== void 0 && command2.to !== void 0) p(`give "by" or "to", not both.`);
|
|
304
310
|
if (command2.by !== void 0 && !isPoint(command2.by)) p(`"by" must be { "x": number, "y": number }.`);
|
|
305
311
|
if (command2.to !== void 0 && !isPoint(command2.to)) p(`"to" must be { "x": number, "y": number }.`);
|
|
312
|
+
if (command2.via !== void 0 && !(Array.isArray(command2.via) && command2.via.length > 0 && command2.via.length <= 64 && command2.via.every(isPoint))) p(`"via" must be a list of 1 to 64 points { "x": number, "y": number } (document units).`);
|
|
313
|
+
if (command2.pacing !== void 0 && command2.pacing !== "even" && command2.pacing !== "equal") p(`"pacing" must be "even" (steady speed) or "equal" (each leg the same time).`);
|
|
314
|
+
if (command2.pacing !== void 0 && command2.via === void 0) p(`"pacing" goes with "via".`);
|
|
306
315
|
break;
|
|
307
316
|
case "rotate":
|
|
308
317
|
if (command2.by === void 0 && command2.to === void 0) p(`give "by" or "to" (degrees).`);
|
|
@@ -323,6 +332,10 @@ function commandShapeProblems(command2, where) {
|
|
|
323
332
|
if (command2.stroke !== void 0 && typeof command2.stroke !== "string") p(`"stroke" must be a CSS colour.`);
|
|
324
333
|
if (command2.strokeWidth !== void 0 && !(isNum(command2.strokeWidth) && command2.strokeWidth >= 0)) p(`"strokeWidth" must be a number \u2265 0.`);
|
|
325
334
|
break;
|
|
335
|
+
case "play":
|
|
336
|
+
if (typeof command2.clip !== "string" || !command2.clip) p(`"clip" must be the name of one of the scene's clips.`);
|
|
337
|
+
if (command2.speed !== void 0 && !(isNum(command2.speed) && command2.speed >= 0.05 && command2.speed <= 20)) p(`"speed" must be a number from 0.05 to 20 (2 plays the clip twice as fast).`);
|
|
338
|
+
break;
|
|
326
339
|
case "morph":
|
|
327
340
|
case "match":
|
|
328
341
|
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"}.`);
|
|
@@ -360,6 +373,25 @@ function commandShapeProblems(command2, where) {
|
|
|
360
373
|
}
|
|
361
374
|
return problems;
|
|
362
375
|
}
|
|
376
|
+
function clipsShapeProblems(clips) {
|
|
377
|
+
if (!isObject(clips)) return ['Scene: "clips" must be an object of named clips { "pop": { "run": [ \u2026 ] } }.'];
|
|
378
|
+
const problems = [];
|
|
379
|
+
for (const [name, clip] of Object.entries(clips)) {
|
|
380
|
+
const where = `Clip "${name}"`;
|
|
381
|
+
if (!/^[A-Za-z_][\w-]*$/.test(name)) problems.push(`${where}: a clip name is letters, digits, "_" or "-" (e.g. "pop-in").`);
|
|
382
|
+
if (!isObject(clip) || !Array.isArray(clip.run)) {
|
|
383
|
+
problems.push(`${where} must be { "description"?, "run": [commands] }.`);
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
unknownKeys(clip, ["description", "run"], where, problems);
|
|
387
|
+
if (clip.description !== void 0 && typeof clip.description !== "string") problems.push(`${where}: "description" must be a string.`);
|
|
388
|
+
clip.run.forEach((command2, i) => {
|
|
389
|
+
if (isObject(command2) && command2.type === "play") problems.push(`${where}, command ${i + 1}: a clip cannot play another clip; copy its commands in instead.`);
|
|
390
|
+
else problems.push(...commandShapeProblems(command2, `${where}, command ${i + 1}`));
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
return problems;
|
|
394
|
+
}
|
|
363
395
|
function shotShapeProblems(shot, where) {
|
|
364
396
|
if (!isObject(shot)) return [`${where} must be an object.`];
|
|
365
397
|
const problems = [];
|
|
@@ -407,6 +439,7 @@ function motionSceneShapeProblems(input) {
|
|
|
407
439
|
const art = input.artwork;
|
|
408
440
|
if (!isObject(art) || !isNum(art.width) || !isNum(art.height) || !(art.width > 0) || !(art.height > 0) || !Array.isArray(art.nodes))
|
|
409
441
|
problems.push('Scene: "artwork" must be a vector document { width, height, nodes }.');
|
|
442
|
+
if (input.clips !== void 0) problems.push(...clipsShapeProblems(input.clips));
|
|
410
443
|
if (input.trigger !== void 0 && !MOTION_TRIGGERS.includes(input.trigger)) problems.push(`Scene: "trigger" must be one of ${MOTION_TRIGGERS.join(", ")}.`);
|
|
411
444
|
if (input.loop !== void 0 && !["none", "loop", "ping-pong"].includes(input.loop)) problems.push('Scene: "loop" must be "none", "loop" or "ping-pong".');
|
|
412
445
|
if (input.fps !== void 0 && !(isNum(input.fps) && input.fps > 0 && input.fps <= 120)) problems.push('Scene: "fps" must be a number from 1 to 120.');
|
|
@@ -503,6 +536,45 @@ function matchMotionNodes(from, into) {
|
|
|
503
536
|
return out;
|
|
504
537
|
}
|
|
505
538
|
|
|
539
|
+
// src/animation-editor/smooth.ts
|
|
540
|
+
function smoothMotionLegs(times, values) {
|
|
541
|
+
const n = values.length;
|
|
542
|
+
const slope = new Array(n).fill(0);
|
|
543
|
+
const secant = (i) => (values[i + 1] - values[i]) / Math.max(1e-9, times[i + 1] - times[i]);
|
|
544
|
+
for (let i = 1; i < n - 1; i++) {
|
|
545
|
+
const a = secant(i - 1);
|
|
546
|
+
const b = secant(i);
|
|
547
|
+
if (a * b <= 0) continue;
|
|
548
|
+
const ha = times[i] - times[i - 1];
|
|
549
|
+
const hb = times[i + 1] - times[i];
|
|
550
|
+
slope[i] = 3 * (ha + hb) / ((2 * hb + ha) / a + (hb + 2 * ha) / b);
|
|
551
|
+
}
|
|
552
|
+
const legs = [];
|
|
553
|
+
for (let i = 0; i + 1 < n; i++) {
|
|
554
|
+
const dt = times[i + 1] - times[i];
|
|
555
|
+
const dv = values[i + 1] - values[i];
|
|
556
|
+
if (Math.abs(dv) < 1e-9) {
|
|
557
|
+
legs.push({ start: times[i], end: times[i + 1], from: values[i], to: values[i + 1], ease: "linear" });
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
const y1 = slope[i] * dt / (3 * dv);
|
|
561
|
+
const y2 = 1 - slope[i + 1] * dt / (3 * dv);
|
|
562
|
+
legs.push({ start: times[i], end: times[i + 1], from: values[i], to: values[i + 1], ease: { type: "cubic-bezier", x1: 1 / 3, y1, x2: 2 / 3, y2 } });
|
|
563
|
+
}
|
|
564
|
+
return legs;
|
|
565
|
+
}
|
|
566
|
+
function smoothMotionTimes(points, start, duration, pacing = "even") {
|
|
567
|
+
const legs = points.slice(1).map((p, i) => pacing === "equal" ? 1 : Math.hypot(p.x - points[i].x, p.y - points[i].y));
|
|
568
|
+
const total = legs.reduce((a, b) => a + b, 0) || legs.length || 1;
|
|
569
|
+
const times = [start];
|
|
570
|
+
let acc = 0;
|
|
571
|
+
for (const l of legs) {
|
|
572
|
+
acc += total > 0 ? l : 1;
|
|
573
|
+
times.push(start + duration * acc / total);
|
|
574
|
+
}
|
|
575
|
+
return times;
|
|
576
|
+
}
|
|
577
|
+
|
|
506
578
|
// src/animation-editor/compile.ts
|
|
507
579
|
var indexCache = /* @__PURE__ */ new WeakMap();
|
|
508
580
|
function indexMotionNodes(nodes) {
|
|
@@ -751,8 +823,38 @@ function motionCommandRepeat(command2) {
|
|
|
751
823
|
function motionCommandDuration(command2, scene, target) {
|
|
752
824
|
return motionCycleDuration(command2, scene, target) * motionCommandRepeat(command2);
|
|
753
825
|
}
|
|
826
|
+
function motionClipLayout(scene, clip, target, speed = 1) {
|
|
827
|
+
const run = _optionalChain([scene, 'access', _22 => _22.clips, 'optionalAccess', _23 => _23[clip], 'optionalAccess', _24 => _24.run]);
|
|
828
|
+
if (!run) return { items: [], length: 0 };
|
|
829
|
+
const f = speed > 0 && Number.isFinite(speed) ? 1 / speed : 1;
|
|
830
|
+
const items = [];
|
|
831
|
+
let runEnd = 0;
|
|
832
|
+
let prevStart = 0;
|
|
833
|
+
run.forEach((raw, i) => {
|
|
834
|
+
const base = raw.with === "previous" && i > 0 ? prevStart : runEnd;
|
|
835
|
+
if (raw.type === "wait") {
|
|
836
|
+
prevStart = base;
|
|
837
|
+
runEnd = Math.max(runEnd, base + raw.duration * f);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
if (raw.type === "play") return;
|
|
841
|
+
const command2 = { ...raw, targets: raw.targets.map((t) => t === MOTION_CLIP_TARGET ? target : t) };
|
|
842
|
+
const begin = base + (_nullishCoalesce(command2.delay, () => ( 0))) * f;
|
|
843
|
+
let end = begin;
|
|
844
|
+
command2.targets.forEach((t, k) => {
|
|
845
|
+
const cycle = motionCycleDuration(command2, scene, t) * f;
|
|
846
|
+
const s = begin + k * (_nullishCoalesce(command2.stagger, () => ( 0))) * f;
|
|
847
|
+
items.push({ command: command2, target: t, start: s, cycle });
|
|
848
|
+
end = Math.max(end, s + cycle * motionCommandRepeat(command2));
|
|
849
|
+
});
|
|
850
|
+
prevStart = begin;
|
|
851
|
+
runEnd = Math.max(runEnd, end);
|
|
852
|
+
});
|
|
853
|
+
return { items, length: runEnd };
|
|
854
|
+
}
|
|
754
855
|
function motionCycleDuration(command2, scene, target) {
|
|
755
856
|
if (command2.type === "wait") return command2.duration;
|
|
857
|
+
if (command2.type === "play") return motionClipLayout(scene, command2.clip, _nullishCoalesce(target, () => ( MOTION_CLIP_TARGET)), command2.speed).length;
|
|
756
858
|
if (command2.duration !== void 0) return command2.duration;
|
|
757
859
|
if (command2.ease !== void 0) {
|
|
758
860
|
const ease = _chunk2FHLHZALcjs.resolveEasing.call(void 0, command2.ease);
|
|
@@ -764,6 +866,7 @@ function motionCycleDuration(command2, scene, target) {
|
|
|
764
866
|
const ms = length * MOTION_DRAW_MS_PER_UNIT;
|
|
765
867
|
return Math.round(Math.min(MOTION_DRAW_RANGE[1], Math.max(MOTION_DRAW_RANGE[0], ms)));
|
|
766
868
|
}
|
|
869
|
+
if (command2.type === "move" && _optionalChain([command2, 'access', _25 => _25.via, 'optionalAccess', _26 => _26.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command2.via.length;
|
|
767
870
|
return MOTION_DEFAULT_DURATIONS[command2.type];
|
|
768
871
|
}
|
|
769
872
|
var MOTION_EASE_OUT = { type: "cubic-bezier", x1: 1 / 3, y1: 1, x2: 2 / 3, y2: 1 };
|
|
@@ -841,6 +944,19 @@ function compileMotionScene(scene) {
|
|
|
841
944
|
const shot = scene.shots[timing.shotIndex];
|
|
842
945
|
const command2 = shot.run[timing.command];
|
|
843
946
|
if (command2.type === "wait") continue;
|
|
947
|
+
if (command2.type === "play") {
|
|
948
|
+
const f = motionShotTimeScale(shot);
|
|
949
|
+
command2.targets.forEach((target, k) => {
|
|
950
|
+
if (!nodes.has(target)) return;
|
|
951
|
+
const at = timing.start + k * (_nullishCoalesce(command2.stagger, () => ( 0))) * f;
|
|
952
|
+
for (const item of motionClipLayout(scene, command2.clip, target, (_nullishCoalesce(command2.speed, () => ( 1))) / f).items) {
|
|
953
|
+
const entry = nodes.get(item.target);
|
|
954
|
+
if (!entry) continue;
|
|
955
|
+
jobs.push({ start: at + item.start, order: order++, run: () => compileRepeated(item.command, item.target, entry, at + item.start, item.cycle, timing) });
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
continue;
|
|
959
|
+
}
|
|
844
960
|
command2.targets.forEach((target, k) => {
|
|
845
961
|
const entry = nodes.get(target);
|
|
846
962
|
if (!entry) return;
|
|
@@ -892,7 +1008,7 @@ function compileMotionScene(scene) {
|
|
|
892
1008
|
const style = _nullishCoalesce(command2.style, () => ( "fade"));
|
|
893
1009
|
const opacity = rest("opacity");
|
|
894
1010
|
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;
|
|
895
|
-
for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess',
|
|
1011
|
+
for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _27 => _27.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
|
|
896
1012
|
if (reveal) {
|
|
897
1013
|
seg("opacity", opacity, "linear", start, start);
|
|
898
1014
|
seg(reveal.property, reveal.to, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: reveal.from });
|
|
@@ -954,14 +1070,28 @@ function compileMotionScene(scene) {
|
|
|
954
1070
|
}
|
|
955
1071
|
case "move": {
|
|
956
1072
|
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
957
|
-
let dx = _nullishCoalesce(_optionalChain([command2, 'access',
|
|
958
|
-
let dy = _nullishCoalesce(_optionalChain([command2, 'access',
|
|
1073
|
+
let dx = _nullishCoalesce(_optionalChain([command2, 'access', _28 => _28.by, 'optionalAccess', _29 => _29.x]), () => ( 0));
|
|
1074
|
+
let dy = _nullishCoalesce(_optionalChain([command2, 'access', _30 => _30.by, 'optionalAccess', _31 => _31.y]), () => ( 0));
|
|
959
1075
|
if (command2.to) {
|
|
960
1076
|
const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
|
|
961
1077
|
const target = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, command2.to);
|
|
962
1078
|
dx = target.x - (entry.center.x + num("x"));
|
|
963
1079
|
dy = target.y - (entry.center.y + num("y"));
|
|
964
1080
|
}
|
|
1081
|
+
if (_optionalChain([command2, 'access', _32 => _32.via, 'optionalAccess', _33 => _33.length])) {
|
|
1082
|
+
const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
|
|
1083
|
+
const x0 = num("x");
|
|
1084
|
+
const y0 = num("y");
|
|
1085
|
+
const add = command2.blend === "add";
|
|
1086
|
+
const offsets = [{ x: 0, y: 0 }, ...command2.via.map((p) => _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, p)).map((p) => ({ x: p.x - entry.center.x - x0, y: p.y - entry.center.y - y0 })), { x: dx, y: dy }];
|
|
1087
|
+
const times = smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(command2.pacing, () => ( "even")));
|
|
1088
|
+
for (const axis of ["x", "y"]) {
|
|
1089
|
+
const base = add ? 0 : axis === "x" ? x0 : y0;
|
|
1090
|
+
for (const leg of smoothMotionLegs(times, offsets.map((o) => o[axis])))
|
|
1091
|
+
seg(axis, base + leg.to, leg.ease, leg.start, leg.end, { from: base + leg.from, ...add ? { blend: "add" } : {} });
|
|
1092
|
+
}
|
|
1093
|
+
break;
|
|
1094
|
+
}
|
|
965
1095
|
if (command2.blend === "add") {
|
|
966
1096
|
seg("x", dx, e, start, end, { from: 0, blend: "add" });
|
|
967
1097
|
seg("y", dy, e, start, end, { from: 0, blend: "add" });
|
|
@@ -1059,7 +1189,7 @@ var MOTION_DRAW_EFFECT_ID = "~draw";
|
|
|
1059
1189
|
var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
|
|
1060
1190
|
var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
|
|
1061
1191
|
function applyMotionControlValues(scene, values) {
|
|
1062
|
-
if (!values || !_optionalChain([scene, 'access',
|
|
1192
|
+
if (!values || !_optionalChain([scene, 'access', _34 => _34.controls, 'optionalAccess', _35 => _35.length])) return scene;
|
|
1063
1193
|
const map = /* @__PURE__ */ new Map();
|
|
1064
1194
|
for (const control of scene.controls) {
|
|
1065
1195
|
const value = values[control.name];
|
|
@@ -1105,7 +1235,7 @@ function shapeIn(entry, shape) {
|
|
|
1105
1235
|
}
|
|
1106
1236
|
function shapeAt(entry, timeline, nodes, time) {
|
|
1107
1237
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
|
|
1108
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
1238
|
+
if (!_optionalChain([track, 'optionalAccess', _36 => _36.length])) return null;
|
|
1109
1239
|
const s = activeSegment(track, time);
|
|
1110
1240
|
const fromId = String(s ? s.from : track[0].from);
|
|
1111
1241
|
if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
|
|
@@ -1128,8 +1258,8 @@ function motionFollowRoute(entry, path) {
|
|
|
1128
1258
|
}
|
|
1129
1259
|
function followAt(entry, timeline, nodes, time) {
|
|
1130
1260
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "follow"));
|
|
1131
|
-
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess',
|
|
1132
|
-
if (!_optionalChain([s, 'optionalAccess',
|
|
1261
|
+
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _37 => _37[0]])));
|
|
1262
|
+
if (!_optionalChain([s, 'optionalAccess', _38 => _38.path])) return null;
|
|
1133
1263
|
const route = motionFollowRoute(entry, nodes.get(s.path));
|
|
1134
1264
|
const progress = Number(trackValue(track, time));
|
|
1135
1265
|
if (!route || !(progress >= 0)) return null;
|
|
@@ -1189,7 +1319,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1189
1319
|
if (out.visible === void 0) delete out.visible;
|
|
1190
1320
|
}
|
|
1191
1321
|
const effectTracks = [...timeline.tracks.keys()].filter((k) => k.startsWith(`${id}\0effect:`));
|
|
1192
|
-
if (effectTracks.length && _optionalChain([out, 'access',
|
|
1322
|
+
if (effectTracks.length && _optionalChain([out, 'access', _39 => _39.effects, 'optionalAccess', _40 => _40.length])) {
|
|
1193
1323
|
out = {
|
|
1194
1324
|
...out,
|
|
1195
1325
|
effects: out.effects.map((effect) => {
|
|
@@ -1302,7 +1432,7 @@ function motionPath(scene, id, options = {}) {
|
|
|
1302
1432
|
const r = (n) => Math.round(n * 100) / 100;
|
|
1303
1433
|
const centreAt = (t) => {
|
|
1304
1434
|
const node = indexMotionNodes(motionFrameAtCache(scene, t)).get(id);
|
|
1305
|
-
const b = _optionalChain([node, 'optionalAccess',
|
|
1435
|
+
const b = _optionalChain([node, 'optionalAccess', _41 => _41.bounds]);
|
|
1306
1436
|
return b ? { t: r(t), x: r(b.x + b.width / 2), y: r(b.y + b.height / 2) } : null;
|
|
1307
1437
|
};
|
|
1308
1438
|
const points = [];
|
|
@@ -1342,14 +1472,14 @@ function motionStageSvg(scene, time, options = {}) {
|
|
|
1342
1472
|
const open = current.indexOf(">") + 1;
|
|
1343
1473
|
const close = current.lastIndexOf("</svg>");
|
|
1344
1474
|
const body = current.slice(open, close);
|
|
1345
|
-
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access',
|
|
1475
|
+
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _42 => _42.exec, 'call', _43 => _43(body), 'optionalAccess', _44 => _44[0]]), () => ( "")) : "";
|
|
1346
1476
|
return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
|
|
1347
1477
|
}
|
|
1348
1478
|
|
|
1349
1479
|
// src/animation-editor/check.ts
|
|
1350
1480
|
var MOTION_MIN_CHANGE_MS = 120;
|
|
1351
1481
|
var NUMERIC_PARAMS = (node, effectId) => {
|
|
1352
|
-
const effect = _optionalChain([node, 'access',
|
|
1482
|
+
const effect = _optionalChain([node, 'access', _45 => _45.effects, 'optionalAccess', _46 => _46.find, 'call', _47 => _47((e) => e.id === effectId)]);
|
|
1353
1483
|
if (!effect) return null;
|
|
1354
1484
|
return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
|
|
1355
1485
|
};
|
|
@@ -1426,6 +1556,8 @@ function checkMotionScene(scene) {
|
|
|
1426
1556
|
if (command2.type === "follow" && known(command2.path, "unknown-path", "path", where) && nodes.get(command2.path).node.type !== "path")
|
|
1427
1557
|
issues.push(motionIssue("not-a-path", `"${command2.path}" is a group; follow a single path node.`, { ...where, ids: [command2.path] }));
|
|
1428
1558
|
if (command2.type === "morph") known(command2.into, "unknown-shape", "shape", where);
|
|
1559
|
+
if (command2.type === "play" && !_optionalChain([scene, 'access', _48 => _48.clips, 'optionalAccess', _49 => _49[command2.clip]]))
|
|
1560
|
+
issues.push(motionIssue("unknown-clip", `There is no clip ${namedWithSuggestion(command2.clip, Object.keys(_nullishCoalesce(scene.clips, () => ( {}))))}; define it with set_animation_clip.`, where));
|
|
1429
1561
|
if (command2.type === "match" && known(command2.into, "unknown-shape", "group", where)) {
|
|
1430
1562
|
const into = nodes.get(command2.into);
|
|
1431
1563
|
for (const id of targets) {
|
|
@@ -1498,6 +1630,12 @@ function checkMotionScene(scene) {
|
|
|
1498
1630
|
}
|
|
1499
1631
|
});
|
|
1500
1632
|
});
|
|
1633
|
+
for (const [name, clip] of Object.entries(_nullishCoalesce(scene.clips, () => ( {}))))
|
|
1634
|
+
for (const command2 of clip.run)
|
|
1635
|
+
if (command2.type !== "wait") {
|
|
1636
|
+
for (const id of command2.targets)
|
|
1637
|
+
if (id !== MOTION_CLIP_TARGET && !nodes.has(id)) issues.push(motionIssue("unknown-target", `Clip "${name}" names ${namedWithSuggestion(id, [...nodes.keys()])}, which the artwork does not have; use "$" for the node the clip is played on.`, { ids: [id] }));
|
|
1638
|
+
}
|
|
1501
1639
|
if (scene.trigger) {
|
|
1502
1640
|
if ((_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") issues.push(motionIssue("trigger-loop", `The scene plays on ${scene.trigger}, so its "${scene.loop}" loop does not apply; set loop to "none" or remove the trigger.`, {}));
|
|
1503
1641
|
if (scene.trigger === "click") {
|
|
@@ -1511,7 +1649,7 @@ function checkMotionScene(scene) {
|
|
|
1511
1649
|
if (!shot.at) return;
|
|
1512
1650
|
const timing = timeline.shots[i];
|
|
1513
1651
|
if (timing.cue === void 0) {
|
|
1514
|
-
const what = shot.at.beat !== void 0 ? `beat ${shot.at.beat}, but the scene has no beat grid; set one with set_animation_settings ({ "beat": { "bpm": \u2026 } })` : `word ${shot.at.word}, but the narration has ${_nullishCoalesce(_optionalChain([scene, 'access',
|
|
1652
|
+
const what = shot.at.beat !== void 0 ? `beat ${shot.at.beat}, but the scene has no beat grid; set one with set_animation_settings ({ "beat": { "bpm": \u2026 } })` : `word ${shot.at.word}, but the narration has ${_nullishCoalesce(_optionalChain([scene, 'access', _50 => _50.narration, 'optionalAccess', _51 => _51.words, 'access', _52 => _52.length]), () => ( 0))} words (indexes from 0)`;
|
|
1515
1653
|
issues.push(motionIssue("unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
|
|
1516
1654
|
} else if (timing.missedBy !== void 0) {
|
|
1517
1655
|
const late = Math.round(timing.missedBy);
|
|
@@ -1544,7 +1682,7 @@ function checkMotionScene(scene) {
|
|
|
1544
1682
|
const cam = frame.camera;
|
|
1545
1683
|
const docIndex = indexMotionNodes(frame.document.nodes);
|
|
1546
1684
|
for (const id of command2.targets) {
|
|
1547
|
-
const b = _optionalChain([docIndex, 'access',
|
|
1685
|
+
const b = _optionalChain([docIndex, 'access', _53 => _53.get, 'call', _54 => _54(id), 'optionalAccess', _55 => _55.bounds]);
|
|
1548
1686
|
if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
|
|
1549
1687
|
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;
|
|
1550
1688
|
if (outside) {
|
|
@@ -1581,6 +1719,7 @@ var MOTION_EDIT_OPS = [
|
|
|
1581
1719
|
"move_command",
|
|
1582
1720
|
"set_artwork",
|
|
1583
1721
|
"set_controls",
|
|
1722
|
+
"set_clip",
|
|
1584
1723
|
"replace_scene"
|
|
1585
1724
|
];
|
|
1586
1725
|
var EditError = class extends Error {
|
|
@@ -1637,6 +1776,23 @@ function applyOne(scene, edit) {
|
|
|
1637
1776
|
else if (edit.target !== void 0) next.target = edit.target;
|
|
1638
1777
|
return next;
|
|
1639
1778
|
}
|
|
1779
|
+
case "set_clip": {
|
|
1780
|
+
if (typeof edit.name !== "string" || !edit.name) fail('Give the clip a "name".');
|
|
1781
|
+
const clips = { ..._nullishCoalesce(scene.clips, () => ( {})) };
|
|
1782
|
+
if (edit.clip === null) {
|
|
1783
|
+
if (!clips[edit.name]) fail(`There is no clip ${namedWithSuggestion(edit.name, Object.keys(clips))} to delete.`);
|
|
1784
|
+
const playing = scene.shots.filter((s) => s.run.some((c) => c.type === "play" && c.clip === edit.name)).map((s) => `"${s.id}"`);
|
|
1785
|
+
if (playing.length) fail(`Clip "${edit.name}" is played in shot${playing.length > 1 ? "s" : ""} ${playing.join(", ")}; remove those play commands first.`);
|
|
1786
|
+
delete clips[edit.name];
|
|
1787
|
+
} else {
|
|
1788
|
+
const problems = clipsShapeProblems({ [edit.name]: edit.clip });
|
|
1789
|
+
if (problems.length) fail(problems.join(" "));
|
|
1790
|
+
clips[edit.name] = edit.clip;
|
|
1791
|
+
}
|
|
1792
|
+
const next = { ...scene, clips };
|
|
1793
|
+
if (!Object.keys(clips).length) delete next.clips;
|
|
1794
|
+
return next;
|
|
1795
|
+
}
|
|
1640
1796
|
case "insert_shots": {
|
|
1641
1797
|
if (!edit.shots.length) fail("Give at least one shot.");
|
|
1642
1798
|
edit.shots.forEach((shot, i) => {
|
|
@@ -1750,9 +1906,9 @@ function applyMotionEdits(scene, edits) {
|
|
|
1750
1906
|
let next = scene;
|
|
1751
1907
|
for (let i = 0; i < list.length; i++) {
|
|
1752
1908
|
const edit = list[i];
|
|
1753
|
-
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess',
|
|
1909
|
+
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _56 => _56.op])}): ` : "";
|
|
1754
1910
|
if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
|
|
1755
|
-
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess',
|
|
1911
|
+
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _57 => _57.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
|
|
1756
1912
|
try {
|
|
1757
1913
|
next = applyOne(next, edit);
|
|
1758
1914
|
} catch (error) {
|
|
@@ -1912,7 +2068,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1912
2068
|
const wrapper = freshId(`${id}--follow`);
|
|
1913
2069
|
const centre = freshId(`${id}--follow-centre`);
|
|
1914
2070
|
const c = entry.center;
|
|
1915
|
-
const at = _optionalChain([motionNodeOffset, 'call',
|
|
2071
|
+
const at = _optionalChain([motionNodeOffset, 'call', _58 => _58(entry, timeline, 0, nodes), 'optionalAccess', _59 => _59.follow]);
|
|
1916
2072
|
const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
|
|
1917
2073
|
(wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
|
|
1918
2074
|
follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
|
|
@@ -1972,7 +2128,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1972
2128
|
exact: () => false,
|
|
1973
2129
|
value: (t) => {
|
|
1974
2130
|
const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
|
|
1975
|
-
const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call',
|
|
2131
|
+
const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _60 => _60(frame.document.nodes), 'access', _61 => _61.get, 'call', _62 => _62(id), 'optionalAccess', _63 => _63.node]));
|
|
1976
2132
|
if (!now || now.type !== "path") return "";
|
|
1977
2133
|
const bezier = _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, now, _chunkYJLCBA7Vcjs.IDENTITY_MATRIX, { effects: false }), inverse);
|
|
1978
2134
|
return _chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
|
|
@@ -1993,8 +2149,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1993
2149
|
...delay > 0 ? { delay: round2(delay) } : {},
|
|
1994
2150
|
ms: round2(ms),
|
|
1995
2151
|
ease: written,
|
|
1996
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
1997
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
2152
|
+
..._optionalChain([segment, 'optionalAccess', _64 => _64.behavior]) ? { behavior: segment.behavior } : {},
|
|
2153
|
+
..._optionalChain([segment, 'optionalAccess', _65 => _65.steps]) ? { strobe: segment.steps } : {}
|
|
1998
2154
|
};
|
|
1999
2155
|
if (channel.kind === "view") animate.push({ ...base, view: to });
|
|
2000
2156
|
else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
|
|
@@ -2083,7 +2239,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2083
2239
|
let svg = _chunkYJLCBA7Vcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
|
|
2084
2240
|
if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
|
|
2085
2241
|
let motion = { svg, animate };
|
|
2086
|
-
if (_optionalChain([scene, 'access',
|
|
2242
|
+
if (_optionalChain([scene, 'access', _66 => _66.controls, 'optionalAccess', _67 => _67.length])) {
|
|
2087
2243
|
const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
|
|
2088
2244
|
const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
|
|
2089
2245
|
svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
|
|
@@ -2105,7 +2261,7 @@ function toFlairVectorEffect(scene, options = {}) {
|
|
|
2105
2261
|
tags: _nullishCoalesce(options.tags, () => ( [])),
|
|
2106
2262
|
motion: out.motion,
|
|
2107
2263
|
hold: out.hold,
|
|
2108
|
-
..._optionalChain([scene, 'access',
|
|
2264
|
+
..._optionalChain([scene, 'access', _68 => _68.presets, 'optionalAccess', _69 => _69.length]) ? { presets: scene.presets } : {},
|
|
2109
2265
|
...out.trigger ? { trigger: out.trigger } : {}
|
|
2110
2266
|
};
|
|
2111
2267
|
}
|
|
@@ -2149,7 +2305,7 @@ function resolvePlaceholders(motion, notes) {
|
|
|
2149
2305
|
const filled = text.replace(PLACEHOLDER, (_, name) => {
|
|
2150
2306
|
const d = declared.get(name);
|
|
2151
2307
|
if (!d) unknown.add(name);
|
|
2152
|
-
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess',
|
|
2308
|
+
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _70 => _70.value]), () => ( ""))).replace(/"/g, '\\"');
|
|
2153
2309
|
});
|
|
2154
2310
|
for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
|
|
2155
2311
|
return { motion: JSON.parse(filled), controls };
|
|
@@ -2203,7 +2359,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2203
2359
|
if (anim.along) {
|
|
2204
2360
|
const path = nodes.get(anim.along);
|
|
2205
2361
|
if (!path || path.node.type !== "path") notes.push(`${where} follows "${anim.along}", which is not a path in the artwork; the follow was skipped.`);
|
|
2206
|
-
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access',
|
|
2362
|
+
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _71 => _71.at, 'optionalAccess', _72 => _72[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _73 => _73.at, 'optionalAccess', _74 => _74[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2207
2363
|
}
|
|
2208
2364
|
for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
|
|
2209
2365
|
if (attr === "opacity") {
|
|
@@ -2214,7 +2370,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2214
2370
|
out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
|
|
2215
2371
|
} else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2216
2372
|
} else if (attr === "fill" || attr === "stroke") {
|
|
2217
|
-
if (_optionalChain([behavior, 'optionalAccess',
|
|
2373
|
+
if (_optionalChain([behavior, 'optionalAccess', _75 => _75.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
|
|
2218
2374
|
else {
|
|
2219
2375
|
if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
|
|
2220
2376
|
out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
@@ -2497,7 +2653,7 @@ function toLottie(scene, options = {}) {
|
|
|
2497
2653
|
const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
|
|
2498
2654
|
const geometryAt = (t) => {
|
|
2499
2655
|
if (!shapeSegments.length) return _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2500
|
-
const now = _optionalChain([indexMotionNodes, 'call',
|
|
2656
|
+
const now = _optionalChain([indexMotionNodes, 'call', _76 => _76(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _77 => _77.get, 'call', _78 => _78(path.id), 'optionalAccess', _79 => _79.node]);
|
|
2501
2657
|
return now && now.type === "path" ? _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2502
2658
|
};
|
|
2503
2659
|
const rest = lottieContours(_chunkO2UH7LZEcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
|
|
@@ -2543,7 +2699,7 @@ function toLottie(scene, options = {}) {
|
|
|
2543
2699
|
lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
|
|
2544
2700
|
ml: 4
|
|
2545
2701
|
});
|
|
2546
|
-
if (_optionalChain([path, 'access',
|
|
2702
|
+
if (_optionalChain([path, 'access', _80 => _80.strokeDasharray, 'optionalAccess', _81 => _81.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
|
|
2547
2703
|
if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
|
|
2548
2704
|
}
|
|
2549
2705
|
const fill = paintOf(path.fill, "fill", path.id);
|
|
@@ -2694,7 +2850,7 @@ var AnimationEditorController = (_class = class {
|
|
|
2694
2850
|
time: p.time,
|
|
2695
2851
|
playing: p.playing,
|
|
2696
2852
|
loop: p.loop,
|
|
2697
|
-
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call',
|
|
2853
|
+
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _82 => _82(timeline, p.time), 'optionalAccess', _83 => _83.id]), () => ( null)),
|
|
2698
2854
|
selection: this.selection,
|
|
2699
2855
|
readOnly: this.readOnly,
|
|
2700
2856
|
error: this.error,
|
|
@@ -2733,7 +2889,7 @@ var AnimationEditorController = (_class = class {
|
|
|
2733
2889
|
this.applying = false;
|
|
2734
2890
|
}
|
|
2735
2891
|
this.notify();
|
|
2736
|
-
_optionalChain([this, 'access',
|
|
2892
|
+
_optionalChain([this, 'access', _84 => _84.onChange, 'optionalCall', _85 => _85(scene)]);
|
|
2737
2893
|
}
|
|
2738
2894
|
commit(label, next) {
|
|
2739
2895
|
const before = this.scene;
|
|
@@ -2937,7 +3093,7 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
2937
3093
|
distance: { type: "number", description: "For slide: document units (default 40)." }
|
|
2938
3094
|
}),
|
|
2939
3095
|
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).") }),
|
|
2940
|
-
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.") }),
|
|
3096
|
+
command("move", "Moves targets by an offset or so their centre lands on a point.", { via: { type: "array", items: POINT("A point the centre passes through."), minItems: 1, maxItems: 64, description: 'Waypoints (document units) the centre passes through on the way to "to" or "by", smoothly (velocity carries through each) and without overshooting any. Default length 700 ms + 400 per waypoint.' }, pacing: { type: "string", enum: ["even", "equal"], description: "With via: even (default) keeps the speed steady along the path; equal gives each stretch the same time." }, blend: BLEND("replace"), by: POINT("Offset in document units."), to: POINT("Point (document coordinates) for the centre.") }),
|
|
2941
3097
|
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." } }),
|
|
2942
3098
|
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"]),
|
|
2943
3099
|
command("fade", "Changes opacity.", { to: FRACTION("Opacity at the end (0\u20131).") }, ["to"]),
|
|
@@ -2946,6 +3102,20 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
2946
3102
|
stroke: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
|
|
2947
3103
|
strokeWidth: { type: "number", minimum: 0, description: "Document units." }
|
|
2948
3104
|
}),
|
|
3105
|
+
object(
|
|
3106
|
+
{
|
|
3107
|
+
type: { const: "play", description: 'Plays a clip (set_animation_clip) on the targets: its commands, with "$" standing for each target, timed as in a shot.' },
|
|
3108
|
+
targets: NODE_IDS,
|
|
3109
|
+
clip: { type: "string", minLength: 1, description: "The clip's name (get_animation lists them)." },
|
|
3110
|
+
speed: { type: "number", minimum: 0.05, maximum: 20, description: "Play it this many times as fast (default 1)." },
|
|
3111
|
+
delay: BASE.delay,
|
|
3112
|
+
stagger: BASE.stagger,
|
|
3113
|
+
with: BASE.with,
|
|
3114
|
+
note: BASE.note
|
|
3115
|
+
},
|
|
3116
|
+
["type", "targets", "clip"],
|
|
3117
|
+
"Plays a clip on the targets."
|
|
3118
|
+
),
|
|
2949
3119
|
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"]),
|
|
2950
3120
|
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"]),
|
|
2951
3121
|
command("follow", "Moves targets along a path node, centre on the path.", {
|
|
@@ -3154,6 +3324,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3154
3324
|
...s.target ? { target: s.target } : {},
|
|
3155
3325
|
...includeElements ? { elements: describeMotionElements(s) } : {},
|
|
3156
3326
|
shots: describeMotionShots(s),
|
|
3327
|
+
...s.clips ? { clips: Object.fromEntries(Object.entries(s.clips).map(([name, c]) => [name, { ...c.description ? { description: c.description } : {}, commands: c.run.length, length: Math.round(motionClipLayout(s, name, "$").length) }])) } : {},
|
|
3157
3328
|
...s.controls ? { controls: s.controls } : {},
|
|
3158
3329
|
...s.presets ? { presets: s.presets } : {},
|
|
3159
3330
|
issues: issueSummary(controller.getState().issues),
|
|
@@ -3255,9 +3426,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3255
3426
|
handler: ({ from = 0, to, limit = 200 }) => {
|
|
3256
3427
|
const s = scene();
|
|
3257
3428
|
const timeline = compileMotionScene(s);
|
|
3258
|
-
const words = _nullishCoalesce(_optionalChain([s, 'access',
|
|
3429
|
+
const words = _nullishCoalesce(_optionalChain([s, 'access', _86 => _86.narration, 'optionalAccess', _87 => _87.words]), () => ( []));
|
|
3259
3430
|
const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
|
|
3260
|
-
const shotAt = (ms) => _optionalChain([timeline, 'access',
|
|
3431
|
+
const shotAt = (ms) => _optionalChain([timeline, 'access', _88 => _88.shots, 'access', _89 => _89.find, 'call', _90 => _90((x) => ms >= x.start && ms < x.end), 'optionalAccess', _91 => _91.id]);
|
|
3261
3432
|
const beats = [];
|
|
3262
3433
|
if (s.beat && s.beat.bpm > 0) {
|
|
3263
3434
|
const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
|
|
@@ -3399,6 +3570,68 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3399
3570
|
return apply(edits, "Fit to length", () => report);
|
|
3400
3571
|
}
|
|
3401
3572
|
};
|
|
3573
|
+
const setClip = {
|
|
3574
|
+
name: "set_animation_clip",
|
|
3575
|
+
title: "Define a reusable clip",
|
|
3576
|
+
description: `Defines, replaces or (with clip null) deletes a named clip: commands written against the target "$" that a play command plays on any node, e.g. a "pop-settle" or "attention" used many times. One undo step. Returns the clip's length and the timing.`,
|
|
3577
|
+
inputSchema: object(
|
|
3578
|
+
{
|
|
3579
|
+
name: { type: "string", pattern: "^[A-Za-z_][\\w-]*$", description: 'Clip name, e.g. "pop-settle".' },
|
|
3580
|
+
clip: {
|
|
3581
|
+
anyOf: [object({ description: { type: "string", description: "What it does, in a few words." }, run: { type: "array", items: MOTION_COMMAND_SCHEMA, minItems: 1, description: 'Commands, timed as in a shot; target "$" for the node it is played on. Clips cannot play clips.' } }, ["run"]), { type: "null" }],
|
|
3582
|
+
description: "The clip, or null to delete it (refused while a play command uses it)."
|
|
3583
|
+
}
|
|
3584
|
+
},
|
|
3585
|
+
["name", "clip"]
|
|
3586
|
+
),
|
|
3587
|
+
annotations: { title: "Define a reusable clip", ...WRITE_IDEMPOTENT },
|
|
3588
|
+
handler: ({ name, clip }) => apply({ op: "set_clip", name, clip }, clip === null ? "Delete clip" : "Set clip", (s) => clip === null ? { deleted: name } : { clip: name, length: Math.round(motionClipLayout(s, name, "$").length) })
|
|
3589
|
+
};
|
|
3590
|
+
const copyAnimation = {
|
|
3591
|
+
name: "copy_animation",
|
|
3592
|
+
title: "Copy one node's animation to others",
|
|
3593
|
+
description: 'Copies every command that animates "from" (in all shots, or the ones given) so it also animates "to": each copy goes right after its original and starts with it. One undo step. Returns how many commands were copied per shot. For motion you will reuse often, a clip (set_animation_clip + play) is tidier.',
|
|
3594
|
+
inputSchema: object(
|
|
3595
|
+
{
|
|
3596
|
+
from: { type: "string", minLength: 1, description: "Element id whose commands to copy." },
|
|
3597
|
+
to: { type: "array", items: { type: "string", minLength: 1 }, minItems: 1, description: "Element ids to give the same motion." },
|
|
3598
|
+
shots: { type: "array", items: SHOT_ID, description: "Only these shots (default all)." },
|
|
3599
|
+
stagger: MS("Start each copy this much after the one before (default 0)")
|
|
3600
|
+
},
|
|
3601
|
+
["from", "to"]
|
|
3602
|
+
),
|
|
3603
|
+
annotations: { title: "Copy one node's animation to others", ...WRITE },
|
|
3604
|
+
handler: ({ from, to, shots, stagger }) => {
|
|
3605
|
+
const s = scene();
|
|
3606
|
+
const ids = describeMotionElements(s).map((e) => e.id);
|
|
3607
|
+
for (const id of [from, ...to]) if (!ids.includes(id)) throw new Error(`There is no element ${namedWithSuggestion(id, ids)}. Nothing was changed.`);
|
|
3608
|
+
if (to.includes(from)) throw new Error(`"to" includes "${from}" itself; give other elements. Nothing was changed.`);
|
|
3609
|
+
const only = shots ? new Set(shots) : null;
|
|
3610
|
+
if (only) {
|
|
3611
|
+
for (const id of only) if (!s.shots.some((x) => x.id === id)) throw new Error(`There is no shot ${namedWithSuggestion(id, s.shots.map((x) => x.id))}. Nothing was changed.`);
|
|
3612
|
+
}
|
|
3613
|
+
const copied = {};
|
|
3614
|
+
const edits = [];
|
|
3615
|
+
for (const shot of s.shots) {
|
|
3616
|
+
if (only && !only.has(shot.id)) continue;
|
|
3617
|
+
const run = [];
|
|
3618
|
+
let n = 0;
|
|
3619
|
+
for (const c of shot.run) {
|
|
3620
|
+
run.push(c);
|
|
3621
|
+
if (c.type === "wait" || !c.targets.includes(from)) continue;
|
|
3622
|
+
const { delay: _delay, ...rest } = c;
|
|
3623
|
+
run.push({ ...rest, targets: to, with: "previous", ...stagger ? { stagger } : {} });
|
|
3624
|
+
n++;
|
|
3625
|
+
}
|
|
3626
|
+
if (n) {
|
|
3627
|
+
copied[shot.id] = n;
|
|
3628
|
+
edits.push({ op: "update_shot", shot: shot.id, set: { run } });
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
if (!edits.length) throw new Error(`No command animates "${from}"${only ? " in those shots" : ""}; nothing to copy.`);
|
|
3632
|
+
return apply(edits, "Copy animation", () => ({ copied }));
|
|
3633
|
+
}
|
|
3634
|
+
};
|
|
3402
3635
|
const insertShots = {
|
|
3403
3636
|
name: "insert_shots",
|
|
3404
3637
|
title: "Add shots",
|
|
@@ -3445,7 +3678,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3445
3678
|
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"]),
|
|
3446
3679
|
annotations: { title: "Add commands to a shot", ...WRITE },
|
|
3447
3680
|
handler: ({ shot, commands, at }) => {
|
|
3448
|
-
const before = _nullishCoalesce(_optionalChain([scene, 'call',
|
|
3681
|
+
const before = _nullishCoalesce(_optionalChain([scene, 'call', _92 => _92(), 'access', _93 => _93.shots, 'access', _94 => _94.find, 'call', _95 => _95((s) => s.id === shot), 'optionalAccess', _96 => _96.run, 'access', _97 => _97.length]), () => ( 0));
|
|
3449
3682
|
const first = _nullishCoalesce(at, () => ( before));
|
|
3450
3683
|
return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
|
|
3451
3684
|
const shots = describeMotionShots(s);
|
|
@@ -3575,7 +3808,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3575
3808
|
}
|
|
3576
3809
|
};
|
|
3577
3810
|
const reads = [getAnimation, getShot, findElements, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
|
|
3578
|
-
const writes = [setArtworkSvg, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
|
|
3811
|
+
const writes = [setArtworkSvg, setClip, copyAnimation, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
|
|
3579
3812
|
return {
|
|
3580
3813
|
id: _nullishCoalesce(options.id, () => ( "animation")),
|
|
3581
3814
|
namespace: options.namespace,
|
|
@@ -3607,6 +3840,8 @@ Commands
|
|
|
3607
3840
|
- enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.
|
|
3608
3841
|
- 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.
|
|
3609
3842
|
- 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.
|
|
3843
|
+
- Reuse motion: set_animation_clip defines a clip (commands targeting "$"), and { "type": "play", "clip": name, "targets": [...] } plays it on any nodes (with stagger and speed). copy_animation gives other nodes one node's motion.
|
|
3844
|
+
- move takes "via" waypoints for a curved, smooth path that passes exactly through each point (steady speed by default); use it instead of chaining moves, which stop at each point.
|
|
3610
3845
|
- enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting "scale".
|
|
3611
3846
|
- 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).
|
|
3612
3847
|
- 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).
|
|
@@ -3632,7 +3867,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
|
|
|
3632
3867
|
var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
|
|
3633
3868
|
var NODES = /* @__PURE__ */ new Set(["into", "path"]);
|
|
3634
3869
|
function branch(type) {
|
|
3635
|
-
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access',
|
|
3870
|
+
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _98 => _98.properties, 'optionalAccess', _99 => _99.type, 'optionalAccess', _100 => _100.const]) === type);
|
|
3636
3871
|
}
|
|
3637
3872
|
function unitOf(type, name) {
|
|
3638
3873
|
if (name === "duration" || name === "delay" || name === "stagger") return "ms";
|
|
@@ -3667,7 +3902,7 @@ function kindOf(name, schema) {
|
|
|
3667
3902
|
}
|
|
3668
3903
|
function motionCommandFields(type) {
|
|
3669
3904
|
const schema = branch(type);
|
|
3670
|
-
if (!_optionalChain([schema, 'optionalAccess',
|
|
3905
|
+
if (!_optionalChain([schema, 'optionalAccess', _101 => _101.properties])) return [];
|
|
3671
3906
|
const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
|
|
3672
3907
|
const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
|
|
3673
3908
|
const kind = kindOf(name, s);
|
|
@@ -3724,7 +3959,7 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
3724
3959
|
if (type === "wait") return { type: "wait", duration: 500 };
|
|
3725
3960
|
if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
|
|
3726
3961
|
const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
|
|
3727
|
-
const other = (pred) => _optionalChain([nodes, 'access',
|
|
3962
|
+
const other = (pred) => _optionalChain([nodes, 'access', _102 => _102.find, 'call', _103 => _103((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _104 => _104.node, 'access', _105 => _105.id]);
|
|
3728
3963
|
const base = { targets: [...targets] };
|
|
3729
3964
|
switch (type) {
|
|
3730
3965
|
case "scale":
|
|
@@ -3745,14 +3980,18 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
3745
3980
|
const into = _nullishCoalesce(other((e) => e.node.type === "group" && e.node.visible === false), () => ( other((e) => e.node.type === "group")));
|
|
3746
3981
|
return into ? { type, ...base, into } : { error: "Match needs another group to become; group the end state (it can stay hidden)." };
|
|
3747
3982
|
}
|
|
3983
|
+
case "play": {
|
|
3984
|
+
const clip = Object.keys(_nullishCoalesce(scene.clips, () => ( {})))[0];
|
|
3985
|
+
return clip ? { type, ...base, clip } : { error: 'Play needs a clip; define one first (set_animation_clip), with "$" as its target.' };
|
|
3986
|
+
}
|
|
3748
3987
|
case "follow": {
|
|
3749
3988
|
const path = _nullishCoalesce(other((e) => e.node.type === "path" && e.node.visible === false), () => ( other((e) => e.node.type === "path")));
|
|
3750
3989
|
return path ? { type, ...base, path } : { error: "Follow needs a path to travel along; draw one (it can stay hidden)." };
|
|
3751
3990
|
}
|
|
3752
3991
|
case "effect": {
|
|
3753
3992
|
for (const id of targets) {
|
|
3754
|
-
const node = _optionalChain([nodes, 'access',
|
|
3755
|
-
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess',
|
|
3993
|
+
const node = _optionalChain([nodes, 'access', _106 => _106.find, 'call', _107 => _107((e) => e.node.id === id), 'optionalAccess', _108 => _108.node]);
|
|
3994
|
+
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _109 => _109.effects]), () => ( []))) {
|
|
3756
3995
|
const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
|
|
3757
3996
|
if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
|
|
3758
3997
|
}
|
|
@@ -3777,11 +4016,11 @@ function motionCommandRows(scene, shotId) {
|
|
|
3777
4016
|
return scene.shots[index].run.map((command2, i) => {
|
|
3778
4017
|
const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
|
|
3779
4018
|
const primitive = motionFlairPrimitive(command2);
|
|
3780
|
-
return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess',
|
|
4019
|
+
return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _110 => _110.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _111 => _111.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
|
|
3781
4020
|
});
|
|
3782
4021
|
}
|
|
3783
4022
|
function duplicateMotionCommandEdit(scene, shot, command2) {
|
|
3784
|
-
const run = _nullishCoalesce(_optionalChain([scene, 'access',
|
|
4023
|
+
const run = _nullishCoalesce(_optionalChain([scene, 'access', _112 => _112.shots, 'access', _113 => _113.find, 'call', _114 => _114((s) => s.id === shot), 'optionalAccess', _115 => _115.run]), () => ( []));
|
|
3785
4024
|
return { op: "add_commands", shot, commands: run[command2] ? [structuredClone(run[command2])] : [], at: command2 + 1 };
|
|
3786
4025
|
}
|
|
3787
4026
|
var MOTION_EASE_CHOICES = [
|
|
@@ -3866,7 +4105,7 @@ function motionCueFromKey(key) {
|
|
|
3866
4105
|
function motionCueChoices(scene, limit = 256) {
|
|
3867
4106
|
const choices = [];
|
|
3868
4107
|
const s = (ms) => `${(ms / 1e3).toFixed(2)} s`;
|
|
3869
|
-
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access',
|
|
4108
|
+
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _116 => _116.narration, 'optionalAccess', _117 => _117.words, 'access', _118 => _118.map, 'call', _119 => _119((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
|
|
3870
4109
|
if (scene.beat && scene.beat.bpm > 0) {
|
|
3871
4110
|
for (let beat = 0; choices.length < limit; beat++) {
|
|
3872
4111
|
const time = motionBeatTime(scene.beat, beat);
|
|
@@ -3876,7 +4115,7 @@ function motionCueChoices(scene, limit = 256) {
|
|
|
3876
4115
|
choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
|
|
3877
4116
|
}
|
|
3878
4117
|
}
|
|
3879
|
-
_optionalChain([scene, 'access',
|
|
4118
|
+
_optionalChain([scene, 'access', _120 => _120.narration, 'optionalAccess', _121 => _121.words, 'access', _122 => _122.forEach, 'call', _123 => _123((w, i) => {
|
|
3880
4119
|
if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
|
|
3881
4120
|
})]);
|
|
3882
4121
|
return choices;
|
|
@@ -3885,7 +4124,7 @@ function motionShotCueTime(scene, cue) {
|
|
|
3885
4124
|
return cue ? motionCueTime(scene, cue) : void 0;
|
|
3886
4125
|
}
|
|
3887
4126
|
function formatMotionNarration(narration) {
|
|
3888
|
-
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess',
|
|
4127
|
+
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _124 => _124.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
|
|
3889
4128
|
}
|
|
3890
4129
|
function parseMotionNarration(text) {
|
|
3891
4130
|
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
@@ -4020,5 +4259,10 @@ function parseMotionNarration(text) {
|
|
|
4020
4259
|
|
|
4021
4260
|
|
|
4022
4261
|
|
|
4023
|
-
|
|
4262
|
+
|
|
4263
|
+
|
|
4264
|
+
|
|
4265
|
+
|
|
4266
|
+
|
|
4267
|
+
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_CLIP_TARGET = MOTION_CLIP_TARGET; 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_CHOICES = MOTION_EASE_CHOICES; 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_SPEED_RANGE = MOTION_SPEED_RANGE; exports.MOTION_SPLIT_ORIENTATIONS = MOTION_SPLIT_ORIENTATIONS; exports.MOTION_TRIGGERS = MOTION_TRIGGERS; exports.MotionSceneFormatError = MotionSceneFormatError; exports.activeSegment = activeSegment; exports.applyMotionControlValues = applyMotionControlValues; exports.applyMotionEdits = applyMotionEdits; exports.checkMotionScene = checkMotionScene; exports.clipsShapeProblems = clipsShapeProblems; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createMotionScene = createMotionScene; exports.defaultMotionCommand = defaultMotionCommand; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.duplicateMotionCommandEdit = duplicateMotionCommandEdit; exports.fitMotionRect = fitMotionRect; exports.fitMotionScene = fitMotionScene; exports.fitMotionSceneEdits = fitMotionSceneEdits; exports.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.formatMotionNarration = formatMotionNarration; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.highlightMotionSvg = highlightMotionSvg; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionClipAttrs = motionClipAttrs; exports.motionClipLayout = motionClipLayout; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandFields = motionCommandFields; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCommandRows = motionCommandRows; exports.motionCommandSummary = motionCommandSummary; exports.motionCueChoices = motionCueChoices; exports.motionCueFromKey = motionCueFromKey; exports.motionCueKey = motionCueKey; exports.motionCueTime = motionCueTime; exports.motionCycleDuration = motionCycleDuration; exports.motionEaseKey = motionEaseKey; exports.motionEasingCurve = motionEasingCurve; exports.motionEasingGuides = motionEasingGuides; exports.motionEasingPath = motionEasingPath; exports.motionFieldEdit = motionFieldEdit; exports.motionFieldLabel = motionFieldLabel; exports.motionFlairPrimitive = motionFlairPrimitive; exports.motionFollowRoute = motionFollowRoute; exports.motionFrameAt = motionFrameAt; exports.motionFrameToSvg = motionFrameToSvg; exports.motionGhosts = motionGhosts; exports.motionIssue = motionIssue; exports.motionIssueKey = motionIssueKey; exports.motionIssueLine = motionIssueLine; exports.motionMovingIds = motionMovingIds; exports.motionNodeAtElement = motionNodeAtElement; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionPath = motionPath; exports.motionPathLength = motionPathLength; exports.motionPathsSvg = motionPathsSvg; exports.motionRestValue = motionRestValue; exports.motionRevealClip = motionRevealClip; exports.motionRevealPadding = motionRevealPadding; exports.motionRulerTicks = motionRulerTicks; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionShotCueTime = motionShotCueTime; exports.motionShotTimeScale = motionShotTimeScale; exports.motionStageSvg = motionStageSvg; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = namedWithSuggestion; exports.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.smoothMotionLegs = smoothMotionLegs; exports.smoothMotionTimes = smoothMotionTimes; exports.suggestName = suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
|
|
4024
4268
|
//# sourceMappingURL=index.cjs.map
|