@pixerate/editor 0.65.0 → 0.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animation-editor/index.cjs +335 -4
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +154 -3
- package/dist/animation-editor/index.d.ts +154 -3
- package/dist/animation-editor/index.js +334 -3
- package/dist/animation-editor/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -51,6 +51,7 @@ var _chunkA6PHCAGXcjs = require('../chunk-A6PHCAGX.cjs');
|
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
|
|
54
55
|
var _chunk2FHLHZALcjs = require('../chunk-2FHLHZAL.cjs');
|
|
55
56
|
|
|
56
57
|
// src/animation-editor/types.ts
|
|
@@ -1563,6 +1564,7 @@ var MOTION_EDIT_OPS = [
|
|
|
1563
1564
|
"add_commands",
|
|
1564
1565
|
"update_command",
|
|
1565
1566
|
"delete_commands",
|
|
1567
|
+
"move_command",
|
|
1566
1568
|
"set_artwork",
|
|
1567
1569
|
"set_controls",
|
|
1568
1570
|
"replace_scene"
|
|
@@ -1687,6 +1689,16 @@ function applyOne(scene, edit) {
|
|
|
1687
1689
|
const drop = new Set(edit.commands);
|
|
1688
1690
|
return replaceShot(scene, i, { ...scene.shots[i], run: run.filter((_, k) => !drop.has(k)) });
|
|
1689
1691
|
}
|
|
1692
|
+
case "move_command": {
|
|
1693
|
+
const i = shotIndex(scene, edit.shot);
|
|
1694
|
+
const run = [...scene.shots[i].run];
|
|
1695
|
+
if (!Number.isInteger(edit.command) || edit.command < 0 || edit.command >= run.length)
|
|
1696
|
+
fail(`Shot "${edit.shot}" has ${run.length} command${run.length === 1 ? "" : "s"}; "command" must be an index from 0 to ${run.length - 1} (got ${edit.command}).`);
|
|
1697
|
+
const to = position(edit.to, run.length - 1, '"to"');
|
|
1698
|
+
const [moved] = run.splice(edit.command, 1);
|
|
1699
|
+
run.splice(to, 0, moved);
|
|
1700
|
+
return replaceShot(scene, i, { ...scene.shots[i], run });
|
|
1701
|
+
}
|
|
1690
1702
|
case "set_artwork":
|
|
1691
1703
|
return { ...scene, artwork: edit.artwork };
|
|
1692
1704
|
case "set_controls": {
|
|
@@ -2255,11 +2267,17 @@ function fromFlairSvgMotion(input, options = {}) {
|
|
|
2255
2267
|
${problems.join("\n")}`);
|
|
2256
2268
|
return { scene, notes: [...new Set(notes)], issues: checkMotionScene(scene) };
|
|
2257
2269
|
}
|
|
2270
|
+
function presetColor(value) {
|
|
2271
|
+
if (typeof value === "string") return /^#[0-9a-f]{6}$/i.test(value) ? value.toLowerCase() : value;
|
|
2272
|
+
if (Array.isArray(value) && value.length >= 3 && value.slice(0, 3).every((n) => typeof n === "number" && Number.isFinite(n)))
|
|
2273
|
+
return `#${value.slice(0, 3).map((n) => Math.round(Math.min(1, Math.max(0, n)) * 255).toString(16).padStart(2, "0")).join("")}`;
|
|
2274
|
+
return void 0;
|
|
2275
|
+
}
|
|
2258
2276
|
function fromFlairVectorEffect(effect, options = {}) {
|
|
2259
2277
|
if (!effect || effect.kind !== "vector" || !effect.motion) throw new Error('Give a Flair vector effect: { kind: "vector", id, name, motion: { svg, animate } }.');
|
|
2260
2278
|
const result = fromFlairSvgMotion(effect.motion, { name: _nullishCoalesce(_nullishCoalesce(options.name, () => ( effect.id)), () => ( effect.name)), hold: _nullishCoalesce(options.hold, () => ( effect.hold)) });
|
|
2261
2279
|
const names = new Set((_nullishCoalesce(result.scene.controls, () => ( []))).map((c) => c.name));
|
|
2262
|
-
const presets = (_nullishCoalesce(effect.presets, () => ( []))).map((p) => ({ name: p.name, values: Object.fromEntries(Object.entries(p.values).
|
|
2280
|
+
const presets = (_nullishCoalesce(effect.presets, () => ( []))).map((p) => ({ name: p.name, values: Object.fromEntries(Object.entries(p.values).flatMap(([k, v]) => names.has(k) && presetColor(v) ? [[k, presetColor(v)]] : [])) })).filter((p) => Object.keys(p.values).length);
|
|
2263
2281
|
const scene = { ...result.scene, ...effect.description ? { description: effect.description } : {}, ...presets.length ? { presets } : {} };
|
|
2264
2282
|
const notes = [...result.notes];
|
|
2265
2283
|
if (effect.trigger) notes.push(`The effect plays on ${effect.trigger}; scenes play through, so the trigger is not kept (pass it back to toFlairVectorEffect).`);
|
|
@@ -2996,6 +3014,7 @@ var EDIT_OP = {
|
|
|
2996
3014
|
object({ op: { const: "move_shot", description: "Like move_shot." }, shot: SHOT_ID, to: { type: "integer", minimum: 0, description: "New position (0 = first)." } }, ["op", "shot", "to"]),
|
|
2997
3015
|
object({ op: { const: "add_commands", description: "Like add_commands." }, shot: SHOT_ID, commands: { type: "array", items: MOTION_COMMAND_SCHEMA, minItems: 1, description: "Commands to add." }, at: { type: "integer", minimum: 0, description: "Index in the shot's run (default: the end)." } }, ["op", "shot", "commands"]),
|
|
2998
3016
|
object({ op: { const: "update_command", description: "Like update_command." }, shot: SHOT_ID, command: { type: "integer", minimum: 0, description: "Index in the shot's run." }, set: { type: "object", description: "Command fields to replace." }, remove: { type: "array", items: { type: "string" }, description: "Command fields to clear." } }, ["op", "shot", "command"]),
|
|
3017
|
+
object({ op: { const: "move_command", description: "Like move_command." }, shot: SHOT_ID, command: { type: "integer", minimum: 0, description: "Index in the shot's run." }, to: { type: "integer", minimum: 0, description: "New index in the run (0 = first)." } }, ["op", "shot", "command", "to"]),
|
|
2999
3018
|
object({ op: { const: "delete_commands", description: "Like delete_commands." }, shot: SHOT_ID, commands: { type: "array", items: { type: "integer", minimum: 0 }, minItems: 1, description: "Indexes in the shot's run." } }, ["op", "shot", "commands"]),
|
|
3000
3019
|
object({ op: { const: "set_controls", description: "Like set_controls." }, controls: { type: "array", items: CONTROL, description: "Controls (empty clears)." }, presets: { type: "array", items: PRESET, description: "Presets (empty clears)." } }, ["op", "controls"])
|
|
3001
3020
|
]
|
|
@@ -3416,6 +3435,21 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3416
3435
|
annotations: { title: "Delete commands", ...DESTRUCTIVE },
|
|
3417
3436
|
handler: ({ shot, commands }) => apply({ op: "delete_commands", shot, commands }, "Delete commands")
|
|
3418
3437
|
};
|
|
3438
|
+
const moveCommand = {
|
|
3439
|
+
name: "move_command",
|
|
3440
|
+
title: "Reorder a command",
|
|
3441
|
+
description: `Moves one command to a new index in its shot's run (0 = first), as one undo step; the others close up around it. A command with "with": "previous" then starts with its new neighbour. Returns the command's new index, its old one and the shot's timing.`,
|
|
3442
|
+
inputSchema: object(
|
|
3443
|
+
{
|
|
3444
|
+
shot: SHOT_ID,
|
|
3445
|
+
command: { type: "integer", minimum: 0, description: "Index of the command in the shot's run (from get_animation)." },
|
|
3446
|
+
to: { type: "integer", minimum: 0, description: "Its new index, 0 = first (at most the last index)." }
|
|
3447
|
+
},
|
|
3448
|
+
["shot", "command", "to"]
|
|
3449
|
+
),
|
|
3450
|
+
annotations: { title: "Reorder a command", ...WRITE },
|
|
3451
|
+
handler: ({ shot, command: command2, to }) => apply({ op: "move_command", shot, command: command2, to }, "Move command", (s) => ({ shot, command: to, from: command2, commands: describeMotionShots(s).find((x) => x.id === shot).commands.map((c) => ({ index: c.index, type: c.type, start: c.start, end: c.end })) }))
|
|
3452
|
+
};
|
|
3419
3453
|
const setSettings = {
|
|
3420
3454
|
name: "set_animation_settings",
|
|
3421
3455
|
title: "Change animation settings",
|
|
@@ -3498,7 +3532,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3498
3532
|
}
|
|
3499
3533
|
};
|
|
3500
3534
|
const reads = [getAnimation, getShot, findElements, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
|
|
3501
|
-
const writes = [setArtworkSvg, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
|
|
3535
|
+
const writes = [setArtworkSvg, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
|
|
3502
3536
|
return {
|
|
3503
3537
|
id: _nullishCoalesce(options.id, () => ( "animation")),
|
|
3504
3538
|
namespace: options.namespace,
|
|
@@ -3543,12 +3577,309 @@ Commands
|
|
|
3543
3577
|
|
|
3544
3578
|
Working method
|
|
3545
3579
|
1. get_animation to learn the element ids (set_animation_artwork_svg first if there is no artwork: give every element you will animate an id; or import_flair_effect to start from a Flair effect and edit it).
|
|
3546
|
-
2. Plan a few shots, each one idea. Add them with insert_shots, or edit_animation to make several edits as one step (dry_run first when unsure).
|
|
3580
|
+
2. Plan a few shots, each one idea. Add them with insert_shots (add_commands, update_command, move_command and delete_commands refine a shot), or edit_animation to make several edits as one step (dry_run first when unsure).
|
|
3547
3581
|
3. To hit a length, fit_animation (keep the shots whose pace matters). check_animation and fix every error and warning; render_animation_frame (shot + "end") to look at the result; add onion_skin or motion_paths to see the motion in one picture, or get_motion_path for the numbers.
|
|
3548
3582
|
4. To make a reusable Flair effect, set_animation_controls (colour controls stand for every use of their default colour) and export_flair_effect.
|
|
3549
3583
|
|
|
3550
3584
|
Keep motion purposeful: one thing moving at a time reads best, ease-out for arrivals, ease-in for exits, and hold long enough to see each result.`;
|
|
3551
3585
|
|
|
3586
|
+
// src/animation-editor/form.ts
|
|
3587
|
+
var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "ease", "repeat", "repeatMode", "steps", "note"]);
|
|
3588
|
+
var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
|
|
3589
|
+
var NODES = /* @__PURE__ */ new Set(["into", "path"]);
|
|
3590
|
+
function branch(type) {
|
|
3591
|
+
return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _89 => _89.properties, 'optionalAccess', _90 => _90.type, 'optionalAccess', _91 => _91.const]) === type);
|
|
3592
|
+
}
|
|
3593
|
+
function unitOf(type, name) {
|
|
3594
|
+
if (name === "duration" || name === "delay" || name === "stagger") return "ms";
|
|
3595
|
+
if (name === "steps") return "fps";
|
|
3596
|
+
if (name === "frequency") return "Hz";
|
|
3597
|
+
if (name === "repeat" || name === "count") return "\xD7";
|
|
3598
|
+
if (name === "distance" || name === "strokeWidth") return "units";
|
|
3599
|
+
if (name === "angle") return "\xB0";
|
|
3600
|
+
if (name === "amount") return type === "pulse" ? "\xD7" : "units";
|
|
3601
|
+
if (name === "rotate" && type === "wiggle") return "\xB0";
|
|
3602
|
+
if ((name === "by" || name === "to") && type === "rotate") return "\xB0";
|
|
3603
|
+
if (name === "scale" || name === "to" && type === "scale") return "\xD7";
|
|
3604
|
+
if ((name === "from" || name === "to") && (type === "draw" || type === "fade" || type === "follow")) return "0\u20131";
|
|
3605
|
+
return void 0;
|
|
3606
|
+
}
|
|
3607
|
+
function motionFieldLabel(name) {
|
|
3608
|
+
const words = name.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
|
|
3609
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
3610
|
+
}
|
|
3611
|
+
function kindOf(name, schema) {
|
|
3612
|
+
if (name === "targets") return "targets";
|
|
3613
|
+
if (name === "ease") return "ease";
|
|
3614
|
+
if (schema.enum) return "enum";
|
|
3615
|
+
if (schema.anyOf) return "scale";
|
|
3616
|
+
if (schema.type === "object") return "point";
|
|
3617
|
+
if (schema.type === "boolean") return "boolean";
|
|
3618
|
+
if (schema.type === "integer") return "integer";
|
|
3619
|
+
if (schema.type === "number") return "number";
|
|
3620
|
+
if (COLORS.has(name)) return "color";
|
|
3621
|
+
if (NODES.has(name)) return "node";
|
|
3622
|
+
return "text";
|
|
3623
|
+
}
|
|
3624
|
+
function motionCommandFields(type) {
|
|
3625
|
+
const schema = branch(type);
|
|
3626
|
+
if (!_optionalChain([schema, 'optionalAccess', _92 => _92.properties])) return [];
|
|
3627
|
+
const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
|
|
3628
|
+
const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
|
|
3629
|
+
const kind = kindOf(name, s);
|
|
3630
|
+
const min = typeof s.minimum === "number" ? s.minimum : typeof s.exclusiveMinimum === "number" ? s.exclusiveMinimum : void 0;
|
|
3631
|
+
return {
|
|
3632
|
+
name,
|
|
3633
|
+
kind,
|
|
3634
|
+
label: motionFieldLabel(name),
|
|
3635
|
+
description: _nullishCoalesce(s.description, () => ( "")),
|
|
3636
|
+
required: required.has(name),
|
|
3637
|
+
...s.enum ? { options: s.enum.map(String) } : {},
|
|
3638
|
+
...min !== void 0 ? { min } : {},
|
|
3639
|
+
...typeof s.maximum === "number" ? { max: s.maximum } : {},
|
|
3640
|
+
...unitOf(type, name) ? { unit: unitOf(type, name) } : {},
|
|
3641
|
+
group: TIMING.has(name) ? "timing" : "main"
|
|
3642
|
+
};
|
|
3643
|
+
});
|
|
3644
|
+
return [...fields.filter((f) => f.group === "main"), ...fields.filter((f) => f.group === "timing")];
|
|
3645
|
+
}
|
|
3646
|
+
function parseMotionFieldInput(field, raw) {
|
|
3647
|
+
if (field.kind === "boolean") return raw === true ? { set: true } : { remove: true };
|
|
3648
|
+
if (field.kind === "targets") {
|
|
3649
|
+
const ids = (Array.isArray(raw) ? raw : String(raw).split(",")).map((s) => String(s).trim()).filter(Boolean);
|
|
3650
|
+
return ids.length ? { set: ids } : { error: "Pick at least one target." };
|
|
3651
|
+
}
|
|
3652
|
+
if (field.kind === "point" || field.kind === "scale" && typeof raw === "object" && !Array.isArray(raw)) {
|
|
3653
|
+
const p = raw;
|
|
3654
|
+
if (p.x.trim() === "" && p.y.trim() === "") return field.required ? { error: `${field.label} is required.` } : { remove: true };
|
|
3655
|
+
const x = Number(p.x);
|
|
3656
|
+
const y = Number(p.y);
|
|
3657
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return { error: `${field.label} needs a number for x and for y.` };
|
|
3658
|
+
return { set: { x, y } };
|
|
3659
|
+
}
|
|
3660
|
+
const text = String(raw).trim();
|
|
3661
|
+
if (text === "") return field.required ? { error: `${field.label} is required.` } : { remove: true };
|
|
3662
|
+
if (field.kind === "number" || field.kind === "integer" || field.kind === "scale") {
|
|
3663
|
+
const n = Number(text);
|
|
3664
|
+
if (!Number.isFinite(n)) return { error: `${field.label} must be a number${field.unit ? ` (${field.unit})` : ""}.` };
|
|
3665
|
+
if (field.kind === "integer" && !Number.isInteger(n)) return { error: `${field.label} must be a whole number.` };
|
|
3666
|
+
if (field.min !== void 0 && n < field.min) return { error: `${field.label} must be at least ${field.min}.` };
|
|
3667
|
+
if (field.max !== void 0 && n > field.max) return { error: `${field.label} must be at most ${field.max}.` };
|
|
3668
|
+
return { set: n };
|
|
3669
|
+
}
|
|
3670
|
+
if (field.kind === "enum" && field.options && !field.options.includes(text)) return { error: `${field.label} must be one of ${field.options.join(", ")}.` };
|
|
3671
|
+
return { set: text };
|
|
3672
|
+
}
|
|
3673
|
+
function motionFieldEdit(shot, command2, field, raw) {
|
|
3674
|
+
const input = parseMotionFieldInput(field, raw);
|
|
3675
|
+
if ("error" in input) return input;
|
|
3676
|
+
if ("remove" in input) return { op: "update_command", shot, command: command2, remove: [field.name] };
|
|
3677
|
+
return { op: "update_command", shot, command: command2, set: { [field.name]: input.set } };
|
|
3678
|
+
}
|
|
3679
|
+
function defaultMotionCommand(type, targets, scene) {
|
|
3680
|
+
if (type === "wait") return { type: "wait", duration: 500 };
|
|
3681
|
+
if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
|
|
3682
|
+
const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
|
|
3683
|
+
const other = (pred) => _optionalChain([nodes, 'access', _93 => _93.find, 'call', _94 => _94((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _95 => _95.node, 'access', _96 => _96.id]);
|
|
3684
|
+
const base = { targets: [...targets] };
|
|
3685
|
+
switch (type) {
|
|
3686
|
+
case "scale":
|
|
3687
|
+
return { type, ...base, to: 1.2 };
|
|
3688
|
+
case "fade":
|
|
3689
|
+
return { type, ...base, to: 0.5 };
|
|
3690
|
+
case "move":
|
|
3691
|
+
return { type, ...base, by: { x: 40, y: 0 } };
|
|
3692
|
+
case "rotate":
|
|
3693
|
+
return { type, ...base, by: 90 };
|
|
3694
|
+
case "style":
|
|
3695
|
+
return { type, ...base, fill: "#f59e0b" };
|
|
3696
|
+
case "morph": {
|
|
3697
|
+
const into = _nullishCoalesce(other((e) => e.node.type === "path" && e.node.visible === false), () => ( other((e) => e.node.type === "path")));
|
|
3698
|
+
return into ? { type, ...base, into } : { error: "Morph needs another shape to become; draw one (it can stay hidden)." };
|
|
3699
|
+
}
|
|
3700
|
+
case "match": {
|
|
3701
|
+
const into = _nullishCoalesce(other((e) => e.node.type === "group" && e.node.visible === false), () => ( other((e) => e.node.type === "group")));
|
|
3702
|
+
return into ? { type, ...base, into } : { error: "Match needs another group to become; group the end state (it can stay hidden)." };
|
|
3703
|
+
}
|
|
3704
|
+
case "follow": {
|
|
3705
|
+
const path = _nullishCoalesce(other((e) => e.node.type === "path" && e.node.visible === false), () => ( other((e) => e.node.type === "path")));
|
|
3706
|
+
return path ? { type, ...base, path } : { error: "Follow needs a path to travel along; draw one (it can stay hidden)." };
|
|
3707
|
+
}
|
|
3708
|
+
case "effect": {
|
|
3709
|
+
for (const id of targets) {
|
|
3710
|
+
const node = _optionalChain([nodes, 'access', _97 => _97.find, 'call', _98 => _98((e) => e.node.id === id), 'optionalAccess', _99 => _99.node]);
|
|
3711
|
+
for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _100 => _100.effects]), () => ( []))) {
|
|
3712
|
+
const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
|
|
3713
|
+
if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
|
|
3714
|
+
}
|
|
3715
|
+
}
|
|
3716
|
+
return { error: "Effect needs a target with a live path effect (wiggle, twist, zig zag\u2026)." };
|
|
3717
|
+
}
|
|
3718
|
+
default:
|
|
3719
|
+
return { type, ...base };
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
function motionCommandSummary(command2) {
|
|
3723
|
+
const c = command2;
|
|
3724
|
+
const what = [command2.type, typeof c.style === "string" ? c.style : ""].filter(Boolean).join(" ");
|
|
3725
|
+
if (command2.type === "wait") return `wait ${command2.duration} ms`;
|
|
3726
|
+
const extra = typeof c.into === "string" ? ` \u2192 ${c.into}` : typeof c.path === "string" ? ` along ${c.path}` : "";
|
|
3727
|
+
return `${what} \xB7 ${(_nullishCoalesce(command2.targets, () => ( []))).join(", ")}${extra}`;
|
|
3728
|
+
}
|
|
3729
|
+
function motionCommandRows(scene, shotId) {
|
|
3730
|
+
const index = scene.shots.findIndex((s) => s.id === shotId);
|
|
3731
|
+
if (index < 0) return [];
|
|
3732
|
+
const timeline = compileMotionScene(scene);
|
|
3733
|
+
return scene.shots[index].run.map((command2, i) => {
|
|
3734
|
+
const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
|
|
3735
|
+
const primitive = motionFlairPrimitive(command2);
|
|
3736
|
+
return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _101 => _101.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _102 => _102.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
|
|
3737
|
+
});
|
|
3738
|
+
}
|
|
3739
|
+
function duplicateMotionCommandEdit(scene, shot, command2) {
|
|
3740
|
+
const run = _nullishCoalesce(_optionalChain([scene, 'access', _103 => _103.shots, 'access', _104 => _104.find, 'call', _105 => _105((s) => s.id === shot), 'optionalAccess', _106 => _106.run]), () => ( []));
|
|
3741
|
+
return { op: "add_commands", shot, commands: run[command2] ? [structuredClone(run[command2])] : [], at: command2 + 1 };
|
|
3742
|
+
}
|
|
3743
|
+
var MOTION_EASE_CHOICES = [
|
|
3744
|
+
{ value: "", label: "Default" },
|
|
3745
|
+
..._chunk2FHLHZALcjs.ANIMATION_EASING_PRESETS.map((p) => ({ value: p, label: _chunk2FHLHZALcjs.ANIMATION_EASING_LABELS[p] }))
|
|
3746
|
+
];
|
|
3747
|
+
function motionEaseKey(ease) {
|
|
3748
|
+
if (ease === void 0 || ease === null) return "";
|
|
3749
|
+
return typeof ease === "string" ? ease : "custom";
|
|
3750
|
+
}
|
|
3751
|
+
function motionEasingCurve(ease, samples = 48, durationMs = 1e3) {
|
|
3752
|
+
const resolved = _chunk2FHLHZALcjs.resolveEasing.call(void 0, ease);
|
|
3753
|
+
const ms = resolved !== "hold" && resolved.type === "spring" ? _chunk2FHLHZALcjs.springSettleMs.call(void 0, resolved) : durationMs;
|
|
3754
|
+
const n = Math.max(2, Math.floor(samples));
|
|
3755
|
+
const points = [];
|
|
3756
|
+
for (let i = 0; i <= n; i++) {
|
|
3757
|
+
const u = i / n;
|
|
3758
|
+
points.push({ u, v: resolved === "hold" ? i === n ? 1 : 0 : _chunk2FHLHZALcjs.evaluateEasing.call(void 0, ease, u, ms) });
|
|
3759
|
+
}
|
|
3760
|
+
const values = points.map((p) => p.v);
|
|
3761
|
+
return { points, min: Math.min(0, ...values), max: Math.max(1, ...values), durationMs: ms };
|
|
3762
|
+
}
|
|
3763
|
+
function motionEasingPath(curve, width, height, pad = 4) {
|
|
3764
|
+
const span = curve.max - curve.min || 1;
|
|
3765
|
+
const f = (n) => String(Math.round(n * 100) / 100);
|
|
3766
|
+
return curve.points.map((p, i) => `${i ? "L" : "M"}${f(pad + p.u * (width - 2 * pad))} ${f(pad + (1 - (p.v - curve.min) / span) * (height - 2 * pad))}`).join(" ");
|
|
3767
|
+
}
|
|
3768
|
+
function motionEasingGuides(curve, height, pad = 4) {
|
|
3769
|
+
const span = curve.max - curve.min || 1;
|
|
3770
|
+
const y = (v) => pad + (1 - (v - curve.min) / span) * (height - 2 * pad);
|
|
3771
|
+
return { zero: y(0), one: y(1) };
|
|
3772
|
+
}
|
|
3773
|
+
function motionNodeAtElement(scene, target, root) {
|
|
3774
|
+
const ids = indexMotionNodes(scene.artwork.nodes);
|
|
3775
|
+
for (let el = target; el && el !== root; el = el.parentElement) {
|
|
3776
|
+
const id = el.getAttribute("id");
|
|
3777
|
+
if (id && ids.has(id)) return id;
|
|
3778
|
+
}
|
|
3779
|
+
return null;
|
|
3780
|
+
}
|
|
3781
|
+
var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3782
|
+
function highlightMotionSvg(svg, ids, color = "#f43f5e") {
|
|
3783
|
+
if (!ids.length) return svg;
|
|
3784
|
+
let out = svg;
|
|
3785
|
+
for (const id of ids) {
|
|
3786
|
+
const escaped = id.replace(/&/g, "&").replace(/"/g, """);
|
|
3787
|
+
out = out.replace(new RegExp(` id="${escapeRegExp(escaped)}"`), ` id="${escaped}" data-picked=""`);
|
|
3788
|
+
}
|
|
3789
|
+
return out.replace(/(<svg\b[^>]*>)/, `$1<style>[data-picked]{filter:drop-shadow(0 0 1px #fff) drop-shadow(0 0 3px ${color}) drop-shadow(0 0 3px ${color})}</style>`);
|
|
3790
|
+
}
|
|
3791
|
+
function motionRulerTicks(duration, width, minGap = 56) {
|
|
3792
|
+
const span = Math.max(1, duration);
|
|
3793
|
+
const steps = [100, 250, 500, 1e3, 2e3, 5e3, 1e4, 3e4, 6e4];
|
|
3794
|
+
const step = _nullishCoalesce(steps.find((s) => s / span * Math.max(1, width) >= minGap), () => ( steps[steps.length - 1]));
|
|
3795
|
+
const ticks = [];
|
|
3796
|
+
for (let t = 0; t <= span + 1e-6; t += step / 2) {
|
|
3797
|
+
const major = Math.round(t / (step / 2)) % 2 === 0;
|
|
3798
|
+
ticks.push({ time: t, major, label: major ? `${step < 1e3 ? (t / 1e3).toFixed(step < 500 ? 2 : 1) : String(Math.round(t / 1e3))}s` : "" });
|
|
3799
|
+
}
|
|
3800
|
+
return ticks;
|
|
3801
|
+
}
|
|
3802
|
+
function fitMotionSceneEdits(scene, ms, options = {}) {
|
|
3803
|
+
const fit = fitMotionScene(scene, ms, options);
|
|
3804
|
+
return fit.scene.shots.flatMap((shot, i) => {
|
|
3805
|
+
const before = scene.shots[i].speed;
|
|
3806
|
+
if (before === shot.speed) return [];
|
|
3807
|
+
return shot.speed === void 0 ? [{ op: "update_shot", shot: shot.id, remove: ["speed"] }] : [{ op: "update_shot", shot: shot.id, set: { speed: shot.speed } }];
|
|
3808
|
+
});
|
|
3809
|
+
}
|
|
3810
|
+
function motionCueKey(cue) {
|
|
3811
|
+
if (!cue) return "";
|
|
3812
|
+
if (typeof cue.beat === "number") return `beat:${cue.beat}`;
|
|
3813
|
+
if (typeof cue.word === "number") return `word:${cue.word}`;
|
|
3814
|
+
if (typeof cue.ms === "number") return `ms:${cue.ms}`;
|
|
3815
|
+
return "";
|
|
3816
|
+
}
|
|
3817
|
+
function motionCueFromKey(key) {
|
|
3818
|
+
const m = /^(beat|word|ms):(-?\d+(?:\.\d+)?)$/.exec(key);
|
|
3819
|
+
if (!m) return void 0;
|
|
3820
|
+
return { [m[1]]: Number(m[2]) };
|
|
3821
|
+
}
|
|
3822
|
+
function motionCueChoices(scene, limit = 256) {
|
|
3823
|
+
const choices = [];
|
|
3824
|
+
const s = (ms) => `${(ms / 1e3).toFixed(2)} s`;
|
|
3825
|
+
const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _107 => _107.narration, 'optionalAccess', _108 => _108.words, 'access', _109 => _109.map, 'call', _110 => _110((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
|
|
3826
|
+
if (scene.beat && scene.beat.bpm > 0) {
|
|
3827
|
+
for (let beat = 0; choices.length < limit; beat++) {
|
|
3828
|
+
const time = motionBeatTime(scene.beat, beat);
|
|
3829
|
+
if (time > end) break;
|
|
3830
|
+
if (time < 0) continue;
|
|
3831
|
+
const at = motionBeatAt(scene.beat, time);
|
|
3832
|
+
choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
_optionalChain([scene, 'access', _111 => _111.narration, 'optionalAccess', _112 => _112.words, 'access', _113 => _113.forEach, 'call', _114 => _114((w, i) => {
|
|
3836
|
+
if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
|
|
3837
|
+
})]);
|
|
3838
|
+
return choices;
|
|
3839
|
+
}
|
|
3840
|
+
function motionShotCueTime(scene, cue) {
|
|
3841
|
+
return cue ? motionCueTime(scene, cue) : void 0;
|
|
3842
|
+
}
|
|
3843
|
+
function formatMotionNarration(narration) {
|
|
3844
|
+
return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _115 => _115.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
|
|
3845
|
+
}
|
|
3846
|
+
function parseMotionNarration(text) {
|
|
3847
|
+
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
3848
|
+
if (!lines.length) return { narration: null };
|
|
3849
|
+
const words = [];
|
|
3850
|
+
for (const [i, line] of lines.entries()) {
|
|
3851
|
+
const m = /^(\d+(?:\.\d+)?)\s+(.+)$/.exec(line);
|
|
3852
|
+
if (!m) return { error: `Line ${i + 1} ("${line}") should be a start time in ms and a word, e.g. "1200 hello".` };
|
|
3853
|
+
const start = Number(m[1]);
|
|
3854
|
+
if (words.length && start < words[words.length - 1].start) return { error: `Line ${i + 1} starts before the word above it; keep the words in time order.` };
|
|
3855
|
+
words.push({ text: m[2], start });
|
|
3856
|
+
}
|
|
3857
|
+
return { narration: { words } };
|
|
3858
|
+
}
|
|
3859
|
+
|
|
3860
|
+
|
|
3861
|
+
|
|
3862
|
+
|
|
3863
|
+
|
|
3864
|
+
|
|
3865
|
+
|
|
3866
|
+
|
|
3867
|
+
|
|
3868
|
+
|
|
3869
|
+
|
|
3870
|
+
|
|
3871
|
+
|
|
3872
|
+
|
|
3873
|
+
|
|
3874
|
+
|
|
3875
|
+
|
|
3876
|
+
|
|
3877
|
+
|
|
3878
|
+
|
|
3879
|
+
|
|
3880
|
+
|
|
3881
|
+
|
|
3882
|
+
|
|
3552
3883
|
|
|
3553
3884
|
|
|
3554
3885
|
|
|
@@ -3644,5 +3975,5 @@ Keep motion purposeful: one thing moving at a time reads best, ease-out for arri
|
|
|
3644
3975
|
|
|
3645
3976
|
|
|
3646
3977
|
|
|
3647
|
-
exports.ANIMATION_EDITOR_AGENT_INSTRUCTIONS = ANIMATION_EDITOR_AGENT_INSTRUCTIONS; exports.AnimationEditorController = AnimationEditorController; exports.FLAIR_EASES = FLAIR_EASES; exports.FLAIR_EXPORT_VERSION = FLAIR_EXPORT_VERSION; exports.MOTION_ADDITIVE_PROPERTIES = MOTION_ADDITIVE_PROPERTIES; exports.MOTION_BLENDS = MOTION_BLENDS; exports.MOTION_CAMERA_MS = MOTION_CAMERA_MS; exports.MOTION_COMMAND_SCHEMA = MOTION_COMMAND_SCHEMA; exports.MOTION_COMMAND_TYPES = MOTION_COMMAND_TYPES; exports.MOTION_DEFAULT_DURATIONS = MOTION_DEFAULT_DURATIONS; exports.MOTION_DEFAULT_HOLD = MOTION_DEFAULT_HOLD; exports.MOTION_DIRECTIONS = MOTION_DIRECTIONS; exports.MOTION_DRAW_EFFECT_ID = MOTION_DRAW_EFFECT_ID; exports.MOTION_DRAW_MS_PER_UNIT = MOTION_DRAW_MS_PER_UNIT; exports.MOTION_DRAW_RANGE = MOTION_DRAW_RANGE; exports.MOTION_EASE_IN_OUT = MOTION_EASE_IN_OUT; exports.MOTION_EASE_OUT = MOTION_EASE_OUT; exports.MOTION_EDIT_OPS = MOTION_EDIT_OPS; exports.MOTION_ENTER_STYLES = MOTION_ENTER_STYLES; exports.MOTION_EXIT_STYLES = MOTION_EXIT_STYLES; exports.MOTION_IRIS_SHAPES = MOTION_IRIS_SHAPES; exports.MOTION_ISSUE_CODES = MOTION_ISSUE_CODES; exports.MOTION_MIN_CHANGE_MS = MOTION_MIN_CHANGE_MS; exports.MOTION_REPEAT_MODES = MOTION_REPEAT_MODES; exports.MOTION_SPEED_RANGE = MOTION_SPEED_RANGE; exports.MOTION_SPLIT_ORIENTATIONS = MOTION_SPLIT_ORIENTATIONS; exports.MotionSceneFormatError = MotionSceneFormatError; exports.activeSegment = activeSegment; exports.applyMotionControlValues = applyMotionControlValues; exports.applyMotionEdits = applyMotionEdits; exports.checkMotionScene = checkMotionScene; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createMotionScene = createMotionScene; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.fitMotionRect = fitMotionRect; exports.fitMotionScene = fitMotionScene; exports.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionClipAttrs = motionClipAttrs; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCueTime = motionCueTime; exports.motionCycleDuration = motionCycleDuration; exports.motionFlairPrimitive = motionFlairPrimitive; exports.motionFollowRoute = motionFollowRoute; exports.motionFrameAt = motionFrameAt; exports.motionFrameToSvg = motionFrameToSvg; exports.motionGhosts = motionGhosts; exports.motionIssue = motionIssue; exports.motionIssueKey = motionIssueKey; exports.motionIssueLine = motionIssueLine; exports.motionMovingIds = motionMovingIds; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionPath = motionPath; exports.motionPathLength = motionPathLength; exports.motionPathsSvg = motionPathsSvg; exports.motionRestValue = motionRestValue; exports.motionRevealClip = motionRevealClip; exports.motionRevealPadding = motionRevealPadding; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionShotTimeScale = motionShotTimeScale; exports.motionStageSvg = motionStageSvg; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = namedWithSuggestion; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.suggestName = suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
|
|
3978
|
+
exports.ANIMATION_EDITOR_AGENT_INSTRUCTIONS = ANIMATION_EDITOR_AGENT_INSTRUCTIONS; exports.AnimationEditorController = AnimationEditorController; exports.FLAIR_EASES = FLAIR_EASES; exports.FLAIR_EXPORT_VERSION = FLAIR_EXPORT_VERSION; exports.MOTION_ADDITIVE_PROPERTIES = MOTION_ADDITIVE_PROPERTIES; exports.MOTION_BLENDS = MOTION_BLENDS; exports.MOTION_CAMERA_MS = MOTION_CAMERA_MS; exports.MOTION_COMMAND_SCHEMA = MOTION_COMMAND_SCHEMA; exports.MOTION_COMMAND_TYPES = MOTION_COMMAND_TYPES; exports.MOTION_DEFAULT_DURATIONS = MOTION_DEFAULT_DURATIONS; exports.MOTION_DEFAULT_HOLD = MOTION_DEFAULT_HOLD; exports.MOTION_DIRECTIONS = MOTION_DIRECTIONS; exports.MOTION_DRAW_EFFECT_ID = MOTION_DRAW_EFFECT_ID; exports.MOTION_DRAW_MS_PER_UNIT = MOTION_DRAW_MS_PER_UNIT; exports.MOTION_DRAW_RANGE = MOTION_DRAW_RANGE; exports.MOTION_EASE_CHOICES = MOTION_EASE_CHOICES; exports.MOTION_EASE_IN_OUT = MOTION_EASE_IN_OUT; exports.MOTION_EASE_OUT = MOTION_EASE_OUT; exports.MOTION_EDIT_OPS = MOTION_EDIT_OPS; exports.MOTION_ENTER_STYLES = MOTION_ENTER_STYLES; exports.MOTION_EXIT_STYLES = MOTION_EXIT_STYLES; exports.MOTION_IRIS_SHAPES = MOTION_IRIS_SHAPES; exports.MOTION_ISSUE_CODES = MOTION_ISSUE_CODES; exports.MOTION_MIN_CHANGE_MS = MOTION_MIN_CHANGE_MS; exports.MOTION_REPEAT_MODES = MOTION_REPEAT_MODES; exports.MOTION_SPEED_RANGE = MOTION_SPEED_RANGE; exports.MOTION_SPLIT_ORIENTATIONS = MOTION_SPLIT_ORIENTATIONS; exports.MotionSceneFormatError = MotionSceneFormatError; exports.activeSegment = activeSegment; exports.applyMotionControlValues = applyMotionControlValues; exports.applyMotionEdits = applyMotionEdits; exports.checkMotionScene = checkMotionScene; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createMotionScene = createMotionScene; exports.defaultMotionCommand = defaultMotionCommand; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.duplicateMotionCommandEdit = duplicateMotionCommandEdit; exports.fitMotionRect = fitMotionRect; exports.fitMotionScene = fitMotionScene; exports.fitMotionSceneEdits = fitMotionSceneEdits; exports.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.formatMotionNarration = formatMotionNarration; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.highlightMotionSvg = highlightMotionSvg; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionClipAttrs = motionClipAttrs; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandFields = motionCommandFields; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCommandRows = motionCommandRows; exports.motionCommandSummary = motionCommandSummary; exports.motionCueChoices = motionCueChoices; exports.motionCueFromKey = motionCueFromKey; exports.motionCueKey = motionCueKey; exports.motionCueTime = motionCueTime; exports.motionCycleDuration = motionCycleDuration; exports.motionEaseKey = motionEaseKey; exports.motionEasingCurve = motionEasingCurve; exports.motionEasingGuides = motionEasingGuides; exports.motionEasingPath = motionEasingPath; exports.motionFieldEdit = motionFieldEdit; exports.motionFieldLabel = motionFieldLabel; exports.motionFlairPrimitive = motionFlairPrimitive; exports.motionFollowRoute = motionFollowRoute; exports.motionFrameAt = motionFrameAt; exports.motionFrameToSvg = motionFrameToSvg; exports.motionGhosts = motionGhosts; exports.motionIssue = motionIssue; exports.motionIssueKey = motionIssueKey; exports.motionIssueLine = motionIssueLine; exports.motionMovingIds = motionMovingIds; exports.motionNodeAtElement = motionNodeAtElement; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionPath = motionPath; exports.motionPathLength = motionPathLength; exports.motionPathsSvg = motionPathsSvg; exports.motionRestValue = motionRestValue; exports.motionRevealClip = motionRevealClip; exports.motionRevealPadding = motionRevealPadding; exports.motionRulerTicks = motionRulerTicks; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionShotCueTime = motionShotCueTime; exports.motionShotTimeScale = motionShotTimeScale; exports.motionStageSvg = motionStageSvg; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = namedWithSuggestion; exports.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.suggestName = suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
|
|
3648
3979
|
//# sourceMappingURL=index.cjs.map
|