@pixerate/editor 0.72.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 +95 -44
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +23 -2
- package/dist/animation-editor/index.d.ts +23 -2
- package/dist/animation-editor/index.js +57 -6
- package/dist/animation-editor/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -221,7 +221,7 @@ ${problems.map((p) => `- ${p}`).join("\n")}`);
|
|
|
221
221
|
this.problems = problems;
|
|
222
222
|
}
|
|
223
223
|
};
|
|
224
|
-
var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "drivers", "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"];
|
|
225
225
|
var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
|
|
226
226
|
var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric"];
|
|
227
227
|
var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps"];
|
|
@@ -471,6 +471,11 @@ function motionSceneShapeProblems(input) {
|
|
|
471
471
|
problems.push('Scene: "artwork" must be a vector document { width, height, nodes }.');
|
|
472
472
|
if (input.clips !== void 0) problems.push(...clipsShapeProblems(input.clips));
|
|
473
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
|
+
}
|
|
474
479
|
if (input.trigger !== void 0 && !MOTION_TRIGGERS.includes(input.trigger)) problems.push(`Scene: "trigger" must be one of ${MOTION_TRIGGERS.join(", ")}.`);
|
|
475
480
|
if (input.loop !== void 0 && !["none", "loop", "ping-pong"].includes(input.loop)) problems.push('Scene: "loop" must be "none", "loop" or "ping-pong".');
|
|
476
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.');
|
|
@@ -1574,12 +1579,49 @@ function motionPathsSvg(paths, camera, color = "#f43f5e") {
|
|
|
1574
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>`
|
|
1575
1580
|
).join("");
|
|
1576
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
|
+
}
|
|
1577
1611
|
var innerSvg = (svg) => svg.slice(svg.indexOf(">") + 1, svg.lastIndexOf("</svg>"));
|
|
1578
1612
|
function motionStageSvg(scene, time, options = {}) {
|
|
1579
|
-
const { onionSkin, motionPaths, motionPathColor, ...svgOptions } = options;
|
|
1580
|
-
const current = motionFrameToSvg(scene, time, svgOptions);
|
|
1581
|
-
if (!onionSkin && !motionPaths) return current;
|
|
1613
|
+
const { onionSkin, motionPaths, motionPathColor, motionBlur, ...svgOptions } = options;
|
|
1582
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;
|
|
1583
1625
|
const ghosts = onionSkin ? motionGhosts(scene, time, onionSkin).map((g, i) => {
|
|
1584
1626
|
const own = `${prefix}ghost${i}-`;
|
|
1585
1627
|
const inner = innerSvg(motionFrameToSvg(scene, g.time, { ...svgOptions, idPrefix: own, background: false })).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
|
|
@@ -1591,7 +1633,7 @@ function motionStageSvg(scene, time, options = {}) {
|
|
|
1591
1633
|
const open = current.indexOf(">") + 1;
|
|
1592
1634
|
const close = current.lastIndexOf("</svg>");
|
|
1593
1635
|
const body = current.slice(open, close);
|
|
1594
|
-
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]]), () => ( "")) : "";
|
|
1595
1637
|
return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
|
|
1596
1638
|
}
|
|
1597
1639
|
function motionContactSheetSvg(scene, times, options = {}) {
|
|
@@ -1610,7 +1652,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
|
|
|
1610
1652
|
const x = gap + i % cols * (w + gap);
|
|
1611
1653
|
const y = gap + Math.floor(i / cols) * (h + label + gap);
|
|
1612
1654
|
const frame = motionStageSvg(scene, t, { ...frameOptions, idPrefix: `${prefix}f${i}-` });
|
|
1613
|
-
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}`));
|
|
1614
1656
|
const inner = innerSvg(frame).replace(new RegExp(` id="(?!${`${prefix}f${i}-`.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
|
|
1615
1657
|
const shot = _nullishCoalesce(timeline.shots.find((s) => t >= s.start && t < s.end), () => ( timeline.shots[timeline.shots.length - 1]));
|
|
1616
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>` : "";
|
|
@@ -1622,7 +1664,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
|
|
|
1622
1664
|
// src/animation-editor/check.ts
|
|
1623
1665
|
var MOTION_MIN_CHANGE_MS = 120;
|
|
1624
1666
|
var NUMERIC_PARAMS = (node, effectId) => {
|
|
1625
|
-
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)]);
|
|
1626
1668
|
if (!effect) return null;
|
|
1627
1669
|
return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
|
|
1628
1670
|
};
|
|
@@ -1703,7 +1745,7 @@ function checkMotionScene(scene) {
|
|
|
1703
1745
|
if (command2.type === "follow" && known(command2.path, "unknown-path", "path", where) && nodes.get(command2.path).node.type !== "path")
|
|
1704
1746
|
issues.push(motionIssue("not-a-path", `"${command2.path}" is a group; follow a single path node.`, { ...where, ids: [command2.path] }));
|
|
1705
1747
|
if (command2.type === "morph") known(command2.into, "unknown-shape", "shape", where);
|
|
1706
|
-
if (command2.type === "play" && !_optionalChain([scene, 'access',
|
|
1748
|
+
if (command2.type === "play" && !_optionalChain([scene, 'access', _79 => _79.clips, 'optionalAccess', _80 => _80[command2.clip]]))
|
|
1707
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));
|
|
1708
1750
|
if (command2.type === "match" && known(command2.into, "unknown-shape", "group", where)) {
|
|
1709
1751
|
const into = nodes.get(command2.into);
|
|
@@ -1818,7 +1860,7 @@ function checkMotionScene(scene) {
|
|
|
1818
1860
|
if (!shot.at) return;
|
|
1819
1861
|
const timing = timeline.shots[i];
|
|
1820
1862
|
if (timing.cue === void 0) {
|
|
1821
|
-
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)`;
|
|
1822
1864
|
issues.push(motionIssue("unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
|
|
1823
1865
|
} else if (timing.missedBy !== void 0) {
|
|
1824
1866
|
const late = Math.round(timing.missedBy);
|
|
@@ -1851,7 +1893,7 @@ function checkMotionScene(scene) {
|
|
|
1851
1893
|
const cam = frame.camera;
|
|
1852
1894
|
const docIndex = indexMotionNodes(frame.document.nodes);
|
|
1853
1895
|
for (const id of command2.targets) {
|
|
1854
|
-
const b = _optionalChain([docIndex, 'access',
|
|
1896
|
+
const b = _optionalChain([docIndex, 'access', _84 => _84.get, 'call', _85 => _85(id), 'optionalAccess', _86 => _86.bounds]);
|
|
1855
1897
|
if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
|
|
1856
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;
|
|
1857
1899
|
if (outside) {
|
|
@@ -1934,12 +1976,12 @@ function applyOne(scene, edit) {
|
|
|
1934
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.');
|
|
1935
1977
|
next.steps = edit.steps;
|
|
1936
1978
|
}
|
|
1937
|
-
for (const key of ["beat", "narration"]) {
|
|
1979
|
+
for (const key of ["beat", "narration", "motionBlur"]) {
|
|
1938
1980
|
if (edit[key] === null) delete next[key];
|
|
1939
1981
|
else if (edit[key] !== void 0) next[key] = edit[key];
|
|
1940
1982
|
}
|
|
1941
1983
|
{
|
|
1942
|
-
const problems = motionSceneShapeProblems(next).filter((p) => /"beat"|"narration"/.test(p));
|
|
1984
|
+
const problems = motionSceneShapeProblems(next).filter((p) => /"beat"|"narration"|"motionBlur"/.test(p));
|
|
1943
1985
|
if (problems.length) fail(problems.join(" "));
|
|
1944
1986
|
}
|
|
1945
1987
|
if (edit.target === null) delete next.target;
|
|
@@ -2083,9 +2125,9 @@ function applyMotionEdits(scene, edits) {
|
|
|
2083
2125
|
let next = scene;
|
|
2084
2126
|
for (let i = 0; i < list.length; i++) {
|
|
2085
2127
|
const edit = list[i];
|
|
2086
|
-
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])}): ` : "";
|
|
2087
2129
|
if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
|
|
2088
|
-
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.` };
|
|
2089
2131
|
try {
|
|
2090
2132
|
next = applyOne(next, edit);
|
|
2091
2133
|
} catch (error) {
|
|
@@ -2107,7 +2149,7 @@ function resolveMotionEditRefs(scene, edits) {
|
|
|
2107
2149
|
const resolved = [];
|
|
2108
2150
|
let next = scene;
|
|
2109
2151
|
for (let i = 0; i < edits.length; i++) {
|
|
2110
|
-
const where = `op ${i + 1} (${_optionalChain([edits, 'access',
|
|
2152
|
+
const where = `op ${i + 1} (${_optionalChain([edits, 'access', _89 => _89[i], 'optionalAccess', _90 => _90.op])})`;
|
|
2111
2153
|
let problem = null;
|
|
2112
2154
|
const walk = (v) => {
|
|
2113
2155
|
if (typeof v === "string") {
|
|
@@ -2140,9 +2182,9 @@ function resolveMotionEditRefs(scene, edits) {
|
|
|
2140
2182
|
resolved.push(edit);
|
|
2141
2183
|
const out = { op: edit.op };
|
|
2142
2184
|
if (edit.op === "insert_shots") out.shots = edit.shots.map((s) => s.id);
|
|
2143
|
-
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;
|
|
2144
2186
|
if (edit.op === "add_commands") {
|
|
2145
|
-
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));
|
|
2146
2188
|
out.indexes = edit.commands.map((_, k) => at + k);
|
|
2147
2189
|
}
|
|
2148
2190
|
if (edit.op === "move_command") out.indexes = [edit.to];
|
|
@@ -2301,7 +2343,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2301
2343
|
const wrapper = freshId(`${id}--follow`);
|
|
2302
2344
|
const centre = freshId(`${id}--follow-centre`);
|
|
2303
2345
|
const c = entry.center;
|
|
2304
|
-
const at = _optionalChain([motionNodeOffset, 'call',
|
|
2346
|
+
const at = _optionalChain([motionNodeOffset, 'call', _98 => _98(entry, timeline, 0, nodes), 'optionalAccess', _99 => _99.follow]);
|
|
2305
2347
|
const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
|
|
2306
2348
|
(wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
|
|
2307
2349
|
follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
|
|
@@ -2362,7 +2404,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2362
2404
|
exact: () => false,
|
|
2363
2405
|
value: (t) => {
|
|
2364
2406
|
const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
|
|
2365
|
-
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]));
|
|
2366
2408
|
if (!now || now.type !== "path") return "";
|
|
2367
2409
|
const bezier = _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, now, _chunkYJLCBA7Vcjs.IDENTITY_MATRIX, { effects: false }), inverse);
|
|
2368
2410
|
return _chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
|
|
@@ -2383,8 +2425,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2383
2425
|
...delay > 0 ? { delay: round2(delay) } : {},
|
|
2384
2426
|
ms: round2(ms),
|
|
2385
2427
|
ease: written,
|
|
2386
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
2387
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
2428
|
+
..._optionalChain([segment, 'optionalAccess', _104 => _104.behavior]) ? { behavior: segment.behavior } : {},
|
|
2429
|
+
..._optionalChain([segment, 'optionalAccess', _105 => _105.steps]) ? { strobe: segment.steps } : {}
|
|
2388
2430
|
};
|
|
2389
2431
|
if (channel.kind === "view") animate.push({ ...base, view: to });
|
|
2390
2432
|
else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
|
|
@@ -2469,11 +2511,12 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2469
2511
|
}
|
|
2470
2512
|
animate.sort((x, y) => (_nullishCoalesce(x.step, () => ( 0))) - (_nullishCoalesce(y.step, () => ( 0))) || (_nullishCoalesce(x.delay, () => ( 0))) - (_nullishCoalesce(y.delay, () => ( 0))));
|
|
2471
2513
|
}
|
|
2514
|
+
if (scene.motionBlur) notes.push("Motion blur is drawn on the stage only; Flair plays the scene sharp.");
|
|
2472
2515
|
if (trigger && (_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") notes.push(`The scene plays on ${trigger}, so its loop does not apply in Flair.`);
|
|
2473
2516
|
let svg = _chunkYJLCBA7Vcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
|
|
2474
2517
|
if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
|
|
2475
2518
|
let motion = { svg, animate };
|
|
2476
|
-
if (_optionalChain([scene, 'access',
|
|
2519
|
+
if (_optionalChain([scene, 'access', _106 => _106.controls, 'optionalAccess', _107 => _107.length])) {
|
|
2477
2520
|
const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
|
|
2478
2521
|
const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
|
|
2479
2522
|
svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
|
|
@@ -2495,7 +2538,7 @@ function toFlairVectorEffect(scene, options = {}) {
|
|
|
2495
2538
|
tags: _nullishCoalesce(options.tags, () => ( [])),
|
|
2496
2539
|
motion: out.motion,
|
|
2497
2540
|
hold: out.hold,
|
|
2498
|
-
..._optionalChain([scene, 'access',
|
|
2541
|
+
..._optionalChain([scene, 'access', _108 => _108.presets, 'optionalAccess', _109 => _109.length]) ? { presets: scene.presets } : {},
|
|
2499
2542
|
...out.trigger ? { trigger: out.trigger } : {}
|
|
2500
2543
|
};
|
|
2501
2544
|
}
|
|
@@ -2539,7 +2582,7 @@ function resolvePlaceholders(motion, notes) {
|
|
|
2539
2582
|
const filled = text.replace(PLACEHOLDER, (_, name) => {
|
|
2540
2583
|
const d = declared.get(name);
|
|
2541
2584
|
if (!d) unknown.add(name);
|
|
2542
|
-
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess',
|
|
2585
|
+
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _110 => _110.value]), () => ( ""))).replace(/"/g, '\\"');
|
|
2543
2586
|
});
|
|
2544
2587
|
for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
|
|
2545
2588
|
return { motion: JSON.parse(filled), controls };
|
|
@@ -2593,7 +2636,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2593
2636
|
if (anim.along) {
|
|
2594
2637
|
const path = nodes.get(anim.along);
|
|
2595
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.`);
|
|
2596
|
-
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) });
|
|
2597
2640
|
}
|
|
2598
2641
|
for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
|
|
2599
2642
|
if (attr === "opacity") {
|
|
@@ -2604,7 +2647,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2604
2647
|
out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
|
|
2605
2648
|
} else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2606
2649
|
} else if (attr === "fill" || attr === "stroke") {
|
|
2607
|
-
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") });
|
|
2608
2651
|
else {
|
|
2609
2652
|
if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
|
|
2610
2653
|
out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
@@ -2785,6 +2828,7 @@ function toLottie(scene, options = {}) {
|
|
|
2785
2828
|
const timeline = compileMotionScene(scene);
|
|
2786
2829
|
const nodes = indexMotionNodes(scene.artwork.nodes);
|
|
2787
2830
|
const notes = [];
|
|
2831
|
+
if (scene.motionBlur) notes.push("Motion blur is drawn on the stage only; the Lottie plays sharp.");
|
|
2788
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).`);
|
|
2789
2833
|
let sampled = 0;
|
|
2790
2834
|
const track = (id, p) => _nullishCoalesce(timeline.tracks.get(motionTrackKey(id, p)), () => ( []));
|
|
@@ -2893,7 +2937,7 @@ function toLottie(scene, options = {}) {
|
|
|
2893
2937
|
const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
|
|
2894
2938
|
const geometryAt = (t) => {
|
|
2895
2939
|
if (!shapeSegments.length) return _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2896
|
-
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]);
|
|
2897
2941
|
return now && now.type === "path" ? _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2898
2942
|
};
|
|
2899
2943
|
const rest = lottieContours(_chunkO2UH7LZEcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
|
|
@@ -2941,7 +2985,7 @@ function toLottie(scene, options = {}) {
|
|
|
2941
2985
|
lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
|
|
2942
2986
|
ml: 4
|
|
2943
2987
|
});
|
|
2944
|
-
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.`);
|
|
2945
2989
|
if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
|
|
2946
2990
|
}
|
|
2947
2991
|
const fill = paintOf(path.fill, "fill", path.id);
|
|
@@ -3092,7 +3136,7 @@ var AnimationEditorController = (_class = class {
|
|
|
3092
3136
|
time: p.time,
|
|
3093
3137
|
playing: p.playing,
|
|
3094
3138
|
loop: p.loop,
|
|
3095
|
-
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call',
|
|
3139
|
+
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _122 => _122(timeline, p.time), 'optionalAccess', _123 => _123.id]), () => ( null)),
|
|
3096
3140
|
selection: this.selection,
|
|
3097
3141
|
readOnly: this.readOnly,
|
|
3098
3142
|
error: this.error,
|
|
@@ -3131,7 +3175,7 @@ var AnimationEditorController = (_class = class {
|
|
|
3131
3175
|
this.applying = false;
|
|
3132
3176
|
}
|
|
3133
3177
|
this.notify();
|
|
3134
|
-
_optionalChain([this, 'access',
|
|
3178
|
+
_optionalChain([this, 'access', _124 => _124.onChange, 'optionalCall', _125 => _125(scene)]);
|
|
3135
3179
|
}
|
|
3136
3180
|
commit(label, next) {
|
|
3137
3181
|
const before = this.scene;
|
|
@@ -3451,6 +3495,10 @@ var SETTINGS = {
|
|
|
3451
3495
|
},
|
|
3452
3496
|
fps: { type: "number", minimum: 1, maximum: 120, description: "Sampling rate for exports (default 30)." },
|
|
3453
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
|
+
},
|
|
3454
3502
|
beat: {
|
|
3455
3503
|
anyOf: [
|
|
3456
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"]),
|
|
@@ -3577,6 +3625,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3577
3625
|
shots: describeMotionShots(s),
|
|
3578
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) }])) } : {},
|
|
3579
3627
|
...s.drivers ? { drivers: s.drivers } : {},
|
|
3628
|
+
...s.motionBlur ? { motionBlur: s.motionBlur } : {},
|
|
3580
3629
|
...s.controls ? { controls: s.controls } : {},
|
|
3581
3630
|
...s.presets ? { presets: s.presets } : {},
|
|
3582
3631
|
issues: issueSummary(controller.getState().issues),
|
|
@@ -3691,9 +3740,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3691
3740
|
handler: ({ from = 0, to, limit = 200 }) => {
|
|
3692
3741
|
const s = scene();
|
|
3693
3742
|
const timeline = compileMotionScene(s);
|
|
3694
|
-
const words = _nullishCoalesce(_optionalChain([s, 'access',
|
|
3743
|
+
const words = _nullishCoalesce(_optionalChain([s, 'access', _126 => _126.narration, 'optionalAccess', _127 => _127.words]), () => ( []));
|
|
3695
3744
|
const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
|
|
3696
|
-
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]);
|
|
3697
3746
|
const beats = [];
|
|
3698
3747
|
if (s.beat && s.beat.bpm > 0) {
|
|
3699
3748
|
const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
|
|
@@ -3973,7 +4022,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3973
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"]),
|
|
3974
4023
|
annotations: { title: "Add commands to a shot", ...WRITE },
|
|
3975
4024
|
handler: ({ shot, commands, at }) => {
|
|
3976
|
-
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));
|
|
3977
4026
|
const first = _nullishCoalesce(at, () => ( before));
|
|
3978
4027
|
return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
|
|
3979
4028
|
const shots = describeMotionShots(s);
|
|
@@ -4138,6 +4187,7 @@ Commands
|
|
|
4138
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.
|
|
4139
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.
|
|
4140
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).
|
|
4141
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.
|
|
4142
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.
|
|
4143
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.
|
|
@@ -4167,7 +4217,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
|
|
|
4167
4217
|
var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
|
|
4168
4218
|
var NODES = /* @__PURE__ */ new Set(["into", "path"]);
|
|
4169
4219
|
function branch(type) {
|
|
4170
|
-
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);
|
|
4171
4221
|
}
|
|
4172
4222
|
function unitOf(type, name) {
|
|
4173
4223
|
if (name === "duration" || name === "delay" || name === "stagger") return "ms";
|
|
@@ -4202,7 +4252,7 @@ function kindOf(name, schema) {
|
|
|
4202
4252
|
}
|
|
4203
4253
|
function motionCommandFields(type) {
|
|
4204
4254
|
const schema = branch(type);
|
|
4205
|
-
if (!_optionalChain([schema, 'optionalAccess',
|
|
4255
|
+
if (!_optionalChain([schema, 'optionalAccess', _141 => _141.properties])) return [];
|
|
4206
4256
|
const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
|
|
4207
4257
|
const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
|
|
4208
4258
|
const kind = kindOf(name, s);
|
|
@@ -4259,7 +4309,7 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
4259
4309
|
if (type === "wait") return { type: "wait", duration: 500 };
|
|
4260
4310
|
if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
|
|
4261
4311
|
const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
|
|
4262
|
-
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]);
|
|
4263
4313
|
const base = { targets: [...targets] };
|
|
4264
4314
|
switch (type) {
|
|
4265
4315
|
case "scale":
|
|
@@ -4290,8 +4340,8 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
4290
4340
|
}
|
|
4291
4341
|
case "effect": {
|
|
4292
4342
|
for (const id of targets) {
|
|
4293
|
-
const node = _optionalChain([nodes, 'access',
|
|
4294
|
-
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]), () => ( []))) {
|
|
4295
4345
|
const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
|
|
4296
4346
|
if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
|
|
4297
4347
|
}
|
|
@@ -4316,11 +4366,11 @@ function motionCommandRows(scene, shotId) {
|
|
|
4316
4366
|
return scene.shots[index].run.map((command2, i) => {
|
|
4317
4367
|
const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
|
|
4318
4368
|
const primitive = motionFlairPrimitive(command2);
|
|
4319
|
-
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 } : {} };
|
|
4320
4370
|
});
|
|
4321
4371
|
}
|
|
4322
4372
|
function duplicateMotionCommandEdit(scene, shot, command2) {
|
|
4323
|
-
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]), () => ( []));
|
|
4324
4374
|
return { op: "add_commands", shot, commands: run[command2] ? [structuredClone(run[command2])] : [], at: command2 + 1 };
|
|
4325
4375
|
}
|
|
4326
4376
|
var MOTION_EASE_CHOICES = [
|
|
@@ -4405,7 +4455,7 @@ function motionCueFromKey(key) {
|
|
|
4405
4455
|
function motionCueChoices(scene, limit = 256) {
|
|
4406
4456
|
const choices = [];
|
|
4407
4457
|
const s = (ms) => `${(ms / 1e3).toFixed(2)} s`;
|
|
4408
|
-
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;
|
|
4409
4459
|
if (scene.beat && scene.beat.bpm > 0) {
|
|
4410
4460
|
for (let beat = 0; choices.length < limit; beat++) {
|
|
4411
4461
|
const time = motionBeatTime(scene.beat, beat);
|
|
@@ -4415,7 +4465,7 @@ function motionCueChoices(scene, limit = 256) {
|
|
|
4415
4465
|
choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
|
|
4416
4466
|
}
|
|
4417
4467
|
}
|
|
4418
|
-
_optionalChain([scene, 'access',
|
|
4468
|
+
_optionalChain([scene, 'access', _160 => _160.narration, 'optionalAccess', _161 => _161.words, 'access', _162 => _162.forEach, 'call', _163 => _163((w, i) => {
|
|
4419
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 });
|
|
4420
4470
|
})]);
|
|
4421
4471
|
return choices;
|
|
@@ -4424,7 +4474,7 @@ function motionShotCueTime(scene, cue) {
|
|
|
4424
4474
|
return cue ? motionCueTime(scene, cue) : void 0;
|
|
4425
4475
|
}
|
|
4426
4476
|
function formatMotionNarration(narration) {
|
|
4427
|
-
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess',
|
|
4477
|
+
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _164 => _164.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
|
|
4428
4478
|
}
|
|
4429
4479
|
function parseMotionNarration(text) {
|
|
4430
4480
|
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
@@ -4595,5 +4645,6 @@ function parseMotionDrivers(text) {
|
|
|
4595
4645
|
|
|
4596
4646
|
|
|
4597
4647
|
|
|
4598
|
-
|
|
4648
|
+
|
|
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;
|
|
4599
4650
|
//# sourceMappingURL=index.cjs.map
|