@pixerate/editor 0.71.0 → 0.73.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 +285 -73
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +88 -2
- package/dist/animation-editor/index.d.ts +88 -2
- package/dist/animation-editor/index.js +233 -21
- 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_DRIVEN_PROPERTIES = ["x", "y", "rotation", "scaleX", "scaleY", "opacity"];
|
|
59
60
|
var MOTION_CLIP_TARGET = "$";
|
|
60
61
|
var MOTION_COMMAND_TYPES = [
|
|
61
62
|
"enter",
|
|
@@ -141,6 +142,7 @@ var MOTION_ISSUE_CODES = {
|
|
|
141
142
|
"unknown-path": { severity: "error", wording: "A follow command names a path the artwork does not have." },
|
|
142
143
|
"not-a-path": { severity: "error", wording: "A follow path must be a path node, not a group." },
|
|
143
144
|
"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." },
|
|
145
|
+
"driver-cycle": { severity: "error", wording: "Drivers follow each other in a loop, so none of them has a value." },
|
|
144
146
|
"unknown-clip": { severity: "error", wording: "A play command names a clip the scene does not have." },
|
|
145
147
|
"unknown-shape": { severity: "error", wording: "A morph names a shape the artwork does not have." },
|
|
146
148
|
"match-self": { severity: "error", wording: "A match turns a group into itself or into a group it holds (or that holds it)." },
|
|
@@ -219,7 +221,7 @@ ${problems.map((p) => `- ${p}`).join("\n")}`);
|
|
|
219
221
|
this.problems = problems;
|
|
220
222
|
}
|
|
221
223
|
};
|
|
222
|
-
var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
|
|
224
|
+
var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "drivers", "motionBlur", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
|
|
223
225
|
var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
|
|
224
226
|
var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric"];
|
|
225
227
|
var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps"];
|
|
@@ -403,6 +405,23 @@ function clipsShapeProblems(clips) {
|
|
|
403
405
|
}
|
|
404
406
|
return problems;
|
|
405
407
|
}
|
|
408
|
+
function driversShapeProblems(drivers) {
|
|
409
|
+
if (!Array.isArray(drivers)) return ['Scene: "drivers" must be a list of { target, property, source: { node, property }, factor?, offset?, clamp? }.'];
|
|
410
|
+
const problems = [];
|
|
411
|
+
const props = MOTION_DRIVEN_PROPERTIES;
|
|
412
|
+
drivers.forEach((d, i) => {
|
|
413
|
+
const where = `Driver ${i + 1}`;
|
|
414
|
+
if (!isObject(d)) return void problems.push(`${where} must be an object.`);
|
|
415
|
+
unknownKeys(d, ["target", "property", "source", "factor", "offset", "clamp"], where, problems);
|
|
416
|
+
if (typeof d.target !== "string" || !d.target) problems.push(`${where}: "target" must be the id of the node that follows.`);
|
|
417
|
+
if (!props.includes(d.property)) problems.push(`${where}: "property" must be one of ${MOTION_DRIVEN_PROPERTIES.join(", ")}.`);
|
|
418
|
+
if (!isObject(d.source) || typeof d.source.node !== "string" || !d.source.node || !props.includes(d.source.property)) problems.push(`${where}: "source" must be { "node": id, "property": one of ${MOTION_DRIVEN_PROPERTIES.join(", ")} }.`);
|
|
419
|
+
if (d.factor !== void 0 && !isNum(d.factor)) problems.push(`${where}: "factor" must be a number.`);
|
|
420
|
+
if (d.offset !== void 0 && !isNum(d.offset)) problems.push(`${where}: "offset" must be a number.`);
|
|
421
|
+
if (d.clamp !== void 0 && !(Array.isArray(d.clamp) && d.clamp.length === 2 && d.clamp.every(isNum) && d.clamp[0] <= d.clamp[1])) problems.push(`${where}: "clamp" must be [min, max].`);
|
|
422
|
+
});
|
|
423
|
+
return problems;
|
|
424
|
+
}
|
|
406
425
|
function shotShapeProblems(shot, where) {
|
|
407
426
|
if (!isObject(shot)) return [`${where} must be an object.`];
|
|
408
427
|
const problems = [];
|
|
@@ -451,6 +470,12 @@ function motionSceneShapeProblems(input) {
|
|
|
451
470
|
if (!isObject(art) || !isNum(art.width) || !isNum(art.height) || !(art.width > 0) || !(art.height > 0) || !Array.isArray(art.nodes))
|
|
452
471
|
problems.push('Scene: "artwork" must be a vector document { width, height, nodes }.');
|
|
453
472
|
if (input.clips !== void 0) problems.push(...clipsShapeProblems(input.clips));
|
|
473
|
+
if (input.drivers !== void 0) problems.push(...driversShapeProblems(input.drivers));
|
|
474
|
+
if (input.motionBlur !== void 0) {
|
|
475
|
+
const b = input.motionBlur;
|
|
476
|
+
if (!isObject(b) || Object.keys(b).some((k) => k !== "shutter" && k !== "samples") || b.shutter !== void 0 && !(isNum(b.shutter) && b.shutter > 0 && b.shutter <= 720) || b.samples !== void 0 && !(Number.isInteger(b.samples) && b.samples >= 2 && b.samples <= 32))
|
|
477
|
+
problems.push('Scene: "motionBlur" must be { "shutter"?: degrees above 0 up to 720 (default 180), "samples"?: 2 to 32 (default 8) }.');
|
|
478
|
+
}
|
|
454
479
|
if (input.trigger !== void 0 && !MOTION_TRIGGERS.includes(input.trigger)) problems.push(`Scene: "trigger" must be one of ${MOTION_TRIGGERS.join(", ")}.`);
|
|
455
480
|
if (input.loop !== void 0 && !["none", "loop", "ping-pong"].includes(input.loop)) problems.push('Scene: "loop" must be "none", "loop" or "ping-pong".');
|
|
456
481
|
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.');
|
|
@@ -826,6 +851,41 @@ function motionCueTime(scene, cue) {
|
|
|
826
851
|
if (typeof cue.word === "number") return _optionalChain([scene, 'access', _18 => _18.narration, 'optionalAccess', _19 => _19.words, 'access', _20 => _20[cue.word], 'optionalAccess', _21 => _21.start]);
|
|
827
852
|
return void 0;
|
|
828
853
|
}
|
|
854
|
+
var SCALE_LIKE = /* @__PURE__ */ new Set(["scaleX", "scaleY", "opacity"]);
|
|
855
|
+
function motionPropertyValue(timeline, node, property, time, raw = false, depth = 0) {
|
|
856
|
+
const rest = property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access', _22 => _22.restOpacity, 'optionalAccess', _23 => _23.get, 'call', _24 => _24(node)]), () => ( 1)) : SCALE_LIKE.has(property) ? 1 : 0;
|
|
857
|
+
const v = trackValue(timeline.tracks.get(motionTrackKey(node, property)), time, raw);
|
|
858
|
+
const base = property === "opacity" ? typeof v === "number" ? v : rest : withMotionLayers(timeline, node, property, typeof v === "number" ? v : rest, time, raw);
|
|
859
|
+
return applyMotionDrivers(timeline, node, property, base, time, raw, depth);
|
|
860
|
+
}
|
|
861
|
+
function applyMotionDrivers(timeline, node, property, value, time, raw = false, depth = 0) {
|
|
862
|
+
if (!timeline.drivers || depth > 8) return value;
|
|
863
|
+
let v = value;
|
|
864
|
+
for (const d of timeline.drivers) {
|
|
865
|
+
if (d.target !== node || d.property !== property) continue;
|
|
866
|
+
const src = motionPropertyValue(timeline, d.source.node, d.source.property, time, raw, depth + 1);
|
|
867
|
+
const srcRest = d.source.property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access', _25 => _25.restOpacity, 'optionalAccess', _26 => _26.get, 'call', _27 => _27(d.source.node)]), () => ( 1)) : SCALE_LIKE.has(d.source.property) ? 1 : 0;
|
|
868
|
+
let change = (src - srcRest) * (_nullishCoalesce(d.factor, () => ( 1))) + (_nullishCoalesce(d.offset, () => ( 0)));
|
|
869
|
+
if (d.clamp) change = Math.min(d.clamp[1], Math.max(d.clamp[0], change));
|
|
870
|
+
v = SCALE_LIKE.has(property) ? v * (1 + change) : v + change;
|
|
871
|
+
}
|
|
872
|
+
return property === "opacity" ? Math.min(1, Math.max(0, v)) : v;
|
|
873
|
+
}
|
|
874
|
+
function motionDrivenNodes(timeline) {
|
|
875
|
+
return new Set((_nullishCoalesce(timeline.drivers, () => ( []))).map((d) => d.target));
|
|
876
|
+
}
|
|
877
|
+
function motionDriverSources(timeline, node, properties, seen = /* @__PURE__ */ new Set()) {
|
|
878
|
+
const out = [];
|
|
879
|
+
for (const d of _nullishCoalesce(timeline.drivers, () => ( []))) {
|
|
880
|
+
if (d.target !== node || !properties.includes(d.property)) continue;
|
|
881
|
+
const key = `${d.source.node}\0${d.source.property}`;
|
|
882
|
+
if (seen.has(key)) continue;
|
|
883
|
+
seen.add(key);
|
|
884
|
+
out.push(..._nullishCoalesce(timeline.tracks.get(motionTrackKey(d.source.node, d.source.property)), () => ( [])), ..._nullishCoalesce(timeline.tracks.get(`${motionTrackKey(d.source.node, d.source.property)}\0add`), () => ( [])));
|
|
885
|
+
out.push(...motionDriverSources(timeline, d.source.node, [d.source.property], seen));
|
|
886
|
+
}
|
|
887
|
+
return out;
|
|
888
|
+
}
|
|
829
889
|
function motionCommandRepeat(command2) {
|
|
830
890
|
if (command2.type === "wait" || command2.type === "enter" || command2.type === "exit") return 1;
|
|
831
891
|
const n = _nullishCoalesce(command2.repeat, () => ( 1));
|
|
@@ -835,7 +895,7 @@ function motionCommandDuration(command2, scene, target) {
|
|
|
835
895
|
return motionCycleDuration(command2, scene, target) * motionCommandRepeat(command2);
|
|
836
896
|
}
|
|
837
897
|
function motionClipLayout(scene, clip, target, speed = 1) {
|
|
838
|
-
const run = _optionalChain([scene, 'access',
|
|
898
|
+
const run = _optionalChain([scene, 'access', _28 => _28.clips, 'optionalAccess', _29 => _29[clip], 'optionalAccess', _30 => _30.run]);
|
|
839
899
|
if (!run) return { items: [], length: 0 };
|
|
840
900
|
const f = speed > 0 && Number.isFinite(speed) ? 1 / speed : 1;
|
|
841
901
|
const items = [];
|
|
@@ -877,7 +937,7 @@ function motionCycleDuration(command2, scene, target) {
|
|
|
877
937
|
const ms = length * MOTION_DRAW_MS_PER_UNIT;
|
|
878
938
|
return Math.round(Math.min(MOTION_DRAW_RANGE[1], Math.max(MOTION_DRAW_RANGE[0], ms)));
|
|
879
939
|
}
|
|
880
|
-
if (command2.type === "move" && _optionalChain([command2, 'access',
|
|
940
|
+
if (command2.type === "move" && _optionalChain([command2, 'access', _31 => _31.via, 'optionalAccess', _32 => _32.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command2.via.length;
|
|
881
941
|
return MOTION_DEFAULT_DURATIONS[command2.type];
|
|
882
942
|
}
|
|
883
943
|
var MOTION_EASE_OUT = { type: "cubic-bezier", x1: 1 / 3, y1: 1, x2: 2 / 3, y2: 1 };
|
|
@@ -1023,11 +1083,11 @@ function compileMotionScene(scene) {
|
|
|
1023
1083
|
const at = nodes.get(p.id);
|
|
1024
1084
|
let first = { x: 0, y: 0 };
|
|
1025
1085
|
try {
|
|
1026
|
-
const m = _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, p, _nullishCoalesce(_optionalChain([at, 'optionalAccess',
|
|
1086
|
+
const m = _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, p, _nullishCoalesce(_optionalChain([at, 'optionalAccess', _33 => _33.parentWorld]), () => ( _chunkYJLCBA7Vcjs.IDENTITY_MATRIX)), { effects: false })[0];
|
|
1027
1087
|
if (m && m.type === "M") first = { x: m.x, y: m.y };
|
|
1028
1088
|
} catch (e3) {
|
|
1029
1089
|
}
|
|
1030
|
-
return { id: p.id, len: Math.max(1e-6, motionPathLength(p, _optionalChain([at, 'optionalAccess',
|
|
1090
|
+
return { id: p.id, len: Math.max(1e-6, motionPathLength(p, _optionalChain([at, 'optionalAccess', _34 => _34.parentWorld]))), first };
|
|
1031
1091
|
});
|
|
1032
1092
|
if (!list.length) return null;
|
|
1033
1093
|
const span = Math.max(0, e - s);
|
|
@@ -1056,7 +1116,7 @@ function compileMotionScene(scene) {
|
|
|
1056
1116
|
const style = _nullishCoalesce(command2.style, () => ( "fade"));
|
|
1057
1117
|
const opacity = rest("opacity");
|
|
1058
1118
|
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;
|
|
1059
|
-
for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess',
|
|
1119
|
+
for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _35 => _35.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
|
|
1060
1120
|
if (reveal) {
|
|
1061
1121
|
seg("opacity", opacity, "linear", start, start);
|
|
1062
1122
|
seg(reveal.property, reveal.to, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: reveal.from });
|
|
@@ -1132,15 +1192,15 @@ function compileMotionScene(scene) {
|
|
|
1132
1192
|
}
|
|
1133
1193
|
case "move": {
|
|
1134
1194
|
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
1135
|
-
let dx = _nullishCoalesce(_optionalChain([command2, 'access',
|
|
1136
|
-
let dy = _nullishCoalesce(_optionalChain([command2, 'access',
|
|
1195
|
+
let dx = _nullishCoalesce(_optionalChain([command2, 'access', _36 => _36.by, 'optionalAccess', _37 => _37.x]), () => ( 0));
|
|
1196
|
+
let dy = _nullishCoalesce(_optionalChain([command2, 'access', _38 => _38.by, 'optionalAccess', _39 => _39.y]), () => ( 0));
|
|
1137
1197
|
if (command2.to) {
|
|
1138
1198
|
const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
|
|
1139
1199
|
const target = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, command2.to);
|
|
1140
1200
|
dx = target.x - (entry.center.x + num("x"));
|
|
1141
1201
|
dy = target.y - (entry.center.y + num("y"));
|
|
1142
1202
|
}
|
|
1143
|
-
if (_optionalChain([command2, 'access',
|
|
1203
|
+
if (_optionalChain([command2, 'access', _40 => _40.via, 'optionalAccess', _41 => _41.length])) {
|
|
1144
1204
|
const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
|
|
1145
1205
|
const x0 = num("x");
|
|
1146
1206
|
const y0 = num("y");
|
|
@@ -1238,7 +1298,7 @@ function compileMotionScene(scene) {
|
|
|
1238
1298
|
for (const track of tracks.values()) track.sort((a, b) => a.start - b.start);
|
|
1239
1299
|
segments.sort((a, b) => a.start - b.start);
|
|
1240
1300
|
const duration = shots.length ? shots[shots.length - 1].end : 0;
|
|
1241
|
-
const timeline = { duration, shots, commands, segments, tracks };
|
|
1301
|
+
const timeline = { duration, shots, commands, segments, tracks, ..._optionalChain([scene, 'access', _42 => _42.drivers, 'optionalAccess', _43 => _43.length]) ? { drivers: scene.drivers, restOpacity: new Map([...nodes].map(([id, e]) => [id, _nullishCoalesce(e.node.opacity, () => ( 1))])) } : {} };
|
|
1242
1302
|
timelineCache.set(scene, timeline);
|
|
1243
1303
|
return timeline;
|
|
1244
1304
|
}
|
|
@@ -1251,7 +1311,7 @@ var MOTION_DRAW_EFFECT_ID = "~draw";
|
|
|
1251
1311
|
var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
|
|
1252
1312
|
var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
|
|
1253
1313
|
function applyMotionControlValues(scene, values) {
|
|
1254
|
-
if (!values || !_optionalChain([scene, 'access',
|
|
1314
|
+
if (!values || !_optionalChain([scene, 'access', _44 => _44.controls, 'optionalAccess', _45 => _45.length])) return scene;
|
|
1255
1315
|
const map = /* @__PURE__ */ new Map();
|
|
1256
1316
|
for (const control of scene.controls) {
|
|
1257
1317
|
const value = values[control.name];
|
|
@@ -1297,7 +1357,7 @@ function shapeIn(entry, shape) {
|
|
|
1297
1357
|
}
|
|
1298
1358
|
function shapeAt(entry, timeline, nodes, time) {
|
|
1299
1359
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
|
|
1300
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
1360
|
+
if (!_optionalChain([track, 'optionalAccess', _46 => _46.length])) return null;
|
|
1301
1361
|
const s = activeSegment(track, time);
|
|
1302
1362
|
const fromId = String(s ? s.from : track[0].from);
|
|
1303
1363
|
if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
|
|
@@ -1320,8 +1380,8 @@ function motionFollowRoute(entry, path) {
|
|
|
1320
1380
|
}
|
|
1321
1381
|
function followAt(entry, timeline, nodes, time) {
|
|
1322
1382
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "follow"));
|
|
1323
|
-
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess',
|
|
1324
|
-
if (!_optionalChain([s, 'optionalAccess',
|
|
1383
|
+
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _47 => _47[0]])));
|
|
1384
|
+
if (!_optionalChain([s, 'optionalAccess', _48 => _48.path])) return null;
|
|
1325
1385
|
const route = motionFollowRoute(entry, nodes.get(s.path));
|
|
1326
1386
|
const progress = Number(trackValue(track, time));
|
|
1327
1387
|
if (!route || !(progress >= 0)) return null;
|
|
@@ -1336,9 +1396,11 @@ function followAt(entry, timeline, nodes, time) {
|
|
|
1336
1396
|
function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry.node]), raw = false, follow = true) {
|
|
1337
1397
|
const read = (p, rest) => {
|
|
1338
1398
|
const v = trackValue(timeline.tracks.get(motionTrackKey(entry.node.id, p)), time, raw);
|
|
1339
|
-
|
|
1399
|
+
const layered = withMotionLayers(timeline, entry.node.id, p, typeof v === "number" ? v : rest, time, raw);
|
|
1400
|
+
return p === "follow" ? layered : applyMotionDrivers(timeline, entry.node.id, p, layered, time, raw);
|
|
1340
1401
|
};
|
|
1341
|
-
|
|
1402
|
+
const driven = _optionalChain([timeline, 'access', _49 => _49.drivers, 'optionalAccess', _50 => _50.some, 'call', _51 => _51((d) => d.target === entry.node.id && d.property !== "opacity")]);
|
|
1403
|
+
if (!driven && !TRANSFORM_PROPS.some((p) => (follow || p !== "follow") && (timeline.tracks.has(motionTrackKey(entry.node.id, p)) || timeline.tracks.has(motionAddTrackKey(entry.node.id, p))))) return null;
|
|
1342
1404
|
const dx = read("x", 0);
|
|
1343
1405
|
const dy = read("y", 0);
|
|
1344
1406
|
const rotation = read("rotation", 0);
|
|
@@ -1364,7 +1426,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1364
1426
|
const nodes = indexMotionNodes(s.artwork.nodes);
|
|
1365
1427
|
const drawOn = options.draw !== false;
|
|
1366
1428
|
const value = (id, p) => trackValue(timeline.tracks.get(motionTrackKey(id, p)), time);
|
|
1367
|
-
const animated = new Set(timeline.segments.map((seg) => seg.node));
|
|
1429
|
+
const animated = /* @__PURE__ */ new Set([...timeline.segments.map((seg) => seg.node), ...motionDrivenNodes(timeline)]);
|
|
1368
1430
|
const clips = {};
|
|
1369
1431
|
const visit = (node) => {
|
|
1370
1432
|
let out = node.type === "group" ? { ...node, children: node.children.map(visit) } : node;
|
|
@@ -1381,7 +1443,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1381
1443
|
if (out.visible === void 0) delete out.visible;
|
|
1382
1444
|
}
|
|
1383
1445
|
const effectTracks = [...timeline.tracks.keys()].filter((k) => k.startsWith(`${id}\0effect:`));
|
|
1384
|
-
if (effectTracks.length && _optionalChain([out, 'access',
|
|
1446
|
+
if (effectTracks.length && _optionalChain([out, 'access', _52 => _52.effects, 'optionalAccess', _53 => _53.length])) {
|
|
1385
1447
|
out = {
|
|
1386
1448
|
...out,
|
|
1387
1449
|
effects: out.effects.map((effect) => {
|
|
@@ -1421,7 +1483,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1421
1483
|
return p;
|
|
1422
1484
|
});
|
|
1423
1485
|
}
|
|
1424
|
-
const opacity = value(id, "opacity");
|
|
1486
|
+
const opacity = _optionalChain([timeline, 'access', _54 => _54.drivers, 'optionalAccess', _55 => _55.some, 'call', _56 => _56((d) => d.target === id && d.property === "opacity")]) ? motionPropertyValue(timeline, id, "opacity", time) : value(id, "opacity");
|
|
1425
1487
|
if (typeof opacity === "number") {
|
|
1426
1488
|
const o = Math.min(1, Math.max(0, tidy(opacity)));
|
|
1427
1489
|
out = { ...out, opacity: o };
|
|
@@ -1494,7 +1556,7 @@ function motionPath(scene, id, options = {}) {
|
|
|
1494
1556
|
const r = (n) => Math.round(n * 100) / 100;
|
|
1495
1557
|
const centreAt = (t) => {
|
|
1496
1558
|
const node = indexMotionNodes(motionFrameAtCache(scene, t)).get(id);
|
|
1497
|
-
const b = _optionalChain([node, 'optionalAccess',
|
|
1559
|
+
const b = _optionalChain([node, 'optionalAccess', _57 => _57.bounds]);
|
|
1498
1560
|
return b ? { t: r(t), x: r(b.x + b.width / 2), y: r(b.y + b.height / 2) } : null;
|
|
1499
1561
|
};
|
|
1500
1562
|
const points = [];
|
|
@@ -1517,12 +1579,49 @@ function motionPathsSvg(paths, camera, color = "#f43f5e") {
|
|
|
1517
1579
|
(p) => `<g data-motion-path="${p.id.replace(/"/g, """)}" fill="none" stroke="${color}" stroke-width="${f(w)}" stroke-linecap="round" stroke-linejoin="round" opacity="0.8"><polyline points="${p.points.map((q) => `${f(q.x)},${f(q.y)}`).join(" ")}" stroke-dasharray="${f(w * 3)} ${f(w * 2)}"/>${p.keys.map((k) => `<circle cx="${f(k.x)}" cy="${f(k.y)}" r="${f(w * 2.5)}" fill="${color}" stroke="none"/>`).join("")}</g>`
|
|
1518
1580
|
).join("");
|
|
1519
1581
|
}
|
|
1582
|
+
function motionBlurTimes(scene, time, blur = {}) {
|
|
1583
|
+
const shutter = Math.min(720, Math.max(0, _nullishCoalesce(blur.shutter, () => ( 180))));
|
|
1584
|
+
const most = Math.max(1, Math.min(32, Math.floor(_nullishCoalesce(blur.samples, () => ( 8)))));
|
|
1585
|
+
const span = 1e3 / (_nullishCoalesce(scene.fps, () => ( 30))) * shutter / 360;
|
|
1586
|
+
if (span <= 0 || most <= 1) return [time];
|
|
1587
|
+
const ids = motionMovingIds(scene);
|
|
1588
|
+
if (!ids.length) return [time];
|
|
1589
|
+
const a = indexMotionNodes(motionFrameAt(scene, time - span / 2).document.nodes);
|
|
1590
|
+
const b = indexMotionNodes(motionFrameAt(scene, time + span / 2).document.nodes);
|
|
1591
|
+
let travel = 0;
|
|
1592
|
+
for (const id of ids) {
|
|
1593
|
+
const p = _optionalChain([a, 'access', _58 => _58.get, 'call', _59 => _59(id), 'optionalAccess', _60 => _60.bounds]);
|
|
1594
|
+
const q = _optionalChain([b, 'access', _61 => _61.get, 'call', _62 => _62(id), 'optionalAccess', _63 => _63.bounds]);
|
|
1595
|
+
if (p && q) travel = Math.max(travel, Math.abs(p.x - q.x), Math.abs(p.y - q.y), Math.abs(p.x + p.width - q.x - q.width), Math.abs(p.y + p.height - q.y - q.height));
|
|
1596
|
+
}
|
|
1597
|
+
const n = Math.min(most, Math.ceil(travel / 1.5));
|
|
1598
|
+
if (n <= 1) return [time];
|
|
1599
|
+
return Array.from({ length: n }, (_, k) => time - span / 2 + span * (k + 0.5) / n);
|
|
1600
|
+
}
|
|
1601
|
+
function averagedFrames(scene, times, options, prefix) {
|
|
1602
|
+
const n = times.length;
|
|
1603
|
+
return `<g data-motion-blur="${n}" style="isolation:isolate">${times.map((t, k) => {
|
|
1604
|
+
const own = `${prefix}blur${k}-`;
|
|
1605
|
+
const frame = motionFrameToSvg(scene, t, { ...options, idPrefix: own, background: false });
|
|
1606
|
+
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _64 => _64.exec, 'call', _65 => _65(frame), 'optionalAccess', _66 => _66[1]]), () => ( ""));
|
|
1607
|
+
const inner = k === n - 1 ? innerSvg(frame) : innerSvg(frame).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
|
|
1608
|
+
return `<svg viewBox="${view}" preserveAspectRatio="none" style="mix-blend-mode:plus-lighter" opacity="${Math.round(1e4 / n) / 1e4}">${inner}</svg>`;
|
|
1609
|
+
}).join("")}</g>`;
|
|
1610
|
+
}
|
|
1520
1611
|
var innerSvg = (svg) => svg.slice(svg.indexOf(">") + 1, svg.lastIndexOf("</svg>"));
|
|
1521
1612
|
function motionStageSvg(scene, time, options = {}) {
|
|
1522
|
-
const { onionSkin, motionPaths, motionPathColor, ...svgOptions } = options;
|
|
1523
|
-
const current = motionFrameToSvg(scene, time, svgOptions);
|
|
1524
|
-
if (!onionSkin && !motionPaths) return current;
|
|
1613
|
+
const { onionSkin, motionPaths, motionPathColor, motionBlur, ...svgOptions } = options;
|
|
1525
1614
|
const prefix = _nullishCoalesce(svgOptions.idPrefix, () => ( "vg-"));
|
|
1615
|
+
let current = motionFrameToSvg(scene, time, svgOptions);
|
|
1616
|
+
const blur = motionBlur === false ? void 0 : _nullishCoalesce(motionBlur, () => ( scene.motionBlur));
|
|
1617
|
+
const blurTimes = blur ? motionBlurTimes(scene, time, blur) : [time];
|
|
1618
|
+
if (blurTimes.length > 1) {
|
|
1619
|
+
const open2 = current.indexOf(">") + 1;
|
|
1620
|
+
const body2 = current.slice(open2, current.lastIndexOf("</svg>"));
|
|
1621
|
+
const bg2 = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _67 => _67.exec, 'call', _68 => _68(body2), 'optionalAccess', _69 => _69[0]]), () => ( "")) : "";
|
|
1622
|
+
current = `${current.slice(0, open2)}${bg2}${averagedFrames(scene, blurTimes, svgOptions, prefix)}</svg>`;
|
|
1623
|
+
}
|
|
1624
|
+
if (!onionSkin && !motionPaths) return current;
|
|
1526
1625
|
const ghosts = onionSkin ? motionGhosts(scene, time, onionSkin).map((g, i) => {
|
|
1527
1626
|
const own = `${prefix}ghost${i}-`;
|
|
1528
1627
|
const inner = innerSvg(motionFrameToSvg(scene, g.time, { ...svgOptions, idPrefix: own, background: false })).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
|
|
@@ -1534,7 +1633,7 @@ function motionStageSvg(scene, time, options = {}) {
|
|
|
1534
1633
|
const open = current.indexOf(">") + 1;
|
|
1535
1634
|
const close = current.lastIndexOf("</svg>");
|
|
1536
1635
|
const body = current.slice(open, close);
|
|
1537
|
-
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access',
|
|
1636
|
+
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _70 => _70.exec, 'call', _71 => _71(body), 'optionalAccess', _72 => _72[0]]), () => ( "")) : "";
|
|
1538
1637
|
return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
|
|
1539
1638
|
}
|
|
1540
1639
|
function motionContactSheetSvg(scene, times, options = {}) {
|
|
@@ -1553,7 +1652,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
|
|
|
1553
1652
|
const x = gap + i % cols * (w + gap);
|
|
1554
1653
|
const y = gap + Math.floor(i / cols) * (h + label + gap);
|
|
1555
1654
|
const frame = motionStageSvg(scene, t, { ...frameOptions, idPrefix: `${prefix}f${i}-` });
|
|
1556
|
-
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access',
|
|
1655
|
+
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _73 => _73.exec, 'call', _74 => _74(frame), 'optionalAccess', _75 => _75[1]]), () => ( `0 0 ${w} ${h}`));
|
|
1557
1656
|
const inner = innerSvg(frame).replace(new RegExp(` id="(?!${`${prefix}f${i}-`.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
|
|
1558
1657
|
const shot = _nullishCoalesce(timeline.shots.find((s) => t >= s.start && t < s.end), () => ( timeline.shots[timeline.shots.length - 1]));
|
|
1559
1658
|
const caption = labels ? `<text x="${x + w / 2}" y="${y + h + label * 0.8}" font-family="system-ui, sans-serif" font-size="${Math.round(label * 0.7)}" text-anchor="middle" fill="#64748b">${(t / 1e3).toFixed(2)} s${shot ? ` \xB7 ${shot.id.replace(/[<&]/g, "")}` : ""}</text>` : "";
|
|
@@ -1565,7 +1664,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
|
|
|
1565
1664
|
// src/animation-editor/check.ts
|
|
1566
1665
|
var MOTION_MIN_CHANGE_MS = 120;
|
|
1567
1666
|
var NUMERIC_PARAMS = (node, effectId) => {
|
|
1568
|
-
const effect = _optionalChain([node, 'access',
|
|
1667
|
+
const effect = _optionalChain([node, 'access', _76 => _76.effects, 'optionalAccess', _77 => _77.find, 'call', _78 => _78((e) => e.id === effectId)]);
|
|
1569
1668
|
if (!effect) return null;
|
|
1570
1669
|
return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
|
|
1571
1670
|
};
|
|
@@ -1646,7 +1745,7 @@ function checkMotionScene(scene) {
|
|
|
1646
1745
|
if (command2.type === "follow" && known(command2.path, "unknown-path", "path", where) && nodes.get(command2.path).node.type !== "path")
|
|
1647
1746
|
issues.push(motionIssue("not-a-path", `"${command2.path}" is a group; follow a single path node.`, { ...where, ids: [command2.path] }));
|
|
1648
1747
|
if (command2.type === "morph") known(command2.into, "unknown-shape", "shape", where);
|
|
1649
|
-
if (command2.type === "play" && !_optionalChain([scene, 'access',
|
|
1748
|
+
if (command2.type === "play" && !_optionalChain([scene, 'access', _79 => _79.clips, 'optionalAccess', _80 => _80[command2.clip]]))
|
|
1650
1749
|
issues.push(motionIssue("unknown-clip", `There is no clip ${namedWithSuggestion(command2.clip, Object.keys(_nullishCoalesce(scene.clips, () => ( {}))))}; define it with set_animation_clip.`, where));
|
|
1651
1750
|
if (command2.type === "match" && known(command2.into, "unknown-shape", "group", where)) {
|
|
1652
1751
|
const into = nodes.get(command2.into);
|
|
@@ -1720,6 +1819,28 @@ function checkMotionScene(scene) {
|
|
|
1720
1819
|
}
|
|
1721
1820
|
});
|
|
1722
1821
|
});
|
|
1822
|
+
const drivers = _nullishCoalesce(scene.drivers, () => ( []));
|
|
1823
|
+
drivers.forEach((d, i) => {
|
|
1824
|
+
for (const id of [d.target, d.source.node])
|
|
1825
|
+
if (!nodes.has(id)) issues.push(motionIssue("unknown-target", `Driver ${i + 1} names ${namedWithSuggestion(id, [...nodes.keys()])}, which the artwork does not have.`, { ids: [id] }));
|
|
1826
|
+
});
|
|
1827
|
+
{
|
|
1828
|
+
const key = (n, p) => `${n}.${p}`;
|
|
1829
|
+
const edges = /* @__PURE__ */ new Map();
|
|
1830
|
+
for (const d of drivers) edges.set(key(d.target, d.property), [..._nullishCoalesce(edges.get(key(d.target, d.property)), () => ( [])), key(d.source.node, d.source.property)]);
|
|
1831
|
+
const state = /* @__PURE__ */ new Map();
|
|
1832
|
+
const loop = [];
|
|
1833
|
+
const visit = (k, trail) => {
|
|
1834
|
+
if (state.get(k) === 2) return false;
|
|
1835
|
+
if (state.get(k) === 1) return loop.push(...trail.slice(trail.indexOf(k)), k), true;
|
|
1836
|
+
state.set(k, 1);
|
|
1837
|
+
for (const n of _nullishCoalesce(edges.get(k), () => ( []))) if (visit(n, [...trail, k])) return true;
|
|
1838
|
+
state.set(k, 2);
|
|
1839
|
+
return false;
|
|
1840
|
+
};
|
|
1841
|
+
for (const k of edges.keys()) if (visit(k, [])) break;
|
|
1842
|
+
if (loop.length) issues.push(motionIssue("driver-cycle", `Drivers follow each other round in a loop (${loop.join(" \u2190 ")}); remove one of them.`, { ids: [...new Set(loop.map((k) => k.split(".")[0]))] }));
|
|
1843
|
+
}
|
|
1723
1844
|
for (const [name, clip] of Object.entries(_nullishCoalesce(scene.clips, () => ( {}))))
|
|
1724
1845
|
for (const command2 of clip.run)
|
|
1725
1846
|
if (command2.type !== "wait") {
|
|
@@ -1739,7 +1860,7 @@ function checkMotionScene(scene) {
|
|
|
1739
1860
|
if (!shot.at) return;
|
|
1740
1861
|
const timing = timeline.shots[i];
|
|
1741
1862
|
if (timing.cue === void 0) {
|
|
1742
|
-
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',
|
|
1863
|
+
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', _81 => _81.narration, 'optionalAccess', _82 => _82.words, 'access', _83 => _83.length]), () => ( 0))} words (indexes from 0)`;
|
|
1743
1864
|
issues.push(motionIssue("unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
|
|
1744
1865
|
} else if (timing.missedBy !== void 0) {
|
|
1745
1866
|
const late = Math.round(timing.missedBy);
|
|
@@ -1772,7 +1893,7 @@ function checkMotionScene(scene) {
|
|
|
1772
1893
|
const cam = frame.camera;
|
|
1773
1894
|
const docIndex = indexMotionNodes(frame.document.nodes);
|
|
1774
1895
|
for (const id of command2.targets) {
|
|
1775
|
-
const b = _optionalChain([docIndex, 'access',
|
|
1896
|
+
const b = _optionalChain([docIndex, 'access', _84 => _84.get, 'call', _85 => _85(id), 'optionalAccess', _86 => _86.bounds]);
|
|
1776
1897
|
if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
|
|
1777
1898
|
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;
|
|
1778
1899
|
if (outside) {
|
|
@@ -1810,6 +1931,7 @@ var MOTION_EDIT_OPS = [
|
|
|
1810
1931
|
"set_artwork",
|
|
1811
1932
|
"set_controls",
|
|
1812
1933
|
"set_clip",
|
|
1934
|
+
"set_drivers",
|
|
1813
1935
|
"replace_scene"
|
|
1814
1936
|
];
|
|
1815
1937
|
var EditError = class extends Error {
|
|
@@ -1854,18 +1976,25 @@ function applyOne(scene, edit) {
|
|
|
1854
1976
|
if (!(typeof edit.steps === "number" && edit.steps > 0 && edit.steps <= 120)) fail('"steps" must be frames per second from above 0 to 120 (12 is "on twos" at 24 fps), or null for smooth.');
|
|
1855
1977
|
next.steps = edit.steps;
|
|
1856
1978
|
}
|
|
1857
|
-
for (const key of ["beat", "narration"]) {
|
|
1979
|
+
for (const key of ["beat", "narration", "motionBlur"]) {
|
|
1858
1980
|
if (edit[key] === null) delete next[key];
|
|
1859
1981
|
else if (edit[key] !== void 0) next[key] = edit[key];
|
|
1860
1982
|
}
|
|
1861
1983
|
{
|
|
1862
|
-
const problems = motionSceneShapeProblems(next).filter((p) => /"beat"|"narration"/.test(p));
|
|
1984
|
+
const problems = motionSceneShapeProblems(next).filter((p) => /"beat"|"narration"|"motionBlur"/.test(p));
|
|
1863
1985
|
if (problems.length) fail(problems.join(" "));
|
|
1864
1986
|
}
|
|
1865
1987
|
if (edit.target === null) delete next.target;
|
|
1866
1988
|
else if (edit.target !== void 0) next.target = edit.target;
|
|
1867
1989
|
return next;
|
|
1868
1990
|
}
|
|
1991
|
+
case "set_drivers": {
|
|
1992
|
+
const problems = driversShapeProblems(edit.drivers);
|
|
1993
|
+
if (problems.length) fail(problems.join(" "));
|
|
1994
|
+
const next = { ...scene, drivers: edit.drivers };
|
|
1995
|
+
if (!edit.drivers.length) delete next.drivers;
|
|
1996
|
+
return next;
|
|
1997
|
+
}
|
|
1869
1998
|
case "set_clip": {
|
|
1870
1999
|
if (typeof edit.name !== "string" || !edit.name) fail('Give the clip a "name".');
|
|
1871
2000
|
const clips = { ..._nullishCoalesce(scene.clips, () => ( {})) };
|
|
@@ -1996,9 +2125,9 @@ function applyMotionEdits(scene, edits) {
|
|
|
1996
2125
|
let next = scene;
|
|
1997
2126
|
for (let i = 0; i < list.length; i++) {
|
|
1998
2127
|
const edit = list[i];
|
|
1999
|
-
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess',
|
|
2128
|
+
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _87 => _87.op])}): ` : "";
|
|
2000
2129
|
if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
|
|
2001
|
-
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess',
|
|
2130
|
+
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _88 => _88.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
|
|
2002
2131
|
try {
|
|
2003
2132
|
next = applyOne(next, edit);
|
|
2004
2133
|
} catch (error) {
|
|
@@ -2020,7 +2149,7 @@ function resolveMotionEditRefs(scene, edits) {
|
|
|
2020
2149
|
const resolved = [];
|
|
2021
2150
|
let next = scene;
|
|
2022
2151
|
for (let i = 0; i < edits.length; i++) {
|
|
2023
|
-
const where = `op ${i + 1} (${_optionalChain([edits, 'access',
|
|
2152
|
+
const where = `op ${i + 1} (${_optionalChain([edits, 'access', _89 => _89[i], 'optionalAccess', _90 => _90.op])})`;
|
|
2024
2153
|
let problem = null;
|
|
2025
2154
|
const walk = (v) => {
|
|
2026
2155
|
if (typeof v === "string") {
|
|
@@ -2053,9 +2182,9 @@ function resolveMotionEditRefs(scene, edits) {
|
|
|
2053
2182
|
resolved.push(edit);
|
|
2054
2183
|
const out = { op: edit.op };
|
|
2055
2184
|
if (edit.op === "insert_shots") out.shots = edit.shots.map((s) => s.id);
|
|
2056
|
-
if ("shot" in edit && typeof edit.shot === "string") out.shot = edit.op === "update_shot" && _optionalChain([edit, 'access',
|
|
2185
|
+
if ("shot" in edit && typeof edit.shot === "string") out.shot = edit.op === "update_shot" && _optionalChain([edit, 'access', _91 => _91.set, 'optionalAccess', _92 => _92.id]) ? edit.set.id : edit.shot;
|
|
2057
2186
|
if (edit.op === "add_commands") {
|
|
2058
|
-
const at = _nullishCoalesce(_nullishCoalesce(edit.at, () => ( _optionalChain([before, 'access',
|
|
2187
|
+
const at = _nullishCoalesce(_nullishCoalesce(edit.at, () => ( _optionalChain([before, 'access', _93 => _93.shots, 'access', _94 => _94.find, 'call', _95 => _95((s) => s.id === edit.shot), 'optionalAccess', _96 => _96.run, 'access', _97 => _97.length]))), () => ( 0));
|
|
2059
2188
|
out.indexes = edit.commands.map((_, k) => at + k);
|
|
2060
2189
|
}
|
|
2061
2190
|
if (edit.op === "move_command") out.indexes = [edit.to];
|
|
@@ -2167,7 +2296,13 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2167
2296
|
if (!entry) return void 0;
|
|
2168
2297
|
return [...entry.ancestors, path.id].find((id) => timeline.tracks.has(motionTrackKey(id, p)));
|
|
2169
2298
|
};
|
|
2170
|
-
const animatedNodes = new Set(timeline.segments.map((s) => s.node).filter(Boolean));
|
|
2299
|
+
const animatedNodes = /* @__PURE__ */ new Set([...timeline.segments.map((s) => s.node).filter(Boolean), ...motionDrivenNodes(timeline)]);
|
|
2300
|
+
const drivenBy = /* @__PURE__ */ new WeakSet();
|
|
2301
|
+
const sourcesOf = (id, props) => motionDriverSources(timeline, id, props).map((s) => {
|
|
2302
|
+
const copy = { ...s };
|
|
2303
|
+
drivenBy.add(copy);
|
|
2304
|
+
return copy;
|
|
2305
|
+
});
|
|
2171
2306
|
const pathsSeen = /* @__PURE__ */ new Set();
|
|
2172
2307
|
const wrap = {};
|
|
2173
2308
|
const routes = [];
|
|
@@ -2208,16 +2343,17 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2208
2343
|
const wrapper = freshId(`${id}--follow`);
|
|
2209
2344
|
const centre = freshId(`${id}--follow-centre`);
|
|
2210
2345
|
const c = entry.center;
|
|
2211
|
-
const at = _optionalChain([motionNodeOffset, 'call',
|
|
2346
|
+
const at = _optionalChain([motionNodeOffset, 'call', _98 => _98(entry, timeline, 0, nodes), 'optionalAccess', _99 => _99.follow]);
|
|
2212
2347
|
const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
|
|
2213
2348
|
(wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
|
|
2214
2349
|
follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
|
|
2215
2350
|
}
|
|
2216
2351
|
}
|
|
2217
|
-
|
|
2218
|
-
|
|
2352
|
+
const opacitySources = sourcesOf(id, ["opacity"]);
|
|
2353
|
+
if (timeline.tracks.has(motionTrackKey(id, "opacity")) || opacitySources.length)
|
|
2354
|
+
channels.push({ id, kind: "attr", attr: "opacity", segments: [...track(id, "opacity"), ...opacitySources], exact: (s) => plays(s) && !drivenBy.has(s), value: (t) => round2(motionPropertyValue(timeline, id, "opacity", t)) });
|
|
2219
2355
|
const followed = follows.some((x) => x.id === id);
|
|
2220
|
-
const transformSegments = TRANSFORM_PROPS2.flatMap((p) => followed && p === "follow" ? [] : [...track(id, p), ..._nullishCoalesce(timeline.tracks.get(motionAddTrackKey(id, p)), () => ( []))]);
|
|
2356
|
+
const transformSegments = [...TRANSFORM_PROPS2.flatMap((p) => followed && p === "follow" ? [] : [...track(id, p), ..._nullishCoalesce(timeline.tracks.get(motionAddTrackKey(id, p)), () => ( []))]), ...sourcesOf(id, ["x", "y", "rotation", "scaleX", "scaleY"])];
|
|
2221
2357
|
if (transformSegments.length) {
|
|
2222
2358
|
const base = node.transform ? ` matrix(${node.transform.map(f).join(" ")})` : "";
|
|
2223
2359
|
const c = entry.center;
|
|
@@ -2230,7 +2366,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2230
2366
|
kind: "attr",
|
|
2231
2367
|
attr: "transform",
|
|
2232
2368
|
segments: transformSegments,
|
|
2233
|
-
exact: (s) => LINEAR_TRANSFORM.has(s.property) && plays(s),
|
|
2369
|
+
exact: (s) => LINEAR_TRANSFORM.has(s.property) && plays(s) && !drivenBy.has(s),
|
|
2234
2370
|
overshoot: true,
|
|
2235
2371
|
// x, y and the angle are the transform's numbers 0, 1 and 2 (`MotionSegment.index`).
|
|
2236
2372
|
value: (t) => transformAt(t, false),
|
|
@@ -2268,7 +2404,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2268
2404
|
exact: () => false,
|
|
2269
2405
|
value: (t) => {
|
|
2270
2406
|
const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
|
|
2271
|
-
const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call',
|
|
2407
|
+
const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _100 => _100(frame.document.nodes), 'access', _101 => _101.get, 'call', _102 => _102(id), 'optionalAccess', _103 => _103.node]));
|
|
2272
2408
|
if (!now || now.type !== "path") return "";
|
|
2273
2409
|
const bezier = _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, now, _chunkYJLCBA7Vcjs.IDENTITY_MATRIX, { effects: false }), inverse);
|
|
2274
2410
|
return _chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
|
|
@@ -2289,8 +2425,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2289
2425
|
...delay > 0 ? { delay: round2(delay) } : {},
|
|
2290
2426
|
ms: round2(ms),
|
|
2291
2427
|
ease: written,
|
|
2292
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
2293
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
2428
|
+
..._optionalChain([segment, 'optionalAccess', _104 => _104.behavior]) ? { behavior: segment.behavior } : {},
|
|
2429
|
+
..._optionalChain([segment, 'optionalAccess', _105 => _105.steps]) ? { strobe: segment.steps } : {}
|
|
2294
2430
|
};
|
|
2295
2431
|
if (channel.kind === "view") animate.push({ ...base, view: to });
|
|
2296
2432
|
else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
|
|
@@ -2375,11 +2511,12 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2375
2511
|
}
|
|
2376
2512
|
animate.sort((x, y) => (_nullishCoalesce(x.step, () => ( 0))) - (_nullishCoalesce(y.step, () => ( 0))) || (_nullishCoalesce(x.delay, () => ( 0))) - (_nullishCoalesce(y.delay, () => ( 0))));
|
|
2377
2513
|
}
|
|
2514
|
+
if (scene.motionBlur) notes.push("Motion blur is drawn on the stage only; Flair plays the scene sharp.");
|
|
2378
2515
|
if (trigger && (_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") notes.push(`The scene plays on ${trigger}, so its loop does not apply in Flair.`);
|
|
2379
2516
|
let svg = _chunkYJLCBA7Vcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
|
|
2380
2517
|
if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
|
|
2381
2518
|
let motion = { svg, animate };
|
|
2382
|
-
if (_optionalChain([scene, 'access',
|
|
2519
|
+
if (_optionalChain([scene, 'access', _106 => _106.controls, 'optionalAccess', _107 => _107.length])) {
|
|
2383
2520
|
const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
|
|
2384
2521
|
const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
|
|
2385
2522
|
svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
|
|
@@ -2401,7 +2538,7 @@ function toFlairVectorEffect(scene, options = {}) {
|
|
|
2401
2538
|
tags: _nullishCoalesce(options.tags, () => ( [])),
|
|
2402
2539
|
motion: out.motion,
|
|
2403
2540
|
hold: out.hold,
|
|
2404
|
-
..._optionalChain([scene, 'access',
|
|
2541
|
+
..._optionalChain([scene, 'access', _108 => _108.presets, 'optionalAccess', _109 => _109.length]) ? { presets: scene.presets } : {},
|
|
2405
2542
|
...out.trigger ? { trigger: out.trigger } : {}
|
|
2406
2543
|
};
|
|
2407
2544
|
}
|
|
@@ -2445,7 +2582,7 @@ function resolvePlaceholders(motion, notes) {
|
|
|
2445
2582
|
const filled = text.replace(PLACEHOLDER, (_, name) => {
|
|
2446
2583
|
const d = declared.get(name);
|
|
2447
2584
|
if (!d) unknown.add(name);
|
|
2448
|
-
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess',
|
|
2585
|
+
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _110 => _110.value]), () => ( ""))).replace(/"/g, '\\"');
|
|
2449
2586
|
});
|
|
2450
2587
|
for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
|
|
2451
2588
|
return { motion: JSON.parse(filled), controls };
|
|
@@ -2499,7 +2636,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2499
2636
|
if (anim.along) {
|
|
2500
2637
|
const path = nodes.get(anim.along);
|
|
2501
2638
|
if (!path || path.node.type !== "path") notes.push(`${where} follows "${anim.along}", which is not a path in the artwork; the follow was skipped.`);
|
|
2502
|
-
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access',
|
|
2639
|
+
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _111 => _111.at, 'optionalAccess', _112 => _112[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _113 => _113.at, 'optionalAccess', _114 => _114[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2503
2640
|
}
|
|
2504
2641
|
for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
|
|
2505
2642
|
if (attr === "opacity") {
|
|
@@ -2510,7 +2647,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2510
2647
|
out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
|
|
2511
2648
|
} else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2512
2649
|
} else if (attr === "fill" || attr === "stroke") {
|
|
2513
|
-
if (_optionalChain([behavior, 'optionalAccess',
|
|
2650
|
+
if (_optionalChain([behavior, 'optionalAccess', _115 => _115.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
|
|
2514
2651
|
else {
|
|
2515
2652
|
if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
|
|
2516
2653
|
out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
@@ -2691,6 +2828,7 @@ function toLottie(scene, options = {}) {
|
|
|
2691
2828
|
const timeline = compileMotionScene(scene);
|
|
2692
2829
|
const nodes = indexMotionNodes(scene.artwork.nodes);
|
|
2693
2830
|
const notes = [];
|
|
2831
|
+
if (scene.motionBlur) notes.push("Motion blur is drawn on the stage only; the Lottie plays sharp.");
|
|
2694
2832
|
if (scene.trigger) notes.push(`The scene plays on ${scene.trigger}; Lottie has no trigger, so it plays through (markers show where each shot starts, for a player to stop at).`);
|
|
2695
2833
|
let sampled = 0;
|
|
2696
2834
|
const track = (id, p) => _nullishCoalesce(timeline.tracks.get(motionTrackKey(id, p)), () => ( []));
|
|
@@ -2762,16 +2900,22 @@ function toLottie(scene, options = {}) {
|
|
|
2762
2900
|
const tr = STATIC_TR();
|
|
2763
2901
|
const c = [entry.center.x, entry.center.y].map(round2);
|
|
2764
2902
|
const own = (p) => track(id, p);
|
|
2765
|
-
const
|
|
2903
|
+
const sources = motionDriverSources(timeline, id, ["x", "y", "rotation", "scaleX", "scaleY"]);
|
|
2904
|
+
const layered = ["x", "y", "rotation", "scaleX", "scaleY"].some((p) => layers(id, p).length) || sources.length > 0;
|
|
2766
2905
|
const moving = ["x", "y", "rotation", "scaleX", "scaleY", "follow"].some((p) => own(p).length) || layered;
|
|
2767
2906
|
if (moving) {
|
|
2768
2907
|
const mixed = own("follow").length > 0 || layered;
|
|
2769
2908
|
tr.a = { a: 0, k: c };
|
|
2770
|
-
tr.p = animate(mixed ? [...own("x"), ...own("y"), ...own("follow"), ...layers(id, "x"), ...layers(id, "y")] : [...own("x"), ...own("y")], (t) => poseAt(entry, t).p, !mixed);
|
|
2771
|
-
tr.r = animate(mixed ? [...own("rotation"), ...own("follow"), ...layers(id, "rotation")] : own("rotation"), (t) => [poseAt(entry, t).r], !mixed);
|
|
2772
|
-
tr.s = animate(mixed ? [...own("scaleX"), ...own("scaleY"), ...layers(id, "scaleX"), ...layers(id, "scaleY")] : [...own("scaleX"), ...own("scaleY")], (t) => poseAt(entry, t).s, !mixed);
|
|
2909
|
+
tr.p = animate(mixed ? [...own("x"), ...own("y"), ...own("follow"), ...layers(id, "x"), ...layers(id, "y"), ...sources] : [...own("x"), ...own("y")], (t) => poseAt(entry, t).p, !mixed);
|
|
2910
|
+
tr.r = animate(mixed ? [...own("rotation"), ...own("follow"), ...layers(id, "rotation"), ...sources] : own("rotation"), (t) => [poseAt(entry, t).r], !mixed);
|
|
2911
|
+
tr.s = animate(mixed ? [...own("scaleX"), ...own("scaleY"), ...layers(id, "scaleX"), ...layers(id, "scaleY"), ...sources] : [...own("scaleX"), ...own("scaleY")], (t) => poseAt(entry, t).s, !mixed);
|
|
2773
2912
|
if (tr.p.a === 0) tr.p = { a: 0, k: poseAt(entry, 0).p.map(round2) };
|
|
2774
2913
|
}
|
|
2914
|
+
const opacitySources = motionDriverSources(timeline, id, ["opacity"]);
|
|
2915
|
+
if (opacitySources.length) {
|
|
2916
|
+
tr.o = animate([...own("opacity"), ...opacitySources], (t) => [motionPropertyValue(timeline, id, "opacity", t) * 100], false);
|
|
2917
|
+
return tr;
|
|
2918
|
+
}
|
|
2775
2919
|
const opacity = own("opacity");
|
|
2776
2920
|
const rest = _nullishCoalesce(entry.node.opacity, () => ( 1));
|
|
2777
2921
|
tr.o = opacity.length ? animate(opacity, (t) => [Math.min(1, Math.max(0, Number(_nullishCoalesce(trackValue(opacity, t), () => ( rest))))) * 100]) : { a: 0, k: round2(rest * 100) };
|
|
@@ -2793,7 +2937,7 @@ function toLottie(scene, options = {}) {
|
|
|
2793
2937
|
const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
|
|
2794
2938
|
const geometryAt = (t) => {
|
|
2795
2939
|
if (!shapeSegments.length) return _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2796
|
-
const now = _optionalChain([indexMotionNodes, 'call',
|
|
2940
|
+
const now = _optionalChain([indexMotionNodes, 'call', _116 => _116(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _117 => _117.get, 'call', _118 => _118(path.id), 'optionalAccess', _119 => _119.node]);
|
|
2797
2941
|
return now && now.type === "path" ? _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2798
2942
|
};
|
|
2799
2943
|
const rest = lottieContours(_chunkO2UH7LZEcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
|
|
@@ -2841,7 +2985,7 @@ function toLottie(scene, options = {}) {
|
|
|
2841
2985
|
lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
|
|
2842
2986
|
ml: 4
|
|
2843
2987
|
});
|
|
2844
|
-
if (_optionalChain([path, 'access',
|
|
2988
|
+
if (_optionalChain([path, 'access', _120 => _120.strokeDasharray, 'optionalAccess', _121 => _121.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
|
|
2845
2989
|
if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
|
|
2846
2990
|
}
|
|
2847
2991
|
const fill = paintOf(path.fill, "fill", path.id);
|
|
@@ -2992,7 +3136,7 @@ var AnimationEditorController = (_class = class {
|
|
|
2992
3136
|
time: p.time,
|
|
2993
3137
|
playing: p.playing,
|
|
2994
3138
|
loop: p.loop,
|
|
2995
|
-
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call',
|
|
3139
|
+
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _122 => _122(timeline, p.time), 'optionalAccess', _123 => _123.id]), () => ( null)),
|
|
2996
3140
|
selection: this.selection,
|
|
2997
3141
|
readOnly: this.readOnly,
|
|
2998
3142
|
error: this.error,
|
|
@@ -3031,7 +3175,7 @@ var AnimationEditorController = (_class = class {
|
|
|
3031
3175
|
this.applying = false;
|
|
3032
3176
|
}
|
|
3033
3177
|
this.notify();
|
|
3034
|
-
_optionalChain([this, 'access',
|
|
3178
|
+
_optionalChain([this, 'access', _124 => _124.onChange, 'optionalCall', _125 => _125(scene)]);
|
|
3035
3179
|
}
|
|
3036
3180
|
commit(label, next) {
|
|
3037
3181
|
const before = this.scene;
|
|
@@ -3351,6 +3495,10 @@ var SETTINGS = {
|
|
|
3351
3495
|
},
|
|
3352
3496
|
fps: { type: "number", minimum: 1, maximum: 120, description: "Sampling rate for exports (default 30)." },
|
|
3353
3497
|
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).' },
|
|
3498
|
+
motionBlur: {
|
|
3499
|
+
anyOf: [object({ shutter: { type: "number", exclusiveMinimum: 0, maximum: 720, description: "Shutter angle in degrees of a frame (default 180; 360 is a whole frame, more blur)." }, samples: { type: "integer", minimum: 2, maximum: 32, description: "Most moments a frame averages (default 8)." } }), { type: "null" }],
|
|
3500
|
+
description: "Motion blur on the stage and in rendered frames (not exported to Flair or Lottie); null turns it off."
|
|
3501
|
+
},
|
|
3354
3502
|
beat: {
|
|
3355
3503
|
anyOf: [
|
|
3356
3504
|
object({ bpm: { type: "number", minimum: 1, maximum: 1e3, description: "Beats a minute." }, offset: { type: "number", description: "When beat 0 falls, ms (default 0)." }, meter: { type: "integer", minimum: 1, description: "Beats a bar (default 4)." } }, ["bpm"]),
|
|
@@ -3476,6 +3624,8 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3476
3624
|
...includeElements ? { elements: describeMotionElements(s) } : {},
|
|
3477
3625
|
shots: describeMotionShots(s),
|
|
3478
3626
|
...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) }])) } : {},
|
|
3627
|
+
...s.drivers ? { drivers: s.drivers } : {},
|
|
3628
|
+
...s.motionBlur ? { motionBlur: s.motionBlur } : {},
|
|
3479
3629
|
...s.controls ? { controls: s.controls } : {},
|
|
3480
3630
|
...s.presets ? { presets: s.presets } : {},
|
|
3481
3631
|
issues: issueSummary(controller.getState().issues),
|
|
@@ -3590,9 +3740,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3590
3740
|
handler: ({ from = 0, to, limit = 200 }) => {
|
|
3591
3741
|
const s = scene();
|
|
3592
3742
|
const timeline = compileMotionScene(s);
|
|
3593
|
-
const words = _nullishCoalesce(_optionalChain([s, 'access',
|
|
3743
|
+
const words = _nullishCoalesce(_optionalChain([s, 'access', _126 => _126.narration, 'optionalAccess', _127 => _127.words]), () => ( []));
|
|
3594
3744
|
const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
|
|
3595
|
-
const shotAt = (ms) => _optionalChain([timeline, 'access',
|
|
3745
|
+
const shotAt = (ms) => _optionalChain([timeline, 'access', _128 => _128.shots, 'access', _129 => _129.find, 'call', _130 => _130((x) => ms >= x.start && ms < x.end), 'optionalAccess', _131 => _131.id]);
|
|
3596
3746
|
const beats = [];
|
|
3597
3747
|
if (s.beat && s.beat.bpm > 0) {
|
|
3598
3748
|
const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
|
|
@@ -3734,6 +3884,36 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3734
3884
|
return apply(edits, "Fit to length", () => report);
|
|
3735
3885
|
}
|
|
3736
3886
|
};
|
|
3887
|
+
const PROP = { type: "string", enum: ["x", "y", "rotation", "scaleX", "scaleY", "opacity"], description: "x / y (offset, document units), rotation (degrees), scaleX / scaleY or opacity (1 = rest)." };
|
|
3888
|
+
const setDrivers = {
|
|
3889
|
+
name: "set_animation_drivers",
|
|
3890
|
+
title: "Make properties follow others",
|
|
3891
|
+
description: "Replaces the drivers (empty clears them): each makes a target's property follow a source node's property, as a change from rest \u2014 target change = source change \xB7 factor + offset, clamped \u2014 added to offsets and turns, multiplied into scales and opacity, on top of the target's own commands. For parallax (x follows x \xB7 0.5), a wheel turning as it rolls (rotation follows x \xB7 360 / (2\u03C0\xB7radius)), a shadow fading as a ball rises (opacity follows y \xB7 0.005). One undo step; loops between drivers are refused by check_animation. Returns the timing and issues.",
|
|
3892
|
+
inputSchema: object(
|
|
3893
|
+
{
|
|
3894
|
+
drivers: {
|
|
3895
|
+
type: "array",
|
|
3896
|
+
maxItems: 64,
|
|
3897
|
+
items: object(
|
|
3898
|
+
{
|
|
3899
|
+
target: { type: "string", minLength: 1, description: "Element id that follows." },
|
|
3900
|
+
property: PROP,
|
|
3901
|
+
source: object({ node: { type: "string", minLength: 1, description: "Element id it follows." }, property: PROP }, ["node", "property"], "What it follows."),
|
|
3902
|
+
factor: { type: "number", description: "Multiplies the source's change (default 1)." },
|
|
3903
|
+
offset: { type: "number", description: "Added to the change (default 0)." },
|
|
3904
|
+
clamp: { type: "array", items: { type: "number" }, minItems: 2, maxItems: 2, description: "Limits the change to [min, max]." }
|
|
3905
|
+
},
|
|
3906
|
+
["target", "property", "source"],
|
|
3907
|
+
"One property following another."
|
|
3908
|
+
),
|
|
3909
|
+
description: "Every driver (the list replaces the current one)."
|
|
3910
|
+
}
|
|
3911
|
+
},
|
|
3912
|
+
["drivers"]
|
|
3913
|
+
),
|
|
3914
|
+
annotations: { title: "Make properties follow others", ...WRITE_IDEMPOTENT },
|
|
3915
|
+
handler: ({ drivers }) => apply({ op: "set_drivers", drivers }, "Set drivers")
|
|
3916
|
+
};
|
|
3737
3917
|
const setClip = {
|
|
3738
3918
|
name: "set_animation_clip",
|
|
3739
3919
|
title: "Define a reusable clip",
|
|
@@ -3842,7 +4022,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3842
4022
|
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"]),
|
|
3843
4023
|
annotations: { title: "Add commands to a shot", ...WRITE },
|
|
3844
4024
|
handler: ({ shot, commands, at }) => {
|
|
3845
|
-
const before = _nullishCoalesce(_optionalChain([scene, 'call',
|
|
4025
|
+
const before = _nullishCoalesce(_optionalChain([scene, 'call', _132 => _132(), 'access', _133 => _133.shots, 'access', _134 => _134.find, 'call', _135 => _135((s) => s.id === shot), 'optionalAccess', _136 => _136.run, 'access', _137 => _137.length]), () => ( 0));
|
|
3846
4026
|
const first = _nullishCoalesce(at, () => ( before));
|
|
3847
4027
|
return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
|
|
3848
4028
|
const shots = describeMotionShots(s);
|
|
@@ -3974,7 +4154,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3974
4154
|
}
|
|
3975
4155
|
};
|
|
3976
4156
|
const reads = [getAnimation, getShot, findElements, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
|
|
3977
|
-
const writes = [setArtworkSvg, setClip, copyAnimation, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
|
|
4157
|
+
const writes = [setArtworkSvg, setDrivers, setClip, copyAnimation, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
|
|
3978
4158
|
return {
|
|
3979
4159
|
id: _nullishCoalesce(options.id, () => ( "animation")),
|
|
3980
4160
|
namespace: options.namespace,
|
|
@@ -4007,6 +4187,8 @@ Commands
|
|
|
4007
4187
|
- 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.
|
|
4008
4188
|
- 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.
|
|
4009
4189
|
- Drawing a group of strokes: "order": "sequence" draws them one after another (a signature, a diagram), "sortBy": "distance" from "origin" reveals outward, "pace": "speed" keeps one speed; draw with "comet": 0.2 sends a short stroke along a path and off the end.
|
|
4190
|
+
- Fast motion reads better with blur: set_animation_settings { "motionBlur": { "shutter": 180 } } (stage and rendered frames only).
|
|
4191
|
+
- Tie properties together with set_animation_drivers: parallax layers, a wheel that turns as it rolls, a shadow that fades as something rises. Drivers add to the target's own commands.
|
|
4010
4192
|
- 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.
|
|
4011
4193
|
- 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.
|
|
4012
4194
|
- enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting "scale".
|
|
@@ -4035,7 +4217,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
|
|
|
4035
4217
|
var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
|
|
4036
4218
|
var NODES = /* @__PURE__ */ new Set(["into", "path"]);
|
|
4037
4219
|
function branch(type) {
|
|
4038
|
-
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access',
|
|
4220
|
+
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _138 => _138.properties, 'optionalAccess', _139 => _139.type, 'optionalAccess', _140 => _140.const]) === type);
|
|
4039
4221
|
}
|
|
4040
4222
|
function unitOf(type, name) {
|
|
4041
4223
|
if (name === "duration" || name === "delay" || name === "stagger") return "ms";
|
|
@@ -4070,7 +4252,7 @@ function kindOf(name, schema) {
|
|
|
4070
4252
|
}
|
|
4071
4253
|
function motionCommandFields(type) {
|
|
4072
4254
|
const schema = branch(type);
|
|
4073
|
-
if (!_optionalChain([schema, 'optionalAccess',
|
|
4255
|
+
if (!_optionalChain([schema, 'optionalAccess', _141 => _141.properties])) return [];
|
|
4074
4256
|
const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
|
|
4075
4257
|
const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
|
|
4076
4258
|
const kind = kindOf(name, s);
|
|
@@ -4127,7 +4309,7 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
4127
4309
|
if (type === "wait") return { type: "wait", duration: 500 };
|
|
4128
4310
|
if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
|
|
4129
4311
|
const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
|
|
4130
|
-
const other = (pred) => _optionalChain([nodes, 'access',
|
|
4312
|
+
const other = (pred) => _optionalChain([nodes, 'access', _142 => _142.find, 'call', _143 => _143((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _144 => _144.node, 'access', _145 => _145.id]);
|
|
4131
4313
|
const base = { targets: [...targets] };
|
|
4132
4314
|
switch (type) {
|
|
4133
4315
|
case "scale":
|
|
@@ -4158,8 +4340,8 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
4158
4340
|
}
|
|
4159
4341
|
case "effect": {
|
|
4160
4342
|
for (const id of targets) {
|
|
4161
|
-
const node = _optionalChain([nodes, 'access',
|
|
4162
|
-
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess',
|
|
4343
|
+
const node = _optionalChain([nodes, 'access', _146 => _146.find, 'call', _147 => _147((e) => e.node.id === id), 'optionalAccess', _148 => _148.node]);
|
|
4344
|
+
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _149 => _149.effects]), () => ( []))) {
|
|
4163
4345
|
const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
|
|
4164
4346
|
if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
|
|
4165
4347
|
}
|
|
@@ -4184,11 +4366,11 @@ function motionCommandRows(scene, shotId) {
|
|
|
4184
4366
|
return scene.shots[index].run.map((command2, i) => {
|
|
4185
4367
|
const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
|
|
4186
4368
|
const primitive = motionFlairPrimitive(command2);
|
|
4187
|
-
return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess',
|
|
4369
|
+
return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _150 => _150.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _151 => _151.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
|
|
4188
4370
|
});
|
|
4189
4371
|
}
|
|
4190
4372
|
function duplicateMotionCommandEdit(scene, shot, command2) {
|
|
4191
|
-
const run = _nullishCoalesce(_optionalChain([scene, 'access',
|
|
4373
|
+
const run = _nullishCoalesce(_optionalChain([scene, 'access', _152 => _152.shots, 'access', _153 => _153.find, 'call', _154 => _154((s) => s.id === shot), 'optionalAccess', _155 => _155.run]), () => ( []));
|
|
4192
4374
|
return { op: "add_commands", shot, commands: run[command2] ? [structuredClone(run[command2])] : [], at: command2 + 1 };
|
|
4193
4375
|
}
|
|
4194
4376
|
var MOTION_EASE_CHOICES = [
|
|
@@ -4273,7 +4455,7 @@ function motionCueFromKey(key) {
|
|
|
4273
4455
|
function motionCueChoices(scene, limit = 256) {
|
|
4274
4456
|
const choices = [];
|
|
4275
4457
|
const s = (ms) => `${(ms / 1e3).toFixed(2)} s`;
|
|
4276
|
-
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access',
|
|
4458
|
+
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _156 => _156.narration, 'optionalAccess', _157 => _157.words, 'access', _158 => _158.map, 'call', _159 => _159((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
|
|
4277
4459
|
if (scene.beat && scene.beat.bpm > 0) {
|
|
4278
4460
|
for (let beat = 0; choices.length < limit; beat++) {
|
|
4279
4461
|
const time = motionBeatTime(scene.beat, beat);
|
|
@@ -4283,7 +4465,7 @@ function motionCueChoices(scene, limit = 256) {
|
|
|
4283
4465
|
choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
|
|
4284
4466
|
}
|
|
4285
4467
|
}
|
|
4286
|
-
_optionalChain([scene, 'access',
|
|
4468
|
+
_optionalChain([scene, 'access', _160 => _160.narration, 'optionalAccess', _161 => _161.words, 'access', _162 => _162.forEach, 'call', _163 => _163((w, i) => {
|
|
4287
4469
|
if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
|
|
4288
4470
|
})]);
|
|
4289
4471
|
return choices;
|
|
@@ -4292,7 +4474,7 @@ function motionShotCueTime(scene, cue) {
|
|
|
4292
4474
|
return cue ? motionCueTime(scene, cue) : void 0;
|
|
4293
4475
|
}
|
|
4294
4476
|
function formatMotionNarration(narration) {
|
|
4295
|
-
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess',
|
|
4477
|
+
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _164 => _164.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
|
|
4296
4478
|
}
|
|
4297
4479
|
function parseMotionNarration(text) {
|
|
4298
4480
|
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
@@ -4307,6 +4489,36 @@ function parseMotionNarration(text) {
|
|
|
4307
4489
|
}
|
|
4308
4490
|
return { narration: { words } };
|
|
4309
4491
|
}
|
|
4492
|
+
function formatMotionDrivers(drivers) {
|
|
4493
|
+
return (_nullishCoalesce(drivers, () => ( []))).map((d) => `${d.target}.${d.property} <- ${d.source.node}.${d.source.property}${d.factor !== void 0 && d.factor !== 1 ? ` * ${d.factor}` : ""}${d.offset ? ` ${d.offset < 0 ? "-" : "+"} ${Math.abs(d.offset)}` : ""}${d.clamp ? ` [${d.clamp[0]}, ${d.clamp[1]}]` : ""}`).join("\n");
|
|
4494
|
+
}
|
|
4495
|
+
function parseMotionDrivers(text) {
|
|
4496
|
+
const props = MOTION_DRIVEN_PROPERTIES;
|
|
4497
|
+
const drivers = [];
|
|
4498
|
+
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
4499
|
+
for (const [i, line] of lines.entries()) {
|
|
4500
|
+
const m = /^([\w.-]+)\.(\w+)\s*<-\s*([\w.-]+)\.(\w+)\s*(?:\*\s*(-?[\d.]+(?:e-?\d+)?))?\s*(?:([+-])\s*([\d.]+(?:e-?\d+)?))?\s*(?:\[\s*(-?[\d.]+)\s*,\s*(-?[\d.]+)\s*\])?$/.exec(line);
|
|
4501
|
+
if (!m) return { error: `Line ${i + 1} ("${line}") should read "target.property <- source.property", optionally "* factor", "+ offset" and "[min, max]", e.g. "dot.x <- box.x * 0.5".` };
|
|
4502
|
+
const [, target, property, node, sourceProperty, factor, sign, offset, min, max] = m;
|
|
4503
|
+
for (const p of [property, sourceProperty]) if (!props.includes(p)) return { error: `Line ${i + 1}: "${p}" is not a property drivers use; use ${MOTION_DRIVEN_PROPERTIES.join(", ")}.` };
|
|
4504
|
+
const d = { target, property, source: { node, property: sourceProperty } };
|
|
4505
|
+
if (factor !== void 0) d.factor = Number(factor);
|
|
4506
|
+
if (offset !== void 0) d.offset = (sign === "-" ? -1 : 1) * Number(offset);
|
|
4507
|
+
if (min !== void 0) d.clamp = [Number(min), Number(max)];
|
|
4508
|
+
if ([d.factor, d.offset, ..._nullishCoalesce(d.clamp, () => ( []))].some((n) => n !== void 0 && !Number.isFinite(n))) return { error: `Line ${i + 1} has a number that cannot be read.` };
|
|
4509
|
+
drivers.push(d);
|
|
4510
|
+
}
|
|
4511
|
+
return { drivers };
|
|
4512
|
+
}
|
|
4513
|
+
|
|
4514
|
+
|
|
4515
|
+
|
|
4516
|
+
|
|
4517
|
+
|
|
4518
|
+
|
|
4519
|
+
|
|
4520
|
+
|
|
4521
|
+
|
|
4310
4522
|
|
|
4311
4523
|
|
|
4312
4524
|
|
|
@@ -4434,5 +4646,5 @@ function parseMotionNarration(text) {
|
|
|
4434
4646
|
|
|
4435
4647
|
|
|
4436
4648
|
|
|
4437
|
-
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.motionContactSheetSvg = motionContactSheetSvg; 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.resolveMotionEditRefs = resolveMotionEditRefs; 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;
|
|
4649
|
+
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_DRIVEN_PROPERTIES = MOTION_DRIVEN_PROPERTIES; 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.applyMotionDrivers = applyMotionDrivers; 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.driversShapeProblems = driversShapeProblems; exports.duplicateMotionCommandEdit = duplicateMotionCommandEdit; exports.fitMotionRect = fitMotionRect; exports.fitMotionScene = fitMotionScene; exports.fitMotionSceneEdits = fitMotionSceneEdits; exports.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.formatMotionDrivers = formatMotionDrivers; 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.motionBlurTimes = motionBlurTimes; exports.motionClipAttrs = motionClipAttrs; exports.motionClipLayout = motionClipLayout; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandFields = motionCommandFields; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCommandRows = motionCommandRows; exports.motionCommandSummary = motionCommandSummary; exports.motionContactSheetSvg = motionContactSheetSvg; exports.motionCueChoices = motionCueChoices; exports.motionCueFromKey = motionCueFromKey; exports.motionCueKey = motionCueKey; exports.motionCueTime = motionCueTime; exports.motionCycleDuration = motionCycleDuration; exports.motionDrivenNodes = motionDrivenNodes; exports.motionDriverSources = motionDriverSources; 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.motionPropertyValue = motionPropertyValue; 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.parseMotionDrivers = parseMotionDrivers; exports.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; exports.resolveMotionEditRefs = resolveMotionEditRefs; 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;
|
|
4438
4650
|
//# sourceMappingURL=index.cjs.map
|