@pixerate/editor 0.67.0 → 0.68.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 +112 -51
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +46 -5
- package/dist/animation-editor/index.d.ts +46 -5
- package/dist/animation-editor/index.js +70 -9
- package/dist/animation-editor/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -222,7 +222,7 @@ var COMMAND_KEYS = {
|
|
|
222
222
|
enter: [...BASE_KEYS, "style", "direction", "distance", "scale", "shape", "orientation"],
|
|
223
223
|
exit: [...BASE_KEYS, "style", "direction", "distance"],
|
|
224
224
|
draw: [...BASE_KEYS, "from", "to"],
|
|
225
|
-
move: [...BASE_KEYS, "by", "to", "blend"],
|
|
225
|
+
move: [...BASE_KEYS, "by", "to", "via", "pacing", "blend"],
|
|
226
226
|
rotate: [...BASE_KEYS, "by", "to", "blend"],
|
|
227
227
|
scale: [...BASE_KEYS, "to", "geometric", "blend"],
|
|
228
228
|
fade: [...BASE_KEYS, "to"],
|
|
@@ -303,6 +303,9 @@ function commandShapeProblems(command2, where) {
|
|
|
303
303
|
if (command2.by !== void 0 && command2.to !== void 0) p(`give "by" or "to", not both.`);
|
|
304
304
|
if (command2.by !== void 0 && !isPoint(command2.by)) p(`"by" must be { "x": number, "y": number }.`);
|
|
305
305
|
if (command2.to !== void 0 && !isPoint(command2.to)) p(`"to" must be { "x": number, "y": number }.`);
|
|
306
|
+
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).`);
|
|
307
|
+
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).`);
|
|
308
|
+
if (command2.pacing !== void 0 && command2.via === void 0) p(`"pacing" goes with "via".`);
|
|
306
309
|
break;
|
|
307
310
|
case "rotate":
|
|
308
311
|
if (command2.by === void 0 && command2.to === void 0) p(`give "by" or "to" (degrees).`);
|
|
@@ -503,6 +506,45 @@ function matchMotionNodes(from, into) {
|
|
|
503
506
|
return out;
|
|
504
507
|
}
|
|
505
508
|
|
|
509
|
+
// src/animation-editor/smooth.ts
|
|
510
|
+
function smoothMotionLegs(times, values) {
|
|
511
|
+
const n = values.length;
|
|
512
|
+
const slope = new Array(n).fill(0);
|
|
513
|
+
const secant = (i) => (values[i + 1] - values[i]) / Math.max(1e-9, times[i + 1] - times[i]);
|
|
514
|
+
for (let i = 1; i < n - 1; i++) {
|
|
515
|
+
const a = secant(i - 1);
|
|
516
|
+
const b = secant(i);
|
|
517
|
+
if (a * b <= 0) continue;
|
|
518
|
+
const ha = times[i] - times[i - 1];
|
|
519
|
+
const hb = times[i + 1] - times[i];
|
|
520
|
+
slope[i] = 3 * (ha + hb) / ((2 * hb + ha) / a + (hb + 2 * ha) / b);
|
|
521
|
+
}
|
|
522
|
+
const legs = [];
|
|
523
|
+
for (let i = 0; i + 1 < n; i++) {
|
|
524
|
+
const dt = times[i + 1] - times[i];
|
|
525
|
+
const dv = values[i + 1] - values[i];
|
|
526
|
+
if (Math.abs(dv) < 1e-9) {
|
|
527
|
+
legs.push({ start: times[i], end: times[i + 1], from: values[i], to: values[i + 1], ease: "linear" });
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
const y1 = slope[i] * dt / (3 * dv);
|
|
531
|
+
const y2 = 1 - slope[i + 1] * dt / (3 * dv);
|
|
532
|
+
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 } });
|
|
533
|
+
}
|
|
534
|
+
return legs;
|
|
535
|
+
}
|
|
536
|
+
function smoothMotionTimes(points, start, duration, pacing = "even") {
|
|
537
|
+
const legs = points.slice(1).map((p, i) => pacing === "equal" ? 1 : Math.hypot(p.x - points[i].x, p.y - points[i].y));
|
|
538
|
+
const total = legs.reduce((a, b) => a + b, 0) || legs.length || 1;
|
|
539
|
+
const times = [start];
|
|
540
|
+
let acc = 0;
|
|
541
|
+
for (const l of legs) {
|
|
542
|
+
acc += total > 0 ? l : 1;
|
|
543
|
+
times.push(start + duration * acc / total);
|
|
544
|
+
}
|
|
545
|
+
return times;
|
|
546
|
+
}
|
|
547
|
+
|
|
506
548
|
// src/animation-editor/compile.ts
|
|
507
549
|
var indexCache = /* @__PURE__ */ new WeakMap();
|
|
508
550
|
function indexMotionNodes(nodes) {
|
|
@@ -764,6 +806,7 @@ function motionCycleDuration(command2, scene, target) {
|
|
|
764
806
|
const ms = length * MOTION_DRAW_MS_PER_UNIT;
|
|
765
807
|
return Math.round(Math.min(MOTION_DRAW_RANGE[1], Math.max(MOTION_DRAW_RANGE[0], ms)));
|
|
766
808
|
}
|
|
809
|
+
if (command2.type === "move" && _optionalChain([command2, 'access', _22 => _22.via, 'optionalAccess', _23 => _23.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command2.via.length;
|
|
767
810
|
return MOTION_DEFAULT_DURATIONS[command2.type];
|
|
768
811
|
}
|
|
769
812
|
var MOTION_EASE_OUT = { type: "cubic-bezier", x1: 1 / 3, y1: 1, x2: 2 / 3, y2: 1 };
|
|
@@ -892,7 +935,7 @@ function compileMotionScene(scene) {
|
|
|
892
935
|
const style = _nullishCoalesce(command2.style, () => ( "fade"));
|
|
893
936
|
const opacity = rest("opacity");
|
|
894
937
|
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',
|
|
938
|
+
for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _24 => _24.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
|
|
896
939
|
if (reveal) {
|
|
897
940
|
seg("opacity", opacity, "linear", start, start);
|
|
898
941
|
seg(reveal.property, reveal.to, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: reveal.from });
|
|
@@ -954,14 +997,28 @@ function compileMotionScene(scene) {
|
|
|
954
997
|
}
|
|
955
998
|
case "move": {
|
|
956
999
|
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
957
|
-
let dx = _nullishCoalesce(_optionalChain([command2, 'access',
|
|
958
|
-
let dy = _nullishCoalesce(_optionalChain([command2, 'access',
|
|
1000
|
+
let dx = _nullishCoalesce(_optionalChain([command2, 'access', _25 => _25.by, 'optionalAccess', _26 => _26.x]), () => ( 0));
|
|
1001
|
+
let dy = _nullishCoalesce(_optionalChain([command2, 'access', _27 => _27.by, 'optionalAccess', _28 => _28.y]), () => ( 0));
|
|
959
1002
|
if (command2.to) {
|
|
960
1003
|
const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
|
|
961
1004
|
const target = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, command2.to);
|
|
962
1005
|
dx = target.x - (entry.center.x + num("x"));
|
|
963
1006
|
dy = target.y - (entry.center.y + num("y"));
|
|
964
1007
|
}
|
|
1008
|
+
if (_optionalChain([command2, 'access', _29 => _29.via, 'optionalAccess', _30 => _30.length])) {
|
|
1009
|
+
const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
|
|
1010
|
+
const x0 = num("x");
|
|
1011
|
+
const y0 = num("y");
|
|
1012
|
+
const add = command2.blend === "add";
|
|
1013
|
+
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 }];
|
|
1014
|
+
const times = smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(command2.pacing, () => ( "even")));
|
|
1015
|
+
for (const axis of ["x", "y"]) {
|
|
1016
|
+
const base = add ? 0 : axis === "x" ? x0 : y0;
|
|
1017
|
+
for (const leg of smoothMotionLegs(times, offsets.map((o) => o[axis])))
|
|
1018
|
+
seg(axis, base + leg.to, leg.ease, leg.start, leg.end, { from: base + leg.from, ...add ? { blend: "add" } : {} });
|
|
1019
|
+
}
|
|
1020
|
+
break;
|
|
1021
|
+
}
|
|
965
1022
|
if (command2.blend === "add") {
|
|
966
1023
|
seg("x", dx, e, start, end, { from: 0, blend: "add" });
|
|
967
1024
|
seg("y", dy, e, start, end, { from: 0, blend: "add" });
|
|
@@ -1059,7 +1116,7 @@ var MOTION_DRAW_EFFECT_ID = "~draw";
|
|
|
1059
1116
|
var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
|
|
1060
1117
|
var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
|
|
1061
1118
|
function applyMotionControlValues(scene, values) {
|
|
1062
|
-
if (!values || !_optionalChain([scene, 'access',
|
|
1119
|
+
if (!values || !_optionalChain([scene, 'access', _31 => _31.controls, 'optionalAccess', _32 => _32.length])) return scene;
|
|
1063
1120
|
const map = /* @__PURE__ */ new Map();
|
|
1064
1121
|
for (const control of scene.controls) {
|
|
1065
1122
|
const value = values[control.name];
|
|
@@ -1105,7 +1162,7 @@ function shapeIn(entry, shape) {
|
|
|
1105
1162
|
}
|
|
1106
1163
|
function shapeAt(entry, timeline, nodes, time) {
|
|
1107
1164
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
|
|
1108
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
1165
|
+
if (!_optionalChain([track, 'optionalAccess', _33 => _33.length])) return null;
|
|
1109
1166
|
const s = activeSegment(track, time);
|
|
1110
1167
|
const fromId = String(s ? s.from : track[0].from);
|
|
1111
1168
|
if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
|
|
@@ -1128,8 +1185,8 @@ function motionFollowRoute(entry, path) {
|
|
|
1128
1185
|
}
|
|
1129
1186
|
function followAt(entry, timeline, nodes, time) {
|
|
1130
1187
|
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',
|
|
1188
|
+
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _34 => _34[0]])));
|
|
1189
|
+
if (!_optionalChain([s, 'optionalAccess', _35 => _35.path])) return null;
|
|
1133
1190
|
const route = motionFollowRoute(entry, nodes.get(s.path));
|
|
1134
1191
|
const progress = Number(trackValue(track, time));
|
|
1135
1192
|
if (!route || !(progress >= 0)) return null;
|
|
@@ -1189,7 +1246,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1189
1246
|
if (out.visible === void 0) delete out.visible;
|
|
1190
1247
|
}
|
|
1191
1248
|
const effectTracks = [...timeline.tracks.keys()].filter((k) => k.startsWith(`${id}\0effect:`));
|
|
1192
|
-
if (effectTracks.length && _optionalChain([out, 'access',
|
|
1249
|
+
if (effectTracks.length && _optionalChain([out, 'access', _36 => _36.effects, 'optionalAccess', _37 => _37.length])) {
|
|
1193
1250
|
out = {
|
|
1194
1251
|
...out,
|
|
1195
1252
|
effects: out.effects.map((effect) => {
|
|
@@ -1302,7 +1359,7 @@ function motionPath(scene, id, options = {}) {
|
|
|
1302
1359
|
const r = (n) => Math.round(n * 100) / 100;
|
|
1303
1360
|
const centreAt = (t) => {
|
|
1304
1361
|
const node = indexMotionNodes(motionFrameAtCache(scene, t)).get(id);
|
|
1305
|
-
const b = _optionalChain([node, 'optionalAccess',
|
|
1362
|
+
const b = _optionalChain([node, 'optionalAccess', _38 => _38.bounds]);
|
|
1306
1363
|
return b ? { t: r(t), x: r(b.x + b.width / 2), y: r(b.y + b.height / 2) } : null;
|
|
1307
1364
|
};
|
|
1308
1365
|
const points = [];
|
|
@@ -1342,14 +1399,14 @@ function motionStageSvg(scene, time, options = {}) {
|
|
|
1342
1399
|
const open = current.indexOf(">") + 1;
|
|
1343
1400
|
const close = current.lastIndexOf("</svg>");
|
|
1344
1401
|
const body = current.slice(open, close);
|
|
1345
|
-
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access',
|
|
1402
|
+
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _39 => _39.exec, 'call', _40 => _40(body), 'optionalAccess', _41 => _41[0]]), () => ( "")) : "";
|
|
1346
1403
|
return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
|
|
1347
1404
|
}
|
|
1348
1405
|
|
|
1349
1406
|
// src/animation-editor/check.ts
|
|
1350
1407
|
var MOTION_MIN_CHANGE_MS = 120;
|
|
1351
1408
|
var NUMERIC_PARAMS = (node, effectId) => {
|
|
1352
|
-
const effect = _optionalChain([node, 'access',
|
|
1409
|
+
const effect = _optionalChain([node, 'access', _42 => _42.effects, 'optionalAccess', _43 => _43.find, 'call', _44 => _44((e) => e.id === effectId)]);
|
|
1353
1410
|
if (!effect) return null;
|
|
1354
1411
|
return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
|
|
1355
1412
|
};
|
|
@@ -1501,7 +1558,7 @@ function checkMotionScene(scene) {
|
|
|
1501
1558
|
if (scene.trigger) {
|
|
1502
1559
|
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
1560
|
if (scene.trigger === "click") {
|
|
1504
|
-
if (scene.shots.length === 1) issues.push(motionIssue("click-one-shot", "The scene plays on click but has one shot, so every click replays it from the start; split it into shots (
|
|
1561
|
+
if (scene.shots.length === 1) issues.push(motionIssue("click-one-shot", "The scene plays on click but has one shot, so every click replays it from the start; split it into shots (each click plays the next one).", { shot: scene.shots[0].id }));
|
|
1505
1562
|
scene.shots.forEach((shot, i) => {
|
|
1506
1563
|
if (i > 0 && shot.at) issues.push(motionIssue("click-cue", `Shot "${shot.id}" is cued, but on click a shot starts when it is clicked to; remove its "at" or the trigger.`, { shot: shot.id }));
|
|
1507
1564
|
});
|
|
@@ -1511,7 +1568,7 @@ function checkMotionScene(scene) {
|
|
|
1511
1568
|
if (!shot.at) return;
|
|
1512
1569
|
const timing = timeline.shots[i];
|
|
1513
1570
|
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',
|
|
1571
|
+
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', _45 => _45.narration, 'optionalAccess', _46 => _46.words, 'access', _47 => _47.length]), () => ( 0))} words (indexes from 0)`;
|
|
1515
1572
|
issues.push(motionIssue("unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
|
|
1516
1573
|
} else if (timing.missedBy !== void 0) {
|
|
1517
1574
|
const late = Math.round(timing.missedBy);
|
|
@@ -1544,7 +1601,7 @@ function checkMotionScene(scene) {
|
|
|
1544
1601
|
const cam = frame.camera;
|
|
1545
1602
|
const docIndex = indexMotionNodes(frame.document.nodes);
|
|
1546
1603
|
for (const id of command2.targets) {
|
|
1547
|
-
const b = _optionalChain([docIndex, 'access',
|
|
1604
|
+
const b = _optionalChain([docIndex, 'access', _48 => _48.get, 'call', _49 => _49(id), 'optionalAccess', _50 => _50.bounds]);
|
|
1548
1605
|
if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
|
|
1549
1606
|
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
1607
|
if (outside) {
|
|
@@ -1750,9 +1807,9 @@ function applyMotionEdits(scene, edits) {
|
|
|
1750
1807
|
let next = scene;
|
|
1751
1808
|
for (let i = 0; i < list.length; i++) {
|
|
1752
1809
|
const edit = list[i];
|
|
1753
|
-
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess',
|
|
1810
|
+
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _51 => _51.op])}): ` : "";
|
|
1754
1811
|
if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
|
|
1755
|
-
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess',
|
|
1812
|
+
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _52 => _52.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
|
|
1756
1813
|
try {
|
|
1757
1814
|
next = applyOne(next, edit);
|
|
1758
1815
|
} catch (error) {
|
|
@@ -1912,7 +1969,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1912
1969
|
const wrapper = freshId(`${id}--follow`);
|
|
1913
1970
|
const centre = freshId(`${id}--follow-centre`);
|
|
1914
1971
|
const c = entry.center;
|
|
1915
|
-
const at = _optionalChain([motionNodeOffset, 'call',
|
|
1972
|
+
const at = _optionalChain([motionNodeOffset, 'call', _53 => _53(entry, timeline, 0, nodes), 'optionalAccess', _54 => _54.follow]);
|
|
1916
1973
|
const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
|
|
1917
1974
|
(wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
|
|
1918
1975
|
follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
|
|
@@ -1972,7 +2029,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1972
2029
|
exact: () => false,
|
|
1973
2030
|
value: (t) => {
|
|
1974
2031
|
const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
|
|
1975
|
-
const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call',
|
|
2032
|
+
const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _55 => _55(frame.document.nodes), 'access', _56 => _56.get, 'call', _57 => _57(id), 'optionalAccess', _58 => _58.node]));
|
|
1976
2033
|
if (!now || now.type !== "path") return "";
|
|
1977
2034
|
const bezier = _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, now, _chunkYJLCBA7Vcjs.IDENTITY_MATRIX, { effects: false }), inverse);
|
|
1978
2035
|
return _chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
|
|
@@ -1993,8 +2050,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1993
2050
|
...delay > 0 ? { delay: round2(delay) } : {},
|
|
1994
2051
|
ms: round2(ms),
|
|
1995
2052
|
ease: written,
|
|
1996
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
1997
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
2053
|
+
..._optionalChain([segment, 'optionalAccess', _59 => _59.behavior]) ? { behavior: segment.behavior } : {},
|
|
2054
|
+
..._optionalChain([segment, 'optionalAccess', _60 => _60.steps]) ? { strobe: segment.steps } : {}
|
|
1998
2055
|
};
|
|
1999
2056
|
if (channel.kind === "view") animate.push({ ...base, view: to });
|
|
2000
2057
|
else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
|
|
@@ -2065,7 +2122,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2065
2122
|
animate.sort((x, y) => (_nullishCoalesce(x.delay, () => ( 0))) - (_nullishCoalesce(y.delay, () => ( 0))));
|
|
2066
2123
|
const lastChange = animate.reduce((m, a) => Math.max(m, (_nullishCoalesce(a.delay, () => ( 0))) + (_nullishCoalesce(a.ms, () => ( 0)))), 0);
|
|
2067
2124
|
const trigger = options.trigger === null ? void 0 : _nullishCoalesce(options.trigger, () => ( scene.trigger));
|
|
2068
|
-
if (trigger === "click" && timeline.shots.length
|
|
2125
|
+
if (trigger === "click" && timeline.shots.length) {
|
|
2069
2126
|
for (const a of animate) {
|
|
2070
2127
|
const at = _nullishCoalesce(a.delay, () => ( 0));
|
|
2071
2128
|
let step = 0;
|
|
@@ -2075,7 +2132,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2075
2132
|
const delay = round2(at - timeline.shots[step].start);
|
|
2076
2133
|
delete a.delay;
|
|
2077
2134
|
if (delay > 0) a.delay = delay;
|
|
2078
|
-
|
|
2135
|
+
a.step = step + 1;
|
|
2079
2136
|
}
|
|
2080
2137
|
animate.sort((x, y) => (_nullishCoalesce(x.step, () => ( 0))) - (_nullishCoalesce(y.step, () => ( 0))) || (_nullishCoalesce(x.delay, () => ( 0))) - (_nullishCoalesce(y.delay, () => ( 0))));
|
|
2081
2138
|
}
|
|
@@ -2083,7 +2140,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2083
2140
|
let svg = _chunkYJLCBA7Vcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
|
|
2084
2141
|
if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
|
|
2085
2142
|
let motion = { svg, animate };
|
|
2086
|
-
if (_optionalChain([scene, 'access',
|
|
2143
|
+
if (_optionalChain([scene, 'access', _61 => _61.controls, 'optionalAccess', _62 => _62.length])) {
|
|
2087
2144
|
const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
|
|
2088
2145
|
const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
|
|
2089
2146
|
svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
|
|
@@ -2105,7 +2162,7 @@ function toFlairVectorEffect(scene, options = {}) {
|
|
|
2105
2162
|
tags: _nullishCoalesce(options.tags, () => ( [])),
|
|
2106
2163
|
motion: out.motion,
|
|
2107
2164
|
hold: out.hold,
|
|
2108
|
-
..._optionalChain([scene, 'access',
|
|
2165
|
+
..._optionalChain([scene, 'access', _63 => _63.presets, 'optionalAccess', _64 => _64.length]) ? { presets: scene.presets } : {},
|
|
2109
2166
|
...out.trigger ? { trigger: out.trigger } : {}
|
|
2110
2167
|
};
|
|
2111
2168
|
}
|
|
@@ -2149,7 +2206,7 @@ function resolvePlaceholders(motion, notes) {
|
|
|
2149
2206
|
const filled = text.replace(PLACEHOLDER, (_, name) => {
|
|
2150
2207
|
const d = declared.get(name);
|
|
2151
2208
|
if (!d) unknown.add(name);
|
|
2152
|
-
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess',
|
|
2209
|
+
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _65 => _65.value]), () => ( ""))).replace(/"/g, '\\"');
|
|
2153
2210
|
});
|
|
2154
2211
|
for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
|
|
2155
2212
|
return { motion: JSON.parse(filled), controls };
|
|
@@ -2203,7 +2260,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2203
2260
|
if (anim.along) {
|
|
2204
2261
|
const path = nodes.get(anim.along);
|
|
2205
2262
|
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',
|
|
2263
|
+
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _66 => _66.at, 'optionalAccess', _67 => _67[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _68 => _68.at, 'optionalAccess', _69 => _69[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2207
2264
|
}
|
|
2208
2265
|
for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
|
|
2209
2266
|
if (attr === "opacity") {
|
|
@@ -2214,7 +2271,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2214
2271
|
out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
|
|
2215
2272
|
} else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2216
2273
|
} else if (attr === "fill" || attr === "stroke") {
|
|
2217
|
-
if (_optionalChain([behavior, 'optionalAccess',
|
|
2274
|
+
if (_optionalChain([behavior, 'optionalAccess', _70 => _70.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
|
|
2218
2275
|
else {
|
|
2219
2276
|
if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
|
|
2220
2277
|
out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
@@ -2260,7 +2317,8 @@ function fromFlairSvgMotion(input, options = {}) {
|
|
|
2260
2317
|
const nodes = indexMotionNodes(artwork.nodes);
|
|
2261
2318
|
const byStep = /* @__PURE__ */ new Map();
|
|
2262
2319
|
for (const anim of _nullishCoalesce(motion.animate, () => ( []))) {
|
|
2263
|
-
const
|
|
2320
|
+
const raw = Math.max(0, Math.floor(_nullishCoalesce(anim.step, () => ( 0))));
|
|
2321
|
+
const step = options.clickSteps ? Math.max(1, raw) : raw;
|
|
2264
2322
|
if (!byStep.has(step)) byStep.set(step, []);
|
|
2265
2323
|
byStep.get(step).push(anim);
|
|
2266
2324
|
}
|
|
@@ -2311,7 +2369,7 @@ function presetColor(value) {
|
|
|
2311
2369
|
}
|
|
2312
2370
|
function fromFlairVectorEffect(effect, options = {}) {
|
|
2313
2371
|
if (!effect || effect.kind !== "vector" || !effect.motion) throw new Error('Give a Flair vector effect: { kind: "vector", id, name, motion: { svg, animate } }.');
|
|
2314
|
-
const result = fromFlairSvgMotion(effect.motion, { name: _nullishCoalesce(_nullishCoalesce(options.name, () => ( effect.id)), () => ( effect.name)), hold: _nullishCoalesce(options.hold, () => ( effect.hold)) });
|
|
2372
|
+
const result = fromFlairSvgMotion(effect.motion, { name: _nullishCoalesce(_nullishCoalesce(options.name, () => ( effect.id)), () => ( effect.name)), hold: _nullishCoalesce(options.hold, () => ( effect.hold)), ...effect.trigger === "click" ? { clickSteps: true } : {} });
|
|
2315
2373
|
const names = new Set((_nullishCoalesce(result.scene.controls, () => ( []))).map((c) => c.name));
|
|
2316
2374
|
const presets = (_nullishCoalesce(effect.presets, () => ( []))).map((p) => ({ name: p.name, values: Object.fromEntries(Object.entries(p.values).flatMap(([k, v]) => names.has(k) && presetColor(v) ? [[k, presetColor(v)]] : [])) })).filter((p) => Object.keys(p.values).length);
|
|
2317
2375
|
const scene = { ...result.scene, ...effect.description ? { description: effect.description } : {}, ...presets.length ? { presets } : {}, ...effect.trigger ? { trigger: effect.trigger } : {} };
|
|
@@ -2496,7 +2554,7 @@ function toLottie(scene, options = {}) {
|
|
|
2496
2554
|
const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
|
|
2497
2555
|
const geometryAt = (t) => {
|
|
2498
2556
|
if (!shapeSegments.length) return _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2499
|
-
const now = _optionalChain([indexMotionNodes, 'call',
|
|
2557
|
+
const now = _optionalChain([indexMotionNodes, 'call', _71 => _71(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _72 => _72.get, 'call', _73 => _73(path.id), 'optionalAccess', _74 => _74.node]);
|
|
2500
2558
|
return now && now.type === "path" ? _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2501
2559
|
};
|
|
2502
2560
|
const rest = lottieContours(_chunkO2UH7LZEcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
|
|
@@ -2542,7 +2600,7 @@ function toLottie(scene, options = {}) {
|
|
|
2542
2600
|
lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
|
|
2543
2601
|
ml: 4
|
|
2544
2602
|
});
|
|
2545
|
-
if (_optionalChain([path, 'access',
|
|
2603
|
+
if (_optionalChain([path, 'access', _75 => _75.strokeDasharray, 'optionalAccess', _76 => _76.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
|
|
2546
2604
|
if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
|
|
2547
2605
|
}
|
|
2548
2606
|
const fill = paintOf(path.fill, "fill", path.id);
|
|
@@ -2693,7 +2751,7 @@ var AnimationEditorController = (_class = class {
|
|
|
2693
2751
|
time: p.time,
|
|
2694
2752
|
playing: p.playing,
|
|
2695
2753
|
loop: p.loop,
|
|
2696
|
-
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call',
|
|
2754
|
+
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _77 => _77(timeline, p.time), 'optionalAccess', _78 => _78.id]), () => ( null)),
|
|
2697
2755
|
selection: this.selection,
|
|
2698
2756
|
readOnly: this.readOnly,
|
|
2699
2757
|
error: this.error,
|
|
@@ -2732,7 +2790,7 @@ var AnimationEditorController = (_class = class {
|
|
|
2732
2790
|
this.applying = false;
|
|
2733
2791
|
}
|
|
2734
2792
|
this.notify();
|
|
2735
|
-
_optionalChain([this, 'access',
|
|
2793
|
+
_optionalChain([this, 'access', _79 => _79.onChange, 'optionalCall', _80 => _80(scene)]);
|
|
2736
2794
|
}
|
|
2737
2795
|
commit(label, next) {
|
|
2738
2796
|
const before = this.scene;
|
|
@@ -2936,7 +2994,7 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
2936
2994
|
distance: { type: "number", description: "For slide: document units (default 40)." }
|
|
2937
2995
|
}),
|
|
2938
2996
|
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).") }),
|
|
2939
|
-
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.") }),
|
|
2997
|
+
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.") }),
|
|
2940
2998
|
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." } }),
|
|
2941
2999
|
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"]),
|
|
2942
3000
|
command("fade", "Changes opacity.", { to: FRACTION("Opacity at the end (0\u20131).") }, ["to"]),
|
|
@@ -3025,7 +3083,7 @@ var SETTINGS = {
|
|
|
3025
3083
|
loop: { type: "string", enum: ["none", "loop", "ping-pong"], description: "Playback past the end (default none)." },
|
|
3026
3084
|
trigger: {
|
|
3027
3085
|
anyOf: [{ type: "string", enum: ["click", "hover", "press", "scroll"] }, { type: "null" }],
|
|
3028
|
-
description: "Play in answer to the viewer when exported to Flair: click (
|
|
3086
|
+
description: "Play in answer to the viewer when exported to Flair: click (nothing plays until a click; each click plays the next shot, then the first again), hover or press (plays while the pointer is over or down, rewinds when it leaves), scroll (scrubs as it scrolls past). null plays on its own (default). The editor previews it played through."
|
|
3029
3087
|
},
|
|
3030
3088
|
fps: { type: "number", minimum: 1, maximum: 120, description: "Sampling rate for exports (default 30)." },
|
|
3031
3089
|
steps: { anyOf: [{ type: "number", exclusiveMinimum: 0, maximum: 120 }, { type: "null" }], description: 'Stepped time for every command without its own: changes hold on a grid of this many frames per second (12 = "on twos" at 24 fps) for a hand-drawn look; null makes it smooth again (default).' },
|
|
@@ -3254,9 +3312,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3254
3312
|
handler: ({ from = 0, to, limit = 200 }) => {
|
|
3255
3313
|
const s = scene();
|
|
3256
3314
|
const timeline = compileMotionScene(s);
|
|
3257
|
-
const words = _nullishCoalesce(_optionalChain([s, 'access',
|
|
3315
|
+
const words = _nullishCoalesce(_optionalChain([s, 'access', _81 => _81.narration, 'optionalAccess', _82 => _82.words]), () => ( []));
|
|
3258
3316
|
const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
|
|
3259
|
-
const shotAt = (ms) => _optionalChain([timeline, 'access',
|
|
3317
|
+
const shotAt = (ms) => _optionalChain([timeline, 'access', _83 => _83.shots, 'access', _84 => _84.find, 'call', _85 => _85((x) => ms >= x.start && ms < x.end), 'optionalAccess', _86 => _86.id]);
|
|
3260
3318
|
const beats = [];
|
|
3261
3319
|
if (s.beat && s.beat.bpm > 0) {
|
|
3262
3320
|
const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
|
|
@@ -3444,7 +3502,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3444
3502
|
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"]),
|
|
3445
3503
|
annotations: { title: "Add commands to a shot", ...WRITE },
|
|
3446
3504
|
handler: ({ shot, commands, at }) => {
|
|
3447
|
-
const before = _nullishCoalesce(_optionalChain([scene, 'call',
|
|
3505
|
+
const before = _nullishCoalesce(_optionalChain([scene, 'call', _87 => _87(), 'access', _88 => _88.shots, 'access', _89 => _89.find, 'call', _90 => _90((s) => s.id === shot), 'optionalAccess', _91 => _91.run, 'access', _92 => _92.length]), () => ( 0));
|
|
3448
3506
|
const first = _nullishCoalesce(at, () => ( before));
|
|
3449
3507
|
return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
|
|
3450
3508
|
const shots = describeMotionShots(s);
|
|
@@ -3606,6 +3664,7 @@ Commands
|
|
|
3606
3664
|
- enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.
|
|
3607
3665
|
- 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.
|
|
3608
3666
|
- 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.
|
|
3667
|
+
- 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.
|
|
3609
3668
|
- enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting "scale".
|
|
3610
3669
|
- 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).
|
|
3611
3670
|
- 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).
|
|
@@ -3621,7 +3680,7 @@ Working method
|
|
|
3621
3680
|
1. get_animation to learn the element ids (set_animation_artwork_svg first if there is no artwork: give every element you will animate an id; or import_flair_effect to start from a Flair effect and edit it).
|
|
3622
3681
|
2. Plan a few shots, each one idea. Add them with insert_shots (add_commands, update_command, move_command and delete_commands refine a shot), or edit_animation to make several edits as one step (dry_run first when unsure).
|
|
3623
3682
|
3. To hit a length, fit_animation (keep the shots whose pace matters). check_animation and fix every error and warning; render_animation_frame (shot + "end") to look at the result; add onion_skin or motion_paths to see the motion in one picture, or get_motion_path for the numbers.
|
|
3624
|
-
- For something the viewer plays (a button, a toggle, a step-by-step explainer), set "trigger" with set_animation_settings: click plays the next shot on each click (make the last shot
|
|
3683
|
+
- For something the viewer plays (a button, a toggle, a step-by-step explainer), set "trigger" with set_animation_settings: click plays the next shot on each click and then starts over (make the last shot put things back for a toggle), hover or press plays and rewinds, scroll scrubs.
|
|
3625
3684
|
4. To make a reusable Flair effect, set_animation_controls (colour controls stand for every use of their default colour) and export_flair_effect.
|
|
3626
3685
|
|
|
3627
3686
|
Keep motion purposeful: one thing moving at a time reads best, ease-out for arrivals, ease-in for exits, and hold long enough to see each result.`;
|
|
@@ -3631,7 +3690,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
|
|
|
3631
3690
|
var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
|
|
3632
3691
|
var NODES = /* @__PURE__ */ new Set(["into", "path"]);
|
|
3633
3692
|
function branch(type) {
|
|
3634
|
-
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access',
|
|
3693
|
+
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _93 => _93.properties, 'optionalAccess', _94 => _94.type, 'optionalAccess', _95 => _95.const]) === type);
|
|
3635
3694
|
}
|
|
3636
3695
|
function unitOf(type, name) {
|
|
3637
3696
|
if (name === "duration" || name === "delay" || name === "stagger") return "ms";
|
|
@@ -3666,7 +3725,7 @@ function kindOf(name, schema) {
|
|
|
3666
3725
|
}
|
|
3667
3726
|
function motionCommandFields(type) {
|
|
3668
3727
|
const schema = branch(type);
|
|
3669
|
-
if (!_optionalChain([schema, 'optionalAccess',
|
|
3728
|
+
if (!_optionalChain([schema, 'optionalAccess', _96 => _96.properties])) return [];
|
|
3670
3729
|
const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
|
|
3671
3730
|
const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
|
|
3672
3731
|
const kind = kindOf(name, s);
|
|
@@ -3723,7 +3782,7 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
3723
3782
|
if (type === "wait") return { type: "wait", duration: 500 };
|
|
3724
3783
|
if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
|
|
3725
3784
|
const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
|
|
3726
|
-
const other = (pred) => _optionalChain([nodes, 'access',
|
|
3785
|
+
const other = (pred) => _optionalChain([nodes, 'access', _97 => _97.find, 'call', _98 => _98((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _99 => _99.node, 'access', _100 => _100.id]);
|
|
3727
3786
|
const base = { targets: [...targets] };
|
|
3728
3787
|
switch (type) {
|
|
3729
3788
|
case "scale":
|
|
@@ -3750,8 +3809,8 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
3750
3809
|
}
|
|
3751
3810
|
case "effect": {
|
|
3752
3811
|
for (const id of targets) {
|
|
3753
|
-
const node = _optionalChain([nodes, 'access',
|
|
3754
|
-
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess',
|
|
3812
|
+
const node = _optionalChain([nodes, 'access', _101 => _101.find, 'call', _102 => _102((e) => e.node.id === id), 'optionalAccess', _103 => _103.node]);
|
|
3813
|
+
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _104 => _104.effects]), () => ( []))) {
|
|
3755
3814
|
const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
|
|
3756
3815
|
if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
|
|
3757
3816
|
}
|
|
@@ -3776,11 +3835,11 @@ function motionCommandRows(scene, shotId) {
|
|
|
3776
3835
|
return scene.shots[index].run.map((command2, i) => {
|
|
3777
3836
|
const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
|
|
3778
3837
|
const primitive = motionFlairPrimitive(command2);
|
|
3779
|
-
return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess',
|
|
3838
|
+
return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _105 => _105.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _106 => _106.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
|
|
3780
3839
|
});
|
|
3781
3840
|
}
|
|
3782
3841
|
function duplicateMotionCommandEdit(scene, shot, command2) {
|
|
3783
|
-
const run = _nullishCoalesce(_optionalChain([scene, 'access',
|
|
3842
|
+
const run = _nullishCoalesce(_optionalChain([scene, 'access', _107 => _107.shots, 'access', _108 => _108.find, 'call', _109 => _109((s) => s.id === shot), 'optionalAccess', _110 => _110.run]), () => ( []));
|
|
3784
3843
|
return { op: "add_commands", shot, commands: run[command2] ? [structuredClone(run[command2])] : [], at: command2 + 1 };
|
|
3785
3844
|
}
|
|
3786
3845
|
var MOTION_EASE_CHOICES = [
|
|
@@ -3865,7 +3924,7 @@ function motionCueFromKey(key) {
|
|
|
3865
3924
|
function motionCueChoices(scene, limit = 256) {
|
|
3866
3925
|
const choices = [];
|
|
3867
3926
|
const s = (ms) => `${(ms / 1e3).toFixed(2)} s`;
|
|
3868
|
-
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access',
|
|
3927
|
+
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _111 => _111.narration, 'optionalAccess', _112 => _112.words, 'access', _113 => _113.map, 'call', _114 => _114((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
|
|
3869
3928
|
if (scene.beat && scene.beat.bpm > 0) {
|
|
3870
3929
|
for (let beat = 0; choices.length < limit; beat++) {
|
|
3871
3930
|
const time = motionBeatTime(scene.beat, beat);
|
|
@@ -3875,7 +3934,7 @@ function motionCueChoices(scene, limit = 256) {
|
|
|
3875
3934
|
choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
|
|
3876
3935
|
}
|
|
3877
3936
|
}
|
|
3878
|
-
_optionalChain([scene, 'access',
|
|
3937
|
+
_optionalChain([scene, 'access', _115 => _115.narration, 'optionalAccess', _116 => _116.words, 'access', _117 => _117.forEach, 'call', _118 => _118((w, i) => {
|
|
3879
3938
|
if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
|
|
3880
3939
|
})]);
|
|
3881
3940
|
return choices;
|
|
@@ -3884,7 +3943,7 @@ function motionShotCueTime(scene, cue) {
|
|
|
3884
3943
|
return cue ? motionCueTime(scene, cue) : void 0;
|
|
3885
3944
|
}
|
|
3886
3945
|
function formatMotionNarration(narration) {
|
|
3887
|
-
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess',
|
|
3946
|
+
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _119 => _119.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
|
|
3888
3947
|
}
|
|
3889
3948
|
function parseMotionNarration(text) {
|
|
3890
3949
|
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
@@ -4019,5 +4078,7 @@ function parseMotionNarration(text) {
|
|
|
4019
4078
|
|
|
4020
4079
|
|
|
4021
4080
|
|
|
4022
|
-
|
|
4081
|
+
|
|
4082
|
+
|
|
4083
|
+
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_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.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.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;
|
|
4023
4084
|
//# sourceMappingURL=index.cjs.map
|