@pixerate/editor 0.73.0 → 0.75.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/THIRD_PARTY_NOTICES.md +3 -0
- package/dist/animation-editor/index.cjs +928 -399
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +130 -3
- package/dist/animation-editor/index.d.ts +130 -3
- package/dist/animation-editor/index.js +819 -290
- package/dist/animation-editor/index.js.map +1 -1
- package/dist/canvas/index.cjs +26 -26
- package/dist/canvas/index.js +2 -2
- package/dist/chart/index.cjs +11 -9
- package/dist/chart/index.cjs.map +1 -1
- package/dist/chart/index.js +5 -3
- package/dist/chart/index.js.map +1 -1
- package/dist/{chunk-3S72F46R.js → chunk-2GFUA4X5.js} +2 -322
- package/dist/chunk-2GFUA4X5.js.map +1 -0
- package/dist/chunk-33AHNSEB.js +323 -0
- package/dist/chunk-33AHNSEB.js.map +1 -0
- package/dist/{chunk-3TLL5OID.js → chunk-4JLB2USO.js} +2 -2
- package/dist/{chunk-NN3JGUSX.cjs → chunk-5PTR7HTL.cjs} +3 -323
- package/dist/chunk-5PTR7HTL.cjs.map +1 -0
- package/dist/{chunk-YJLCBA7V.cjs → chunk-7MD7C6XQ.cjs} +87 -87
- package/dist/{chunk-YJLCBA7V.cjs.map → chunk-7MD7C6XQ.cjs.map} +1 -1
- package/dist/{chunk-4YFMSPBU.js → chunk-EIXXBKUB.js} +6 -4
- package/dist/{chunk-4YFMSPBU.js.map → chunk-EIXXBKUB.js.map} +1 -1
- package/dist/chunk-EMQWJA3G.cjs +323 -0
- package/dist/chunk-EMQWJA3G.cjs.map +1 -0
- package/dist/{chunk-BQQZ6MOI.js → chunk-FGW5OWJ4.js} +6 -4
- package/dist/{chunk-BQQZ6MOI.js.map → chunk-FGW5OWJ4.js.map} +1 -1
- package/dist/{chunk-YZZMX6V7.cjs → chunk-FV5AXTSF.cjs} +11 -9
- package/dist/chunk-FV5AXTSF.cjs.map +1 -0
- package/dist/{chunk-MLREO6J3.cjs → chunk-JEYDXRWQ.cjs} +46 -46
- package/dist/{chunk-MLREO6J3.cjs.map → chunk-JEYDXRWQ.cjs.map} +1 -1
- package/dist/{chunk-7ZSU4MQZ.cjs → chunk-PL3MPFPA.cjs} +10 -8
- package/dist/chunk-PL3MPFPA.cjs.map +1 -0
- package/dist/{chunk-O2UH7LZE.cjs → chunk-XGD3FSNC.cjs} +239 -239
- package/dist/chunk-XGD3FSNC.cjs.map +1 -0
- package/dist/{chunk-VWZB6BCY.js → chunk-Y3NW4VJE.js} +2 -2
- package/dist/{chunk-GTMJ4Y3S.js → chunk-YCSFS3GK.js} +244 -244
- package/dist/{chunk-GTMJ4Y3S.js.map → chunk-YCSFS3GK.js.map} +1 -1
- package/dist/export/index.cjs +4 -3
- package/dist/export/index.cjs.map +1 -1
- package/dist/export/index.js +3 -2
- package/dist/extensions/index.cjs +4 -3
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.js +3 -2
- package/dist/index.cjs +19 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +12 -11
- package/dist/index.js.map +1 -1
- package/dist/vector/index.cjs +532 -532
- package/dist/vector/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-3S72F46R.js.map +0 -1
- package/dist/chunk-7ZSU4MQZ.cjs.map +0 -1
- package/dist/chunk-NN3JGUSX.cjs.map +0 -1
- package/dist/chunk-O2UH7LZE.cjs.map +0 -1
- package/dist/chunk-YZZMX6V7.cjs.map +0 -1
- /package/dist/{chunk-3TLL5OID.js.map → chunk-4JLB2USO.js.map} +0 -0
- /package/dist/{chunk-VWZB6BCY.js.map → chunk-Y3NW4VJE.js.map} +0 -0
|
@@ -18,14 +18,19 @@
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
var _chunkYJLCBA7Vcjs = require('../chunk-YJLCBA7V.cjs');
|
|
22
21
|
|
|
23
22
|
|
|
23
|
+
var _chunk7MD7C6XQcjs = require('../chunk-7MD7C6XQ.cjs');
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
var _chunkXGD3FSNCcjs = require('../chunk-XGD3FSNC.cjs');
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
var _chunkEMQWJA3Gcjs = require('../chunk-EMQWJA3G.cjs');
|
|
29
34
|
|
|
30
35
|
|
|
31
36
|
var _chunkQKLRAA4Tcjs = require('../chunk-QKLRAA4T.cjs');
|
|
@@ -56,6 +61,8 @@ var _chunk2FHLHZALcjs = require('../chunk-2FHLHZAL.cjs');
|
|
|
56
61
|
|
|
57
62
|
// src/animation-editor/types.ts
|
|
58
63
|
var MOTION_TRIGGERS = ["click", "hover", "press", "scroll"];
|
|
64
|
+
var MOTION_TEXT_UNITS = ["letter", "word", "line"];
|
|
65
|
+
var MOTION_CASCADES = ["forward", "backward", "center", "edges", "random"];
|
|
59
66
|
var MOTION_DRIVEN_PROPERTIES = ["x", "y", "rotation", "scaleX", "scaleY", "opacity"];
|
|
60
67
|
var MOTION_CLIP_TARGET = "$";
|
|
61
68
|
var MOTION_COMMAND_TYPES = [
|
|
@@ -112,21 +119,21 @@ var MOTION_DEFAULT_HOLD = 600;
|
|
|
112
119
|
var MOTION_CAMERA_MS = 1e3;
|
|
113
120
|
var MOTION_DRAW_MS_PER_UNIT = 1.5;
|
|
114
121
|
var MOTION_DRAW_RANGE = [500, 2500];
|
|
115
|
-
function motionFlairPrimitive(
|
|
116
|
-
switch (
|
|
122
|
+
function motionFlairPrimitive(command3) {
|
|
123
|
+
switch (command3.type) {
|
|
117
124
|
case "enter":
|
|
118
|
-
return `entrance.${_nullishCoalesce(
|
|
125
|
+
return `entrance.${_nullishCoalesce(command3.style, () => ( "fade"))}`;
|
|
119
126
|
case "exit":
|
|
120
|
-
return `exit.${_nullishCoalesce(
|
|
127
|
+
return `exit.${_nullishCoalesce(command3.style, () => ( "fade"))}`;
|
|
121
128
|
case "pulse":
|
|
122
129
|
case "shake":
|
|
123
130
|
case "teeter":
|
|
124
131
|
case "wave":
|
|
125
132
|
case "wiggle":
|
|
126
133
|
case "color-pulse":
|
|
127
|
-
return `emphasis.${
|
|
134
|
+
return `emphasis.${command3.type}`;
|
|
128
135
|
case "rotate":
|
|
129
|
-
return
|
|
136
|
+
return command3.by !== void 0 ? "emphasis.spin" : void 0;
|
|
130
137
|
case "follow":
|
|
131
138
|
return "path.follow";
|
|
132
139
|
default:
|
|
@@ -143,6 +150,7 @@ var MOTION_ISSUE_CODES = {
|
|
|
143
150
|
"not-a-path": { severity: "error", wording: "A follow path must be a path node, not a group." },
|
|
144
151
|
"reveal-no-box": { severity: "warning", wording: "A wipe, iris or split cannot clip a node with no width or height (a lone straight line), so it fades instead." },
|
|
145
152
|
"driver-cycle": { severity: "error", wording: "Drivers follow each other in a loop, so none of them has a value." },
|
|
153
|
+
"split-not-text": { severity: "warning", wording: "A command splits a target into letters, but it is not a group of letter paths, so it animates as a whole." },
|
|
146
154
|
"unknown-clip": { severity: "error", wording: "A play command names a clip the scene does not have." },
|
|
147
155
|
"unknown-shape": { severity: "error", wording: "A morph names a shape the artwork does not have." },
|
|
148
156
|
"match-self": { severity: "error", wording: "A match turns a group into itself or into a group it holds (or that holds it)." },
|
|
@@ -224,7 +232,7 @@ ${problems.map((p) => `- ${p}`).join("\n")}`);
|
|
|
224
232
|
var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "drivers", "motionBlur", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
|
|
225
233
|
var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
|
|
226
234
|
var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric"];
|
|
227
|
-
var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps"];
|
|
235
|
+
var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps", "split", "cascade"];
|
|
228
236
|
var DRAW_ORDER_KEYS = ["order", "pace", "align", "sortBy", "origin"];
|
|
229
237
|
var COMMAND_KEYS = {
|
|
230
238
|
enter: [...BASE_KEYS, ...DRAW_ORDER_KEYS, "style", "direction", "distance", "scale", "shape", "orientation"],
|
|
@@ -254,108 +262,111 @@ var isPoint = (v) => isObject(v) && isNum(v.x) && isNum(v.y);
|
|
|
254
262
|
function unknownKeys(value, known, where, problems) {
|
|
255
263
|
for (const key of Object.keys(value)) if (!known.includes(key)) problems.push(`${where}: unknown field ${namedWithSuggestion(key, known)}.`);
|
|
256
264
|
}
|
|
257
|
-
function commandShapeProblems(
|
|
265
|
+
function commandShapeProblems(command3, where) {
|
|
258
266
|
const problems = [];
|
|
259
|
-
if (!isObject(
|
|
260
|
-
const type =
|
|
267
|
+
if (!isObject(command3)) return [`${where} must be an object.`];
|
|
268
|
+
const type = command3.type;
|
|
261
269
|
if (typeof type !== "string" || !MOTION_COMMAND_TYPES.includes(type)) {
|
|
262
270
|
return [`${where}: unknown type ${typeof type === "string" ? namedWithSuggestion(type, MOTION_COMMAND_TYPES) : String(type)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`];
|
|
263
271
|
}
|
|
264
|
-
unknownKeys(
|
|
272
|
+
unknownKeys(command3, COMMAND_KEYS[type], `${where} (${type})`, problems);
|
|
265
273
|
const p = (msg) => problems.push(`${where} (${type}): ${msg}`);
|
|
266
274
|
const nonNegative = (key) => {
|
|
267
|
-
if (
|
|
275
|
+
if (command3[key] !== void 0 && !(isNum(command3[key]) && command3[key] >= 0)) p(`"${key}" must be a number of milliseconds \u2265 0.`);
|
|
268
276
|
};
|
|
269
277
|
const fraction = (key) => {
|
|
270
|
-
if (
|
|
278
|
+
if (command3[key] !== void 0 && !(isNum(command3[key]) && command3[key] >= 0 && command3[key] <= 1)) p(`"${key}" must be a fraction from 0 to 1.`);
|
|
271
279
|
};
|
|
272
280
|
const optionalNumber = (key) => {
|
|
273
|
-
if (
|
|
281
|
+
if (command3[key] !== void 0 && !isNum(command3[key])) p(`"${key}" must be a number.`);
|
|
274
282
|
};
|
|
275
|
-
if (
|
|
276
|
-
if (DRAW_ORDER_KEYS.some((k) =>
|
|
277
|
-
if (type === "enter" &&
|
|
278
|
-
if (
|
|
279
|
-
if (
|
|
280
|
-
if (
|
|
281
|
-
if (
|
|
282
|
-
if (
|
|
283
|
+
if (command3.with !== void 0 && command3.with !== "after" && command3.with !== "previous") p(`"with" must be "after" or "previous".`);
|
|
284
|
+
if (DRAW_ORDER_KEYS.some((k) => command3[k] !== void 0)) {
|
|
285
|
+
if (type === "enter" && command3.style !== "draw" || type === "exit" && command3.style !== "undraw") p(`"order", "pace", "align", "sortBy" and "origin" go with drawing: style "${type === "enter" ? "draw" : "undraw"}".`);
|
|
286
|
+
if (command3.order !== void 0 && command3.order !== "together" && command3.order !== "sequence") p(`"order" must be "together" or "sequence" (one stroke after another).`);
|
|
287
|
+
if (command3.pace !== void 0 && command3.pace !== "time" && command3.pace !== "speed") p(`"pace" must be "time" (each stroke takes the whole time) or "speed" (all at one speed).`);
|
|
288
|
+
if (command3.align !== void 0 && command3.align !== "start" && command3.align !== "end") p(`"align" must be "start" or "end".`);
|
|
289
|
+
if (command3.sortBy !== void 0 && command3.sortBy !== "document" && command3.sortBy !== "distance") p(`"sortBy" must be "document" or "distance".`);
|
|
290
|
+
if (command3.origin !== void 0 && !isPoint(command3.origin)) p(`"origin" must be { "x": number, "y": number } (document units).`);
|
|
283
291
|
}
|
|
284
|
-
if (
|
|
292
|
+
if (command3.note !== void 0 && typeof command3.note !== "string") p(`"note" must be a string.`);
|
|
285
293
|
if (type === "wait") {
|
|
286
|
-
if (!isNum(
|
|
294
|
+
if (!isNum(command3.duration) || command3.duration < 0) p(`"duration" must be a number of milliseconds \u2265 0.`);
|
|
287
295
|
return problems;
|
|
288
296
|
}
|
|
289
|
-
if (!Array.isArray(
|
|
297
|
+
if (!Array.isArray(command3.targets) || command3.targets.length === 0 || !command3.targets.every((t) => typeof t === "string" && t.length > 0)) p(`"targets" must be a non-empty list of node ids.`);
|
|
290
298
|
nonNegative("duration");
|
|
291
299
|
nonNegative("delay");
|
|
292
300
|
nonNegative("stagger");
|
|
293
|
-
if (
|
|
294
|
-
if (
|
|
301
|
+
if (command3.ease !== void 0 && !_chunk2FHLHZALcjs.isAnimationEasing.call(void 0, command3.ease)) p(`"ease" is not an easing; use a preset such as "ease-in-out" or "spring-bouncy", or { "type": "cubic-bezier", \u2026 } or { "type": "spring", \u2026 }.`);
|
|
302
|
+
if (command3.repeat !== void 0) {
|
|
295
303
|
if (type === "enter" || type === "exit") p(`"repeat" is not for ${type} (it brings things in or out once); repeat an emphasis or a move instead.`);
|
|
296
|
-
else if (!(Number.isInteger(
|
|
304
|
+
else if (!(Number.isInteger(command3.repeat) && command3.repeat >= 1 && command3.repeat <= 1e3)) p(`"repeat" must be a whole number from 1 to 1000.`);
|
|
297
305
|
}
|
|
298
|
-
if (
|
|
299
|
-
if (
|
|
300
|
-
if (
|
|
306
|
+
if (command3.blend !== void 0 && !MOTION_BLENDS.includes(command3.blend)) p(`"blend" must be "replace" (the change takes over) or "add" (a layer on top).`);
|
|
307
|
+
if (command3.split !== void 0 && !MOTION_TEXT_UNITS.includes(command3.split)) p(`"split" must be letter, word or line (for outlined text: a group of letter paths).`);
|
|
308
|
+
if (command3.cascade !== void 0 && !MOTION_CASCADES.includes(command3.cascade)) p(`"cascade" must be one of ${MOTION_CASCADES.join(", ")}.`);
|
|
309
|
+
if (command3.cascade !== void 0 && command3.split === void 0) p(`"cascade" goes with "split".`);
|
|
310
|
+
if (command3.repeatMode !== void 0 && !MOTION_REPEAT_MODES.includes(command3.repeatMode)) p(`"repeatMode" must be one of ${MOTION_REPEAT_MODES.join(", ")}.`);
|
|
311
|
+
if (command3.steps !== void 0 && !(isNum(command3.steps) && command3.steps > 0 && command3.steps <= 120)) p(`"steps" must be frames per second from above 0 to 120 (12 holds each pose for two frames at 24 fps).`);
|
|
301
312
|
switch (type) {
|
|
302
313
|
case "enter":
|
|
303
314
|
case "exit": {
|
|
304
315
|
const styles = type === "enter" ? MOTION_ENTER_STYLES : MOTION_EXIT_STYLES;
|
|
305
|
-
if (
|
|
306
|
-
p(`"style" must be one of ${styles.join(", ")}${typeof
|
|
307
|
-
if (
|
|
316
|
+
if (command3.style !== void 0 && !(typeof command3.style === "string" && styles.includes(command3.style)))
|
|
317
|
+
p(`"style" must be one of ${styles.join(", ")}${typeof command3.style === "string" ? ` (got ${namedWithSuggestion(command3.style, styles)})` : ""}.`);
|
|
318
|
+
if (command3.direction !== void 0 && !MOTION_DIRECTIONS.includes(command3.direction)) p(`"direction" must be one of ${MOTION_DIRECTIONS.join(", ")}.`);
|
|
308
319
|
optionalNumber("distance");
|
|
309
|
-
if (
|
|
310
|
-
if (
|
|
311
|
-
if (
|
|
320
|
+
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).`);
|
|
321
|
+
if (command3.shape !== void 0 && !MOTION_IRIS_SHAPES.includes(command3.shape)) p(`"shape" must be one of ${MOTION_IRIS_SHAPES.join(", ")} (the opening of an iris).`);
|
|
322
|
+
if (command3.orientation !== void 0 && !MOTION_SPLIT_ORIENTATIONS.includes(command3.orientation)) p(`"orientation" must be one of ${MOTION_SPLIT_ORIENTATIONS.join(", ")} (the line a split opens from).`);
|
|
312
323
|
break;
|
|
313
324
|
}
|
|
314
325
|
case "draw":
|
|
315
326
|
fraction("from");
|
|
316
327
|
fraction("to");
|
|
317
328
|
fraction("comet");
|
|
318
|
-
if (
|
|
329
|
+
if (command3.comet !== void 0 && (command3.from !== void 0 || command3.to !== void 0)) p(`"comet" runs the whole path; leave out "from" and "to".`);
|
|
319
330
|
break;
|
|
320
331
|
case "move":
|
|
321
|
-
if (
|
|
322
|
-
if (
|
|
323
|
-
if (
|
|
324
|
-
if (
|
|
325
|
-
if (
|
|
326
|
-
if (
|
|
327
|
-
if (
|
|
332
|
+
if (command3.by === void 0 && command3.to === void 0) p(`give "by" (an offset) or "to" (a point).`);
|
|
333
|
+
if (command3.by !== void 0 && command3.to !== void 0) p(`give "by" or "to", not both.`);
|
|
334
|
+
if (command3.by !== void 0 && !isPoint(command3.by)) p(`"by" must be { "x": number, "y": number }.`);
|
|
335
|
+
if (command3.to !== void 0 && !isPoint(command3.to)) p(`"to" must be { "x": number, "y": number }.`);
|
|
336
|
+
if (command3.via !== void 0 && !(Array.isArray(command3.via) && command3.via.length > 0 && command3.via.length <= 64 && command3.via.every(isPoint))) p(`"via" must be a list of 1 to 64 points { "x": number, "y": number } (document units).`);
|
|
337
|
+
if (command3.pacing !== void 0 && command3.pacing !== "even" && command3.pacing !== "equal") p(`"pacing" must be "even" (steady speed) or "equal" (each leg the same time).`);
|
|
338
|
+
if (command3.pacing !== void 0 && command3.via === void 0) p(`"pacing" goes with "via".`);
|
|
328
339
|
break;
|
|
329
340
|
case "rotate":
|
|
330
|
-
if (
|
|
331
|
-
if (
|
|
341
|
+
if (command3.by === void 0 && command3.to === void 0) p(`give "by" or "to" (degrees).`);
|
|
342
|
+
if (command3.by !== void 0 && command3.to !== void 0) p(`give "by" or "to", not both.`);
|
|
332
343
|
optionalNumber("by");
|
|
333
344
|
optionalNumber("to");
|
|
334
345
|
break;
|
|
335
346
|
case "scale":
|
|
336
|
-
if (!(isNum(
|
|
337
|
-
if (
|
|
347
|
+
if (!(isNum(command3.to) || isPoint(command3.to))) p(`"to" must be a number or { "x": number, "y": number }.`);
|
|
348
|
+
if (command3.geometric !== void 0 && typeof command3.geometric !== "boolean") p(`"geometric" must be true or false.`);
|
|
338
349
|
break;
|
|
339
350
|
case "fade":
|
|
340
|
-
if (!(isNum(
|
|
351
|
+
if (!(isNum(command3.to) && command3.to >= 0 && command3.to <= 1)) p(`"to" must be an opacity from 0 to 1.`);
|
|
341
352
|
break;
|
|
342
353
|
case "style":
|
|
343
|
-
if (
|
|
344
|
-
if (
|
|
345
|
-
if (
|
|
346
|
-
if (
|
|
354
|
+
if (command3.fill === void 0 && command3.stroke === void 0 && command3.strokeWidth === void 0) p(`give at least one of "fill", "stroke" or "strokeWidth".`);
|
|
355
|
+
if (command3.fill !== void 0 && typeof command3.fill !== "string") p(`"fill" must be a CSS colour.`);
|
|
356
|
+
if (command3.stroke !== void 0 && typeof command3.stroke !== "string") p(`"stroke" must be a CSS colour.`);
|
|
357
|
+
if (command3.strokeWidth !== void 0 && !(isNum(command3.strokeWidth) && command3.strokeWidth >= 0)) p(`"strokeWidth" must be a number \u2265 0.`);
|
|
347
358
|
break;
|
|
348
359
|
case "play":
|
|
349
|
-
if (typeof
|
|
350
|
-
if (
|
|
360
|
+
if (typeof command3.clip !== "string" || !command3.clip) p(`"clip" must be the name of one of the scene's clips.`);
|
|
361
|
+
if (command3.speed !== void 0 && !(isNum(command3.speed) && command3.speed >= 0.05 && command3.speed <= 20)) p(`"speed" must be a number from 0.05 to 20 (2 plays the clip twice as fast).`);
|
|
351
362
|
break;
|
|
352
363
|
case "morph":
|
|
353
364
|
case "match":
|
|
354
|
-
if (typeof
|
|
365
|
+
if (typeof command3.into !== "string" || !command3.into) p(`"into" must be the id of a ${type === "match" ? "group to become" : "node whose shape to take"}.`);
|
|
355
366
|
break;
|
|
356
367
|
case "follow":
|
|
357
|
-
if (typeof
|
|
358
|
-
if (
|
|
368
|
+
if (typeof command3.path !== "string" || !command3.path) p(`"path" must be the id of a path node.`);
|
|
369
|
+
if (command3.rotate !== void 0 && typeof command3.rotate !== "boolean") p(`"rotate" must be true or false.`);
|
|
359
370
|
fraction("from");
|
|
360
371
|
fraction("to");
|
|
361
372
|
break;
|
|
@@ -366,22 +377,22 @@ function commandShapeProblems(command2, where) {
|
|
|
366
377
|
case "color-pulse":
|
|
367
378
|
optionalNumber("amount");
|
|
368
379
|
optionalNumber("angle");
|
|
369
|
-
if (
|
|
370
|
-
if (
|
|
371
|
-
if (
|
|
372
|
-
if (
|
|
380
|
+
if (command3.count !== void 0 && !(Number.isInteger(command3.count) && command3.count >= 1)) p(`"count" must be a whole number \u2265 1.`);
|
|
381
|
+
if (command3.axis !== void 0 && command3.axis !== "horizontal" && command3.axis !== "vertical") p(`"axis" must be "horizontal" or "vertical".`);
|
|
382
|
+
if (command3.color !== void 0 && typeof command3.color !== "string") p(`"color" must be a CSS colour.`);
|
|
383
|
+
if (command3.paint !== void 0 && command3.paint !== "fill" && command3.paint !== "stroke") p(`"paint" must be "fill" or "stroke".`);
|
|
373
384
|
break;
|
|
374
385
|
case "wiggle":
|
|
375
386
|
optionalNumber("amount");
|
|
376
387
|
optionalNumber("rotate");
|
|
377
|
-
if (
|
|
378
|
-
if (
|
|
379
|
-
if (
|
|
388
|
+
if (command3.frequency !== void 0 && !(isNum(command3.frequency) && command3.frequency > 0)) p(`"frequency" must be a number of Hz > 0.`);
|
|
389
|
+
if (command3.octaves !== void 0 && !(Number.isInteger(command3.octaves) && command3.octaves >= 1 && command3.octaves <= 8)) p(`"octaves" must be a whole number from 1 to 8.`);
|
|
390
|
+
if (command3.seed !== void 0 && !(Number.isInteger(command3.seed) && command3.seed >= 0)) p(`"seed" must be a whole number \u2265 0.`);
|
|
380
391
|
break;
|
|
381
392
|
case "effect":
|
|
382
|
-
if (typeof
|
|
383
|
-
if (typeof
|
|
384
|
-
if (!isNum(
|
|
393
|
+
if (typeof command3.effect !== "string" || !command3.effect) p(`"effect" must be the id of one of the node's effects.`);
|
|
394
|
+
if (typeof command3.param !== "string" || !command3.param) p(`"param" must name a numeric parameter of the effect.`);
|
|
395
|
+
if (!isNum(command3.to)) p(`"to" must be a number.`);
|
|
385
396
|
break;
|
|
386
397
|
}
|
|
387
398
|
return problems;
|
|
@@ -398,9 +409,9 @@ function clipsShapeProblems(clips) {
|
|
|
398
409
|
}
|
|
399
410
|
unknownKeys(clip, ["description", "run"], where, problems);
|
|
400
411
|
if (clip.description !== void 0 && typeof clip.description !== "string") problems.push(`${where}: "description" must be a string.`);
|
|
401
|
-
clip.run.forEach((
|
|
402
|
-
if (isObject(
|
|
403
|
-
else problems.push(...commandShapeProblems(
|
|
412
|
+
clip.run.forEach((command3, i) => {
|
|
413
|
+
if (isObject(command3) && command3.type === "play") problems.push(`${where}, command ${i + 1}: a clip cannot play another clip; copy its commands in instead.`);
|
|
414
|
+
else problems.push(...commandShapeProblems(command3, `${where}, command ${i + 1}`));
|
|
404
415
|
});
|
|
405
416
|
}
|
|
406
417
|
return problems;
|
|
@@ -456,7 +467,7 @@ function shotShapeProblems(shot, where) {
|
|
|
456
467
|
}
|
|
457
468
|
}
|
|
458
469
|
if (!Array.isArray(shot.run)) problems.push(`${name}: "run" must be a list of commands (it may be empty).`);
|
|
459
|
-
else shot.run.forEach((
|
|
470
|
+
else shot.run.forEach((command3, i) => problems.push(...commandShapeProblems(command3, `${name}, command ${i + 1}`)));
|
|
460
471
|
return problems;
|
|
461
472
|
}
|
|
462
473
|
function motionSceneShapeProblems(input) {
|
|
@@ -523,7 +534,7 @@ function motionSceneToJson(scene, space = 2) {
|
|
|
523
534
|
return JSON.stringify(scene, null, space);
|
|
524
535
|
}
|
|
525
536
|
var isMotionShot = (shot) => shotShapeProblems(shot, "Shot").length === 0;
|
|
526
|
-
var isMotionCommand = (
|
|
537
|
+
var isMotionCommand = (command3) => commandShapeProblems(command3, "Command").length === 0;
|
|
527
538
|
|
|
528
539
|
// src/animation-editor/match.ts
|
|
529
540
|
var SEPARATOR = /[-_/.:]/;
|
|
@@ -611,6 +622,87 @@ function smoothMotionTimes(points, start, duration, pacing = "even") {
|
|
|
611
622
|
return times;
|
|
612
623
|
}
|
|
613
624
|
|
|
625
|
+
// src/animation-editor/text.ts
|
|
626
|
+
function motionTextLayout(nodes, id) {
|
|
627
|
+
const group = _optionalChain([nodes, 'access', _7 => _7.get, 'call', _8 => _8(id), 'optionalAccess', _9 => _9.node]);
|
|
628
|
+
if (!group || group.type !== "group") return null;
|
|
629
|
+
const letters = _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, group).map((p) => ({ id: p.id, b: _optionalChain([nodes, 'access', _10 => _10.get, 'call', _11 => _11(p.id), 'optionalAccess', _12 => _12.bounds]) })).filter((l) => !!l.b && l.b.width + l.b.height > 0);
|
|
630
|
+
if (!letters.length) return null;
|
|
631
|
+
const lines = [];
|
|
632
|
+
for (const l of [...letters].sort((a, c) => a.b.y + a.b.height / 2 - (c.b.y + c.b.height / 2))) {
|
|
633
|
+
const cy = l.b.y + l.b.height / 2;
|
|
634
|
+
const line = lines.find((x) => cy >= x.top && cy <= x.bottom);
|
|
635
|
+
if (line) {
|
|
636
|
+
line.letters.push(l);
|
|
637
|
+
line.top = Math.min(line.top, l.b.y);
|
|
638
|
+
line.bottom = Math.max(line.bottom, l.b.y + l.b.height);
|
|
639
|
+
} else lines.push({ top: l.b.y, bottom: l.b.y + l.b.height, letters: [l] });
|
|
640
|
+
}
|
|
641
|
+
lines.sort((a, c) => a.top - c.top);
|
|
642
|
+
return {
|
|
643
|
+
lines: lines.map((line) => {
|
|
644
|
+
const row = [...line.letters].sort((a, c) => a.b.x - c.b.x);
|
|
645
|
+
const heights = row.map((l) => l.b.height).sort((a, c) => a - c);
|
|
646
|
+
const gap = heights[Math.floor(heights.length / 2)] * 0.35;
|
|
647
|
+
const words = [];
|
|
648
|
+
row.forEach((l, i) => {
|
|
649
|
+
const prev = row[i - 1];
|
|
650
|
+
if (!prev || l.b.x - (prev.b.x + prev.b.width) > gap) words.push({ letters: [] });
|
|
651
|
+
words[words.length - 1].letters.push(l.id);
|
|
652
|
+
});
|
|
653
|
+
return { words };
|
|
654
|
+
})
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
function motionTextUnits(layout, by) {
|
|
658
|
+
if (by === "line") return layout.lines.map((l) => l.words.flatMap((w) => w.letters));
|
|
659
|
+
if (by === "word") return layout.lines.flatMap((l) => l.words.map((w) => w.letters));
|
|
660
|
+
return layout.lines.flatMap((l) => l.words.flatMap((w) => w.letters.map((id) => [id])));
|
|
661
|
+
}
|
|
662
|
+
function motionCascade(units, cascade = "forward", seed = 1) {
|
|
663
|
+
const n = units.length;
|
|
664
|
+
const mid = (n - 1) / 2;
|
|
665
|
+
const indexed = units.map((u, i) => ({ u, i }));
|
|
666
|
+
if (cascade === "backward") return [...units].reverse();
|
|
667
|
+
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);
|
|
668
|
+
if (cascade === "edges") return indexed.sort((a, b) => Math.abs(b.i - mid) - Math.abs(a.i - mid) || a.i - b.i).map((x) => x.u);
|
|
669
|
+
if (cascade === "random") {
|
|
670
|
+
let s = seed >>> 0 || 1;
|
|
671
|
+
const rand = () => {
|
|
672
|
+
s = s + 1831565813 >>> 0;
|
|
673
|
+
let t = s;
|
|
674
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
675
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
676
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
677
|
+
};
|
|
678
|
+
const out = [...units];
|
|
679
|
+
for (let i = n - 1; i > 0; i--) {
|
|
680
|
+
const j = Math.floor(rand() * (i + 1));
|
|
681
|
+
[out[i], out[j]] = [out[j], out[i]];
|
|
682
|
+
}
|
|
683
|
+
return out;
|
|
684
|
+
}
|
|
685
|
+
return [...units];
|
|
686
|
+
}
|
|
687
|
+
var MOTION_TEXT_STAGGER = { letter: 40, word: 120, line: 300 };
|
|
688
|
+
function motionCommandSlots(nodes, command3) {
|
|
689
|
+
if (!command3.split) return { slots: command3.targets.map((id, k) => ({ id, slot: k })), stagger: _nullishCoalesce(command3.stagger, () => ( 0)) };
|
|
690
|
+
const slots = [];
|
|
691
|
+
let slot = 0;
|
|
692
|
+
for (const target of command3.targets) {
|
|
693
|
+
const layout = motionTextLayout(nodes, target);
|
|
694
|
+
if (!layout) {
|
|
695
|
+
slots.push({ id: target, slot: slot++ });
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
for (const unit of motionCascade(motionTextUnits(layout, command3.split), command3.cascade, _chunkZCNLBRT6cjs.motionSeedFromId.call(void 0, target))) {
|
|
699
|
+
for (const id of unit) slots.push({ id, slot });
|
|
700
|
+
slot++;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return { slots, stagger: _nullishCoalesce(command3.stagger, () => ( MOTION_TEXT_STAGGER[command3.split])) };
|
|
704
|
+
}
|
|
705
|
+
|
|
614
706
|
// src/animation-editor/compile.ts
|
|
615
707
|
var indexCache = /* @__PURE__ */ new WeakMap();
|
|
616
708
|
function indexMotionNodes(nodes) {
|
|
@@ -619,21 +711,21 @@ function indexMotionNodes(nodes) {
|
|
|
619
711
|
const out = /* @__PURE__ */ new Map();
|
|
620
712
|
const walk = (list, parentWorld, ancestors) => {
|
|
621
713
|
for (const node of list) {
|
|
622
|
-
const local =
|
|
623
|
-
const bounds =
|
|
714
|
+
const local = _chunk7MD7C6XQcjs.vectorNodeBounds.call(void 0, node);
|
|
715
|
+
const bounds = _chunk7MD7C6XQcjs.vectorNodeBounds.call(void 0, node, parentWorld);
|
|
624
716
|
const center = local ? { x: local.x + local.width / 2, y: local.y + local.height / 2 } : { x: 0, y: 0 };
|
|
625
717
|
if (!out.has(node.id)) out.set(node.id, { node, ancestors, parentWorld, center, bounds, box: local });
|
|
626
|
-
if (node.type === "group") walk(node.children,
|
|
718
|
+
if (node.type === "group") walk(node.children, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, node), parentWorld), [...ancestors, node.id]);
|
|
627
719
|
}
|
|
628
720
|
};
|
|
629
|
-
walk(nodes,
|
|
721
|
+
walk(nodes, _chunk7MD7C6XQcjs.IDENTITY_MATRIX, []);
|
|
630
722
|
indexCache.set(nodes, out);
|
|
631
723
|
return out;
|
|
632
724
|
}
|
|
633
725
|
var solid = (paint) => typeof paint === "string" && paint !== "none" ? paint : void 0;
|
|
634
726
|
function firstPaint(node, key) {
|
|
635
727
|
if (node.type === "path") return solid(node[key]);
|
|
636
|
-
for (const p of
|
|
728
|
+
for (const p of _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node)) {
|
|
637
729
|
const s = solid(p[key]);
|
|
638
730
|
if (s) return s;
|
|
639
731
|
}
|
|
@@ -641,7 +733,7 @@ function firstPaint(node, key) {
|
|
|
641
733
|
}
|
|
642
734
|
function strokeReach(node) {
|
|
643
735
|
let reach = 0;
|
|
644
|
-
for (const p of node.type === "path" ? [node] :
|
|
736
|
+
for (const p of node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node)) {
|
|
645
737
|
if (p.stroke == null || p.stroke === "none") continue;
|
|
646
738
|
const width = _nullishCoalesce(p.strokeWidth, () => ( 1));
|
|
647
739
|
reach = Math.max(reach, p.strokeAlign === "outside" ? width : p.strokeAlign === "inside" ? 0 : width / 2);
|
|
@@ -690,10 +782,10 @@ function motionRevealClip(entry, reveal) {
|
|
|
690
782
|
}
|
|
691
783
|
}
|
|
692
784
|
function motionRestValue(entry, property, artwork) {
|
|
693
|
-
const node = _optionalChain([entry, 'optionalAccess',
|
|
785
|
+
const node = _optionalChain([entry, 'optionalAccess', _13 => _13.node]);
|
|
694
786
|
switch (property) {
|
|
695
787
|
case "opacity":
|
|
696
|
-
return _nullishCoalesce(_optionalChain([node, 'optionalAccess',
|
|
788
|
+
return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _14 => _14.opacity]), () => ( 1));
|
|
697
789
|
case "x":
|
|
698
790
|
case "y":
|
|
699
791
|
case "rotation":
|
|
@@ -711,11 +803,11 @@ function motionRestValue(entry, property, artwork) {
|
|
|
711
803
|
case "stroke":
|
|
712
804
|
return _nullishCoalesce((node && firstPaint(node, property)), () => ( "transparent"));
|
|
713
805
|
case "strokeWidth": {
|
|
714
|
-
const path = _optionalChain([node, 'optionalAccess',
|
|
715
|
-
return _nullishCoalesce(_optionalChain([path, 'optionalAccess',
|
|
806
|
+
const path = _optionalChain([node, 'optionalAccess', _15 => _15.type]) === "path" ? node : node ? _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node)[0] : void 0;
|
|
807
|
+
return _nullishCoalesce(_optionalChain([path, 'optionalAccess', _16 => _16.strokeWidth]), () => ( 1));
|
|
716
808
|
}
|
|
717
809
|
case "shape":
|
|
718
|
-
return _nullishCoalesce(_optionalChain([node, 'optionalAccess',
|
|
810
|
+
return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _17 => _17.id]), () => ( ""));
|
|
719
811
|
case "clipRect":
|
|
720
812
|
case "clipCircle": {
|
|
721
813
|
const pad = entry && motionRevealPadding(entry);
|
|
@@ -725,7 +817,7 @@ function motionRestValue(entry, property, artwork) {
|
|
|
725
817
|
return [0, 0, artwork.width, artwork.height];
|
|
726
818
|
}
|
|
727
819
|
const [, effectId, param] = property.split(":");
|
|
728
|
-
const effect = _optionalChain([node, 'optionalAccess',
|
|
820
|
+
const effect = _optionalChain([node, 'optionalAccess', _18 => _18.effects, 'optionalAccess', _19 => _19.find, 'call', _20 => _20((e) => e.id === effectId)]);
|
|
729
821
|
const v = effect ? effect.params[param] : void 0;
|
|
730
822
|
return typeof v === "number" ? v : 0;
|
|
731
823
|
}
|
|
@@ -774,13 +866,13 @@ function segmentValue(segment, time, raw = false) {
|
|
|
774
866
|
return typeof segment.from === "string" ? interpolateMotionValue(segment.from, segment.to, Math.min(1, Math.max(0, p))) : interpolateMotionValue(segment.from, segment.to, p);
|
|
775
867
|
}
|
|
776
868
|
function activeSegment(track, time) {
|
|
777
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
869
|
+
if (!_optionalChain([track, 'optionalAccess', _21 => _21.length])) return void 0;
|
|
778
870
|
let found;
|
|
779
871
|
for (const s of track) if (s.start <= time && (!found || s.start >= found.start)) found = s;
|
|
780
872
|
return found;
|
|
781
873
|
}
|
|
782
874
|
function trackValue(track, time, raw = false) {
|
|
783
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
875
|
+
if (!_optionalChain([track, 'optionalAccess', _22 => _22.length])) return void 0;
|
|
784
876
|
const s = activeSegment(track, time);
|
|
785
877
|
if (s) return segmentValue(s, time, raw);
|
|
786
878
|
let first = track[0];
|
|
@@ -813,7 +905,7 @@ function fitMotionRect(rect, aspect) {
|
|
|
813
905
|
function resolveMotionCamera(camera, scene) {
|
|
814
906
|
if ("frame" in camera && typeof camera.frame === "string") {
|
|
815
907
|
const entry = indexMotionNodes(scene.artwork.nodes).get(camera.frame);
|
|
816
|
-
if (!_optionalChain([entry, 'optionalAccess',
|
|
908
|
+
if (!_optionalChain([entry, 'optionalAccess', _23 => _23.bounds])) return null;
|
|
817
909
|
const pad = _nullishCoalesce(camera.padding, () => ( 24));
|
|
818
910
|
const b = entry.bounds;
|
|
819
911
|
const rect = { x: b.x - pad, y: b.y - pad, width: Math.max(1, b.width + pad * 2), height: Math.max(1, b.height + pad * 2) };
|
|
@@ -822,12 +914,12 @@ function resolveMotionCamera(camera, scene) {
|
|
|
822
914
|
const r = camera;
|
|
823
915
|
return { x: r.x, y: r.y, width: r.width, height: r.height };
|
|
824
916
|
}
|
|
825
|
-
function motionPathLength(node, parentWorld =
|
|
917
|
+
function motionPathLength(node, parentWorld = _chunk7MD7C6XQcjs.IDENTITY_MATRIX) {
|
|
826
918
|
let longest = 0;
|
|
827
|
-
const paths = node.type === "path" ? [node] :
|
|
919
|
+
const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
|
|
828
920
|
for (const p of paths) {
|
|
829
921
|
try {
|
|
830
|
-
longest = Math.max(longest,
|
|
922
|
+
longest = Math.max(longest, _chunkXGD3FSNCcjs.bezierPathLength.call(void 0, _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, p, parentWorld, { effects: false })));
|
|
831
923
|
} catch (e2) {
|
|
832
924
|
}
|
|
833
925
|
}
|
|
@@ -848,12 +940,12 @@ function motionBeatAt(grid, ms) {
|
|
|
848
940
|
function motionCueTime(scene, cue) {
|
|
849
941
|
if (typeof cue.ms === "number") return Math.max(0, cue.ms);
|
|
850
942
|
if (typeof cue.beat === "number") return scene.beat && scene.beat.bpm > 0 ? Math.max(0, motionBeatTime(scene.beat, cue.beat)) : void 0;
|
|
851
|
-
if (typeof cue.word === "number") return _optionalChain([scene, 'access',
|
|
943
|
+
if (typeof cue.word === "number") return _optionalChain([scene, 'access', _24 => _24.narration, 'optionalAccess', _25 => _25.words, 'access', _26 => _26[cue.word], 'optionalAccess', _27 => _27.start]);
|
|
852
944
|
return void 0;
|
|
853
945
|
}
|
|
854
946
|
var SCALE_LIKE = /* @__PURE__ */ new Set(["scaleX", "scaleY", "opacity"]);
|
|
855
947
|
function motionPropertyValue(timeline, node, property, time, raw = false, depth = 0) {
|
|
856
|
-
const rest = property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access',
|
|
948
|
+
const rest = property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access', _28 => _28.restOpacity, 'optionalAccess', _29 => _29.get, 'call', _30 => _30(node)]), () => ( 1)) : SCALE_LIKE.has(property) ? 1 : 0;
|
|
857
949
|
const v = trackValue(timeline.tracks.get(motionTrackKey(node, property)), time, raw);
|
|
858
950
|
const base = property === "opacity" ? typeof v === "number" ? v : rest : withMotionLayers(timeline, node, property, typeof v === "number" ? v : rest, time, raw);
|
|
859
951
|
return applyMotionDrivers(timeline, node, property, base, time, raw, depth);
|
|
@@ -864,7 +956,7 @@ function applyMotionDrivers(timeline, node, property, value, time, raw = false,
|
|
|
864
956
|
for (const d of timeline.drivers) {
|
|
865
957
|
if (d.target !== node || d.property !== property) continue;
|
|
866
958
|
const src = motionPropertyValue(timeline, d.source.node, d.source.property, time, raw, depth + 1);
|
|
867
|
-
const srcRest = d.source.property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access',
|
|
959
|
+
const srcRest = d.source.property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access', _31 => _31.restOpacity, 'optionalAccess', _32 => _32.get, 'call', _33 => _33(d.source.node)]), () => ( 1)) : SCALE_LIKE.has(d.source.property) ? 1 : 0;
|
|
868
960
|
let change = (src - srcRest) * (_nullishCoalesce(d.factor, () => ( 1))) + (_nullishCoalesce(d.offset, () => ( 0)));
|
|
869
961
|
if (d.clamp) change = Math.min(d.clamp[1], Math.max(d.clamp[0], change));
|
|
870
962
|
v = SCALE_LIKE.has(property) ? v * (1 + change) : v + change;
|
|
@@ -886,16 +978,16 @@ function motionDriverSources(timeline, node, properties, seen = /* @__PURE__ */
|
|
|
886
978
|
}
|
|
887
979
|
return out;
|
|
888
980
|
}
|
|
889
|
-
function motionCommandRepeat(
|
|
890
|
-
if (
|
|
891
|
-
const n = _nullishCoalesce(
|
|
981
|
+
function motionCommandRepeat(command3) {
|
|
982
|
+
if (command3.type === "wait" || command3.type === "enter" || command3.type === "exit") return 1;
|
|
983
|
+
const n = _nullishCoalesce(command3.repeat, () => ( 1));
|
|
892
984
|
return Number.isInteger(n) && n >= 1 ? n : 1;
|
|
893
985
|
}
|
|
894
|
-
function motionCommandDuration(
|
|
895
|
-
return motionCycleDuration(
|
|
986
|
+
function motionCommandDuration(command3, scene, target) {
|
|
987
|
+
return motionCycleDuration(command3, scene, target) * motionCommandRepeat(command3);
|
|
896
988
|
}
|
|
897
989
|
function motionClipLayout(scene, clip, target, speed = 1) {
|
|
898
|
-
const run = _optionalChain([scene, 'access',
|
|
990
|
+
const run = _optionalChain([scene, 'access', _34 => _34.clips, 'optionalAccess', _35 => _35[clip], 'optionalAccess', _36 => _36.run]);
|
|
899
991
|
if (!run) return { items: [], length: 0 };
|
|
900
992
|
const f = speed > 0 && Number.isFinite(speed) ? 1 / speed : 1;
|
|
901
993
|
const items = [];
|
|
@@ -909,36 +1001,36 @@ function motionClipLayout(scene, clip, target, speed = 1) {
|
|
|
909
1001
|
return;
|
|
910
1002
|
}
|
|
911
1003
|
if (raw.type === "play") return;
|
|
912
|
-
const
|
|
913
|
-
const begin = base + (_nullishCoalesce(
|
|
1004
|
+
const command3 = { ...raw, targets: raw.targets.map((t) => t === MOTION_CLIP_TARGET ? target : t) };
|
|
1005
|
+
const begin = base + (_nullishCoalesce(command3.delay, () => ( 0))) * f;
|
|
914
1006
|
let end = begin;
|
|
915
|
-
|
|
916
|
-
const cycle = motionCycleDuration(
|
|
917
|
-
const s = begin + k * (_nullishCoalesce(
|
|
918
|
-
items.push({ command:
|
|
919
|
-
end = Math.max(end, s + cycle * motionCommandRepeat(
|
|
1007
|
+
command3.targets.forEach((t, k) => {
|
|
1008
|
+
const cycle = motionCycleDuration(command3, scene, t) * f;
|
|
1009
|
+
const s = begin + k * (_nullishCoalesce(command3.stagger, () => ( 0))) * f;
|
|
1010
|
+
items.push({ command: command3, target: t, start: s, cycle });
|
|
1011
|
+
end = Math.max(end, s + cycle * motionCommandRepeat(command3));
|
|
920
1012
|
});
|
|
921
1013
|
prevStart = begin;
|
|
922
1014
|
runEnd = Math.max(runEnd, end);
|
|
923
1015
|
});
|
|
924
1016
|
return { items, length: runEnd };
|
|
925
1017
|
}
|
|
926
|
-
function motionCycleDuration(
|
|
927
|
-
if (
|
|
928
|
-
if (
|
|
929
|
-
if (
|
|
930
|
-
if (
|
|
931
|
-
const ease = _chunk2FHLHZALcjs.resolveEasing.call(void 0,
|
|
1018
|
+
function motionCycleDuration(command3, scene, target) {
|
|
1019
|
+
if (command3.type === "wait") return command3.duration;
|
|
1020
|
+
if (command3.type === "play") return motionClipLayout(scene, command3.clip, _nullishCoalesce(target, () => ( MOTION_CLIP_TARGET)), command3.speed).length;
|
|
1021
|
+
if (command3.duration !== void 0) return command3.duration;
|
|
1022
|
+
if (command3.ease !== void 0) {
|
|
1023
|
+
const ease = _chunk2FHLHZALcjs.resolveEasing.call(void 0, command3.ease);
|
|
932
1024
|
if (ease !== "hold" && ease.type === "spring") return _chunk2FHLHZALcjs.springSettleMs.call(void 0, ease);
|
|
933
1025
|
}
|
|
934
|
-
if (
|
|
1026
|
+
if (command3.type === "draw" || command3.type === "enter" && command3.style === "draw" || command3.type === "exit" && command3.style === "undraw") {
|
|
935
1027
|
const entry = target ? indexMotionNodes(scene.artwork.nodes).get(target) : void 0;
|
|
936
1028
|
const length = entry ? motionPathLength(entry.node) : 0;
|
|
937
1029
|
const ms = length * MOTION_DRAW_MS_PER_UNIT;
|
|
938
1030
|
return Math.round(Math.min(MOTION_DRAW_RANGE[1], Math.max(MOTION_DRAW_RANGE[0], ms)));
|
|
939
1031
|
}
|
|
940
|
-
if (
|
|
941
|
-
return MOTION_DEFAULT_DURATIONS[
|
|
1032
|
+
if (command3.type === "move" && _optionalChain([command3, 'access', _37 => _37.via, 'optionalAccess', _38 => _38.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command3.via.length;
|
|
1033
|
+
return MOTION_DEFAULT_DURATIONS[command3.type];
|
|
942
1034
|
}
|
|
943
1035
|
var MOTION_EASE_OUT = { type: "cubic-bezier", x1: 1 / 3, y1: 1, x2: 2 / 3, y2: 1 };
|
|
944
1036
|
var MOTION_EASE_IN_OUT = { type: "cubic-bezier", x1: 0.65, y1: 0, x2: 0.35, y2: 1 };
|
|
@@ -974,14 +1066,15 @@ function compileMotionScene(scene) {
|
|
|
974
1066
|
const commandsStart = cursor;
|
|
975
1067
|
let runEnd = cursor;
|
|
976
1068
|
let prevStart = cursor;
|
|
977
|
-
shot.run.forEach((
|
|
978
|
-
const base =
|
|
979
|
-
const begin = base + (
|
|
980
|
-
const
|
|
981
|
-
const
|
|
982
|
-
const
|
|
983
|
-
const
|
|
984
|
-
|
|
1069
|
+
shot.run.forEach((command3, i) => {
|
|
1070
|
+
const base = command3.with === "previous" && i > 0 ? prevStart : runEnd;
|
|
1071
|
+
const begin = base + (command3.type === "wait" ? 0 : (_nullishCoalesce(command3.delay, () => ( 0))) * f);
|
|
1072
|
+
const split = command3.type === "wait" ? null : motionCommandSlots(nodes, command3);
|
|
1073
|
+
const slots = _nullishCoalesce(_optionalChain([split, 'optionalAccess', _39 => _39.slots]), () => ( []));
|
|
1074
|
+
const durations = command3.type === "wait" ? [command3.duration * f] : slots.map((s) => motionCommandDuration(command3, scene, s.id) * f);
|
|
1075
|
+
const stagger = (_nullishCoalesce(_optionalChain([split, 'optionalAccess', _40 => _40.stagger]), () => ( 0))) * f;
|
|
1076
|
+
const end2 = durations.reduce((m, d, k) => Math.max(m, begin + (_nullishCoalesce(_optionalChain([slots, 'access', _41 => _41[k], 'optionalAccess', _42 => _42.slot]), () => ( k))) * stagger + d), begin);
|
|
1077
|
+
commands.push({ shot: shot.id, shotIndex: index, command: i, type: command3.type, start: begin, end: end2, duration: _nullishCoalesce(durations[0], () => ( 0)) });
|
|
985
1078
|
prevStart = begin;
|
|
986
1079
|
runEnd = Math.max(runEnd, end2);
|
|
987
1080
|
});
|
|
@@ -1013,14 +1106,14 @@ function compileMotionScene(scene) {
|
|
|
1013
1106
|
}
|
|
1014
1107
|
for (const timing of commands) {
|
|
1015
1108
|
const shot = scene.shots[timing.shotIndex];
|
|
1016
|
-
const
|
|
1017
|
-
if (
|
|
1018
|
-
if (
|
|
1109
|
+
const command3 = shot.run[timing.command];
|
|
1110
|
+
if (command3.type === "wait") continue;
|
|
1111
|
+
if (command3.type === "play") {
|
|
1019
1112
|
const f = motionShotTimeScale(shot);
|
|
1020
|
-
|
|
1113
|
+
command3.targets.forEach((target, k) => {
|
|
1021
1114
|
if (!nodes.has(target)) return;
|
|
1022
|
-
const at = timing.start + k * (_nullishCoalesce(
|
|
1023
|
-
for (const item of motionClipLayout(scene,
|
|
1115
|
+
const at = timing.start + k * (_nullishCoalesce(command3.stagger, () => ( 0))) * f;
|
|
1116
|
+
for (const item of motionClipLayout(scene, command3.clip, target, (_nullishCoalesce(command3.speed, () => ( 1))) / f).items) {
|
|
1024
1117
|
const entry = nodes.get(item.target);
|
|
1025
1118
|
if (!entry) continue;
|
|
1026
1119
|
jobs.push({ start: at + item.start, order: order++, run: () => compileRepeated(item.command, item.target, entry, at + item.start, item.cycle, timing) });
|
|
@@ -1028,24 +1121,25 @@ function compileMotionScene(scene) {
|
|
|
1028
1121
|
});
|
|
1029
1122
|
continue;
|
|
1030
1123
|
}
|
|
1031
|
-
|
|
1124
|
+
const split = motionCommandSlots(nodes, command3);
|
|
1125
|
+
for (const { id: target, slot } of split.slots) {
|
|
1032
1126
|
const entry = nodes.get(target);
|
|
1033
|
-
if (!entry)
|
|
1127
|
+
if (!entry) continue;
|
|
1034
1128
|
const f = motionShotTimeScale(shot);
|
|
1035
|
-
const start = timing.start +
|
|
1036
|
-
const cycle = motionCycleDuration(
|
|
1037
|
-
jobs.push({ start, order: order++, run: () => compileRepeated(
|
|
1038
|
-
}
|
|
1129
|
+
const start = timing.start + slot * split.stagger * f;
|
|
1130
|
+
const cycle = motionCycleDuration(command3, scene, target) * f;
|
|
1131
|
+
jobs.push({ start, order: order++, run: () => compileRepeated(command3, target, entry, start, cycle, timing) });
|
|
1132
|
+
}
|
|
1039
1133
|
}
|
|
1040
1134
|
jobs.sort((a, b) => a.start - b.start || a.order - b.order).forEach((job) => job.run());
|
|
1041
|
-
function compileRepeated(
|
|
1135
|
+
function compileRepeated(command3, node, entry, start, cycle, timing) {
|
|
1042
1136
|
const first = segments.length;
|
|
1043
|
-
compileCommand(
|
|
1137
|
+
compileCommand(command3, node, entry, start, cycle, timing);
|
|
1044
1138
|
const made = segments.slice(first);
|
|
1045
|
-
const steps = _nullishCoalesce(
|
|
1139
|
+
const steps = _nullishCoalesce(command3.steps, () => ( scene.steps));
|
|
1046
1140
|
if (steps && steps > 0) for (const s of made) s.steps = steps;
|
|
1047
|
-
const n = motionCommandRepeat(
|
|
1048
|
-
const mode = _nullishCoalesce(
|
|
1141
|
+
const n = motionCommandRepeat(command3);
|
|
1142
|
+
const mode = _nullishCoalesce(command3.repeatMode, () => ( "loop"));
|
|
1049
1143
|
const shift = (v, by, k) => {
|
|
1050
1144
|
if (typeof v === "number" && typeof by === "number") return v + by * k;
|
|
1051
1145
|
if (Array.isArray(v) && Array.isArray(by) && v.length === by.length) return v.map((x, i) => x + by[i] * k);
|
|
@@ -1064,30 +1158,30 @@ function compileMotionScene(scene) {
|
|
|
1064
1158
|
}
|
|
1065
1159
|
}
|
|
1066
1160
|
}
|
|
1067
|
-
function compileCommand(
|
|
1161
|
+
function compileCommand(command3, node, entry, start, duration2, timing) {
|
|
1068
1162
|
const end = start + duration2;
|
|
1069
1163
|
const where = { shot: timing.shot, command: timing.command };
|
|
1070
1164
|
const seg = (property, to, ease2, s = start, e = end, extra = {}) => push({ node, property, start: s, end: e, from: _nullishCoalesce(extra.from, () => ( valueAt(node, property, s))), to, ease: ease2, ...where, ...extra });
|
|
1071
1165
|
const rest = (p) => motionRestValue(entry, p, artwork);
|
|
1072
|
-
const
|
|
1166
|
+
const num2 = (p, time = start) => {
|
|
1073
1167
|
const v = valueAt(node, p, time);
|
|
1074
1168
|
return typeof v === "number" ? v : 0;
|
|
1075
1169
|
};
|
|
1076
|
-
const ease =
|
|
1170
|
+
const ease = command3.ease;
|
|
1077
1171
|
const drawWindows = (s, e, o) => {
|
|
1078
1172
|
const order2 = _nullishCoalesce(o.order, () => ( "together"));
|
|
1079
1173
|
const pace = _nullishCoalesce(o.pace, () => ( "time"));
|
|
1080
1174
|
if (order2 === "together" && pace === "time") return null;
|
|
1081
|
-
const paths = entry.node.type === "path" ? [entry.node] :
|
|
1175
|
+
const paths = entry.node.type === "path" ? [entry.node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, entry.node);
|
|
1082
1176
|
let list = paths.map((p) => {
|
|
1083
1177
|
const at = nodes.get(p.id);
|
|
1084
1178
|
let first = { x: 0, y: 0 };
|
|
1085
1179
|
try {
|
|
1086
|
-
const m =
|
|
1180
|
+
const m = _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, p, _nullishCoalesce(_optionalChain([at, 'optionalAccess', _43 => _43.parentWorld]), () => ( _chunk7MD7C6XQcjs.IDENTITY_MATRIX)), { effects: false })[0];
|
|
1087
1181
|
if (m && m.type === "M") first = { x: m.x, y: m.y };
|
|
1088
1182
|
} catch (e3) {
|
|
1089
1183
|
}
|
|
1090
|
-
return { id: p.id, len: Math.max(1e-6, motionPathLength(p, _optionalChain([at, 'optionalAccess',
|
|
1184
|
+
return { id: p.id, len: Math.max(1e-6, motionPathLength(p, _optionalChain([at, 'optionalAccess', _44 => _44.parentWorld]))), first };
|
|
1091
1185
|
});
|
|
1092
1186
|
if (!list.length) return null;
|
|
1093
1187
|
const span = Math.max(0, e - s);
|
|
@@ -1111,42 +1205,42 @@ function compileMotionScene(scene) {
|
|
|
1111
1205
|
return o.align === "end" ? { id: p.id, start: e - d, end: e } : { id: p.id, start: s, end: s + d };
|
|
1112
1206
|
});
|
|
1113
1207
|
};
|
|
1114
|
-
switch (
|
|
1208
|
+
switch (command3.type) {
|
|
1115
1209
|
case "enter": {
|
|
1116
|
-
const style = _nullishCoalesce(
|
|
1210
|
+
const style = _nullishCoalesce(command3.style, () => ( "fade"));
|
|
1117
1211
|
const opacity = rest("opacity");
|
|
1118
|
-
const reveal = style === "wipe" ? motionRevealClip(entry, { style, direction:
|
|
1119
|
-
for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess',
|
|
1212
|
+
const reveal = style === "wipe" ? motionRevealClip(entry, { style, direction: command3.direction }) : style === "iris" ? motionRevealClip(entry, { style, shape: command3.shape }) : style === "split" ? motionRevealClip(entry, { style, orientation: command3.orientation }) : null;
|
|
1213
|
+
for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _45 => _45.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
|
|
1120
1214
|
if (reveal) {
|
|
1121
1215
|
seg("opacity", opacity, "linear", start, start);
|
|
1122
1216
|
seg(reveal.property, reveal.to, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: reveal.from });
|
|
1123
1217
|
break;
|
|
1124
1218
|
}
|
|
1125
1219
|
if (style === "draw") {
|
|
1126
|
-
const windows = drawWindows(start, start + duration2 * 0.75,
|
|
1220
|
+
const windows = drawWindows(start, start + duration2 * 0.75, command3);
|
|
1127
1221
|
if (windows) for (const w of windows) push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: 0, to: 1, ease: _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), ...where });
|
|
1128
1222
|
else seg("drawEnd", 1, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, start + duration2 * 0.75, { from: 0 });
|
|
1129
1223
|
seg("fillOpacity", 1, MOTION_EASE_OUT, start + duration2 * 0.6, end, { from: 0 });
|
|
1130
1224
|
break;
|
|
1131
1225
|
}
|
|
1132
1226
|
if (style === "pop" || style === "zoom") {
|
|
1133
|
-
const from = _nullishCoalesce(
|
|
1227
|
+
const from = _nullishCoalesce(command3.scale, () => ( (style === "pop" ? 0.5 : 1.6)));
|
|
1134
1228
|
seg("opacity", opacity, MOTION_EASE_OUT, start, start + duration2 * (style === "pop" ? 0.4 : 0.5), { from: 0 });
|
|
1135
1229
|
seg("scaleX", 1, _nullishCoalesce(ease, () => ( (style === "pop" ? "ease-out-back" : MOTION_EASE_OUT))), start, end, { from });
|
|
1136
1230
|
seg("scaleY", 1, _nullishCoalesce(ease, () => ( (style === "pop" ? "ease-out-back" : MOTION_EASE_OUT))), start, end, { from });
|
|
1137
1231
|
} else if (style === "rise") {
|
|
1138
|
-
const y =
|
|
1232
|
+
const y = num2("y");
|
|
1139
1233
|
seg("opacity", opacity, MOTION_EASE_OUT, start, start + duration2 * 0.5, { from: 0 });
|
|
1140
|
-
seg("y", y, _nullishCoalesce(ease, () => ( "ease-out-back")), start, end, { from: y + (_nullishCoalesce(
|
|
1234
|
+
seg("y", y, _nullishCoalesce(ease, () => ( "ease-out-back")), start, end, { from: y + (_nullishCoalesce(command3.distance, () => ( 20))) });
|
|
1141
1235
|
} else if (style === "grow") {
|
|
1142
1236
|
seg("opacity", opacity, MOTION_EASE_OUT, start, start + duration2 * 0.3, { from: 0 });
|
|
1143
1237
|
seg("scaleX", 1, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: 0 });
|
|
1144
1238
|
seg("scaleY", 1, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: 0 });
|
|
1145
1239
|
} else if (style === "slide") {
|
|
1146
|
-
const dir = DIRECTION[_nullishCoalesce(
|
|
1147
|
-
const distance = _nullishCoalesce(
|
|
1148
|
-
const x =
|
|
1149
|
-
const y =
|
|
1240
|
+
const dir = DIRECTION[_nullishCoalesce(command3.direction, () => ( "up"))];
|
|
1241
|
+
const distance = _nullishCoalesce(command3.distance, () => ( 40));
|
|
1242
|
+
const x = num2("x");
|
|
1243
|
+
const y = num2("y");
|
|
1150
1244
|
seg("opacity", opacity, MOTION_EASE_OUT, start, end, { from: 0 });
|
|
1151
1245
|
seg("x", x, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: x - dir.x * distance });
|
|
1152
1246
|
seg("y", y, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: y - dir.y * distance });
|
|
@@ -1154,12 +1248,12 @@ function compileMotionScene(scene) {
|
|
|
1154
1248
|
break;
|
|
1155
1249
|
}
|
|
1156
1250
|
case "exit": {
|
|
1157
|
-
const style = _nullishCoalesce(
|
|
1158
|
-
const wipe = style === "wipe" ? motionRevealClip(entry, { style, direction:
|
|
1251
|
+
const style = _nullishCoalesce(command3.style, () => ( "fade"));
|
|
1252
|
+
const wipe = style === "wipe" ? motionRevealClip(entry, { style, direction: command3.direction, hide: true }) : null;
|
|
1159
1253
|
if (wipe) seg(wipe.property, wipe.to, _nullishCoalesce(ease, () => ( "ease-in")), start, end, { from: wipe.from });
|
|
1160
1254
|
else if (style === "undraw") {
|
|
1161
1255
|
seg("fillOpacity", 0, "ease-in", start, start + duration2 * 0.4);
|
|
1162
|
-
const windows = drawWindows(start, end,
|
|
1256
|
+
const windows = drawWindows(start, end, command3);
|
|
1163
1257
|
if (windows) for (const w of windows) push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: valueAt(w.id, "drawEnd", w.start), to: 0, ease: _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), ...where });
|
|
1164
1258
|
else seg("drawEnd", 0, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
|
|
1165
1259
|
} else if (style === "shrink") {
|
|
@@ -1167,18 +1261,18 @@ function compileMotionScene(scene) {
|
|
|
1167
1261
|
seg("scaleY", 0, _nullishCoalesce(ease, () => ( "ease-in")));
|
|
1168
1262
|
seg("opacity", 0, "ease-in", start + duration2 * 0.6, end);
|
|
1169
1263
|
} else if (style === "slide") {
|
|
1170
|
-
const dir = DIRECTION[_nullishCoalesce(
|
|
1171
|
-
const distance = _nullishCoalesce(
|
|
1172
|
-
seg("x",
|
|
1173
|
-
seg("y",
|
|
1264
|
+
const dir = DIRECTION[_nullishCoalesce(command3.direction, () => ( "down"))];
|
|
1265
|
+
const distance = _nullishCoalesce(command3.distance, () => ( 40));
|
|
1266
|
+
seg("x", num2("x") + dir.x * distance, _nullishCoalesce(ease, () => ( "ease-in")));
|
|
1267
|
+
seg("y", num2("y") + dir.y * distance, _nullishCoalesce(ease, () => ( "ease-in")));
|
|
1174
1268
|
seg("opacity", 0, _nullishCoalesce(ease, () => ( "ease-in")));
|
|
1175
1269
|
} else seg("opacity", 0, _nullishCoalesce(ease, () => ( "ease-in")));
|
|
1176
1270
|
break;
|
|
1177
1271
|
}
|
|
1178
1272
|
case "draw": {
|
|
1179
1273
|
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
1180
|
-
const comet =
|
|
1181
|
-
const windows = _nullishCoalesce(drawWindows(start, end,
|
|
1274
|
+
const comet = command3.comet !== void 0 ? Math.min(1, Math.max(0, command3.comet)) : void 0;
|
|
1275
|
+
const windows = _nullishCoalesce(drawWindows(start, end, command3), () => ( [{ id: node, start, end }]));
|
|
1182
1276
|
for (const w of windows) {
|
|
1183
1277
|
if (comet !== void 0) {
|
|
1184
1278
|
push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: 0, to: 1 + comet, ease: e, ...where });
|
|
@@ -1186,27 +1280,27 @@ function compileMotionScene(scene) {
|
|
|
1186
1280
|
continue;
|
|
1187
1281
|
}
|
|
1188
1282
|
const drawn = tracks.has(motionTrackKey(w.id, "drawEnd"));
|
|
1189
|
-
push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: _nullishCoalesce(
|
|
1283
|
+
push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: _nullishCoalesce(command3.from, () => ( (drawn ? valueAt(w.id, "drawEnd", w.start) : 0))), to: _nullishCoalesce(command3.to, () => ( 1)), ease: e, ...where });
|
|
1190
1284
|
}
|
|
1191
1285
|
break;
|
|
1192
1286
|
}
|
|
1193
1287
|
case "move": {
|
|
1194
1288
|
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
1195
|
-
let dx = _nullishCoalesce(_optionalChain([
|
|
1196
|
-
let dy = _nullishCoalesce(_optionalChain([
|
|
1197
|
-
if (
|
|
1198
|
-
const inv =
|
|
1199
|
-
const target =
|
|
1200
|
-
dx = target.x - (entry.center.x +
|
|
1201
|
-
dy = target.y - (entry.center.y +
|
|
1289
|
+
let dx = _nullishCoalesce(_optionalChain([command3, 'access', _46 => _46.by, 'optionalAccess', _47 => _47.x]), () => ( 0));
|
|
1290
|
+
let dy = _nullishCoalesce(_optionalChain([command3, 'access', _48 => _48.by, 'optionalAccess', _49 => _49.y]), () => ( 0));
|
|
1291
|
+
if (command3.to) {
|
|
1292
|
+
const inv = _chunk7MD7C6XQcjs.invertMatrix.call(void 0, entry.parentWorld);
|
|
1293
|
+
const target = _chunk7MD7C6XQcjs.applyMatrix.call(void 0, inv, command3.to);
|
|
1294
|
+
dx = target.x - (entry.center.x + num2("x"));
|
|
1295
|
+
dy = target.y - (entry.center.y + num2("y"));
|
|
1202
1296
|
}
|
|
1203
|
-
if (_optionalChain([
|
|
1204
|
-
const inv =
|
|
1205
|
-
const x0 =
|
|
1206
|
-
const y0 =
|
|
1207
|
-
const add =
|
|
1208
|
-
const offsets = [{ x: 0, y: 0 }, ...
|
|
1209
|
-
const times = smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(
|
|
1297
|
+
if (_optionalChain([command3, 'access', _50 => _50.via, 'optionalAccess', _51 => _51.length])) {
|
|
1298
|
+
const inv = _chunk7MD7C6XQcjs.invertMatrix.call(void 0, entry.parentWorld);
|
|
1299
|
+
const x0 = num2("x");
|
|
1300
|
+
const y0 = num2("y");
|
|
1301
|
+
const add = command3.blend === "add";
|
|
1302
|
+
const offsets = [{ x: 0, y: 0 }, ...command3.via.map((p) => _chunk7MD7C6XQcjs.applyMatrix.call(void 0, inv, p)).map((p) => ({ x: p.x - entry.center.x - x0, y: p.y - entry.center.y - y0 })), { x: dx, y: dy }];
|
|
1303
|
+
const times = smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(command3.pacing, () => ( "even")));
|
|
1210
1304
|
for (const axis of ["x", "y"]) {
|
|
1211
1305
|
const base = add ? 0 : axis === "x" ? x0 : y0;
|
|
1212
1306
|
for (const leg of smoothMotionLegs(times, offsets.map((o) => o[axis])))
|
|
@@ -1214,42 +1308,42 @@ function compileMotionScene(scene) {
|
|
|
1214
1308
|
}
|
|
1215
1309
|
break;
|
|
1216
1310
|
}
|
|
1217
|
-
if (
|
|
1311
|
+
if (command3.blend === "add") {
|
|
1218
1312
|
seg("x", dx, e, start, end, { from: 0, blend: "add" });
|
|
1219
1313
|
seg("y", dy, e, start, end, { from: 0, blend: "add" });
|
|
1220
1314
|
} else {
|
|
1221
|
-
seg("x",
|
|
1222
|
-
seg("y",
|
|
1315
|
+
seg("x", num2("x") + dx, e);
|
|
1316
|
+
seg("y", num2("y") + dy, e);
|
|
1223
1317
|
}
|
|
1224
1318
|
break;
|
|
1225
1319
|
}
|
|
1226
1320
|
case "rotate": {
|
|
1227
1321
|
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
1228
|
-
if (
|
|
1229
|
-
else seg("rotation", _nullishCoalesce(
|
|
1322
|
+
if (command3.blend === "add") seg("rotation", command3.to !== void 0 ? command3.to - num2("rotation") : _nullishCoalesce(command3.by, () => ( 0)), e, start, end, { from: 0, blend: "add" });
|
|
1323
|
+
else seg("rotation", _nullishCoalesce(command3.to, () => ( num2("rotation") + (_nullishCoalesce(command3.by, () => ( 0))))), e);
|
|
1230
1324
|
break;
|
|
1231
1325
|
}
|
|
1232
1326
|
case "scale": {
|
|
1233
|
-
const to = typeof
|
|
1234
|
-
const extra = { ...
|
|
1327
|
+
const to = typeof command3.to === "number" ? { x: command3.to, y: command3.to } : command3.to;
|
|
1328
|
+
const extra = { ...command3.geometric ? { geometric: true } : {}, ...command3.blend === "add" ? { from: 1, blend: "add" } : {} };
|
|
1235
1329
|
seg("scaleX", to.x, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, extra);
|
|
1236
1330
|
seg("scaleY", to.y, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, extra);
|
|
1237
1331
|
break;
|
|
1238
1332
|
}
|
|
1239
1333
|
case "fade":
|
|
1240
|
-
seg("opacity",
|
|
1334
|
+
seg("opacity", command3.to, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
|
|
1241
1335
|
break;
|
|
1242
1336
|
case "style":
|
|
1243
|
-
if (
|
|
1244
|
-
if (
|
|
1245
|
-
if (
|
|
1337
|
+
if (command3.fill !== void 0) seg("fill", command3.fill, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
|
|
1338
|
+
if (command3.stroke !== void 0) seg("stroke", command3.stroke, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
|
|
1339
|
+
if (command3.strokeWidth !== void 0) seg("strokeWidth", command3.strokeWidth, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
|
|
1246
1340
|
break;
|
|
1247
1341
|
case "morph":
|
|
1248
|
-
seg("shape",
|
|
1342
|
+
seg("shape", command3.into, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
|
|
1249
1343
|
break;
|
|
1250
1344
|
case "match": {
|
|
1251
|
-
const into = nodes.get(
|
|
1252
|
-
if (!into ||
|
|
1345
|
+
const into = nodes.get(command3.into);
|
|
1346
|
+
if (!into || command3.into === node) break;
|
|
1253
1347
|
const match = matchMotionNodes(entry.node, into.node);
|
|
1254
1348
|
const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
|
|
1255
1349
|
for (const [a, b] of match.pairs) push({ node: a, property: "shape", start, end, from: valueAt(a, "shape", start), to: b, ease: e, ...where });
|
|
@@ -1257,7 +1351,7 @@ function compileMotionScene(scene) {
|
|
|
1257
1351
|
break;
|
|
1258
1352
|
}
|
|
1259
1353
|
case "follow":
|
|
1260
|
-
seg("follow", _nullishCoalesce(
|
|
1354
|
+
seg("follow", _nullishCoalesce(command3.to, () => ( 1)), _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, { from: _nullishCoalesce(command3.from, () => ( 0)), path: command3.path, rotate: _nullishCoalesce(command3.rotate, () => ( false)) });
|
|
1261
1355
|
break;
|
|
1262
1356
|
// Emphasis: a change toward a peak that a behaviour swings round (as Flair's primitives do).
|
|
1263
1357
|
case "pulse":
|
|
@@ -1265,40 +1359,40 @@ function compileMotionScene(scene) {
|
|
|
1265
1359
|
case "teeter":
|
|
1266
1360
|
case "wave":
|
|
1267
1361
|
case "wiggle": {
|
|
1268
|
-
const add = (_nullishCoalesce(
|
|
1362
|
+
const add = (_nullishCoalesce(command3.blend, () => ( "add"))) === "add";
|
|
1269
1363
|
const swing = (p, by, extra) => {
|
|
1270
1364
|
const scale = p === "scaleX" || p === "scaleY";
|
|
1271
1365
|
if (add) seg(p, by, _nullishCoalesce(ease, () => ( "linear")), start, end, { from: scale ? 1 : 0, blend: "add", ...extra });
|
|
1272
|
-
else seg(p, scale ?
|
|
1366
|
+
else seg(p, scale ? num2(p) * by : num2(p) + by, _nullishCoalesce(ease, () => ( "linear")), start, end, extra);
|
|
1273
1367
|
};
|
|
1274
|
-
if (
|
|
1275
|
-
const behavior = { type: "pulse", count: _nullishCoalesce(
|
|
1276
|
-
swing("scaleX", 1 + (_nullishCoalesce(
|
|
1277
|
-
swing("scaleY", 1 + (_nullishCoalesce(
|
|
1278
|
-
} else if (
|
|
1279
|
-
else if (
|
|
1280
|
-
else if (
|
|
1368
|
+
if (command3.type === "pulse") {
|
|
1369
|
+
const behavior = { type: "pulse", count: _nullishCoalesce(command3.count, () => ( 1)) };
|
|
1370
|
+
swing("scaleX", 1 + (_nullishCoalesce(command3.amount, () => ( 0.15))), { behavior });
|
|
1371
|
+
swing("scaleY", 1 + (_nullishCoalesce(command3.amount, () => ( 0.15))), { behavior });
|
|
1372
|
+
} else if (command3.type === "shake") swing(command3.axis === "vertical" ? "y" : "x", _nullishCoalesce(command3.amount, () => ( 8)), { behavior: { type: "oscillate", count: _nullishCoalesce(command3.count, () => ( 3)), decay: 1 } });
|
|
1373
|
+
else if (command3.type === "teeter") swing("rotation", _nullishCoalesce(command3.angle, () => ( 8)), { behavior: { type: "oscillate", count: _nullishCoalesce(command3.count, () => ( 3)), decay: 1 } });
|
|
1374
|
+
else if (command3.type === "wave") swing("y", -(_nullishCoalesce(command3.amount, () => ( 6))), { behavior: { type: "oscillate", count: _nullishCoalesce(command3.count, () => ( 2)) } });
|
|
1281
1375
|
else {
|
|
1282
|
-
const behavior = { type: "wriggle", frequency: _nullishCoalesce(
|
|
1283
|
-
const amount = _nullishCoalesce(
|
|
1376
|
+
const behavior = { type: "wriggle", frequency: _nullishCoalesce(command3.frequency, () => ( 3)), octaves: _nullishCoalesce(command3.octaves, () => ( 2)), seed: command3.seed || _chunkZCNLBRT6cjs.motionSeedFromId.call(void 0, node) };
|
|
1377
|
+
const amount = _nullishCoalesce(command3.amount, () => ( 6));
|
|
1284
1378
|
swing("x", amount, { behavior, index: 0 });
|
|
1285
1379
|
swing("y", amount, { behavior, index: 1 });
|
|
1286
|
-
if (
|
|
1380
|
+
if (command3.rotate) swing("rotation", command3.rotate, { behavior, index: 2 });
|
|
1287
1381
|
}
|
|
1288
1382
|
break;
|
|
1289
1383
|
}
|
|
1290
1384
|
case "color-pulse":
|
|
1291
|
-
seg(_nullishCoalesce(
|
|
1385
|
+
seg(_nullishCoalesce(command3.paint, () => ( "fill")), _nullishCoalesce(command3.color, () => ( "#f59e0b")), _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior: { type: "pulse", count: _nullishCoalesce(command3.count, () => ( 1)) } });
|
|
1292
1386
|
break;
|
|
1293
1387
|
case "effect":
|
|
1294
|
-
seg(`effect:${
|
|
1388
|
+
seg(`effect:${command3.effect}:${command3.param}`, command3.to, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
|
|
1295
1389
|
break;
|
|
1296
1390
|
}
|
|
1297
1391
|
}
|
|
1298
1392
|
for (const track of tracks.values()) track.sort((a, b) => a.start - b.start);
|
|
1299
1393
|
segments.sort((a, b) => a.start - b.start);
|
|
1300
1394
|
const duration = shots.length ? shots[shots.length - 1].end : 0;
|
|
1301
|
-
const timeline = { duration, shots, commands, segments, tracks, ..._optionalChain([scene, 'access',
|
|
1395
|
+
const timeline = { duration, shots, commands, segments, tracks, ..._optionalChain([scene, 'access', _52 => _52.drivers, 'optionalAccess', _53 => _53.length]) ? { drivers: scene.drivers, restOpacity: new Map([...nodes].map(([id, e]) => [id, _nullishCoalesce(e.node.opacity, () => ( 1))])) } : {} };
|
|
1302
1396
|
timelineCache.set(scene, timeline);
|
|
1303
1397
|
return timeline;
|
|
1304
1398
|
}
|
|
@@ -1311,7 +1405,7 @@ var MOTION_DRAW_EFFECT_ID = "~draw";
|
|
|
1311
1405
|
var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
|
|
1312
1406
|
var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
|
|
1313
1407
|
function applyMotionControlValues(scene, values) {
|
|
1314
|
-
if (!values || !_optionalChain([scene, 'access',
|
|
1408
|
+
if (!values || !_optionalChain([scene, 'access', _54 => _54.controls, 'optionalAccess', _55 => _55.length])) return scene;
|
|
1315
1409
|
const map = /* @__PURE__ */ new Map();
|
|
1316
1410
|
for (const control of scene.controls) {
|
|
1317
1411
|
const value = values[control.name];
|
|
@@ -1347,17 +1441,17 @@ function morphBetween(a, b) {
|
|
|
1347
1441
|
let inner = morphCache.get(a);
|
|
1348
1442
|
if (!inner) morphCache.set(a, inner = /* @__PURE__ */ new WeakMap());
|
|
1349
1443
|
let morph = inner.get(b);
|
|
1350
|
-
if (!morph) inner.set(b, morph =
|
|
1444
|
+
if (!morph) inner.set(b, morph = _chunk7MD7C6XQcjs.createVectorMorph.call(void 0, a, b, { id: a.id }));
|
|
1351
1445
|
return morph;
|
|
1352
1446
|
}
|
|
1353
1447
|
function shapeIn(entry, shape) {
|
|
1354
1448
|
if (shape === entry) return entry.node;
|
|
1355
|
-
const m =
|
|
1356
|
-
return { ...shape.node, ...
|
|
1449
|
+
const m = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, shape.node), shape.parentWorld), _chunk7MD7C6XQcjs.invertMatrix.call(void 0, entry.parentWorld));
|
|
1450
|
+
return { ...shape.node, ..._chunk7MD7C6XQcjs.isIdentityMatrix.call(void 0, m) ? { transform: void 0 } : { transform: m } };
|
|
1357
1451
|
}
|
|
1358
1452
|
function shapeAt(entry, timeline, nodes, time) {
|
|
1359
1453
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
|
|
1360
|
-
if (!_optionalChain([track, 'optionalAccess',
|
|
1454
|
+
if (!_optionalChain([track, 'optionalAccess', _56 => _56.length])) return null;
|
|
1361
1455
|
const s = activeSegment(track, time);
|
|
1362
1456
|
const fromId = String(s ? s.from : track[0].from);
|
|
1363
1457
|
if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
|
|
@@ -1373,20 +1467,20 @@ function shapeAt(entry, timeline, nodes, time) {
|
|
|
1373
1467
|
function motionFollowRoute(entry, path) {
|
|
1374
1468
|
if (!path || path.node.type !== "path") return null;
|
|
1375
1469
|
try {
|
|
1376
|
-
return
|
|
1470
|
+
return _chunkXGD3FSNCcjs.transformBezierPath.call(void 0, _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, path.node, path.parentWorld, { effects: false }), _chunk7MD7C6XQcjs.invertMatrix.call(void 0, entry.parentWorld));
|
|
1377
1471
|
} catch (e4) {
|
|
1378
1472
|
return null;
|
|
1379
1473
|
}
|
|
1380
1474
|
}
|
|
1381
1475
|
function followAt(entry, timeline, nodes, time) {
|
|
1382
1476
|
const track = timeline.tracks.get(motionTrackKey(entry.node.id, "follow"));
|
|
1383
|
-
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess',
|
|
1384
|
-
if (!_optionalChain([s, 'optionalAccess',
|
|
1477
|
+
const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _57 => _57[0]])));
|
|
1478
|
+
if (!_optionalChain([s, 'optionalAccess', _58 => _58.path])) return null;
|
|
1385
1479
|
const route = motionFollowRoute(entry, nodes.get(s.path));
|
|
1386
1480
|
const progress = Number(trackValue(track, time));
|
|
1387
1481
|
if (!route || !(progress >= 0)) return null;
|
|
1388
1482
|
try {
|
|
1389
|
-
const at =
|
|
1483
|
+
const at = _chunkXGD3FSNCcjs.bezierPathPointAtLength.call(void 0, route, Math.min(1, Math.max(0, progress)) * _chunkXGD3FSNCcjs.bezierPathLength.call(void 0, route));
|
|
1390
1484
|
if (!at) return null;
|
|
1391
1485
|
return { x: at.point[0], y: at.point[1], angle: s.rotate ? at.angle * 180 / Math.PI : 0 };
|
|
1392
1486
|
} catch (e5) {
|
|
@@ -1399,7 +1493,7 @@ function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry
|
|
|
1399
1493
|
const layered = withMotionLayers(timeline, entry.node.id, p, typeof v === "number" ? v : rest, time, raw);
|
|
1400
1494
|
return p === "follow" ? layered : applyMotionDrivers(timeline, entry.node.id, p, layered, time, raw);
|
|
1401
1495
|
};
|
|
1402
|
-
const driven = _optionalChain([timeline, 'access',
|
|
1496
|
+
const driven = _optionalChain([timeline, 'access', _59 => _59.drivers, 'optionalAccess', _60 => _60.some, 'call', _61 => _61((d) => d.target === entry.node.id && d.property !== "opacity")]);
|
|
1403
1497
|
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;
|
|
1404
1498
|
const dx = read("x", 0);
|
|
1405
1499
|
const dy = read("y", 0);
|
|
@@ -1407,9 +1501,9 @@ function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry
|
|
|
1407
1501
|
const scaleX = read("scaleX", 1);
|
|
1408
1502
|
const scaleY = read("scaleY", 1);
|
|
1409
1503
|
const c = entry.center;
|
|
1410
|
-
let matrix =
|
|
1504
|
+
let matrix = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.scaleMatrix.call(void 0, scaleX, scaleY, c), _chunk7MD7C6XQcjs.rotateMatrix.call(void 0, rotation, c)), _chunk7MD7C6XQcjs.translateMatrix.call(void 0, dx, dy));
|
|
1411
1505
|
const along = follow ? followAt(entry, timeline, nodes, time) : null;
|
|
1412
|
-
if (along) matrix =
|
|
1506
|
+
if (along) matrix = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, matrix, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.translateMatrix.call(void 0, -c.x, -c.y), _chunk7MD7C6XQcjs.rotateMatrix.call(void 0, along.angle)), _chunk7MD7C6XQcjs.translateMatrix.call(void 0, along.x, along.y)));
|
|
1413
1507
|
return { matrix, dx, dy, rotation, scaleX, scaleY, follow: along };
|
|
1414
1508
|
}
|
|
1415
1509
|
function motionNodeClips(id, timeline, time) {
|
|
@@ -1443,7 +1537,7 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1443
1537
|
if (out.visible === void 0) delete out.visible;
|
|
1444
1538
|
}
|
|
1445
1539
|
const effectTracks = [...timeline.tracks.keys()].filter((k) => k.startsWith(`${id}\0effect:`));
|
|
1446
|
-
if (effectTracks.length && _optionalChain([out, 'access',
|
|
1540
|
+
if (effectTracks.length && _optionalChain([out, 'access', _62 => _62.effects, 'optionalAccess', _63 => _63.length])) {
|
|
1447
1541
|
out = {
|
|
1448
1542
|
...out,
|
|
1449
1543
|
effects: out.effects.map((effect) => {
|
|
@@ -1476,22 +1570,22 @@ function motionFrameAt(scene, time, options = {}) {
|
|
|
1476
1570
|
const start = Math.min(1, Math.max(0, typeof drawStart === "number" ? drawStart : 0));
|
|
1477
1571
|
const end = Math.min(1, Math.max(0, typeof drawEnd === "number" ? drawEnd : 1));
|
|
1478
1572
|
if (start > 0 || end < 1) {
|
|
1479
|
-
const trim =
|
|
1573
|
+
const trim = _chunk7MD7C6XQcjs.createVectorEffect.call(void 0, "trim", MOTION_DRAW_EFFECT_ID, { start: tidy(start * 100), end: tidy(end * 100) });
|
|
1480
1574
|
p = { ...p, effects: [trim, ...(_nullishCoalesce(p.effects, () => ( []))).filter((e) => e.id !== MOTION_DRAW_EFFECT_ID)] };
|
|
1481
1575
|
}
|
|
1482
1576
|
}
|
|
1483
1577
|
return p;
|
|
1484
1578
|
});
|
|
1485
1579
|
}
|
|
1486
|
-
const opacity = _optionalChain([timeline, 'access',
|
|
1580
|
+
const opacity = _optionalChain([timeline, 'access', _64 => _64.drivers, 'optionalAccess', _65 => _65.some, 'call', _66 => _66((d) => d.target === id && d.property === "opacity")]) ? motionPropertyValue(timeline, id, "opacity", time) : value(id, "opacity");
|
|
1487
1581
|
if (typeof opacity === "number") {
|
|
1488
1582
|
const o = Math.min(1, Math.max(0, tidy(opacity)));
|
|
1489
1583
|
out = { ...out, opacity: o };
|
|
1490
1584
|
if (o >= 1) delete out.opacity;
|
|
1491
1585
|
}
|
|
1492
1586
|
const offset = options.offsets === false ? null : motionNodeOffset(entry, timeline, time, nodes);
|
|
1493
|
-
if (offset && !
|
|
1494
|
-
const m =
|
|
1587
|
+
if (offset && !_chunk7MD7C6XQcjs.isIdentityMatrix.call(void 0, offset.matrix)) {
|
|
1588
|
+
const m = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, out), offset.matrix).map(tidy);
|
|
1495
1589
|
out = { ...out, transform: m };
|
|
1496
1590
|
}
|
|
1497
1591
|
return out;
|
|
@@ -1511,7 +1605,7 @@ function motionFrameToSvg(scene, time, options = {}) {
|
|
|
1511
1605
|
const wrap = { ...options.wrap };
|
|
1512
1606
|
for (const [id, clips] of Object.entries(frame.clips))
|
|
1513
1607
|
wrap[id] = [..._nullishCoalesce(wrap[id], () => ( [])), ...clips.map((clip, i) => ({ clip: { id: `${prefix}reveal-${id}-${i}`, shape: clip.shape, attrs: motionClipAttrs(clip) } }))];
|
|
1514
|
-
return withViewBox(
|
|
1608
|
+
return withViewBox(_chunk7MD7C6XQcjs.vectorDocumentToSvg.call(void 0, frame.document, { ...options, wrap }), frame.camera);
|
|
1515
1609
|
}
|
|
1516
1610
|
function withViewBox(svg, box) {
|
|
1517
1611
|
const f = (n) => String(Math.round(n * 1e3) / 1e3);
|
|
@@ -1556,7 +1650,7 @@ function motionPath(scene, id, options = {}) {
|
|
|
1556
1650
|
const r = (n) => Math.round(n * 100) / 100;
|
|
1557
1651
|
const centreAt = (t) => {
|
|
1558
1652
|
const node = indexMotionNodes(motionFrameAtCache(scene, t)).get(id);
|
|
1559
|
-
const b = _optionalChain([node, 'optionalAccess',
|
|
1653
|
+
const b = _optionalChain([node, 'optionalAccess', _67 => _67.bounds]);
|
|
1560
1654
|
return b ? { t: r(t), x: r(b.x + b.width / 2), y: r(b.y + b.height / 2) } : null;
|
|
1561
1655
|
};
|
|
1562
1656
|
const points = [];
|
|
@@ -1590,8 +1684,8 @@ function motionBlurTimes(scene, time, blur = {}) {
|
|
|
1590
1684
|
const b = indexMotionNodes(motionFrameAt(scene, time + span / 2).document.nodes);
|
|
1591
1685
|
let travel = 0;
|
|
1592
1686
|
for (const id of ids) {
|
|
1593
|
-
const p = _optionalChain([a, 'access',
|
|
1594
|
-
const q = _optionalChain([b, 'access',
|
|
1687
|
+
const p = _optionalChain([a, 'access', _68 => _68.get, 'call', _69 => _69(id), 'optionalAccess', _70 => _70.bounds]);
|
|
1688
|
+
const q = _optionalChain([b, 'access', _71 => _71.get, 'call', _72 => _72(id), 'optionalAccess', _73 => _73.bounds]);
|
|
1595
1689
|
if (p && q) travel = Math.max(travel, Math.abs(p.x - q.x), Math.abs(p.y - q.y), Math.abs(p.x + p.width - q.x - q.width), Math.abs(p.y + p.height - q.y - q.height));
|
|
1596
1690
|
}
|
|
1597
1691
|
const n = Math.min(most, Math.ceil(travel / 1.5));
|
|
@@ -1603,7 +1697,7 @@ function averagedFrames(scene, times, options, prefix) {
|
|
|
1603
1697
|
return `<g data-motion-blur="${n}" style="isolation:isolate">${times.map((t, k) => {
|
|
1604
1698
|
const own = `${prefix}blur${k}-`;
|
|
1605
1699
|
const frame = motionFrameToSvg(scene, t, { ...options, idPrefix: own, background: false });
|
|
1606
|
-
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access',
|
|
1700
|
+
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _74 => _74.exec, 'call', _75 => _75(frame), 'optionalAccess', _76 => _76[1]]), () => ( ""));
|
|
1607
1701
|
const inner = k === n - 1 ? innerSvg(frame) : innerSvg(frame).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
|
|
1608
1702
|
return `<svg viewBox="${view}" preserveAspectRatio="none" style="mix-blend-mode:plus-lighter" opacity="${Math.round(1e4 / n) / 1e4}">${inner}</svg>`;
|
|
1609
1703
|
}).join("")}</g>`;
|
|
@@ -1618,7 +1712,7 @@ function motionStageSvg(scene, time, options = {}) {
|
|
|
1618
1712
|
if (blurTimes.length > 1) {
|
|
1619
1713
|
const open2 = current.indexOf(">") + 1;
|
|
1620
1714
|
const body2 = current.slice(open2, current.lastIndexOf("</svg>"));
|
|
1621
|
-
const bg2 = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access',
|
|
1715
|
+
const bg2 = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _77 => _77.exec, 'call', _78 => _78(body2), 'optionalAccess', _79 => _79[0]]), () => ( "")) : "";
|
|
1622
1716
|
current = `${current.slice(0, open2)}${bg2}${averagedFrames(scene, blurTimes, svgOptions, prefix)}</svg>`;
|
|
1623
1717
|
}
|
|
1624
1718
|
if (!onionSkin && !motionPaths) return current;
|
|
@@ -1633,7 +1727,7 @@ function motionStageSvg(scene, time, options = {}) {
|
|
|
1633
1727
|
const open = current.indexOf(">") + 1;
|
|
1634
1728
|
const close = current.lastIndexOf("</svg>");
|
|
1635
1729
|
const body = current.slice(open, close);
|
|
1636
|
-
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access',
|
|
1730
|
+
const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _80 => _80.exec, 'call', _81 => _81(body), 'optionalAccess', _82 => _82[0]]), () => ( "")) : "";
|
|
1637
1731
|
return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
|
|
1638
1732
|
}
|
|
1639
1733
|
function motionContactSheetSvg(scene, times, options = {}) {
|
|
@@ -1652,7 +1746,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
|
|
|
1652
1746
|
const x = gap + i % cols * (w + gap);
|
|
1653
1747
|
const y = gap + Math.floor(i / cols) * (h + label + gap);
|
|
1654
1748
|
const frame = motionStageSvg(scene, t, { ...frameOptions, idPrefix: `${prefix}f${i}-` });
|
|
1655
|
-
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access',
|
|
1749
|
+
const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _83 => _83.exec, 'call', _84 => _84(frame), 'optionalAccess', _85 => _85[1]]), () => ( `0 0 ${w} ${h}`));
|
|
1656
1750
|
const inner = innerSvg(frame).replace(new RegExp(` id="(?!${`${prefix}f${i}-`.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
|
|
1657
1751
|
const shot = _nullishCoalesce(timeline.shots.find((s) => t >= s.start && t < s.end), () => ( timeline.shots[timeline.shots.length - 1]));
|
|
1658
1752
|
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>` : "";
|
|
@@ -1664,7 +1758,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
|
|
|
1664
1758
|
// src/animation-editor/check.ts
|
|
1665
1759
|
var MOTION_MIN_CHANGE_MS = 120;
|
|
1666
1760
|
var NUMERIC_PARAMS = (node, effectId) => {
|
|
1667
|
-
const effect = _optionalChain([node, 'access',
|
|
1761
|
+
const effect = _optionalChain([node, 'access', _86 => _86.effects, 'optionalAccess', _87 => _87.find, 'call', _88 => _88((e) => e.id === effectId)]);
|
|
1668
1762
|
if (!effect) return null;
|
|
1669
1763
|
return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
|
|
1670
1764
|
};
|
|
@@ -1682,24 +1776,24 @@ function usesColor(scene, color) {
|
|
|
1682
1776
|
return found;
|
|
1683
1777
|
}
|
|
1684
1778
|
function visibleAt(timeline, id, time, node) {
|
|
1685
|
-
const
|
|
1779
|
+
const num2 = (p, rest) => {
|
|
1686
1780
|
const v = trackValue(timeline.tracks.get(motionTrackKey(id, p)), time);
|
|
1687
1781
|
return typeof v === "number" ? v : rest;
|
|
1688
1782
|
};
|
|
1689
1783
|
if (node.visible === false) return false;
|
|
1690
|
-
if (
|
|
1691
|
-
if (Math.abs(
|
|
1784
|
+
if (num2("opacity", _nullishCoalesce(node.opacity, () => ( 1))) <= 0.01) return false;
|
|
1785
|
+
if (Math.abs(num2("scaleX", 1) * num2("scaleY", 1)) <= 1e-4) return false;
|
|
1692
1786
|
const clip = (p) => trackValue(timeline.tracks.get(motionTrackKey(id, p)), time);
|
|
1693
1787
|
const rect = clip("clipRect");
|
|
1694
1788
|
if (Array.isArray(rect) && (rect[2] <= 1e-4 || rect[3] <= 1e-4)) return false;
|
|
1695
1789
|
const circle = clip("clipCircle");
|
|
1696
1790
|
if (Array.isArray(circle) && circle[2] <= 1e-4) return false;
|
|
1697
|
-
const hasFill = node.type === "path" ? !!node.fill && node.fill !== "none" :
|
|
1698
|
-
const drawn =
|
|
1791
|
+
const hasFill = node.type === "path" ? !!node.fill && node.fill !== "none" : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node).some((p) => p.fill && p.fill !== "none");
|
|
1792
|
+
const drawn = num2("drawEnd", 1) > 0.01 && (node.type === "path" || _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node).length === 0 || _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node).some((p) => {
|
|
1699
1793
|
const v = trackValue(timeline.tracks.get(motionTrackKey(p.id, "drawEnd")), time);
|
|
1700
1794
|
return typeof v !== "number" || v > 0.01;
|
|
1701
1795
|
}));
|
|
1702
|
-
return drawn || hasFill &&
|
|
1796
|
+
return drawn || hasFill && num2("fillOpacity", 1) > 0.01;
|
|
1703
1797
|
}
|
|
1704
1798
|
function checkMotionScene(scene) {
|
|
1705
1799
|
const issues = [];
|
|
@@ -1727,48 +1821,53 @@ function checkMotionScene(scene) {
|
|
|
1727
1821
|
issues.push(motionIssue("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 }));
|
|
1728
1822
|
}
|
|
1729
1823
|
if (!shot.run.length && !shot.camera && shotIndex2 > 0) issues.push(motionIssue("empty-shot", "This shot only holds; add commands or a camera move, or remove it.", { shot: shot.id }));
|
|
1730
|
-
shot.run.forEach((
|
|
1824
|
+
shot.run.forEach((command3, i) => {
|
|
1731
1825
|
const where = { shot: shot.id, command: i };
|
|
1732
|
-
if (
|
|
1733
|
-
const targets =
|
|
1826
|
+
if (command3.type === "wait") return;
|
|
1827
|
+
const targets = command3.targets.filter((id) => known(id, "unknown-target", "node", where));
|
|
1734
1828
|
const timing = timeline.commands.find((c) => c.shot === shot.id && c.command === i);
|
|
1735
1829
|
if (timing && timing.duration > 0 && timing.duration < MOTION_MIN_CHANGE_MS)
|
|
1736
|
-
issues.push(motionIssue("too-fast", `This ${
|
|
1737
|
-
if (
|
|
1738
|
-
const ease = _chunk2FHLHZALcjs.resolveEasing.call(void 0,
|
|
1830
|
+
issues.push(motionIssue("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 }));
|
|
1831
|
+
if (command3.duration !== void 0 && command3.ease !== void 0) {
|
|
1832
|
+
const ease = _chunk2FHLHZALcjs.resolveEasing.call(void 0, command3.ease);
|
|
1739
1833
|
if (ease !== "hold" && ease.type === "spring") {
|
|
1740
1834
|
const settle = _chunk2FHLHZALcjs.springSettleMs.call(void 0, ease);
|
|
1741
|
-
if (
|
|
1742
|
-
issues.push(motionIssue("spring-cut-short", `This ${
|
|
1835
|
+
if (command3.duration < settle * 0.9)
|
|
1836
|
+
issues.push(motionIssue("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 }));
|
|
1743
1837
|
}
|
|
1744
1838
|
}
|
|
1745
|
-
if (
|
|
1746
|
-
issues.push(motionIssue("not-a-path", `"${
|
|
1747
|
-
if (
|
|
1748
|
-
if (
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1839
|
+
if (command3.type === "follow" && known(command3.path, "unknown-path", "path", where) && nodes.get(command3.path).node.type !== "path")
|
|
1840
|
+
issues.push(motionIssue("not-a-path", `"${command3.path}" is a group; follow a single path node.`, { ...where, ids: [command3.path] }));
|
|
1841
|
+
if (command3.type === "morph") known(command3.into, "unknown-shape", "shape", where);
|
|
1842
|
+
if (command3.type !== "play" && command3.split) {
|
|
1843
|
+
for (const id of targets)
|
|
1844
|
+
if (!motionTextLayout(nodes, id))
|
|
1845
|
+
issues.push(motionIssue("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] }));
|
|
1846
|
+
}
|
|
1847
|
+
if (command3.type === "play" && !_optionalChain([scene, 'access', _89 => _89.clips, 'optionalAccess', _90 => _90[command3.clip]]))
|
|
1848
|
+
issues.push(motionIssue("unknown-clip", `There is no clip ${namedWithSuggestion(command3.clip, Object.keys(_nullishCoalesce(scene.clips, () => ( {}))))}; define it with set_animation_clip.`, where));
|
|
1849
|
+
if (command3.type === "match" && known(command3.into, "unknown-shape", "group", where)) {
|
|
1850
|
+
const into = nodes.get(command3.into);
|
|
1752
1851
|
for (const id of targets) {
|
|
1753
1852
|
const entry = nodes.get(id);
|
|
1754
|
-
if (id ===
|
|
1755
|
-
issues.push(motionIssue("match-self", `"${id}" cannot match "${
|
|
1853
|
+
if (id === command3.into || into.ancestors.includes(id) || entry.ancestors.includes(command3.into)) {
|
|
1854
|
+
issues.push(motionIssue("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] }));
|
|
1756
1855
|
continue;
|
|
1757
1856
|
}
|
|
1758
1857
|
const m = matchMotionNodes(entry.node, into.node);
|
|
1759
1858
|
if (m.unpairedInto.length)
|
|
1760
|
-
issues.push(motionIssue("match-unpaired", `${m.unpairedInto.map((x) => `"${x}"`).join(", ")} in "${
|
|
1859
|
+
issues.push(motionIssue("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 }));
|
|
1761
1860
|
}
|
|
1762
1861
|
}
|
|
1763
|
-
const style =
|
|
1862
|
+
const style = command3.type === "enter" || command3.type === "exit" ? command3.style : void 0;
|
|
1764
1863
|
if (style === "wipe" || style === "iris" || style === "split") {
|
|
1765
1864
|
for (const id of targets)
|
|
1766
1865
|
if (!motionRevealPadding(nodes.get(id)))
|
|
1767
|
-
issues.push(motionIssue("reveal-no-box", `"${id}" has no width or height (a straight line), so a ${style} cannot clip it and it fades instead; use style "${
|
|
1866
|
+
issues.push(motionIssue("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] }));
|
|
1768
1867
|
}
|
|
1769
|
-
if (
|
|
1868
|
+
if (command3.type === "style") {
|
|
1770
1869
|
for (const key of ["fill", "stroke"]) {
|
|
1771
|
-
const color =
|
|
1870
|
+
const color = command3[key];
|
|
1772
1871
|
if (color === void 0) continue;
|
|
1773
1872
|
if (_chunkA6PHCAGXcjs.normalizeTokenColor.call(void 0, color) === null) {
|
|
1774
1873
|
issues.push(motionIssue("invalid-color", `${key} "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
|
|
@@ -1776,33 +1875,33 @@ function checkMotionScene(scene) {
|
|
|
1776
1875
|
}
|
|
1777
1876
|
for (const id of targets) {
|
|
1778
1877
|
const node = nodes.get(id).node;
|
|
1779
|
-
const paths = node.type === "path" ? [node] :
|
|
1878
|
+
const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
|
|
1780
1879
|
if (paths.some((p) => p[key] !== void 0 && p[key] !== null && typeof p[key] !== "string"))
|
|
1781
1880
|
issues.push(motionIssue("paint-not-color", `"${id}" has a gradient ${key}; it switches to ${color} at the end instead of blending.`, { ...where, ids: [id] }));
|
|
1782
1881
|
}
|
|
1783
1882
|
}
|
|
1784
1883
|
}
|
|
1785
|
-
if (
|
|
1786
|
-
const key = _nullishCoalesce(
|
|
1787
|
-
const color = _nullishCoalesce(
|
|
1884
|
+
if (command3.type === "color-pulse") {
|
|
1885
|
+
const key = _nullishCoalesce(command3.paint, () => ( "fill"));
|
|
1886
|
+
const color = _nullishCoalesce(command3.color, () => ( "#f59e0b"));
|
|
1788
1887
|
if (_chunkA6PHCAGXcjs.normalizeTokenColor.call(void 0, color) === null) issues.push(motionIssue("invalid-color", `color "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
|
|
1789
1888
|
else
|
|
1790
1889
|
for (const id of targets) {
|
|
1791
1890
|
const node = nodes.get(id).node;
|
|
1792
|
-
const paths = node.type === "path" ? [node] :
|
|
1891
|
+
const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
|
|
1793
1892
|
if (paths.some((p) => typeof p[key] !== "string"))
|
|
1794
1893
|
issues.push(motionIssue("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] }));
|
|
1795
1894
|
}
|
|
1796
1895
|
}
|
|
1797
|
-
if (
|
|
1896
|
+
if (command3.type === "effect") {
|
|
1798
1897
|
for (const id of targets) {
|
|
1799
1898
|
const node = nodes.get(id).node;
|
|
1800
|
-
const params = NUMERIC_PARAMS(node,
|
|
1899
|
+
const params = NUMERIC_PARAMS(node, command3.effect);
|
|
1801
1900
|
const effects = (_nullishCoalesce(node.effects, () => ( []))).map((e) => e.id);
|
|
1802
1901
|
if (!params)
|
|
1803
|
-
issues.push(motionIssue("unknown-effect", `"${id}" has no effect ${namedWithSuggestion(
|
|
1804
|
-
else if (!params.includes(
|
|
1805
|
-
issues.push(motionIssue("unknown-effect-param", `Effect "${
|
|
1902
|
+
issues.push(motionIssue("unknown-effect", `"${id}" has no effect ${namedWithSuggestion(command3.effect, effects)}${effects.length ? `; its effects are ${effects.map((e) => `"${e}"`).join(", ")}` : "; it has no live effects"}.`, { ...where, ids: [id] }));
|
|
1903
|
+
else if (!params.includes(command3.param))
|
|
1904
|
+
issues.push(motionIssue("unknown-effect-param", `Effect "${command3.effect}" has no numeric parameter ${namedWithSuggestion(command3.param, params)}; use one of ${params.join(", ")}.`, { ...where, ids: [id] }));
|
|
1806
1905
|
}
|
|
1807
1906
|
}
|
|
1808
1907
|
if (timing) {
|
|
@@ -1810,11 +1909,11 @@ function checkMotionScene(scene) {
|
|
|
1810
1909
|
const node = nodes.get(id).node;
|
|
1811
1910
|
const before = Math.max(0, timing.start - 0.5);
|
|
1812
1911
|
const visible = timing.start > 0 ? visibleAt(timeline, id, before, node) : node.visible !== false;
|
|
1813
|
-
if (
|
|
1912
|
+
if (command3.type === "enter" && visible && timing.start > 0)
|
|
1814
1913
|
issues.push(motionIssue("enter-visible", `"${id}" is already showing when it enters, so it blinks out first; remove the enter or exit it earlier.`, { ...where, ids: [id] }));
|
|
1815
|
-
const probe =
|
|
1816
|
-
if (
|
|
1817
|
-
issues.push(motionIssue("exit-hidden", `"${id}" is hidden when this ${
|
|
1914
|
+
const probe = command3.type === "exit" ? timing.start + 0.5 : (timing.start + timing.end) / 2;
|
|
1915
|
+
if (command3.type !== "enter" && command3.type !== "draw" && !visibleAt(timeline, id, probe, node))
|
|
1916
|
+
issues.push(motionIssue("exit-hidden", `"${id}" is hidden when this ${command3.type} starts, so it is not seen; enter it first.`, { ...where, ids: [id] }));
|
|
1818
1917
|
}
|
|
1819
1918
|
}
|
|
1820
1919
|
});
|
|
@@ -1842,9 +1941,9 @@ function checkMotionScene(scene) {
|
|
|
1842
1941
|
if (loop.length) issues.push(motionIssue("driver-cycle", `Drivers follow each other round in a loop (${loop.join(" \u2190 ")}); remove one of them.`, { ids: [...new Set(loop.map((k) => k.split(".")[0]))] }));
|
|
1843
1942
|
}
|
|
1844
1943
|
for (const [name, clip] of Object.entries(_nullishCoalesce(scene.clips, () => ( {}))))
|
|
1845
|
-
for (const
|
|
1846
|
-
if (
|
|
1847
|
-
for (const id of
|
|
1944
|
+
for (const command3 of clip.run)
|
|
1945
|
+
if (command3.type !== "wait") {
|
|
1946
|
+
for (const id of command3.targets)
|
|
1848
1947
|
if (id !== MOTION_CLIP_TARGET && !nodes.has(id)) issues.push(motionIssue("unknown-target", `Clip "${name}" names ${namedWithSuggestion(id, [...nodes.keys()])}, which the artwork does not have; use "$" for the node the clip is played on.`, { ids: [id] }));
|
|
1849
1948
|
}
|
|
1850
1949
|
if (scene.trigger) {
|
|
@@ -1860,7 +1959,7 @@ function checkMotionScene(scene) {
|
|
|
1860
1959
|
if (!shot.at) return;
|
|
1861
1960
|
const timing = timeline.shots[i];
|
|
1862
1961
|
if (timing.cue === void 0) {
|
|
1863
|
-
const what = shot.at.beat !== void 0 ? `beat ${shot.at.beat}, but the scene has no beat grid; set one with set_animation_settings ({ "beat": { "bpm": \u2026 } })` : `word ${shot.at.word}, but the narration has ${_nullishCoalesce(_optionalChain([scene, 'access',
|
|
1962
|
+
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', _91 => _91.narration, 'optionalAccess', _92 => _92.words, 'access', _93 => _93.length]), () => ( 0))} words (indexes from 0)`;
|
|
1864
1963
|
issues.push(motionIssue("unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
|
|
1865
1964
|
} else if (timing.missedBy !== void 0) {
|
|
1866
1965
|
const late = Math.round(timing.missedBy);
|
|
@@ -1887,18 +1986,18 @@ function checkMotionScene(scene) {
|
|
|
1887
1986
|
}
|
|
1888
1987
|
const reported = /* @__PURE__ */ new Set();
|
|
1889
1988
|
for (const timing of timeline.commands) {
|
|
1890
|
-
const
|
|
1891
|
-
if (
|
|
1989
|
+
const command3 = scene.shots[timing.shotIndex].run[timing.command];
|
|
1990
|
+
if (command3.type === "wait" || command3.type === "exit") continue;
|
|
1892
1991
|
const frame = motionFrameAt(scene, timing.end);
|
|
1893
1992
|
const cam = frame.camera;
|
|
1894
1993
|
const docIndex = indexMotionNodes(frame.document.nodes);
|
|
1895
|
-
for (const id of
|
|
1896
|
-
const b = _optionalChain([docIndex, 'access',
|
|
1994
|
+
for (const id of command3.targets) {
|
|
1995
|
+
const b = _optionalChain([docIndex, 'access', _94 => _94.get, 'call', _95 => _95(id), 'optionalAccess', _96 => _96.bounds]);
|
|
1897
1996
|
if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
|
|
1898
1997
|
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;
|
|
1899
1998
|
if (outside) {
|
|
1900
1999
|
reported.add(id);
|
|
1901
|
-
issues.push(motionIssue("out-of-frame", `"${id}" is outside the camera when this ${
|
|
2000
|
+
issues.push(motionIssue("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] }));
|
|
1902
2001
|
}
|
|
1903
2002
|
}
|
|
1904
2003
|
}
|
|
@@ -2052,8 +2151,8 @@ function applyOne(scene, edit) {
|
|
|
2052
2151
|
case "add_commands": {
|
|
2053
2152
|
const i = shotIndex(scene, edit.shot);
|
|
2054
2153
|
if (!edit.commands.length) fail("Give at least one command.");
|
|
2055
|
-
edit.commands.forEach((
|
|
2056
|
-
const problems = commandShapeProblems(
|
|
2154
|
+
edit.commands.forEach((command3, k) => {
|
|
2155
|
+
const problems = commandShapeProblems(command3, `Command ${k + 1}`);
|
|
2057
2156
|
if (problems.length) fail(problems.join(" "));
|
|
2058
2157
|
});
|
|
2059
2158
|
const run = scene.shots[i].run;
|
|
@@ -2065,14 +2164,14 @@ function applyOne(scene, edit) {
|
|
|
2065
2164
|
const run = scene.shots[i].run;
|
|
2066
2165
|
if (!Number.isInteger(edit.command) || edit.command < 0 || edit.command >= run.length)
|
|
2067
2166
|
fail(`Shot "${edit.shot}" has ${run.length} command${run.length === 1 ? "" : "s"}; "command" must be an index from 0 to ${run.length - 1} (got ${edit.command}).`);
|
|
2068
|
-
const
|
|
2167
|
+
const command3 = { ...run[edit.command], ..._nullishCoalesce(edit.set, () => ( {})) };
|
|
2069
2168
|
for (const key of _nullishCoalesce(edit.remove, () => ( []))) {
|
|
2070
2169
|
if (key === "type") fail('"type" cannot be removed; replace the command instead.');
|
|
2071
|
-
delete
|
|
2170
|
+
delete command3[key];
|
|
2072
2171
|
}
|
|
2073
|
-
const problems = commandShapeProblems(
|
|
2172
|
+
const problems = commandShapeProblems(command3, `Command ${edit.command}`);
|
|
2074
2173
|
if (problems.length) fail(problems.join(" "));
|
|
2075
|
-
return replaceShot(scene, i, { ...scene.shots[i], run: run.map((c, k) => k === edit.command ?
|
|
2174
|
+
return replaceShot(scene, i, { ...scene.shots[i], run: run.map((c, k) => k === edit.command ? command3 : c) });
|
|
2076
2175
|
}
|
|
2077
2176
|
case "delete_commands": {
|
|
2078
2177
|
const i = shotIndex(scene, edit.shot);
|
|
@@ -2103,9 +2202,9 @@ function applyOne(scene, edit) {
|
|
|
2103
2202
|
else delete next.presets;
|
|
2104
2203
|
}
|
|
2105
2204
|
const names = new Set(edit.controls.map((c) => c.name));
|
|
2106
|
-
for (const
|
|
2107
|
-
for (const key of Object.keys(
|
|
2108
|
-
if (!names.has(key)) fail(`Preset "${
|
|
2205
|
+
for (const preset2 of _nullishCoalesce(next.presets, () => ( [])))
|
|
2206
|
+
for (const key of Object.keys(preset2.values))
|
|
2207
|
+
if (!names.has(key)) fail(`Preset "${preset2.name}" sets ${namedWithSuggestion(key, names)}, which is not a control.`);
|
|
2109
2208
|
return next;
|
|
2110
2209
|
}
|
|
2111
2210
|
case "replace_scene":
|
|
@@ -2125,9 +2224,9 @@ function applyMotionEdits(scene, edits) {
|
|
|
2125
2224
|
let next = scene;
|
|
2126
2225
|
for (let i = 0; i < list.length; i++) {
|
|
2127
2226
|
const edit = list[i];
|
|
2128
|
-
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess',
|
|
2227
|
+
const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _97 => _97.op])}): ` : "";
|
|
2129
2228
|
if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
|
|
2130
|
-
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess',
|
|
2229
|
+
return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _98 => _98.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
|
|
2131
2230
|
try {
|
|
2132
2231
|
next = applyOne(next, edit);
|
|
2133
2232
|
} catch (error) {
|
|
@@ -2149,7 +2248,7 @@ function resolveMotionEditRefs(scene, edits) {
|
|
|
2149
2248
|
const resolved = [];
|
|
2150
2249
|
let next = scene;
|
|
2151
2250
|
for (let i = 0; i < edits.length; i++) {
|
|
2152
|
-
const where = `op ${i + 1} (${_optionalChain([edits, 'access',
|
|
2251
|
+
const where = `op ${i + 1} (${_optionalChain([edits, 'access', _99 => _99[i], 'optionalAccess', _100 => _100.op])})`;
|
|
2153
2252
|
let problem = null;
|
|
2154
2253
|
const walk = (v) => {
|
|
2155
2254
|
if (typeof v === "string") {
|
|
@@ -2182,9 +2281,9 @@ function resolveMotionEditRefs(scene, edits) {
|
|
|
2182
2281
|
resolved.push(edit);
|
|
2183
2282
|
const out = { op: edit.op };
|
|
2184
2283
|
if (edit.op === "insert_shots") out.shots = edit.shots.map((s) => s.id);
|
|
2185
|
-
if ("shot" in edit && typeof edit.shot === "string") out.shot = edit.op === "update_shot" && _optionalChain([edit, 'access',
|
|
2284
|
+
if ("shot" in edit && typeof edit.shot === "string") out.shot = edit.op === "update_shot" && _optionalChain([edit, 'access', _101 => _101.set, 'optionalAccess', _102 => _102.id]) ? edit.set.id : edit.shot;
|
|
2186
2285
|
if (edit.op === "add_commands") {
|
|
2187
|
-
const at = _nullishCoalesce(_nullishCoalesce(edit.at, () => ( _optionalChain([before, 'access',
|
|
2286
|
+
const at = _nullishCoalesce(_nullishCoalesce(edit.at, () => ( _optionalChain([before, 'access', _103 => _103.shots, 'access', _104 => _104.find, 'call', _105 => _105((s) => s.id === edit.shot), 'optionalAccess', _106 => _106.run, 'access', _107 => _107.length]))), () => ( 0));
|
|
2188
2287
|
out.indexes = edit.commands.map((_, k) => at + k);
|
|
2189
2288
|
}
|
|
2190
2289
|
if (edit.op === "move_command") out.indexes = [edit.to];
|
|
@@ -2272,7 +2371,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2272
2371
|
const springs = flairAtLeast(flair, "0.39");
|
|
2273
2372
|
const strobes = flairAtLeast(flair, "0.39");
|
|
2274
2373
|
const writeEase = (ease) => typeof ease === "string" || "spring" in ease ? ease : ease.map(round2);
|
|
2275
|
-
const
|
|
2374
|
+
const easeOf2 = (segment) => {
|
|
2276
2375
|
const resolved = _chunk2FHLHZALcjs.resolveEasing.call(void 0, segment.ease);
|
|
2277
2376
|
if (resolved !== "hold" && resolved.type === "spring") {
|
|
2278
2377
|
if (!springs || segment.reverse) return void 0;
|
|
@@ -2337,13 +2436,13 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2337
2436
|
if (!route) continue;
|
|
2338
2437
|
const routeId = freshId(`${id}--follow-route`);
|
|
2339
2438
|
ids.set(seg.path, routeId);
|
|
2340
|
-
routes.push(`<path id="${routeId}" d="${
|
|
2439
|
+
routes.push(`<path id="${routeId}" d="${_chunkXGD3FSNCcjs.bezierPathToSvg.call(void 0, route, { precision })}" fill="none"/>`);
|
|
2341
2440
|
}
|
|
2342
2441
|
if (ids.size) {
|
|
2343
2442
|
const wrapper = freshId(`${id}--follow`);
|
|
2344
2443
|
const centre = freshId(`${id}--follow-centre`);
|
|
2345
2444
|
const c = entry.center;
|
|
2346
|
-
const at = _optionalChain([motionNodeOffset, 'call',
|
|
2445
|
+
const at = _optionalChain([motionNodeOffset, 'call', _108 => _108(entry, timeline, 0, nodes), 'optionalAccess', _109 => _109.follow]);
|
|
2347
2446
|
const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
|
|
2348
2447
|
(wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
|
|
2349
2448
|
follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
|
|
@@ -2373,7 +2472,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2373
2472
|
raw: (t) => transformAt(t, true)
|
|
2374
2473
|
});
|
|
2375
2474
|
}
|
|
2376
|
-
const paths = node.type === "path" ? [node] :
|
|
2475
|
+
const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
|
|
2377
2476
|
for (const path of paths) {
|
|
2378
2477
|
if (pathsSeen.has(path.id)) continue;
|
|
2379
2478
|
pathsSeen.add(path.id);
|
|
@@ -2395,7 +2494,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2395
2494
|
if (shapeSegments.length) {
|
|
2396
2495
|
if (node.type !== "path") notes.push(`"${id}" is a group: its morph or effect animation is not exported (Flair tweens one path's "d").`);
|
|
2397
2496
|
else {
|
|
2398
|
-
const inverse =
|
|
2497
|
+
const inverse = _chunk7MD7C6XQcjs.invertMatrix.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, node));
|
|
2399
2498
|
channels.push({
|
|
2400
2499
|
id,
|
|
2401
2500
|
kind: "attr",
|
|
@@ -2404,10 +2503,10 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2404
2503
|
exact: () => false,
|
|
2405
2504
|
value: (t) => {
|
|
2406
2505
|
const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
|
|
2407
|
-
const now =
|
|
2506
|
+
const now = _chunk7MD7C6XQcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _110 => _110(frame.document.nodes), 'access', _111 => _111.get, 'call', _112 => _112(id), 'optionalAccess', _113 => _113.node]));
|
|
2408
2507
|
if (!now || now.type !== "path") return "";
|
|
2409
|
-
const bezier =
|
|
2410
|
-
return
|
|
2508
|
+
const bezier = _chunkXGD3FSNCcjs.transformBezierPath.call(void 0, _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, now, _chunk7MD7C6XQcjs.IDENTITY_MATRIX, { effects: false }), inverse);
|
|
2509
|
+
return _chunkXGD3FSNCcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
|
|
2411
2510
|
}
|
|
2412
2511
|
});
|
|
2413
2512
|
}
|
|
@@ -2425,8 +2524,8 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2425
2524
|
...delay > 0 ? { delay: round2(delay) } : {},
|
|
2426
2525
|
ms: round2(ms),
|
|
2427
2526
|
ease: written,
|
|
2428
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
2429
|
-
..._optionalChain([segment, 'optionalAccess',
|
|
2527
|
+
..._optionalChain([segment, 'optionalAccess', _114 => _114.behavior]) ? { behavior: segment.behavior } : {},
|
|
2528
|
+
..._optionalChain([segment, 'optionalAccess', _115 => _115.steps]) ? { strobe: segment.steps } : {}
|
|
2430
2529
|
};
|
|
2431
2530
|
if (channel.kind === "view") animate.push({ ...base, view: to });
|
|
2432
2531
|
else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
|
|
@@ -2451,7 +2550,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2451
2550
|
const first = active[0];
|
|
2452
2551
|
const key = (x) => JSON.stringify([x.ease, x.behavior, _nullishCoalesce(x.reverse, () => ( false)), _nullishCoalesce(x.steps, () => ( 0))]);
|
|
2453
2552
|
const together = active.every((x) => x.start === a && x.end === b && channel.exact(x) && key(x) === key(first));
|
|
2454
|
-
const curve = together ?
|
|
2553
|
+
const curve = together ? easeOf2(first) : void 0;
|
|
2455
2554
|
const ease = curve && (!overshoots(curve) || channel.overshoot) ? curve : void 0;
|
|
2456
2555
|
if (ease) {
|
|
2457
2556
|
const from = channel.value(a);
|
|
@@ -2478,7 +2577,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2478
2577
|
for (const seg of follow.segments) {
|
|
2479
2578
|
const along = { id: follow.wrapper, along: follow.routes.get(seg.path), ...seg.rotate ? { orient: true } : {} };
|
|
2480
2579
|
const progress = (t) => round2(Math.min(1, Math.max(0, Number(segmentValue(seg, t)))));
|
|
2481
|
-
const curve = seg.end > seg.start ? plays(seg) ?
|
|
2580
|
+
const curve = seg.end > seg.start ? plays(seg) ? easeOf2(seg) : void 0 : "linear";
|
|
2482
2581
|
if (curve && !(overshoots(curve) && seg.rotate)) {
|
|
2483
2582
|
const ends = seg.reverse ? [Number(seg.to), Number(seg.from)] : [Number(seg.from), Number(seg.to)];
|
|
2484
2583
|
animate.push({ ...along, ...seg.start > 0 ? { delay: round2(seg.start) } : {}, ms: round2(seg.end - seg.start), ease: writeEase(curve), ...seg.steps ? { strobe: seg.steps } : {}, at: [round2(ends[0]), round2(ends[1])] });
|
|
@@ -2513,10 +2612,10 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2513
2612
|
}
|
|
2514
2613
|
if (scene.motionBlur) notes.push("Motion blur is drawn on the stage only; Flair plays the scene sharp.");
|
|
2515
2614
|
if (trigger && (_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") notes.push(`The scene plays on ${trigger}, so its loop does not apply in Flair.`);
|
|
2516
|
-
let svg =
|
|
2615
|
+
let svg = _chunk7MD7C6XQcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunk7MD7C6XQcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
|
|
2517
2616
|
if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
|
|
2518
2617
|
let motion = { svg, animate };
|
|
2519
|
-
if (_optionalChain([scene, 'access',
|
|
2618
|
+
if (_optionalChain([scene, 'access', _116 => _116.controls, 'optionalAccess', _117 => _117.length])) {
|
|
2520
2619
|
const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
|
|
2521
2620
|
const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
|
|
2522
2621
|
svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
|
|
@@ -2538,7 +2637,7 @@ function toFlairVectorEffect(scene, options = {}) {
|
|
|
2538
2637
|
tags: _nullishCoalesce(options.tags, () => ( [])),
|
|
2539
2638
|
motion: out.motion,
|
|
2540
2639
|
hold: out.hold,
|
|
2541
|
-
..._optionalChain([scene, 'access',
|
|
2640
|
+
..._optionalChain([scene, 'access', _118 => _118.presets, 'optionalAccess', _119 => _119.length]) ? { presets: scene.presets } : {},
|
|
2542
2641
|
...out.trigger ? { trigger: out.trigger } : {}
|
|
2543
2642
|
};
|
|
2544
2643
|
}
|
|
@@ -2582,7 +2681,7 @@ function resolvePlaceholders(motion, notes) {
|
|
|
2582
2681
|
const filled = text.replace(PLACEHOLDER, (_, name) => {
|
|
2583
2682
|
const d = declared.get(name);
|
|
2584
2683
|
if (!d) unknown.add(name);
|
|
2585
|
-
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess',
|
|
2684
|
+
return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _120 => _120.value]), () => ( ""))).replace(/"/g, '\\"');
|
|
2586
2685
|
});
|
|
2587
2686
|
for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
|
|
2588
2687
|
return { motion: JSON.parse(filled), controls };
|
|
@@ -2597,14 +2696,14 @@ function easingOf(ease, fallback) {
|
|
|
2597
2696
|
return fallback;
|
|
2598
2697
|
}
|
|
2599
2698
|
function poseOf(value, entry) {
|
|
2600
|
-
const t =
|
|
2601
|
-
const o =
|
|
2699
|
+
const t = _chunk7MD7C6XQcjs.parseSvgTransform.call(void 0, String(value));
|
|
2700
|
+
const o = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _nullishCoalesce(_chunk7MD7C6XQcjs.invertMatrix.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, entry.node)), () => ( [1, 0, 0, 1, 0, 0])), t);
|
|
2602
2701
|
const sx = Math.hypot(o[0], o[1]);
|
|
2603
2702
|
if (!(sx > 1e-9)) return null;
|
|
2604
2703
|
const sy = (o[0] * o[3] - o[1] * o[2]) / sx;
|
|
2605
2704
|
if (Math.abs(o[2] + o[1] / sx * sy) > 1e-6 || Math.abs(o[3] - o[0] / sx * sy) > 1e-6) return null;
|
|
2606
2705
|
const c = entry.center;
|
|
2607
|
-
const moved =
|
|
2706
|
+
const moved = _chunk7MD7C6XQcjs.applyMatrix.call(void 0, o, c);
|
|
2608
2707
|
return { dx: moved.x - c.x, dy: moved.y - c.y, rotation: Math.atan2(o[1], o[0]) * 180 / Math.PI, sx, sy };
|
|
2609
2708
|
}
|
|
2610
2709
|
var near = (a, b, eps = 1e-6) => Math.abs(a - b) < eps;
|
|
@@ -2636,7 +2735,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2636
2735
|
if (anim.along) {
|
|
2637
2736
|
const path = nodes.get(anim.along);
|
|
2638
2737
|
if (!path || path.node.type !== "path") notes.push(`${where} follows "${anim.along}", which is not a path in the artwork; the follow was skipped.`);
|
|
2639
|
-
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access',
|
|
2738
|
+
else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _121 => _121.at, 'optionalAccess', _122 => _122[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _123 => _123.at, 'optionalAccess', _124 => _124[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2640
2739
|
}
|
|
2641
2740
|
for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
|
|
2642
2741
|
if (attr === "opacity") {
|
|
@@ -2647,7 +2746,7 @@ function commandsFor(anim, nodes, entered, notes) {
|
|
|
2647
2746
|
out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
|
|
2648
2747
|
} else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
2649
2748
|
} else if (attr === "fill" || attr === "stroke") {
|
|
2650
|
-
if (_optionalChain([behavior, 'optionalAccess',
|
|
2749
|
+
if (_optionalChain([behavior, 'optionalAccess', _125 => _125.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
|
|
2651
2750
|
else {
|
|
2652
2751
|
if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
|
|
2653
2752
|
out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
|
|
@@ -2689,7 +2788,7 @@ function fromFlairSvgMotion(input, options = {}) {
|
|
|
2689
2788
|
const notes = [];
|
|
2690
2789
|
if (!input || typeof input.svg !== "string") throw new Error('Give a Flair SvgMotion: { svg: "<svg \u2026>", animate: [ \u2026 ] }.');
|
|
2691
2790
|
const { motion, controls } = resolvePlaceholders(input, notes);
|
|
2692
|
-
const artwork =
|
|
2791
|
+
const artwork = _chunk7MD7C6XQcjs.parseVectorSvg.call(void 0, motion.svg);
|
|
2693
2792
|
const nodes = indexMotionNodes(artwork.nodes);
|
|
2694
2793
|
const byStep = /* @__PURE__ */ new Map();
|
|
2695
2794
|
for (const anim of _nullishCoalesce(motion.animate, () => ( []))) {
|
|
@@ -2722,9 +2821,9 @@ function fromFlairSvgMotion(input, options = {}) {
|
|
|
2722
2821
|
if (!anim.id) continue;
|
|
2723
2822
|
const at = Math.max(0, (_nullishCoalesce(anim.delay, () => ( 0))) - cameraMs);
|
|
2724
2823
|
if (cameraMs && (_nullishCoalesce(anim.delay, () => ( 0))) < cameraMs) notes.push(`Step ${step}: a change to "${anim.id}" during the camera move now starts after it.`);
|
|
2725
|
-
for (const
|
|
2824
|
+
for (const command3 of commandsFor(anim, nodes, entered, notes)) {
|
|
2726
2825
|
const first = run.length === 0;
|
|
2727
|
-
run.push({ ...
|
|
2826
|
+
run.push({ ...command3, ...first ? {} : { with: "previous" }, ...at - last > 0 || first ? { delay: first ? at : at - last } : {} });
|
|
2728
2827
|
if (first && at === 0) delete run[run.length - 1].delay;
|
|
2729
2828
|
last = at;
|
|
2730
2829
|
}
|
|
@@ -2936,11 +3035,11 @@ function toLottie(scene, options = {}) {
|
|
|
2936
3035
|
const items = [];
|
|
2937
3036
|
const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
|
|
2938
3037
|
const geometryAt = (t) => {
|
|
2939
|
-
if (!shapeSegments.length) return
|
|
2940
|
-
const now = _optionalChain([indexMotionNodes, 'call',
|
|
2941
|
-
return now && now.type === "path" ?
|
|
3038
|
+
if (!shapeSegments.length) return _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, path);
|
|
3039
|
+
const now = _optionalChain([indexMotionNodes, 'call', _126 => _126(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _127 => _127.get, 'call', _128 => _128(path.id), 'optionalAccess', _129 => _129.node]);
|
|
3040
|
+
return now && now.type === "path" ? _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, _chunk7MD7C6XQcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, path);
|
|
2942
3041
|
};
|
|
2943
|
-
const rest = lottieContours(
|
|
3042
|
+
const rest = lottieContours(_chunkXGD3FSNCcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
|
|
2944
3043
|
rest.forEach((contour, n) => {
|
|
2945
3044
|
let ks = { a: 0, k: contour };
|
|
2946
3045
|
if (shapeSegments.length) {
|
|
@@ -2949,7 +3048,7 @@ function toLottie(scene, options = {}) {
|
|
|
2949
3048
|
const count = Math.max(1, Math.ceil(end * fps / 1e3));
|
|
2950
3049
|
for (let k = 0; k <= count && fits; k++) {
|
|
2951
3050
|
const t = end * k / count;
|
|
2952
|
-
const c = lottieContours(
|
|
3051
|
+
const c = lottieContours(_chunkXGD3FSNCcjs.toBezierPath.call(void 0, geometryAt(t)), round2)[n];
|
|
2953
3052
|
if (!c || c.v.length !== contour.v.length || c.c !== contour.c) fits = false;
|
|
2954
3053
|
else keys.push({ t: frame(t), s: [c], ...k < count ? { o: { x: [0], y: [0] }, i: { x: [1], y: [1] } } : {} });
|
|
2955
3054
|
}
|
|
@@ -2974,28 +3073,28 @@ function toLottie(scene, options = {}) {
|
|
|
2974
3073
|
}
|
|
2975
3074
|
const stroke = paintOf(path.stroke, "stroke", path.id);
|
|
2976
3075
|
if (stroke || strokeFrom) {
|
|
2977
|
-
const
|
|
3076
|
+
const colour2 = strokeFrom ? track(strokeFrom, "stroke") : [];
|
|
2978
3077
|
items.push({
|
|
2979
3078
|
ty: "st",
|
|
2980
3079
|
nm: "Stroke",
|
|
2981
|
-
c:
|
|
3080
|
+
c: colour2.length ? animate(colour2, (t) => _nullishCoalesce(_nullishCoalesce(rgba(trackValue(colour2, t)), () => ( stroke)), () => ( [0, 0, 0, 1]))) : { a: 0, k: (_nullishCoalesce(stroke, () => ( [0, 0, 0, 1]))).map(round2) },
|
|
2982
3081
|
o: { a: 0, k: 100 },
|
|
2983
3082
|
w: widthFrom ? animate(track(widthFrom, "strokeWidth"), (t) => [Math.max(0, Number(_nullishCoalesce(_nullishCoalesce(trackValue(track(widthFrom, "strokeWidth"), t), () => ( path.strokeWidth)), () => ( 1))))]) : { a: 0, k: round2(_nullishCoalesce(path.strokeWidth, () => ( 1))) },
|
|
2984
3083
|
lc: path.strokeLinecap === "round" ? 2 : path.strokeLinecap === "square" ? 3 : 1,
|
|
2985
3084
|
lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
|
|
2986
3085
|
ml: 4
|
|
2987
3086
|
});
|
|
2988
|
-
if (_optionalChain([path, 'access',
|
|
3087
|
+
if (_optionalChain([path, 'access', _130 => _130.strokeDasharray, 'optionalAccess', _131 => _131.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
|
|
2989
3088
|
if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
|
|
2990
3089
|
}
|
|
2991
3090
|
const fill = paintOf(path.fill, "fill", path.id);
|
|
2992
3091
|
if (fill || fillFrom) {
|
|
2993
|
-
const
|
|
3092
|
+
const colour2 = fillFrom ? track(fillFrom, "fill") : [];
|
|
2994
3093
|
const fade = fadeFrom ? track(fadeFrom, "fillOpacity") : [];
|
|
2995
3094
|
items.push({
|
|
2996
3095
|
ty: "fl",
|
|
2997
3096
|
nm: "Fill",
|
|
2998
|
-
c:
|
|
3097
|
+
c: colour2.length ? animate(colour2, (t) => _nullishCoalesce(_nullishCoalesce(rgba(trackValue(colour2, t)), () => ( fill)), () => ( [0, 0, 0, 1]))) : { a: 0, k: (_nullishCoalesce(fill, () => ( [0, 0, 0, 1]))).map(round2) },
|
|
2999
3098
|
o: fade.length ? animate(fade, (t) => [Math.min(1, Math.max(0, Number(_nullishCoalesce(trackValue(fade, t), () => ( 1))))) * 100]) : { a: 0, k: 100 },
|
|
3000
3099
|
r: path.fillRule === "evenodd" ? 2 : 1
|
|
3001
3100
|
});
|
|
@@ -3012,8 +3111,8 @@ function toLottie(scene, options = {}) {
|
|
|
3012
3111
|
if (node.type === "path") inner = [...pathShapes(node)];
|
|
3013
3112
|
else {
|
|
3014
3113
|
inner = shown(node.children).reverse().map(nodeGroup);
|
|
3015
|
-
const m =
|
|
3016
|
-
if (m !==
|
|
3114
|
+
const m = _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, node);
|
|
3115
|
+
if (m !== _chunk7MD7C6XQcjs.IDENTITY_MATRIX) {
|
|
3017
3116
|
const parts = staticParts(m);
|
|
3018
3117
|
if (!parts) notes.push(`"${node.id}": its transform skews, which is not exported; it is drawn without the skew.`);
|
|
3019
3118
|
else {
|
|
@@ -3026,7 +3125,7 @@ function toLottie(scene, options = {}) {
|
|
|
3026
3125
|
const body = { ty: "gr", nm: `${node.id} (own)`, it: [...inner, innerTr] };
|
|
3027
3126
|
return { ty: "gr", nm: _nullishCoalesce(node.name, () => ( node.id)), it: [body, poseTransform(entry)] };
|
|
3028
3127
|
};
|
|
3029
|
-
const artwork = { ...scene.artwork, nodes:
|
|
3128
|
+
const artwork = { ...scene.artwork, nodes: _chunk7MD7C6XQcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) };
|
|
3030
3129
|
const content = shown(artwork.nodes).reverse().map(nodeGroup);
|
|
3031
3130
|
if (artwork.background && rgba(artwork.background))
|
|
3032
3131
|
content.push({ ty: "gr", nm: "Background", it: [{ ty: "rc", nm: "Background", p: { a: 0, k: [artwork.width / 2, artwork.height / 2] }, s: { a: 0, k: [artwork.width, artwork.height] }, r: { a: 0, k: 0 } }, { ty: "fl", c: { a: 0, k: rgba(artwork.background).map(round2) }, o: { a: 0, k: 100 }, r: 1 }, STATIC_TR()] });
|
|
@@ -3069,6 +3168,383 @@ function toLottie(scene, options = {}) {
|
|
|
3069
3168
|
return { lottie, sampled, notes: [...new Set(notes)] };
|
|
3070
3169
|
}
|
|
3071
3170
|
|
|
3171
|
+
// src/animation-editor/pptx.ts
|
|
3172
|
+
var EMU = 9525;
|
|
3173
|
+
var kids = (el, name) => el ? Array.from(el.children).filter((c) => c.localName === name) : [];
|
|
3174
|
+
var kid = (el, name) => _nullishCoalesce(kids(el, name)[0], () => ( null));
|
|
3175
|
+
var deep = (el, name) => el ? Array.from(el.getElementsByTagNameNS("*", name)) : [];
|
|
3176
|
+
var num = (el, attr, fallback = 0) => {
|
|
3177
|
+
const v = _optionalChain([el, 'optionalAccess', _132 => _132.getAttribute, 'call', _133 => _133(attr)]);
|
|
3178
|
+
const n = v === null || v === void 0 ? NaN : Number(v);
|
|
3179
|
+
return Number.isFinite(n) ? n : fallback;
|
|
3180
|
+
};
|
|
3181
|
+
var dirname = (p) => p.slice(0, p.lastIndexOf("/") + 1);
|
|
3182
|
+
function resolve(base, target) {
|
|
3183
|
+
const out = [];
|
|
3184
|
+
for (const seg of (target.startsWith("/") ? target.slice(1) : base + target).split("/")) {
|
|
3185
|
+
if (seg === "..") out.pop();
|
|
3186
|
+
else if (seg && seg !== ".") out.push(seg);
|
|
3187
|
+
}
|
|
3188
|
+
return out.join("/");
|
|
3189
|
+
}
|
|
3190
|
+
async function xml(ctx, path) {
|
|
3191
|
+
if (!ctx.zip.has(path)) return null;
|
|
3192
|
+
const text = new TextDecoder().decode(await ctx.zip.read(path));
|
|
3193
|
+
const doc = new ctx.Parser().parseFromString(text, "application/xml");
|
|
3194
|
+
return doc.getElementsByTagName("parsererror").length ? null : doc;
|
|
3195
|
+
}
|
|
3196
|
+
async function rels(ctx, part) {
|
|
3197
|
+
const doc = await xml(ctx, `${dirname(part)}_rels/${part.slice(part.lastIndexOf("/") + 1)}.rels`);
|
|
3198
|
+
const out = /* @__PURE__ */ new Map();
|
|
3199
|
+
for (const r of deep(doc, "Relationship")) if (r.getAttribute("TargetMode") !== "External") out.set(_nullishCoalesce(r.getAttribute("Id"), () => ( "")), resolve(dirname(part), _nullishCoalesce(r.getAttribute("Target"), () => ( ""))));
|
|
3200
|
+
return out;
|
|
3201
|
+
}
|
|
3202
|
+
function colour(ctx, holder) {
|
|
3203
|
+
if (!holder) return null;
|
|
3204
|
+
const c = holder.firstElementChild;
|
|
3205
|
+
if (!c) return null;
|
|
3206
|
+
let hex = null;
|
|
3207
|
+
if (c.localName === "srgbClr") hex = `#${(_nullishCoalesce(c.getAttribute("val"), () => ( "000000"))).toLowerCase()}`;
|
|
3208
|
+
else if (c.localName === "sysClr") hex = `#${(_nullishCoalesce(c.getAttribute("lastClr"), () => ( "000000"))).toLowerCase()}`;
|
|
3209
|
+
else if (c.localName === "schemeClr") {
|
|
3210
|
+
const name = _nullishCoalesce(c.getAttribute("val"), () => ( ""));
|
|
3211
|
+
const alias = { tx1: "dk1", bg1: "lt1", tx2: "dk2", bg2: "lt2" };
|
|
3212
|
+
hex = _nullishCoalesce(ctx.theme.get(_nullishCoalesce(alias[name], () => ( name))), () => ( null));
|
|
3213
|
+
} else if (c.localName === "prstClr") hex = _nullishCoalesce({ black: "#000000", white: "#ffffff", red: "#ff0000", green: "#008000", blue: "#0000ff" }[_nullishCoalesce(c.getAttribute("val"), () => ( ""))], () => ( null));
|
|
3214
|
+
if (!hex || !/^#[0-9a-f]{6}$/.test(hex)) return null;
|
|
3215
|
+
const lum = kid(c, "lumMod");
|
|
3216
|
+
if (lum) {
|
|
3217
|
+
const k = num(lum, "val", 1e5) / 1e5;
|
|
3218
|
+
const off = num(kid(c, "lumOff"), "val", 0) / 1e5;
|
|
3219
|
+
hex = `#${[1, 3, 5].map((i) => Math.round(Math.min(255, Math.max(0, parseInt(hex.slice(i, i + 2), 16) * k + 255 * off))).toString(16).padStart(2, "0")).join("")}`;
|
|
3220
|
+
}
|
|
3221
|
+
return hex;
|
|
3222
|
+
}
|
|
3223
|
+
function preset(prst, w, h) {
|
|
3224
|
+
const poly = (pts) => [{ closed: true, anchors: pts.map(([x, y]) => ({ x, y })) }];
|
|
3225
|
+
switch (prst) {
|
|
3226
|
+
case "rect":
|
|
3227
|
+
return [_chunk7MD7C6XQcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
|
|
3228
|
+
case "roundRect":
|
|
3229
|
+
return [_chunk7MD7C6XQcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h }, Math.min(w, h) * 0.16667)];
|
|
3230
|
+
case "ellipse":
|
|
3231
|
+
return [_chunk7MD7C6XQcjs.ellipseSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
|
|
3232
|
+
case "triangle":
|
|
3233
|
+
return poly([[w / 2, 0], [w, h], [0, h]]);
|
|
3234
|
+
case "rtTriangle":
|
|
3235
|
+
return poly([[0, 0], [w, h], [0, h]]);
|
|
3236
|
+
case "diamond":
|
|
3237
|
+
return poly([[w / 2, 0], [w, h / 2], [w / 2, h], [0, h / 2]]);
|
|
3238
|
+
case "parallelogram":
|
|
3239
|
+
return poly([[w * 0.25, 0], [w, 0], [w * 0.75, h], [0, h]]);
|
|
3240
|
+
case "hexagon":
|
|
3241
|
+
return poly([[w * 0.25, 0], [w * 0.75, 0], [w, h / 2], [w * 0.75, h], [w * 0.25, h], [0, h / 2]]);
|
|
3242
|
+
case "line":
|
|
3243
|
+
case "straightConnector1":
|
|
3244
|
+
return [{ closed: false, anchors: [{ x: 0, y: 0 }, { x: w, y: h }] }];
|
|
3245
|
+
default:
|
|
3246
|
+
return null;
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
function custom(geom, w, h) {
|
|
3250
|
+
const out = [];
|
|
3251
|
+
for (const path of deep(geom, "path")) {
|
|
3252
|
+
const sx = w / (num(path, "w") || w || 1);
|
|
3253
|
+
const sy = h / (num(path, "h") || h || 1);
|
|
3254
|
+
const pt = (el) => ({ x: num(el, "x") * sx, y: num(el, "y") * sy });
|
|
3255
|
+
let cur = null;
|
|
3256
|
+
for (const cmd of Array.from(path.children)) {
|
|
3257
|
+
const pts = kids(cmd, "pt").map(pt);
|
|
3258
|
+
if (cmd.localName === "moveTo" && pts[0]) {
|
|
3259
|
+
if (cur) out.push(cur);
|
|
3260
|
+
cur = { closed: false, anchors: [{ x: pts[0].x, y: pts[0].y }] };
|
|
3261
|
+
} else if (!cur) continue;
|
|
3262
|
+
else if (cmd.localName === "lnTo" && pts[0]) cur.anchors.push({ x: pts[0].x, y: pts[0].y });
|
|
3263
|
+
else if (cmd.localName === "cubicBezTo" && pts.length === 3) {
|
|
3264
|
+
cur.anchors[cur.anchors.length - 1].out = pts[0];
|
|
3265
|
+
cur.anchors.push({ x: pts[2].x, y: pts[2].y, in: pts[1] });
|
|
3266
|
+
} else if (cmd.localName === "quadBezTo" && pts.length === 2) {
|
|
3267
|
+
const p0 = cur.anchors[cur.anchors.length - 1];
|
|
3268
|
+
cur.anchors[cur.anchors.length - 1].out = { x: p0.x + 2 / 3 * (pts[0].x - p0.x), y: p0.y + 2 / 3 * (pts[0].y - p0.y) };
|
|
3269
|
+
cur.anchors.push({ x: pts[1].x, y: pts[1].y, in: { x: pts[1].x + 2 / 3 * (pts[0].x - pts[1].x), y: pts[1].y + 2 / 3 * (pts[0].y - pts[1].y) } });
|
|
3270
|
+
} else if (cmd.localName === "close") {
|
|
3271
|
+
cur.closed = true;
|
|
3272
|
+
out.push(cur);
|
|
3273
|
+
cur = null;
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
if (cur) out.push(cur);
|
|
3277
|
+
}
|
|
3278
|
+
return out;
|
|
3279
|
+
}
|
|
3280
|
+
function placement(xfrm, map) {
|
|
3281
|
+
const off = kid(xfrm, "off");
|
|
3282
|
+
const ext = kid(xfrm, "ext");
|
|
3283
|
+
const [x, y, w, h] = map(num(off, "x"), num(off, "y"), num(ext, "cx"), num(ext, "cy"));
|
|
3284
|
+
const rot = num(xfrm, "rot") / 6e4 * (Math.PI / 180);
|
|
3285
|
+
const fx = _optionalChain([xfrm, 'optionalAccess', _134 => _134.getAttribute, 'call', _135 => _135("flipH")]) === "1" ? -1 : 1;
|
|
3286
|
+
const fy = _optionalChain([xfrm, 'optionalAccess', _136 => _136.getAttribute, 'call', _137 => _137("flipV")]) === "1" ? -1 : 1;
|
|
3287
|
+
const cx = x + w / 2;
|
|
3288
|
+
const cy = y + h / 2;
|
|
3289
|
+
const cos = Math.cos(rot);
|
|
3290
|
+
const sin = Math.sin(rot);
|
|
3291
|
+
const a = cos * fx;
|
|
3292
|
+
const b = sin * fx;
|
|
3293
|
+
const c = -sin * fy;
|
|
3294
|
+
const d = cos * fy;
|
|
3295
|
+
const e = cx - a * (w / 2) - c * (h / 2);
|
|
3296
|
+
const f = cy - b * (w / 2) - d * (h / 2);
|
|
3297
|
+
return { x, y, w, h, transform: [a, b, c, d, e, f].map((v) => v + 0) };
|
|
3298
|
+
}
|
|
3299
|
+
var idFor = (ctx, spid, name) => {
|
|
3300
|
+
const base = `${name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "shape"}-${spid}`;
|
|
3301
|
+
let id = base;
|
|
3302
|
+
for (let k = 2; ctx.used.has(id); k++) id = `${base}-${k}`;
|
|
3303
|
+
ctx.used.add(id);
|
|
3304
|
+
ctx.nodes.set(spid, id);
|
|
3305
|
+
return id;
|
|
3306
|
+
};
|
|
3307
|
+
function shapes(ctx, tree, map) {
|
|
3308
|
+
const out = [];
|
|
3309
|
+
for (const el of Array.from(tree.children)) {
|
|
3310
|
+
const nv = el.firstElementChild;
|
|
3311
|
+
const cNvPr = kid(nv, "cNvPr");
|
|
3312
|
+
const spid = num(cNvPr, "id", -1);
|
|
3313
|
+
const name = _nullishCoalesce(_optionalChain([cNvPr, 'optionalAccess', _138 => _138.getAttribute, 'call', _139 => _139("name")]), () => ( ""));
|
|
3314
|
+
if (el.localName === "grpSp") {
|
|
3315
|
+
const xfrm = kid(kid(el, "grpSpPr"), "xfrm");
|
|
3316
|
+
const off = kid(xfrm, "off");
|
|
3317
|
+
const ext = kid(xfrm, "ext");
|
|
3318
|
+
const chOff = kid(xfrm, "chOff");
|
|
3319
|
+
const chExt = kid(xfrm, "chExt");
|
|
3320
|
+
const sx = num(ext, "cx") / (num(chExt, "cx") || num(ext, "cx") || 1);
|
|
3321
|
+
const sy = num(ext, "cy") / (num(chExt, "cy") || num(ext, "cy") || 1);
|
|
3322
|
+
const inner = (x, y, w2, h2) => map(num(off, "x") + (x - num(chOff, "x")) * sx, num(off, "y") + (y - num(chOff, "y")) * sy, w2 * sx, h2 * sy);
|
|
3323
|
+
const id = idFor(ctx, spid, name || "group");
|
|
3324
|
+
out.push({ id, type: "group", ...name ? { name } : {}, children: shapes(ctx, el, inner) });
|
|
3325
|
+
continue;
|
|
3326
|
+
}
|
|
3327
|
+
if (el.localName === "pic" || el.localName === "graphicFrame") {
|
|
3328
|
+
ctx.notes.push(`"${name || `shape ${spid}`}" is a ${el.localName === "pic" ? "picture" : "chart, table or diagram"}, which the artwork cannot hold; it was left out.`);
|
|
3329
|
+
continue;
|
|
3330
|
+
}
|
|
3331
|
+
if (el.localName !== "sp" && el.localName !== "cxnSp") continue;
|
|
3332
|
+
const spPr = kid(el, "spPr");
|
|
3333
|
+
const { w, h, transform } = placement(kid(spPr, "xfrm"), map);
|
|
3334
|
+
const prst = _optionalChain([kid, 'call', _140 => _140(spPr, "prstGeom"), 'optionalAccess', _141 => _141.getAttribute, 'call', _142 => _142("prst")]);
|
|
3335
|
+
const cust = kid(spPr, "custGeom");
|
|
3336
|
+
let subpaths = cust ? custom(cust, w, h) : prst ? preset(prst, w, h) : null;
|
|
3337
|
+
if (!subpaths) {
|
|
3338
|
+
if (prst) ctx.notes.push(`"${name}" is a ${prst}, drawn as its bounding rectangle.`);
|
|
3339
|
+
subpaths = [_chunk7MD7C6XQcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
|
|
3340
|
+
}
|
|
3341
|
+
const style = kid(el, "style");
|
|
3342
|
+
const fill = kid(spPr, "noFill") ? null : _nullishCoalesce(colour(ctx, kid(spPr, "solidFill")), () => ( (el.localName === "cxnSp" ? null : colour(ctx, kid(style, "fillRef")))));
|
|
3343
|
+
const ln = kid(spPr, "ln");
|
|
3344
|
+
const stroke = kid(ln, "noFill") ? null : _nullishCoalesce(colour(ctx, kid(ln, "solidFill")), () => ( colour(ctx, kid(style, "lnRef"))));
|
|
3345
|
+
if (kid(spPr, "gradFill")) ctx.notes.push(`"${name}" has a gradient fill, imported as its first colour or none.`);
|
|
3346
|
+
const text = deep(kid(el, "txBody"), "t").map((t) => _nullishCoalesce(t.textContent, () => ( ""))).join("").trim();
|
|
3347
|
+
if (text) ctx.notes.push(`"${name}" has text ("${text.slice(0, 40)}${text.length > 40 ? "\u2026" : ""}"), which the artwork cannot hold; only its shape was imported.`);
|
|
3348
|
+
const node = {
|
|
3349
|
+
id: idFor(ctx, spid, name),
|
|
3350
|
+
type: "path",
|
|
3351
|
+
...name ? { name } : {},
|
|
3352
|
+
transform,
|
|
3353
|
+
fill: _nullishCoalesce(fill, () => ( (kid(spPr, "gradFill") ? colour(ctx, kid(deep(spPr, "gs")[0], "srgbClr") ? deep(spPr, "gs")[0] : null) : null))),
|
|
3354
|
+
stroke,
|
|
3355
|
+
strokeWidth: Math.max(0.5, (num(ln, "w", 12700) || 12700) / EMU),
|
|
3356
|
+
subpaths
|
|
3357
|
+
};
|
|
3358
|
+
out.push(node);
|
|
3359
|
+
}
|
|
3360
|
+
return out;
|
|
3361
|
+
}
|
|
3362
|
+
var DIRECTION_FROM = { 1: "down", 2: "left", 4: "up", 8: "right" };
|
|
3363
|
+
var DIRECTION_TO = { 1: "up", 2: "right", 4: "down", 8: "left" };
|
|
3364
|
+
function easeOf(ctn) {
|
|
3365
|
+
const accel = num(ctn, "accel") / 1e5;
|
|
3366
|
+
const decel = num(ctn, "decel") / 1e5;
|
|
3367
|
+
if (!accel && !decel) return void 0;
|
|
3368
|
+
return { type: "cubic-bezier", x1: Math.min(1, accel), y1: 0, x2: Math.max(0, 1 - decel), y2: 1 };
|
|
3369
|
+
}
|
|
3370
|
+
function command(ctx, ctn, scene, artwork, target, hidden) {
|
|
3371
|
+
const cls = ctn.getAttribute("presetClass");
|
|
3372
|
+
const id = num(ctn, "presetID");
|
|
3373
|
+
const sub = num(ctn, "presetSubtype");
|
|
3374
|
+
const durs = [ctn, ...deep(ctn, "cTn")].map((c) => num(c, "dur", NaN)).filter(Number.isFinite);
|
|
3375
|
+
const duration = durs.length ? Math.max(...durs) : void 0;
|
|
3376
|
+
const ease = easeOf(ctn);
|
|
3377
|
+
const base = { targets: [target], ...duration !== void 0 ? { duration } : {}, ...ease ? { ease } : {} };
|
|
3378
|
+
const repeat = num(ctn, "repeatCount", 1e3) / 1e3;
|
|
3379
|
+
const auto = ctn.getAttribute("autoRev") === "1";
|
|
3380
|
+
const timing = auto || repeat > 1 ? { repeat: Math.max(1, Math.round(repeat)) * (auto ? 2 : 1), ...auto ? { repeatMode: "mirror" } : {} } : {};
|
|
3381
|
+
const label = `${cls} effect ${id} on "${target}"`;
|
|
3382
|
+
if (cls === "entr") {
|
|
3383
|
+
const by = {
|
|
3384
|
+
1: { type: "enter", ...base, duration: 0 },
|
|
3385
|
+
2: { type: "enter", style: "slide", ...base, direction: _nullishCoalesce(DIRECTION_FROM[sub], () => ( "up")), distance: Math.round(Math.max(scene.width, scene.height) / 3) },
|
|
3386
|
+
10: { type: "enter", style: "fade", ...base },
|
|
3387
|
+
9: { type: "enter", style: "fade", ...base },
|
|
3388
|
+
22: { type: "enter", style: "wipe", ...base, direction: _nullishCoalesce(DIRECTION_FROM[sub], () => ( "right")) },
|
|
3389
|
+
16: { type: "enter", style: "split", ...base, orientation: sub === 26 || sub === 42 ? "vertical" : "horizontal" },
|
|
3390
|
+
6: { type: "enter", style: "iris", ...base, shape: "circle" },
|
|
3391
|
+
4: { type: "enter", style: "iris", ...base, shape: "box" },
|
|
3392
|
+
53: { type: "enter", style: "zoom", ...base },
|
|
3393
|
+
23: { type: "enter", style: "zoom", ...base },
|
|
3394
|
+
31: { type: "enter", style: "pop", ...base },
|
|
3395
|
+
26: { type: "enter", style: "pop", ...base },
|
|
3396
|
+
55: { type: "enter", style: "grow", ...base },
|
|
3397
|
+
37: { type: "enter", style: "rise", ...base },
|
|
3398
|
+
42: { type: "enter", style: "rise", ...base }
|
|
3399
|
+
};
|
|
3400
|
+
if (by[id]) return by[id];
|
|
3401
|
+
ctx.notes.push(`${label} has no match here; it fades in instead.`);
|
|
3402
|
+
return { type: "enter", style: "fade", ...base };
|
|
3403
|
+
}
|
|
3404
|
+
if (cls === "exit") {
|
|
3405
|
+
const by = {
|
|
3406
|
+
1: { type: "exit", ...base, duration: 0 },
|
|
3407
|
+
10: { type: "exit", style: "fade", ...base },
|
|
3408
|
+
9: { type: "exit", style: "fade", ...base },
|
|
3409
|
+
2: { type: "exit", style: "slide", ...base, direction: _nullishCoalesce(DIRECTION_TO[sub], () => ( "down")), distance: Math.round(Math.max(scene.width, scene.height) / 3) },
|
|
3410
|
+
22: { type: "exit", style: "wipe", ...base, direction: _nullishCoalesce(DIRECTION_TO[sub], () => ( "right")) },
|
|
3411
|
+
53: { type: "exit", style: "shrink", ...base },
|
|
3412
|
+
31: { type: "exit", style: "shrink", ...base }
|
|
3413
|
+
};
|
|
3414
|
+
if (by[id]) return by[id];
|
|
3415
|
+
ctx.notes.push(`${label} has no match here; it fades out instead.`);
|
|
3416
|
+
return { type: "exit", style: "fade", ...base };
|
|
3417
|
+
}
|
|
3418
|
+
if (cls === "emph") {
|
|
3419
|
+
const rot = deep(ctn, "animRot")[0];
|
|
3420
|
+
const scale = kid(deep(ctn, "animScale")[0], "by");
|
|
3421
|
+
const clr = colour(ctx, kid(deep(ctn, "animClr")[0], "to"));
|
|
3422
|
+
switch (id) {
|
|
3423
|
+
case 26:
|
|
3424
|
+
return { type: "pulse", ...base, ...timing };
|
|
3425
|
+
case 27:
|
|
3426
|
+
return { type: "color-pulse", ...base, ...clr ? { color: clr } : {}, ...timing };
|
|
3427
|
+
case 32:
|
|
3428
|
+
return { type: "teeter", ...base, ...timing };
|
|
3429
|
+
case 34:
|
|
3430
|
+
return { type: "wave", ...base, ...timing };
|
|
3431
|
+
case 8:
|
|
3432
|
+
return { type: "rotate", ...base, by: rot ? num(rot, "by") / 6e4 : 360, ...timing };
|
|
3433
|
+
case 6:
|
|
3434
|
+
return { type: "scale", ...base, to: scale ? { x: num(scale, "x", 1e5) / 1e5, y: num(scale, "y", 1e5) / 1e5 } : 1.5, ...timing };
|
|
3435
|
+
case 9:
|
|
3436
|
+
return { type: "fade", ...base, to: 0.5, ...timing };
|
|
3437
|
+
case 1:
|
|
3438
|
+
case 19:
|
|
3439
|
+
return clr ? { type: "style", ...base, fill: clr, ...timing } : null;
|
|
3440
|
+
case 7:
|
|
3441
|
+
return clr ? { type: "style", ...base, stroke: clr, ...timing } : null;
|
|
3442
|
+
}
|
|
3443
|
+
ctx.notes.push(`${label} has no match here and was skipped.`);
|
|
3444
|
+
return null;
|
|
3445
|
+
}
|
|
3446
|
+
if (cls === "path") {
|
|
3447
|
+
const motion = deep(ctn, "animMotion")[0];
|
|
3448
|
+
const d = _optionalChain([motion, 'optionalAccess', _143 => _143.getAttribute, 'call', _144 => _144("path")]);
|
|
3449
|
+
if (!d) return null;
|
|
3450
|
+
const entry = artwork.flatMap(function all(n) {
|
|
3451
|
+
return n.type === "group" ? [n, ...n.children.flatMap(all)] : [n];
|
|
3452
|
+
}).find((n) => n.id === target);
|
|
3453
|
+
const t = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _145 => _145.transform]), () => ( [1, 0, 0, 1, 0, 0]));
|
|
3454
|
+
const p = _optionalChain([entry, 'optionalAccess', _146 => _146.type]) === "path" ? _optionalChain([entry, 'access', _147 => _147.subpaths, 'access', _148 => _148[0], 'optionalAccess', _149 => _149.anchors]) : void 0;
|
|
3455
|
+
const xs = (_nullishCoalesce(p, () => ( []))).map((a) => a.x);
|
|
3456
|
+
const ys = (_nullishCoalesce(p, () => ( []))).map((a) => a.y);
|
|
3457
|
+
const lx = xs.length ? (Math.min(...xs) + Math.max(...xs)) / 2 : 0;
|
|
3458
|
+
const ly = ys.length ? (Math.min(...ys) + Math.max(...ys)) / 2 : 0;
|
|
3459
|
+
const cx = t[0] * lx + t[2] * ly + t[4];
|
|
3460
|
+
const cy = t[1] * lx + t[3] * ly + t[5];
|
|
3461
|
+
const nums = _nullishCoalesce(d.match(/[MLCZE]|-?[\d.]+(?:e-?\d+)?/gi), () => ( []));
|
|
3462
|
+
const sp = { closed: false, anchors: [] };
|
|
3463
|
+
let i = 0;
|
|
3464
|
+
const read = () => ({ x: cx + Number(nums[i++]) * scene.width, y: cy + Number(nums[i++]) * scene.height });
|
|
3465
|
+
while (i < nums.length) {
|
|
3466
|
+
const c = nums[i++].toUpperCase();
|
|
3467
|
+
if (c === "M" || c === "L") sp.anchors.push(read());
|
|
3468
|
+
else if (c === "C") {
|
|
3469
|
+
const c1 = read();
|
|
3470
|
+
const c2 = read();
|
|
3471
|
+
const e = read();
|
|
3472
|
+
if (sp.anchors.length) sp.anchors[sp.anchors.length - 1].out = c1;
|
|
3473
|
+
sp.anchors.push({ ...e, in: c2 });
|
|
3474
|
+
} else if (c === "Z") sp.closed = true;
|
|
3475
|
+
}
|
|
3476
|
+
if (sp.anchors.length < 2) return null;
|
|
3477
|
+
const pathId = `${target}-path-${hidden.length + 1}`;
|
|
3478
|
+
hidden.push({ id: pathId, type: "path", name: "Motion path", visible: false, fill: null, stroke: "#94a3b8", subpaths: [sp] });
|
|
3479
|
+
return { type: "follow", ...base, path: pathId, ...timing };
|
|
3480
|
+
}
|
|
3481
|
+
return null;
|
|
3482
|
+
}
|
|
3483
|
+
async function fromPptxAnimation(data, options = {}) {
|
|
3484
|
+
const Parser = _nullishCoalesce(options.DOMParser, () => ( globalThis.DOMParser));
|
|
3485
|
+
if (!Parser) throw new Error("No DOMParser: pass one in options (jsdom's or xmldom's in Node).");
|
|
3486
|
+
let zip;
|
|
3487
|
+
try {
|
|
3488
|
+
zip = await _chunkEMQWJA3Gcjs.readZip.call(void 0, data, options);
|
|
3489
|
+
} catch (error) {
|
|
3490
|
+
throw new Error(`This is not a PowerPoint file (.pptx): ${error.message}`);
|
|
3491
|
+
}
|
|
3492
|
+
const ctx = { zip, Parser, notes: [], theme: /* @__PURE__ */ new Map(), nodes: /* @__PURE__ */ new Map(), used: /* @__PURE__ */ new Set() };
|
|
3493
|
+
const pres = await xml(ctx, "ppt/presentation.xml");
|
|
3494
|
+
if (!pres) throw new Error("This is not a PowerPoint file (.pptx): it has no ppt/presentation.xml.");
|
|
3495
|
+
const presRels = await rels(ctx, "ppt/presentation.xml");
|
|
3496
|
+
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);
|
|
3497
|
+
const n = _nullishCoalesce(options.slide, () => ( 1));
|
|
3498
|
+
if (!(Number.isInteger(n) && n >= 1 && n <= slidePaths.length)) throw new Error(`There is no slide ${n}; the file has ${slidePaths.length} slide${slidePaths.length === 1 ? "" : "s"}.`);
|
|
3499
|
+
const size = deep(pres, "sldSz")[0];
|
|
3500
|
+
const width = Math.round(num(size, "cx", 12192e3) / EMU);
|
|
3501
|
+
const height = Math.round(num(size, "cy", 6858e3) / EMU);
|
|
3502
|
+
for (const [, path] of presRels) {
|
|
3503
|
+
if (!path.includes("theme/")) continue;
|
|
3504
|
+
const theme = await xml(ctx, path);
|
|
3505
|
+
const scheme = deep(theme, "clrScheme")[0];
|
|
3506
|
+
for (const c of Array.from(_nullishCoalesce(_optionalChain([scheme, 'optionalAccess', _150 => _150.children]), () => ( [])))) {
|
|
3507
|
+
const v = c.firstElementChild;
|
|
3508
|
+
const hex = _optionalChain([v, 'optionalAccess', _151 => _151.localName]) === "srgbClr" ? v.getAttribute("val") : _optionalChain([v, 'optionalAccess', _152 => _152.getAttribute, 'call', _153 => _153("lastClr")]);
|
|
3509
|
+
if (hex) ctx.theme.set(c.localName, `#${hex.toLowerCase()}`);
|
|
3510
|
+
}
|
|
3511
|
+
break;
|
|
3512
|
+
}
|
|
3513
|
+
const slide = await xml(ctx, slidePaths[n - 1]);
|
|
3514
|
+
if (!slide) throw new Error(`Slide ${n} cannot be read.`);
|
|
3515
|
+
const tree = deep(slide, "spTree")[0];
|
|
3516
|
+
const toPx = (x, y, w, h) => [x / EMU, y / EMU, w / EMU, h / EMU];
|
|
3517
|
+
const nodes = tree ? shapes(ctx, tree, toPx) : [];
|
|
3518
|
+
const bg = _nullishCoalesce(colour(ctx, _nullishCoalesce(deep(deep(slide, "bg")[0], "solidFill")[0], () => ( null))), () => ( "#ffffff"));
|
|
3519
|
+
const hidden = [];
|
|
3520
|
+
const shots = [];
|
|
3521
|
+
const effects = deep(deep(slide, "timing")[0], "cTn").filter((c) => c.hasAttribute("presetClass"));
|
|
3522
|
+
for (const ctn of effects) {
|
|
3523
|
+
const spid = num(deep(ctn, "spTgt")[0], "spid", -1);
|
|
3524
|
+
const target = ctx.nodes.get(spid);
|
|
3525
|
+
if (!target) {
|
|
3526
|
+
ctx.notes.push(`An effect targets shape ${spid}, which was not imported; it was skipped.`);
|
|
3527
|
+
continue;
|
|
3528
|
+
}
|
|
3529
|
+
if (deep(ctn, "txEl").length) ctx.notes.push(`An effect on "${target}" animates part of its text, which was not imported; it animates the whole shape.`);
|
|
3530
|
+
const cmd = command(ctx, ctn, { width, height }, nodes, target, hidden);
|
|
3531
|
+
if (!cmd) continue;
|
|
3532
|
+
const kind = ctn.getAttribute("nodeType");
|
|
3533
|
+
const delay = num(kid(kid(ctn, "stCondLst"), "cond"), "delay", 0);
|
|
3534
|
+
if (kind === "clickEffect" || !shots.length) shots.push({ id: `click-${shots.length + 1}`, run: [] });
|
|
3535
|
+
const run = shots[shots.length - 1].run;
|
|
3536
|
+
const placed = { ...cmd, ...delay > 0 ? { delay } : {}, ...kind === "withEffect" && run.length ? { with: "previous" } : {} };
|
|
3537
|
+
run.push(placed);
|
|
3538
|
+
}
|
|
3539
|
+
if (effects.length && !shots.length) ctx.notes.push("The slide's effects could not be read.");
|
|
3540
|
+
const artwork = { width, height, background: bg, nodes: [...nodes, ...hidden] };
|
|
3541
|
+
const scene = { version: 1, name: `slide-${n}`, artwork, shots, ...shots.length > 1 ? { trigger: "click" } : {} };
|
|
3542
|
+
const problems = motionSceneShapeProblems(scene);
|
|
3543
|
+
if (problems.length) throw new Error(`The imported scene is not well formed:
|
|
3544
|
+
${problems.join("\n")}`);
|
|
3545
|
+
return { scene, notes: [...new Set(ctx.notes)], issues: checkMotionScene(scene), slides: slidePaths.length };
|
|
3546
|
+
}
|
|
3547
|
+
|
|
3072
3548
|
// src/animation-editor/controller.ts
|
|
3073
3549
|
var BLANK = { width: 800, height: 450, background: "#ffffff", nodes: [] };
|
|
3074
3550
|
var AnimationEditorController = (_class = class {
|
|
@@ -3136,7 +3612,7 @@ var AnimationEditorController = (_class = class {
|
|
|
3136
3612
|
time: p.time,
|
|
3137
3613
|
playing: p.playing,
|
|
3138
3614
|
loop: p.loop,
|
|
3139
|
-
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call',
|
|
3615
|
+
currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _154 => _154(timeline, p.time), 'optionalAccess', _155 => _155.id]), () => ( null)),
|
|
3140
3616
|
selection: this.selection,
|
|
3141
3617
|
readOnly: this.readOnly,
|
|
3142
3618
|
error: this.error,
|
|
@@ -3175,7 +3651,7 @@ var AnimationEditorController = (_class = class {
|
|
|
3175
3651
|
this.applying = false;
|
|
3176
3652
|
}
|
|
3177
3653
|
this.notify();
|
|
3178
|
-
_optionalChain([this, 'access',
|
|
3654
|
+
_optionalChain([this, 'access', _156 => _156.onChange, 'optionalCall', _157 => _157(scene)]);
|
|
3179
3655
|
}
|
|
3180
3656
|
commit(label, next) {
|
|
3181
3657
|
const before = this.scene;
|
|
@@ -3184,14 +3660,14 @@ var AnimationEditorController = (_class = class {
|
|
|
3184
3660
|
this.notify();
|
|
3185
3661
|
return;
|
|
3186
3662
|
}
|
|
3187
|
-
const
|
|
3663
|
+
const command3 = {
|
|
3188
3664
|
name: label,
|
|
3189
3665
|
tag: "animation-editor",
|
|
3190
3666
|
execute: () => this.setScene(next),
|
|
3191
3667
|
undo: () => this.setScene(before),
|
|
3192
3668
|
redo: () => this.setScene(next)
|
|
3193
3669
|
};
|
|
3194
|
-
this.history.execute(
|
|
3670
|
+
this.history.execute(command3);
|
|
3195
3671
|
}
|
|
3196
3672
|
refuse(message) {
|
|
3197
3673
|
this.error = message;
|
|
@@ -3348,6 +3824,8 @@ var BASE = {
|
|
|
3348
3824
|
with: { type: "string", enum: ["after", "previous"], description: '"after" (default) starts when the commands before it finish; "previous" starts together with the command before.' },
|
|
3349
3825
|
ease: EASE,
|
|
3350
3826
|
note: { type: "string", description: "Why this command is here, in a few words." },
|
|
3827
|
+
split: { type: "string", enum: ["letter", "word", "line"], description: "For outlined text (a group of letter paths): animate it a letter, word or line at a time in reading order, staggered (default 40 ms a letter, 120 a word, 300 a line). get_text_layout shows the units." },
|
|
3828
|
+
cascade: { type: "string", enum: ["forward", "backward", "center", "edges", "random"], description: "With split: the order units go in (default forward; random is the same every time)." },
|
|
3351
3829
|
repeat: { type: "integer", minimum: 1, maximum: 1e3, description: 'Play it this many times (default 1); "duration" is one cycle. Not for enter or exit.' },
|
|
3352
3830
|
repeatMode: { type: "string", enum: [...MOTION_REPEAT_MODES], description: "loop (default) restarts each cycle, mirror plays every other one backwards, offset carries on from where the last ended (rotate by 90 with repeat 4 makes a full turn)." },
|
|
3353
3831
|
steps: { type: "number", exclusiveMinimum: 0, maximum: 120, description: `Stepped time: hold on a grid of this many frames per second (12 = "on twos"). Default: the scene's steps, else smooth.` }
|
|
@@ -3364,11 +3842,11 @@ var DRAW_ORDER = {
|
|
|
3364
3842
|
sortBy: { type: "string", enum: ["document", "distance"], description: "With sequence: stacking order (default) or distance from origin (a radial reveal)." },
|
|
3365
3843
|
origin: object({ x: { type: "number", description: "Document units." }, y: { type: "number", description: "Document units." } }, ["x", "y"], "With sortBy distance: where strokes are drawn out from (default the target's centre).")
|
|
3366
3844
|
};
|
|
3367
|
-
var
|
|
3845
|
+
var command2 = (type, description, extra = {}, required = []) => object({ type: { const: type, description }, ...BASE, ...extra }, ["type", "targets", ...required], description);
|
|
3368
3846
|
var MOTION_COMMAND_SCHEMA = {
|
|
3369
3847
|
description: `A command (one of ${MOTION_COMMAND_TYPES.join(", ")}). Commands in a shot play one after another unless "with": "previous".`,
|
|
3370
3848
|
oneOf: [
|
|
3371
|
-
|
|
3849
|
+
command2("enter", "Brings hidden targets in; they are hidden before this shot.", {
|
|
3372
3850
|
...DRAW_ORDER,
|
|
3373
3851
|
style: {
|
|
3374
3852
|
type: "string",
|
|
@@ -3381,18 +3859,18 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
3381
3859
|
shape: { type: "string", enum: [...MOTION_IRIS_SHAPES], description: "For iris: open through a circle (default; an ellipse on a box that is not square) or a box." },
|
|
3382
3860
|
orientation: { type: "string", enum: [...MOTION_SPLIT_ORIENTATIONS], description: "For split: horizontal (default) opens up and down from a horizontal line through the middle; vertical opens left and right." }
|
|
3383
3861
|
}),
|
|
3384
|
-
|
|
3862
|
+
command2("exit", "Takes targets out.", {
|
|
3385
3863
|
...DRAW_ORDER,
|
|
3386
3864
|
style: { type: "string", enum: [...MOTION_EXIT_STYLES], description: "fade (default), shrink, slide, undraw, or wipe (hides behind a travelling edge through a clip over the target's box: a wipe in, reversed)." },
|
|
3387
3865
|
direction: { type: "string", enum: [...MOTION_DIRECTIONS], description: "For slide: direction of travel (default down). For wipe: the way the edge travels (default right, hiding from the left)." },
|
|
3388
3866
|
distance: { type: "number", description: "For slide: document units (default 40)." }
|
|
3389
3867
|
}),
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3868
|
+
command2("draw", "Draws strokes on (or off) to a fraction of their length.", { ...DRAW_ORDER, comet: FRACTION("A travelling stroke this fraction of the length long: it runs along the path and off the end (leave out from and to)."), to: FRACTION("Fraction drawn at the end (default 1)."), from: FRACTION("Fraction drawn at the start (default: what is drawn now).") }),
|
|
3869
|
+
command2("move", "Moves targets by an offset or so their centre lands on a point.", { via: { type: "array", items: POINT("A point the centre passes through."), minItems: 1, maxItems: 64, description: 'Waypoints (document units) the centre passes through on the way to "to" or "by", smoothly (velocity carries through each) and without overshooting any. Default length 700 ms + 400 per waypoint.' }, pacing: { type: "string", enum: ["even", "equal"], description: "With via: even (default) keeps the speed steady along the path; equal gives each stretch the same time." }, blend: BLEND("replace"), by: POINT("Offset in document units."), to: POINT("Point (document coordinates) for the centre.") }),
|
|
3870
|
+
command2("rotate", "Turns targets about their centre (degrees, clockwise).", { blend: BLEND("replace"), by: { type: "number", description: "Degrees to turn by." }, to: { type: "number", description: "Angle to turn to, in degrees from rest." } }),
|
|
3871
|
+
command2("scale", "Scales targets about their centre (1 = rest size).", { blend: BLEND("replace"), to: { description: "A factor, or { x, y } factors.", anyOf: [{ type: "number" }, POINT("Factors per axis.")] }, geometric: { type: "boolean", description: "Grow by a steady factor, which reads as an even zoom (default false)." } }, ["to"]),
|
|
3872
|
+
command2("fade", "Changes opacity.", { to: FRACTION("Opacity at the end (0\u20131).") }, ["to"]),
|
|
3873
|
+
command2("style", "Blends solid fill / stroke colours (in OKLab) and stroke width. On a group it changes every path in it.", {
|
|
3396
3874
|
fill: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
|
|
3397
3875
|
stroke: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
|
|
3398
3876
|
strokeWidth: { type: "number", minimum: 0, description: "Document units." }
|
|
@@ -3411,24 +3889,24 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
3411
3889
|
["type", "targets", "clip"],
|
|
3412
3890
|
"Plays a clip on the targets."
|
|
3413
3891
|
),
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3892
|
+
command2("match", `Smart Animate: tweens a group into another group (usually hidden), part by part. Parts pair by name, then by id with the group ids taken out (card-a-title \u2194 card-b-title), then by kind in order; each takes its partner's shape, paint and place. Unpaired parts fade out; parts of "into" with no partner do not appear (check_animation lists them).`, { into: { type: "string", minLength: 1, description: "Id of the group to become." } }, ["into"]),
|
|
3893
|
+
command2("morph", "Morphs each target into the shape (and paint) of another node, which usually stays hidden.", { into: { type: "string", minLength: 1, description: "Id of the node whose shape to take." } }, ["into"]),
|
|
3894
|
+
command2("follow", "Moves targets along a path node, centre on the path.", {
|
|
3417
3895
|
path: { type: "string", minLength: 1, description: "Id of a path node (it can be hidden)." },
|
|
3418
3896
|
rotate: { type: "boolean", description: "Turn with the path (default false); moves and shakes made meanwhile turn with it too." },
|
|
3419
3897
|
from: FRACTION("Where to start along the path (default 0)."),
|
|
3420
3898
|
to: FRACTION("Where to end along the path (default 1).")
|
|
3421
3899
|
}, ["path"]),
|
|
3422
|
-
|
|
3423
|
-
|
|
3900
|
+
command2("pulse", "Scales up and back to draw the eye.", { blend: BLEND("add"), amount: { type: "number", description: "Extra scale at the peak (default 0.15)." }, count: { type: "integer", minimum: 1, description: "Pulses (default 1)." } }),
|
|
3901
|
+
command2("shake", "Shakes side to side (or up and down), settling.", {
|
|
3424
3902
|
blend: BLEND("add"),
|
|
3425
3903
|
amount: { type: "number", description: "Document units (default 8)." },
|
|
3426
3904
|
count: { type: "integer", minimum: 1, description: "Shakes (default 3)." },
|
|
3427
3905
|
axis: { type: "string", enum: ["horizontal", "vertical"], description: "Default horizontal." }
|
|
3428
3906
|
}),
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3907
|
+
command2("teeter", "Rocks about the centre either way, settling.", { blend: BLEND("add"), angle: { type: "number", description: "Degrees either way (default 8)." }, count: { type: "integer", minimum: 1, description: "Rocks (default 3)." } }),
|
|
3908
|
+
command2("wave", "Bobs up and down without settling, like something floating (default 1000 ms).", { blend: BLEND("add"), amount: { type: "number", description: "Height in document units (default 6)." }, count: { type: "integer", minimum: 1, description: "Bobs (default 2)." } }),
|
|
3909
|
+
command2("wiggle", "Wanders about its place as smooth seeded noise, easing out of and back to rest (default 1500 ms). The same seed always wanders the same way.", {
|
|
3432
3910
|
blend: BLEND("add"),
|
|
3433
3911
|
amount: { type: "number", description: "Up to about this far, in document units (default 6)." },
|
|
3434
3912
|
frequency: { type: "number", exclusiveMinimum: 0, description: "Wanders per second, in Hz (default 3)." },
|
|
@@ -3436,12 +3914,12 @@ var MOTION_COMMAND_SCHEMA = {
|
|
|
3436
3914
|
rotate: { type: "number", description: "Also turns about the centre by up to about this many degrees (default 0)." },
|
|
3437
3915
|
seed: { type: "integer", minimum: 0, description: "Default: one picked from the target id, so each target wanders its own way." }
|
|
3438
3916
|
}),
|
|
3439
|
-
|
|
3917
|
+
command2("color-pulse", "Tints solid paint toward a colour and back (mixed in OKLab). On a group it tints every path in it.", {
|
|
3440
3918
|
color: { type: "string", description: 'The tint, a CSS colour (default "#f59e0b").' },
|
|
3441
3919
|
paint: { type: "string", enum: ["fill", "stroke"], description: "Which paint (default fill)." },
|
|
3442
3920
|
count: { type: "integer", minimum: 1, description: "Pulses (default 1)." }
|
|
3443
3921
|
}),
|
|
3444
|
-
|
|
3922
|
+
command2("effect", "Tweens a numeric parameter of a live path effect on the targets (twist angle, wiggle time, zig zag size, trim offset\u2026).", {
|
|
3445
3923
|
effect: { type: "string", minLength: 1, description: `Effect id from get_animation's element "effects".` },
|
|
3446
3924
|
param: { type: "string", minLength: 1, description: "A numeric parameter of that effect (listed with it)." },
|
|
3447
3925
|
to: { type: "number", description: "Value at the end." }
|
|
@@ -3740,9 +4218,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3740
4218
|
handler: ({ from = 0, to, limit = 200 }) => {
|
|
3741
4219
|
const s = scene();
|
|
3742
4220
|
const timeline = compileMotionScene(s);
|
|
3743
|
-
const words = _nullishCoalesce(_optionalChain([s, 'access',
|
|
4221
|
+
const words = _nullishCoalesce(_optionalChain([s, 'access', _158 => _158.narration, 'optionalAccess', _159 => _159.words]), () => ( []));
|
|
3744
4222
|
const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
|
|
3745
|
-
const shotAt = (ms) => _optionalChain([timeline, 'access',
|
|
4223
|
+
const shotAt = (ms) => _optionalChain([timeline, 'access', _160 => _160.shots, 'access', _161 => _161.find, 'call', _162 => _162((x) => ms >= x.start && ms < x.end), 'optionalAccess', _163 => _163.id]);
|
|
3746
4224
|
const beats = [];
|
|
3747
4225
|
if (s.beat && s.beat.bpm > 0) {
|
|
3748
4226
|
const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
|
|
@@ -3763,6 +4241,21 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3763
4241
|
};
|
|
3764
4242
|
}
|
|
3765
4243
|
};
|
|
4244
|
+
const getTextLayout = {
|
|
4245
|
+
name: "get_text_layout",
|
|
4246
|
+
title: "Read outlined text as letters, words and lines",
|
|
4247
|
+
description: 'Returns how a group of letter paths (text converted to outlines) reads: its lines, each a list of words, each a list of letter ids, in reading order \u2014 the units a command with "split": "letter" | "word" | "line" animates. Errors if the element is not a group with paths.',
|
|
4248
|
+
inputSchema: object({ group: { type: "string", minLength: 1, description: "Element id of the group of letters." } }, ["group"]),
|
|
4249
|
+
annotations: { title: "Read outlined text as letters, words and lines", ...READ },
|
|
4250
|
+
handler: ({ group }) => {
|
|
4251
|
+
const s = scene();
|
|
4252
|
+
const nodes = indexMotionNodes(s.artwork.nodes);
|
|
4253
|
+
if (!nodes.has(group)) throw new Error(`There is no element ${namedWithSuggestion(group, [...nodes.keys()])}.`);
|
|
4254
|
+
const layout = motionTextLayout(nodes, group);
|
|
4255
|
+
if (!layout) throw new Error(`"${group}" is not a group of paths; convert the text to outlines (one path a letter) and group it.`);
|
|
4256
|
+
return { group, letters: layout.lines.reduce((n, l) => n + l.words.reduce((m, w) => m + w.letters.length, 0), 0), ...layout };
|
|
4257
|
+
}
|
|
4258
|
+
};
|
|
3766
4259
|
const getMotionPath = {
|
|
3767
4260
|
name: "get_motion_path",
|
|
3768
4261
|
title: "Read where a node travels",
|
|
@@ -3828,13 +4321,40 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3828
4321
|
handler: ({ svg }) => {
|
|
3829
4322
|
let artwork;
|
|
3830
4323
|
try {
|
|
3831
|
-
artwork =
|
|
4324
|
+
artwork = _chunk7MD7C6XQcjs.parseVectorSvg.call(void 0, svg);
|
|
3832
4325
|
} catch (error) {
|
|
3833
4326
|
throw new Error(`The SVG could not be read: ${error.message}. Nothing was changed.`);
|
|
3834
4327
|
}
|
|
3835
4328
|
return apply({ op: "set_artwork", artwork }, "Replace artwork", (s) => ({ elements: describeMotionElements(s) }));
|
|
3836
4329
|
}
|
|
3837
4330
|
};
|
|
4331
|
+
const importPptx = {
|
|
4332
|
+
name: "import_pptx_animation",
|
|
4333
|
+
title: "Import a PowerPoint slide's animation",
|
|
4334
|
+
description: "Replaces the whole animation with a PowerPoint slide (one undo step): its shapes become the artwork and its animation pane becomes shots, a shot per click (with previous / after previous, delays, repeats and acceleration kept; the scene plays on click). Text, pictures and charts are left out and effects with no match fade, with notes. Returns the shots, notes and issues. With dry_run it only reports them.",
|
|
4335
|
+
inputSchema: object(
|
|
4336
|
+
{
|
|
4337
|
+
data: { type: "string", minLength: 1, description: "The .pptx file, base64-encoded." },
|
|
4338
|
+
slide: { type: "integer", minimum: 1, description: "Which slide (1 = first, default 1)." },
|
|
4339
|
+
dry_run: { type: "boolean", description: "Report without replacing anything (default false)." }
|
|
4340
|
+
},
|
|
4341
|
+
["data"]
|
|
4342
|
+
),
|
|
4343
|
+
annotations: { title: "Import a PowerPoint slide's animation", ...DESTRUCTIVE },
|
|
4344
|
+
handler: async ({ data, slide, dry_run = false }) => {
|
|
4345
|
+
let result;
|
|
4346
|
+
try {
|
|
4347
|
+
const bytes = Uint8Array.from(atob(data.replace(/\s+/g, "")), (c) => c.charCodeAt(0));
|
|
4348
|
+
result = await fromPptxAnimation(bytes, slide ? { slide } : {});
|
|
4349
|
+
} catch (error) {
|
|
4350
|
+
throw new Error(`The slide could not be imported: ${error.message} Nothing was changed.`);
|
|
4351
|
+
}
|
|
4352
|
+
const report = { slides: result.slides, notes: result.notes, issues: issueSummary(result.issues), shots: describeMotionShots(result.scene).map(({ id, start, end, commands }) => ({ id, start, end, commands: commands.length })) };
|
|
4353
|
+
if (dry_run) return { dry_run: true, ...report, hint: "Nothing was replaced; call again without dry_run to import." };
|
|
4354
|
+
const applied = controller.apply({ op: "replace_scene", scene: result.scene }, "Import PowerPoint slide");
|
|
4355
|
+
return outcome(applied, applied.ok ? { ...report, elements: describeMotionElements(result.scene) } : {});
|
|
4356
|
+
}
|
|
4357
|
+
};
|
|
3838
4358
|
const importFlairEffect = {
|
|
3839
4359
|
name: "import_flair_effect",
|
|
3840
4360
|
title: "Import a Flair effect",
|
|
@@ -4022,7 +4542,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4022
4542
|
inputSchema: object({ shot: SHOT_ID, commands: { type: "array", items: MOTION_COMMAND_SCHEMA, minItems: 1, description: "Commands to add." }, at: { type: "integer", minimum: 0, description: "Index in the run (default: the end)." } }, ["shot", "commands"]),
|
|
4023
4543
|
annotations: { title: "Add commands to a shot", ...WRITE },
|
|
4024
4544
|
handler: ({ shot, commands, at }) => {
|
|
4025
|
-
const before = _nullishCoalesce(_optionalChain([scene, 'call',
|
|
4545
|
+
const before = _nullishCoalesce(_optionalChain([scene, 'call', _164 => _164(), 'access', _165 => _165.shots, 'access', _166 => _166.find, 'call', _167 => _167((s) => s.id === shot), 'optionalAccess', _168 => _168.run, 'access', _169 => _169.length]), () => ( 0));
|
|
4026
4546
|
const first = _nullishCoalesce(at, () => ( before));
|
|
4027
4547
|
return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
|
|
4028
4548
|
const shots = describeMotionShots(s);
|
|
@@ -4045,7 +4565,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4045
4565
|
["shot", "command"]
|
|
4046
4566
|
),
|
|
4047
4567
|
annotations: { title: "Change a command", ...WRITE_IDEMPOTENT },
|
|
4048
|
-
handler: ({ shot, command:
|
|
4568
|
+
handler: ({ shot, command: command3, set, remove }) => apply({ op: "update_command", shot, command: command3, set, remove }, "Change command", (s) => ({ command: describeMotionShots(s).find((x) => x.id === shot).commands[command3] }))
|
|
4049
4569
|
};
|
|
4050
4570
|
const deleteCommands = {
|
|
4051
4571
|
name: "delete_commands",
|
|
@@ -4068,7 +4588,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4068
4588
|
["shot", "command", "to"]
|
|
4069
4589
|
),
|
|
4070
4590
|
annotations: { title: "Reorder a command", ...WRITE },
|
|
4071
|
-
handler: ({ shot, command:
|
|
4591
|
+
handler: ({ shot, command: command3, to }) => apply({ op: "move_command", shot, command: command3, to }, "Move command", (s) => ({ shot, command: to, from: command3, commands: describeMotionShots(s).find((x) => x.id === shot).commands.map((c) => ({ index: c.index, type: c.type, start: c.start, end: c.end })) }))
|
|
4072
4592
|
};
|
|
4073
4593
|
const setSettings = {
|
|
4074
4594
|
name: "set_animation_settings",
|
|
@@ -4153,8 +4673,8 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4153
4673
|
return { redone, ...redone ? { label } : {} };
|
|
4154
4674
|
}
|
|
4155
4675
|
};
|
|
4156
|
-
const reads = [getAnimation, getShot, findElements, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
|
|
4157
|
-
const writes = [setArtworkSvg, setDrivers, setClip, copyAnimation, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
|
|
4676
|
+
const reads = [getAnimation, getShot, findElements, getTextLayout, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
|
|
4677
|
+
const writes = [setArtworkSvg, importPptx, setDrivers, setClip, copyAnimation, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
|
|
4158
4678
|
return {
|
|
4159
4679
|
id: _nullishCoalesce(options.id, () => ( "animation")),
|
|
4160
4680
|
namespace: options.namespace,
|
|
@@ -4186,6 +4706,7 @@ Commands
|
|
|
4186
4706
|
- enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.
|
|
4187
4707
|
- enter also reveals through a clip over the target's box: wipe (behind an edge travelling "direction", default right), iris (from the centre; "shape": circle or box) and split (from a line through the middle; "orientation": horizontal or vertical). exit wipe hides the same way. Reveals need a width and a height: use draw / undraw for a straight line.
|
|
4188
4708
|
- draw draws strokes on to a fraction; move, rotate, scale and fade change the pose (about the centre); style blends solid colours and stroke width.
|
|
4709
|
+
- Text: convert it to outlines (a group with a path per letter) and give a command "split": "letter", "word" or "line" (and "cascade") to animate it a unit at a time; get_text_layout shows the units.
|
|
4189
4710
|
- Drawing a group of strokes: "order": "sequence" draws them one after another (a signature, a diagram), "sortBy": "distance" from "origin" reveals outward, "pace": "speed" keeps one speed; draw with "comet": 0.2 sends a short stroke along a path and off the end.
|
|
4190
4711
|
- Fast motion reads better with blur: set_animation_settings { "motionBlur": { "shutter": 180 } } (stage and rendered frames only).
|
|
4191
4712
|
- Tie properties together with set_animation_drivers: parallax layers, a wheel that turns as it rolls, a shadow that fades as something rises. Drivers add to the target's own commands.
|
|
@@ -4203,7 +4724,7 @@ Commands
|
|
|
4203
4724
|
- effect tweens a numeric parameter of a live path effect already on the node (twist angle, wiggle time, zig zag size).
|
|
4204
4725
|
|
|
4205
4726
|
Working method
|
|
4206
|
-
1. get_animation to learn the element ids (set_animation_artwork_svg first if there is no artwork: give every element you will animate an id; or import_flair_effect to start from a Flair effect
|
|
4727
|
+
1. get_animation to learn the element ids (set_animation_artwork_svg first if there is no artwork: give every element you will animate an id; or import_flair_effect / import_pptx_animation to start from a Flair effect or a PowerPoint slide).
|
|
4207
4728
|
2. Plan a few shots, each one idea. Add them with insert_shots (add_commands, update_command, move_command and delete_commands refine a shot), or edit_animation to make several edits as one step (dry_run first when unsure).
|
|
4208
4729
|
- In edit_animation, a later op can use what an earlier one made: "$0.indexes[0]" (the first command op 1 added), "$last.shot".
|
|
4209
4730
|
3. To hit a length, fit_animation (keep the shots whose pace matters). check_animation and fix every error and warning; render_animation_frame (shot + "end") to look at the result, or with "times" for a contact sheet of several moments; add onion_skin or motion_paths to see the motion in one picture, or get_motion_path for the numbers.
|
|
@@ -4217,7 +4738,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
|
|
|
4217
4738
|
var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
|
|
4218
4739
|
var NODES = /* @__PURE__ */ new Set(["into", "path"]);
|
|
4219
4740
|
function branch(type) {
|
|
4220
|
-
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access',
|
|
4741
|
+
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _170 => _170.properties, 'optionalAccess', _171 => _171.type, 'optionalAccess', _172 => _172.const]) === type);
|
|
4221
4742
|
}
|
|
4222
4743
|
function unitOf(type, name) {
|
|
4223
4744
|
if (name === "duration" || name === "delay" || name === "stagger") return "ms";
|
|
@@ -4252,7 +4773,7 @@ function kindOf(name, schema) {
|
|
|
4252
4773
|
}
|
|
4253
4774
|
function motionCommandFields(type) {
|
|
4254
4775
|
const schema = branch(type);
|
|
4255
|
-
if (!_optionalChain([schema, 'optionalAccess',
|
|
4776
|
+
if (!_optionalChain([schema, 'optionalAccess', _173 => _173.properties])) return [];
|
|
4256
4777
|
const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
|
|
4257
4778
|
const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
|
|
4258
4779
|
const kind = kindOf(name, s);
|
|
@@ -4299,17 +4820,17 @@ function parseMotionFieldInput(field, raw) {
|
|
|
4299
4820
|
if (field.kind === "enum" && field.options && !field.options.includes(text)) return { error: `${field.label} must be one of ${field.options.join(", ")}.` };
|
|
4300
4821
|
return { set: text };
|
|
4301
4822
|
}
|
|
4302
|
-
function motionFieldEdit(shot,
|
|
4823
|
+
function motionFieldEdit(shot, command3, field, raw) {
|
|
4303
4824
|
const input = parseMotionFieldInput(field, raw);
|
|
4304
4825
|
if ("error" in input) return input;
|
|
4305
|
-
if ("remove" in input) return { op: "update_command", shot, command:
|
|
4306
|
-
return { op: "update_command", shot, command:
|
|
4826
|
+
if ("remove" in input) return { op: "update_command", shot, command: command3, remove: [field.name] };
|
|
4827
|
+
return { op: "update_command", shot, command: command3, set: { [field.name]: input.set } };
|
|
4307
4828
|
}
|
|
4308
4829
|
function defaultMotionCommand(type, targets, scene) {
|
|
4309
4830
|
if (type === "wait") return { type: "wait", duration: 500 };
|
|
4310
4831
|
if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
|
|
4311
4832
|
const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
|
|
4312
|
-
const other = (pred) => _optionalChain([nodes, 'access',
|
|
4833
|
+
const other = (pred) => _optionalChain([nodes, 'access', _174 => _174.find, 'call', _175 => _175((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _176 => _176.node, 'access', _177 => _177.id]);
|
|
4313
4834
|
const base = { targets: [...targets] };
|
|
4314
4835
|
switch (type) {
|
|
4315
4836
|
case "scale":
|
|
@@ -4340,8 +4861,8 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
4340
4861
|
}
|
|
4341
4862
|
case "effect": {
|
|
4342
4863
|
for (const id of targets) {
|
|
4343
|
-
const node = _optionalChain([nodes, 'access',
|
|
4344
|
-
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess',
|
|
4864
|
+
const node = _optionalChain([nodes, 'access', _178 => _178.find, 'call', _179 => _179((e) => e.node.id === id), 'optionalAccess', _180 => _180.node]);
|
|
4865
|
+
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _181 => _181.effects]), () => ( []))) {
|
|
4345
4866
|
const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
|
|
4346
4867
|
if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
|
|
4347
4868
|
}
|
|
@@ -4352,26 +4873,26 @@ function defaultMotionCommand(type, targets, scene) {
|
|
|
4352
4873
|
return { type, ...base };
|
|
4353
4874
|
}
|
|
4354
4875
|
}
|
|
4355
|
-
function motionCommandSummary(
|
|
4356
|
-
const c =
|
|
4357
|
-
const what = [
|
|
4358
|
-
if (
|
|
4876
|
+
function motionCommandSummary(command3) {
|
|
4877
|
+
const c = command3;
|
|
4878
|
+
const what = [command3.type, typeof c.style === "string" ? c.style : ""].filter(Boolean).join(" ");
|
|
4879
|
+
if (command3.type === "wait") return `wait ${command3.duration} ms`;
|
|
4359
4880
|
const extra = typeof c.into === "string" ? ` \u2192 ${c.into}` : typeof c.path === "string" ? ` along ${c.path}` : "";
|
|
4360
|
-
return `${what} \xB7 ${(_nullishCoalesce(
|
|
4881
|
+
return `${what} \xB7 ${(_nullishCoalesce(command3.targets, () => ( []))).join(", ")}${extra}`;
|
|
4361
4882
|
}
|
|
4362
4883
|
function motionCommandRows(scene, shotId) {
|
|
4363
4884
|
const index = scene.shots.findIndex((s) => s.id === shotId);
|
|
4364
4885
|
if (index < 0) return [];
|
|
4365
4886
|
const timeline = compileMotionScene(scene);
|
|
4366
|
-
return scene.shots[index].run.map((
|
|
4887
|
+
return scene.shots[index].run.map((command3, i) => {
|
|
4367
4888
|
const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
|
|
4368
|
-
const primitive = motionFlairPrimitive(
|
|
4369
|
-
return { index: i, command:
|
|
4889
|
+
const primitive = motionFlairPrimitive(command3);
|
|
4890
|
+
return { index: i, command: command3, summary: motionCommandSummary(command3), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _182 => _182.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _183 => _183.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
|
|
4370
4891
|
});
|
|
4371
4892
|
}
|
|
4372
|
-
function duplicateMotionCommandEdit(scene, shot,
|
|
4373
|
-
const run = _nullishCoalesce(_optionalChain([scene, 'access',
|
|
4374
|
-
return { op: "add_commands", shot, commands: run[
|
|
4893
|
+
function duplicateMotionCommandEdit(scene, shot, command3) {
|
|
4894
|
+
const run = _nullishCoalesce(_optionalChain([scene, 'access', _184 => _184.shots, 'access', _185 => _185.find, 'call', _186 => _186((s) => s.id === shot), 'optionalAccess', _187 => _187.run]), () => ( []));
|
|
4895
|
+
return { op: "add_commands", shot, commands: run[command3] ? [structuredClone(run[command3])] : [], at: command3 + 1 };
|
|
4375
4896
|
}
|
|
4376
4897
|
var MOTION_EASE_CHOICES = [
|
|
4377
4898
|
{ value: "", label: "Default" },
|
|
@@ -4455,7 +4976,7 @@ function motionCueFromKey(key) {
|
|
|
4455
4976
|
function motionCueChoices(scene, limit = 256) {
|
|
4456
4977
|
const choices = [];
|
|
4457
4978
|
const s = (ms) => `${(ms / 1e3).toFixed(2)} s`;
|
|
4458
|
-
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access',
|
|
4979
|
+
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _188 => _188.narration, 'optionalAccess', _189 => _189.words, 'access', _190 => _190.map, 'call', _191 => _191((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
|
|
4459
4980
|
if (scene.beat && scene.beat.bpm > 0) {
|
|
4460
4981
|
for (let beat = 0; choices.length < limit; beat++) {
|
|
4461
4982
|
const time = motionBeatTime(scene.beat, beat);
|
|
@@ -4465,7 +4986,7 @@ function motionCueChoices(scene, limit = 256) {
|
|
|
4465
4986
|
choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
|
|
4466
4987
|
}
|
|
4467
4988
|
}
|
|
4468
|
-
_optionalChain([scene, 'access',
|
|
4989
|
+
_optionalChain([scene, 'access', _192 => _192.narration, 'optionalAccess', _193 => _193.words, 'access', _194 => _194.forEach, 'call', _195 => _195((w, i) => {
|
|
4469
4990
|
if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
|
|
4470
4991
|
})]);
|
|
4471
4992
|
return choices;
|
|
@@ -4474,7 +4995,7 @@ function motionShotCueTime(scene, cue) {
|
|
|
4474
4995
|
return cue ? motionCueTime(scene, cue) : void 0;
|
|
4475
4996
|
}
|
|
4476
4997
|
function formatMotionNarration(narration) {
|
|
4477
|
-
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess',
|
|
4998
|
+
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _196 => _196.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
|
|
4478
4999
|
}
|
|
4479
5000
|
function parseMotionNarration(text) {
|
|
4480
5001
|
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
@@ -4646,5 +5167,13 @@ function parseMotionDrivers(text) {
|
|
|
4646
5167
|
|
|
4647
5168
|
|
|
4648
5169
|
|
|
4649
|
-
|
|
5170
|
+
|
|
5171
|
+
|
|
5172
|
+
|
|
5173
|
+
|
|
5174
|
+
|
|
5175
|
+
|
|
5176
|
+
|
|
5177
|
+
|
|
5178
|
+
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_SCHEMA = MOTION_COMMAND_SCHEMA; exports.MOTION_COMMAND_TYPES = MOTION_COMMAND_TYPES; exports.MOTION_DEFAULT_DURATIONS = MOTION_DEFAULT_DURATIONS; exports.MOTION_DEFAULT_HOLD = MOTION_DEFAULT_HOLD; exports.MOTION_DIRECTIONS = MOTION_DIRECTIONS; exports.MOTION_DRAW_EFFECT_ID = MOTION_DRAW_EFFECT_ID; exports.MOTION_DRAW_MS_PER_UNIT = MOTION_DRAW_MS_PER_UNIT; exports.MOTION_DRAW_RANGE = MOTION_DRAW_RANGE; exports.MOTION_DRIVEN_PROPERTIES = MOTION_DRIVEN_PROPERTIES; exports.MOTION_EASE_CHOICES = MOTION_EASE_CHOICES; exports.MOTION_EASE_IN_OUT = MOTION_EASE_IN_OUT; exports.MOTION_EASE_OUT = MOTION_EASE_OUT; exports.MOTION_EDIT_OPS = MOTION_EDIT_OPS; exports.MOTION_ENTER_STYLES = MOTION_ENTER_STYLES; exports.MOTION_EXIT_STYLES = MOTION_EXIT_STYLES; exports.MOTION_IRIS_SHAPES = MOTION_IRIS_SHAPES; exports.MOTION_ISSUE_CODES = MOTION_ISSUE_CODES; exports.MOTION_MIN_CHANGE_MS = MOTION_MIN_CHANGE_MS; exports.MOTION_REPEAT_MODES = MOTION_REPEAT_MODES; exports.MOTION_SPEED_RANGE = MOTION_SPEED_RANGE; exports.MOTION_SPLIT_ORIENTATIONS = MOTION_SPLIT_ORIENTATIONS; exports.MOTION_TEXT_STAGGER = MOTION_TEXT_STAGGER; exports.MOTION_TEXT_UNITS = MOTION_TEXT_UNITS; exports.MOTION_TRIGGERS = MOTION_TRIGGERS; exports.MotionSceneFormatError = MotionSceneFormatError; exports.activeSegment = activeSegment; exports.applyMotionControlValues = applyMotionControlValues; exports.applyMotionDrivers = applyMotionDrivers; exports.applyMotionEdits = applyMotionEdits; exports.checkMotionScene = checkMotionScene; exports.clipsShapeProblems = clipsShapeProblems; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createMotionScene = createMotionScene; exports.defaultMotionCommand = defaultMotionCommand; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.driversShapeProblems = driversShapeProblems; exports.duplicateMotionCommandEdit = duplicateMotionCommandEdit; exports.fitMotionRect = fitMotionRect; exports.fitMotionScene = fitMotionScene; exports.fitMotionSceneEdits = fitMotionSceneEdits; exports.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.formatMotionDrivers = formatMotionDrivers; exports.formatMotionNarration = formatMotionNarration; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.fromPptxAnimation = fromPptxAnimation; exports.highlightMotionSvg = highlightMotionSvg; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionBlurTimes = motionBlurTimes; exports.motionCascade = motionCascade; 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.motionContactSheetSvg = motionContactSheetSvg; exports.motionCueChoices = motionCueChoices; exports.motionCueFromKey = motionCueFromKey; exports.motionCueKey = motionCueKey; exports.motionCueTime = motionCueTime; exports.motionCycleDuration = motionCycleDuration; exports.motionDrivenNodes = motionDrivenNodes; exports.motionDriverSources = motionDriverSources; exports.motionEaseKey = motionEaseKey; exports.motionEasingCurve = motionEasingCurve; exports.motionEasingGuides = motionEasingGuides; exports.motionEasingPath = motionEasingPath; exports.motionFieldEdit = motionFieldEdit; exports.motionFieldLabel = motionFieldLabel; exports.motionFlairPrimitive = motionFlairPrimitive; exports.motionFollowRoute = motionFollowRoute; exports.motionFrameAt = motionFrameAt; exports.motionFrameToSvg = motionFrameToSvg; exports.motionGhosts = motionGhosts; exports.motionIssue = motionIssue; exports.motionIssueKey = motionIssueKey; exports.motionIssueLine = motionIssueLine; exports.motionMovingIds = motionMovingIds; exports.motionNodeAtElement = motionNodeAtElement; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionPath = motionPath; exports.motionPathLength = motionPathLength; exports.motionPathsSvg = motionPathsSvg; exports.motionPropertyValue = motionPropertyValue; exports.motionRestValue = motionRestValue; exports.motionRevealClip = motionRevealClip; exports.motionRevealPadding = motionRevealPadding; exports.motionRulerTicks = motionRulerTicks; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionShotCueTime = motionShotCueTime; exports.motionShotTimeScale = motionShotTimeScale; exports.motionStageSvg = motionStageSvg; exports.motionTextLayout = motionTextLayout; exports.motionTextUnits = motionTextUnits; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = namedWithSuggestion; exports.parseMotionDrivers = parseMotionDrivers; exports.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; exports.resolveMotionEditRefs = resolveMotionEditRefs; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.smoothMotionLegs = smoothMotionLegs; exports.smoothMotionTimes = smoothMotionTimes; exports.suggestName = suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
|
|
4650
5179
|
//# sourceMappingURL=index.cjs.map
|