@pixerate/editor 0.64.0 → 0.66.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 +481 -31
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +226 -4
- package/dist/animation-editor/index.d.ts +226 -4
- package/dist/animation-editor/index.js +459 -9
- package/dist/animation-editor/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -51,6 +51,7 @@ var _chunkA6PHCAGXcjs = require('../chunk-A6PHCAGX.cjs');
|
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
|
|
54
55
|
var _chunk2FHLHZALcjs = require('../chunk-2FHLHZAL.cjs');
|
|
55
56
|
|
|
56
57
|
// src/animation-editor/types.ts
|
|
@@ -1258,10 +1259,92 @@ function withViewBox(svg, box) {
|
|
|
1258
1259
|
return svg.replace(/viewBox="[^"]*"/, `viewBox="${f(box.x)} ${f(box.y)} ${f(box.width)} ${f(box.height)}"`);
|
|
1259
1260
|
}
|
|
1260
1261
|
|
|
1262
|
+
// src/animation-editor/onion.ts
|
|
1263
|
+
function motionGhosts(scene, time, onion = {}) {
|
|
1264
|
+
const before = Math.max(0, Math.floor(_nullishCoalesce(onion.before, () => ( 2))));
|
|
1265
|
+
const after = Math.max(0, Math.floor(_nullishCoalesce(onion.after, () => ( 0))));
|
|
1266
|
+
const base = Math.min(1, Math.max(0, _nullishCoalesce(onion.opacity, () => ( 0.35))));
|
|
1267
|
+
const timeline = compileMotionScene(scene);
|
|
1268
|
+
const ghosts = [];
|
|
1269
|
+
const push = (t, offset) => ghosts.push({ time: t, offset, opacity: Math.round(base / Math.abs(offset) * 1e3) / 1e3 });
|
|
1270
|
+
if (onion.spacing === "commands") {
|
|
1271
|
+
const marks = [...new Set(timeline.commands.flatMap((c) => [c.start, c.end]))].sort((a, b) => a - b);
|
|
1272
|
+
marks.filter((t) => t < time - 1e-6).reverse().slice(0, before).forEach((t, i) => push(t, -(i + 1)));
|
|
1273
|
+
marks.filter((t) => t > time + 1e-6).slice(0, after).forEach((t, i) => push(t, i + 1));
|
|
1274
|
+
return ghosts;
|
|
1275
|
+
}
|
|
1276
|
+
const spacing = typeof onion.spacing === "number" && onion.spacing > 0 ? onion.spacing : 1e3 / 12;
|
|
1277
|
+
for (let i = 1; i <= before && time - i * spacing >= 0; i++) push(time - i * spacing, -i);
|
|
1278
|
+
for (let i = 1; i <= after && time + i * spacing <= timeline.duration; i++) push(time + i * spacing, i);
|
|
1279
|
+
return ghosts;
|
|
1280
|
+
}
|
|
1281
|
+
var MOVING = ["x", "y", "rotation", "scaleX", "scaleY", "follow", "shape"];
|
|
1282
|
+
function motionMovingIds(scene) {
|
|
1283
|
+
const timeline = compileMotionScene(scene);
|
|
1284
|
+
const nodes = indexMotionNodes(scene.artwork.nodes);
|
|
1285
|
+
const moving = new Set(timeline.segments.filter((s) => s.node && MOVING.includes(s.property)).map((s) => s.node));
|
|
1286
|
+
return [...nodes.values()].filter((e) => e.node.visible !== false && (moving.has(e.node.id) || e.ancestors.some((a) => moving.has(a)))).map((e) => e.node.id);
|
|
1287
|
+
}
|
|
1288
|
+
function motionPath(scene, id, options = {}) {
|
|
1289
|
+
const nodes = indexMotionNodes(scene.artwork.nodes);
|
|
1290
|
+
const entry = nodes.get(id);
|
|
1291
|
+
if (!entry) throw new Error(`There is no element "${id}" in the artwork.`);
|
|
1292
|
+
const timeline = compileMotionScene(scene);
|
|
1293
|
+
const from = Math.max(0, _nullishCoalesce(options.from, () => ( 0)));
|
|
1294
|
+
const to = Math.min(timeline.duration, _nullishCoalesce(options.to, () => ( timeline.duration)));
|
|
1295
|
+
let step = options.step && options.step > 0 ? options.step : 1e3 / 30;
|
|
1296
|
+
if ((to - from) / step > 400) step = (to - from) / 400;
|
|
1297
|
+
const r = (n) => Math.round(n * 100) / 100;
|
|
1298
|
+
const centreAt = (t) => {
|
|
1299
|
+
const node = indexMotionNodes(motionFrameAtCache(scene, t)).get(id);
|
|
1300
|
+
const b = _optionalChain([node, 'optionalAccess', _34 => _34.bounds]);
|
|
1301
|
+
return b ? { t: r(t), x: r(b.x + b.width / 2), y: r(b.y + b.height / 2) } : null;
|
|
1302
|
+
};
|
|
1303
|
+
const points = [];
|
|
1304
|
+
for (let t = from; t <= to + 1e-6; t += step) {
|
|
1305
|
+
const p = centreAt(Math.min(t, to));
|
|
1306
|
+
if (p) points.push(p);
|
|
1307
|
+
}
|
|
1308
|
+
const owners = /* @__PURE__ */ new Set([id, ...entry.ancestors]);
|
|
1309
|
+
const times = [...new Set(timeline.segments.filter((s) => owners.has(s.node) && MOVING.includes(s.property)).flatMap((s) => [s.start, s.end]))].filter((t) => t >= from && t <= to).sort((a, b) => a - b);
|
|
1310
|
+
const keys = times.map(centreAt).filter((p) => p !== null);
|
|
1311
|
+
return { id, points, keys };
|
|
1312
|
+
}
|
|
1313
|
+
function motionFrameAtCache(scene, t) {
|
|
1314
|
+
return motionFrameAt(scene, t).document.nodes;
|
|
1315
|
+
}
|
|
1316
|
+
function motionPathsSvg(paths, camera, color = "#f43f5e") {
|
|
1317
|
+
const w = Math.max(camera.width, camera.height) / 400;
|
|
1318
|
+
const f = (n) => String(Math.round(n * 100) / 100);
|
|
1319
|
+
return paths.filter((p) => p.points.length > 1).map(
|
|
1320
|
+
(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>`
|
|
1321
|
+
).join("");
|
|
1322
|
+
}
|
|
1323
|
+
var innerSvg = (svg) => svg.slice(svg.indexOf(">") + 1, svg.lastIndexOf("</svg>"));
|
|
1324
|
+
function motionStageSvg(scene, time, options = {}) {
|
|
1325
|
+
const { onionSkin, motionPaths, motionPathColor, ...svgOptions } = options;
|
|
1326
|
+
const current = motionFrameToSvg(scene, time, svgOptions);
|
|
1327
|
+
if (!onionSkin && !motionPaths) return current;
|
|
1328
|
+
const prefix = _nullishCoalesce(svgOptions.idPrefix, () => ( "vg-"));
|
|
1329
|
+
const ghosts = onionSkin ? motionGhosts(scene, time, onionSkin).map((g, i) => {
|
|
1330
|
+
const own = `${prefix}ghost${i}-`;
|
|
1331
|
+
const inner = innerSvg(motionFrameToSvg(scene, g.time, { ...svgOptions, idPrefix: own, background: false })).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
|
|
1332
|
+
return `<g data-onion="${g.offset < 0 ? "before" : "after"}" opacity="${g.opacity}">${inner}</g>`;
|
|
1333
|
+
}) : [];
|
|
1334
|
+
const camera = motionFrameAt(scene, time).camera;
|
|
1335
|
+
const ids = motionPaths === true ? motionMovingIds(scene) : motionPaths ? [...motionPaths] : [];
|
|
1336
|
+
const paths = ids.length ? motionPathsSvg(ids.map((id) => motionPath(scene, id)), camera, motionPathColor) : "";
|
|
1337
|
+
const open = current.indexOf(">") + 1;
|
|
1338
|
+
const close = current.lastIndexOf("</svg>");
|
|
1339
|
+
const body = current.slice(open, close);
|
|
1340
|
+
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _35 => _35.exec, 'call', _36 => _36(body), 'optionalAccess', _37 => _37[0]]), () => ( "")) : "";
|
|
1341
|
+
return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1261
1344
|
// src/animation-editor/check.ts
|
|
1262
1345
|
var MOTION_MIN_CHANGE_MS = 120;
|
|
1263
1346
|
var NUMERIC_PARAMS = (node, effectId) => {
|
|
1264
|
-
const effect = _optionalChain([node, 'access',
|
|
1347
|
+
const effect = _optionalChain([node, 'access', _38 => _38.effects, 'optionalAccess', _39 => _39.find, 'call', _40 => _40((e) => e.id === effectId)]);
|
|
1265
1348
|
if (!effect) return null;
|
|
1266
1349
|
return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
|
|
1267
1350
|
};
|
|
@@ -1414,7 +1497,7 @@ function checkMotionScene(scene) {
|
|
|
1414
1497
|
if (!shot.at) return;
|
|
1415
1498
|
const timing = timeline.shots[i];
|
|
1416
1499
|
if (timing.cue === void 0) {
|
|
1417
|
-
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',
|
|
1500
|
+
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', _41 => _41.narration, 'optionalAccess', _42 => _42.words, 'access', _43 => _43.length]), () => ( 0))} words (indexes from 0)`;
|
|
1418
1501
|
issues.push(motionIssue("unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
|
|
1419
1502
|
} else if (timing.missedBy !== void 0) {
|
|
1420
1503
|
const late = Math.round(timing.missedBy);
|
|
@@ -1447,7 +1530,7 @@ function checkMotionScene(scene) {
|
|
|
1447
1530
|
const cam = frame.camera;
|
|
1448
1531
|
const docIndex = indexMotionNodes(frame.document.nodes);
|
|
1449
1532
|
for (const id of command2.targets) {
|
|
1450
|
-
const b = _optionalChain([docIndex, 'access',
|
|
1533
|
+
const b = _optionalChain([docIndex, 'access', _44 => _44.get, 'call', _45 => _45(id), 'optionalAccess', _46 => _46.bounds]);
|
|
1451
1534
|
if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
|
|
1452
1535
|
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;
|
|
1453
1536
|
if (outside) {
|
|
@@ -1481,6 +1564,7 @@ var MOTION_EDIT_OPS = [
|
|
|
1481
1564
|
"add_commands",
|
|
1482
1565
|
"update_command",
|
|
1483
1566
|
"delete_commands",
|
|
1567
|
+
"move_command",
|
|
1484
1568
|
"set_artwork",
|
|
1485
1569
|
"set_controls",
|
|
1486
1570
|
"replace_scene"
|
|
@@ -1605,6 +1689,16 @@ function applyOne(scene, edit) {
|
|
|
1605
1689
|
const drop = new Set(edit.commands);
|
|
1606
1690
|
return replaceShot(scene, i, { ...scene.shots[i], run: run.filter((_, k) => !drop.has(k)) });
|
|
1607
1691
|
}
|
|
1692
|
+
case "move_command": {
|
|
1693
|
+
const i = shotIndex(scene, edit.shot);
|
|
1694
|
+
const run = [...scene.shots[i].run];
|
|
1695
|
+
if (!Number.isInteger(edit.command) || edit.command < 0 || edit.command >= run.length)
|
|
1696
|
+
fail(`Shot "${edit.shot}" has ${run.length} command${run.length === 1 ? "" : "s"}; "command" must be an index from 0 to ${run.length - 1} (got ${edit.command}).`);
|
|
1697
|
+
const to = position(edit.to, run.length - 1, '"to"');
|
|
1698
|
+
const [moved] = run.splice(edit.command, 1);
|
|
1699
|
+
run.splice(to, 0, moved);
|
|
1700
|
+
return replaceShot(scene, i, { ...scene.shots[i], run });
|
|
1701
|
+
}
|
|
1608
1702
|
case "set_artwork":
|
|
1609
1703
|
return { ...scene, artwork: edit.artwork };
|
|
1610
1704
|
case "set_controls": {
|
|
@@ -1637,9 +1731,9 @@ function applyMotionEdits(scene, edits) {
|
|
|
1637
1731
|
let next = scene;
|
|
1638
1732
|
for (let i = 0; i < list.length; i++) {
|
|
1639
1733
|
const edit = list[i];
|
|
1640
|
-
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess',
|
|
1734
|
+
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _47 => _47.op])}): ` : "";
|
|
1641
1735
|
if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
|
|
1642
|
-
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess',
|
|
1736
|
+
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _48 => _48.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
|
|
1643
1737
|
try {
|
|
1644
1738
|
next = applyOne(next, edit);
|
|
1645
1739
|
} catch (error) {
|
|
@@ -1799,7 +1893,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1799
1893
|
const wrapper = freshId(`${id}--follow`);
|
|
1800
1894
|
const centre = freshId(`${id}--follow-centre`);
|
|
1801
1895
|
const c = entry.center;
|
|
1802
|
-
const at = _optionalChain([motionNodeOffset, 'call',
|
|
1896
|
+
const at = _optionalChain([motionNodeOffset, 'call', _49 => _49(entry, timeline, 0, nodes), 'optionalAccess', _50 => _50.follow]);
|
|
1803
1897
|
const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
|
|
1804
1898
|
(wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
|
|
1805
1899
|
follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
|
|
@@ -1859,7 +1953,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1859
1953
|
exact: () => false,
|
|
1860
1954
|
value: (t) => {
|
|
1861
1955
|
const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
|
|
1862
|
-
const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call',
|
|
1956
|
+
const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _51 => _51(frame.document.nodes), 'access', _52 => _52.get, 'call', _53 => _53(id), 'optionalAccess', _54 => _54.node]));
|
|
1863
1957
|
if (!now || now.type !== "path") return "";
|
|
1864
1958
|
const bezier = _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, now, _chunkYJLCBA7Vcjs.IDENTITY_MATRIX, { effects: false }), inverse);
|
|
1865
1959
|
return _chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
|
|
@@ -1880,8 +1974,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1880
1974
|
...delay > 0 ? { delay: round2(delay) } : {},
|
|
1881
1975
|
ms: round2(ms),
|
|
1882
1976
|
ease: written,
|
|
1883
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
1884
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
1977
|
+
..._optionalChain([segment, 'optionalAccess', _55 => _55.behavior]) ? { behavior: segment.behavior } : {},
|
|
1978
|
+
..._optionalChain([segment, 'optionalAccess', _56 => _56.steps]) ? { strobe: segment.steps } : {}
|
|
1885
1979
|
};
|
|
1886
1980
|
if (channel.kind === "view") animate.push({ ...base, view: to });
|
|
1887
1981
|
else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
|
|
@@ -1954,7 +2048,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
1954
2048
|
if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
|
|
1955
2049
|
const lastChange = animate.reduce((m, a) => Math.max(m, (_nullishCoalesce(a.delay, () => ( 0))) + (_nullishCoalesce(a.ms, () => ( 0)))), 0);
|
|
1956
2050
|
let motion = { svg, animate };
|
|
1957
|
-
if (_optionalChain([scene, 'access',
|
|
2051
|
+
if (_optionalChain([scene, 'access', _57 => _57.controls, 'optionalAccess', _58 => _58.length])) {
|
|
1958
2052
|
const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
|
|
1959
2053
|
const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
|
|
1960
2054
|
svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
|
|
@@ -1976,7 +2070,7 @@ function toFlairVectorEffect(scene, options = {}) {
|
|
|
1976
2070
|
tags: _nullishCoalesce(options.tags, () => ( [])),
|
|
1977
2071
|
motion: out.motion,
|
|
1978
2072
|
hold: out.hold,
|
|
1979
|
-
..._optionalChain([scene, 'access',
|
|
2073
|
+
..._optionalChain([scene, 'access', _59 => _59.presets, 'optionalAccess', _60 => _60.length]) ? { presets: scene.presets } : {},
|
|
1980
2074
|
...options.trigger ? { trigger: options.trigger } : {}
|
|
1981
2075
|
};
|
|
1982
2076
|
}
|
|
@@ -2019,7 +2113,7 @@ function resolvePlaceholders(motion, notes) {
|
|
|
2019
2113
|
const filled = text.replace(PLACEHOLDER, (_, name) => {
|
|
2020
2114
|
const d = declared.get(name);
|
|
2021
2115
|
if (!d) unknown.add(name);
|
|
2022
|
-
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess',
|
|
2116
|
+
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _61 => _61.value]), () => ( ""))).replace(/"/g, '\\"');
|
|
2023
2117
|
});
|
|
2024
2118
|
for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
|
|
2025
2119
|
return { motion: JSON.parse(filled), controls };
|
|
@@ -2073,7 +2167,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2073
2167
|
if (anim.along) {
|
|
2074
2168
|
const path = nodes.get(anim.along);
|
|
2075
2169
|
if (!path || path.node.type !== "path") notes.push(`${where} follows "${anim.along}", which is not a path in the artwork; the follow was skipped.`);
|
|
2076
|
-
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access',
|
|
2170
|
+
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _62 => _62.at, 'optionalAccess', _63 => _63[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _64 => _64.at, 'optionalAccess', _65 => _65[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2077
2171
|
}
|
|
2078
2172
|
for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
|
|
2079
2173
|
if (attr === "opacity") {
|
|
@@ -2084,7 +2178,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2084
2178
|
out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
|
|
2085
2179
|
} else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2086
2180
|
} else if (attr === "fill" || attr === "stroke") {
|
|
2087
|
-
if (_optionalChain([behavior, 'optionalAccess',
|
|
2181
|
+
if (_optionalChain([behavior, 'optionalAccess', _66 => _66.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
|
|
2088
2182
|
else {
|
|
2089
2183
|
if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
|
|
2090
2184
|
out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
@@ -2173,11 +2267,17 @@ function fromFlairSvgMotion(input, options = {}) {
|
|
|
2173
2267
|
${problems.join("\n")}`);
|
|
2174
2268
|
return { scene, notes: [...new Set(notes)], issues: checkMotionScene(scene) };
|
|
2175
2269
|
}
|
|
2270
|
+
function presetColor(value) {
|
|
2271
|
+
if (typeof value === "string") return /^#[0-9a-f]{6}$/i.test(value) ? value.toLowerCase() : value;
|
|
2272
|
+
if (Array.isArray(value) && value.length >= 3 && value.slice(0, 3).every((n) => typeof n === "number" && Number.isFinite(n)))
|
|
2273
|
+
return `#${value.slice(0, 3).map((n) => Math.round(Math.min(1, Math.max(0, n)) * 255).toString(16).padStart(2, "0")).join("")}`;
|
|
2274
|
+
return void 0;
|
|
2275
|
+
}
|
|
2176
2276
|
function fromFlairVectorEffect(effect, options = {}) {
|
|
2177
2277
|
if (!effect || effect.kind !== "vector" || !effect.motion) throw new Error('Give a Flair vector effect: { kind: "vector", id, name, motion: { svg, animate } }.');
|
|
2178
2278
|
const result = fromFlairSvgMotion(effect.motion, { name: _nullishCoalesce(_nullishCoalesce(options.name, () => ( effect.id)), () => ( effect.name)), hold: _nullishCoalesce(options.hold, () => ( effect.hold)) });
|
|
2179
2279
|
const names = new Set((_nullishCoalesce(result.scene.controls, () => ( []))).map((c) => c.name));
|
|
2180
|
-
const presets = (_nullishCoalesce(effect.presets, () => ( []))).map((p) => ({ name: p.name, values: Object.fromEntries(Object.entries(p.values).
|
|
2280
|
+
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);
|
|
2181
2281
|
const scene = { ...result.scene, ...effect.description ? { description: effect.description } : {}, ...presets.length ? { presets } : {} };
|
|
2182
2282
|
const notes = [...result.notes];
|
|
2183
2283
|
if (effect.trigger) notes.push(`The effect plays on ${effect.trigger}; scenes play through, so the trigger is not kept (pass it back to toFlairVectorEffect).`);
|
|
@@ -2360,7 +2460,7 @@ function toLottie(scene, options = {}) {
|
|
|
2360
2460
|
const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
|
|
2361
2461
|
const geometryAt = (t) => {
|
|
2362
2462
|
if (!shapeSegments.length) return _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2363
|
-
const now = _optionalChain([indexMotionNodes, 'call',
|
|
2463
|
+
const now = _optionalChain([indexMotionNodes, 'call', _67 => _67(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _68 => _68.get, 'call', _69 => _69(path.id), 'optionalAccess', _70 => _70.node]);
|
|
2364
2464
|
return now && now.type === "path" ? _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2365
2465
|
};
|
|
2366
2466
|
const rest = lottieContours(_chunkO2UH7LZEcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
|
|
@@ -2406,7 +2506,7 @@ function toLottie(scene, options = {}) {
|
|
|
2406
2506
|
lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
|
|
2407
2507
|
ml: 4
|
|
2408
2508
|
});
|
|
2409
|
-
if (_optionalChain([path, 'access',
|
|
2509
|
+
if (_optionalChain([path, 'access', _71 => _71.strokeDasharray, 'optionalAccess', _72 => _72.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
|
|
2410
2510
|
if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
|
|
2411
2511
|
}
|
|
2412
2512
|
const fill = paintOf(path.fill, "fill", path.id);
|
|
@@ -2556,7 +2656,7 @@ var AnimationEditorController = (_class = class {
|
|
|
2556
2656
|
time: p.time,
|
|
2557
2657
|
playing: p.playing,
|
|
2558
2658
|
loop: p.loop,
|
|
2559
|
-
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call',
|
|
2659
|
+
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _73 => _73(timeline, p.time), 'optionalAccess', _74 => _74.id]), () => ( null)),
|
|
2560
2660
|
selection: this.selection,
|
|
2561
2661
|
readOnly: this.readOnly,
|
|
2562
2662
|
error: this.error,
|
|
@@ -2595,7 +2695,7 @@ var AnimationEditorController = (_class = class {
|
|
|
2595
2695
|
this.applying = false;
|
|
2596
2696
|
}
|
|
2597
2697
|
this.notify();
|
|
2598
|
-
_optionalChain([this, 'access',
|
|
2698
|
+
_optionalChain([this, 'access', _75 => _75.onChange, 'optionalCall', _76 => _76(scene)]);
|
|
2599
2699
|
}
|
|
2600
2700
|
commit(label, next) {
|
|
2601
2701
|
const before = this.scene;
|
|
@@ -2701,7 +2801,7 @@ var AnimationEditorController = (_class = class {
|
|
|
2701
2801
|
}
|
|
2702
2802
|
/** The scene at `time` (default: the playhead) as SVG. */
|
|
2703
2803
|
toSvg(time = this.player.currentTime, options = {}) {
|
|
2704
|
-
return
|
|
2804
|
+
return motionStageSvg(this.scene, time, options);
|
|
2705
2805
|
}
|
|
2706
2806
|
/** The scene as a Flair `SvgMotion`. */
|
|
2707
2807
|
toFlairMotion(options = {}) {
|
|
@@ -2914,6 +3014,7 @@ var EDIT_OP = {
|
|
|
2914
3014
|
object({ op: { const: "move_shot", description: "Like move_shot." }, shot: SHOT_ID, to: { type: "integer", minimum: 0, description: "New position (0 = first)." } }, ["op", "shot", "to"]),
|
|
2915
3015
|
object({ op: { const: "add_commands", description: "Like add_commands." }, 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 shot's run (default: the end)." } }, ["op", "shot", "commands"]),
|
|
2916
3016
|
object({ op: { const: "update_command", description: "Like update_command." }, shot: SHOT_ID, command: { type: "integer", minimum: 0, description: "Index in the shot's run." }, set: { type: "object", description: "Command fields to replace." }, remove: { type: "array", items: { type: "string" }, description: "Command fields to clear." } }, ["op", "shot", "command"]),
|
|
3017
|
+
object({ op: { const: "move_command", description: "Like move_command." }, shot: SHOT_ID, command: { type: "integer", minimum: 0, description: "Index in the shot's run." }, to: { type: "integer", minimum: 0, description: "New index in the run (0 = first)." } }, ["op", "shot", "command", "to"]),
|
|
2917
3018
|
object({ op: { const: "delete_commands", description: "Like delete_commands." }, shot: SHOT_ID, commands: { type: "array", items: { type: "integer", minimum: 0 }, minItems: 1, description: "Indexes in the shot's run." } }, ["op", "shot", "commands"]),
|
|
2918
3019
|
object({ op: { const: "set_controls", description: "Like set_controls." }, controls: { type: "array", items: CONTROL, description: "Controls (empty clears)." }, presets: { type: "array", items: PRESET, description: "Presets (empty clears)." } }, ["op", "controls"])
|
|
2919
3020
|
]
|
|
@@ -3061,10 +3162,20 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3061
3162
|
time: MS("Time from the start"),
|
|
3062
3163
|
shot: { ...SHOT_ID, description: 'Render a moment of this shot instead of "time".' },
|
|
3063
3164
|
at: { type: "string", enum: ["start", "middle", "end"], description: "With shot: which moment (default end: everything drawn, before the next shot)." },
|
|
3064
|
-
format: { type: "string", enum: ["svg", "png"], description: "svg (default) or png (only when the host supports it)." }
|
|
3165
|
+
format: { type: "string", enum: ["svg", "png"], description: "svg (default) or png (only when the host supports it)." },
|
|
3166
|
+
onion_skin: object(
|
|
3167
|
+
{
|
|
3168
|
+
before: { type: "integer", minimum: 0, maximum: 12, description: "Ghost frames before the moment (default 2)." },
|
|
3169
|
+
after: { type: "integer", minimum: 0, maximum: 12, description: "Ghost frames after it (default 0)." },
|
|
3170
|
+
spacing: { anyOf: [{ type: "number", exclusiveMinimum: 0 }, { type: "string", enum: ["commands"] }], description: 'Ms between ghosts (default 83, every other frame at 24 fps), or "commands" for the moments commands start and end.' }
|
|
3171
|
+
},
|
|
3172
|
+
[],
|
|
3173
|
+
"Draw faded frames either side of the moment, to see motion in one picture."
|
|
3174
|
+
),
|
|
3175
|
+
motion_paths: { anyOf: [{ type: "boolean" }, { type: "array", items: { type: "string", minLength: 1 } }], description: "Draw where nodes travel (dashed, with a dot where each change starts or ends): true for every node whose place changes, or a list of ids." }
|
|
3065
3176
|
}),
|
|
3066
3177
|
annotations: { title: "Render a frame", ...READ },
|
|
3067
|
-
handler: async ({ time, shot, at = "end", format = "svg" }) => {
|
|
3178
|
+
handler: async ({ time, shot, at = "end", format = "svg", onion_skin, motion_paths }) => {
|
|
3068
3179
|
const s = scene();
|
|
3069
3180
|
let t = _nullishCoalesce(time, () => ( controller.getState().time));
|
|
3070
3181
|
if (shot !== void 0) {
|
|
@@ -3072,7 +3183,11 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3072
3183
|
if (!timing) throw new Error(`There is no shot "${shot}"; the shots are ${s.shots.map((x) => `"${x.id}"`).join(", ") || "none yet"}.`);
|
|
3073
3184
|
t = at === "start" ? timing.start : at === "middle" ? (timing.commandsStart + timing.commandsEnd) / 2 : Math.max(timing.start, timing.end - 1);
|
|
3074
3185
|
}
|
|
3075
|
-
|
|
3186
|
+
if (Array.isArray(motion_paths)) {
|
|
3187
|
+
const known = new Set(describeMotionElements(s).map((e) => e.id));
|
|
3188
|
+
for (const id of motion_paths) if (!known.has(id)) throw new Error(`There is no element ${namedWithSuggestion(id, known)} to draw a motion path for.`);
|
|
3189
|
+
}
|
|
3190
|
+
const svg = controller.toSvg(t, { pretty: false, ...onion_skin ? { onionSkin: onion_skin } : {}, ...motion_paths ? { motionPaths: motion_paths } : {} });
|
|
3076
3191
|
if (format === "png") {
|
|
3077
3192
|
if (!options.rasterize) throw new Error('This host cannot make PNG images; call render_animation_frame with format "svg".');
|
|
3078
3193
|
const image = await options.rasterize(svg, { width: s.artwork.width, height: s.artwork.height });
|
|
@@ -3097,9 +3212,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3097
3212
|
handler: ({ from = 0, to, limit = 200 }) => {
|
|
3098
3213
|
const s = scene();
|
|
3099
3214
|
const timeline = compileMotionScene(s);
|
|
3100
|
-
const words = _nullishCoalesce(_optionalChain([s, 'access',
|
|
3215
|
+
const words = _nullishCoalesce(_optionalChain([s, 'access', _77 => _77.narration, 'optionalAccess', _78 => _78.words]), () => ( []));
|
|
3101
3216
|
const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
|
|
3102
|
-
const shotAt = (ms) => _optionalChain([timeline, 'access',
|
|
3217
|
+
const shotAt = (ms) => _optionalChain([timeline, 'access', _79 => _79.shots, 'access', _80 => _80.find, 'call', _81 => _81((x) => ms >= x.start && ms < x.end), 'optionalAccess', _82 => _82.id]);
|
|
3103
3218
|
const beats = [];
|
|
3104
3219
|
if (s.beat && s.beat.bpm > 0) {
|
|
3105
3220
|
const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
|
|
@@ -3120,6 +3235,24 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3120
3235
|
};
|
|
3121
3236
|
}
|
|
3122
3237
|
};
|
|
3238
|
+
const getMotionPath = {
|
|
3239
|
+
name: "get_motion_path",
|
|
3240
|
+
title: "Read where a node travels",
|
|
3241
|
+
description: "Returns where a node's centre is over time, in document units (sampled), and where it is each time a change that moves it starts or ends. Use it to check a path, spacing or arc without reading pictures; render_animation_frame with motion_paths draws it.",
|
|
3242
|
+
inputSchema: object({
|
|
3243
|
+
node: { type: "string", minLength: 1, description: "Element id from get_animation." },
|
|
3244
|
+
from: { type: "number", minimum: 0, description: "From this time, ms (default 0)." },
|
|
3245
|
+
to: { type: "number", minimum: 0, description: "To this time, ms (default the end)." },
|
|
3246
|
+
step: { type: "number", exclusiveMinimum: 0, description: "Ms between samples (default 33; at most 400 samples)." }
|
|
3247
|
+
}, ["node"]),
|
|
3248
|
+
annotations: { title: "Read where a node travels", ...READ },
|
|
3249
|
+
handler: ({ node, from, to, step }) => {
|
|
3250
|
+
const s = scene();
|
|
3251
|
+
const ids = describeMotionElements(s).map((e) => e.id);
|
|
3252
|
+
if (!ids.includes(node)) throw new Error(`There is no element ${namedWithSuggestion(node, ids)}.`);
|
|
3253
|
+
return motionPath(s, node, { from, to, step });
|
|
3254
|
+
}
|
|
3255
|
+
};
|
|
3123
3256
|
const exportFlairMotion = {
|
|
3124
3257
|
name: "export_flair_motion",
|
|
3125
3258
|
title: "Export as Flair vector motion",
|
|
@@ -3269,7 +3402,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3269
3402
|
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"]),
|
|
3270
3403
|
annotations: { title: "Add commands to a shot", ...WRITE },
|
|
3271
3404
|
handler: ({ shot, commands, at }) => {
|
|
3272
|
-
const before = _nullishCoalesce(_optionalChain([scene, 'call',
|
|
3405
|
+
const before = _nullishCoalesce(_optionalChain([scene, 'call', _83 => _83(), 'access', _84 => _84.shots, 'access', _85 => _85.find, 'call', _86 => _86((s) => s.id === shot), 'optionalAccess', _87 => _87.run, 'access', _88 => _88.length]), () => ( 0));
|
|
3273
3406
|
const first = _nullishCoalesce(at, () => ( before));
|
|
3274
3407
|
return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
|
|
3275
3408
|
const shots = describeMotionShots(s);
|
|
@@ -3302,6 +3435,21 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3302
3435
|
annotations: { title: "Delete commands", ...DESTRUCTIVE },
|
|
3303
3436
|
handler: ({ shot, commands }) => apply({ op: "delete_commands", shot, commands }, "Delete commands")
|
|
3304
3437
|
};
|
|
3438
|
+
const moveCommand = {
|
|
3439
|
+
name: "move_command",
|
|
3440
|
+
title: "Reorder a command",
|
|
3441
|
+
description: `Moves one command to a new index in its shot's run (0 = first), as one undo step; the others close up around it. A command with "with": "previous" then starts with its new neighbour. Returns the command's new index, its old one and the shot's timing.`,
|
|
3442
|
+
inputSchema: object(
|
|
3443
|
+
{
|
|
3444
|
+
shot: SHOT_ID,
|
|
3445
|
+
command: { type: "integer", minimum: 0, description: "Index of the command in the shot's run (from get_animation)." },
|
|
3446
|
+
to: { type: "integer", minimum: 0, description: "Its new index, 0 = first (at most the last index)." }
|
|
3447
|
+
},
|
|
3448
|
+
["shot", "command", "to"]
|
|
3449
|
+
),
|
|
3450
|
+
annotations: { title: "Reorder a command", ...WRITE },
|
|
3451
|
+
handler: ({ shot, command: command2, to }) => apply({ op: "move_command", shot, command: command2, to }, "Move command", (s) => ({ shot, command: to, from: command2, commands: describeMotionShots(s).find((x) => x.id === shot).commands.map((c) => ({ index: c.index, type: c.type, start: c.start, end: c.end })) }))
|
|
3452
|
+
};
|
|
3305
3453
|
const setSettings = {
|
|
3306
3454
|
name: "set_animation_settings",
|
|
3307
3455
|
title: "Change animation settings",
|
|
@@ -3383,8 +3531,8 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3383
3531
|
return { redone, ...redone ? { label } : {} };
|
|
3384
3532
|
}
|
|
3385
3533
|
};
|
|
3386
|
-
const reads = [getAnimation, getShot, findElements, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
|
|
3387
|
-
const writes = [setArtworkSvg, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
|
|
3534
|
+
const reads = [getAnimation, getShot, findElements, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
|
|
3535
|
+
const writes = [setArtworkSvg, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
|
|
3388
3536
|
return {
|
|
3389
3537
|
id: _nullishCoalesce(options.id, () => ( "animation")),
|
|
3390
3538
|
namespace: options.namespace,
|
|
@@ -3429,12 +3577,314 @@ Commands
|
|
|
3429
3577
|
|
|
3430
3578
|
Working method
|
|
3431
3579
|
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).
|
|
3432
|
-
2. Plan a few shots, each one idea. Add them with insert_shots, or edit_animation to make several edits as one step (dry_run first when unsure).
|
|
3433
|
-
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.
|
|
3580
|
+
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).
|
|
3581
|
+
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.
|
|
3434
3582
|
4. To make a reusable Flair effect, set_animation_controls (colour controls stand for every use of their default colour) and export_flair_effect.
|
|
3435
3583
|
|
|
3436
3584
|
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.`;
|
|
3437
3585
|
|
|
3586
|
+
// src/animation-editor/form.ts
|
|
3587
|
+
var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "ease", "repeat", "repeatMode", "steps", "note"]);
|
|
3588
|
+
var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
|
|
3589
|
+
var NODES = /* @__PURE__ */ new Set(["into", "path"]);
|
|
3590
|
+
function branch(type) {
|
|
3591
|
+
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _89 => _89.properties, 'optionalAccess', _90 => _90.type, 'optionalAccess', _91 => _91.const]) === type);
|
|
3592
|
+
}
|
|
3593
|
+
function unitOf(type, name) {
|
|
3594
|
+
if (name === "duration" || name === "delay" || name === "stagger") return "ms";
|
|
3595
|
+
if (name === "steps") return "fps";
|
|
3596
|
+
if (name === "frequency") return "Hz";
|
|
3597
|
+
if (name === "repeat" || name === "count") return "\xD7";
|
|
3598
|
+
if (name === "distance" || name === "strokeWidth") return "units";
|
|
3599
|
+
if (name === "angle") return "\xB0";
|
|
3600
|
+
if (name === "amount") return type === "pulse" ? "\xD7" : "units";
|
|
3601
|
+
if (name === "rotate" && type === "wiggle") return "\xB0";
|
|
3602
|
+
if ((name === "by" || name === "to") && type === "rotate") return "\xB0";
|
|
3603
|
+
if (name === "scale" || name === "to" && type === "scale") return "\xD7";
|
|
3604
|
+
if ((name === "from" || name === "to") && (type === "draw" || type === "fade" || type === "follow")) return "0\u20131";
|
|
3605
|
+
return void 0;
|
|
3606
|
+
}
|
|
3607
|
+
function motionFieldLabel(name) {
|
|
3608
|
+
const words = name.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
|
|
3609
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
3610
|
+
}
|
|
3611
|
+
function kindOf(name, schema) {
|
|
3612
|
+
if (name === "targets") return "targets";
|
|
3613
|
+
if (name === "ease") return "ease";
|
|
3614
|
+
if (schema.enum) return "enum";
|
|
3615
|
+
if (schema.anyOf) return "scale";
|
|
3616
|
+
if (schema.type === "object") return "point";
|
|
3617
|
+
if (schema.type === "boolean") return "boolean";
|
|
3618
|
+
if (schema.type === "integer") return "integer";
|
|
3619
|
+
if (schema.type === "number") return "number";
|
|
3620
|
+
if (COLORS.has(name)) return "color";
|
|
3621
|
+
if (NODES.has(name)) return "node";
|
|
3622
|
+
return "text";
|
|
3623
|
+
}
|
|
3624
|
+
function motionCommandFields(type) {
|
|
3625
|
+
const schema = branch(type);
|
|
3626
|
+
if (!_optionalChain([schema, 'optionalAccess', _92 => _92.properties])) return [];
|
|
3627
|
+
const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
|
|
3628
|
+
const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
|
|
3629
|
+
const kind = kindOf(name, s);
|
|
3630
|
+
const min = typeof s.minimum === "number" ? s.minimum : typeof s.exclusiveMinimum === "number" ? s.exclusiveMinimum : void 0;
|
|
3631
|
+
return {
|
|
3632
|
+
name,
|
|
3633
|
+
kind,
|
|
3634
|
+
label: motionFieldLabel(name),
|
|
3635
|
+
description: _nullishCoalesce(s.description, () => ( "")),
|
|
3636
|
+
required: required.has(name),
|
|
3637
|
+
...s.enum ? { options: s.enum.map(String) } : {},
|
|
3638
|
+
...min !== void 0 ? { min } : {},
|
|
3639
|
+
...typeof s.maximum === "number" ? { max: s.maximum } : {},
|
|
3640
|
+
...unitOf(type, name) ? { unit: unitOf(type, name) } : {},
|
|
3641
|
+
group: TIMING.has(name) ? "timing" : "main"
|
|
3642
|
+
};
|
|
3643
|
+
});
|
|
3644
|
+
return [...fields.filter((f) => f.group === "main"), ...fields.filter((f) => f.group === "timing")];
|
|
3645
|
+
}
|
|
3646
|
+
function parseMotionFieldInput(field, raw) {
|
|
3647
|
+
if (field.kind === "boolean") return raw === true ? { set: true } : { remove: true };
|
|
3648
|
+
if (field.kind === "targets") {
|
|
3649
|
+
const ids = (Array.isArray(raw) ? raw : String(raw).split(",")).map((s) => String(s).trim()).filter(Boolean);
|
|
3650
|
+
return ids.length ? { set: ids } : { error: "Pick at least one target." };
|
|
3651
|
+
}
|
|
3652
|
+
if (field.kind === "point" || field.kind === "scale" && typeof raw === "object" && !Array.isArray(raw)) {
|
|
3653
|
+
const p = raw;
|
|
3654
|
+
if (p.x.trim() === "" && p.y.trim() === "") return field.required ? { error: `${field.label} is required.` } : { remove: true };
|
|
3655
|
+
const x = Number(p.x);
|
|
3656
|
+
const y = Number(p.y);
|
|
3657
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return { error: `${field.label} needs a number for x and for y.` };
|
|
3658
|
+
return { set: { x, y } };
|
|
3659
|
+
}
|
|
3660
|
+
const text = String(raw).trim();
|
|
3661
|
+
if (text === "") return field.required ? { error: `${field.label} is required.` } : { remove: true };
|
|
3662
|
+
if (field.kind === "number" || field.kind === "integer" || field.kind === "scale") {
|
|
3663
|
+
const n = Number(text);
|
|
3664
|
+
if (!Number.isFinite(n)) return { error: `${field.label} must be a number${field.unit ? ` (${field.unit})` : ""}.` };
|
|
3665
|
+
if (field.kind === "integer" && !Number.isInteger(n)) return { error: `${field.label} must be a whole number.` };
|
|
3666
|
+
if (field.min !== void 0 && n < field.min) return { error: `${field.label} must be at least ${field.min}.` };
|
|
3667
|
+
if (field.max !== void 0 && n > field.max) return { error: `${field.label} must be at most ${field.max}.` };
|
|
3668
|
+
return { set: n };
|
|
3669
|
+
}
|
|
3670
|
+
if (field.kind === "enum" && field.options && !field.options.includes(text)) return { error: `${field.label} must be one of ${field.options.join(", ")}.` };
|
|
3671
|
+
return { set: text };
|
|
3672
|
+
}
|
|
3673
|
+
function motionFieldEdit(shot, command2, field, raw) {
|
|
3674
|
+
const input = parseMotionFieldInput(field, raw);
|
|
3675
|
+
if ("error" in input) return input;
|
|
3676
|
+
if ("remove" in input) return { op: "update_command", shot, command: command2, remove: [field.name] };
|
|
3677
|
+
return { op: "update_command", shot, command: command2, set: { [field.name]: input.set } };
|
|
3678
|
+
}
|
|
3679
|
+
function defaultMotionCommand(type, targets, scene) {
|
|
3680
|
+
if (type === "wait") return { type: "wait", duration: 500 };
|
|
3681
|
+
if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
|
|
3682
|
+
const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
|
|
3683
|
+
const other = (pred) => _optionalChain([nodes, 'access', _93 => _93.find, 'call', _94 => _94((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _95 => _95.node, 'access', _96 => _96.id]);
|
|
3684
|
+
const base = { targets: [...targets] };
|
|
3685
|
+
switch (type) {
|
|
3686
|
+
case "scale":
|
|
3687
|
+
return { type, ...base, to: 1.2 };
|
|
3688
|
+
case "fade":
|
|
3689
|
+
return { type, ...base, to: 0.5 };
|
|
3690
|
+
case "move":
|
|
3691
|
+
return { type, ...base, by: { x: 40, y: 0 } };
|
|
3692
|
+
case "rotate":
|
|
3693
|
+
return { type, ...base, by: 90 };
|
|
3694
|
+
case "style":
|
|
3695
|
+
return { type, ...base, fill: "#f59e0b" };
|
|
3696
|
+
case "morph": {
|
|
3697
|
+
const into = _nullishCoalesce(other((e) => e.node.type === "path" && e.node.visible === false), () => ( other((e) => e.node.type === "path")));
|
|
3698
|
+
return into ? { type, ...base, into } : { error: "Morph needs another shape to become; draw one (it can stay hidden)." };
|
|
3699
|
+
}
|
|
3700
|
+
case "match": {
|
|
3701
|
+
const into = _nullishCoalesce(other((e) => e.node.type === "group" && e.node.visible === false), () => ( other((e) => e.node.type === "group")));
|
|
3702
|
+
return into ? { type, ...base, into } : { error: "Match needs another group to become; group the end state (it can stay hidden)." };
|
|
3703
|
+
}
|
|
3704
|
+
case "follow": {
|
|
3705
|
+
const path = _nullishCoalesce(other((e) => e.node.type === "path" && e.node.visible === false), () => ( other((e) => e.node.type === "path")));
|
|
3706
|
+
return path ? { type, ...base, path } : { error: "Follow needs a path to travel along; draw one (it can stay hidden)." };
|
|
3707
|
+
}
|
|
3708
|
+
case "effect": {
|
|
3709
|
+
for (const id of targets) {
|
|
3710
|
+
const node = _optionalChain([nodes, 'access', _97 => _97.find, 'call', _98 => _98((e) => e.node.id === id), 'optionalAccess', _99 => _99.node]);
|
|
3711
|
+
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _100 => _100.effects]), () => ( []))) {
|
|
3712
|
+
const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
|
|
3713
|
+
if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
|
|
3714
|
+
}
|
|
3715
|
+
}
|
|
3716
|
+
return { error: "Effect needs a target with a live path effect (wiggle, twist, zig zag\u2026)." };
|
|
3717
|
+
}
|
|
3718
|
+
default:
|
|
3719
|
+
return { type, ...base };
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
function motionCommandSummary(command2) {
|
|
3723
|
+
const c = command2;
|
|
3724
|
+
const what = [command2.type, typeof c.style === "string" ? c.style : ""].filter(Boolean).join(" ");
|
|
3725
|
+
if (command2.type === "wait") return `wait ${command2.duration} ms`;
|
|
3726
|
+
const extra = typeof c.into === "string" ? ` \u2192 ${c.into}` : typeof c.path === "string" ? ` along ${c.path}` : "";
|
|
3727
|
+
return `${what} \xB7 ${(_nullishCoalesce(command2.targets, () => ( []))).join(", ")}${extra}`;
|
|
3728
|
+
}
|
|
3729
|
+
function motionCommandRows(scene, shotId) {
|
|
3730
|
+
const index = scene.shots.findIndex((s) => s.id === shotId);
|
|
3731
|
+
if (index < 0) return [];
|
|
3732
|
+
const timeline = compileMotionScene(scene);
|
|
3733
|
+
return scene.shots[index].run.map((command2, i) => {
|
|
3734
|
+
const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
|
|
3735
|
+
const primitive = motionFlairPrimitive(command2);
|
|
3736
|
+
return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _101 => _101.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _102 => _102.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
|
|
3737
|
+
});
|
|
3738
|
+
}
|
|
3739
|
+
function duplicateMotionCommandEdit(scene, shot, command2) {
|
|
3740
|
+
const run = _nullishCoalesce(_optionalChain([scene, 'access', _103 => _103.shots, 'access', _104 => _104.find, 'call', _105 => _105((s) => s.id === shot), 'optionalAccess', _106 => _106.run]), () => ( []));
|
|
3741
|
+
return { op: "add_commands", shot, commands: run[command2] ? [structuredClone(run[command2])] : [], at: command2 + 1 };
|
|
3742
|
+
}
|
|
3743
|
+
var MOTION_EASE_CHOICES = [
|
|
3744
|
+
{ value: "", label: "Default" },
|
|
3745
|
+
..._chunk2FHLHZALcjs.ANIMATION_EASING_PRESETS.map((p) => ({ value: p, label: _chunk2FHLHZALcjs.ANIMATION_EASING_LABELS[p] }))
|
|
3746
|
+
];
|
|
3747
|
+
function motionEaseKey(ease) {
|
|
3748
|
+
if (ease === void 0 || ease === null) return "";
|
|
3749
|
+
return typeof ease === "string" ? ease : "custom";
|
|
3750
|
+
}
|
|
3751
|
+
function motionEasingCurve(ease, samples = 48, durationMs = 1e3) {
|
|
3752
|
+
const resolved = _chunk2FHLHZALcjs.resolveEasing.call(void 0, ease);
|
|
3753
|
+
const ms = resolved !== "hold" && resolved.type === "spring" ? _chunk2FHLHZALcjs.springSettleMs.call(void 0, resolved) : durationMs;
|
|
3754
|
+
const n = Math.max(2, Math.floor(samples));
|
|
3755
|
+
const points = [];
|
|
3756
|
+
for (let i = 0; i <= n; i++) {
|
|
3757
|
+
const u = i / n;
|
|
3758
|
+
points.push({ u, v: resolved === "hold" ? i === n ? 1 : 0 : _chunk2FHLHZALcjs.evaluateEasing.call(void 0, ease, u, ms) });
|
|
3759
|
+
}
|
|
3760
|
+
const values = points.map((p) => p.v);
|
|
3761
|
+
return { points, min: Math.min(0, ...values), max: Math.max(1, ...values), durationMs: ms };
|
|
3762
|
+
}
|
|
3763
|
+
function motionEasingPath(curve, width, height, pad = 4) {
|
|
3764
|
+
const span = curve.max - curve.min || 1;
|
|
3765
|
+
const f = (n) => String(Math.round(n * 100) / 100);
|
|
3766
|
+
return curve.points.map((p, i) => `${i ? "L" : "M"}${f(pad + p.u * (width - 2 * pad))} ${f(pad + (1 - (p.v - curve.min) / span) * (height - 2 * pad))}`).join(" ");
|
|
3767
|
+
}
|
|
3768
|
+
function motionEasingGuides(curve, height, pad = 4) {
|
|
3769
|
+
const span = curve.max - curve.min || 1;
|
|
3770
|
+
const y = (v) => pad + (1 - (v - curve.min) / span) * (height - 2 * pad);
|
|
3771
|
+
return { zero: y(0), one: y(1) };
|
|
3772
|
+
}
|
|
3773
|
+
function motionNodeAtElement(scene, target, root) {
|
|
3774
|
+
const ids = indexMotionNodes(scene.artwork.nodes);
|
|
3775
|
+
for (let el = target; el && el !== root; el = el.parentElement) {
|
|
3776
|
+
const id = el.getAttribute("id");
|
|
3777
|
+
if (id && ids.has(id)) return id;
|
|
3778
|
+
}
|
|
3779
|
+
return null;
|
|
3780
|
+
}
|
|
3781
|
+
var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3782
|
+
function highlightMotionSvg(svg, ids, color = "#f43f5e") {
|
|
3783
|
+
if (!ids.length) return svg;
|
|
3784
|
+
let out = svg;
|
|
3785
|
+
for (const id of ids) {
|
|
3786
|
+
const escaped = id.replace(/&/g, "&").replace(/"/g, """);
|
|
3787
|
+
out = out.replace(new RegExp(` id="${escapeRegExp(escaped)}"`), ` id="${escaped}" data-picked=""`);
|
|
3788
|
+
}
|
|
3789
|
+
return out.replace(/(<svg\b[^>]*>)/, `$1<style>[data-picked]{filter:drop-shadow(0 0 1px #fff) drop-shadow(0 0 3px ${color}) drop-shadow(0 0 3px ${color})}</style>`);
|
|
3790
|
+
}
|
|
3791
|
+
function motionRulerTicks(duration, width, minGap = 56) {
|
|
3792
|
+
const span = Math.max(1, duration);
|
|
3793
|
+
const steps = [100, 250, 500, 1e3, 2e3, 5e3, 1e4, 3e4, 6e4];
|
|
3794
|
+
const step = _nullishCoalesce(steps.find((s) => s / span * Math.max(1, width) >= minGap), () => ( steps[steps.length - 1]));
|
|
3795
|
+
const ticks = [];
|
|
3796
|
+
for (let t = 0; t <= span + 1e-6; t += step / 2) {
|
|
3797
|
+
const major = Math.round(t / (step / 2)) % 2 === 0;
|
|
3798
|
+
ticks.push({ time: t, major, label: major ? `${step < 1e3 ? (t / 1e3).toFixed(step < 500 ? 2 : 1) : String(Math.round(t / 1e3))}s` : "" });
|
|
3799
|
+
}
|
|
3800
|
+
return ticks;
|
|
3801
|
+
}
|
|
3802
|
+
function fitMotionSceneEdits(scene, ms, options = {}) {
|
|
3803
|
+
const fit = fitMotionScene(scene, ms, options);
|
|
3804
|
+
return fit.scene.shots.flatMap((shot, i) => {
|
|
3805
|
+
const before = scene.shots[i].speed;
|
|
3806
|
+
if (before === shot.speed) return [];
|
|
3807
|
+
return shot.speed === void 0 ? [{ op: "update_shot", shot: shot.id, remove: ["speed"] }] : [{ op: "update_shot", shot: shot.id, set: { speed: shot.speed } }];
|
|
3808
|
+
});
|
|
3809
|
+
}
|
|
3810
|
+
function motionCueKey(cue) {
|
|
3811
|
+
if (!cue) return "";
|
|
3812
|
+
if (typeof cue.beat === "number") return `beat:${cue.beat}`;
|
|
3813
|
+
if (typeof cue.word === "number") return `word:${cue.word}`;
|
|
3814
|
+
if (typeof cue.ms === "number") return `ms:${cue.ms}`;
|
|
3815
|
+
return "";
|
|
3816
|
+
}
|
|
3817
|
+
function motionCueFromKey(key) {
|
|
3818
|
+
const m = /^(beat|word|ms):(-?\d+(?:\.\d+)?)$/.exec(key);
|
|
3819
|
+
if (!m) return void 0;
|
|
3820
|
+
return { [m[1]]: Number(m[2]) };
|
|
3821
|
+
}
|
|
3822
|
+
function motionCueChoices(scene, limit = 256) {
|
|
3823
|
+
const choices = [];
|
|
3824
|
+
const s = (ms) => `${(ms / 1e3).toFixed(2)} s`;
|
|
3825
|
+
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _107 => _107.narration, 'optionalAccess', _108 => _108.words, 'access', _109 => _109.map, 'call', _110 => _110((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
|
|
3826
|
+
if (scene.beat && scene.beat.bpm > 0) {
|
|
3827
|
+
for (let beat = 0; choices.length < limit; beat++) {
|
|
3828
|
+
const time = motionBeatTime(scene.beat, beat);
|
|
3829
|
+
if (time > end) break;
|
|
3830
|
+
if (time < 0) continue;
|
|
3831
|
+
const at = motionBeatAt(scene.beat, time);
|
|
3832
|
+
choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
_optionalChain([scene, 'access', _111 => _111.narration, 'optionalAccess', _112 => _112.words, 'access', _113 => _113.forEach, 'call', _114 => _114((w, i) => {
|
|
3836
|
+
if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
|
|
3837
|
+
})]);
|
|
3838
|
+
return choices;
|
|
3839
|
+
}
|
|
3840
|
+
function motionShotCueTime(scene, cue) {
|
|
3841
|
+
return cue ? motionCueTime(scene, cue) : void 0;
|
|
3842
|
+
}
|
|
3843
|
+
function formatMotionNarration(narration) {
|
|
3844
|
+
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _115 => _115.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
|
|
3845
|
+
}
|
|
3846
|
+
function parseMotionNarration(text) {
|
|
3847
|
+
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
3848
|
+
if (!lines.length) return { narration: null };
|
|
3849
|
+
const words = [];
|
|
3850
|
+
for (const [i, line] of lines.entries()) {
|
|
3851
|
+
const m = /^(\d+(?:\.\d+)?)\s+(.+)$/.exec(line);
|
|
3852
|
+
if (!m) return { error: `Line ${i + 1} ("${line}") should be a start time in ms and a word, e.g. "1200 hello".` };
|
|
3853
|
+
const start = Number(m[1]);
|
|
3854
|
+
if (words.length && start < words[words.length - 1].start) return { error: `Line ${i + 1} starts before the word above it; keep the words in time order.` };
|
|
3855
|
+
words.push({ text: m[2], start });
|
|
3856
|
+
}
|
|
3857
|
+
return { narration: { words } };
|
|
3858
|
+
}
|
|
3859
|
+
|
|
3860
|
+
|
|
3861
|
+
|
|
3862
|
+
|
|
3863
|
+
|
|
3864
|
+
|
|
3865
|
+
|
|
3866
|
+
|
|
3867
|
+
|
|
3868
|
+
|
|
3869
|
+
|
|
3870
|
+
|
|
3871
|
+
|
|
3872
|
+
|
|
3873
|
+
|
|
3874
|
+
|
|
3875
|
+
|
|
3876
|
+
|
|
3877
|
+
|
|
3878
|
+
|
|
3879
|
+
|
|
3880
|
+
|
|
3881
|
+
|
|
3882
|
+
|
|
3883
|
+
|
|
3884
|
+
|
|
3885
|
+
|
|
3886
|
+
|
|
3887
|
+
|
|
3438
3888
|
|
|
3439
3889
|
|
|
3440
3890
|
|
|
@@ -3525,5 +3975,5 @@ Keep motion purposeful: one thing moving at a time reads best, ease-out for arri
|
|
|
3525
3975
|
|
|
3526
3976
|
|
|
3527
3977
|
|
|
3528
|
-
exports.ANIMATION_EDITOR_AGENT_INSTRUCTIONS = ANIMATION_EDITOR_AGENT_INSTRUCTIONS; exports.AnimationEditorController = AnimationEditorController; exports.FLAIR_EASES = FLAIR_EASES; exports.FLAIR_EXPORT_VERSION = FLAIR_EXPORT_VERSION; exports.MOTION_ADDITIVE_PROPERTIES = MOTION_ADDITIVE_PROPERTIES; exports.MOTION_BLENDS = MOTION_BLENDS; exports.MOTION_CAMERA_MS = MOTION_CAMERA_MS; exports.MOTION_COMMAND_SCHEMA = MOTION_COMMAND_SCHEMA; exports.MOTION_COMMAND_TYPES = MOTION_COMMAND_TYPES; exports.MOTION_DEFAULT_DURATIONS = MOTION_DEFAULT_DURATIONS; exports.MOTION_DEFAULT_HOLD = MOTION_DEFAULT_HOLD; exports.MOTION_DIRECTIONS = MOTION_DIRECTIONS; exports.MOTION_DRAW_EFFECT_ID = MOTION_DRAW_EFFECT_ID; exports.MOTION_DRAW_MS_PER_UNIT = MOTION_DRAW_MS_PER_UNIT; exports.MOTION_DRAW_RANGE = MOTION_DRAW_RANGE; exports.MOTION_EASE_IN_OUT = MOTION_EASE_IN_OUT; exports.MOTION_EASE_OUT = MOTION_EASE_OUT; exports.MOTION_EDIT_OPS = MOTION_EDIT_OPS; exports.MOTION_ENTER_STYLES = MOTION_ENTER_STYLES; exports.MOTION_EXIT_STYLES = MOTION_EXIT_STYLES; exports.MOTION_IRIS_SHAPES = MOTION_IRIS_SHAPES; exports.MOTION_ISSUE_CODES = MOTION_ISSUE_CODES; exports.MOTION_MIN_CHANGE_MS = MOTION_MIN_CHANGE_MS; exports.MOTION_REPEAT_MODES = MOTION_REPEAT_MODES; exports.MOTION_SPEED_RANGE = MOTION_SPEED_RANGE; exports.MOTION_SPLIT_ORIENTATIONS = MOTION_SPLIT_ORIENTATIONS; exports.MotionSceneFormatError = MotionSceneFormatError; exports.activeSegment = activeSegment; exports.applyMotionControlValues = applyMotionControlValues; exports.applyMotionEdits = applyMotionEdits; exports.checkMotionScene = checkMotionScene; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createMotionScene = createMotionScene; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.fitMotionRect = fitMotionRect; exports.fitMotionScene = fitMotionScene; exports.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionClipAttrs = motionClipAttrs; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCueTime = motionCueTime; exports.motionCycleDuration = motionCycleDuration; exports.motionFlairPrimitive = motionFlairPrimitive; exports.motionFollowRoute = motionFollowRoute; exports.motionFrameAt = motionFrameAt; exports.motionFrameToSvg = motionFrameToSvg; exports.motionIssue = motionIssue; exports.motionIssueKey = motionIssueKey; exports.motionIssueLine = motionIssueLine; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionPathLength = motionPathLength; exports.motionRestValue = motionRestValue; exports.motionRevealClip = motionRevealClip; exports.motionRevealPadding = motionRevealPadding; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionShotTimeScale = motionShotTimeScale; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = namedWithSuggestion; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.suggestName = suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
|
|
3978
|
+
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.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.suggestName = suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
|
|
3529
3979
|
//# sourceMappingURL=index.cjs.map
|