@pixerate/editor 0.232.0 → 0.234.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/compile.d.cts +3 -0
- package/dist/animation-editor/compile.d.ts +3 -0
- package/dist/animation-editor/controller.d.cts +67 -2
- package/dist/animation-editor/controller.d.ts +67 -2
- package/dist/animation-editor/edit.d.cts +1 -1
- package/dist/animation-editor/edit.d.ts +1 -1
- package/dist/animation-editor/evaluate.d.cts +8 -1
- package/dist/animation-editor/evaluate.d.ts +8 -1
- package/dist/animation-editor/index.cjs +1202 -371
- package/dist/animation-editor/index.d.cts +3 -0
- package/dist/animation-editor/index.d.ts +3 -0
- package/dist/animation-editor/index.js +1032 -201
- package/dist/animation-editor/issues.d.cts +28 -0
- package/dist/animation-editor/issues.d.ts +28 -0
- package/dist/animation-editor/layer-edit.d.cts +55 -0
- package/dist/animation-editor/layer-edit.d.ts +55 -0
- package/dist/animation-editor/layer-tools.d.cts +11 -0
- package/dist/animation-editor/layer-tools.d.ts +11 -0
- package/dist/animation-editor/layers.d.cts +166 -0
- package/dist/animation-editor/layers.d.ts +166 -0
- package/dist/animation-editor/parse.d.cts +2 -0
- package/dist/animation-editor/parse.d.ts +2 -0
- package/dist/animation-editor/types.d.cts +44 -1
- package/dist/animation-editor/types.d.ts +44 -1
- package/dist/canvas/editorDocument.d.cts +49 -4
- package/dist/canvas/editorDocument.d.ts +49 -4
- package/dist/canvas/index.cjs +57 -30
- package/dist/canvas/index.js +44 -17
- package/dist/chunk-6RZVFYGJ.cjs +255 -0
- package/dist/{chunk-RG4O6K2A.cjs → chunk-A7PQNIBX.cjs} +14 -14
- package/dist/{chunk-ERJA5CGT.cjs → chunk-DGWOGQJ5.cjs} +8 -1
- package/dist/{chunk-TYCJGFCF.js → chunk-EUKY4KFX.js} +8 -1
- package/dist/chunk-I277KJLQ.js +255 -0
- package/dist/{chunk-2K5TELHV.cjs → chunk-JAOSL334.cjs} +10 -10
- package/dist/{chunk-MUSZYMBX.js → chunk-TEFQISBY.js} +1 -1
- package/dist/{chunk-6QLTUGMO.js → chunk-WDDUPWVG.js} +1 -1
- package/dist/{chunk-A653N65Q.cjs → chunk-ZQIWBJGH.cjs} +7 -7
- package/dist/effects/index.cjs +114 -322
- package/dist/effects/index.js +23 -231
- package/dist/image-editor/index.cjs +16 -16
- package/dist/image-editor/index.js +4 -4
- package/dist/paint-editor/index.cjs +10 -10
- package/dist/paint-editor/index.js +5 -5
- package/dist/vector/index.cjs +6 -6
- package/dist/vector/index.js +1 -1
- package/dist/video-editor/index.cjs +339 -339
- package/dist/video-editor/index.js +5 -5
- package/package.json +1 -1
- package/skills/pixerate-animation-editor/SKILL.md +10 -0
- package/skills/pixerate-animation-motion-graphics/SKILL.md +4 -0
- package/skills/pixerate-canvas/SKILL.md +2 -2
- package/skills/pixerate-video-editor/SKILL.md +11 -0
- package/skills/pixerate-video-montage/SKILL.md +2 -0
- package/dist/{chunk-PQYDJ2AV.js → chunk-SIK3LT6M.js} +16 -16
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
var _chunk6RZVFYGJcjs = require('../chunk-6RZVFYGJ.cjs');
|
|
7
|
+
|
|
2
8
|
|
|
3
9
|
var _chunkGXLZZVR5cjs = require('../chunk-GXLZZVR5.cjs');
|
|
4
10
|
|
|
@@ -8,7 +14,7 @@ var _chunkGXLZZVR5cjs = require('../chunk-GXLZZVR5.cjs');
|
|
|
8
14
|
|
|
9
15
|
|
|
10
16
|
|
|
11
|
-
var
|
|
17
|
+
var _chunkDGWOGQJ5cjs = require('../chunk-DGWOGQJ5.cjs');
|
|
12
18
|
|
|
13
19
|
|
|
14
20
|
|
|
@@ -44,6 +50,10 @@ var _chunkGF2RBSDMcjs = require('../chunk-GF2RBSDM.cjs');
|
|
|
44
50
|
require('../chunk-NM3G4VQT.cjs');
|
|
45
51
|
|
|
46
52
|
|
|
53
|
+
var _chunkPY4GWSE2cjs = require('../chunk-PY4GWSE2.cjs');
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
47
57
|
|
|
48
58
|
|
|
49
59
|
|
|
@@ -54,7 +64,9 @@ require('../chunk-NM3G4VQT.cjs');
|
|
|
54
64
|
|
|
55
65
|
|
|
56
66
|
|
|
57
|
-
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
var _chunkJAOSL334cjs = require('../chunk-JAOSL334.cjs');
|
|
58
70
|
require('../chunk-WOFXZ3XU.cjs');
|
|
59
71
|
require('../chunk-PQ3H2AAN.cjs');
|
|
60
72
|
require('../chunk-YQGCPL5X.cjs');
|
|
@@ -196,7 +208,10 @@ ${problems.map((p) => `- ${p}`).join("\n")}`);
|
|
|
196
208
|
}
|
|
197
209
|
};
|
|
198
210
|
var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "drivers", "motionBlur", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
|
|
199
|
-
var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
|
|
211
|
+
var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed", "layers", "transition"];
|
|
212
|
+
var LAYER_KEYS = ["id", "effect", "preset", "values", "subject", "role", "rect", "from", "until", "opacity", "fade", "provider", "name"];
|
|
213
|
+
var TRANSITION_KEYS = ["effect", "ms", "preset", "values", "provider", "name"];
|
|
214
|
+
var LAYER_ID = /^[A-Za-z_][\w.-]*$/;
|
|
200
215
|
var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric", "in", "during"];
|
|
201
216
|
var CAMERA_MOVE_KEYS = ["move", "ms", "preset", "values"];
|
|
202
217
|
var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps", "split", "cascade", "source"];
|
|
@@ -228,14 +243,14 @@ var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
|
228
243
|
var isNum = (v) => typeof v === "number" && Number.isFinite(v);
|
|
229
244
|
var isPoint = (v) => isObject(v) && isNum(v.x) && isNum(v.y);
|
|
230
245
|
function unknownKeys(value, known, where, problems) {
|
|
231
|
-
for (const key of Object.keys(value)) if (!known.includes(key)) problems.push(`${where}: unknown field ${
|
|
246
|
+
for (const key of Object.keys(value)) if (!known.includes(key)) problems.push(`${where}: unknown field ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, key, known)}.`);
|
|
232
247
|
}
|
|
233
248
|
function commandShapeProblems(command3, where) {
|
|
234
249
|
const problems = [];
|
|
235
250
|
if (!isObject(command3)) return [`${where} must be an object.`];
|
|
236
251
|
const type = command3.type;
|
|
237
252
|
if (typeof type !== "string" || !MOTION_COMMAND_TYPES.includes(type)) {
|
|
238
|
-
return [`${where}: unknown type ${typeof type === "string" ?
|
|
253
|
+
return [`${where}: unknown type ${typeof type === "string" ? _chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, type, MOTION_COMMAND_TYPES) : String(type)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`];
|
|
239
254
|
}
|
|
240
255
|
unknownKeys(command3, COMMAND_KEYS[type], `${where} (${type})`, problems);
|
|
241
256
|
const p = (msg) => problems.push(`${where} (${type}): ${msg}`);
|
|
@@ -287,7 +302,7 @@ function commandShapeProblems(command3, where) {
|
|
|
287
302
|
case "exit": {
|
|
288
303
|
const styles = type === "enter" ? MOTION_ENTER_STYLES : MOTION_EXIT_STYLES;
|
|
289
304
|
if (command3.style !== void 0 && !(typeof command3.style === "string" && styles.includes(command3.style)))
|
|
290
|
-
p(`"style" must be one of ${styles.join(", ")}${typeof command3.style === "string" ? ` (got ${
|
|
305
|
+
p(`"style" must be one of ${styles.join(", ")}${typeof command3.style === "string" ? ` (got ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, command3.style, styles)})` : ""}.`);
|
|
291
306
|
if (command3.direction !== void 0 && !MOTION_DIRECTIONS.includes(command3.direction)) p(`"direction" must be one of ${MOTION_DIRECTIONS.join(", ")}.`);
|
|
292
307
|
optionalNumber("distance");
|
|
293
308
|
if (command3.scale !== void 0 && !(isNum(command3.scale) && command3.scale >= 0)) p(`"scale" must be a number \u2265 0 (the starting scale for pop and zoom).`);
|
|
@@ -466,6 +481,50 @@ function shotShapeProblems(shot, where) {
|
|
|
466
481
|
}
|
|
467
482
|
if (!Array.isArray(shot.run)) problems.push(`${name}: "run" must be a list of commands (it may be empty).`);
|
|
468
483
|
else shot.run.forEach((command3, i) => problems.push(...commandShapeProblems(command3, `${name}, command ${i + 1}`)));
|
|
484
|
+
problems.push(...shotLayersShapeProblems(shot, name));
|
|
485
|
+
return problems;
|
|
486
|
+
}
|
|
487
|
+
var isLayerTime = (t) => isNum(t) && t >= 0 || isObject(t) && Object.keys(t).length === 1 && Number.isInteger(t.shots) && t.shots >= 1;
|
|
488
|
+
function shotLayersShapeProblems(shot, name) {
|
|
489
|
+
const problems = [];
|
|
490
|
+
if (shot.layers !== void 0) {
|
|
491
|
+
if (!Array.isArray(shot.layers)) problems.push(`${name}: "layers" must be a list of layers.`);
|
|
492
|
+
else
|
|
493
|
+
shot.layers.forEach((layer, i) => {
|
|
494
|
+
const where = `${name}, layer ${i + 1}`;
|
|
495
|
+
if (!isObject(layer)) return void problems.push(`${where} must be an object.`);
|
|
496
|
+
unknownKeys(layer, LAYER_KEYS, where, problems);
|
|
497
|
+
if (typeof layer.id !== "string" || !LAYER_ID.test(layer.id)) problems.push(`${where}: "id" must be letters, digits, "_", "-" or "." (e.g. "layer1").`);
|
|
498
|
+
if (layer.effect === void 0 && layer.subject === void 0) problems.push(`${where} needs an "effect", a "subject" or both.`);
|
|
499
|
+
if (layer.effect !== void 0 && (typeof layer.effect !== "string" || !layer.effect)) problems.push(`${where}: "effect" must be an effect id.`);
|
|
500
|
+
if (layer.subject !== void 0) {
|
|
501
|
+
const kind = _chunk6RZVFYGJcjs.effectSubjectKind.call(void 0, layer.subject);
|
|
502
|
+
if (kind === "video") problems.push(`${where}: an animation layer cannot play a video; use { "image" }, { "svg" }, { "text" } or { "slot" } (the video editor plays video).`);
|
|
503
|
+
else if (!kind || !String(layer.subject[kind]).trim()) problems.push(`${where}: "subject" must be { "image": url }, { "svg": markup }, { "text": words } or { "slot": name }.`);
|
|
504
|
+
}
|
|
505
|
+
if (layer.role !== void 0 && !_chunkJAOSL334cjs.EFFECT_LAYER_ROLES.includes(layer.role)) problems.push(`${where}: "role" must be one of ${_chunkJAOSL334cjs.EFFECT_LAYER_ROLES.join(", ")}.`);
|
|
506
|
+
if (layer.rect !== void 0) {
|
|
507
|
+
const r = layer.rect;
|
|
508
|
+
if (!isObject(r) || !["x", "y", "width", "height"].every((k) => isNum(r[k])) || !(r.width > 0 && r.height > 0)) problems.push(`${where}: "rect" must be { x, y, width, height } in artwork units, width and height > 0.`);
|
|
509
|
+
}
|
|
510
|
+
for (const k of ["from", "until"]) if (layer[k] !== void 0 && !isLayerTime(layer[k])) problems.push(`${where}: "${k}" must be ms \u2265 0 after the shot starts, or { "shots": n } (n \u2265 1: when the n-th shot after this one starts).`);
|
|
511
|
+
if (layer.opacity !== void 0 && !(isNum(layer.opacity) && layer.opacity >= 0 && layer.opacity <= 1)) problems.push(`${where}: "opacity" must be a number from 0 to 1.`);
|
|
512
|
+
if (layer.fade !== void 0 && !(isNum(layer.fade) && layer.fade >= 0)) problems.push(`${where}: "fade" must be ms \u2265 0.`);
|
|
513
|
+
if (layer.preset !== void 0 && typeof layer.preset !== "string") problems.push(`${where}: "preset" is a preset's name.`);
|
|
514
|
+
if (layer.values !== void 0 && !isObject(layer.values)) problems.push(`${where}: "values" is an object of the effect's control values.`);
|
|
515
|
+
for (const k of ["provider", "name"]) if (layer[k] !== void 0 && typeof layer[k] !== "string") problems.push(`${where}: "${k}" must be a string.`);
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
if (shot.transition !== void 0) {
|
|
519
|
+
const t = shot.transition;
|
|
520
|
+
if (!isObject(t) || typeof t.effect !== "string" || !t.effect) problems.push(`${name}: "transition" is { "effect": id, "ms"?, "preset"?, "values"? }.`);
|
|
521
|
+
else {
|
|
522
|
+
unknownKeys(t, TRANSITION_KEYS, `${name} transition`, problems);
|
|
523
|
+
if (t.ms !== void 0 && !(isNum(t.ms) && t.ms > 0 && t.ms <= 6e4)) problems.push(`${name} transition: "ms" must be a number from 1 to 60000.`);
|
|
524
|
+
if (t.preset !== void 0 && typeof t.preset !== "string") problems.push(`${name} transition: "preset" is a preset's name.`);
|
|
525
|
+
if (t.values !== void 0 && !isObject(t.values)) problems.push(`${name} transition: "values" is an object of the effect's control values.`);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
469
528
|
return problems;
|
|
470
529
|
}
|
|
471
530
|
function motionSceneShapeProblems(input) {
|
|
@@ -494,8 +553,8 @@ function motionSceneShapeProblems(input) {
|
|
|
494
553
|
problems.push('Scene: "beat" must be { "bpm": 1\u20131000, "offset"?: ms, "meter"?: beats a bar }.');
|
|
495
554
|
}
|
|
496
555
|
if (input.narration !== void 0) {
|
|
497
|
-
const
|
|
498
|
-
if (!isObject(
|
|
556
|
+
const n2 = input.narration;
|
|
557
|
+
if (!isObject(n2) || !Array.isArray(n2.words) || !n2.words.every((w, i, all) => isObject(w) && typeof w.text === "string" && isNum(w.start) && w.start >= 0 && (w.end === void 0 || isNum(w.end) && w.end >= w.start) && (i === 0 || w.start >= (_nullishCoalesce(all[i - 1].start, () => ( 0))))))
|
|
499
558
|
problems.push('Scene: "narration" must be { "words": [{ "text", "start": ms, "end"?: ms }, \u2026] } in time order.');
|
|
500
559
|
}
|
|
501
560
|
if (input.steps !== void 0 && !(isNum(input.steps) && input.steps > 0 && input.steps <= 120)) problems.push('Scene: "steps" must be frames per second from above 0 to 120.');
|
|
@@ -513,6 +572,17 @@ function motionSceneShapeProblems(input) {
|
|
|
513
572
|
problems.push('Scene: "presets" must be a list of { name, values }.');
|
|
514
573
|
if (!Array.isArray(input.shots)) problems.push('Scene: "shots" must be a list.');
|
|
515
574
|
else input.shots.forEach((shot, i) => problems.push(...shotShapeProblems(shot, `Shot ${i + 1}`)));
|
|
575
|
+
if (Array.isArray(input.shots)) {
|
|
576
|
+
const seen = /* @__PURE__ */ new Set();
|
|
577
|
+
for (const shot of input.shots)
|
|
578
|
+
if (isObject(shot) && Array.isArray(shot.layers)) {
|
|
579
|
+
for (const layer of shot.layers)
|
|
580
|
+
if (isObject(layer) && typeof layer.id === "string") {
|
|
581
|
+
if (seen.has(layer.id)) problems.push(`Layer id "${layer.id}" is used twice; layer ids are unique in the scene.`);
|
|
582
|
+
seen.add(layer.id);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
516
586
|
return problems;
|
|
517
587
|
}
|
|
518
588
|
function parseMotionScene(input) {
|
|
@@ -556,7 +626,7 @@ function matchMotionNodes(from, into) {
|
|
|
556
626
|
for (const x of [...left]) {
|
|
557
627
|
const k = key(x, a);
|
|
558
628
|
if (!k) continue;
|
|
559
|
-
const y = [...right].find((
|
|
629
|
+
const y = [...right].find((n2) => key(n2, b) === k);
|
|
560
630
|
if (!y) continue;
|
|
561
631
|
left.delete(x);
|
|
562
632
|
right.delete(y);
|
|
@@ -564,18 +634,18 @@ function matchMotionNodes(from, into) {
|
|
|
564
634
|
else out.pairs.push([x.id, y.id]);
|
|
565
635
|
}
|
|
566
636
|
};
|
|
567
|
-
pair((
|
|
568
|
-
pair((
|
|
637
|
+
pair((n2) => _optionalChain([n2, 'access', _2 => _2.name, 'optionalAccess', _3 => _3.trim, 'call', _4 => _4()]) || void 0);
|
|
638
|
+
pair((n2, g) => localId(n2.id, g.id) || void 0);
|
|
569
639
|
for (const x of [...left]) {
|
|
570
|
-
const y = [...right].find((
|
|
640
|
+
const y = [...right].find((n2) => n2.type === x.type);
|
|
571
641
|
if (!y) continue;
|
|
572
642
|
left.delete(x);
|
|
573
643
|
right.delete(y);
|
|
574
644
|
if (x.type === "group" && y.type === "group") visit(x, y);
|
|
575
645
|
else out.pairs.push([x.id, y.id]);
|
|
576
646
|
}
|
|
577
|
-
out.unpairedFrom.push(...[...left].map((
|
|
578
|
-
out.unpairedInto.push(...[...right].map((
|
|
647
|
+
out.unpairedFrom.push(...[...left].map((n2) => n2.id));
|
|
648
|
+
out.unpairedInto.push(...[...right].map((n2) => n2.id));
|
|
579
649
|
};
|
|
580
650
|
visit(from, into);
|
|
581
651
|
return out;
|
|
@@ -583,10 +653,10 @@ function matchMotionNodes(from, into) {
|
|
|
583
653
|
|
|
584
654
|
// src/animation-editor/smooth.ts
|
|
585
655
|
function smoothMotionLegs(times, values) {
|
|
586
|
-
const
|
|
587
|
-
const slope = new Array(
|
|
656
|
+
const n2 = values.length;
|
|
657
|
+
const slope = new Array(n2).fill(0);
|
|
588
658
|
const secant = (i) => (values[i + 1] - values[i]) / Math.max(1e-9, times[i + 1] - times[i]);
|
|
589
|
-
for (let i = 1; i <
|
|
659
|
+
for (let i = 1; i < n2 - 1; i++) {
|
|
590
660
|
const a = secant(i - 1);
|
|
591
661
|
const b = secant(i);
|
|
592
662
|
if (a * b <= 0) continue;
|
|
@@ -595,7 +665,7 @@ function smoothMotionLegs(times, values) {
|
|
|
595
665
|
slope[i] = 3 * (ha + hb) / ((2 * hb + ha) / a + (hb + 2 * ha) / b);
|
|
596
666
|
}
|
|
597
667
|
const legs = [];
|
|
598
|
-
for (let i = 0; i + 1 <
|
|
668
|
+
for (let i = 0; i + 1 < n2; i++) {
|
|
599
669
|
const dt = times[i + 1] - times[i];
|
|
600
670
|
const dv = values[i + 1] - values[i];
|
|
601
671
|
if (Math.abs(dv) < 1e-9) {
|
|
@@ -658,8 +728,8 @@ function motionTextUnits(layout, by) {
|
|
|
658
728
|
return layout.lines.flatMap((l) => l.words.flatMap((w) => w.letters.map((id) => [id])));
|
|
659
729
|
}
|
|
660
730
|
function motionCascade(units, cascade = "forward", seed = 1) {
|
|
661
|
-
const
|
|
662
|
-
const mid = (
|
|
731
|
+
const n2 = units.length;
|
|
732
|
+
const mid = (n2 - 1) / 2;
|
|
663
733
|
const indexed = units.map((u, i) => ({ u, i }));
|
|
664
734
|
if (cascade === "backward") return [...units].reverse();
|
|
665
735
|
if (cascade === "center") return indexed.sort((a, b) => Math.abs(a.i - mid) - Math.abs(b.i - mid) || a.i - b.i).map((x) => x.u);
|
|
@@ -674,7 +744,7 @@ function motionCascade(units, cascade = "forward", seed = 1) {
|
|
|
674
744
|
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
675
745
|
};
|
|
676
746
|
const out = [...units];
|
|
677
|
-
for (let i =
|
|
747
|
+
for (let i = n2 - 1; i > 0; i--) {
|
|
678
748
|
const j = Math.floor(rand() * (i + 1));
|
|
679
749
|
[out[i], out[j]] = [out[j], out[i]];
|
|
680
750
|
}
|
|
@@ -739,12 +809,12 @@ function strokeReach(node) {
|
|
|
739
809
|
return reach;
|
|
740
810
|
}
|
|
741
811
|
function motionRevealPadding(entry) {
|
|
742
|
-
const
|
|
743
|
-
if (!
|
|
812
|
+
const box2 = entry.box;
|
|
813
|
+
if (!box2 || !(box2.width > 0) || !(box2.height > 0)) return null;
|
|
744
814
|
const s = strokeReach(entry.node);
|
|
745
|
-
return [Math.min(1, s /
|
|
815
|
+
return [Math.min(1, s / box2.width + 0.02), Math.min(1, s / box2.height + 0.02)];
|
|
746
816
|
}
|
|
747
|
-
var clipRound = (
|
|
817
|
+
var clipRound = (n2) => Math.round(n2 * 1e4) / 1e4 || 0;
|
|
748
818
|
function revealFull(property, [px, py]) {
|
|
749
819
|
return (property === "clipRect" ? [-px, -py, 1 + 2 * px, 1 + 2 * py] : [0.5, 0.5, Math.hypot(0.5 + px, 0.5 + py)]).map(clipRound);
|
|
750
820
|
}
|
|
@@ -978,8 +1048,8 @@ function motionDriverSources(timeline, node, properties, seen = /* @__PURE__ */
|
|
|
978
1048
|
}
|
|
979
1049
|
function motionCommandRepeat(command3) {
|
|
980
1050
|
if (command3.type === "wait" || command3.type === "enter" || command3.type === "exit") return 1;
|
|
981
|
-
const
|
|
982
|
-
return Number.isInteger(
|
|
1051
|
+
const n2 = _nullishCoalesce(command3.repeat, () => ( 1));
|
|
1052
|
+
return Number.isInteger(n2) && n2 >= 1 ? n2 : 1;
|
|
983
1053
|
}
|
|
984
1054
|
function motionCommandDuration(command3, scene, target) {
|
|
985
1055
|
return motionCycleDuration(command3, scene, target) * motionCommandRepeat(command3);
|
|
@@ -1053,14 +1123,15 @@ function compileMotionScene(scene) {
|
|
|
1053
1123
|
const start = t;
|
|
1054
1124
|
let cursor = start;
|
|
1055
1125
|
const f = motionShotTimeScale(shot);
|
|
1056
|
-
const moveIn = shot.camera ?
|
|
1057
|
-
const
|
|
1126
|
+
const moveIn = shot.camera ? _chunkJAOSL334cjs.cameraMoveParts.call(void 0, shot.camera.in) : void 0;
|
|
1127
|
+
const transitionMs = index > 0 && shot.transition ? (_nullishCoalesce(shot.transition.ms, () => ( _chunkJAOSL334cjs.EFFECT_TRANSITION_MS))) * f : 0;
|
|
1128
|
+
const moveDuring = shot.camera ? _chunkJAOSL334cjs.cameraMoveParts.call(void 0, shot.camera.during) : void 0;
|
|
1058
1129
|
let playsIn = false;
|
|
1059
1130
|
if (shot.camera) {
|
|
1060
1131
|
const framed = motionCameraFramed(shot.camera);
|
|
1061
1132
|
const rect = framed ? resolveMotionCamera(shot.camera, scene) : null;
|
|
1062
1133
|
if (rect && rect.width > 0 && rect.height > 0 || !framed && moveIn) {
|
|
1063
|
-
const ms2 = index === 0 ? 0 : (_nullishCoalesce(_nullishCoalesce(_optionalChain([moveIn, 'optionalAccess', _37 => _37.ms]), () => ( shot.camera.ms)), () => ( MOTION_CAMERA_MS))) * f;
|
|
1134
|
+
const ms2 = index === 0 || transitionMs > 0 && !moveIn ? 0 : (_nullishCoalesce(_nullishCoalesce(_optionalChain([moveIn, 'optionalAccess', _37 => _37.ms]), () => ( shot.camera.ms)), () => ( MOTION_CAMERA_MS))) * f;
|
|
1064
1135
|
cameraMoves.push({ shot: shot.id, start, end: start + ms2, to: rect, ease: _nullishCoalesce(shot.camera.ease, () => ( MOTION_EASE_IN_OUT)), geometric: shot.camera.geometric === true });
|
|
1065
1136
|
cursor = start + ms2;
|
|
1066
1137
|
playsIn = !!moveIn && index > 0;
|
|
@@ -1081,7 +1152,7 @@ function compileMotionScene(scene) {
|
|
|
1081
1152
|
prevStart = begin;
|
|
1082
1153
|
runEnd = Math.max(runEnd, end2);
|
|
1083
1154
|
});
|
|
1084
|
-
const end = runEnd + (_nullishCoalesce(shot.hold, () => ( MOTION_DEFAULT_HOLD))) * f;
|
|
1155
|
+
const end = Math.max(runEnd, start + transitionMs) + (_nullishCoalesce(shot.hold, () => ( MOTION_DEFAULT_HOLD))) * f;
|
|
1085
1156
|
shots.push({
|
|
1086
1157
|
id: shot.id,
|
|
1087
1158
|
index,
|
|
@@ -1093,7 +1164,8 @@ function compileMotionScene(scene) {
|
|
|
1093
1164
|
...cue !== void 0 ? { cue } : {},
|
|
1094
1165
|
...missedBy !== void 0 ? { missedBy } : {},
|
|
1095
1166
|
...playsIn ? { cameraIn: moveIn.move } : {},
|
|
1096
|
-
...moveDuring ? { cameraDuring: moveDuring.move } : {}
|
|
1167
|
+
...moveDuring ? { cameraDuring: moveDuring.move } : {},
|
|
1168
|
+
...transitionMs > 0 ? { transition: shot.transition.effect, transitionEnd: start + transitionMs } : {}
|
|
1097
1169
|
});
|
|
1098
1170
|
t = end;
|
|
1099
1171
|
});
|
|
@@ -1157,14 +1229,14 @@ function compileMotionScene(scene) {
|
|
|
1157
1229
|
const made = segments.slice(first);
|
|
1158
1230
|
const steps = _nullishCoalesce(command3.steps, () => ( scene.steps));
|
|
1159
1231
|
if (steps && steps > 0) for (const s of made) s.steps = steps;
|
|
1160
|
-
const
|
|
1232
|
+
const n2 = motionCommandRepeat(command3);
|
|
1161
1233
|
const mode = _nullishCoalesce(command3.repeatMode, () => ( "loop"));
|
|
1162
1234
|
const shift = (v, by, k) => {
|
|
1163
1235
|
if (typeof v === "number" && typeof by === "number") return v + by * k;
|
|
1164
1236
|
if (Array.isArray(v) && Array.isArray(by) && v.length === by.length) return v.map((x, i) => x + by[i] * k);
|
|
1165
1237
|
return v;
|
|
1166
1238
|
};
|
|
1167
|
-
for (let k = 1; k <
|
|
1239
|
+
for (let k = 1; k < n2; k++) {
|
|
1168
1240
|
const at = start + k * cycle;
|
|
1169
1241
|
for (const s of made) {
|
|
1170
1242
|
if (mode === "mirror" && k % 2 === 1) {
|
|
@@ -1422,7 +1494,7 @@ function motionShotAt(timeline, time) {
|
|
|
1422
1494
|
// src/animation-editor/camera.ts
|
|
1423
1495
|
var windowCache = /* @__PURE__ */ new WeakMap();
|
|
1424
1496
|
function motionShotCameraMove(shot, role) {
|
|
1425
|
-
return
|
|
1497
|
+
return _chunkJAOSL334cjs.cameraMoveParts.call(void 0, _optionalChain([shot, 'optionalAccess', _55 => _55.camera, 'optionalAccess', _56 => _56[role === "transition" ? "in" : "during"]]));
|
|
1426
1498
|
}
|
|
1427
1499
|
var motionCameraStage = (scene) => ({ width: scene.artwork.width, height: scene.artwork.height });
|
|
1428
1500
|
var effectsPlayCamera = (provider) => !!provider && provider.capabilities.supportsCamera === true && typeof provider.cameraView === "function";
|
|
@@ -1444,7 +1516,7 @@ function motionCameraWindows(scene, provider) {
|
|
|
1444
1516
|
const track = timeline.tracks.get(motionTrackKey("", "camera"));
|
|
1445
1517
|
const boxView = (t) => {
|
|
1446
1518
|
const b = trackValue(track, t);
|
|
1447
|
-
return
|
|
1519
|
+
return _chunkJAOSL334cjs.cameraViewOfBox.call(void 0, Array.isArray(b) ? { x: b[0], y: b[1], width: b[2], height: b[3] } : full, stage);
|
|
1448
1520
|
};
|
|
1449
1521
|
const view = (move, values, from, to, u, ms2) => {
|
|
1450
1522
|
try {
|
|
@@ -1460,7 +1532,7 @@ function motionCameraWindows(scene, provider) {
|
|
|
1460
1532
|
const eases = timing.commandsStart > timing.start && !!_optionalChain([track, 'optionalAccess', _57 => _57.some, 'call', _58 => _58((seg) => seg.shot === timing.id)]);
|
|
1461
1533
|
const framed = !!_optionalChain([track, 'optionalAccess', _59 => _59.some, 'call', _60 => _60((seg) => seg.shot === timing.id)]);
|
|
1462
1534
|
if (timing.cameraIn && timing.commandsStart > timing.start) {
|
|
1463
|
-
const spec =
|
|
1535
|
+
const spec = _chunkJAOSL334cjs.cameraMoveParts.call(void 0, _optionalChain([shot, 'access', _61 => _61.camera, 'optionalAccess', _62 => _62.in]));
|
|
1464
1536
|
const from = _nullishCoalesce(carry, () => ( boxView(timing.start)));
|
|
1465
1537
|
const to = boxView(timing.commandsStart);
|
|
1466
1538
|
if (view(spec.move, spec.values, from, to, 0, timing.commandsStart - timing.start)) {
|
|
@@ -1472,7 +1544,7 @@ function motionCameraWindows(scene, provider) {
|
|
|
1472
1544
|
carry = null;
|
|
1473
1545
|
} else if (framed) carry = null;
|
|
1474
1546
|
if (timing.cameraDuring && timing.end > timing.commandsEnd) {
|
|
1475
|
-
const spec =
|
|
1547
|
+
const spec = _chunkJAOSL334cjs.cameraMoveParts.call(void 0, _optionalChain([shot, 'access', _63 => _63.camera, 'optionalAccess', _64 => _64.during]));
|
|
1476
1548
|
const from = _nullishCoalesce(carry, () => ( boxView(timing.commandsEnd)));
|
|
1477
1549
|
const ms2 = timing.end - timing.commandsEnd;
|
|
1478
1550
|
const last = view(spec.move, spec.values, from, from, 1, ms2);
|
|
@@ -1489,8 +1561,8 @@ var lerp = (a, b, t) => a + (b - a) * t;
|
|
|
1489
1561
|
var smooth = (t) => t * t * (3 - 2 * t);
|
|
1490
1562
|
function easeViews(from, to, u, stage) {
|
|
1491
1563
|
const k = smooth(Math.min(1, Math.max(0, u)));
|
|
1492
|
-
const a =
|
|
1493
|
-
const b =
|
|
1564
|
+
const a = _chunkJAOSL334cjs.cameraBoxOfView.call(void 0, from, stage);
|
|
1565
|
+
const b = _chunkJAOSL334cjs.cameraBoxOfView.call(void 0, to, stage);
|
|
1494
1566
|
const zoom = from.zoom * Math.pow(to.zoom / from.zoom, k);
|
|
1495
1567
|
const cx = lerp(a.x + a.width / 2, b.x + b.width / 2, k);
|
|
1496
1568
|
const cy = lerp(a.y + a.height / 2, b.y + b.height / 2, k);
|
|
@@ -1522,15 +1594,15 @@ function motionCameraViewAt(scene, time, provider) {
|
|
|
1522
1594
|
return retaken ? null : before.after;
|
|
1523
1595
|
}
|
|
1524
1596
|
function motionCameraBox(view, scene) {
|
|
1525
|
-
return
|
|
1597
|
+
return _chunkJAOSL334cjs.cameraBoxOfView.call(void 0, view, motionCameraStage(scene));
|
|
1526
1598
|
}
|
|
1527
1599
|
function motionCameraTransform(view, width) {
|
|
1528
1600
|
if (!view || !view.tilt && !view.turn) return "";
|
|
1529
1601
|
const distance = (_nullishCoalesce(view.perspective, () => ( 2))) * width;
|
|
1530
1602
|
return `perspective(${Math.round(distance)}px)${view.tilt ? ` rotateX(${round(view.tilt)}deg)` : ""}${view.turn ? ` rotateY(${round(-view.turn)}deg)` : ""}`;
|
|
1531
1603
|
}
|
|
1532
|
-
var round = (
|
|
1533
|
-
function withCameraViewEffects(svg, view,
|
|
1604
|
+
var round = (n2) => Math.round(n2 * 1e3) / 1e3;
|
|
1605
|
+
function withCameraViewEffects(svg, view, box2, idPrefix = "vg-") {
|
|
1534
1606
|
if (!view || !view.roll && !(view.blur && view.blur > 0)) return svg;
|
|
1535
1607
|
const open = svg.match(/<svg\b[^>]*>/);
|
|
1536
1608
|
const close = svg.lastIndexOf("</svg>");
|
|
@@ -1538,7 +1610,7 @@ function withCameraViewEffects(svg, view, box, idPrefix = "vg-") {
|
|
|
1538
1610
|
const startBody = open.index + open[0].length;
|
|
1539
1611
|
const attrs = [];
|
|
1540
1612
|
let defs = "";
|
|
1541
|
-
if (view.roll) attrs.push(`transform="rotate(${round(view.roll)} ${round(
|
|
1613
|
+
if (view.roll) attrs.push(`transform="rotate(${round(view.roll)} ${round(box2.x + box2.width / 2)} ${round(box2.y + box2.height / 2)})"`);
|
|
1542
1614
|
if (view.blur && view.blur > 0) {
|
|
1543
1615
|
const s = view.blur / view.zoom / 2;
|
|
1544
1616
|
const a = (_nullishCoalesce(view.blurAngle, () => ( 0))) * Math.PI / 180;
|
|
@@ -1555,7 +1627,7 @@ async function checkMotionCameraMoves(scene, provider) {
|
|
|
1555
1627
|
if (!named.length) return issues;
|
|
1556
1628
|
if (!effectsPlayCamera(provider)) {
|
|
1557
1629
|
const ids = named.map((s) => `"${s.id}"`).join(", ");
|
|
1558
|
-
issues.push(
|
|
1630
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "camera-move-not-played", `Shots ${ids} name camera moves, but ${provider ? `${provider.name} has no camera moves` : "no effects provider is set"}, so the camera eases between framings instead; set a provider with camera moves to play them.`));
|
|
1559
1631
|
return issues;
|
|
1560
1632
|
}
|
|
1561
1633
|
for (const shot of named) {
|
|
@@ -1563,22 +1635,345 @@ async function checkMotionCameraMoves(scene, provider) {
|
|
|
1563
1635
|
const spec = shot.camera[field];
|
|
1564
1636
|
if (spec === void 0) continue;
|
|
1565
1637
|
try {
|
|
1566
|
-
await
|
|
1638
|
+
await _chunkJAOSL334cjs.resolveCameraMoveSpec.call(void 0, provider, spec, role);
|
|
1567
1639
|
} catch (error) {
|
|
1568
1640
|
const code = error.code === "invalid_values" || /preset/.test(error.message) ? "camera-move-values" : "camera-move-unknown";
|
|
1569
|
-
issues.push(
|
|
1641
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, code, error.message, { shot: shot.id }));
|
|
1570
1642
|
}
|
|
1571
1643
|
}
|
|
1572
1644
|
}
|
|
1573
1645
|
return issues;
|
|
1574
1646
|
}
|
|
1575
1647
|
|
|
1648
|
+
// src/animation-editor/layers.ts
|
|
1649
|
+
var spanCache = /* @__PURE__ */ new WeakMap();
|
|
1650
|
+
function motionLayerSpans(scene) {
|
|
1651
|
+
const hit = spanCache.get(scene);
|
|
1652
|
+
if (hit) return hit;
|
|
1653
|
+
const timeline = compileMotionScene(scene);
|
|
1654
|
+
const shots = timeline.shots;
|
|
1655
|
+
const total = timeline.duration;
|
|
1656
|
+
const at = (shotIndex2, t, fallback) => {
|
|
1657
|
+
if (t === void 0) return fallback;
|
|
1658
|
+
if (typeof t === "number") return shots[shotIndex2].start + t;
|
|
1659
|
+
return _nullishCoalesce(_optionalChain([shots, 'access', _68 => _68[shotIndex2 + t.shots], 'optionalAccess', _69 => _69.start]), () => ( total));
|
|
1660
|
+
};
|
|
1661
|
+
const out = [];
|
|
1662
|
+
scene.shots.forEach((shot, shotIndex2) => {
|
|
1663
|
+
(_nullishCoalesce(shot.layers, () => ( []))).forEach((layer, index) => {
|
|
1664
|
+
const start = at(shotIndex2, layer.from, shots[shotIndex2].start);
|
|
1665
|
+
const end = Math.max(start, at(shotIndex2, _nullishCoalesce(layer.until, () => ( { shots: 1 })), total));
|
|
1666
|
+
out.push({ layer, shot: shot.id, shotIndex: shotIndex2, index, role: _chunk6RZVFYGJcjs.effectLayerRole.call(void 0, layer), start, end });
|
|
1667
|
+
});
|
|
1668
|
+
});
|
|
1669
|
+
spanCache.set(scene, out);
|
|
1670
|
+
return out;
|
|
1671
|
+
}
|
|
1672
|
+
function motionLayersAt(scene, time) {
|
|
1673
|
+
if (!scene.shots.some((s) => _optionalChain([s, 'access', _70 => _70.layers, 'optionalAccess', _71 => _71.length]))) return [];
|
|
1674
|
+
const total = compileMotionScene(scene).duration;
|
|
1675
|
+
const out = [];
|
|
1676
|
+
for (const span of motionLayerSpans(scene)) {
|
|
1677
|
+
if (time < span.start || time > span.end || time === span.end && span.end < total) continue;
|
|
1678
|
+
const fade = _nullishCoalesce(span.layer.fade, () => ( 0));
|
|
1679
|
+
const k = fade > 0 ? Math.min(1, (time - span.start) / fade, (span.end - time) / fade) : 1;
|
|
1680
|
+
const opacity = Math.max(0, Math.min(1, (_nullishCoalesce(span.layer.opacity, () => ( 1))) * k));
|
|
1681
|
+
if (opacity <= 0) continue;
|
|
1682
|
+
out.push({ ...span, time: time - span.start, opacity });
|
|
1683
|
+
}
|
|
1684
|
+
return out;
|
|
1685
|
+
}
|
|
1686
|
+
function motionTransitionAt(scene, time) {
|
|
1687
|
+
if (!scene.shots.some((s) => s.transition)) return null;
|
|
1688
|
+
for (const s of compileMotionScene(scene).shots) {
|
|
1689
|
+
if (s.transition && s.transitionEnd !== void 0 && time >= s.start && time < s.transitionEnd)
|
|
1690
|
+
return { shot: s.id, shotIndex: s.index, effect: s.transition, start: s.start, end: s.transitionEnd, progress: (time - s.start) / (s.transitionEnd - s.start) };
|
|
1691
|
+
}
|
|
1692
|
+
return null;
|
|
1693
|
+
}
|
|
1694
|
+
var motionSceneHasLayers = (scene) => scene.shots.some((s) => _optionalChain([s, 'access', _72 => _72.layers, 'optionalAccess', _73 => _73.length]) || s.transition);
|
|
1695
|
+
var esc = (s) => s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
1696
|
+
var n = (v) => String(Math.round(v * 1e3) / 1e3);
|
|
1697
|
+
var box = (b) => `x="${n(b.x)}" y="${n(b.y)}" width="${n(b.width)}" height="${n(b.height)}"`;
|
|
1698
|
+
var svgDataUrl = (svg) => `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
1699
|
+
function subjectSvg(subject, b, opacity, pictures) {
|
|
1700
|
+
const o = opacity < 1 ? ` opacity="${n(opacity)}"` : "";
|
|
1701
|
+
if ("image" in subject) {
|
|
1702
|
+
const href = _nullishCoalesce(_optionalChain([pictures, 'optionalAccess', _74 => _74.subject, 'call', _75 => _75(subject)]), () => ( subject.image));
|
|
1703
|
+
return `<image href="${esc(href)}" ${box(b)} preserveAspectRatio="xMidYMid meet"${o}/>`;
|
|
1704
|
+
}
|
|
1705
|
+
if ("svg" in subject) {
|
|
1706
|
+
const href = subject.svg.trimStart().startsWith("<") ? svgDataUrl(subject.svg) : subject.svg;
|
|
1707
|
+
return `<image href="${esc(href)}" ${box(b)} preserveAspectRatio="xMidYMid meet"${o}/>`;
|
|
1708
|
+
}
|
|
1709
|
+
if ("text" in subject) {
|
|
1710
|
+
const size = Math.max(1, Math.min(b.height * 0.6, b.width / Math.max(1, subject.text.length) * 1.6));
|
|
1711
|
+
return `<text x="${n(b.x + b.width / 2)}" y="${n(b.y + b.height / 2)}" text-anchor="middle" dominant-baseline="central" font-family="${esc(_nullishCoalesce(subject.font, () => ( "system-ui, sans-serif")))}" font-weight="${esc(String(_nullishCoalesce(subject.weight, () => ( 700))))}" font-size="${n(size)}" fill="#ffffff"${o}>${esc(subject.text)}</text>`;
|
|
1712
|
+
}
|
|
1713
|
+
return "";
|
|
1714
|
+
}
|
|
1715
|
+
function layerSvg(scene, active, camera, pictures) {
|
|
1716
|
+
const b = _nullishCoalesce(active.layer.rect, () => ( camera));
|
|
1717
|
+
if (!active.layer.effect) return active.layer.subject ? subjectSvg(active.layer.subject, b, active.opacity, pictures) : "";
|
|
1718
|
+
const href = _optionalChain([pictures, 'optionalAccess', _76 => _76.layer, 'call', _77 => _77(scene, active, b)]);
|
|
1719
|
+
if (!href) return "";
|
|
1720
|
+
return `<image href="${esc(href)}" ${box(b)} preserveAspectRatio="none" data-layer="${esc(active.layer.id)}"${active.opacity < 1 ? ` opacity="${n(active.opacity)}"` : ""}/>`;
|
|
1721
|
+
}
|
|
1722
|
+
function withMotionShotLayers(svg, scene, time, camera, pictures, background) {
|
|
1723
|
+
const active = motionLayersAt(scene, time);
|
|
1724
|
+
const open = svg.indexOf(">") + 1;
|
|
1725
|
+
let body = svg.slice(open, svg.lastIndexOf("</svg>"));
|
|
1726
|
+
const defs = _nullishCoalesce(_optionalChain([/^\s*<defs>[\s\S]*?<\/defs>/, 'access', _78 => _78.exec, 'call', _79 => _79(body), 'optionalAccess', _80 => _80[0]]), () => ( ""));
|
|
1727
|
+
body = body.slice(defs.length);
|
|
1728
|
+
const bg = background && scene.artwork.background ? `<rect width="${n(scene.artwork.width)}" height="${n(scene.artwork.height)}" fill="${esc(scene.artwork.background)}"/>` : "";
|
|
1729
|
+
const draw = (roles) => active.filter((a) => roles.includes(a.role)).map((a) => layerSvg(scene, a, camera, pictures)).join("");
|
|
1730
|
+
return `${svg.slice(0, open)}${defs}${bg}${draw(["background"])}${body}${draw(["subject"])}${draw(["overlay"])}</svg>`;
|
|
1731
|
+
}
|
|
1732
|
+
function motionTransitionSvg(svg, from, active, camera, picture) {
|
|
1733
|
+
const open = svg.indexOf(">") + 1;
|
|
1734
|
+
if (picture) return `${svg.slice(0, open)}<image href="${esc(picture)}" ${box(camera)} preserveAspectRatio="none" data-transition="${esc(active.effect)}"/></svg>`;
|
|
1735
|
+
const inner = svg.slice(open, svg.lastIndexOf("</svg>"));
|
|
1736
|
+
const fromView = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _81 => _81.exec, 'call', _82 => _82(from), 'optionalAccess', _83 => _83[1]]), () => ( ""));
|
|
1737
|
+
const fromInner = from.slice(from.indexOf(">") + 1, from.lastIndexOf("</svg>"));
|
|
1738
|
+
return `${svg.slice(0, open)}<svg ${box(camera)} viewBox="${fromView}" preserveAspectRatio="none" data-transition-from="">${fromInner}</svg><g opacity="${n(active.progress)}" data-transition-to="">${inner}</g></svg>`;
|
|
1739
|
+
}
|
|
1740
|
+
var sceneIds = /* @__PURE__ */ new WeakMap();
|
|
1741
|
+
var nextSceneId = 1;
|
|
1742
|
+
var sceneId = (scene) => {
|
|
1743
|
+
let id = sceneIds.get(scene);
|
|
1744
|
+
if (!id) sceneIds.set(scene, id = nextSceneId++);
|
|
1745
|
+
return id;
|
|
1746
|
+
};
|
|
1747
|
+
var MotionLayersEngine = (_class = class {
|
|
1748
|
+
|
|
1749
|
+
|
|
1750
|
+
|
|
1751
|
+
__init() {this.cache = /* @__PURE__ */ new Map()}
|
|
1752
|
+
__init2() {this.pending = /* @__PURE__ */ new Map()}
|
|
1753
|
+
__init3() {this.failures = /* @__PURE__ */ new Map()}
|
|
1754
|
+
__init4() {this.descriptions = /* @__PURE__ */ new Map()}
|
|
1755
|
+
__init5() {this.listeners = /* @__PURE__ */ new Set()}
|
|
1756
|
+
|
|
1757
|
+
|
|
1758
|
+
__init6() {this.generation = 0}
|
|
1759
|
+
|
|
1760
|
+
constructor(options = {}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this);_class.prototype.__init7.call(this);
|
|
1761
|
+
this.slot = _nullishCoalesce(options.slot, () => ( new (0, _chunkJAOSL334cjs.EffectsSlot)()));
|
|
1762
|
+
this.host = _nullishCoalesce(options.host, () => ( null));
|
|
1763
|
+
this.frameSvg = options.frameSvg;
|
|
1764
|
+
this.options = { scale: _nullishCoalesce(options.scale, () => ( 1)), maxSize: _nullishCoalesce(options.maxSize, () => ( 1280)), fps: _nullishCoalesce(options.fps, () => ( 30)), maxEntries: _nullishCoalesce(options.maxEntries, () => ( 160)) };
|
|
1765
|
+
this.pool = new (0, _chunkPY4GWSE2cjs.EffectRendererPool)({ maxRenderers: options.maxRenderers });
|
|
1766
|
+
this.detach = this.slot.subscribe(() => {
|
|
1767
|
+
this.reset();
|
|
1768
|
+
this.notify();
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
get provider() {
|
|
1772
|
+
return this.slot.provider;
|
|
1773
|
+
}
|
|
1774
|
+
/** Called when a picture is ready (draw the frame again). */
|
|
1775
|
+
subscribe(listener) {
|
|
1776
|
+
this.listeners.add(listener);
|
|
1777
|
+
return () => this.listeners.delete(listener);
|
|
1778
|
+
}
|
|
1779
|
+
/** Why pictures failed, newest last. */
|
|
1780
|
+
failuresList() {
|
|
1781
|
+
return [...this.failures.values()];
|
|
1782
|
+
}
|
|
1783
|
+
/** True while any picture is being made. */
|
|
1784
|
+
get busy() {
|
|
1785
|
+
return this.pending.size > 0;
|
|
1786
|
+
}
|
|
1787
|
+
/** Resolves once every picture asked for so far is made (or failed). */
|
|
1788
|
+
async idle() {
|
|
1789
|
+
while (this.pending.size) await Promise.all([...this.pending.values()]);
|
|
1790
|
+
}
|
|
1791
|
+
/** Forgets every picture and failure (a new provider, or the host changed). */
|
|
1792
|
+
reset() {
|
|
1793
|
+
this.generation++;
|
|
1794
|
+
this.cache.clear();
|
|
1795
|
+
this.pending.clear();
|
|
1796
|
+
this.failures.clear();
|
|
1797
|
+
this.descriptions.clear();
|
|
1798
|
+
this.pool.clear();
|
|
1799
|
+
}
|
|
1800
|
+
dispose() {
|
|
1801
|
+
this.detach();
|
|
1802
|
+
this.reset();
|
|
1803
|
+
this.listeners.clear();
|
|
1804
|
+
}
|
|
1805
|
+
notify() {
|
|
1806
|
+
this.listeners.forEach((l) => l());
|
|
1807
|
+
}
|
|
1808
|
+
size(b) {
|
|
1809
|
+
const k = Math.min(this.options.scale, this.options.maxSize / Math.max(b.width, b.height));
|
|
1810
|
+
return { width: Math.max(1, Math.round(b.width * k)), height: Math.max(1, Math.round(b.height * k)) };
|
|
1811
|
+
}
|
|
1812
|
+
snap(t) {
|
|
1813
|
+
const step = 1e3 / this.options.fps;
|
|
1814
|
+
return Math.round(Math.round(t / step) * step * 1e3) / 1e3;
|
|
1815
|
+
}
|
|
1816
|
+
get(key) {
|
|
1817
|
+
const v = this.cache.get(key);
|
|
1818
|
+
if (v === void 0) return void 0;
|
|
1819
|
+
this.cache.delete(key);
|
|
1820
|
+
this.cache.set(key, v);
|
|
1821
|
+
return v;
|
|
1822
|
+
}
|
|
1823
|
+
request(key, info2, work) {
|
|
1824
|
+
if (this.cache.has(key) || this.pending.has(key) || this.failures.has(key)) return;
|
|
1825
|
+
const generation = this.generation;
|
|
1826
|
+
const run = work().then((url) => {
|
|
1827
|
+
if (generation !== this.generation) return;
|
|
1828
|
+
this.cache.set(key, url);
|
|
1829
|
+
while (this.cache.size > this.options.maxEntries) this.cache.delete(this.cache.keys().next().value);
|
|
1830
|
+
}).catch((error) => {
|
|
1831
|
+
if (generation !== this.generation) return;
|
|
1832
|
+
this.failures.set(key, { key, ...info2, error: error instanceof Error ? error : new Error(String(error)) });
|
|
1833
|
+
}).finally(() => {
|
|
1834
|
+
if (generation !== this.generation) return;
|
|
1835
|
+
this.pending.delete(key);
|
|
1836
|
+
this.notify();
|
|
1837
|
+
});
|
|
1838
|
+
this.pending.set(key, run);
|
|
1839
|
+
}
|
|
1840
|
+
describe(id) {
|
|
1841
|
+
const provider = this.slot.require();
|
|
1842
|
+
let d = this.descriptions.get(id);
|
|
1843
|
+
if (!d) {
|
|
1844
|
+
d = Promise.resolve(provider.describe(id));
|
|
1845
|
+
this.descriptions.set(id, d);
|
|
1846
|
+
d.catch(() => this.descriptions.delete(id));
|
|
1847
|
+
}
|
|
1848
|
+
return d;
|
|
1849
|
+
}
|
|
1850
|
+
subject(subject) {
|
|
1851
|
+
if (subject.image.startsWith("data:")) return subject.image;
|
|
1852
|
+
const host = this.host;
|
|
1853
|
+
if (!host) return void 0;
|
|
1854
|
+
const key = `img:${subject.image}`;
|
|
1855
|
+
this.request(key, {}, () => host.loadImage(subject.image));
|
|
1856
|
+
return this.get(key);
|
|
1857
|
+
}
|
|
1858
|
+
/** The pixels a layer's subject feeds its effect, at `size`. */
|
|
1859
|
+
async subjectPixels(subject, size) {
|
|
1860
|
+
const host = this.host;
|
|
1861
|
+
const b = { x: 0, y: 0, ...size };
|
|
1862
|
+
let s = subject;
|
|
1863
|
+
if ("image" in s && !s.image.startsWith("data:")) s = { image: await host.loadImage(s.image) };
|
|
1864
|
+
return host.rasterize(`<svg xmlns="http://www.w3.org/2000/svg" width="${size.width}" height="${size.height}" viewBox="0 0 ${size.width} ${size.height}">${subjectSvg(s, b, 1, void 0)}</svg>`, size.width, size.height);
|
|
1865
|
+
}
|
|
1866
|
+
layer(scene, active, b) {
|
|
1867
|
+
const provider = this.slot.provider;
|
|
1868
|
+
const host = this.host;
|
|
1869
|
+
const layer = active.layer;
|
|
1870
|
+
if (!provider || !host || !layer.effect) return void 0;
|
|
1871
|
+
if (layer.subject && "slot" in layer.subject) return void 0;
|
|
1872
|
+
const size = this.size(b);
|
|
1873
|
+
const time = this.snap(active.time);
|
|
1874
|
+
const key = `layer:${provider.id}:${layer.effect}:${JSON.stringify(_nullishCoalesce(layer.values, () => ( {})))}:${JSON.stringify(_nullishCoalesce(layer.subject, () => ( null)))}:${size.width}x${size.height}@${time}`;
|
|
1875
|
+
const effect = layer.effect;
|
|
1876
|
+
this.request(key, { layer: layer.id }, async () => {
|
|
1877
|
+
const d = await this.describe(effect);
|
|
1878
|
+
const values = _chunkJAOSL334cjs.resolveEffectValues.call(void 0, d, layer.values);
|
|
1879
|
+
const input = _chunk6RZVFYGJcjs.effectLayerInput.call(void 0, d);
|
|
1880
|
+
const inputs = layer.subject && input ? { [input]: await this.subjectPixels(layer.subject, size) } : void 0;
|
|
1881
|
+
const pixels = await this.pool.render(provider, effect, size, { time, values, ...inputs ? { inputs } : {} });
|
|
1882
|
+
return host.encode(pixels);
|
|
1883
|
+
});
|
|
1884
|
+
return this.get(key);
|
|
1885
|
+
}
|
|
1886
|
+
transition(scene, time, active) {
|
|
1887
|
+
const provider = this.slot.provider;
|
|
1888
|
+
const host = this.host;
|
|
1889
|
+
const frameSvg = this.frameSvg;
|
|
1890
|
+
if (!provider || !host || !frameSvg) return void 0;
|
|
1891
|
+
const shot = scene.shots[active.shotIndex];
|
|
1892
|
+
const t = shot.transition;
|
|
1893
|
+
const size = this.size({ x: 0, y: 0, width: scene.artwork.width, height: scene.artwork.height });
|
|
1894
|
+
const at = Math.min(active.end - 1e-3, this.snap(time));
|
|
1895
|
+
const progress = (at - active.start) / (active.end - active.start);
|
|
1896
|
+
const key = `transition:${sceneId(scene)}:${provider.id}:${t.effect}:${JSON.stringify(_nullishCoalesce(t.values, () => ( {})))}:${size.width}x${size.height}@${at}`;
|
|
1897
|
+
const fromKey = `from:${sceneId(scene)}:${active.shot}:${size.width}x${size.height}`;
|
|
1898
|
+
this.request(key, { transition: active.shot }, async () => {
|
|
1899
|
+
const d = await this.describe(t.effect);
|
|
1900
|
+
const values = _chunkJAOSL334cjs.resolveEffectValues.call(void 0, d, t.values);
|
|
1901
|
+
frameSvg(scene, Math.max(0, active.start - 1e-3));
|
|
1902
|
+
frameSvg(scene, at);
|
|
1903
|
+
await this.idleExcept(key);
|
|
1904
|
+
const fromSvg = frameSvg(scene, Math.max(0, active.start - 1e-3));
|
|
1905
|
+
const toSvg = frameSvg(scene, at);
|
|
1906
|
+
let from = this.fromPixels.get(fromKey);
|
|
1907
|
+
if (!from) {
|
|
1908
|
+
from = host.rasterize(fromSvg, size.width, size.height);
|
|
1909
|
+
this.fromPixels.set(fromKey, from);
|
|
1910
|
+
if (this.fromPixels.size > 8) this.fromPixels.delete(this.fromPixels.keys().next().value);
|
|
1911
|
+
}
|
|
1912
|
+
const to = await host.rasterize(toSvg, size.width, size.height);
|
|
1913
|
+
const pixels = await this.pool.render(provider, t.effect, size, { time: at - active.start, progress, values, inputs: { from: await from, to } });
|
|
1914
|
+
return host.encode(pixels);
|
|
1915
|
+
});
|
|
1916
|
+
return this.get(key);
|
|
1917
|
+
}
|
|
1918
|
+
__init7() {this.fromPixels = /* @__PURE__ */ new Map()}
|
|
1919
|
+
async idleExcept(key) {
|
|
1920
|
+
for (; ; ) {
|
|
1921
|
+
const others = [...this.pending].filter(([k]) => k !== key && !k.startsWith("transition:")).map(([, p]) => p);
|
|
1922
|
+
if (!others.length) return;
|
|
1923
|
+
await Promise.all(others);
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
}, _class);
|
|
1927
|
+
function browserMotionLayerHost(doc = globalThis.document) {
|
|
1928
|
+
const view = _optionalChain([doc, 'optionalAccess', _84 => _84.defaultView]);
|
|
1929
|
+
if (!doc || !_optionalChain([view, 'optionalAccess', _85 => _85.Image]) || typeof doc.createElement !== "function") return null;
|
|
1930
|
+
const canvas = (width, height) => {
|
|
1931
|
+
const c = doc.createElement("canvas");
|
|
1932
|
+
c.width = width;
|
|
1933
|
+
c.height = height;
|
|
1934
|
+
const ctx = c.getContext("2d");
|
|
1935
|
+
if (!ctx) throw new Error("This browser cannot draw layer pictures (no 2D canvas).");
|
|
1936
|
+
return { c, ctx };
|
|
1937
|
+
};
|
|
1938
|
+
const load = (src, cors) => new Promise((resolve2, reject) => {
|
|
1939
|
+
const image = new view.Image();
|
|
1940
|
+
if (cors) image.crossOrigin = "anonymous";
|
|
1941
|
+
image.onload = () => resolve2(image);
|
|
1942
|
+
image.onerror = () => reject(new Error(`The picture ${src.startsWith("data:") ? "(a data: URL)" : `"${src}"`} could not be loaded; check the URL and that its server allows cross-origin use.`));
|
|
1943
|
+
image.src = src;
|
|
1944
|
+
});
|
|
1945
|
+
return {
|
|
1946
|
+
async rasterize(svg, width, height) {
|
|
1947
|
+
const image = await load(svgDataUrl(svg), false);
|
|
1948
|
+
const { ctx } = canvas(width, height);
|
|
1949
|
+
ctx.drawImage(image, 0, 0, width, height);
|
|
1950
|
+
const data = ctx.getImageData(0, 0, width, height);
|
|
1951
|
+
return { width, height, data: data.data };
|
|
1952
|
+
},
|
|
1953
|
+
encode(pixels) {
|
|
1954
|
+
const { c, ctx } = canvas(pixels.width, pixels.height);
|
|
1955
|
+
const image = ctx.createImageData(pixels.width, pixels.height);
|
|
1956
|
+
image.data.set(pixels.data);
|
|
1957
|
+
ctx.putImageData(image, 0, 0);
|
|
1958
|
+
return c.toDataURL("image/png");
|
|
1959
|
+
},
|
|
1960
|
+
async loadImage(url) {
|
|
1961
|
+
if (url.startsWith("data:")) return url;
|
|
1962
|
+
const image = await load(url, true);
|
|
1963
|
+
const { c, ctx } = canvas(image.naturalWidth || 1, image.naturalHeight || 1);
|
|
1964
|
+
ctx.drawImage(image, 0, 0);
|
|
1965
|
+
return c.toDataURL("image/png");
|
|
1966
|
+
}
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
var motionLayerSlot = (layer) => layer.subject && "slot" in layer.subject ? layer.subject.slot : void 0;
|
|
1970
|
+
|
|
1576
1971
|
// src/animation-editor/evaluate.ts
|
|
1577
1972
|
var MOTION_DRAW_EFFECT_ID = "~draw";
|
|
1578
1973
|
var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
|
|
1579
1974
|
var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
|
|
1580
1975
|
function applyMotionControlValues(scene, values) {
|
|
1581
|
-
if (!values || !_optionalChain([scene, 'access',
|
|
1976
|
+
if (!values || !_optionalChain([scene, 'access', _86 => _86.controls, 'optionalAccess', _87 => _87.length])) return scene;
|
|
1582
1977
|
const map = /* @__PURE__ */ new Map();
|
|
1583
1978
|
for (const control of scene.controls) {
|
|
1584
1979
|
const value = values[control.name];
|
|
@@ -1625,7 +2020,7 @@ function shapeIn(entry, shape) {
|
|
|
1625
2020
|
}
|
|
1626
2021
|
function shapeAt(entry, timeline, nodes, time) {
|
|
1627
2022
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
|
|
1628
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
2023
|
+
if (!_optionalChain([track, 'optionalAccess', _88 => _88.length])) return null;
|
|
1629
2024
|
const s = activeSegment(track, time);
|
|
1630
2025
|
const fromId = String(s ? s.from : track[0].from);
|
|
1631
2026
|
if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
|
|
@@ -1648,8 +2043,8 @@ function motionFollowRoute(entry, path) {
|
|
|
1648
2043
|
}
|
|
1649
2044
|
function followAt(entry, timeline, nodes, time) {
|
|
1650
2045
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "follow"));
|
|
1651
|
-
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess',
|
|
1652
|
-
if (!_optionalChain([s, 'optionalAccess',
|
|
2046
|
+
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _89 => _89[0]])));
|
|
2047
|
+
if (!_optionalChain([s, 'optionalAccess', _90 => _90.path])) return null;
|
|
1653
2048
|
const route = motionFollowRoute(entry, nodes.get(s.path));
|
|
1654
2049
|
const progress = Number(trackValue(track, time));
|
|
1655
2050
|
if (!route || !(progress >= 0)) return null;
|
|
@@ -1667,7 +2062,7 @@ function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry
|
|
|
1667
2062
|
const layered = withMotionLayers(timeline, entry.node.id, p, typeof v === "number" ? v : rest, time, raw);
|
|
1668
2063
|
return p === "follow" ? layered : applyMotionDrivers(timeline, entry.node.id, p, layered, time, raw);
|
|
1669
2064
|
};
|
|
1670
|
-
const driven = _optionalChain([timeline, 'access',
|
|
2065
|
+
const driven = _optionalChain([timeline, 'access', _91 => _91.drivers, 'optionalAccess', _92 => _92.some, 'call', _93 => _93((d) => d.target === entry.node.id && d.property !== "opacity")]);
|
|
1671
2066
|
if (!driven && !TRANSFORM_PROPS.some((p) => (follow || p !== "follow") && (timeline.tracks.has(motionTrackKey(entry.node.id, p)) || timeline.tracks.has(motionAddTrackKey(entry.node.id, p))))) return null;
|
|
1672
2067
|
const dx = read("x", 0);
|
|
1673
2068
|
const dy = read("y", 0);
|
|
@@ -1711,7 +2106,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1711
2106
|
if (out.visible === void 0) delete out.visible;
|
|
1712
2107
|
}
|
|
1713
2108
|
const effectTracks = [...timeline.tracks.keys()].filter((k) => k.startsWith(`${id}\0effect:`));
|
|
1714
|
-
if (effectTracks.length && _optionalChain([out, 'access',
|
|
2109
|
+
if (effectTracks.length && _optionalChain([out, 'access', _94 => _94.effects, 'optionalAccess', _95 => _95.length])) {
|
|
1715
2110
|
out = {
|
|
1716
2111
|
...out,
|
|
1717
2112
|
effects: out.effects.map((effect) => {
|
|
@@ -1751,7 +2146,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1751
2146
|
return p;
|
|
1752
2147
|
});
|
|
1753
2148
|
}
|
|
1754
|
-
const opacity = _optionalChain([timeline, 'access',
|
|
2149
|
+
const opacity = _optionalChain([timeline, 'access', _96 => _96.drivers, 'optionalAccess', _97 => _97.some, 'call', _98 => _98((d) => d.target === id && d.property === "opacity")]) ? motionPropertyValue(timeline, id, "opacity", time) : value(id, "opacity");
|
|
1755
2150
|
if (typeof opacity === "number") {
|
|
1756
2151
|
const o = Math.min(1, Math.max(0, tidy(opacity)));
|
|
1757
2152
|
out = { ...out, opacity: o };
|
|
@@ -1767,8 +2162,8 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1767
2162
|
const document = { ...s.artwork, nodes: s.artwork.nodes.map(visit) };
|
|
1768
2163
|
const cam = trackValue(timeline.tracks.get(motionTrackKey("", "camera")), time);
|
|
1769
2164
|
const view = motionCameraViewAt(s, time, options.effects);
|
|
1770
|
-
const
|
|
1771
|
-
return { time, document, camera: { x: tidy(
|
|
2165
|
+
const box2 = view ? (({ x, y, width, height }) => [x, y, width, height])(motionCameraBox(view, s)) : Array.isArray(cam) ? cam : [0, 0, s.artwork.width, s.artwork.height];
|
|
2166
|
+
return { time, document, camera: { x: tidy(box2[0]), y: tidy(box2[1]), width: tidy(box2[2]), height: tidy(box2[3]) }, ...view ? { view } : {}, clips };
|
|
1772
2167
|
}
|
|
1773
2168
|
function motionClipAttrs(clip) {
|
|
1774
2169
|
const { shape: _shape, ...attrs } = clip;
|
|
@@ -1780,11 +2175,20 @@ function motionFrameToSvg(scene, time, options = {}) {
|
|
|
1780
2175
|
const wrap = { ...options.wrap };
|
|
1781
2176
|
for (const [id, clips] of Object.entries(frame.clips))
|
|
1782
2177
|
wrap[id] = [..._nullishCoalesce(wrap[id], () => ( [])), ...clips.map((clip, i) => ({ clip: { id: `${prefix}reveal-${id}-${i}`, shape: clip.shape, attrs: motionClipAttrs(clip) } }))];
|
|
1783
|
-
return withCameraViewEffects(withViewBox(_chunkBQE3Y6ZOcjs.vectorDocumentToSvg.call(void 0, frame.document, { ...options, wrap }), frame.camera), frame.view, frame.camera, prefix);
|
|
2178
|
+
if (!motionSceneHasLayers(scene)) return withCameraViewEffects(withViewBox(_chunkBQE3Y6ZOcjs.vectorDocumentToSvg.call(void 0, frame.document, { ...options, wrap }), frame.camera), frame.view, frame.camera, prefix);
|
|
2179
|
+
const art = _chunkBQE3Y6ZOcjs.vectorDocumentToSvg.call(void 0, frame.document, { ...options, wrap, background: false });
|
|
2180
|
+
let svg = withViewBox(withMotionShotLayers(art, scene, time, frame.camera, options.layers, options.background !== false), frame.camera);
|
|
2181
|
+
const transition = options.transitions === false ? null : motionTransitionAt(scene, time);
|
|
2182
|
+
if (transition) {
|
|
2183
|
+
const picture = _optionalChain([options, 'access', _99 => _99.layers, 'optionalAccess', _100 => _100.transition, 'call', _101 => _101(scene, time, transition)]);
|
|
2184
|
+
const from = picture ? "" : motionFrameToSvg(scene, Math.max(0, transition.start - 1e-3), { ...options, transitions: false, idPrefix: `${prefix}from-` });
|
|
2185
|
+
svg = motionTransitionSvg(svg, from, transition, frame.camera, picture);
|
|
2186
|
+
}
|
|
2187
|
+
return withCameraViewEffects(svg, frame.view, frame.camera, prefix);
|
|
1784
2188
|
}
|
|
1785
|
-
function withViewBox(svg,
|
|
1786
|
-
const f = (
|
|
1787
|
-
return svg.replace(/viewBox="[^"]*"/, `viewBox="${f(
|
|
2189
|
+
function withViewBox(svg, box2) {
|
|
2190
|
+
const f = (n2) => String(Math.round(n2 * 1e3) / 1e3);
|
|
2191
|
+
return svg.replace(/viewBox="[^"]*"/, `viewBox="${f(box2.x)} ${f(box2.y)} ${f(box2.width)} ${f(box2.height)}"`);
|
|
1788
2192
|
}
|
|
1789
2193
|
|
|
1790
2194
|
// src/animation-editor/onion.ts
|
|
@@ -1822,10 +2226,10 @@ function motionPath(scene, id, options = {}) {
|
|
|
1822
2226
|
const to = Math.min(timeline.duration, _nullishCoalesce(options.to, () => ( timeline.duration)));
|
|
1823
2227
|
let step = options.step && options.step > 0 ? options.step : 1e3 / 30;
|
|
1824
2228
|
if ((to - from) / step > 400) step = (to - from) / 400;
|
|
1825
|
-
const r = (
|
|
2229
|
+
const r = (n2) => Math.round(n2 * 100) / 100;
|
|
1826
2230
|
const centreAt = (t) => {
|
|
1827
2231
|
const node = indexMotionNodes(motionFrameAtCache(scene, t)).get(id);
|
|
1828
|
-
const b = _optionalChain([node, 'optionalAccess',
|
|
2232
|
+
const b = _optionalChain([node, 'optionalAccess', _102 => _102.bounds]);
|
|
1829
2233
|
return b ? { t: r(t), x: r(b.x + b.width / 2), y: r(b.y + b.height / 2) } : null;
|
|
1830
2234
|
};
|
|
1831
2235
|
const points = [];
|
|
@@ -1843,7 +2247,7 @@ function motionFrameAtCache(scene, t) {
|
|
|
1843
2247
|
}
|
|
1844
2248
|
function motionPathsSvg(paths, camera, color = "#f43f5e") {
|
|
1845
2249
|
const w = Math.max(camera.width, camera.height) / 400;
|
|
1846
|
-
const f = (
|
|
2250
|
+
const f = (n2) => String(Math.round(n2 * 100) / 100);
|
|
1847
2251
|
return paths.filter((p) => p.points.length > 1).map(
|
|
1848
2252
|
(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>`
|
|
1849
2253
|
).join("");
|
|
@@ -1859,22 +2263,22 @@ function motionBlurTimes(scene, time, blur = {}) {
|
|
|
1859
2263
|
const b = indexMotionNodes(motionFrameAt(scene, time + span / 2).document.nodes);
|
|
1860
2264
|
let travel = 0;
|
|
1861
2265
|
for (const id of ids) {
|
|
1862
|
-
const p = _optionalChain([a, 'access',
|
|
1863
|
-
const q = _optionalChain([b, 'access',
|
|
2266
|
+
const p = _optionalChain([a, 'access', _103 => _103.get, 'call', _104 => _104(id), 'optionalAccess', _105 => _105.bounds]);
|
|
2267
|
+
const q = _optionalChain([b, 'access', _106 => _106.get, 'call', _107 => _107(id), 'optionalAccess', _108 => _108.bounds]);
|
|
1864
2268
|
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));
|
|
1865
2269
|
}
|
|
1866
|
-
const
|
|
1867
|
-
if (
|
|
1868
|
-
return Array.from({ length:
|
|
2270
|
+
const n2 = Math.min(most, Math.ceil(travel / 1.5));
|
|
2271
|
+
if (n2 <= 1) return [time];
|
|
2272
|
+
return Array.from({ length: n2 }, (_, k) => time - span / 2 + span * (k + 0.5) / n2);
|
|
1869
2273
|
}
|
|
1870
2274
|
function averagedFrames(scene, times, options, prefix) {
|
|
1871
|
-
const
|
|
1872
|
-
return `<g data-motion-blur="${
|
|
2275
|
+
const n2 = times.length;
|
|
2276
|
+
return `<g data-motion-blur="${n2}" style="isolation:isolate">${times.map((t, k) => {
|
|
1873
2277
|
const own = `${prefix}blur${k}-`;
|
|
1874
2278
|
const frame = motionFrameToSvg(scene, t, { ...options, idPrefix: own, background: false });
|
|
1875
|
-
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access',
|
|
1876
|
-
const inner = k ===
|
|
1877
|
-
return `<svg viewBox="${view}" preserveAspectRatio="none" style="mix-blend-mode:plus-lighter" opacity="${Math.round(1e4 /
|
|
2279
|
+
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _109 => _109.exec, 'call', _110 => _110(frame), 'optionalAccess', _111 => _111[1]]), () => ( ""));
|
|
2280
|
+
const inner = k === n2 - 1 ? innerSvg(frame) : innerSvg(frame).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
|
|
2281
|
+
return `<svg viewBox="${view}" preserveAspectRatio="none" style="mix-blend-mode:plus-lighter" opacity="${Math.round(1e4 / n2) / 1e4}">${inner}</svg>`;
|
|
1878
2282
|
}).join("")}</g>`;
|
|
1879
2283
|
}
|
|
1880
2284
|
var innerSvg = (svg) => svg.slice(svg.indexOf(">") + 1, svg.lastIndexOf("</svg>"));
|
|
@@ -1887,7 +2291,7 @@ function motionStageSvg(scene, time, options = {}) {
|
|
|
1887
2291
|
if (blurTimes.length > 1) {
|
|
1888
2292
|
const open2 = current.indexOf(">") + 1;
|
|
1889
2293
|
const body2 = current.slice(open2, current.lastIndexOf("</svg>"));
|
|
1890
|
-
const bg2 = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access',
|
|
2294
|
+
const bg2 = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _112 => _112.exec, 'call', _113 => _113(body2), 'optionalAccess', _114 => _114[0]]), () => ( "")) : "";
|
|
1891
2295
|
current = `${current.slice(0, open2)}${bg2}${averagedFrames(scene, blurTimes, svgOptions, prefix)}</svg>`;
|
|
1892
2296
|
}
|
|
1893
2297
|
if (!onionSkin && !motionPaths) return current;
|
|
@@ -1902,14 +2306,14 @@ function motionStageSvg(scene, time, options = {}) {
|
|
|
1902
2306
|
const open = current.indexOf(">") + 1;
|
|
1903
2307
|
const close = current.lastIndexOf("</svg>");
|
|
1904
2308
|
const body = current.slice(open, close);
|
|
1905
|
-
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access',
|
|
2309
|
+
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _115 => _115.exec, 'call', _116 => _116(body), 'optionalAccess', _117 => _117[0]]), () => ( "")) : "";
|
|
1906
2310
|
return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
|
|
1907
2311
|
}
|
|
1908
2312
|
function motionContactSheetSvg(scene, times, options = {}) {
|
|
1909
2313
|
const { columns, labels = true, ...frameOptions } = options;
|
|
1910
|
-
const
|
|
1911
|
-
const cols = Math.max(1, Math.min(
|
|
1912
|
-
const rows = Math.ceil(
|
|
2314
|
+
const n2 = Math.max(1, times.length);
|
|
2315
|
+
const cols = Math.max(1, Math.min(n2, Math.floor(_nullishCoalesce(columns, () => ( Math.ceil(Math.sqrt(n2)))))));
|
|
2316
|
+
const rows = Math.ceil(n2 / cols);
|
|
1913
2317
|
const { width: w, height: h } = scene.artwork;
|
|
1914
2318
|
const gap = Math.round(Math.max(w, h) * 0.04);
|
|
1915
2319
|
const label = labels ? Math.round(Math.max(12, h * 0.08)) : 0;
|
|
@@ -1921,7 +2325,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
|
|
|
1921
2325
|
const x = gap + i % cols * (w + gap);
|
|
1922
2326
|
const y = gap + Math.floor(i / cols) * (h + label + gap);
|
|
1923
2327
|
const frame = motionStageSvg(scene, t, { ...frameOptions, idPrefix: `${prefix}f${i}-` });
|
|
1924
|
-
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access',
|
|
2328
|
+
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _118 => _118.exec, 'call', _119 => _119(frame), 'optionalAccess', _120 => _120[1]]), () => ( `0 0 ${w} ${h}`));
|
|
1925
2329
|
const inner = innerSvg(frame).replace(new RegExp(` id="(?!${`${prefix}f${i}-`.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
|
|
1926
2330
|
const shot = _nullishCoalesce(timeline.shots.find((s) => t >= s.start && t < s.end), () => ( timeline.shots[timeline.shots.length - 1]));
|
|
1927
2331
|
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>` : "";
|
|
@@ -1933,7 +2337,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
|
|
|
1933
2337
|
// src/animation-editor/check.ts
|
|
1934
2338
|
var MOTION_MIN_CHANGE_MS = 120;
|
|
1935
2339
|
var NUMERIC_PARAMS = (node, effectId) => {
|
|
1936
|
-
const effect = _optionalChain([node, 'access',
|
|
2340
|
+
const effect = _optionalChain([node, 'access', _121 => _121.effects, 'optionalAccess', _122 => _122.find, 'call', _123 => _123((e) => e.id === effectId)]);
|
|
1937
2341
|
if (!effect) return null;
|
|
1938
2342
|
return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
|
|
1939
2343
|
};
|
|
@@ -1976,97 +2380,97 @@ function checkMotionScene(scene) {
|
|
|
1976
2380
|
const ids = [...nodes.keys()];
|
|
1977
2381
|
const timeline = compileMotionScene(scene);
|
|
1978
2382
|
const artAspect = scene.artwork.width / scene.artwork.height;
|
|
1979
|
-
if (!scene.shots.length) issues.push(
|
|
2383
|
+
if (!scene.shots.length) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "no-shots", "The scene has no shots yet; add one with a list of commands."));
|
|
1980
2384
|
const seen = /* @__PURE__ */ new Set();
|
|
1981
2385
|
for (const shot of scene.shots) {
|
|
1982
|
-
if (seen.has(shot.id)) issues.push(
|
|
2386
|
+
if (seen.has(shot.id)) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "duplicate-shot-id", `Shot id "${shot.id}" is used twice; give each shot its own id.`, { shot: shot.id }));
|
|
1983
2387
|
seen.add(shot.id);
|
|
1984
2388
|
}
|
|
1985
2389
|
const known = (id, code, what, where) => {
|
|
1986
2390
|
if (nodes.has(id)) return true;
|
|
1987
|
-
issues.push(
|
|
2391
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, code, `There is no ${what} ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, id, ids)} in the artwork${ids.length ? "" : " (it has no nodes yet)"}.`, { ...where, ids: [id] }));
|
|
1988
2392
|
return false;
|
|
1989
2393
|
};
|
|
1990
2394
|
scene.shots.forEach((shot, shotIndex2) => {
|
|
1991
2395
|
if (shot.camera && "frame" in shot.camera && typeof shot.camera.frame === "string") known(shot.camera.frame, "unknown-frame", "node to frame", { shot: shot.id });
|
|
1992
2396
|
else if (shot.camera && motionCameraFramed(shot.camera)) {
|
|
1993
2397
|
const c = shot.camera;
|
|
1994
|
-
if (!(c.width > 0 && c.height > 0)) issues.push(
|
|
2398
|
+
if (!(c.width > 0 && c.height > 0)) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "invalid-camera", `The camera needs a positive width and height (got ${c.width} \xD7 ${c.height}).`, { shot: shot.id }));
|
|
1995
2399
|
else if (Math.abs(c.width / c.height / artAspect - 1) > 0.02)
|
|
1996
|
-
issues.push(
|
|
2400
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "camera-aspect", `The camera is ${c.width} \xD7 ${c.height}, a different shape from the ${scene.artwork.width} \xD7 ${scene.artwork.height} artwork, so it shows bands at the sides; frame a node instead to match.`, { shot: shot.id }));
|
|
1997
2401
|
}
|
|
1998
|
-
if (shotIndex2 === 0 && _optionalChain([shot, 'access',
|
|
1999
|
-
if (!shot.run.length && !shot.camera && shotIndex2 > 0) issues.push(
|
|
2402
|
+
if (shotIndex2 === 0 && _optionalChain([shot, 'access', _124 => _124.camera, 'optionalAccess', _125 => _125.in]) !== void 0) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "camera-move-first-shot", 'The first shot cuts to its framing (there is none before it to move from), so its camera "in" does not play; put the move on the next shot, or use a "during" move here.', { shot: shot.id }));
|
|
2403
|
+
if (!shot.run.length && !shot.camera && shotIndex2 > 0) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "empty-shot", "This shot only holds; add commands or a camera move, or remove it.", { shot: shot.id }));
|
|
2000
2404
|
shot.run.forEach((command3, i) => {
|
|
2001
2405
|
const where = { shot: shot.id, command: i };
|
|
2002
2406
|
if (command3.type === "wait") return;
|
|
2003
2407
|
const targets = command3.targets.filter((id) => known(id, "unknown-target", "node", where));
|
|
2004
2408
|
const timing = timeline.commands.find((c) => c.shot === shot.id && c.command === i);
|
|
2005
2409
|
if (timing && timing.duration > 0 && timing.duration < MOTION_MIN_CHANGE_MS)
|
|
2006
|
-
issues.push(
|
|
2410
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "too-fast", `This ${command3.type} lasts ${timing.duration} ms, too quick to follow; make it at least ${MOTION_MIN_CHANGE_MS} ms.`, { ...where, measured: timing.duration, needed: MOTION_MIN_CHANGE_MS, unit: "ms", ids: targets }));
|
|
2007
2411
|
if (command3.duration !== void 0 && command3.ease !== void 0) {
|
|
2008
2412
|
const ease = _chunkDWJJI6RTcjs.resolveEasing.call(void 0, command3.ease);
|
|
2009
2413
|
if (ease !== "hold" && ease.type === "spring") {
|
|
2010
2414
|
const settle = _chunkDWJJI6RTcjs.springSettleMs.call(void 0, ease);
|
|
2011
2415
|
if (command3.duration < settle * 0.9)
|
|
2012
|
-
issues.push(
|
|
2416
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "spring-cut-short", `This ${command3.type}'s spring takes ${settle} ms to settle but lasts ${command3.duration} ms, so it jumps to its end; leave "duration" out (the spring sets it) or make it at least ${settle} ms.`, { ...where, measured: command3.duration, needed: settle, unit: "ms", ids: targets }));
|
|
2013
2417
|
}
|
|
2014
2418
|
}
|
|
2015
2419
|
if (command3.type === "follow" && known(command3.path, "unknown-path", "path", where) && nodes.get(command3.path).node.type !== "path")
|
|
2016
|
-
issues.push(
|
|
2420
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "not-a-path", `"${command3.path}" is a group; follow a single path node.`, { ...where, ids: [command3.path] }));
|
|
2017
2421
|
if (command3.type === "morph") known(command3.into, "unknown-shape", "shape", where);
|
|
2018
2422
|
if (command3.type !== "play" && command3.split) {
|
|
2019
2423
|
for (const id of targets)
|
|
2020
2424
|
if (!motionTextLayout(nodes, id))
|
|
2021
|
-
issues.push(
|
|
2425
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "split-not-text", `"${id}" is not a group of letter paths, so "split": "${command3.split}" animates it as a whole; convert the text to outlines and group the letters (get_text_layout shows how they read).`, { ...where, ids: [id] }));
|
|
2022
2426
|
}
|
|
2023
|
-
if (command3.type === "play" && !_optionalChain([scene, 'access',
|
|
2024
|
-
issues.push(
|
|
2427
|
+
if (command3.type === "play" && !_optionalChain([scene, 'access', _126 => _126.clips, 'optionalAccess', _127 => _127[command3.clip]]))
|
|
2428
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "unknown-clip", `There is no clip ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, command3.clip, Object.keys(_nullishCoalesce(scene.clips, () => ( {}))))}; define it with set_animation_clip.`, where));
|
|
2025
2429
|
if (command3.type === "match" && known(command3.into, "unknown-shape", "group", where)) {
|
|
2026
2430
|
const into = nodes.get(command3.into);
|
|
2027
2431
|
for (const id of targets) {
|
|
2028
2432
|
const entry = nodes.get(id);
|
|
2029
2433
|
if (id === command3.into || into.ancestors.includes(id) || entry.ancestors.includes(command3.into)) {
|
|
2030
|
-
issues.push(
|
|
2434
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "match-self", `"${id}" cannot match "${command3.into}": one is the other or holds it. Match two separate groups (the second usually hidden).`, { ...where, ids: [id, command3.into] }));
|
|
2031
2435
|
continue;
|
|
2032
2436
|
}
|
|
2033
2437
|
const m = matchMotionNodes(entry.node, into.node);
|
|
2034
2438
|
if (m.unpairedInto.length)
|
|
2035
|
-
issues.push(
|
|
2439
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "match-unpaired", `${m.unpairedInto.map((x) => `"${x}"`).join(", ")} in "${command3.into}" ${m.unpairedInto.length > 1 ? "have" : "has"} no partner in "${id}", so ${m.unpairedInto.length > 1 ? "they do" : "it does"} not appear; add a part with the same name or id to "${id}" (it can start hidden or tiny).`, { ...where, ids: m.unpairedInto }));
|
|
2036
2440
|
}
|
|
2037
2441
|
}
|
|
2038
2442
|
const style = command3.type === "enter" || command3.type === "exit" ? command3.style : void 0;
|
|
2039
2443
|
if (style === "wipe" || style === "iris" || style === "split") {
|
|
2040
2444
|
for (const id of targets)
|
|
2041
2445
|
if (!motionRevealPadding(nodes.get(id)))
|
|
2042
|
-
issues.push(
|
|
2446
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "reveal-no-box", `"${id}" has no width or height (a straight line), so a ${style} cannot clip it and it fades instead; use style "${command3.type === "enter" ? "draw" : "undraw"}" for a line.`, { ...where, ids: [id] }));
|
|
2043
2447
|
}
|
|
2044
2448
|
if (command3.type === "style") {
|
|
2045
2449
|
for (const key of ["fill", "stroke"]) {
|
|
2046
2450
|
const color = command3[key];
|
|
2047
2451
|
if (color === void 0) continue;
|
|
2048
2452
|
if (_chunkA6QWKBJPcjs.normalizeTokenColor.call(void 0, color) === null) {
|
|
2049
|
-
issues.push(
|
|
2453
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "invalid-color", `${key} "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
|
|
2050
2454
|
continue;
|
|
2051
2455
|
}
|
|
2052
2456
|
for (const id of targets) {
|
|
2053
2457
|
const node = nodes.get(id).node;
|
|
2054
2458
|
const paths = node.type === "path" ? [node] : _chunkBQE3Y6ZOcjs.collectPathNodes.call(void 0, node);
|
|
2055
2459
|
if (paths.some((p) => p[key] !== void 0 && p[key] !== null && typeof p[key] !== "string"))
|
|
2056
|
-
issues.push(
|
|
2460
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "paint-not-color", `"${id}" has a gradient ${key}; it switches to ${color} at the end instead of blending.`, { ...where, ids: [id] }));
|
|
2057
2461
|
}
|
|
2058
2462
|
}
|
|
2059
2463
|
}
|
|
2060
2464
|
if (command3.type === "color-pulse") {
|
|
2061
2465
|
const key = _nullishCoalesce(command3.paint, () => ( "fill"));
|
|
2062
2466
|
const color = _nullishCoalesce(command3.color, () => ( "#f59e0b"));
|
|
2063
|
-
if (_chunkA6QWKBJPcjs.normalizeTokenColor.call(void 0, color) === null) issues.push(
|
|
2467
|
+
if (_chunkA6QWKBJPcjs.normalizeTokenColor.call(void 0, color) === null) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "invalid-color", `color "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
|
|
2064
2468
|
else
|
|
2065
2469
|
for (const id of targets) {
|
|
2066
2470
|
const node = nodes.get(id).node;
|
|
2067
2471
|
const paths = node.type === "path" ? [node] : _chunkBQE3Y6ZOcjs.collectPathNodes.call(void 0, node);
|
|
2068
2472
|
if (paths.some((p) => typeof p[key] !== "string"))
|
|
2069
|
-
issues.push(
|
|
2473
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "paint-not-color", `"${id}" has a gradient or no ${key}, so a colour pulse cannot tint it; give it a solid ${key} or pulse the ${key === "fill" ? "stroke" : "fill"}.`, { ...where, ids: [id] }));
|
|
2070
2474
|
}
|
|
2071
2475
|
}
|
|
2072
2476
|
if (command3.type === "effect") {
|
|
@@ -2075,9 +2479,9 @@ function checkMotionScene(scene) {
|
|
|
2075
2479
|
const params = NUMERIC_PARAMS(node, command3.effect);
|
|
2076
2480
|
const effects = (_nullishCoalesce(node.effects, () => ( []))).map((e) => e.id);
|
|
2077
2481
|
if (!params)
|
|
2078
|
-
issues.push(
|
|
2482
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "unknown-effect", `"${id}" has no effect ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, command3.effect, effects)}${effects.length ? `; its effects are ${effects.map((e) => `"${e}"`).join(", ")}` : "; it has no live effects"}.`, { ...where, ids: [id] }));
|
|
2079
2483
|
else if (!params.includes(command3.param))
|
|
2080
|
-
issues.push(
|
|
2484
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "unknown-effect-param", `Effect "${command3.effect}" has no numeric parameter ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, command3.param, params)}; use one of ${params.join(", ")}.`, { ...where, ids: [id] }));
|
|
2081
2485
|
}
|
|
2082
2486
|
}
|
|
2083
2487
|
if (timing) {
|
|
@@ -2086,10 +2490,10 @@ function checkMotionScene(scene) {
|
|
|
2086
2490
|
const before = Math.max(0, timing.start - 0.5);
|
|
2087
2491
|
const visible = timing.start > 0 ? visibleAt(timeline, id, before, node) : node.visible !== false;
|
|
2088
2492
|
if (command3.type === "enter" && visible && timing.start > 0)
|
|
2089
|
-
issues.push(
|
|
2493
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "enter-visible", `"${id}" is already showing when it enters, so it blinks out first; remove the enter or exit it earlier.`, { ...where, ids: [id] }));
|
|
2090
2494
|
const probe = command3.type === "exit" ? timing.start + 0.5 : (timing.start + timing.end) / 2;
|
|
2091
2495
|
if (command3.type !== "enter" && command3.type !== "draw" && !visibleAt(timeline, id, probe, node))
|
|
2092
|
-
issues.push(
|
|
2496
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "exit-hidden", `"${id}" is hidden when this ${command3.type} starts, so it is not seen; enter it first.`, { ...where, ids: [id] }));
|
|
2093
2497
|
}
|
|
2094
2498
|
}
|
|
2095
2499
|
});
|
|
@@ -2097,10 +2501,10 @@ function checkMotionScene(scene) {
|
|
|
2097
2501
|
const drivers = _nullishCoalesce(scene.drivers, () => ( []));
|
|
2098
2502
|
drivers.forEach((d, i) => {
|
|
2099
2503
|
for (const id of [d.target, d.source.node])
|
|
2100
|
-
if (!nodes.has(id)) issues.push(
|
|
2504
|
+
if (!nodes.has(id)) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "unknown-target", `Driver ${i + 1} names ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, id, [...nodes.keys()])}, which the artwork does not have.`, { ids: [id] }));
|
|
2101
2505
|
});
|
|
2102
2506
|
{
|
|
2103
|
-
const key = (
|
|
2507
|
+
const key = (n2, p) => `${n2}.${p}`;
|
|
2104
2508
|
const edges = /* @__PURE__ */ new Map();
|
|
2105
2509
|
for (const d of drivers) edges.set(key(d.target, d.property), [..._nullishCoalesce(edges.get(key(d.target, d.property)), () => ( [])), key(d.source.node, d.source.property)]);
|
|
2106
2510
|
const state = /* @__PURE__ */ new Map();
|
|
@@ -2109,25 +2513,25 @@ function checkMotionScene(scene) {
|
|
|
2109
2513
|
if (state.get(k) === 2) return false;
|
|
2110
2514
|
if (state.get(k) === 1) return loop.push(...trail.slice(trail.indexOf(k)), k), true;
|
|
2111
2515
|
state.set(k, 1);
|
|
2112
|
-
for (const
|
|
2516
|
+
for (const n2 of _nullishCoalesce(edges.get(k), () => ( []))) if (visit(n2, [...trail, k])) return true;
|
|
2113
2517
|
state.set(k, 2);
|
|
2114
2518
|
return false;
|
|
2115
2519
|
};
|
|
2116
2520
|
for (const k of edges.keys()) if (visit(k, [])) break;
|
|
2117
|
-
if (loop.length) issues.push(
|
|
2521
|
+
if (loop.length) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "driver-cycle", `Drivers follow each other round in a loop (${loop.join(" \u2190 ")}); remove one of them.`, { ids: [...new Set(loop.map((k) => k.split(".")[0]))] }));
|
|
2118
2522
|
}
|
|
2119
2523
|
for (const [name, clip] of Object.entries(_nullishCoalesce(scene.clips, () => ( {}))))
|
|
2120
2524
|
for (const command3 of clip.run)
|
|
2121
2525
|
if (command3.type !== "wait") {
|
|
2122
2526
|
for (const id of command3.targets)
|
|
2123
|
-
if (id !== MOTION_CLIP_TARGET && !nodes.has(id)) issues.push(
|
|
2527
|
+
if (id !== MOTION_CLIP_TARGET && !nodes.has(id)) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "unknown-target", `Clip "${name}" names ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, id, [...nodes.keys()])}, which the artwork does not have; use "$" for the node the clip is played on.`, { ids: [id] }));
|
|
2124
2528
|
}
|
|
2125
2529
|
if (scene.trigger) {
|
|
2126
|
-
if ((_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") issues.push(
|
|
2530
|
+
if ((_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "trigger-loop", `The scene plays on ${scene.trigger}, so its "${scene.loop}" loop does not apply; set loop to "none" or remove the trigger.`, {}));
|
|
2127
2531
|
if (scene.trigger === "click") {
|
|
2128
|
-
if (scene.shots.length === 1) issues.push(
|
|
2532
|
+
if (scene.shots.length === 1) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "click-one-shot", "The scene plays on click but has one shot, so every click replays it from the start; split it into shots (each click plays the next one).", { shot: scene.shots[0].id }));
|
|
2129
2533
|
scene.shots.forEach((shot, i) => {
|
|
2130
|
-
if (i > 0 && shot.at) issues.push(
|
|
2534
|
+
if (i > 0 && shot.at) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "click-cue", `Shot "${shot.id}" is cued, but on click a shot starts when it is clicked to; remove its "at" or the trigger.`, { shot: shot.id }));
|
|
2131
2535
|
});
|
|
2132
2536
|
}
|
|
2133
2537
|
}
|
|
@@ -2135,11 +2539,11 @@ function checkMotionScene(scene) {
|
|
|
2135
2539
|
if (!shot.at) return;
|
|
2136
2540
|
const timing = timeline.shots[i];
|
|
2137
2541
|
if (timing.cue === void 0) {
|
|
2138
|
-
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',
|
|
2139
|
-
issues.push(
|
|
2542
|
+
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', _128 => _128.narration, 'optionalAccess', _129 => _129.words, 'access', _130 => _130.length]), () => ( 0))} words (indexes from 0)`;
|
|
2543
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
|
|
2140
2544
|
} else if (timing.missedBy !== void 0) {
|
|
2141
2545
|
const late = Math.round(timing.missedBy);
|
|
2142
|
-
issues.push(
|
|
2546
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "cue-missed", `Shot "${shot.id}" is cued at ${Math.round(timing.cue)} ms but starts ${late} ms late, because the shot before runs until ${Math.round(timing.start)} ms; shorten that shot (its hold, durations or speed) or cue this one later.`, { shot: shot.id, measured: late, needed: 0, unit: "ms" }));
|
|
2143
2547
|
}
|
|
2144
2548
|
});
|
|
2145
2549
|
for (const [key, track] of timeline.tracks) {
|
|
@@ -2151,7 +2555,7 @@ function checkMotionScene(scene) {
|
|
|
2151
2555
|
const property = key.split("\0")[1];
|
|
2152
2556
|
if (!a.node) continue;
|
|
2153
2557
|
issues.push(
|
|
2154
|
-
|
|
2558
|
+
_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "overlap", `"${a.node}" ${property} is changed by two commands at once (shot "${a.shot}" command ${a.command + 1} and shot "${b.shot}" command ${b.command + 1}); the later one takes over. Start it after the first ends, or use with: "after".`, {
|
|
2155
2559
|
shot: b.shot,
|
|
2156
2560
|
command: b.command,
|
|
2157
2561
|
ids: [a.node]
|
|
@@ -2168,26 +2572,26 @@ function checkMotionScene(scene) {
|
|
|
2168
2572
|
const cam = frame.camera;
|
|
2169
2573
|
const docIndex = indexMotionNodes(frame.document.nodes);
|
|
2170
2574
|
for (const id of command3.targets) {
|
|
2171
|
-
const b = _optionalChain([docIndex, 'access',
|
|
2575
|
+
const b = _optionalChain([docIndex, 'access', _131 => _131.get, 'call', _132 => _132(id), 'optionalAccess', _133 => _133.bounds]);
|
|
2172
2576
|
if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
|
|
2173
2577
|
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;
|
|
2174
2578
|
if (outside) {
|
|
2175
2579
|
reported.add(id);
|
|
2176
|
-
issues.push(
|
|
2580
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "out-of-frame", `"${id}" is outside the camera when this ${command3.type} ends, so it is not seen; move it into frame or move the camera.`, { shot: timing.shot, command: timing.command, ids: [id] }));
|
|
2177
2581
|
}
|
|
2178
2582
|
}
|
|
2179
2583
|
}
|
|
2180
2584
|
if (scene.controls) {
|
|
2181
2585
|
for (const control of scene.controls) {
|
|
2182
2586
|
if (!usesColor(scene, control.default))
|
|
2183
|
-
issues.push(
|
|
2587
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "unknown-control-color", `Control "${control.name}" stands for ${control.default}, which the scene never uses; set its default to a colour in the artwork.`));
|
|
2184
2588
|
}
|
|
2185
2589
|
}
|
|
2186
2590
|
if (scene.target && scene.shots.length) {
|
|
2187
2591
|
const seconds = Math.round(timeline.duration / 100) / 10;
|
|
2188
2592
|
const [min, max] = scene.target;
|
|
2189
|
-
if (seconds > max) issues.push(
|
|
2190
|
-
if (seconds < min) issues.push(
|
|
2593
|
+
if (seconds > max) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "scene-too-long", `The scene runs ${seconds} s, past its ${max} s target; shorten holds or durations, or fit it (fit_animation).`, { measured: seconds, needed: max, unit: "s" }));
|
|
2594
|
+
if (seconds < min) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "scene-too-short", `The scene runs ${seconds} s, under its ${min} s target; hold longer, add shots, or fit it (fit_animation).`, { measured: seconds, needed: min, unit: "s" }));
|
|
2191
2595
|
}
|
|
2192
2596
|
return issues;
|
|
2193
2597
|
}
|
|
@@ -2216,7 +2620,7 @@ var fail = (message) => {
|
|
|
2216
2620
|
};
|
|
2217
2621
|
function shotIndex(scene, id) {
|
|
2218
2622
|
const i = scene.shots.findIndex((s) => s.id === id);
|
|
2219
|
-
if (i < 0) fail(`There is no shot ${
|
|
2623
|
+
if (i < 0) fail(`There is no shot ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, id, scene.shots.map((s) => s.id))}; the shots are ${scene.shots.map((s) => `"${s.id}"`).join(", ") || "none yet"}.`);
|
|
2220
2624
|
return i;
|
|
2221
2625
|
}
|
|
2222
2626
|
function position(at, length, what) {
|
|
@@ -2228,9 +2632,9 @@ var replaceShot = (scene, index, shot) => ({ ...scene, shots: scene.shots.map((s
|
|
|
2228
2632
|
function freshShotId(scene, base = "shot") {
|
|
2229
2633
|
const used = new Set(scene.shots.map((s) => s.id));
|
|
2230
2634
|
if (!used.has(base)) return base;
|
|
2231
|
-
let
|
|
2232
|
-
while (used.has(`${base}-${
|
|
2233
|
-
return `${base}-${
|
|
2635
|
+
let n2 = 2;
|
|
2636
|
+
while (used.has(`${base}-${n2}`)) n2++;
|
|
2637
|
+
return `${base}-${n2}`;
|
|
2234
2638
|
}
|
|
2235
2639
|
function applyOne(scene, edit) {
|
|
2236
2640
|
switch (edit.op) {
|
|
@@ -2274,7 +2678,7 @@ function applyOne(scene, edit) {
|
|
|
2274
2678
|
if (typeof edit.name !== "string" || !edit.name) fail('Give the clip a "name".');
|
|
2275
2679
|
const clips = { ..._nullishCoalesce(scene.clips, () => ( {})) };
|
|
2276
2680
|
if (edit.clip === null) {
|
|
2277
|
-
if (!clips[edit.name]) fail(`There is no clip ${
|
|
2681
|
+
if (!clips[edit.name]) fail(`There is no clip ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, edit.name, Object.keys(clips))} to delete.`);
|
|
2278
2682
|
const playing = scene.shots.filter((s) => s.run.some((c) => c.type === "play" && c.clip === edit.name)).map((s) => `"${s.id}"`);
|
|
2279
2683
|
if (playing.length) fail(`Clip "${edit.name}" is played in shot${playing.length > 1 ? "s" : ""} ${playing.join(", ")}; remove those play commands first.`);
|
|
2280
2684
|
delete clips[edit.name];
|
|
@@ -2380,7 +2784,7 @@ function applyOne(scene, edit) {
|
|
|
2380
2784
|
const names = new Set(edit.controls.map((c) => c.name));
|
|
2381
2785
|
for (const preset2 of _nullishCoalesce(next.presets, () => ( [])))
|
|
2382
2786
|
for (const key of Object.keys(preset2.values))
|
|
2383
|
-
if (!names.has(key)) fail(`Preset "${preset2.name}" sets ${
|
|
2787
|
+
if (!names.has(key)) fail(`Preset "${preset2.name}" sets ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, key, names)}, which is not a control.`);
|
|
2384
2788
|
return next;
|
|
2385
2789
|
}
|
|
2386
2790
|
case "replace_scene":
|
|
@@ -2388,11 +2792,11 @@ function applyOne(scene, edit) {
|
|
|
2388
2792
|
}
|
|
2389
2793
|
}
|
|
2390
2794
|
function errorKeys(issues) {
|
|
2391
|
-
return new Set(issues.filter((i) => i.severity === "error").map(
|
|
2795
|
+
return new Set(issues.filter((i) => i.severity === "error").map(_chunkDGWOGQJ5cjs.motionIssueKey));
|
|
2392
2796
|
}
|
|
2393
2797
|
function editHints(before, after) {
|
|
2394
|
-
const old = new Set(before.map(
|
|
2395
|
-
return after.filter((i) => i.code === "overlap" && !old.has(
|
|
2798
|
+
const old = new Set(before.map(_chunkDGWOGQJ5cjs.motionIssueKey));
|
|
2799
|
+
return after.filter((i) => i.code === "overlap" && !old.has(_chunkDGWOGQJ5cjs.motionIssueKey.call(void 0, i))).map(_chunkDGWOGQJ5cjs.motionIssueLine);
|
|
2396
2800
|
}
|
|
2397
2801
|
function applyMotionEdits(scene, edits) {
|
|
2398
2802
|
const list = Array.isArray(edits) ? edits : [edits];
|
|
@@ -2400,9 +2804,9 @@ function applyMotionEdits(scene, edits) {
|
|
|
2400
2804
|
let next = scene;
|
|
2401
2805
|
for (let i = 0; i < list.length; i++) {
|
|
2402
2806
|
const edit = list[i];
|
|
2403
|
-
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess',
|
|
2807
|
+
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _134 => _134.op])}): ` : "";
|
|
2404
2808
|
if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
|
|
2405
|
-
return { ok: false, error: `${prefix}Unknown op ${
|
|
2809
|
+
return { ok: false, error: `${prefix}Unknown op ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, String(_optionalChain([edit, 'optionalAccess', _135 => _135.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
|
|
2406
2810
|
try {
|
|
2407
2811
|
next = applyOne(next, edit);
|
|
2408
2812
|
} catch (error) {
|
|
@@ -2414,8 +2818,8 @@ function applyMotionEdits(scene, edits) {
|
|
|
2414
2818
|
}
|
|
2415
2819
|
const issues = checkMotionScene(next);
|
|
2416
2820
|
const had = errorKeys(before);
|
|
2417
|
-
const added = issues.filter((i) => i.severity === "error" && !had.has(
|
|
2418
|
-
if (added.length) return { ok: false, error: `Nothing was changed: ${added.map(
|
|
2821
|
+
const added = issues.filter((i) => i.severity === "error" && !had.has(_chunkDGWOGQJ5cjs.motionIssueKey.call(void 0, i)));
|
|
2822
|
+
if (added.length) return { ok: false, error: `Nothing was changed: ${added.map(_chunkDGWOGQJ5cjs.motionIssueLine).join(" ")}` };
|
|
2419
2823
|
return { ok: true, scene: next, issues, hints: editHints(before, issues) };
|
|
2420
2824
|
}
|
|
2421
2825
|
var REF = /^\$(\d+|last)((?:\.[A-Za-z_]\w*|\[\d+\])+)$/;
|
|
@@ -2424,21 +2828,21 @@ function resolveMotionEditRefs(scene, edits) {
|
|
|
2424
2828
|
const resolved = [];
|
|
2425
2829
|
let next = scene;
|
|
2426
2830
|
for (let i = 0; i < edits.length; i++) {
|
|
2427
|
-
const where = `op ${i + 1} (${_optionalChain([edits, 'access',
|
|
2831
|
+
const where = `op ${i + 1} (${_optionalChain([edits, 'access', _136 => _136[i], 'optionalAccess', _137 => _137.op])})`;
|
|
2428
2832
|
let problem = null;
|
|
2429
2833
|
const walk = (v) => {
|
|
2430
2834
|
if (typeof v === "string") {
|
|
2431
2835
|
if (v.startsWith("$$")) return v.slice(1);
|
|
2432
2836
|
const m = REF.exec(v);
|
|
2433
2837
|
if (!m) return v;
|
|
2434
|
-
const
|
|
2435
|
-
if (!(
|
|
2436
|
-
problem = `${where}: "${v}" refers to op ${
|
|
2838
|
+
const n2 = m[1] === "last" ? i - 1 : Number(m[1]);
|
|
2839
|
+
if (!(n2 >= 0 && n2 < i)) {
|
|
2840
|
+
problem = `${where}: "${v}" refers to op ${n2 + 1}, but only ops before this one (1 to ${i}) can be referred to.`;
|
|
2437
2841
|
return v;
|
|
2438
2842
|
}
|
|
2439
|
-
let value = outcomes[
|
|
2843
|
+
let value = outcomes[n2];
|
|
2440
2844
|
for (const part of _nullishCoalesce(m[2].match(/\.[A-Za-z_]\w*|\[\d+\]/g), () => ( []))) value = value == null ? void 0 : value[part.startsWith(".") ? part.slice(1) : part.slice(1, -1)];
|
|
2441
|
-
if (value === void 0) problem = `${where}: "${v}" has no value; op ${
|
|
2845
|
+
if (value === void 0) problem = `${where}: "${v}" has no value; op ${n2 + 1} made ${JSON.stringify(outcomes[n2])}.`;
|
|
2442
2846
|
return value;
|
|
2443
2847
|
}
|
|
2444
2848
|
if (Array.isArray(v)) return v.map(walk);
|
|
@@ -2457,9 +2861,9 @@ function resolveMotionEditRefs(scene, edits) {
|
|
|
2457
2861
|
resolved.push(edit);
|
|
2458
2862
|
const out = { op: edit.op };
|
|
2459
2863
|
if (edit.op === "insert_shots") out.shots = edit.shots.map((s) => s.id);
|
|
2460
|
-
if ("shot" in edit && typeof edit.shot === "string") out.shot = edit.op === "update_shot" && _optionalChain([edit, 'access',
|
|
2864
|
+
if ("shot" in edit && typeof edit.shot === "string") out.shot = edit.op === "update_shot" && _optionalChain([edit, 'access', _138 => _138.set, 'optionalAccess', _139 => _139.id]) ? edit.set.id : edit.shot;
|
|
2461
2865
|
if (edit.op === "add_commands") {
|
|
2462
|
-
const at = _nullishCoalesce(_nullishCoalesce(edit.at, () => ( _optionalChain([before, 'access',
|
|
2866
|
+
const at = _nullishCoalesce(_nullishCoalesce(edit.at, () => ( _optionalChain([before, 'access', _140 => _140.shots, 'access', _141 => _141.find, 'call', _142 => _142((s) => s.id === edit.shot), 'optionalAccess', _143 => _143.run, 'access', _144 => _144.length]))), () => ( 0));
|
|
2463
2867
|
out.indexes = edit.commands.map((_, k) => at + k);
|
|
2464
2868
|
}
|
|
2465
2869
|
if (edit.op === "move_command") out.indexes = [edit.to];
|
|
@@ -2478,7 +2882,7 @@ function fitMotionScene(scene, ms2, options = {}) {
|
|
|
2478
2882
|
if (!(Number.isFinite(ms2) && ms2 > 0)) throw new Error("Give the length to fit as a number of milliseconds above 0.");
|
|
2479
2883
|
const ids = scene.shots.map((s) => s.id);
|
|
2480
2884
|
const keep = new Set(_nullishCoalesce(options.keep, () => ( [])));
|
|
2481
|
-
for (const id of keep) if (!ids.includes(id)) throw new Error(`There is no shot ${
|
|
2885
|
+
for (const id of keep) if (!ids.includes(id)) throw new Error(`There is no shot ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, id, ids)} to keep.`);
|
|
2482
2886
|
const timeline = compileMotionScene(scene);
|
|
2483
2887
|
let kept = 0;
|
|
2484
2888
|
let rest = 0;
|
|
@@ -2506,7 +2910,7 @@ var COLOR_GAP = 80;
|
|
|
2506
2910
|
var MAX_VIA = 64;
|
|
2507
2911
|
function motionNodePose(scene, id, time) {
|
|
2508
2912
|
const entry = indexMotionNodes(scene.artwork.nodes).get(id);
|
|
2509
|
-
if (!entry) throw new Error(`There is no element ${
|
|
2913
|
+
if (!entry) throw new Error(`There is no element ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, id, [...indexMotionNodes(scene.artwork.nodes).keys()])} in the artwork.`);
|
|
2510
2914
|
const timeline = compileMotionScene(scene);
|
|
2511
2915
|
const drawn = indexMotionNodes(motionFrameAt(scene, time).document.nodes).get(id);
|
|
2512
2916
|
const centre = _chunkBQE3Y6ZOcjs.applyMatrix.call(void 0, entry.parentWorld, { x: entry.center.x + motionPropertyValue(timeline, id, "x", time), y: entry.center.y + motionPropertyValue(timeline, id, "y", time) });
|
|
@@ -2524,15 +2928,15 @@ function motionNodePose(scene, id, time) {
|
|
|
2524
2928
|
...typeof fill === "string" && fill !== "transparent" ? { fill } : {},
|
|
2525
2929
|
...typeof stroke === "string" && stroke !== "transparent" ? { stroke } : {},
|
|
2526
2930
|
...typeof width === "number" ? { strokeWidth: width } : {},
|
|
2527
|
-
bounds: _nullishCoalesce(_optionalChain([drawn, 'optionalAccess',
|
|
2931
|
+
bounds: _nullishCoalesce(_optionalChain([drawn, 'optionalAccess', _145 => _145.bounds]), () => ( null))
|
|
2528
2932
|
};
|
|
2529
2933
|
}
|
|
2530
2934
|
function simplifyTimedSamples(times, values, tol) {
|
|
2531
|
-
const
|
|
2532
|
-
if (
|
|
2533
|
-
const keep = new Uint8Array(
|
|
2534
|
-
keep[0] = keep[
|
|
2535
|
-
const stack = [[0,
|
|
2935
|
+
const n2 = times.length;
|
|
2936
|
+
if (n2 <= 2) return [...Array(n2).keys()];
|
|
2937
|
+
const keep = new Uint8Array(n2);
|
|
2938
|
+
keep[0] = keep[n2 - 1] = 1;
|
|
2939
|
+
const stack = [[0, n2 - 1]];
|
|
2536
2940
|
while (stack.length) {
|
|
2537
2941
|
const [a, b] = stack.pop();
|
|
2538
2942
|
let worst = -1;
|
|
@@ -2559,8 +2963,8 @@ function simplifyTimedSamples(times, values, tol) {
|
|
|
2559
2963
|
keep.forEach((k, i) => k && out.push(i));
|
|
2560
2964
|
return out;
|
|
2561
2965
|
}
|
|
2562
|
-
var round2 = (
|
|
2563
|
-
var ms = (
|
|
2966
|
+
var round2 = (n2, places = 2) => Math.round(n2 * 10 ** places) / 10 ** places || 0;
|
|
2967
|
+
var ms = (n2) => Math.max(0, Math.round(n2));
|
|
2564
2968
|
function motionTakeProblems(scene, take) {
|
|
2565
2969
|
const problems = [];
|
|
2566
2970
|
const nodes = indexMotionNodes(scene.artwork.nodes);
|
|
@@ -2569,7 +2973,7 @@ function motionTakeProblems(scene, take) {
|
|
|
2569
2973
|
take.samples.forEach((s, i) => {
|
|
2570
2974
|
const where = `Sample ${i + 1}`;
|
|
2571
2975
|
if (!s || typeof s !== "object") return problems.push(`${where} must be an object.`);
|
|
2572
|
-
if (typeof s.node !== "string" || !nodes.has(s.node)) problems.push(`${where}: the artwork has no element ${
|
|
2976
|
+
if (typeof s.node !== "string" || !nodes.has(s.node)) problems.push(`${where}: the artwork has no element ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, String(s.node), [...nodes.keys()])}; get_animation lists the element ids.`);
|
|
2573
2977
|
if (!num2(s.t) || s.t < 0) problems.push(`${where}: "t" must be ms from the start of the take, \u2265 0.`);
|
|
2574
2978
|
if (s.x === void 0 !== (s.y === void 0)) problems.push(`${where}: give "x" and "y" together (the centre, document units).`);
|
|
2575
2979
|
for (const k of ["x", "y", "scaleX", "scaleY", "rotation", "opacity", "strokeWidth"]) if (s[k] !== void 0 && !num2(s[k])) problems.push(`${where}: "${k}" must be a number.`);
|
|
@@ -2648,7 +3052,7 @@ function channelCommands(node, channel, pose, samples, tol, kept) {
|
|
|
2648
3052
|
const via = [];
|
|
2649
3053
|
for (const k of keep.slice(1, -1)) {
|
|
2650
3054
|
const f = round2((list[k].t - first.t) / span, 6);
|
|
2651
|
-
if (f > (_nullishCoalesce(_optionalChain([via, 'access',
|
|
3055
|
+
if (f > (_nullishCoalesce(_optionalChain([via, 'access', _146 => _146.at, 'call', _147 => _147(-1), 'optionalAccess', _148 => _148.f]), () => ( 0))) && f < 1) via.push({ s: list[k], f });
|
|
2652
3056
|
}
|
|
2653
3057
|
const extra = via.length ? { via: via.map(({ s }) => ({ x: round2(s.v[0]), y: round2(s.v[1]) })), times: via.map(({ f }) => f) } : {};
|
|
2654
3058
|
out.push({ start: first.t, command: make(end.v, span, "linear", extra) });
|
|
@@ -2701,10 +3105,10 @@ function motionTakeShot(scene, take, options = {}) {
|
|
|
2701
3105
|
if (!run.length) Object.assign(shot, { run: [{ type: "wait", duration: ms(Math.max(1, length)) }], hold: 0 });
|
|
2702
3106
|
return { shot, at, start, samples: { given: take.samples.length, kept: kept.n } };
|
|
2703
3107
|
}
|
|
2704
|
-
function motionClientToDocument(camera,
|
|
2705
|
-
const k = Math.min(
|
|
2706
|
-
const ox =
|
|
2707
|
-
const oy =
|
|
3108
|
+
function motionClientToDocument(camera, box2, clientX, clientY) {
|
|
3109
|
+
const k = Math.min(box2.width / camera.width, box2.height / camera.height) || 1;
|
|
3110
|
+
const ox = box2.left + (box2.width - camera.width * k) / 2;
|
|
3111
|
+
const oy = box2.top + (box2.height - camera.height * k) / 2;
|
|
2708
3112
|
return { x: camera.x + (clientX - ox) / k, y: camera.y + (clientY - oy) / k };
|
|
2709
3113
|
}
|
|
2710
3114
|
|
|
@@ -2716,8 +3120,8 @@ var FLAIR_EASES = {
|
|
|
2716
3120
|
};
|
|
2717
3121
|
var FLAIR_EXPORT_VERSION = "0.39";
|
|
2718
3122
|
function flairAtLeast(version, min) {
|
|
2719
|
-
const a = version.split(".").map((
|
|
2720
|
-
const b = min.split(".").map((
|
|
3123
|
+
const a = version.split(".").map((n2) => parseInt(n2, 10) || 0);
|
|
3124
|
+
const b = min.split(".").map((n2) => parseInt(n2, 10) || 0);
|
|
2721
3125
|
for (let i = 0; i < Math.max(a.length, b.length); i++) if ((_nullishCoalesce(a[i], () => ( 0))) !== (_nullishCoalesce(b[i], () => ( 0)))) return (_nullishCoalesce(a[i], () => ( 0))) > (_nullishCoalesce(b[i], () => ( 0)));
|
|
2722
3126
|
return true;
|
|
2723
3127
|
}
|
|
@@ -2767,8 +3171,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2767
3171
|
return back && curves ? flairCurveFor(back, curves) : void 0;
|
|
2768
3172
|
};
|
|
2769
3173
|
const plays = (s) => (!s.behavior || behaviors) && (!s.steps || strobes) && !s.geometric;
|
|
2770
|
-
const round4 = (
|
|
2771
|
-
const f = (
|
|
3174
|
+
const round4 = (n2) => Math.round(n2 * 10 ** precision) / 10 ** precision;
|
|
3175
|
+
const f = (n2) => String(round4(n2));
|
|
2772
3176
|
const timeline = compileMotionScene(scene);
|
|
2773
3177
|
const nodes = indexMotionNodes(scene.artwork.nodes);
|
|
2774
3178
|
const notes = [];
|
|
@@ -2793,14 +3197,14 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2793
3197
|
const usedIds = new Set(nodes.keys());
|
|
2794
3198
|
const freshId = (base) => {
|
|
2795
3199
|
let id = base;
|
|
2796
|
-
for (let
|
|
3200
|
+
for (let n2 = 2; usedIds.has(id); n2++) id = `${base}-${n2}`;
|
|
2797
3201
|
usedIds.add(id);
|
|
2798
3202
|
return id;
|
|
2799
3203
|
};
|
|
2800
3204
|
for (const id of animatedNodes) {
|
|
2801
3205
|
const entry = nodes.get(id);
|
|
2802
3206
|
const node = entry.node;
|
|
2803
|
-
const drawn = [...entry.ancestors.map((a) => nodes.get(a).node), node].every((
|
|
3207
|
+
const drawn = [...entry.ancestors.map((a) => nodes.get(a).node), node].every((n2) => n2.visible !== false);
|
|
2804
3208
|
for (const [p, name] of [["clipRect", "reveal"], ["clipCircle", "iris"]]) {
|
|
2805
3209
|
if (!drawn || !timeline.tracks.has(motionTrackKey(id, p))) continue;
|
|
2806
3210
|
const wrapper = freshId(`${id}--${name}`);
|
|
@@ -2826,7 +3230,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2826
3230
|
const wrapper = freshId(`${id}--follow`);
|
|
2827
3231
|
const centre = freshId(`${id}--follow-centre`);
|
|
2828
3232
|
const c = entry.center;
|
|
2829
|
-
const at = _optionalChain([motionNodeOffset, 'call',
|
|
3233
|
+
const at = _optionalChain([motionNodeOffset, 'call', _149 => _149(entry, timeline, 0, nodes), 'optionalAccess', _150 => _150.follow]);
|
|
2830
3234
|
const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
|
|
2831
3235
|
(wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
|
|
2832
3236
|
follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
|
|
@@ -2887,7 +3291,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2887
3291
|
exact: () => false,
|
|
2888
3292
|
value: (t) => {
|
|
2889
3293
|
const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
|
|
2890
|
-
const now = _chunkBQE3Y6ZOcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call',
|
|
3294
|
+
const now = _chunkBQE3Y6ZOcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _151 => _151(frame.document.nodes), 'access', _152 => _152.get, 'call', _153 => _153(id), 'optionalAccess', _154 => _154.node]));
|
|
2891
3295
|
if (!now || now.type !== "path") return "";
|
|
2892
3296
|
const bezier = _chunkGF2RBSDMcjs.transformBezierPath.call(void 0, _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, now, _chunkBQE3Y6ZOcjs.IDENTITY_MATRIX, { effects: false }), inverse);
|
|
2893
3297
|
return _chunkGF2RBSDMcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
|
|
@@ -2901,8 +3305,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2901
3305
|
const moveSegments = windows.map((w) => ({ node: "", property: "camera", start: w.start, end: w.end, from: [], to: [], ease: "linear", shot: w.shot, command: -1 }));
|
|
2902
3306
|
const sampledMove = new WeakSet(moveSegments);
|
|
2903
3307
|
const cameraValue = windows.length ? (t) => {
|
|
2904
|
-
const
|
|
2905
|
-
return [
|
|
3308
|
+
const box2 = motionFrameAt(scene, t, { draw: false, offsets: false, effects: options.effects }).camera;
|
|
3309
|
+
return [box2.x, box2.y, box2.width, box2.height].map(round4);
|
|
2906
3310
|
} : (t) => trackValue(camera, t).map(round4);
|
|
2907
3311
|
if (camera.length || windows.length) channels.push({ id: "", kind: "view", segments: [...camera, ...moveSegments].sort((a, b) => a.start - b.start), exact: (seg) => !sampledMove.has(seg), overshoot: true, value: cameraValue });
|
|
2908
3312
|
const cameraTag = (t) => {
|
|
@@ -2910,7 +3314,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2910
3314
|
if (w) return `${w.move}@${w.shot}`;
|
|
2911
3315
|
const seg = camera.find((x) => t >= x.start - 1e-6 && t < Math.max(x.end, x.start + 1e-3));
|
|
2912
3316
|
const shot = seg ? scene.shots.find((x) => x.id === seg.shot) : void 0;
|
|
2913
|
-
const move = _optionalChain([
|
|
3317
|
+
const move = _optionalChain([_chunkJAOSL334cjs.cameraMoveParts.call(void 0, _optionalChain([shot, 'optionalAccess', _155 => _155.camera, 'optionalAccess', _156 => _156.in])), 'optionalAccess', _157 => _157.move]);
|
|
2914
3318
|
return move && shot ? `${move}@${shot.id}` : void 0;
|
|
2915
3319
|
};
|
|
2916
3320
|
const unplayed = scene.shots.filter((x) => x.camera && (x.camera.in !== void 0 || x.camera.during !== void 0) && !windows.some((w) => w.shot === x.id));
|
|
@@ -2927,8 +3331,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2927
3331
|
...delay > 0 ? { delay: round4(delay) } : {},
|
|
2928
3332
|
ms: round4(ms2),
|
|
2929
3333
|
ease: written,
|
|
2930
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
2931
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
3334
|
+
..._optionalChain([segment, 'optionalAccess', _158 => _158.behavior]) ? { behavior: segment.behavior } : {},
|
|
3335
|
+
..._optionalChain([segment, 'optionalAccess', _159 => _159.steps]) ? { strobe: segment.steps } : {}
|
|
2932
3336
|
};
|
|
2933
3337
|
if (channel.kind === "view") {
|
|
2934
3338
|
const tag2 = cameraTag(delay);
|
|
@@ -2965,11 +3369,11 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2965
3369
|
if (!same(from, to) || channel.kind === "view") emit(channel, a, b - a, from, to, ease, first);
|
|
2966
3370
|
continue;
|
|
2967
3371
|
}
|
|
2968
|
-
const
|
|
3372
|
+
const n2 = Math.max(1, Math.ceil((b - a) * fps / 1e3));
|
|
2969
3373
|
let prev = channel.value(a);
|
|
2970
|
-
for (let k = 1; k <=
|
|
2971
|
-
const t0 = a + (b - a) * (k - 1) /
|
|
2972
|
-
const t1 = a + (b - a) * k /
|
|
3374
|
+
for (let k = 1; k <= n2; k++) {
|
|
3375
|
+
const t0 = a + (b - a) * (k - 1) / n2;
|
|
3376
|
+
const t1 = a + (b - a) * k / n2;
|
|
2973
3377
|
const next = channel.value(t1);
|
|
2974
3378
|
const jump = channel.kind === "view" && active.some((x) => sampledMove.has(x)) ? viewJump(channel.value, t0, t1) : void 0;
|
|
2975
3379
|
if (jump) {
|
|
@@ -3001,10 +3405,10 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
3001
3405
|
continue;
|
|
3002
3406
|
}
|
|
3003
3407
|
const until = Math.min(seg.end, ...starts.filter((t) => t > seg.start));
|
|
3004
|
-
const
|
|
3005
|
-
for (let k = 1; k <=
|
|
3006
|
-
const t0 = seg.start + (until - seg.start) * (k - 1) /
|
|
3007
|
-
const t1 = seg.start + (until - seg.start) * k /
|
|
3408
|
+
const n2 = Math.max(1, Math.ceil((until - seg.start) * fps / 1e3));
|
|
3409
|
+
for (let k = 1; k <= n2; k++) {
|
|
3410
|
+
const t0 = seg.start + (until - seg.start) * (k - 1) / n2;
|
|
3411
|
+
const t1 = seg.start + (until - seg.start) * k / n2;
|
|
3008
3412
|
animate.push({ ...along, ...t0 > 0 ? { delay: round4(t0) } : {}, ms: round4(t1 - t0), ease: "linear", at: [progress(t0), progress(t1)] });
|
|
3009
3413
|
sampled++;
|
|
3010
3414
|
}
|
|
@@ -3032,7 +3436,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
3032
3436
|
let svg = _chunkBQE3Y6ZOcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunkBQE3Y6ZOcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
|
|
3033
3437
|
if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
|
|
3034
3438
|
let motion = { svg, animate };
|
|
3035
|
-
if (_optionalChain([scene, 'access',
|
|
3439
|
+
if (_optionalChain([scene, 'access', _160 => _160.controls, 'optionalAccess', _161 => _161.length])) {
|
|
3036
3440
|
const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
|
|
3037
3441
|
const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
|
|
3038
3442
|
svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
|
|
@@ -3054,7 +3458,7 @@ function toFlairVectorEffect(scene, options = {}) {
|
|
|
3054
3458
|
tags: _nullishCoalesce(options.tags, () => ( [])),
|
|
3055
3459
|
motion: out.motion,
|
|
3056
3460
|
hold: out.hold,
|
|
3057
|
-
..._optionalChain([scene, 'access',
|
|
3461
|
+
..._optionalChain([scene, 'access', _162 => _162.presets, 'optionalAccess', _163 => _163.length]) ? { presets: scene.presets } : {},
|
|
3058
3462
|
...out.trigger ? { trigger: out.trigger } : {}
|
|
3059
3463
|
};
|
|
3060
3464
|
}
|
|
@@ -3073,17 +3477,17 @@ function toFlairEffectDocument(scene, options = {}) {
|
|
|
3073
3477
|
};
|
|
3074
3478
|
}
|
|
3075
3479
|
function viewJump(value, t0, t1) {
|
|
3076
|
-
const
|
|
3480
|
+
const box2 = (t) => value(t);
|
|
3077
3481
|
const apart = (a2, b2) => Math.hypot(a2[0] + a2[2] / 2 - b2[0] - b2[2] / 2, a2[1] + a2[3] / 2 - b2[1] - b2[3] / 2, a2[2] - b2[2]);
|
|
3078
3482
|
let lo = t0;
|
|
3079
3483
|
let hi = t1;
|
|
3080
3484
|
for (let i = 0; i < 40 && hi - lo > 1e-4; i++) {
|
|
3081
3485
|
const mid = (lo + hi) / 2;
|
|
3082
|
-
if (apart(
|
|
3486
|
+
if (apart(box2(lo), box2(mid)) >= apart(box2(mid), box2(hi))) hi = mid;
|
|
3083
3487
|
else lo = mid;
|
|
3084
3488
|
}
|
|
3085
|
-
const a =
|
|
3086
|
-
const b =
|
|
3489
|
+
const a = box2(lo);
|
|
3490
|
+
const b = box2(hi);
|
|
3087
3491
|
return apart(a, b) > Math.min(a[2], b[2]) / 20 ? hi : void 0;
|
|
3088
3492
|
}
|
|
3089
3493
|
|
|
@@ -3112,7 +3516,7 @@ function resolvePlaceholders(motion, notes) {
|
|
|
3112
3516
|
const filled = text.replace(PLACEHOLDER, (_, name) => {
|
|
3113
3517
|
const d = declared.get(name);
|
|
3114
3518
|
if (!d) unknown.add(name);
|
|
3115
|
-
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess',
|
|
3519
|
+
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _164 => _164.value]), () => ( ""))).replace(/"/g, '\\"');
|
|
3116
3520
|
});
|
|
3117
3521
|
for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
|
|
3118
3522
|
return { motion: JSON.parse(filled), controls };
|
|
@@ -3138,7 +3542,7 @@ function poseOf(value, entry) {
|
|
|
3138
3542
|
return { dx: moved.x - c.x, dy: moved.y - c.y, rotation: Math.atan2(o[1], o[0]) * 180 / Math.PI, sx, sy };
|
|
3139
3543
|
}
|
|
3140
3544
|
var near = (a, b, eps = 1e-6) => Math.abs(a - b) < eps;
|
|
3141
|
-
var r3 = (
|
|
3545
|
+
var r3 = (n2) => Math.round(n2 * 1e3) / 1e3;
|
|
3142
3546
|
function commandsFor(anim, nodes, entered, notes) {
|
|
3143
3547
|
const id = anim.id;
|
|
3144
3548
|
const entry = nodes.get(id);
|
|
@@ -3166,7 +3570,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
3166
3570
|
if (anim.along) {
|
|
3167
3571
|
const path = nodes.get(anim.along);
|
|
3168
3572
|
if (!path || path.node.type !== "path") notes.push(`${where} follows "${anim.along}", which is not a path in the artwork; the follow was skipped.`);
|
|
3169
|
-
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access',
|
|
3573
|
+
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _165 => _165.at, 'optionalAccess', _166 => _166[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _167 => _167.at, 'optionalAccess', _168 => _168[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
3170
3574
|
}
|
|
3171
3575
|
for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
|
|
3172
3576
|
if (attr === "opacity") {
|
|
@@ -3177,7 +3581,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
3177
3581
|
out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
|
|
3178
3582
|
} else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
3179
3583
|
} else if (attr === "fill" || attr === "stroke") {
|
|
3180
|
-
if (_optionalChain([behavior, 'optionalAccess',
|
|
3584
|
+
if (_optionalChain([behavior, 'optionalAccess', _169 => _169.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
|
|
3181
3585
|
else {
|
|
3182
3586
|
if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
|
|
3183
3587
|
out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
@@ -3269,17 +3673,17 @@ ${problems.join("\n")}`);
|
|
|
3269
3673
|
}
|
|
3270
3674
|
function presetColor(value) {
|
|
3271
3675
|
if (typeof value === "string") return /^#[0-9a-f]{6}$/i.test(value) ? value.toLowerCase() : value;
|
|
3272
|
-
if (Array.isArray(value) && value.length >= 3 && value.slice(0, 3).every((
|
|
3273
|
-
return `#${value.slice(0, 3).map((
|
|
3676
|
+
if (Array.isArray(value) && value.length >= 3 && value.slice(0, 3).every((n2) => typeof n2 === "number" && Number.isFinite(n2)))
|
|
3677
|
+
return `#${value.slice(0, 3).map((n2) => Math.round(Math.min(1, Math.max(0, n2)) * 255).toString(16).padStart(2, "0")).join("")}`;
|
|
3274
3678
|
return void 0;
|
|
3275
3679
|
}
|
|
3276
3680
|
function fromFlairVectorEffect(effect, options = {}) {
|
|
3277
3681
|
if (!effect || effect.kind !== "vector" || !effect.motion) throw new Error('Give a Flair vector effect: { kind: "vector", id, name, motion: { svg, animate } }.');
|
|
3278
|
-
const
|
|
3279
|
-
const names = new Set((_nullishCoalesce(
|
|
3682
|
+
const result2 = fromFlairSvgMotion(effect.motion, { name: _nullishCoalesce(_nullishCoalesce(options.name, () => ( effect.id)), () => ( effect.name)), hold: _nullishCoalesce(options.hold, () => ( effect.hold)), ...effect.trigger === "click" ? { clickSteps: true } : {} });
|
|
3683
|
+
const names = new Set((_nullishCoalesce(result2.scene.controls, () => ( []))).map((c) => c.name));
|
|
3280
3684
|
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);
|
|
3281
|
-
const scene = { ...
|
|
3282
|
-
const notes = [...
|
|
3685
|
+
const scene = { ...result2.scene, ...effect.description ? { description: effect.description } : {}, ...presets.length ? { presets } : {}, ...effect.trigger ? { trigger: effect.trigger } : {} };
|
|
3686
|
+
const notes = [...result2.notes];
|
|
3283
3687
|
return { scene, notes, issues: checkMotionScene(scene) };
|
|
3284
3688
|
}
|
|
3285
3689
|
|
|
@@ -3297,8 +3701,8 @@ var STATIC_TR = () => ({
|
|
|
3297
3701
|
function rgba(color) {
|
|
3298
3702
|
const hex = typeof color === "string" ? _chunkA6QWKBJPcjs.normalizeTokenColor.call(void 0, color) : null;
|
|
3299
3703
|
if (!hex) return null;
|
|
3300
|
-
const
|
|
3301
|
-
return [
|
|
3704
|
+
const n2 = (i) => parseInt(hex.slice(i, i + 2), 16) / 255;
|
|
3705
|
+
return [n2(1), n2(3), n2(5), hex.length >= 9 ? parseInt(hex.slice(7, 9), 16) / 255 : 1];
|
|
3302
3706
|
}
|
|
3303
3707
|
function lottieContours(path, round4) {
|
|
3304
3708
|
const out = [];
|
|
@@ -3329,9 +3733,9 @@ function lottieContours(path, round4) {
|
|
|
3329
3733
|
add(cmd.x, cmd.y, cmd.x2, cmd.y2);
|
|
3330
3734
|
} else if (cmd.type === "Z") {
|
|
3331
3735
|
cur.c = true;
|
|
3332
|
-
const
|
|
3333
|
-
if (
|
|
3334
|
-
cur.i[0] = cur.i[
|
|
3736
|
+
const n2 = cur.v.length;
|
|
3737
|
+
if (n2 > 1 && Math.abs(cur.v[n2 - 1][0] - cur.v[0][0]) < 1e-9 && Math.abs(cur.v[n2 - 1][1] - cur.v[0][1]) < 1e-9) {
|
|
3738
|
+
cur.i[0] = cur.i[n2 - 1];
|
|
3335
3739
|
cur.v.pop();
|
|
3336
3740
|
cur.i.pop();
|
|
3337
3741
|
cur.o.pop();
|
|
@@ -3353,7 +3757,7 @@ function staticParts(m) {
|
|
|
3353
3757
|
function toLottie(scene, options = {}) {
|
|
3354
3758
|
const fps = _nullishCoalesce(_nullishCoalesce(options.fps, () => ( scene.fps)), () => ( 30));
|
|
3355
3759
|
const precision = _nullishCoalesce(options.precision, () => ( 3));
|
|
3356
|
-
const round4 = (
|
|
3760
|
+
const round4 = (n2) => Math.round(n2 * 10 ** precision) / 10 ** precision;
|
|
3357
3761
|
const frame = (ms2) => round4(ms2 * fps / 1e3);
|
|
3358
3762
|
const timeline = compileMotionScene(scene);
|
|
3359
3763
|
const nodes = indexMotionNodes(scene.artwork.nodes);
|
|
@@ -3386,9 +3790,9 @@ function toLottie(scene, options = {}) {
|
|
|
3386
3790
|
else keys.push(k);
|
|
3387
3791
|
};
|
|
3388
3792
|
const times = [.../* @__PURE__ */ new Set([0, ...segments.flatMap((s) => [s.start, s.end]), end])].filter((t) => t >= 0 && t <= end).sort((a, b) => a - b);
|
|
3389
|
-
for (let
|
|
3390
|
-
const a = times[
|
|
3391
|
-
const b = times[
|
|
3793
|
+
for (let n2 = 0; n2 + 1 < times.length; n2++) {
|
|
3794
|
+
const a = times[n2];
|
|
3795
|
+
const b = times[n2 + 1];
|
|
3392
3796
|
const active = segments.filter((s) => s.start < b && s.end > a);
|
|
3393
3797
|
if (!active.length) {
|
|
3394
3798
|
key(a, value(a), "hold");
|
|
@@ -3467,11 +3871,11 @@ function toLottie(scene, options = {}) {
|
|
|
3467
3871
|
const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
|
|
3468
3872
|
const geometryAt = (t) => {
|
|
3469
3873
|
if (!shapeSegments.length) return _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, path);
|
|
3470
|
-
const now = _optionalChain([indexMotionNodes, 'call',
|
|
3874
|
+
const now = _optionalChain([indexMotionNodes, 'call', _170 => _170(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _171 => _171.get, 'call', _172 => _172(path.id), 'optionalAccess', _173 => _173.node]);
|
|
3471
3875
|
return now && now.type === "path" ? _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, _chunkBQE3Y6ZOcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, path);
|
|
3472
3876
|
};
|
|
3473
3877
|
const rest = lottieContours(_chunkGF2RBSDMcjs.toBezierPath.call(void 0, geometryAt(0)), round4);
|
|
3474
|
-
rest.forEach((contour,
|
|
3878
|
+
rest.forEach((contour, n2) => {
|
|
3475
3879
|
let ks = { a: 0, k: contour };
|
|
3476
3880
|
if (shapeSegments.length) {
|
|
3477
3881
|
const keys = [];
|
|
@@ -3479,7 +3883,7 @@ function toLottie(scene, options = {}) {
|
|
|
3479
3883
|
const count = Math.max(1, Math.ceil(end * fps / 1e3));
|
|
3480
3884
|
for (let k = 0; k <= count && fits; k++) {
|
|
3481
3885
|
const t = end * k / count;
|
|
3482
|
-
const c = lottieContours(_chunkGF2RBSDMcjs.toBezierPath.call(void 0, geometryAt(t)), round4)[
|
|
3886
|
+
const c = lottieContours(_chunkGF2RBSDMcjs.toBezierPath.call(void 0, geometryAt(t)), round4)[n2];
|
|
3483
3887
|
if (!c || c.v.length !== contour.v.length || c.c !== contour.c) fits = false;
|
|
3484
3888
|
else keys.push({ t: frame(t), s: [c], ...k < count ? { o: { x: [0], y: [0] }, i: { x: [1], y: [1] } } : {} });
|
|
3485
3889
|
}
|
|
@@ -3488,7 +3892,7 @@ function toLottie(scene, options = {}) {
|
|
|
3488
3892
|
sampled += keys.length;
|
|
3489
3893
|
} else notes.push(`"${path.id}": its morph changes how many points the outline has, which Lottie cannot tween; it shows its starting shape.`);
|
|
3490
3894
|
}
|
|
3491
|
-
items.push({ ty: "sh", nm: `${path.id} ${
|
|
3895
|
+
items.push({ ty: "sh", nm: `${path.id} ${n2 + 1}`, ks });
|
|
3492
3896
|
});
|
|
3493
3897
|
const fillFrom = owner(path, "fill");
|
|
3494
3898
|
const strokeFrom = owner(path, "stroke");
|
|
@@ -3515,7 +3919,7 @@ function toLottie(scene, options = {}) {
|
|
|
3515
3919
|
lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
|
|
3516
3920
|
ml: 4
|
|
3517
3921
|
});
|
|
3518
|
-
if (_optionalChain([path, 'access',
|
|
3922
|
+
if (_optionalChain([path, 'access', _174 => _174.strokeDasharray, 'optionalAccess', _175 => _175.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
|
|
3519
3923
|
if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
|
|
3520
3924
|
}
|
|
3521
3925
|
const fill = paintOf(path.fill, "fill", path.id);
|
|
@@ -3532,7 +3936,7 @@ function toLottie(scene, options = {}) {
|
|
|
3532
3936
|
}
|
|
3533
3937
|
return items;
|
|
3534
3938
|
};
|
|
3535
|
-
const shown = (list) => list.filter((
|
|
3939
|
+
const shown = (list) => list.filter((n2) => n2.visible !== false);
|
|
3536
3940
|
const nodeGroup = (node) => {
|
|
3537
3941
|
const entry = nodes.get(node.id);
|
|
3538
3942
|
if (timeline.tracks.has(motionTrackKey(node.id, "clipRect")) || timeline.tracks.has(motionTrackKey(node.id, "clipCircle")))
|
|
@@ -3567,9 +3971,9 @@ function toLottie(scene, options = {}) {
|
|
|
3567
3971
|
const camera = track("", "camera");
|
|
3568
3972
|
const root = STATIC_TR();
|
|
3569
3973
|
if (camera.length) {
|
|
3570
|
-
const
|
|
3571
|
-
root.a = animate(camera, (t) =>
|
|
3572
|
-
root.s = animate(camera, (t) => [artwork.width /
|
|
3974
|
+
const box2 = (t) => _nullishCoalesce(trackValue(camera, t), () => ( [0, 0, artwork.width, artwork.height]));
|
|
3975
|
+
root.a = animate(camera, (t) => box2(t).slice(0, 2), false);
|
|
3976
|
+
root.s = animate(camera, (t) => [artwork.width / box2(t)[2] * 100, artwork.height / box2(t)[3] * 100], false);
|
|
3573
3977
|
}
|
|
3574
3978
|
const op = Math.max(1, Math.ceil(end * fps / 1e3));
|
|
3575
3979
|
const lottie = {
|
|
@@ -3609,9 +4013,9 @@ var kids = (el, name) => el ? Array.from(el.children).filter((c) => c.localName
|
|
|
3609
4013
|
var kid = (el, name) => _nullishCoalesce(kids(el, name)[0], () => ( null));
|
|
3610
4014
|
var deep = (el, name) => el ? Array.from(el.getElementsByTagNameNS("*", name)) : [];
|
|
3611
4015
|
var num = (el, attr, fallback = 0) => {
|
|
3612
|
-
const v = _optionalChain([el, 'optionalAccess',
|
|
3613
|
-
const
|
|
3614
|
-
return Number.isFinite(
|
|
4016
|
+
const v = _optionalChain([el, 'optionalAccess', _176 => _176.getAttribute, 'call', _177 => _177(attr)]);
|
|
4017
|
+
const n2 = v === null || v === void 0 ? NaN : Number(v);
|
|
4018
|
+
return Number.isFinite(n2) ? n2 : fallback;
|
|
3615
4019
|
};
|
|
3616
4020
|
var dirname = (p) => p.slice(0, p.lastIndexOf("/") + 1);
|
|
3617
4021
|
function resolve(base, target) {
|
|
@@ -3717,8 +4121,8 @@ function placement(xfrm, map) {
|
|
|
3717
4121
|
const ext = kid(xfrm, "ext");
|
|
3718
4122
|
const [x, y, w, h] = map(num(off, "x"), num(off, "y"), num(ext, "cx"), num(ext, "cy"));
|
|
3719
4123
|
const rot = num(xfrm, "rot") / 6e4 * (Math.PI / 180);
|
|
3720
|
-
const fx = _optionalChain([xfrm, 'optionalAccess',
|
|
3721
|
-
const fy = _optionalChain([xfrm, 'optionalAccess',
|
|
4124
|
+
const fx = _optionalChain([xfrm, 'optionalAccess', _178 => _178.getAttribute, 'call', _179 => _179("flipH")]) === "1" ? -1 : 1;
|
|
4125
|
+
const fy = _optionalChain([xfrm, 'optionalAccess', _180 => _180.getAttribute, 'call', _181 => _181("flipV")]) === "1" ? -1 : 1;
|
|
3722
4126
|
const cx = x + w / 2;
|
|
3723
4127
|
const cy = y + h / 2;
|
|
3724
4128
|
const cos = Math.cos(rot);
|
|
@@ -3745,7 +4149,7 @@ function shapes(ctx, tree, map) {
|
|
|
3745
4149
|
const nv = el.firstElementChild;
|
|
3746
4150
|
const cNvPr = kid(nv, "cNvPr");
|
|
3747
4151
|
const spid = num(cNvPr, "id", -1);
|
|
3748
|
-
const name = _nullishCoalesce(_optionalChain([cNvPr, 'optionalAccess',
|
|
4152
|
+
const name = _nullishCoalesce(_optionalChain([cNvPr, 'optionalAccess', _182 => _182.getAttribute, 'call', _183 => _183("name")]), () => ( ""));
|
|
3749
4153
|
if (el.localName === "grpSp") {
|
|
3750
4154
|
const xfrm = kid(kid(el, "grpSpPr"), "xfrm");
|
|
3751
4155
|
const off = kid(xfrm, "off");
|
|
@@ -3766,7 +4170,7 @@ function shapes(ctx, tree, map) {
|
|
|
3766
4170
|
if (el.localName !== "sp" && el.localName !== "cxnSp") continue;
|
|
3767
4171
|
const spPr = kid(el, "spPr");
|
|
3768
4172
|
const { w, h, transform } = placement(kid(spPr, "xfrm"), map);
|
|
3769
|
-
const prst = _optionalChain([kid, 'call',
|
|
4173
|
+
const prst = _optionalChain([kid, 'call', _184 => _184(spPr, "prstGeom"), 'optionalAccess', _185 => _185.getAttribute, 'call', _186 => _186("prst")]);
|
|
3770
4174
|
const cust = kid(spPr, "custGeom");
|
|
3771
4175
|
let subpaths = cust ? custom(cust, w, h) : prst ? preset(prst, w, h) : null;
|
|
3772
4176
|
if (!subpaths) {
|
|
@@ -3880,13 +4284,13 @@ function command(ctx, ctn, scene, artwork, target, hidden) {
|
|
|
3880
4284
|
}
|
|
3881
4285
|
if (cls === "path") {
|
|
3882
4286
|
const motion = deep(ctn, "animMotion")[0];
|
|
3883
|
-
const d = _optionalChain([motion, 'optionalAccess',
|
|
4287
|
+
const d = _optionalChain([motion, 'optionalAccess', _187 => _187.getAttribute, 'call', _188 => _188("path")]);
|
|
3884
4288
|
if (!d) return null;
|
|
3885
|
-
const entry = artwork.flatMap(function all(
|
|
3886
|
-
return
|
|
3887
|
-
}).find((
|
|
3888
|
-
const t = _nullishCoalesce(_optionalChain([entry, 'optionalAccess',
|
|
3889
|
-
const p = _optionalChain([entry, 'optionalAccess',
|
|
4289
|
+
const entry = artwork.flatMap(function all(n2) {
|
|
4290
|
+
return n2.type === "group" ? [n2, ...n2.children.flatMap(all)] : [n2];
|
|
4291
|
+
}).find((n2) => n2.id === target);
|
|
4292
|
+
const t = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _189 => _189.transform]), () => ( [1, 0, 0, 1, 0, 0]));
|
|
4293
|
+
const p = _optionalChain([entry, 'optionalAccess', _190 => _190.type]) === "path" ? _optionalChain([entry, 'access', _191 => _191.subpaths, 'access', _192 => _192[0], 'optionalAccess', _193 => _193.anchors]) : void 0;
|
|
3890
4294
|
const xs = (_nullishCoalesce(p, () => ( []))).map((a) => a.x);
|
|
3891
4295
|
const ys = (_nullishCoalesce(p, () => ( []))).map((a) => a.y);
|
|
3892
4296
|
const lx = xs.length ? (Math.min(...xs) + Math.max(...xs)) / 2 : 0;
|
|
@@ -3929,8 +4333,8 @@ async function fromPptxAnimation(data, options = {}) {
|
|
|
3929
4333
|
if (!pres) throw new Error("This is not a PowerPoint file (.pptx): it has no ppt/presentation.xml.");
|
|
3930
4334
|
const presRels = await rels(ctx, "ppt/presentation.xml");
|
|
3931
4335
|
const slidePaths = deep(pres, "sldId").map((s) => _nullishCoalesce(presRels.get(_nullishCoalesce(_nullishCoalesce(s.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id"), () => ( s.getAttribute("r:id"))), () => ( ""))), () => ( ""))).filter(Boolean);
|
|
3932
|
-
const
|
|
3933
|
-
if (!(Number.isInteger(
|
|
4336
|
+
const n2 = _nullishCoalesce(options.slide, () => ( 1));
|
|
4337
|
+
if (!(Number.isInteger(n2) && n2 >= 1 && n2 <= slidePaths.length)) throw new Error(`There is no slide ${n2}; the file has ${slidePaths.length} slide${slidePaths.length === 1 ? "" : "s"}.`);
|
|
3934
4338
|
const size = deep(pres, "sldSz")[0];
|
|
3935
4339
|
const width = Math.round(num(size, "cx", 12192e3) / EMU);
|
|
3936
4340
|
const height = Math.round(num(size, "cy", 6858e3) / EMU);
|
|
@@ -3938,15 +4342,15 @@ async function fromPptxAnimation(data, options = {}) {
|
|
|
3938
4342
|
if (!path.includes("theme/")) continue;
|
|
3939
4343
|
const theme = await xml(ctx, path);
|
|
3940
4344
|
const scheme = deep(theme, "clrScheme")[0];
|
|
3941
|
-
for (const c of Array.from(_nullishCoalesce(_optionalChain([scheme, 'optionalAccess',
|
|
4345
|
+
for (const c of Array.from(_nullishCoalesce(_optionalChain([scheme, 'optionalAccess', _194 => _194.children]), () => ( [])))) {
|
|
3942
4346
|
const v = c.firstElementChild;
|
|
3943
|
-
const hex = _optionalChain([v, 'optionalAccess',
|
|
4347
|
+
const hex = _optionalChain([v, 'optionalAccess', _195 => _195.localName]) === "srgbClr" ? v.getAttribute("val") : _optionalChain([v, 'optionalAccess', _196 => _196.getAttribute, 'call', _197 => _197("lastClr")]);
|
|
3944
4348
|
if (hex) ctx.theme.set(c.localName, `#${hex.toLowerCase()}`);
|
|
3945
4349
|
}
|
|
3946
4350
|
break;
|
|
3947
4351
|
}
|
|
3948
|
-
const slide = await xml(ctx, slidePaths[
|
|
3949
|
-
if (!slide) throw new Error(`Slide ${
|
|
4352
|
+
const slide = await xml(ctx, slidePaths[n2 - 1]);
|
|
4353
|
+
if (!slide) throw new Error(`Slide ${n2} cannot be read.`);
|
|
3950
4354
|
const tree = deep(slide, "spTree")[0];
|
|
3951
4355
|
const toPx = (x, y, w, h) => [x / EMU, y / EMU, w / EMU, h / EMU];
|
|
3952
4356
|
const nodes = tree ? shapes(ctx, tree, toPx) : [];
|
|
@@ -3973,18 +4377,118 @@ async function fromPptxAnimation(data, options = {}) {
|
|
|
3973
4377
|
}
|
|
3974
4378
|
if (effects.length && !shots.length) ctx.notes.push("The slide's effects could not be read.");
|
|
3975
4379
|
const artwork = { width, height, background: bg, nodes: [...nodes, ...hidden] };
|
|
3976
|
-
const scene = { version: 1, name: `slide-${
|
|
4380
|
+
const scene = { version: 1, name: `slide-${n2}`, artwork, shots, ...shots.length > 1 ? { trigger: "click" } : {} };
|
|
3977
4381
|
const problems = motionSceneShapeProblems(scene);
|
|
3978
4382
|
if (problems.length) throw new Error(`The imported scene is not well formed:
|
|
3979
4383
|
${problems.join("\n")}`);
|
|
3980
4384
|
return { scene, notes: [...new Set(ctx.notes)], issues: checkMotionScene(scene), slides: slidePaths.length };
|
|
3981
4385
|
}
|
|
3982
4386
|
|
|
4387
|
+
// src/animation-editor/layer-edit.ts
|
|
4388
|
+
function motionShotLayersInfo(scene, shot) {
|
|
4389
|
+
const spans = motionLayerSpans(scene);
|
|
4390
|
+
const timings = compileMotionScene(scene).shots;
|
|
4391
|
+
return scene.shots.filter((s) => shot === void 0 || s.id === shot).map((s) => {
|
|
4392
|
+
const timing = timings.find((t) => t.id === s.id);
|
|
4393
|
+
return {
|
|
4394
|
+
shot: s.id,
|
|
4395
|
+
layers: spans.filter((sp) => sp.shot === s.id).map((sp) => ({ ...sp.layer, shot: s.id, index: sp.index, role: sp.role, start: sp.start, end: sp.end })),
|
|
4396
|
+
transition: s.transition && timing.transitionEnd !== void 0 ? { ...s.transition, start: timing.start, end: timing.transitionEnd } : null
|
|
4397
|
+
};
|
|
4398
|
+
});
|
|
4399
|
+
}
|
|
4400
|
+
function findMotionShotLayer(scene, id) {
|
|
4401
|
+
for (let shot = 0; shot < scene.shots.length; shot++) {
|
|
4402
|
+
const index = (_nullishCoalesce(scene.shots[shot].layers, () => ( []))).findIndex((l) => l.id === id);
|
|
4403
|
+
if (index >= 0) return { shot, index };
|
|
4404
|
+
}
|
|
4405
|
+
return null;
|
|
4406
|
+
}
|
|
4407
|
+
var motionLayerIds = (scene) => scene.shots.flatMap((s) => (_nullishCoalesce(s.layers, () => ( []))).map((l) => l.id));
|
|
4408
|
+
function freshMotionLayerId(scene, base = "layer") {
|
|
4409
|
+
const used = new Set(motionLayerIds(scene));
|
|
4410
|
+
for (let i = 1; ; i++) if (!used.has(`${base}${i}`)) return `${base}${i}`;
|
|
4411
|
+
}
|
|
4412
|
+
var kindHint = (d) => {
|
|
4413
|
+
if (d.uses.includes("transition")) return "it is a transition: set it between shots with set_shot_transition";
|
|
4414
|
+
if (d.kind === "camera") return "it is a camera move: set it with set_shot_camera_move";
|
|
4415
|
+
if (d.kind === "motion") return "it animates artwork nodes: apply it with apply_effect";
|
|
4416
|
+
return `its uses are ${d.uses.join(", ")}`;
|
|
4417
|
+
};
|
|
4418
|
+
function withPreset(d, preset2, values) {
|
|
4419
|
+
if (preset2 === void 0) return values;
|
|
4420
|
+
const p = d.presets.find((x) => x.name === preset2);
|
|
4421
|
+
if (!p) throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)(`"${d.id}" has no preset "${preset2}"; ${d.presets.length ? `its presets are ${d.presets.map((x) => `"${x.name}"`).join(", ")}` : "it has no presets"}.`, d.id);
|
|
4422
|
+
return { ...p.values, ..._nullishCoalesce(values, () => ( {})) };
|
|
4423
|
+
}
|
|
4424
|
+
async function resolveMotionShotLayer(provider, layer) {
|
|
4425
|
+
if (!layer.effect) {
|
|
4426
|
+
if (!layer.subject) throw new Error('A layer needs an "effect", a "subject" or both.');
|
|
4427
|
+
if (layer.preset !== void 0 || layer.values !== void 0) throw new Error('A bare subject has no controls; leave out "preset" and "values", or give an "effect".');
|
|
4428
|
+
const { provider: _p, name: _n, ...rest } = layer;
|
|
4429
|
+
return rest;
|
|
4430
|
+
}
|
|
4431
|
+
if (!provider) throw new (0, _chunkJAOSL334cjs.NoEffectsProviderError)();
|
|
4432
|
+
const d = await provider.describe(layer.effect);
|
|
4433
|
+
if (!_chunk6RZVFYGJcjs.effectLayerOffered.call(void 0, d)) throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) cannot be a layer; ${kindHint(d)}. A layer's effect is a generator, filter, overlay or title (search_effects with use "generator", "filter", "overlay" or "title").`, d.id);
|
|
4434
|
+
const input = _chunk6RZVFYGJcjs.effectLayerInput.call(void 0, d);
|
|
4435
|
+
if (layer.subject && !input) throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) draws its own picture and takes no subject; leave "subject" out, or pick a filter to change the subject.`, d.id);
|
|
4436
|
+
if (!layer.subject && input && _optionalChain([d, 'access', _198 => _198.inputs, 'access', _199 => _199.find, 'call', _200 => _200((i) => i.name === input), 'optionalAccess', _201 => _201.required])) throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) changes a picture; give a "subject": { "image": url }, { "svg": markup }, { "text": words } or { "slot": name }.`, d.id);
|
|
4437
|
+
const values = withPreset(d, layer.preset, layer.values);
|
|
4438
|
+
_chunkJAOSL334cjs.resolveEffectValues.call(void 0, d, values);
|
|
4439
|
+
const out = { ...layer, provider: provider.id, name: d.name };
|
|
4440
|
+
if (values && Object.keys(values).length) out.values = values;
|
|
4441
|
+
else delete out.values;
|
|
4442
|
+
return out;
|
|
4443
|
+
}
|
|
4444
|
+
async function resolveMotionShotTransition(provider, transition) {
|
|
4445
|
+
if (!provider) throw new (0, _chunkJAOSL334cjs.NoEffectsProviderError)();
|
|
4446
|
+
const d = await provider.describe(transition.effect);
|
|
4447
|
+
if (!d.uses.includes("transition") || d.kind === "camera") throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) is not a transition (${kindHint(d)}); search_effects with use "transition" lists them.`, d.id);
|
|
4448
|
+
if (transition.ms !== void 0 && !(transition.ms > 0 && transition.ms <= 6e4)) throw new Error(`A transition's "ms" is from 1 to 60000; got ${transition.ms}.`);
|
|
4449
|
+
const values = withPreset(d, transition.preset, transition.values);
|
|
4450
|
+
_chunkJAOSL334cjs.resolveEffectValues.call(void 0, d, values);
|
|
4451
|
+
const out = { ...transition, ms: _nullishCoalesce(transition.ms, () => ( _chunkJAOSL334cjs.EFFECT_TRANSITION_MS)), provider: provider.id, name: d.name };
|
|
4452
|
+
if (values && Object.keys(values).length) out.values = values;
|
|
4453
|
+
else delete out.values;
|
|
4454
|
+
return out;
|
|
4455
|
+
}
|
|
4456
|
+
async function checkMotionShotLayers(scene, provider) {
|
|
4457
|
+
const issues = [];
|
|
4458
|
+
if (_optionalChain([scene, 'access', _202 => _202.shots, 'access', _203 => _203[0], 'optionalAccess', _204 => _204.transition])) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "transition-first-shot", `Shot "${scene.shots[0].id}" is the first shot, so its transition does not play; move it to a later shot or clear it.`, { shot: scene.shots[0].id }));
|
|
4459
|
+
for (const shot of scene.shots)
|
|
4460
|
+
for (const layer of _nullishCoalesce(shot.layers, () => ( [])))
|
|
4461
|
+
if (layer.subject && "slot" in layer.subject) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "layer-slot-empty", `Layer "${layer.id}" shows slot "${layer.subject.slot}", which is empty; set its "subject" to a picture with update_shot_layer.`, { shot: shot.id, ids: [layer.id] }));
|
|
4462
|
+
const effectLayers = scene.shots.flatMap((s) => (_nullishCoalesce(s.layers, () => ( []))).filter((l) => l.effect).map((l) => ({ shot: s.id, layer: l })));
|
|
4463
|
+
const transitions = scene.shots.slice(1).filter((s) => s.transition);
|
|
4464
|
+
if (!provider) {
|
|
4465
|
+
if (effectLayers.length) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "layer-not-drawn", `Layers ${effectLayers.map((e) => `"${e.layer.id}"`).join(", ")} name provider effects, but no effects provider is set, so they are left out of frames; set a provider to draw them.`, { ids: effectLayers.map((e) => e.layer.id) }));
|
|
4466
|
+
if (transitions.length) issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, "transition-not-played", `Shots ${transitions.map((s) => `"${s.id}"`).join(", ")} name transitions, but no effects provider is set, so they crossfade; set a provider to play them.`));
|
|
4467
|
+
return issues;
|
|
4468
|
+
}
|
|
4469
|
+
for (const { shot, layer } of effectLayers) {
|
|
4470
|
+
try {
|
|
4471
|
+
await resolveMotionShotLayer(provider, layer);
|
|
4472
|
+
} catch (error) {
|
|
4473
|
+
const code = error.code === "invalid_values" || /preset/.test(error.message) ? "layer-effect-values" : "layer-effect-unknown";
|
|
4474
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, code, `Layer "${layer.id}": ${error.message}`, { shot, ids: [layer.id] }));
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
for (const shot of transitions) {
|
|
4478
|
+
try {
|
|
4479
|
+
await resolveMotionShotTransition(provider, shot.transition);
|
|
4480
|
+
} catch (error) {
|
|
4481
|
+
issues.push(_chunkDGWOGQJ5cjs.motionIssue.call(void 0, error.code === "invalid_values" ? "layer-effect-values" : "transition-unknown", error.message, { shot: shot.id }));
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
return issues;
|
|
4485
|
+
}
|
|
4486
|
+
|
|
3983
4487
|
// src/animation-editor/effects.ts
|
|
3984
4488
|
var sourceOf = (c) => c.source;
|
|
3985
4489
|
function motionSceneEffects(scene) {
|
|
3986
4490
|
const out = /* @__PURE__ */ new Map();
|
|
3987
|
-
const groups = new Set(scene.artwork.nodes.filter((
|
|
4491
|
+
const groups = new Set(scene.artwork.nodes.filter((n2) => n2.type === "group").map((n2) => n2.id));
|
|
3988
4492
|
for (const shot of scene.shots) {
|
|
3989
4493
|
for (const c of shot.run) {
|
|
3990
4494
|
const s = sourceOf(c);
|
|
@@ -4005,7 +4509,7 @@ function motionSceneEffects(scene) {
|
|
|
4005
4509
|
}
|
|
4006
4510
|
function nextMotionEffectInstance(scene) {
|
|
4007
4511
|
const used = /* @__PURE__ */ new Set([...motionSceneEffects(scene).map((e) => e.instance), ...scene.shots.map((s) => s.id)]);
|
|
4008
|
-
const walk = (nodes) => nodes.forEach((
|
|
4512
|
+
const walk = (nodes) => nodes.forEach((n2) => (used.add(n2.id), n2.type === "group" && walk(n2.children)));
|
|
4009
4513
|
walk(scene.artwork.nodes);
|
|
4010
4514
|
for (let i = 1; ; i++) if (!used.has(`fx${i}`)) return `fx${i}`;
|
|
4011
4515
|
}
|
|
@@ -4021,10 +4525,10 @@ function motionCommandsFromEffect(artwork, motion, source) {
|
|
|
4021
4525
|
}
|
|
4022
4526
|
function prefixed(nodes, shots, prefix) {
|
|
4023
4527
|
const map = /* @__PURE__ */ new Map();
|
|
4024
|
-
const rename = (list) => list.map((
|
|
4025
|
-
map.set(
|
|
4026
|
-
const next = { ...
|
|
4027
|
-
if (next.type === "group") next.children = rename(
|
|
4528
|
+
const rename = (list) => list.map((n2) => {
|
|
4529
|
+
map.set(n2.id, prefix + n2.id);
|
|
4530
|
+
const next = { ...n2, id: prefix + n2.id };
|
|
4531
|
+
if (next.type === "group") next.children = rename(n2.children);
|
|
4028
4532
|
return next;
|
|
4029
4533
|
});
|
|
4030
4534
|
const out = rename(nodes);
|
|
@@ -4040,14 +4544,14 @@ function prefixed(nodes, shots, prefix) {
|
|
|
4040
4544
|
}));
|
|
4041
4545
|
return { nodes: out, shots: remapped };
|
|
4042
4546
|
}
|
|
4043
|
-
function motionPartsFromVectorEffect(artwork, motion, source,
|
|
4547
|
+
function motionPartsFromVectorEffect(artwork, motion, source, box2 = { x: 0, y: 0, width: artwork.width, height: artwork.height }) {
|
|
4044
4548
|
const imported = fromFlairSvgMotion({ svg: motion.svg, animate: [..._nullishCoalesce(motion.animate, () => ( []))] }, { hold: 0 });
|
|
4045
4549
|
const art = imported.scene.artwork;
|
|
4046
4550
|
const prefix = `${source.instance}-`;
|
|
4047
4551
|
const { nodes, shots } = prefixed(art.nodes, imported.scene.shots, prefix);
|
|
4048
|
-
const k = Math.min(
|
|
4049
|
-
const dx =
|
|
4050
|
-
const dy =
|
|
4552
|
+
const k = Math.min(box2.width / art.width, box2.height / art.height);
|
|
4553
|
+
const dx = box2.x + (box2.width - art.width * k) / 2;
|
|
4554
|
+
const dy = box2.y + (box2.height - art.height * k) / 2;
|
|
4051
4555
|
const group = { type: "group", id: source.instance, name: _nullishCoalesce(source.name, () => ( source.effect)), children: nodes, transform: [k, 0, 0, k, dx, dy] };
|
|
4052
4556
|
const tagged = shots.map((s, i) => ({ ...s, id: i === 0 ? source.instance + "-shot" : `${source.instance}-shot-${i + 1}`, run: tag(s.run, source) }));
|
|
4053
4557
|
return { group, shots: tagged.map((s) => s.hold === 0 ? (({ hold: _h, ...rest }) => rest)(s) : s), notes: imported.notes };
|
|
@@ -4058,7 +4562,7 @@ function withoutMotionEffect(scene, instance) {
|
|
|
4058
4562
|
const shots = [];
|
|
4059
4563
|
for (const shot of scene.shots) {
|
|
4060
4564
|
const run = shot.run.filter((c, i) => {
|
|
4061
|
-
const mine = _optionalChain([sourceOf, 'call',
|
|
4565
|
+
const mine = _optionalChain([sourceOf, 'call', _205 => _205(c), 'optionalAccess', _206 => _206.instance]) === instance;
|
|
4062
4566
|
if (mine && !place) place = { shot: shot.id, index: i };
|
|
4063
4567
|
return !mine;
|
|
4064
4568
|
});
|
|
@@ -4066,7 +4570,7 @@ function withoutMotionEffect(scene, instance) {
|
|
|
4066
4570
|
else if (run.length === 0) removedShots.push(shot.id);
|
|
4067
4571
|
else shots.push({ ...shot, run });
|
|
4068
4572
|
}
|
|
4069
|
-
const artwork = { ...scene.artwork, nodes: scene.artwork.nodes.filter((
|
|
4573
|
+
const artwork = { ...scene.artwork, nodes: scene.artwork.nodes.filter((n2) => n2.id !== instance) };
|
|
4070
4574
|
return { scene: { ...scene, shots, artwork }, place, removedShots };
|
|
4071
4575
|
}
|
|
4072
4576
|
|
|
@@ -4074,30 +4578,37 @@ function withoutMotionEffect(scene, instance) {
|
|
|
4074
4578
|
var MOTION_RECORD_GESTURE_MODES = ["move", "scale", "rotate"];
|
|
4075
4579
|
var MOTION_MAX_TAKE_MS = 10 * 6e4;
|
|
4076
4580
|
var BLANK = { width: 800, height: 450, background: "#ffffff", nodes: [] };
|
|
4077
|
-
var AnimationEditorController = (
|
|
4581
|
+
var AnimationEditorController = (_class2 = class {
|
|
4078
4582
|
|
|
4079
4583
|
|
|
4080
4584
|
/** The effects provider slot (see `setEffectsProvider`). */
|
|
4081
|
-
|
|
4585
|
+
__init8() {this.effects = new (0, _chunkJAOSL334cjs.EffectsSlot)()}
|
|
4586
|
+
/** Renders shot layer and transition pictures for frames (see `MotionLayersEngine`). */
|
|
4587
|
+
|
|
4082
4588
|
|
|
4083
4589
|
|
|
4084
|
-
|
|
4590
|
+
__init9() {this.selection = null}
|
|
4085
4591
|
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4592
|
+
__init10() {this.error = null}
|
|
4593
|
+
__init11() {this.revision = 0}
|
|
4594
|
+
__init12() {this.applying = false}
|
|
4089
4595
|
|
|
4090
|
-
|
|
4091
|
-
|
|
4596
|
+
__init13() {this.listeners = /* @__PURE__ */ new Set()}
|
|
4597
|
+
__init14() {this.unsubscribers = []}
|
|
4092
4598
|
|
|
4093
|
-
|
|
4094
|
-
constructor(options = {}) {;
|
|
4599
|
+
__init15() {this.recording = null}
|
|
4600
|
+
constructor(options = {}) {;_class2.prototype.__init8.call(this);_class2.prototype.__init9.call(this);_class2.prototype.__init10.call(this);_class2.prototype.__init11.call(this);_class2.prototype.__init12.call(this);_class2.prototype.__init13.call(this);_class2.prototype.__init14.call(this);_class2.prototype.__init15.call(this);_class2.prototype.__init16.call(this);_class2.prototype.__init17.call(this);
|
|
4095
4601
|
this.history = _nullishCoalesce(options.history, () => ( new (0, _chunkFJ2MSI43cjs.HistoryManager)()));
|
|
4096
4602
|
this.scene = options.scene ? parseMotionScene(options.scene) : createMotionScene(BLANK);
|
|
4097
4603
|
this.issues = checkMotionScene(this.scene);
|
|
4098
4604
|
this.readOnly = _nullishCoalesce(options.readOnly, () => ( false));
|
|
4099
4605
|
this.onChange = options.onChange;
|
|
4100
4606
|
if (options.effects) this.effects.set(options.effects);
|
|
4607
|
+
this.layers = new MotionLayersEngine({
|
|
4608
|
+
slot: this.effects,
|
|
4609
|
+
host: options.layerHost === void 0 ? browserMotionLayerHost() : options.layerHost,
|
|
4610
|
+
frameSvg: (scene, time) => motionFrameToSvg(scene, time, { effects: this.effects.provider, layers: this.layers, transitions: false, pretty: false })
|
|
4611
|
+
});
|
|
4101
4612
|
this.player = new (0, _chunkM5GLQQWGcjs.AnimationPlayer)({ clock: options.clock, duration: () => compileMotionScene(this.scene).duration, loop: _nullishCoalesce(this.scene.loop, () => ( "none")) });
|
|
4102
4613
|
this.state = this.computeState();
|
|
4103
4614
|
this.connect();
|
|
@@ -4109,7 +4620,8 @@ var AnimationEditorController = (_class = class {
|
|
|
4109
4620
|
this.history.subscribe(() => {
|
|
4110
4621
|
if (!this.applying) this.notify();
|
|
4111
4622
|
}),
|
|
4112
|
-
this.effects.subscribe(() => this.notify())
|
|
4623
|
+
this.effects.subscribe(() => this.notify()),
|
|
4624
|
+
this.layers.subscribe(() => this.notify())
|
|
4113
4625
|
);
|
|
4114
4626
|
}
|
|
4115
4627
|
/**
|
|
@@ -4121,8 +4633,8 @@ var AnimationEditorController = (_class = class {
|
|
|
4121
4633
|
this.player.pause();
|
|
4122
4634
|
this.unsubscribers.splice(0).forEach((u) => u());
|
|
4123
4635
|
}
|
|
4124
|
-
|
|
4125
|
-
|
|
4636
|
+
__init16() {this.getState = () => this.state}
|
|
4637
|
+
__init17() {this.subscribe = (listener) => {
|
|
4126
4638
|
this.connect();
|
|
4127
4639
|
this.listeners.add(listener);
|
|
4128
4640
|
return () => {
|
|
@@ -4145,7 +4657,7 @@ var AnimationEditorController = (_class = class {
|
|
|
4145
4657
|
time: p.time,
|
|
4146
4658
|
playing: p.playing,
|
|
4147
4659
|
loop: p.loop,
|
|
4148
|
-
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call',
|
|
4660
|
+
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _207 => _207(timeline, p.time), 'optionalAccess', _208 => _208.id]), () => ( null)),
|
|
4149
4661
|
selection: this.selection,
|
|
4150
4662
|
readOnly: this.readOnly,
|
|
4151
4663
|
error: this.error,
|
|
@@ -4193,7 +4705,7 @@ var AnimationEditorController = (_class = class {
|
|
|
4193
4705
|
this.applying = false;
|
|
4194
4706
|
}
|
|
4195
4707
|
this.notify();
|
|
4196
|
-
_optionalChain([this, 'access',
|
|
4708
|
+
_optionalChain([this, 'access', _209 => _209.onChange, 'optionalCall', _210 => _210(scene)]);
|
|
4197
4709
|
}
|
|
4198
4710
|
commit(label, next, merge) {
|
|
4199
4711
|
const before = this.scene;
|
|
@@ -4228,10 +4740,10 @@ var AnimationEditorController = (_class = class {
|
|
|
4228
4740
|
apply(edits, label = "Edit animation", options = {}) {
|
|
4229
4741
|
const reason = _nullishCoalesce(this.readOnlyReason(), () => ( (this.recording ? "A take is being recorded; stop or cancel the recording first." : null)));
|
|
4230
4742
|
if (reason) return this.refuse(reason);
|
|
4231
|
-
const
|
|
4232
|
-
if (!
|
|
4233
|
-
if (!options.dryRun) this.commit(label,
|
|
4234
|
-
return
|
|
4743
|
+
const result2 = applyMotionEdits(this.scene, edits);
|
|
4744
|
+
if (!result2.ok) return options.dryRun ? result2 : this.refuse(result2.error);
|
|
4745
|
+
if (!options.dryRun) this.commit(label, result2.scene, options.merge);
|
|
4746
|
+
return result2;
|
|
4235
4747
|
}
|
|
4236
4748
|
/** Replaces the artwork (e.g. from a vector editor's `onChange`), as one undo step. */
|
|
4237
4749
|
setArtwork(artwork, label = "Change artwork") {
|
|
@@ -4263,7 +4775,7 @@ var AnimationEditorController = (_class = class {
|
|
|
4263
4775
|
try {
|
|
4264
4776
|
plan = await work();
|
|
4265
4777
|
} catch (error) {
|
|
4266
|
-
if (
|
|
4778
|
+
if (_chunkJAOSL334cjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refuse(error.message);
|
|
4267
4779
|
throw error;
|
|
4268
4780
|
}
|
|
4269
4781
|
const r = this.apply({ op: "replace_scene", scene: plan.scene }, plan.label, { merge });
|
|
@@ -4274,17 +4786,17 @@ var AnimationEditorController = (_class = class {
|
|
|
4274
4786
|
}
|
|
4275
4787
|
async describeFor(effect, kinds) {
|
|
4276
4788
|
const provider = this.effects.require();
|
|
4277
|
-
if (!provider.applyVectorEffect) throw new (0,
|
|
4789
|
+
if (!provider.applyVectorEffect) throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)(`${provider.name} has no vector or motion effects.`);
|
|
4278
4790
|
const d = await provider.describe(effect);
|
|
4279
4791
|
if (!kinds.includes(d.kind)) {
|
|
4280
4792
|
const hint = d.kind === "motion" ? "apply it to nodes with apply_effect" : d.kind === "vector" ? "add it with add_vector_effect" : "it draws pixels, which scenes cannot hold";
|
|
4281
|
-
throw new (0,
|
|
4793
|
+
throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) is a ${d.kind} effect: ${hint}.`, d.id);
|
|
4282
4794
|
}
|
|
4283
4795
|
return d;
|
|
4284
4796
|
}
|
|
4285
4797
|
knownNodes(ids) {
|
|
4286
4798
|
const all = /* @__PURE__ */ new Set();
|
|
4287
|
-
const walk = (nodes) => nodes.forEach((
|
|
4799
|
+
const walk = (nodes) => nodes.forEach((n2) => (all.add(n2.id), n2.type === "group" && walk(n2.children)));
|
|
4288
4800
|
walk(this.scene.artwork.nodes);
|
|
4289
4801
|
const missing = ids.filter((id) => !all.has(id));
|
|
4290
4802
|
if (missing.length) throw new Error(`The artwork has no node ${missing.map((m) => `"${m}"`).join(", ")}; get_animation lists the node ids.`);
|
|
@@ -4299,7 +4811,7 @@ var AnimationEditorController = (_class = class {
|
|
|
4299
4811
|
return this.effectEdit(async () => {
|
|
4300
4812
|
this.knownNodes(targets);
|
|
4301
4813
|
const d = await this.describeFor(effect, ["motion"]);
|
|
4302
|
-
const values =
|
|
4814
|
+
const values = _chunkJAOSL334cjs.resolveEffectValues.call(void 0, d, options.values);
|
|
4303
4815
|
const instance = _nullishCoalesce(options.instance, () => ( nextMotionEffectInstance(this.scene)));
|
|
4304
4816
|
const motion = await this.effects.require().applyVectorEffect(d.id, { svg: motionArtworkSvg(this.scene.artwork), nodeIds: [...targets] }, values);
|
|
4305
4817
|
const source = { instance, effect: d.id, provider: this.effects.require().id, name: d.name, values };
|
|
@@ -4321,7 +4833,7 @@ var AnimationEditorController = (_class = class {
|
|
|
4321
4833
|
addVectorEffect(effect, options = {}) {
|
|
4322
4834
|
return this.effectEdit(async () => {
|
|
4323
4835
|
const d = await this.describeFor(effect, ["vector"]);
|
|
4324
|
-
const values =
|
|
4836
|
+
const values = _chunkJAOSL334cjs.resolveEffectValues.call(void 0, d, options.values);
|
|
4325
4837
|
const instance = _nullishCoalesce(options.instance, () => ( nextMotionEffectInstance(this.scene)));
|
|
4326
4838
|
const motion = await this.effects.require().applyVectorEffect(d.id, motionArtworkSvg(this.scene.artwork), values);
|
|
4327
4839
|
const source = { instance, effect: d.id, provider: this.effects.require().id, name: d.name, values };
|
|
@@ -4345,17 +4857,17 @@ var AnimationEditorController = (_class = class {
|
|
|
4345
4857
|
else if (k in d.controls.properties) base[k] = d.defaults[k];
|
|
4346
4858
|
else throw new Error(`"${k}" is not a control of "${d.id}"; its controls are ${Object.keys(d.controls.properties).join(", ")}.`);
|
|
4347
4859
|
}
|
|
4348
|
-
const merged = { ...base, ...
|
|
4860
|
+
const merged = { ...base, ..._chunkJAOSL334cjs.resolveEffectValues.call(void 0, { ...d, defaults: base }, given) };
|
|
4349
4861
|
const { scene: bare, place } = withoutMotionEffect(this.scene, instance);
|
|
4350
4862
|
const provider = this.effects.require();
|
|
4351
4863
|
const source = { instance, effect: d.id, provider: provider.id, name: d.name, values: merged };
|
|
4352
4864
|
if (was.kind === "vector") {
|
|
4353
|
-
const old = this.scene.artwork.nodes.find((
|
|
4865
|
+
const old = this.scene.artwork.nodes.find((n2) => n2.id === instance);
|
|
4354
4866
|
const motion2 = await provider.applyVectorEffect(d.id, motionArtworkSvg(bare.artwork), merged);
|
|
4355
4867
|
const { group, shots: shots2, notes: notes2 } = motionPartsFromVectorEffect(bare.artwork, motion2, source);
|
|
4356
|
-
const index = this.scene.artwork.nodes.findIndex((
|
|
4868
|
+
const index = this.scene.artwork.nodes.findIndex((n2) => n2.id === instance);
|
|
4357
4869
|
const nodes = [...bare.artwork.nodes];
|
|
4358
|
-
nodes.splice(Math.max(0, index), 0, _optionalChain([old, 'optionalAccess',
|
|
4870
|
+
nodes.splice(Math.max(0, index), 0, _optionalChain([old, 'optionalAccess', _211 => _211.transform]) ? { ...group, transform: old.transform } : group);
|
|
4359
4871
|
const at = this.scene.shots.findIndex((s) => was.shots.includes(s.id));
|
|
4360
4872
|
const kept = bare.shots;
|
|
4361
4873
|
const nextShots = [...kept.slice(0, Math.max(0, at)), ...shots2, ...kept.slice(Math.max(0, at))];
|
|
@@ -4366,7 +4878,7 @@ var AnimationEditorController = (_class = class {
|
|
|
4366
4878
|
let shots = bare.shots;
|
|
4367
4879
|
if (place && shots.some((s) => s.id === place.shot)) shots = shots.map((s) => s.id === place.shot ? { ...s, run: [...s.run.slice(0, place.index), ...commands, ...s.run.slice(place.index)] } : s);
|
|
4368
4880
|
else {
|
|
4369
|
-
const at = this.scene.shots.findIndex((s) => s.id === _optionalChain([place, 'optionalAccess',
|
|
4881
|
+
const at = this.scene.shots.findIndex((s) => s.id === _optionalChain([place, 'optionalAccess', _212 => _212.shot]));
|
|
4370
4882
|
shots = [...shots.slice(0, Math.max(0, at)), { id: instance, label: d.name, run: commands }, ...shots.slice(Math.max(0, at))];
|
|
4371
4883
|
}
|
|
4372
4884
|
return { scene: { ...bare, shots }, label: `Change ${d.name}`, instance, notes };
|
|
@@ -4400,12 +4912,12 @@ var AnimationEditorController = (_class = class {
|
|
|
4400
4912
|
if (!found) return this.refuse(`There is no shot "${shot}"; the shots are ${this.scene.shots.map((s) => `"${s.id}"`).join(", ") || "none yet"}.`);
|
|
4401
4913
|
let resolved;
|
|
4402
4914
|
try {
|
|
4403
|
-
resolved = await
|
|
4915
|
+
resolved = await _chunkJAOSL334cjs.resolveCameraMoveSpec.call(void 0, this.effects.require(), spec, role);
|
|
4404
4916
|
} catch (error) {
|
|
4405
|
-
if (
|
|
4917
|
+
if (_chunkJAOSL334cjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refuse(error.message);
|
|
4406
4918
|
throw error;
|
|
4407
4919
|
}
|
|
4408
|
-
const field =
|
|
4920
|
+
const field = _chunkJAOSL334cjs.cameraMoveField.call(void 0, role);
|
|
4409
4921
|
const current = this.scene.shots.find((s) => s.id === shot);
|
|
4410
4922
|
if (!current) return this.refuse(`Shot "${shot}" was removed while the move was checked.`);
|
|
4411
4923
|
const parts = role === "transition" && resolved.spec.ms === void 0 ? { ...resolved.spec, ms: resolved.description.camera.durationMs } : resolved.spec;
|
|
@@ -4419,8 +4931,8 @@ var AnimationEditorController = (_class = class {
|
|
|
4419
4931
|
clearShotCameraMove(shot, role) {
|
|
4420
4932
|
const found = this.scene.shots.find((s) => s.id === shot);
|
|
4421
4933
|
if (!found) return this.refuse(`There is no shot "${shot}"; the shots are ${this.scene.shots.map((s) => `"${s.id}"`).join(", ") || "none yet"}.`);
|
|
4422
|
-
const field =
|
|
4423
|
-
if (_optionalChain([found, 'access',
|
|
4934
|
+
const field = _chunkJAOSL334cjs.cameraMoveField.call(void 0, role);
|
|
4935
|
+
if (_optionalChain([found, 'access', _213 => _213.camera, 'optionalAccess', _214 => _214[field]]) === void 0) return this.refuse(`Shot "${shot}" has no camera "${field}" move to clear${_optionalChain([found, 'access', _215 => _215.camera, 'optionalAccess', _216 => _216[field === "in" ? "during" : "in"]]) !== void 0 ? `; it has a "${field === "in" ? "during" : "in"}" move (role ${role === "hold" ? "transition" : "hold"})` : ""}.`);
|
|
4424
4936
|
const rest = { ...found.camera };
|
|
4425
4937
|
delete rest[field];
|
|
4426
4938
|
const keep = motionCameraFramed(rest) || rest.in !== void 0 || rest.during !== void 0;
|
|
@@ -4430,7 +4942,7 @@ var AnimationEditorController = (_class = class {
|
|
|
4430
4942
|
}
|
|
4431
4943
|
cameraMoveResult(shot, role, move) {
|
|
4432
4944
|
const timing = compileMotionScene(this.scene).shots.find((s) => s.id === shot);
|
|
4433
|
-
const camera = _nullishCoalesce(_optionalChain([this, 'access',
|
|
4945
|
+
const camera = _nullishCoalesce(_optionalChain([this, 'access', _217 => _217.scene, 'access', _218 => _218.shots, 'access', _219 => _219.find, 'call', _220 => _220((s) => s.id === shot), 'optionalAccess', _221 => _221.camera]), () => ( null));
|
|
4434
4946
|
const window = role === "transition" ? { start: timing.start, end: timing.commandsStart } : { start: timing.commandsEnd, end: timing.end };
|
|
4435
4947
|
const notes = [];
|
|
4436
4948
|
if (move && role === "transition" && timing.index === 0) notes.push('This is the first shot, which cuts to its framing, so its "in" move does not play; it plays from the second shot on.');
|
|
@@ -4501,7 +5013,7 @@ var AnimationEditorController = (_class = class {
|
|
|
4501
5013
|
viewScene() {
|
|
4502
5014
|
const r = this.recording;
|
|
4503
5015
|
if (!r) return this.scene;
|
|
4504
|
-
if (_optionalChain([r, 'access',
|
|
5016
|
+
if (_optionalChain([r, 'access', _222 => _222.preview, 'optionalAccess', _223 => _223.count]) === r.samples.length) return r.preview.scene;
|
|
4505
5017
|
let scene = this.scene;
|
|
4506
5018
|
if (r.samples.length) {
|
|
4507
5019
|
try {
|
|
@@ -4517,9 +5029,151 @@ var AnimationEditorController = (_class = class {
|
|
|
4517
5029
|
frame(time = this.player.currentTime, options = {}) {
|
|
4518
5030
|
return motionFrameAt(this.viewScene(), time, { effects: this.effects.provider, ...options });
|
|
4519
5031
|
}
|
|
4520
|
-
/**
|
|
5032
|
+
/**
|
|
5033
|
+
* The scene at `time` (default: the playhead) as SVG. Shot layer and transition pictures that
|
|
5034
|
+
* are not rendered yet are left out (a transition crossfades) and come in on a later frame;
|
|
5035
|
+
* `toSvgExact` waits for them.
|
|
5036
|
+
*/
|
|
4521
5037
|
toSvg(time = this.player.currentTime, options = {}) {
|
|
4522
|
-
return motionStageSvg(this.viewScene(), time, { effects: this.effects.provider, ...options });
|
|
5038
|
+
return motionStageSvg(this.viewScene(), time, { effects: this.effects.provider, layers: this.layers, ...options });
|
|
5039
|
+
}
|
|
5040
|
+
/** Like `toSvg`, once every shot layer and transition picture of the frame is rendered (or has failed). */
|
|
5041
|
+
async toSvgExact(time = this.player.currentTime, options = {}) {
|
|
5042
|
+
let svg = this.toSvg(time, options);
|
|
5043
|
+
for (let pass = 0; pass < 8 && this.layers.busy; pass++) {
|
|
5044
|
+
await this.layers.idle();
|
|
5045
|
+
svg = this.toSvg(time, options);
|
|
5046
|
+
}
|
|
5047
|
+
return svg;
|
|
5048
|
+
}
|
|
5049
|
+
// ---------------------------------------------------------------------------------------
|
|
5050
|
+
// Shot layers and transitions
|
|
5051
|
+
// ---------------------------------------------------------------------------------------
|
|
5052
|
+
/** Every shot's layers and transition (or one shot's). Throws for an unknown shot, naming the shots. */
|
|
5053
|
+
shotLayers(shot) {
|
|
5054
|
+
if (shot !== void 0 && !this.scene.shots.some((s) => s.id === shot)) throw new Error(this.noShot(shot));
|
|
5055
|
+
return motionShotLayersInfo(this.scene, shot);
|
|
5056
|
+
}
|
|
5057
|
+
noShot(shot) {
|
|
5058
|
+
return `There is no shot "${shot}"; the shots are ${this.scene.shots.map((s) => `"${s.id}"`).join(", ") || "none yet"}.`;
|
|
5059
|
+
}
|
|
5060
|
+
noLayer(layer) {
|
|
5061
|
+
const ids = this.scene.shots.flatMap((s) => (_nullishCoalesce(s.layers, () => ( []))).map((l) => `"${l.id}"`));
|
|
5062
|
+
return `There is no layer "${layer}"; ${ids.length ? `the layers are ${ids.join(", ")}` : "the scene has no layers yet (add_shot_layer adds one)"}.`;
|
|
5063
|
+
}
|
|
5064
|
+
layerResult(shot, layerId, notes = []) {
|
|
5065
|
+
const info2 = motionShotLayersInfo(this.scene, shot)[0];
|
|
5066
|
+
const layer = layerId ? info2.layers.find((l) => l.id === layerId) : void 0;
|
|
5067
|
+
return { ok: true, ...info2, ...layer ? { layer } : {}, notes };
|
|
5068
|
+
}
|
|
5069
|
+
async layerEdit(work, merge) {
|
|
5070
|
+
const reason = this.readOnlyReason();
|
|
5071
|
+
if (reason) return this.refuse(reason);
|
|
5072
|
+
let plan;
|
|
5073
|
+
try {
|
|
5074
|
+
plan = await work();
|
|
5075
|
+
} catch (error) {
|
|
5076
|
+
if (_chunkJAOSL334cjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refuse(error.message);
|
|
5077
|
+
throw error;
|
|
5078
|
+
}
|
|
5079
|
+
const id = this.scene.shots[plan.shot].id;
|
|
5080
|
+
const r = this.apply(plan.layers.length ? { op: "update_shot", shot: id, set: { layers: plan.layers } } : { op: "update_shot", shot: id, remove: ["layers"] }, plan.label, { merge });
|
|
5081
|
+
if (!r.ok) return r;
|
|
5082
|
+
return this.layerResult(id, plan.layer, plan.notes);
|
|
5083
|
+
}
|
|
5084
|
+
/**
|
|
5085
|
+
* Adds a layer to a shot: a provider effect (a generator, filter, overlay or title), optionally
|
|
5086
|
+
* applied to a `subject`, or a bare subject. Checked against the provider first; at `index`
|
|
5087
|
+
* (default the top). One undo step. Returns the layer (with its id) and the shot's layers.
|
|
5088
|
+
*/
|
|
5089
|
+
addShotLayer(shot, layer, options = {}) {
|
|
5090
|
+
return this.layerEdit(async () => {
|
|
5091
|
+
const at = this.scene.shots.findIndex((s) => s.id === shot);
|
|
5092
|
+
if (at < 0) throw new Error(this.noShot(shot));
|
|
5093
|
+
const id = _nullishCoalesce(layer.id, () => ( freshMotionLayerId(this.scene)));
|
|
5094
|
+
if (findMotionShotLayer(this.scene, id)) throw new Error(`Layer id "${id}" is already used; choose another (e.g. "${freshMotionLayerId(this.scene)}").`);
|
|
5095
|
+
const resolved = await resolveMotionShotLayer(this.effects.provider, { ...layer, id });
|
|
5096
|
+
const layers = [..._nullishCoalesce(this.scene.shots[at].layers, () => ( []))];
|
|
5097
|
+
const index = _nullishCoalesce(options.index, () => ( layers.length));
|
|
5098
|
+
if (!Number.isInteger(index) || index < 0 || index > layers.length) throw new Error(`"index" must be a whole number from 0 to ${layers.length} (got ${index}).`);
|
|
5099
|
+
layers.splice(index, 0, resolved);
|
|
5100
|
+
const notes = resolved.subject && "slot" in resolved.subject ? [`The subject is slot "${resolved.subject.slot}", which draws nothing until it is filled; set "subject" with update_shot_layer.`] : [];
|
|
5101
|
+
return { shot: at, layers, label: `Add layer ${_nullishCoalesce(resolved.name, () => ( id))}`, layer: id, notes };
|
|
5102
|
+
});
|
|
5103
|
+
}
|
|
5104
|
+
/** Changes a layer's fields (`null` clears an optional one); the result is checked against the provider. One undo step (`merge` folds a slider drag into one). */
|
|
5105
|
+
updateShotLayer(layer, changes, options = {}) {
|
|
5106
|
+
return this.layerEdit(async () => {
|
|
5107
|
+
const found = findMotionShotLayer(this.scene, layer);
|
|
5108
|
+
if (!found) throw new Error(this.noLayer(layer));
|
|
5109
|
+
const was = this.scene.shots[found.shot].layers[found.index];
|
|
5110
|
+
const next = { ...was };
|
|
5111
|
+
for (const [k, v] of Object.entries(changes)) {
|
|
5112
|
+
if (v === null) delete next[k];
|
|
5113
|
+
else if (v !== void 0) next[k] = v;
|
|
5114
|
+
}
|
|
5115
|
+
if (changes.effect !== void 0 && changes.effect !== was.effect && changes.values === void 0) delete next.values;
|
|
5116
|
+
const resolved = await resolveMotionShotLayer(this.effects.provider, next);
|
|
5117
|
+
const layers = this.scene.shots[found.shot].layers.map((l, i) => i === found.index ? resolved : l);
|
|
5118
|
+
return { shot: found.shot, layers, label: `Change layer ${_nullishCoalesce(resolved.name, () => ( layer))}`, layer };
|
|
5119
|
+
}, options.merge);
|
|
5120
|
+
}
|
|
5121
|
+
/** Removes a layer. One undo step. Works without a provider. */
|
|
5122
|
+
removeShotLayer(layer) {
|
|
5123
|
+
return this.layerEdit(async () => {
|
|
5124
|
+
const found = findMotionShotLayer(this.scene, layer);
|
|
5125
|
+
if (!found) throw new Error(this.noLayer(layer));
|
|
5126
|
+
const layers = this.scene.shots[found.shot].layers.filter((_, i) => i !== found.index);
|
|
5127
|
+
return { shot: found.shot, layers, label: "Remove layer" };
|
|
5128
|
+
});
|
|
5129
|
+
}
|
|
5130
|
+
/** Moves a layer to `index` in its shot (0 = bottom). One undo step. */
|
|
5131
|
+
moveShotLayer(layer, index) {
|
|
5132
|
+
return this.layerEdit(async () => {
|
|
5133
|
+
const found = findMotionShotLayer(this.scene, layer);
|
|
5134
|
+
if (!found) throw new Error(this.noLayer(layer));
|
|
5135
|
+
const layers = [...this.scene.shots[found.shot].layers];
|
|
5136
|
+
if (!Number.isInteger(index) || index < 0 || index >= layers.length) throw new Error(`"index" must be a whole number from 0 to ${layers.length - 1} (got ${index}).`);
|
|
5137
|
+
const [moved] = layers.splice(found.index, 1);
|
|
5138
|
+
layers.splice(index, 0, moved);
|
|
5139
|
+
return { shot: found.shot, layers, label: "Move layer", layer };
|
|
5140
|
+
});
|
|
5141
|
+
}
|
|
5142
|
+
/**
|
|
5143
|
+
* Sets the provider transition into a shot from the shot before (not the first shot). Checked
|
|
5144
|
+
* against the provider (its use, preset and values; its length is written out). With no camera
|
|
5145
|
+
* move in, the camera cuts. One undo step (`merge` folds a slider drag into one).
|
|
5146
|
+
*/
|
|
5147
|
+
async setShotTransition(shot, transition, options = {}) {
|
|
5148
|
+
const reason = this.readOnlyReason();
|
|
5149
|
+
if (reason) return this.refuse(reason);
|
|
5150
|
+
const at = this.scene.shots.findIndex((s) => s.id === shot);
|
|
5151
|
+
if (at < 0) return this.refuse(this.noShot(shot));
|
|
5152
|
+
if (at === 0) return this.refuse(`Shot "${shot}" is the first shot, so there is no shot before it to transition from; set the transition on a later shot${this.scene.shots[1] ? ` (e.g. "${this.scene.shots[1].id}")` : ""}.`);
|
|
5153
|
+
let resolved;
|
|
5154
|
+
try {
|
|
5155
|
+
const { provider: _p, name: _n, ...given } = transition;
|
|
5156
|
+
resolved = await resolveMotionShotTransition(this.effects.provider, given);
|
|
5157
|
+
} catch (error) {
|
|
5158
|
+
if (_chunkJAOSL334cjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refuse(error.message);
|
|
5159
|
+
throw error;
|
|
5160
|
+
}
|
|
5161
|
+
if (!this.scene.shots.some((s) => s.id === shot)) return this.refuse(`Shot "${shot}" was removed while the transition was checked.`);
|
|
5162
|
+
const r = this.apply({ op: "update_shot", shot, set: { transition: resolved } }, `Transition ${_nullishCoalesce(resolved.name, () => ( resolved.effect))}`, { merge: options.merge });
|
|
5163
|
+
if (!r.ok) return r;
|
|
5164
|
+
const camera = this.scene.shots.find((s) => s.id === shot).camera;
|
|
5165
|
+
return this.layerResult(shot, void 0, _optionalChain([camera, 'optionalAccess', _224 => _224.in]) === void 0 ? ["With no camera move in, the camera cuts to this shot's framing and the transition does the move."] : []);
|
|
5166
|
+
}
|
|
5167
|
+
/** Removes a shot's transition. One undo step. Works without a provider. */
|
|
5168
|
+
clearShotTransition(shot) {
|
|
5169
|
+
const reason = this.readOnlyReason();
|
|
5170
|
+
if (reason) return this.refuse(reason);
|
|
5171
|
+
const found = this.scene.shots.find((s) => s.id === shot);
|
|
5172
|
+
if (!found) return this.refuse(this.noShot(shot));
|
|
5173
|
+
if (!found.transition) return this.refuse(`Shot "${shot}" has no transition to clear.`);
|
|
5174
|
+
const r = this.apply({ op: "update_shot", shot, remove: ["transition"] }, "Clear transition");
|
|
5175
|
+
if (!r.ok) return r;
|
|
5176
|
+
return this.layerResult(shot, void 0);
|
|
4523
5177
|
}
|
|
4524
5178
|
// ---------------------------------------------------------------------------------------
|
|
4525
5179
|
// Recording
|
|
@@ -4568,8 +5222,8 @@ var AnimationEditorController = (_class = class {
|
|
|
4568
5222
|
return motionNodePose(this.viewScene(), node, time);
|
|
4569
5223
|
}
|
|
4570
5224
|
/** A point on a stage element (client pixels, e.g. a pointer event) in document units, through the camera now. */
|
|
4571
|
-
clientToDocument(
|
|
4572
|
-
return motionClientToDocument(this.frame().camera,
|
|
5225
|
+
clientToDocument(box2, clientX, clientY) {
|
|
5226
|
+
return motionClientToDocument(this.frame().camera, box2, clientX, clientY);
|
|
4573
5227
|
}
|
|
4574
5228
|
/**
|
|
4575
5229
|
* Starts a stage drag while recording: from `point` (document units), `move` drags the node,
|
|
@@ -4586,13 +5240,13 @@ var AnimationEditorController = (_class = class {
|
|
|
4586
5240
|
}
|
|
4587
5241
|
/** Records the drag's pose with the pointer at `point` (document units). */
|
|
4588
5242
|
updateRecordGesture(point) {
|
|
4589
|
-
const g = _optionalChain([this, 'access',
|
|
5243
|
+
const g = _optionalChain([this, 'access', _225 => _225.recording, 'optionalAccess', _226 => _226.gesture]);
|
|
4590
5244
|
if (g) this.recordGesture(g.pose, point);
|
|
4591
5245
|
}
|
|
4592
5246
|
/** Ends the stage drag (the take keeps recording). */
|
|
4593
5247
|
endRecordGesture() {
|
|
4594
5248
|
const r = this.recording;
|
|
4595
|
-
if (!_optionalChain([r, 'optionalAccess',
|
|
5249
|
+
if (!_optionalChain([r, 'optionalAccess', _227 => _227.gesture])) return;
|
|
4596
5250
|
r.gesture = null;
|
|
4597
5251
|
this.notify();
|
|
4598
5252
|
}
|
|
@@ -4606,7 +5260,7 @@ var AnimationEditorController = (_class = class {
|
|
|
4606
5260
|
this.recordSample(g.node, { scaleX: Math.max(0.01, pose.scaleX * f), scaleY: Math.max(0.01, pose.scaleY * f) });
|
|
4607
5261
|
} else {
|
|
4608
5262
|
const turn = (Math.atan2(point.y - c.y, point.x - c.x) - Math.atan2(g.from.y - c.y, g.from.x - c.x)) * (180 / Math.PI);
|
|
4609
|
-
const was = _nullishCoalesce(_optionalChain([this, 'access',
|
|
5263
|
+
const was = _nullishCoalesce(_optionalChain([this, 'access', _228 => _228.recording, 'access', _229 => _229.samples, 'access', _230 => _230.filter, 'call', _231 => _231((s) => s.node === g.node && s.rotation !== void 0), 'access', _232 => _232.at, 'call', _233 => _233(-1), 'optionalAccess', _234 => _234.rotation]), () => ( pose.rotation));
|
|
4610
5264
|
let next = pose.rotation + turn;
|
|
4611
5265
|
next += 360 * Math.round((was - next) / 360);
|
|
4612
5266
|
this.recordSample(g.node, { rotation: next });
|
|
@@ -4633,9 +5287,9 @@ var AnimationEditorController = (_class = class {
|
|
|
4633
5287
|
this.player.seek(r.start);
|
|
4634
5288
|
return this.refuse("Nothing was recorded, so no shot was added: drag an element on the stage (or change its paint) while recording.");
|
|
4635
5289
|
}
|
|
4636
|
-
const
|
|
5290
|
+
const result2 = this.recordTake({ samples: r.samples, length }, r.options);
|
|
4637
5291
|
this.player.seek(r.start);
|
|
4638
|
-
return
|
|
5292
|
+
return result2;
|
|
4639
5293
|
}
|
|
4640
5294
|
/** Stops recording and throws the take away. */
|
|
4641
5295
|
cancelRecording() {
|
|
@@ -4655,10 +5309,10 @@ var AnimationEditorController = (_class = class {
|
|
|
4655
5309
|
} catch (error) {
|
|
4656
5310
|
return options.dryRun ? { ok: false, error: error.message } : this.refuse(error.message);
|
|
4657
5311
|
}
|
|
4658
|
-
const
|
|
4659
|
-
if (!
|
|
5312
|
+
const result2 = this.apply({ op: "insert_shots", shots: [made.shot], at: made.at }, "Record take", { dryRun: options.dryRun });
|
|
5313
|
+
if (!result2.ok) return result2;
|
|
4660
5314
|
if (!options.dryRun) this.select({ shot: made.shot.id });
|
|
4661
|
-
return { ok: true, ...made, issues:
|
|
5315
|
+
return { ok: true, ...made, issues: result2.issues };
|
|
4662
5316
|
}
|
|
4663
5317
|
/** The scene as a Flair `SvgMotion`. */
|
|
4664
5318
|
toFlairMotion(options = {}) {
|
|
@@ -4672,7 +5326,7 @@ var AnimationEditorController = (_class = class {
|
|
|
4672
5326
|
toFlairDocument(options = {}) {
|
|
4673
5327
|
return toFlairEffectDocument(this.scene, { effects: this.effects.provider, ...options });
|
|
4674
5328
|
}
|
|
4675
|
-
},
|
|
5329
|
+
}, _class2);
|
|
4676
5330
|
|
|
4677
5331
|
// src/animation-editor/playback.ts
|
|
4678
5332
|
var str = (v) => typeof v === "string" && v.length > 0;
|
|
@@ -4700,7 +5354,7 @@ function elementsOf(args) {
|
|
|
4700
5354
|
if (Array.isArray(args.ops)) {
|
|
4701
5355
|
for (const op of args.ops) {
|
|
4702
5356
|
fromShot(op);
|
|
4703
|
-
if (Array.isArray(_optionalChain([op, 'optionalAccess',
|
|
5357
|
+
if (Array.isArray(_optionalChain([op, 'optionalAccess', _235 => _235.shots]))) op.shots.forEach(fromShot);
|
|
4704
5358
|
}
|
|
4705
5359
|
}
|
|
4706
5360
|
return out.slice(0, 4);
|
|
@@ -4882,7 +5536,7 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
4882
5536
|
oneOf: MOTION_COMMAND_TYPES.map((type) => MOTION_COMMAND_TYPE_SCHEMAS[type])
|
|
4883
5537
|
};
|
|
4884
5538
|
var REF2 = (name, description) => ({ $ref: `#/$defs/${name}`, ...description ? { description } : {} });
|
|
4885
|
-
var firstSentence = (text) => _nullishCoalesce(_optionalChain([/^.*?[.;](?=\s|$)/, 'access',
|
|
5539
|
+
var firstSentence = (text) => _nullishCoalesce(_optionalChain([/^.*?[.;](?=\s|$)/, 'access', _236 => _236.exec, 'call', _237 => _237(text), 'optionalAccess', _238 => _238[0]]), () => ( text));
|
|
4886
5540
|
var COMMAND_TYPE_LINES = MOTION_COMMAND_TYPES.map((type) => `${type}: ${firstSentence(_nullishCoalesce(MOTION_COMMAND_TYPE_SCHEMAS[type].description, () => ( "")))}`);
|
|
4887
5541
|
var EASE_COMPACT = {
|
|
4888
5542
|
description: `Easing: a preset, or a curve { "type": "cubic-bezier", x1, y1, x2, y2 }, { "type": "spring", stiffness, damping, mass, velocity } (spring presets are Figma's; with no "duration" it lasts until it settles) or { "type": "elastic", amplitude, period, mode }. Default: ease-out for entrances, ease-in-out for moves.`,
|
|
@@ -5019,7 +5673,7 @@ function withDefs(schema) {
|
|
|
5019
5673
|
};
|
|
5020
5674
|
visit(schema);
|
|
5021
5675
|
if (!used.size) return schema;
|
|
5022
|
-
return { ...schema, $defs: Object.fromEntries(Object.keys(DEFS).filter((
|
|
5676
|
+
return { ...schema, $defs: Object.fromEntries(Object.keys(DEFS).filter((n2) => used.has(n2)).map((n2) => [n2, DEFS[n2]])) };
|
|
5023
5677
|
}
|
|
5024
5678
|
var SETTINGS = {
|
|
5025
5679
|
name: { type: "string", minLength: 1, description: 'Short name, e.g. "logo-reveal".' },
|
|
@@ -5084,7 +5738,7 @@ function describeElement(node, ancestors) {
|
|
|
5084
5738
|
...effects.length ? { effects } : {}
|
|
5085
5739
|
};
|
|
5086
5740
|
}
|
|
5087
|
-
var round3 = (
|
|
5741
|
+
var round3 = (n2) => Math.round(n2 * 10) / 10;
|
|
5088
5742
|
function describeMotionElements(scene) {
|
|
5089
5743
|
return [...indexMotionNodes(scene.artwork.nodes).values()].map((e) => ({
|
|
5090
5744
|
...describeElement(e.node, e.ancestors),
|
|
@@ -5116,7 +5770,7 @@ var issueSummary = (issues) => ({
|
|
|
5116
5770
|
errors: issues.filter((i) => i.severity === "error").length,
|
|
5117
5771
|
warnings: issues.filter((i) => i.severity === "warning").length,
|
|
5118
5772
|
notes: issues.filter((i) => i.severity === "note").length,
|
|
5119
|
-
lines: issues.map((i) => `${i.severity}: ${
|
|
5773
|
+
lines: issues.map((i) => `${i.severity}: ${_chunkDGWOGQJ5cjs.motionIssueLine.call(void 0, i)}`)
|
|
5120
5774
|
});
|
|
5121
5775
|
function createAnimationEditorToolProvider(controller, options = {}) {
|
|
5122
5776
|
const readOnlyReason = () => {
|
|
@@ -5125,20 +5779,20 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5125
5779
|
return controller.readOnlyReason();
|
|
5126
5780
|
};
|
|
5127
5781
|
const scene = () => controller.getScene();
|
|
5128
|
-
const outcome = (
|
|
5129
|
-
if (!
|
|
5130
|
-
const timeline = compileMotionScene(
|
|
5782
|
+
const outcome = (result2, extra = {}) => {
|
|
5783
|
+
if (!result2.ok) throw new Error(result2.error);
|
|
5784
|
+
const timeline = compileMotionScene(result2.scene);
|
|
5131
5785
|
return {
|
|
5132
5786
|
...extra,
|
|
5133
5787
|
duration: timeline.duration,
|
|
5134
5788
|
shots: timeline.shots.map((s) => ({ id: s.id, start: s.start, end: s.end })),
|
|
5135
|
-
issues: issueSummary(
|
|
5136
|
-
...
|
|
5789
|
+
issues: issueSummary(result2.issues),
|
|
5790
|
+
...result2.hints.length ? { hints: result2.hints } : {}
|
|
5137
5791
|
};
|
|
5138
5792
|
};
|
|
5139
5793
|
const apply = (edits, label, extra) => {
|
|
5140
|
-
const
|
|
5141
|
-
return outcome(
|
|
5794
|
+
const result2 = controller.apply(edits, label);
|
|
5795
|
+
return outcome(result2, result2.ok && extra ? extra(result2.scene) : {});
|
|
5142
5796
|
};
|
|
5143
5797
|
const getAnimation = {
|
|
5144
5798
|
name: "get_animation",
|
|
@@ -5180,7 +5834,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5180
5834
|
annotations: { title: "Describe command types", ...READ },
|
|
5181
5835
|
handler: ({ types }) => {
|
|
5182
5836
|
for (const type of types)
|
|
5183
|
-
if (!MOTION_COMMAND_TYPES.includes(type)) throw new Error(`There is no command type ${
|
|
5837
|
+
if (!MOTION_COMMAND_TYPES.includes(type)) throw new Error(`There is no command type ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, type, MOTION_COMMAND_TYPES)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`);
|
|
5184
5838
|
return { commands: types.map((type) => ({ type, schema: MOTION_COMMAND_TYPE_SCHEMAS[type] })) };
|
|
5185
5839
|
}
|
|
5186
5840
|
};
|
|
@@ -5253,7 +5907,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5253
5907
|
}
|
|
5254
5908
|
if (Array.isArray(motion_paths)) {
|
|
5255
5909
|
const known = new Set(describeMotionElements(s).map((e) => e.id));
|
|
5256
|
-
for (const id of motion_paths) if (!known.has(id)) throw new Error(`There is no element ${
|
|
5910
|
+
for (const id of motion_paths) if (!known.has(id)) throw new Error(`There is no element ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, id, known)} to draw a motion path for.`);
|
|
5257
5911
|
}
|
|
5258
5912
|
const overlays = { ...onion_skin ? { onionSkin: onion_skin } : {}, ...motion_paths ? { motionPaths: motion_paths } : {} };
|
|
5259
5913
|
if (times) {
|
|
@@ -5266,7 +5920,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5266
5920
|
}
|
|
5267
5921
|
return { times, svg: sheet };
|
|
5268
5922
|
}
|
|
5269
|
-
const svg = controller.
|
|
5923
|
+
const svg = await controller.toSvgExact(t, { pretty: false, ...overlays });
|
|
5270
5924
|
if (format === "png") {
|
|
5271
5925
|
if (!options.rasterize) throw new Error('This host cannot make PNG images; call render_animation_frame with format "svg".');
|
|
5272
5926
|
const image = await options.rasterize(svg, { width: s.artwork.width, height: s.artwork.height });
|
|
@@ -5291,9 +5945,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5291
5945
|
handler: ({ from = 0, to, limit = 200 }) => {
|
|
5292
5946
|
const s = scene();
|
|
5293
5947
|
const timeline = compileMotionScene(s);
|
|
5294
|
-
const words = _nullishCoalesce(_optionalChain([s, 'access',
|
|
5948
|
+
const words = _nullishCoalesce(_optionalChain([s, 'access', _239 => _239.narration, 'optionalAccess', _240 => _240.words]), () => ( []));
|
|
5295
5949
|
const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
|
|
5296
|
-
const shotAt = (ms2) => _optionalChain([timeline, 'access',
|
|
5950
|
+
const shotAt = (ms2) => _optionalChain([timeline, 'access', _241 => _241.shots, 'access', _242 => _242.find, 'call', _243 => _243((x) => ms2 >= x.start && ms2 < x.end), 'optionalAccess', _244 => _244.id]);
|
|
5297
5951
|
const beats = [];
|
|
5298
5952
|
if (s.beat && s.beat.bpm > 0) {
|
|
5299
5953
|
const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
|
|
@@ -5323,10 +5977,10 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5323
5977
|
handler: ({ group }) => {
|
|
5324
5978
|
const s = scene();
|
|
5325
5979
|
const nodes = indexMotionNodes(s.artwork.nodes);
|
|
5326
|
-
if (!nodes.has(group)) throw new Error(`There is no element ${
|
|
5980
|
+
if (!nodes.has(group)) throw new Error(`There is no element ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, group, [...nodes.keys()])}.`);
|
|
5327
5981
|
const layout = motionTextLayout(nodes, group);
|
|
5328
5982
|
if (!layout) throw new Error(`"${group}" is not a group of paths; convert the text to outlines (one path a letter) and group it.`);
|
|
5329
|
-
return { group, letters: layout.lines.reduce((
|
|
5983
|
+
return { group, letters: layout.lines.reduce((n2, l) => n2 + l.words.reduce((m, w) => m + w.letters.length, 0), 0), ...layout };
|
|
5330
5984
|
}
|
|
5331
5985
|
};
|
|
5332
5986
|
const getMotionPath = {
|
|
@@ -5343,7 +5997,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5343
5997
|
handler: ({ node, from, to, step }) => {
|
|
5344
5998
|
const s = scene();
|
|
5345
5999
|
const ids = describeMotionElements(s).map((e) => e.id);
|
|
5346
|
-
if (!ids.includes(node)) throw new Error(`There is no element ${
|
|
6000
|
+
if (!ids.includes(node)) throw new Error(`There is no element ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, node, ids)}.`);
|
|
5347
6001
|
return motionPath(s, node, { from, to, step });
|
|
5348
6002
|
}
|
|
5349
6003
|
};
|
|
@@ -5415,17 +6069,17 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5415
6069
|
),
|
|
5416
6070
|
annotations: { title: "Import a PowerPoint slide's animation", ...DESTRUCTIVE },
|
|
5417
6071
|
handler: async ({ data, slide, dry_run = false }) => {
|
|
5418
|
-
let
|
|
6072
|
+
let result2;
|
|
5419
6073
|
try {
|
|
5420
6074
|
const bytes = Uint8Array.from(atob(data.replace(/\s+/g, "")), (c) => c.charCodeAt(0));
|
|
5421
|
-
|
|
6075
|
+
result2 = await fromPptxAnimation(bytes, slide ? { slide } : {});
|
|
5422
6076
|
} catch (error) {
|
|
5423
6077
|
throw new Error(`The slide could not be imported: ${error.message} Nothing was changed.`);
|
|
5424
6078
|
}
|
|
5425
|
-
const report = { slides:
|
|
6079
|
+
const report = { slides: result2.slides, notes: result2.notes, issues: issueSummary(result2.issues), shots: describeMotionShots(result2.scene).map(({ id, start, end, commands }) => ({ id, start, end, commands: commands.length })) };
|
|
5426
6080
|
if (dry_run) return { dry_run: true, ...report, hint: "Nothing was replaced; call again without dry_run to import." };
|
|
5427
|
-
const applied = controller.apply({ op: "replace_scene", scene:
|
|
5428
|
-
return outcome(applied, applied.ok ? { ...report, elements: describeMotionElements(
|
|
6081
|
+
const applied = controller.apply({ op: "replace_scene", scene: result2.scene }, "Import PowerPoint slide");
|
|
6082
|
+
return outcome(applied, applied.ok ? { ...report, elements: describeMotionElements(result2.scene) } : {});
|
|
5429
6083
|
}
|
|
5430
6084
|
};
|
|
5431
6085
|
const importFlairEffect = {
|
|
@@ -5444,16 +6098,16 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5444
6098
|
annotations: { title: "Import a Flair effect", ...DESTRUCTIVE },
|
|
5445
6099
|
handler: ({ effect, motion, name, dry_run = false }) => {
|
|
5446
6100
|
if (effect === void 0 === (motion === void 0)) throw new Error('Give exactly one of "effect" (a Flair vector effect) or "motion" (a Flair SvgMotion). Nothing was changed.');
|
|
5447
|
-
let
|
|
6101
|
+
let result2;
|
|
5448
6102
|
try {
|
|
5449
|
-
|
|
6103
|
+
result2 = effect !== void 0 ? fromFlairVectorEffect(effect, name ? { name } : {}) : fromFlairSvgMotion(motion, name ? { name } : {});
|
|
5450
6104
|
} catch (error) {
|
|
5451
6105
|
throw new Error(`The Flair effect could not be imported: ${error.message} Nothing was changed.`);
|
|
5452
6106
|
}
|
|
5453
|
-
const report = { notes:
|
|
6107
|
+
const report = { notes: result2.notes, issues: issueSummary(result2.issues), shots: describeMotionShots(result2.scene).map(({ id, start, end, commands }) => ({ id, start, end, commands: commands.length })) };
|
|
5454
6108
|
if (dry_run) return { dry_run: true, ...report, hint: "Nothing was replaced; call again without dry_run to import." };
|
|
5455
|
-
const applied = controller.apply({ op: "replace_scene", scene:
|
|
5456
|
-
return outcome(applied, applied.ok ? { ...report, elements: describeMotionElements(
|
|
6109
|
+
const applied = controller.apply({ op: "replace_scene", scene: result2.scene }, "Import Flair effect");
|
|
6110
|
+
return outcome(applied, applied.ok ? { ...report, elements: describeMotionElements(result2.scene) } : {});
|
|
5457
6111
|
}
|
|
5458
6112
|
};
|
|
5459
6113
|
const fitAnimation = {
|
|
@@ -5516,18 +6170,18 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5516
6170
|
),
|
|
5517
6171
|
annotations: { title: "Record a performed take", ...WRITE },
|
|
5518
6172
|
handler: ({ samples, length, id, label, at, tolerance, dry_run = false }) => {
|
|
5519
|
-
const
|
|
5520
|
-
if (!
|
|
6173
|
+
const result2 = controller.recordTake({ samples, length }, { id, label, at, tolerance, dryRun: dry_run });
|
|
6174
|
+
if (!result2.ok) throw new Error(result2.error);
|
|
5521
6175
|
const s = dry_run ? scene() : controller.getScene();
|
|
5522
|
-
const report = { shot:
|
|
5523
|
-
if (dry_run) return { dry_run: true, ...report, run:
|
|
6176
|
+
const report = { shot: result2.shot.id, at: result2.at, start: Math.round(result2.start), samples: result2.samples };
|
|
6177
|
+
if (dry_run) return { dry_run: true, ...report, run: result2.shot.run, hold: result2.shot.hold, hint: "Nothing was changed; call again without dry_run to add the shot." };
|
|
5524
6178
|
const timeline = compileMotionScene(s);
|
|
5525
|
-
const described = describeMotionShots(s).find((x) => x.id ===
|
|
6179
|
+
const described = describeMotionShots(s).find((x) => x.id === result2.shot.id);
|
|
5526
6180
|
return {
|
|
5527
6181
|
...report,
|
|
5528
6182
|
commands: described.commands.map((c) => ({ index: c.index, type: c.type, targets: "targets" in c ? c.targets : [], start: c.start, end: c.end })),
|
|
5529
6183
|
duration: timeline.duration,
|
|
5530
|
-
issues: issueSummary(
|
|
6184
|
+
issues: issueSummary(result2.issues)
|
|
5531
6185
|
};
|
|
5532
6186
|
}
|
|
5533
6187
|
};
|
|
@@ -5595,27 +6249,27 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5595
6249
|
handler: ({ from, to, shots, stagger }) => {
|
|
5596
6250
|
const s = scene();
|
|
5597
6251
|
const ids = describeMotionElements(s).map((e) => e.id);
|
|
5598
|
-
for (const id of [from, ...to]) if (!ids.includes(id)) throw new Error(`There is no element ${
|
|
6252
|
+
for (const id of [from, ...to]) if (!ids.includes(id)) throw new Error(`There is no element ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, id, ids)}. Nothing was changed.`);
|
|
5599
6253
|
if (to.includes(from)) throw new Error(`"to" includes "${from}" itself; give other elements. Nothing was changed.`);
|
|
5600
6254
|
const only = shots ? new Set(shots) : null;
|
|
5601
6255
|
if (only) {
|
|
5602
|
-
for (const id of only) if (!s.shots.some((x) => x.id === id)) throw new Error(`There is no shot ${
|
|
6256
|
+
for (const id of only) if (!s.shots.some((x) => x.id === id)) throw new Error(`There is no shot ${_chunkDGWOGQJ5cjs.namedWithSuggestion.call(void 0, id, s.shots.map((x) => x.id))}. Nothing was changed.`);
|
|
5603
6257
|
}
|
|
5604
6258
|
const copied = {};
|
|
5605
6259
|
const edits = [];
|
|
5606
6260
|
for (const shot of s.shots) {
|
|
5607
6261
|
if (only && !only.has(shot.id)) continue;
|
|
5608
6262
|
const run = [];
|
|
5609
|
-
let
|
|
6263
|
+
let n2 = 0;
|
|
5610
6264
|
for (const c of shot.run) {
|
|
5611
6265
|
run.push(c);
|
|
5612
6266
|
if (c.type === "wait" || !c.targets.includes(from)) continue;
|
|
5613
6267
|
const { delay: _delay, ...rest } = c;
|
|
5614
6268
|
run.push({ ...rest, targets: to, with: "previous", ...stagger ? { stagger } : {} });
|
|
5615
|
-
|
|
6269
|
+
n2++;
|
|
5616
6270
|
}
|
|
5617
|
-
if (
|
|
5618
|
-
copied[shot.id] =
|
|
6271
|
+
if (n2) {
|
|
6272
|
+
copied[shot.id] = n2;
|
|
5619
6273
|
edits.push({ op: "update_shot", shot: shot.id, set: { run } });
|
|
5620
6274
|
}
|
|
5621
6275
|
}
|
|
@@ -5669,7 +6323,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5669
6323
|
inputSchema: object({ shot: SHOT_ID, commands: { type: "array", items: REF2("command"), minItems: 1, description: "Commands to add." }, at: { type: "integer", minimum: 0, description: "Index in the run (default: the end)." } }, ["shot", "commands"]),
|
|
5670
6324
|
annotations: { title: "Add commands to a shot", ...WRITE },
|
|
5671
6325
|
handler: ({ shot, commands, at }) => {
|
|
5672
|
-
const before = _nullishCoalesce(_optionalChain([scene, 'call',
|
|
6326
|
+
const before = _nullishCoalesce(_optionalChain([scene, 'call', _245 => _245(), 'access', _246 => _246.shots, 'access', _247 => _247.find, 'call', _248 => _248((s) => s.id === shot), 'optionalAccess', _249 => _249.run, 'access', _250 => _250.length]), () => ( 0));
|
|
5673
6327
|
const first = _nullishCoalesce(at, () => ( before));
|
|
5674
6328
|
return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
|
|
5675
6329
|
const shots = describeMotionShots(s);
|
|
@@ -5742,8 +6396,8 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
5742
6396
|
handler: ({ ops, dry_run = false }) => {
|
|
5743
6397
|
const refs = resolveMotionEditRefs(controller.getScene(), ops);
|
|
5744
6398
|
if (!refs.ok) throw new Error(refs.error);
|
|
5745
|
-
const
|
|
5746
|
-
return outcome(
|
|
6399
|
+
const result2 = controller.apply(refs.edits, "Edit animation", { dryRun: dry_run });
|
|
6400
|
+
return outcome(result2, { outcomes: refs.outcomes, ...dry_run ? { dry_run: true, hint: "Nothing was applied; call again without dry_run to apply." } : {} });
|
|
5747
6401
|
}
|
|
5748
6402
|
};
|
|
5749
6403
|
const writeAnimation = {
|
|
@@ -5870,7 +6524,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
|
|
|
5870
6524
|
var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
|
|
5871
6525
|
var NODES = /* @__PURE__ */ new Set(["into", "path"]);
|
|
5872
6526
|
function branch(type) {
|
|
5873
|
-
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access',
|
|
6527
|
+
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _251 => _251.properties, 'optionalAccess', _252 => _252.type, 'optionalAccess', _253 => _253.const]) === type);
|
|
5874
6528
|
}
|
|
5875
6529
|
function unitOf(type, name) {
|
|
5876
6530
|
if (name === "duration" || name === "delay" || name === "stagger") return "ms";
|
|
@@ -5905,9 +6559,9 @@ function kindOf(name, schema) {
|
|
|
5905
6559
|
}
|
|
5906
6560
|
function motionCommandFields(type) {
|
|
5907
6561
|
const schema = branch(type);
|
|
5908
|
-
if (!_optionalChain([schema, 'optionalAccess',
|
|
6562
|
+
if (!_optionalChain([schema, 'optionalAccess', _254 => _254.properties])) return [];
|
|
5909
6563
|
const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
|
|
5910
|
-
const
|
|
6564
|
+
const fields2 = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
|
|
5911
6565
|
const kind = kindOf(name, s);
|
|
5912
6566
|
const min = typeof s.minimum === "number" ? s.minimum : typeof s.exclusiveMinimum === "number" ? s.exclusiveMinimum : void 0;
|
|
5913
6567
|
return {
|
|
@@ -5923,7 +6577,7 @@ function motionCommandFields(type) {
|
|
|
5923
6577
|
group: TIMING.has(name) ? "timing" : "main"
|
|
5924
6578
|
};
|
|
5925
6579
|
});
|
|
5926
|
-
return [...
|
|
6580
|
+
return [...fields2.filter((f) => f.group === "main"), ...fields2.filter((f) => f.group === "timing")];
|
|
5927
6581
|
}
|
|
5928
6582
|
function parseMotionFieldInput(field, raw) {
|
|
5929
6583
|
if (field.kind === "boolean") return raw === true ? { set: true } : { remove: true };
|
|
@@ -5942,12 +6596,12 @@ function parseMotionFieldInput(field, raw) {
|
|
|
5942
6596
|
const text = String(raw).trim();
|
|
5943
6597
|
if (text === "") return field.required ? { error: `${field.label} is required.` } : { remove: true };
|
|
5944
6598
|
if (field.kind === "number" || field.kind === "integer" || field.kind === "scale") {
|
|
5945
|
-
const
|
|
5946
|
-
if (!Number.isFinite(
|
|
5947
|
-
if (field.kind === "integer" && !Number.isInteger(
|
|
5948
|
-
if (field.min !== void 0 &&
|
|
5949
|
-
if (field.max !== void 0 &&
|
|
5950
|
-
return { set:
|
|
6599
|
+
const n2 = Number(text);
|
|
6600
|
+
if (!Number.isFinite(n2)) return { error: `${field.label} must be a number${field.unit ? ` (${field.unit})` : ""}.` };
|
|
6601
|
+
if (field.kind === "integer" && !Number.isInteger(n2)) return { error: `${field.label} must be a whole number.` };
|
|
6602
|
+
if (field.min !== void 0 && n2 < field.min) return { error: `${field.label} must be at least ${field.min}.` };
|
|
6603
|
+
if (field.max !== void 0 && n2 > field.max) return { error: `${field.label} must be at most ${field.max}.` };
|
|
6604
|
+
return { set: n2 };
|
|
5951
6605
|
}
|
|
5952
6606
|
if (field.kind === "enum" && field.options && !field.options.includes(text)) return { error: `${field.label} must be one of ${field.options.join(", ")}.` };
|
|
5953
6607
|
return { set: text };
|
|
@@ -5962,7 +6616,7 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
5962
6616
|
if (type === "wait") return { type: "wait", duration: 500 };
|
|
5963
6617
|
if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
|
|
5964
6618
|
const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
|
|
5965
|
-
const other = (pred) => _optionalChain([nodes, 'access',
|
|
6619
|
+
const other = (pred) => _optionalChain([nodes, 'access', _255 => _255.find, 'call', _256 => _256((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _257 => _257.node, 'access', _258 => _258.id]);
|
|
5966
6620
|
const base = { targets: [...targets] };
|
|
5967
6621
|
switch (type) {
|
|
5968
6622
|
case "scale":
|
|
@@ -5993,8 +6647,8 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
5993
6647
|
}
|
|
5994
6648
|
case "effect": {
|
|
5995
6649
|
for (const id of targets) {
|
|
5996
|
-
const node = _optionalChain([nodes, 'access',
|
|
5997
|
-
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess',
|
|
6650
|
+
const node = _optionalChain([nodes, 'access', _259 => _259.find, 'call', _260 => _260((e) => e.node.id === id), 'optionalAccess', _261 => _261.node]);
|
|
6651
|
+
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _262 => _262.effects]), () => ( []))) {
|
|
5998
6652
|
const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
|
|
5999
6653
|
if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
|
|
6000
6654
|
}
|
|
@@ -6019,11 +6673,11 @@ function motionCommandRows(scene, shotId) {
|
|
|
6019
6673
|
return scene.shots[index].run.map((command3, i) => {
|
|
6020
6674
|
const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
|
|
6021
6675
|
const primitive = motionFlairPrimitive(command3);
|
|
6022
|
-
return { index: i, command: command3, summary: motionCommandSummary(command3), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess',
|
|
6676
|
+
return { index: i, command: command3, summary: motionCommandSummary(command3), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _263 => _263.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _264 => _264.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
|
|
6023
6677
|
});
|
|
6024
6678
|
}
|
|
6025
6679
|
function duplicateMotionCommandEdit(scene, shot, command3) {
|
|
6026
|
-
const run = _nullishCoalesce(_optionalChain([scene, 'access',
|
|
6680
|
+
const run = _nullishCoalesce(_optionalChain([scene, 'access', _265 => _265.shots, 'access', _266 => _266.find, 'call', _267 => _267((s) => s.id === shot), 'optionalAccess', _268 => _268.run]), () => ( []));
|
|
6027
6681
|
return { op: "add_commands", shot, commands: run[command3] ? [structuredClone(run[command3])] : [], at: command3 + 1 };
|
|
6028
6682
|
}
|
|
6029
6683
|
var MOTION_EASE_CHOICES = [
|
|
@@ -6037,18 +6691,18 @@ function motionEaseKey(ease) {
|
|
|
6037
6691
|
function motionEasingCurve(ease, samples = 48, durationMs = 1e3) {
|
|
6038
6692
|
const resolved = _chunkDWJJI6RTcjs.resolveEasing.call(void 0, ease);
|
|
6039
6693
|
const ms2 = resolved !== "hold" && resolved.type === "spring" ? _chunkDWJJI6RTcjs.springSettleMs.call(void 0, resolved) : durationMs;
|
|
6040
|
-
const
|
|
6694
|
+
const n2 = Math.max(2, Math.floor(samples));
|
|
6041
6695
|
const points = [];
|
|
6042
|
-
for (let i = 0; i <=
|
|
6043
|
-
const u = i /
|
|
6044
|
-
points.push({ u, v: resolved === "hold" ? i ===
|
|
6696
|
+
for (let i = 0; i <= n2; i++) {
|
|
6697
|
+
const u = i / n2;
|
|
6698
|
+
points.push({ u, v: resolved === "hold" ? i === n2 ? 1 : 0 : _chunkDWJJI6RTcjs.evaluateEasing.call(void 0, ease, u, ms2) });
|
|
6045
6699
|
}
|
|
6046
6700
|
const values = points.map((p) => p.v);
|
|
6047
6701
|
return { points, min: Math.min(0, ...values), max: Math.max(1, ...values), durationMs: ms2 };
|
|
6048
6702
|
}
|
|
6049
6703
|
function motionEasingPath(curve, width, height, pad = 4) {
|
|
6050
6704
|
const span = curve.max - curve.min || 1;
|
|
6051
|
-
const f = (
|
|
6705
|
+
const f = (n2) => String(Math.round(n2 * 100) / 100);
|
|
6052
6706
|
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(" ");
|
|
6053
6707
|
}
|
|
6054
6708
|
function motionEasingGuides(curve, height, pad = 4) {
|
|
@@ -6108,7 +6762,7 @@ function motionCueFromKey(key) {
|
|
|
6108
6762
|
function motionCueChoices(scene, limit = 256) {
|
|
6109
6763
|
const choices = [];
|
|
6110
6764
|
const s = (ms2) => `${(ms2 / 1e3).toFixed(2)} s`;
|
|
6111
|
-
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access',
|
|
6765
|
+
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _269 => _269.narration, 'optionalAccess', _270 => _270.words, 'access', _271 => _271.map, 'call', _272 => _272((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
|
|
6112
6766
|
if (scene.beat && scene.beat.bpm > 0) {
|
|
6113
6767
|
for (let beat = 0; choices.length < limit; beat++) {
|
|
6114
6768
|
const time = motionBeatTime(scene.beat, beat);
|
|
@@ -6118,7 +6772,7 @@ function motionCueChoices(scene, limit = 256) {
|
|
|
6118
6772
|
choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
|
|
6119
6773
|
}
|
|
6120
6774
|
}
|
|
6121
|
-
_optionalChain([scene, 'access',
|
|
6775
|
+
_optionalChain([scene, 'access', _273 => _273.narration, 'optionalAccess', _274 => _274.words, 'access', _275 => _275.forEach, 'call', _276 => _276((w, i) => {
|
|
6122
6776
|
if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
|
|
6123
6777
|
})]);
|
|
6124
6778
|
return choices;
|
|
@@ -6127,7 +6781,7 @@ function motionShotCueTime(scene, cue) {
|
|
|
6127
6781
|
return cue ? motionCueTime(scene, cue) : void 0;
|
|
6128
6782
|
}
|
|
6129
6783
|
function formatMotionNarration(narration) {
|
|
6130
|
-
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess',
|
|
6784
|
+
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _277 => _277.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
|
|
6131
6785
|
}
|
|
6132
6786
|
function parseMotionNarration(text) {
|
|
6133
6787
|
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
@@ -6158,7 +6812,7 @@ function parseMotionDrivers(text) {
|
|
|
6158
6812
|
if (factor !== void 0) d.factor = Number(factor);
|
|
6159
6813
|
if (offset !== void 0) d.offset = (sign === "-" ? -1 : 1) * Number(offset);
|
|
6160
6814
|
if (min !== void 0) d.clamp = [Number(min), Number(max)];
|
|
6161
|
-
if ([d.factor, d.offset, ..._nullishCoalesce(d.clamp, () => ( []))].some((
|
|
6815
|
+
if ([d.factor, d.offset, ..._nullishCoalesce(d.clamp, () => ( []))].some((n2) => n2 !== void 0 && !Number.isFinite(n2))) return { error: `Line ${i + 1} has a number that cannot be read.` };
|
|
6162
6816
|
drivers.push(d);
|
|
6163
6817
|
}
|
|
6164
6818
|
return { drivers };
|
|
@@ -6170,7 +6824,7 @@ var ROLE = {
|
|
|
6170
6824
|
enum: ["transition", "hold"],
|
|
6171
6825
|
description: `transition: the move the camera gets into the shot with (its camera "in": a glide, whip pan, punch zoom, cut). hold: the move it makes while the shot holds (its camera "during": a Ken Burns drift, a crash zoom), played across the shot's hold.`
|
|
6172
6826
|
};
|
|
6173
|
-
var summary = (e) => ({ id: e.id, name: e.name, role: e.camera.role, durationMs: e.camera.durationMs, ...e.camera.cut !== void 0 ? { cut: e.camera.cut } : {}, ...e.description ? { description: e.description } : {}, ..._optionalChain([e, 'access',
|
|
6827
|
+
var summary = (e) => ({ id: e.id, name: e.name, role: e.camera.role, durationMs: e.camera.durationMs, ...e.camera.cut !== void 0 ? { cut: e.camera.cut } : {}, ...e.description ? { description: e.description } : {}, ..._optionalChain([e, 'access', _278 => _278.tags, 'optionalAccess', _279 => _279.length]) ? { tags: e.tags } : {} });
|
|
6174
6828
|
var done = (r) => {
|
|
6175
6829
|
if (!r.ok) throw new Error(r.error);
|
|
6176
6830
|
return { shot: r.shot, camera: r.camera, ...r.window ? { window: r.window } : {}, ...r.notes.length ? { notes: r.notes } : {} };
|
|
@@ -6199,7 +6853,7 @@ function animationCameraMoveTools(controller, ctx) {
|
|
|
6199
6853
|
shot: { type: "string", minLength: 1, description: "A shot id from get_animation." },
|
|
6200
6854
|
role: ROLE,
|
|
6201
6855
|
move: { type: "string", minLength: 1, description: "A camera move id of that role from list_camera_moves." },
|
|
6202
|
-
ms: { type: "number", minimum: 0, maximum:
|
|
6856
|
+
ms: { type: "number", minimum: 0, maximum: _chunkJAOSL334cjs.CAMERA_MOVE_MAX_MS, description: `How long a transition takes, ms (0\u2013${_chunkJAOSL334cjs.CAMERA_MOVE_MAX_MS}; default the move's durationMs). Not for a hold, which plays across the shot's hold.` },
|
|
6203
6857
|
preset: { type: "string", minLength: 1, description: "A preset of the move by name, from describe_effect; its values are written out on the shot." },
|
|
6204
6858
|
values: ctx.valuesSchema("Control values over the move's defaults (and the preset's), from describe_effect")
|
|
6205
6859
|
},
|
|
@@ -6229,6 +6883,163 @@ function animationCameraMoveTools(controller, ctx) {
|
|
|
6229
6883
|
];
|
|
6230
6884
|
}
|
|
6231
6885
|
|
|
6886
|
+
// src/animation-editor/layer-tools.ts
|
|
6887
|
+
var LAYER_USES = ["generator", "filter", "overlay", "title"];
|
|
6888
|
+
var SHOT2 = { type: "string", minLength: 1, description: "A shot id from get_animation." };
|
|
6889
|
+
var LAYER = { type: "string", minLength: 1, description: 'A layer id from list_shot_layers (e.g. "layer1").' };
|
|
6890
|
+
var SUBJECT = {
|
|
6891
|
+
anyOf: [
|
|
6892
|
+
{ type: "object", properties: { image: { type: "string", minLength: 1, description: "A picture URL or data: URL." } }, required: ["image"], additionalProperties: false, description: '{ "image": url }' },
|
|
6893
|
+
{ type: "object", properties: { svg: { type: "string", minLength: 1, description: "SVG markup or an SVG URL." } }, required: ["svg"], additionalProperties: false, description: '{ "svg": markup }' },
|
|
6894
|
+
{
|
|
6895
|
+
type: "object",
|
|
6896
|
+
properties: { text: { type: "string", minLength: 1, description: "The words." }, font: { type: "string", description: "A CSS font family (default system-ui)." }, weight: { anyOf: [{ type: "number" }, { type: "string" }], description: "A CSS font weight (default 700)." } },
|
|
6897
|
+
required: ["text"],
|
|
6898
|
+
additionalProperties: false,
|
|
6899
|
+
description: '{ "text": words }'
|
|
6900
|
+
},
|
|
6901
|
+
{ type: "object", properties: { slot: { type: "string", minLength: 1, description: "A slot name the host fills later." } }, required: ["slot"], additionalProperties: false, description: '{ "slot": name }: draws nothing until filled.' }
|
|
6902
|
+
],
|
|
6903
|
+
description: "What the layer shows, or feeds its effect (a filter changes it): a picture, SVG, words, or a slot to fill later. Leave out for a generator, overlay or title that draws its own picture."
|
|
6904
|
+
};
|
|
6905
|
+
var RECT = {
|
|
6906
|
+
type: "object",
|
|
6907
|
+
properties: {
|
|
6908
|
+
x: { type: "number", description: "Left edge, artwork units." },
|
|
6909
|
+
y: { type: "number", description: "Top edge, artwork units." },
|
|
6910
|
+
width: { type: "number", exclusiveMinimum: 0, description: "Width, artwork units." },
|
|
6911
|
+
height: { type: "number", exclusiveMinimum: 0, description: "Height, artwork units." }
|
|
6912
|
+
},
|
|
6913
|
+
required: ["x", "y", "width", "height"],
|
|
6914
|
+
additionalProperties: false,
|
|
6915
|
+
description: "Where the layer sits on the artwork (it moves with the camera). Leave out to fill the screen."
|
|
6916
|
+
};
|
|
6917
|
+
var TIME = (what, fallback) => ({
|
|
6918
|
+
anyOf: [
|
|
6919
|
+
{ type: "number", minimum: 0, description: "Ms after the shot starts." },
|
|
6920
|
+
{ type: "object", properties: { shots: { type: "integer", minimum: 1, description: "1: when the next shot starts; 2: the one after\u2026" } }, required: ["shots"], additionalProperties: false, description: '{ "shots": n }' }
|
|
6921
|
+
],
|
|
6922
|
+
description: `When the layer ${what}: ms after its shot starts, or { "shots": n } for when the n-th shot after its own starts (default ${fallback}).`
|
|
6923
|
+
});
|
|
6924
|
+
var fields = (ctx) => ({
|
|
6925
|
+
effect: { ...ctx.effectIdSchema(LAYER_USES), description: "A generator, filter, overlay or title effect id from search_effects. Leave out for a bare subject." },
|
|
6926
|
+
preset: { type: "string", minLength: 1, description: "A preset of the effect by name, from describe_effect; its values are written out on the layer." },
|
|
6927
|
+
values: ctx.valuesSchema("Control values over the effect's defaults (and the preset's), from describe_effect"),
|
|
6928
|
+
subject: SUBJECT,
|
|
6929
|
+
role: { type: "string", enum: [..._chunkJAOSL334cjs.EFFECT_LAYER_ROLES], description: "background: under the artwork; subject: over the artwork; overlay: over everything. Default subject with a rect, else background." },
|
|
6930
|
+
rect: RECT,
|
|
6931
|
+
from: TIME("starts", "0: as its shot starts"),
|
|
6932
|
+
until: TIME("stops", '{ "shots": 1 }: as the next shot starts'),
|
|
6933
|
+
opacity: { type: "number", minimum: 0, maximum: 1, description: "Opacity 0\u20131 (default 1)." },
|
|
6934
|
+
fade: { type: "number", minimum: 0, maximum: 6e4, description: "Ms it fades in and out over (default 0: it cuts)." }
|
|
6935
|
+
});
|
|
6936
|
+
var result = (r) => {
|
|
6937
|
+
if (!r.ok) throw new Error(r.error);
|
|
6938
|
+
const { ok: _ok, notes, ...rest } = r;
|
|
6939
|
+
return { ...rest, ...notes.length ? { notes } : {} };
|
|
6940
|
+
};
|
|
6941
|
+
function animationShotLayerTools(controller, ctx) {
|
|
6942
|
+
const f = fields(ctx);
|
|
6943
|
+
return [
|
|
6944
|
+
{
|
|
6945
|
+
name: "list_shot_layers",
|
|
6946
|
+
title: "List shot layers",
|
|
6947
|
+
description: "Lists the layers and transition of every shot, or of one: [{ shot, layers: [{ id, effect, name, subject, role, rect, from, until, opacity, fade, values, index (0 = bottom), start, end (ms when it shows) }], transition: { effect, ms, values, start, end } or null }]. Use the layer ids with update_shot_layer, move_shot_layer and remove_shot_layer. Works without a provider.",
|
|
6948
|
+
inputSchema: { type: "object", properties: { shot: { ...SHOT2, description: "Only this shot (default every shot)." } }, additionalProperties: false },
|
|
6949
|
+
annotations: { title: "List shot layers", ...ctx.annotations.read },
|
|
6950
|
+
handler: async (args) => ({ shots: controller.shotLayers(args.shot) })
|
|
6951
|
+
},
|
|
6952
|
+
{
|
|
6953
|
+
name: "add_shot_layer",
|
|
6954
|
+
title: "Add a shot layer",
|
|
6955
|
+
description: "Adds a layer to a shot: a provider effect (a generator such as a gradient background, a filter applied to a subject, an overlay or title) or a bare subject (a picture, SVG or words). It shows from its shot's start until the next shot starts unless from / until say otherwise, fills the screen unless given a rect, and goes on top unless given an index. Checked first: an effect that cannot be a layer (a transition, a camera move, a motion effect) is refused with the tool to use instead, as are a subject the effect cannot take, a filter without a subject, an unknown preset and values outside its controls. One undo step. Returns { shot, layer (with its id, start and end), layers (the shot's, bottom to top), transition, notes }. Check it with render_animation_frame.",
|
|
6956
|
+
inputSchema: {
|
|
6957
|
+
type: "object",
|
|
6958
|
+
properties: { shot: SHOT2, ...f, id: { type: "string", pattern: "^[A-Za-z_][\\w.-]*$", description: "The layer's id (default layer1, layer2\u2026); unique in the scene." }, index: { type: "integer", minimum: 0, description: "Its place in the shot, 0 = bottom (default the top)." } },
|
|
6959
|
+
required: ["shot"],
|
|
6960
|
+
additionalProperties: false
|
|
6961
|
+
},
|
|
6962
|
+
annotations: { title: "Add a shot layer", ...ctx.annotations.write },
|
|
6963
|
+
handler: async ({ shot, index, ...layer }) => {
|
|
6964
|
+
if (layer.effect !== void 0) ctx.requireProvider();
|
|
6965
|
+
if (layer.effect === void 0 && layer.subject === void 0) throw new Error('Give an "effect" (search_effects with use generator, filter, overlay or title), a "subject" (a picture, SVG or words), or both.');
|
|
6966
|
+
return result(await controller.addShotLayer(shot, layer, { index }));
|
|
6967
|
+
}
|
|
6968
|
+
},
|
|
6969
|
+
{
|
|
6970
|
+
name: "update_shot_layer",
|
|
6971
|
+
title: "Change a shot layer",
|
|
6972
|
+
description: `Changes a layer's fields: give the ones to change, and list in "clear" the optional ones to remove (back to their defaults). A new effect starts from its own defaults unless values are given. Checked against the provider like add_shot_layer. One undo step. Returns { shot, layer, layers, transition }.`,
|
|
6973
|
+
inputSchema: {
|
|
6974
|
+
type: "object",
|
|
6975
|
+
properties: {
|
|
6976
|
+
layer: LAYER,
|
|
6977
|
+
...f,
|
|
6978
|
+
clear: { type: "array", items: { type: "string", enum: ["effect", "preset", "values", "subject", "role", "rect", "from", "until", "opacity", "fade"] }, uniqueItems: true, description: "Fields to remove." }
|
|
6979
|
+
},
|
|
6980
|
+
required: ["layer"],
|
|
6981
|
+
additionalProperties: false
|
|
6982
|
+
},
|
|
6983
|
+
annotations: { title: "Change a shot layer", ...ctx.annotations.writeIdempotent },
|
|
6984
|
+
handler: async ({ layer, clear, ...set }) => {
|
|
6985
|
+
const changes = { ...set };
|
|
6986
|
+
for (const k of _nullishCoalesce(clear, () => ( []))) {
|
|
6987
|
+
if (k in set) throw new Error(`"${k}" is both given and cleared; do one or the other.`);
|
|
6988
|
+
changes[k] = null;
|
|
6989
|
+
}
|
|
6990
|
+
if (!Object.keys(changes).length) throw new Error('Give at least one field to change, or a field in "clear".');
|
|
6991
|
+
return result(await controller.updateShotLayer(layer, changes));
|
|
6992
|
+
}
|
|
6993
|
+
},
|
|
6994
|
+
{
|
|
6995
|
+
name: "move_shot_layer",
|
|
6996
|
+
title: "Restack a shot layer",
|
|
6997
|
+
description: "Moves a layer to another place in its shot's stack (0 = bottom; within a role, later layers draw over earlier ones). One undo step. Returns { shot, layer, layers }.",
|
|
6998
|
+
inputSchema: { type: "object", properties: { layer: LAYER, index: { type: "integer", minimum: 0, description: "Its new place in the shot, 0 = bottom." } }, required: ["layer", "index"], additionalProperties: false },
|
|
6999
|
+
annotations: { title: "Restack a shot layer", ...ctx.annotations.writeIdempotent },
|
|
7000
|
+
handler: async ({ layer, index }) => result(await controller.moveShotLayer(layer, index))
|
|
7001
|
+
},
|
|
7002
|
+
{
|
|
7003
|
+
name: "remove_shot_layer",
|
|
7004
|
+
title: "Remove a shot layer",
|
|
7005
|
+
description: "Removes a layer from its shot. Works without a provider. One undo step. Returns the shot's remaining layers.",
|
|
7006
|
+
inputSchema: { type: "object", properties: { layer: LAYER }, required: ["layer"], additionalProperties: false },
|
|
7007
|
+
annotations: { title: "Remove a shot layer", ...ctx.annotations.destructive },
|
|
7008
|
+
handler: async ({ layer }) => result(await controller.removeShotLayer(layer))
|
|
7009
|
+
},
|
|
7010
|
+
{
|
|
7011
|
+
name: "set_shot_transition",
|
|
7012
|
+
title: "Set a shot's transition",
|
|
7013
|
+
description: `Sets the transition into a shot: a provider effect with the use transition (search_effects with use "transition") blends the last frame of the shot before into this shot over ms. Not on the first shot (there is no shot before it). With no camera move in (set_shot_camera_move, role transition), the camera cuts and the transition does the move; with one, both play together. Checked first: an effect that is not a transition, an unknown preset or values outside its controls are refused. One undo step. Returns { shot, layers, transition: { effect, ms, values, start, end }, notes }.`,
|
|
7014
|
+
inputSchema: {
|
|
7015
|
+
type: "object",
|
|
7016
|
+
properties: {
|
|
7017
|
+
shot: { ...SHOT2, description: "A shot id from get_animation (not the first shot)." },
|
|
7018
|
+
effect: { ...ctx.effectIdSchema(["transition"]), description: "A transition effect id from search_effects (use transition)." },
|
|
7019
|
+
ms: { type: "number", exclusiveMinimum: 0, maximum: 6e4, description: `How long it takes, ms (default ${_chunkJAOSL334cjs.EFFECT_TRANSITION_MS}).` },
|
|
7020
|
+
preset: { type: "string", minLength: 1, description: "A preset of the transition by name, from describe_effect." },
|
|
7021
|
+
values: ctx.valuesSchema("Control values over the transition's defaults (and the preset's)")
|
|
7022
|
+
},
|
|
7023
|
+
required: ["shot", "effect"],
|
|
7024
|
+
additionalProperties: false
|
|
7025
|
+
},
|
|
7026
|
+
annotations: { title: "Set a shot's transition", ...ctx.annotations.writeIdempotent },
|
|
7027
|
+
handler: async ({ shot, effect, ms: ms2, preset: preset2, values }) => {
|
|
7028
|
+
ctx.requireProvider();
|
|
7029
|
+
return result(await controller.setShotTransition(shot, { effect, ...ms2 !== void 0 ? { ms: ms2 } : {}, ...preset2 !== void 0 ? { preset: preset2 } : {}, ...values !== void 0 ? { values } : {} }));
|
|
7030
|
+
}
|
|
7031
|
+
},
|
|
7032
|
+
{
|
|
7033
|
+
name: "clear_shot_transition",
|
|
7034
|
+
title: "Clear a shot's transition",
|
|
7035
|
+
description: "Removes the transition into a shot, so it cuts (or the camera eases) from the shot before. Works without a provider. One undo step. Returns { shot, layers, transition: null }.",
|
|
7036
|
+
inputSchema: { type: "object", properties: { shot: SHOT2 }, required: ["shot"], additionalProperties: false },
|
|
7037
|
+
annotations: { title: "Clear a shot's transition", ...ctx.annotations.destructive },
|
|
7038
|
+
handler: async ({ shot }) => result(controller.clearShotTransition(shot))
|
|
7039
|
+
}
|
|
7040
|
+
];
|
|
7041
|
+
}
|
|
7042
|
+
|
|
6232
7043
|
// src/animation-editor/effect-tools.ts
|
|
6233
7044
|
var info = (e) => ({ id: e.instance, effect: e.effect, ...e.name ? { name: e.name } : {}, ...e.provider ? { provider: e.provider } : {}, role: e.kind === "vector" ? "vector picture" : "motion", enabled: true, values: e.values, targets: e.targets, shots: e.shots });
|
|
6234
7045
|
function createAnimationEffectsToolProvider(controller, options = {}) {
|
|
@@ -6241,7 +7052,7 @@ function createAnimationEffectsToolProvider(controller, options = {}) {
|
|
|
6241
7052
|
if (!r.ok) throw new Error(r.error);
|
|
6242
7053
|
return { target, effect: info(r.effect), effects: controller.appliedEffects().filter((e) => e.targets.includes(target)).map(info), ...r.notes.length ? { notes: r.notes } : {} };
|
|
6243
7054
|
};
|
|
6244
|
-
return withAnimationPlayback(
|
|
7055
|
+
return withAnimationPlayback(_chunkJAOSL334cjs.createEffectToolProvider.call(void 0, {
|
|
6245
7056
|
id: _nullishCoalesce(options.id, () => ( "animation-effects")),
|
|
6246
7057
|
namespace: options.namespace,
|
|
6247
7058
|
title: "Animation effects",
|
|
@@ -6275,6 +7086,7 @@ function createAnimationEffectsToolProvider(controller, options = {}) {
|
|
|
6275
7086
|
subscribe: (notify) => controller.subscribe(() => notify()),
|
|
6276
7087
|
extraTools: (ctx) => [
|
|
6277
7088
|
...animationCameraMoveTools(controller, ctx),
|
|
7089
|
+
...animationShotLayerTools(controller, ctx),
|
|
6278
7090
|
{
|
|
6279
7091
|
name: "add_vector_effect",
|
|
6280
7092
|
title: "Add a vector effect",
|
|
@@ -6318,8 +7130,8 @@ function createAnimationEditorDocument(controller) {
|
|
|
6318
7130
|
kind: "animation",
|
|
6319
7131
|
get: () => controller.getScene(),
|
|
6320
7132
|
load: (document, { history }) => {
|
|
6321
|
-
const
|
|
6322
|
-
if (!
|
|
7133
|
+
const result2 = controller.load(document, { clearHistory: history === "reset" });
|
|
7134
|
+
if (!result2.ok) throw new Error(result2.error);
|
|
6323
7135
|
},
|
|
6324
7136
|
subscribe: (listener) => {
|
|
6325
7137
|
let scene = controller.getScene();
|
|
@@ -6512,4 +7324,23 @@ function createAnimationEditorDocument(controller) {
|
|
|
6512
7324
|
|
|
6513
7325
|
|
|
6514
7326
|
|
|
6515
|
-
|
|
7327
|
+
|
|
7328
|
+
|
|
7329
|
+
|
|
7330
|
+
|
|
7331
|
+
|
|
7332
|
+
|
|
7333
|
+
|
|
7334
|
+
|
|
7335
|
+
|
|
7336
|
+
|
|
7337
|
+
|
|
7338
|
+
|
|
7339
|
+
|
|
7340
|
+
|
|
7341
|
+
|
|
7342
|
+
|
|
7343
|
+
|
|
7344
|
+
|
|
7345
|
+
|
|
7346
|
+
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_CASCADES = MOTION_CASCADES; exports.MOTION_CLIP_TARGET = MOTION_CLIP_TARGET; exports.MOTION_COMMAND_FIELDS = MOTION_COMMAND_FIELDS; exports.MOTION_COMMAND_SCHEMA = MOTION_COMMAND_SCHEMA; exports.MOTION_COMMAND_TYPES = MOTION_COMMAND_TYPES; exports.MOTION_COMMAND_TYPE_SCHEMAS = MOTION_COMMAND_TYPE_SCHEMAS; 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 = _chunkDGWOGQJ5cjs.MOTION_ISSUE_CODES; exports.MOTION_MAX_TAKE_MS = MOTION_MAX_TAKE_MS; exports.MOTION_MIN_CHANGE_MS = MOTION_MIN_CHANGE_MS; exports.MOTION_RECORD_GESTURE_MODES = MOTION_RECORD_GESTURE_MODES; exports.MOTION_REPEAT_MODES = MOTION_REPEAT_MODES; exports.MOTION_SPEED_RANGE = MOTION_SPEED_RANGE; exports.MOTION_SPLIT_ORIENTATIONS = MOTION_SPLIT_ORIENTATIONS; exports.MOTION_TEXT_STAGGER = MOTION_TEXT_STAGGER; exports.MOTION_TEXT_UNITS = MOTION_TEXT_UNITS; exports.MOTION_TRIGGERS = MOTION_TRIGGERS; exports.MotionLayersEngine = MotionLayersEngine; exports.MotionSceneFormatError = MotionSceneFormatError; exports.activeSegment = activeSegment; exports.animationCameraMoveTools = animationCameraMoveTools; exports.animationShotLayerTools = animationShotLayerTools; exports.applyMotionControlValues = applyMotionControlValues; exports.applyMotionDrivers = applyMotionDrivers; exports.applyMotionEdits = applyMotionEdits; exports.browserMotionLayerHost = browserMotionLayerHost; exports.checkMotionCameraMoves = checkMotionCameraMoves; exports.checkMotionScene = checkMotionScene; exports.checkMotionShotLayers = checkMotionShotLayers; exports.clipsShapeProblems = clipsShapeProblems; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorDocument = createAnimationEditorDocument; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createAnimationEffectsToolProvider = createAnimationEffectsToolProvider; exports.createMotionScene = createMotionScene; exports.defaultMotionCommand = defaultMotionCommand; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.driversShapeProblems = driversShapeProblems; exports.duplicateMotionCommandEdit = duplicateMotionCommandEdit; exports.effectsPlayCamera = effectsPlayCamera; exports.findMotionShotLayer = findMotionShotLayer; 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.freshMotionLayerId = freshMotionLayerId; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.fromPptxAnimation = fromPptxAnimation; exports.highlightMotionSvg = highlightMotionSvg; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionArtworkSvg = motionArtworkSvg; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionBlurTimes = motionBlurTimes; exports.motionCameraBox = motionCameraBox; exports.motionCameraFramed = motionCameraFramed; exports.motionCameraMoves = motionCameraMoves; exports.motionCameraStage = motionCameraStage; exports.motionCameraTransform = motionCameraTransform; exports.motionCameraViewAt = motionCameraViewAt; exports.motionCameraWindows = motionCameraWindows; exports.motionCascade = motionCascade; exports.motionClientToDocument = motionClientToDocument; exports.motionClipAttrs = motionClipAttrs; exports.motionClipLayout = motionClipLayout; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandFields = motionCommandFields; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCommandRows = motionCommandRows; exports.motionCommandSlots = motionCommandSlots; exports.motionCommandSummary = motionCommandSummary; exports.motionCommandsFromEffect = motionCommandsFromEffect; 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 = _chunkDGWOGQJ5cjs.motionIssue; exports.motionIssueKey = _chunkDGWOGQJ5cjs.motionIssueKey; exports.motionIssueLine = _chunkDGWOGQJ5cjs.motionIssueLine; exports.motionLayerIds = motionLayerIds; exports.motionLayerSlot = motionLayerSlot; exports.motionLayerSpans = motionLayerSpans; exports.motionLayersAt = motionLayersAt; exports.motionMovingIds = motionMovingIds; exports.motionNodeAtElement = motionNodeAtElement; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionNodePose = motionNodePose; exports.motionPartsFromVectorEffect = motionPartsFromVectorEffect; 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.motionSceneEffects = motionSceneEffects; exports.motionSceneHasLayers = motionSceneHasLayers; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionShotCameraMove = motionShotCameraMove; exports.motionShotCueTime = motionShotCueTime; exports.motionShotLayersInfo = motionShotLayersInfo; exports.motionShotTimeScale = motionShotTimeScale; exports.motionStageSvg = motionStageSvg; exports.motionTakeProblems = motionTakeProblems; exports.motionTakeShot = motionTakeShot; exports.motionTextLayout = motionTextLayout; exports.motionTextUnits = motionTextUnits; exports.motionTrackKey = motionTrackKey; exports.motionTransitionAt = motionTransitionAt; exports.motionTransitionSvg = motionTransitionSvg; exports.namedWithSuggestion = _chunkDGWOGQJ5cjs.namedWithSuggestion; exports.nextMotionEffectInstance = nextMotionEffectInstance; exports.parseMotionDrivers = parseMotionDrivers; exports.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.planAnimationToolPlayback = planAnimationToolPlayback; exports.resolveMotionCamera = resolveMotionCamera; exports.resolveMotionEditRefs = resolveMotionEditRefs; exports.resolveMotionShotLayer = resolveMotionShotLayer; exports.resolveMotionShotTransition = resolveMotionShotTransition; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotLayersShapeProblems = shotLayersShapeProblems; exports.shotShapeProblems = shotShapeProblems; exports.simplifyTimedSamples = simplifyTimedSamples; exports.smoothMotionLegs = smoothMotionLegs; exports.smoothMotionTimes = smoothMotionTimes; exports.suggestName = _chunkDGWOGQJ5cjs.suggestName; exports.svgDataUrl = svgDataUrl; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withAnimationPlayback = withAnimationPlayback; exports.withCameraViewEffects = withCameraViewEffects; exports.withMotionLayers = withMotionLayers; exports.withMotionShotLayers = withMotionShotLayers; exports.withViewBox = withViewBox; exports.withoutMotionEffect = withoutMotionEffect;
|