@pixerate/editor 0.139.1 → 0.140.1
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/README.md +25 -4
- package/dist/agent/formatTools.d.cts +15 -0
- package/dist/agent/formatTools.d.ts +15 -0
- package/dist/agent/index.cjs +408 -49
- package/dist/agent/index.js +375 -16
- package/dist/agent/providers.d.cts +5 -3
- package/dist/agent/providers.d.ts +5 -3
- package/dist/animation-editor/effect-tools.d.cts +1 -1
- package/dist/animation-editor/effect-tools.d.ts +1 -1
- package/dist/animation-editor/index.cjs +250 -116
- package/dist/animation-editor/index.js +228 -94
- package/dist/animation-editor/instructions.d.cts +1 -1
- package/dist/animation-editor/instructions.d.ts +1 -1
- package/dist/animation-editor/parse.d.cts +3 -1
- package/dist/animation-editor/parse.d.ts +3 -1
- package/dist/animation-editor/tools.d.cts +8 -3
- package/dist/animation-editor/tools.d.ts +8 -3
- package/dist/bridge/cli.cjs +4 -3
- package/dist/bridge/cli.js +3 -2
- package/dist/bridge/index.cjs +8 -3
- package/dist/bridge/index.d.cts +7 -0
- package/dist/bridge/index.d.ts +7 -0
- package/dist/bridge/index.js +9 -4
- package/dist/bridge/skills.d.cts +9 -0
- package/dist/bridge/skills.d.ts +9 -0
- package/dist/canvas/effect-tools.d.cts +1 -1
- package/dist/canvas/effect-tools.d.ts +1 -1
- package/dist/canvas/index.cjs +22 -17
- package/dist/canvas/index.js +8 -3
- package/dist/chart/file-tools.d.cts +1 -1
- package/dist/chart/file-tools.d.ts +1 -1
- package/dist/chart/index.cjs +7 -1
- package/dist/chart/index.js +7 -1
- package/dist/chart/tools.d.cts +1 -1
- package/dist/chart/tools.d.ts +1 -1
- package/dist/chunk-2BSBFBOA.cjs +46 -0
- package/dist/{chunk-SWZTQWY7.js → chunk-2INPJDNY.js} +1 -1
- package/dist/{chunk-CCKP4XAN.cjs → chunk-34RQAGWI.cjs} +27 -7
- package/dist/{chunk-HXCBQ7A6.cjs → chunk-3AJMR7EG.cjs} +7 -4
- package/dist/{chunk-BKMU3V6K.js → chunk-5ED73EC6.js} +8 -1
- package/dist/{chunk-NKBUVQJW.cjs → chunk-5WOY52O6.cjs} +15 -15
- package/dist/{chunk-VRIR53SW.js → chunk-6GAYGQDC.js} +10 -8
- package/dist/{chunk-HZZXBTLB.js → chunk-6IN474P4.js} +25 -5
- package/dist/{chunk-KHMVB3SJ.js → chunk-7KWJEYIK.js} +4 -1
- package/dist/{chunk-R47NQICB.cjs → chunk-AGCD3EHB.cjs} +47 -10
- package/dist/{chunk-6I63VZ45.js → chunk-CXXKJBQZ.js} +5 -1
- package/dist/{chunk-6NXVDJDR.cjs → chunk-G43MNQ4C.cjs} +5 -5
- package/dist/chunk-HDK3T2QS.cjs +1159 -0
- package/dist/chunk-HF5QZS7Z.js +46 -0
- package/dist/{chunk-S7I3RI5Z.cjs → chunk-HMGWFXEC.cjs} +27 -24
- package/dist/{chunk-6NCBFBXA.js → chunk-IQ6KKXOU.js} +1 -1
- package/dist/{chunk-T6Y5FV7G.cjs → chunk-L434J57V.cjs} +10 -8
- package/dist/{chunk-UCRL6JEV.cjs → chunk-L5OWG2NA.cjs} +8 -3
- package/dist/{chunk-CZRWP6IW.cjs → chunk-N2FGYZ4Q.cjs} +8 -1
- package/dist/{chunk-GUPQ5BNA.cjs → chunk-PUR6BZFA.cjs} +112 -111
- package/dist/chunk-RB62U6MS.js +1159 -0
- package/dist/{chunk-3V746PF4.cjs → chunk-RUZQMYXH.cjs} +4 -1
- package/dist/{chunk-HGHXGCKG.cjs → chunk-SVFEVKLF.cjs} +1 -1
- package/dist/{chunk-PCNCT4ZY.js → chunk-UMS6YFA6.js} +40 -3
- package/dist/{chunk-4LGWAJDI.js → chunk-V5OOP74P.js} +5 -2
- package/dist/{chunk-BWT4IWLK.cjs → chunk-VKF3PWKR.cjs} +7 -7
- package/dist/{chunk-PQMADRCI.js → chunk-WBJ6BG4R.js} +23 -22
- package/dist/{chunk-WIYAOZZU.js → chunk-WHKNYFM2.js} +7 -2
- package/dist/{chunk-TBSPPVTT.js → chunk-XCK7QK5D.js} +1 -1
- package/dist/{chunk-F652BKMS.cjs → chunk-YN6JKAUE.cjs} +6 -2
- package/dist/{chunk-YTGF4TJR.js → chunk-ZLZKGHSZ.js} +5 -2
- package/dist/{chunk-USU2FL3N.js → chunk-ZNHB5RG6.js} +1 -1
- package/dist/commands/agentTools.d.cts +1 -1
- package/dist/commands/agentTools.d.ts +1 -1
- package/dist/commands/index.cjs +3 -0
- package/dist/commands/index.js +3 -0
- package/dist/compare/index.cjs +4 -3
- package/dist/compare/index.js +3 -2
- package/dist/diagram/index.cjs +3 -0
- package/dist/diagram/index.js +3 -0
- package/dist/diagram/tools.d.cts +1 -1
- package/dist/diagram/tools.d.ts +1 -1
- package/dist/effects/index.cjs +32 -32
- package/dist/effects/index.js +1 -1
- package/dist/effects/tools.d.cts +5 -1
- package/dist/effects/tools.d.ts +5 -1
- package/dist/export/index.cjs +4 -3
- package/dist/export/index.js +3 -2
- package/dist/extensions/index.cjs +11 -8
- package/dist/extensions/index.d.cts +1 -0
- package/dist/extensions/index.d.ts +1 -0
- package/dist/extensions/index.js +10 -7
- package/dist/extensions/safe-merge-attributes.d.cts +10 -0
- package/dist/extensions/safe-merge-attributes.d.ts +10 -0
- package/dist/generation/index.cjs +7 -1
- package/dist/generation/index.js +7 -1
- package/dist/image-editor/index.cjs +25 -18
- package/dist/image-editor/index.js +10 -3
- package/dist/image-editor/provider-effect-tools.d.cts +1 -1
- package/dist/image-editor/provider-effect-tools.d.ts +1 -1
- package/dist/image-editor/tools.d.cts +1 -1
- package/dist/image-editor/tools.d.ts +1 -1
- package/dist/index.cjs +42 -29
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +22 -9
- package/dist/paint-editor/effect-tools.d.cts +1 -1
- package/dist/paint-editor/effect-tools.d.ts +1 -1
- package/dist/paint-editor/index.cjs +18 -8
- package/dist/paint-editor/index.js +13 -3
- package/dist/paint-editor/tools.d.cts +1 -1
- package/dist/paint-editor/tools.d.ts +1 -1
- package/dist/persistence/index.cjs +3 -2
- package/dist/persistence/index.js +2 -1
- package/dist/serializers/index.cjs +5 -4
- package/dist/serializers/index.js +4 -3
- package/dist/tools/bridge-client.d.cts +3 -3
- package/dist/tools/bridge-client.d.ts +3 -3
- package/dist/tools/capture.d.cts +5 -1
- package/dist/tools/capture.d.ts +5 -1
- package/dist/tools/definitions.d.cts +2 -2
- package/dist/tools/definitions.d.ts +2 -2
- package/dist/tools/index.cjs +39 -5
- package/dist/tools/index.d.cts +4 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.js +39 -5
- package/dist/tools/mcp-server.d.cts +24 -6
- package/dist/tools/mcp-server.d.ts +24 -6
- package/dist/tools/registry.d.cts +81 -6
- package/dist/tools/registry.d.ts +81 -6
- package/dist/tools/safe-json.d.cts +27 -0
- package/dist/tools/safe-json.d.ts +27 -0
- package/dist/tools/search.d.cts +30 -0
- package/dist/tools/search.d.ts +30 -0
- package/dist/tools/skills.d.cts +26 -0
- package/dist/tools/skills.d.ts +26 -0
- package/dist/tools/view.d.cts +95 -0
- package/dist/tools/view.d.ts +95 -0
- package/dist/vector/effect-tools.d.cts +1 -1
- package/dist/vector/effect-tools.d.ts +1 -1
- package/dist/vector/index.cjs +13 -7
- package/dist/vector/index.js +8 -2
- package/dist/video-editor/effect-tools.d.cts +1 -1
- package/dist/video-editor/effect-tools.d.ts +1 -1
- package/dist/video-editor/index.cjs +275 -269
- package/dist/video-editor/index.js +8 -2
- package/dist/video-editor/tools.d.cts +1 -1
- package/dist/video-editor/tools.d.ts +1 -1
- package/package.json +31 -29
- package/skills/README.md +8 -3
- package/skills/pixerate-agent-tools/SKILL.md +33 -7
- package/skills/pixerate-animation-editor/SKILL.md +7 -0
- package/skills/pixerate-rich-text/SKILL.md +18 -4
- package/dist/chunk-5RRYDFU2.js +0 -466
- package/dist/chunk-SPVIXXIB.cjs +0 -466
- /package/dist/{chunk-SMJK5HBJ.js → chunk-K73HMKQP.js} +0 -0
- /package/dist/{chunk-DDF6WQ62.cjs → chunk-LACYURUW.cjs} +0 -0
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
createEffectToolProvider,
|
|
49
49
|
isEffectError,
|
|
50
50
|
resolveEffectValues
|
|
51
|
-
} from "../chunk-
|
|
51
|
+
} from "../chunk-7KWJEYIK.js";
|
|
52
52
|
import "../chunk-V2ZCJRDM.js";
|
|
53
53
|
import "../chunk-AGZ47XY2.js";
|
|
54
54
|
import "../chunk-ODBT55Q7.js";
|
|
@@ -206,6 +206,7 @@ var COMMAND_KEYS = {
|
|
|
206
206
|
effect: [...BASE_KEYS, "effect", "param", "to"],
|
|
207
207
|
wait: ["type", "duration", "with", "note"]
|
|
208
208
|
};
|
|
209
|
+
var MOTION_COMMAND_FIELDS = COMMAND_KEYS;
|
|
209
210
|
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
210
211
|
var isNum = (v) => typeof v === "number" && Number.isFinite(v);
|
|
211
212
|
var isPoint = (v) => isObject(v) && isNum(v.x) && isNum(v.y);
|
|
@@ -4041,106 +4042,194 @@ var DRAW_ORDER = {
|
|
|
4041
4042
|
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).")
|
|
4042
4043
|
};
|
|
4043
4044
|
var command2 = (type, description, extra = {}, required = []) => object({ type: { const: type, description }, ...BASE, ...extra }, ["type", "targets", ...required], description);
|
|
4045
|
+
var MOTION_COMMAND_TYPE_SCHEMAS = {
|
|
4046
|
+
enter: command2("enter", "Brings hidden targets in; they are hidden before this shot.", {
|
|
4047
|
+
...DRAW_ORDER,
|
|
4048
|
+
style: {
|
|
4049
|
+
type: "string",
|
|
4050
|
+
enum: [...MOTION_ENTER_STYLES],
|
|
4051
|
+
description: "fade (default), pop (scales up past full size and settles), grow (from nothing), slide, draw (outline drawn on, then the fill fades in), zoom (settles from larger), rise (rises a short way, overshooting a touch), or a reveal through a clip over the target's box: wipe (behind a travelling edge), iris (from the centre outwards) or split (from a line through the middle). Reveals need a box with a width and a height (not a lone straight line)."
|
|
4052
|
+
},
|
|
4053
|
+
direction: { type: "string", enum: [...MOTION_DIRECTIONS], description: "For slide: direction of travel (default up). For wipe: the way the edge travels (default right, revealing from the left)." },
|
|
4054
|
+
distance: { type: "number", description: "For slide (default 40) and rise (default 20): document units." },
|
|
4055
|
+
scale: { type: "number", minimum: 0, description: "For pop (default 0.5) and zoom (default 1.6): the starting scale (1 = rest size)." },
|
|
4056
|
+
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." },
|
|
4057
|
+
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." }
|
|
4058
|
+
}),
|
|
4059
|
+
exit: command2("exit", "Takes targets out.", {
|
|
4060
|
+
...DRAW_ORDER,
|
|
4061
|
+
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)." },
|
|
4062
|
+
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)." },
|
|
4063
|
+
distance: { type: "number", description: "For slide: document units (default 40)." }
|
|
4064
|
+
}),
|
|
4065
|
+
draw: 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).") }),
|
|
4066
|
+
move: 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.") }),
|
|
4067
|
+
rotate: 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." } }),
|
|
4068
|
+
scale: 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"]),
|
|
4069
|
+
fade: command2("fade", "Changes opacity.", { to: FRACTION("Opacity at the end (0\u20131).") }, ["to"]),
|
|
4070
|
+
style: command2("style", "Blends solid fill / stroke colours (in OKLab) and stroke width. On a group it changes every path in it.", {
|
|
4071
|
+
fill: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
|
|
4072
|
+
stroke: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
|
|
4073
|
+
strokeWidth: { type: "number", minimum: 0, description: "Document units." }
|
|
4074
|
+
}),
|
|
4075
|
+
play: object(
|
|
4076
|
+
{
|
|
4077
|
+
type: { const: "play", description: 'Plays a clip (set_animation_clip) on the targets: its commands, with "$" standing for each target, timed as in a shot.' },
|
|
4078
|
+
targets: NODE_IDS,
|
|
4079
|
+
clip: { type: "string", minLength: 1, description: "The clip's name (get_animation lists them)." },
|
|
4080
|
+
speed: { type: "number", minimum: 0.05, maximum: 20, description: "Play it this many times as fast (default 1)." },
|
|
4081
|
+
delay: BASE.delay,
|
|
4082
|
+
stagger: BASE.stagger,
|
|
4083
|
+
with: BASE.with,
|
|
4084
|
+
note: BASE.note
|
|
4085
|
+
},
|
|
4086
|
+
["type", "targets", "clip"],
|
|
4087
|
+
"Plays a clip on the targets."
|
|
4088
|
+
),
|
|
4089
|
+
match: 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"]),
|
|
4090
|
+
morph: 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"]),
|
|
4091
|
+
follow: command2("follow", "Moves targets along a path node, centre on the path.", {
|
|
4092
|
+
path: { type: "string", minLength: 1, description: "Id of a path node (it can be hidden)." },
|
|
4093
|
+
rotate: { type: "boolean", description: "Turn with the path (default false); moves and shakes made meanwhile turn with it too." },
|
|
4094
|
+
from: FRACTION("Where to start along the path (default 0)."),
|
|
4095
|
+
to: FRACTION("Where to end along the path (default 1).")
|
|
4096
|
+
}, ["path"]),
|
|
4097
|
+
pulse: 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)." } }),
|
|
4098
|
+
shake: command2("shake", "Shakes side to side (or up and down), settling.", {
|
|
4099
|
+
blend: BLEND("add"),
|
|
4100
|
+
amount: { type: "number", description: "Document units (default 8)." },
|
|
4101
|
+
count: { type: "integer", minimum: 1, description: "Shakes (default 3)." },
|
|
4102
|
+
axis: { type: "string", enum: ["horizontal", "vertical"], description: "Default horizontal." }
|
|
4103
|
+
}),
|
|
4104
|
+
teeter: 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)." } }),
|
|
4105
|
+
wave: 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)." } }),
|
|
4106
|
+
wiggle: 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.", {
|
|
4107
|
+
blend: BLEND("add"),
|
|
4108
|
+
amount: { type: "number", description: "Up to about this far, in document units (default 6)." },
|
|
4109
|
+
frequency: { type: "number", exclusiveMinimum: 0, description: "Wanders per second, in Hz (default 3)." },
|
|
4110
|
+
octaves: { type: "integer", minimum: 1, maximum: 8, description: "Layers of finer detail (default 2)." },
|
|
4111
|
+
rotate: { type: "number", description: "Also turns about the centre by up to about this many degrees (default 0)." },
|
|
4112
|
+
seed: { type: "integer", minimum: 0, description: "Default: one picked from the target id, so each target wanders its own way." }
|
|
4113
|
+
}),
|
|
4114
|
+
"color-pulse": command2("color-pulse", "Tints solid paint toward a colour and back (mixed in OKLab). On a group it tints every path in it.", {
|
|
4115
|
+
color: { type: "string", description: 'The tint, a CSS colour (default "#f59e0b").' },
|
|
4116
|
+
paint: { type: "string", enum: ["fill", "stroke"], description: "Which paint (default fill)." },
|
|
4117
|
+
count: { type: "integer", minimum: 1, description: "Pulses (default 1)." }
|
|
4118
|
+
}),
|
|
4119
|
+
effect: command2("effect", "Tweens a numeric parameter of a live path effect on the targets (twist angle, wiggle time, zig zag size, trim offset\u2026).", {
|
|
4120
|
+
effect: { type: "string", minLength: 1, description: `Effect id from get_animation's element "effects".` },
|
|
4121
|
+
param: { type: "string", minLength: 1, description: "A numeric parameter of that effect (listed with it)." },
|
|
4122
|
+
to: { type: "number", description: "Value at the end." }
|
|
4123
|
+
}, ["effect", "param", "to"]),
|
|
4124
|
+
wait: object(
|
|
4125
|
+
{ type: { const: "wait", description: "Waits." }, duration: MS("How long"), with: BASE.with, note: BASE.note },
|
|
4126
|
+
["type", "duration"],
|
|
4127
|
+
"Waits before the next command."
|
|
4128
|
+
)
|
|
4129
|
+
};
|
|
4044
4130
|
var MOTION_COMMAND_SCHEMA = {
|
|
4045
4131
|
description: `A command (one of ${MOTION_COMMAND_TYPES.join(", ")}). Commands in a shot play one after another unless "with": "previous".`,
|
|
4046
|
-
oneOf: [
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
distance: { type: "number", description: "For slide (default 40) and rise (default 20): document units." },
|
|
4056
|
-
scale: { type: "number", minimum: 0, description: "For pop (default 0.5) and zoom (default 1.6): the starting scale (1 = rest size)." },
|
|
4057
|
-
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." },
|
|
4058
|
-
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." }
|
|
4059
|
-
}),
|
|
4060
|
-
command2("exit", "Takes targets out.", {
|
|
4061
|
-
...DRAW_ORDER,
|
|
4062
|
-
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)." },
|
|
4063
|
-
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)." },
|
|
4064
|
-
distance: { type: "number", description: "For slide: document units (default 40)." }
|
|
4065
|
-
}),
|
|
4066
|
-
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).") }),
|
|
4067
|
-
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.") }),
|
|
4068
|
-
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." } }),
|
|
4069
|
-
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"]),
|
|
4070
|
-
command2("fade", "Changes opacity.", { to: FRACTION("Opacity at the end (0\u20131).") }, ["to"]),
|
|
4071
|
-
command2("style", "Blends solid fill / stroke colours (in OKLab) and stroke width. On a group it changes every path in it.", {
|
|
4072
|
-
fill: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
|
|
4073
|
-
stroke: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
|
|
4074
|
-
strokeWidth: { type: "number", minimum: 0, description: "Document units." }
|
|
4075
|
-
}),
|
|
4132
|
+
oneOf: MOTION_COMMAND_TYPES.map((type) => MOTION_COMMAND_TYPE_SCHEMAS[type])
|
|
4133
|
+
};
|
|
4134
|
+
var REF2 = (name, description) => ({ $ref: `#/$defs/${name}`, ...description ? { description } : {} });
|
|
4135
|
+
var firstSentence = (text) => /^.*?[.;](?=\s|$)/.exec(text)?.[0] ?? text;
|
|
4136
|
+
var COMMAND_TYPE_LINES = MOTION_COMMAND_TYPES.map((type) => `${type}: ${firstSentence(MOTION_COMMAND_TYPE_SCHEMAS[type].description ?? "")}`);
|
|
4137
|
+
var EASE_COMPACT = {
|
|
4138
|
+
description: `Easing: a preset, or a curve { "type": "cubic-bezier", x1, y1, x2, y2 }, { "type": "spring", stiffness, damping, mass, velocity } (spring presets are Figma's; with no "duration" it lasts until it settles) or { "type": "elastic", amplitude, period, mode }. Default: ease-out for entrances, ease-in-out for moves.`,
|
|
4139
|
+
anyOf: [
|
|
4140
|
+
{ type: "string", enum: [...ANIMATION_EASING_PRESETS] },
|
|
4076
4141
|
object(
|
|
4077
4142
|
{
|
|
4078
|
-
type: {
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4143
|
+
type: { type: "string", enum: ["cubic-bezier", "spring", "elastic"], description: "Curve kind." },
|
|
4144
|
+
x1: { type: "number", description: "cubic-bezier: out handle x (0\u20131)." },
|
|
4145
|
+
y1: { type: "number", description: "cubic-bezier: out handle y." },
|
|
4146
|
+
x2: { type: "number", description: "cubic-bezier: in handle x (0\u20131)." },
|
|
4147
|
+
y2: { type: "number", description: "cubic-bezier: in handle y." },
|
|
4148
|
+
stiffness: { type: "number", exclusiveMinimum: 0, description: "spring: default 170." },
|
|
4149
|
+
damping: { type: "number", minimum: 0, description: "spring: default 26, lower bounces more." },
|
|
4150
|
+
mass: { type: "number", exclusiveMinimum: 0, description: "spring: default 1." },
|
|
4151
|
+
velocity: { type: "number", description: "spring: starting speed (default 0)." },
|
|
4152
|
+
amplitude: { type: "number", minimum: 0, description: "elastic: overshoot (default 1)." },
|
|
4153
|
+
period: { type: "number", exclusiveMinimum: 0, description: "elastic: fraction of the length (default 0.3)." },
|
|
4154
|
+
mode: { type: "string", enum: ["out", "in", "in-out"], description: "elastic: default out." }
|
|
4086
4155
|
},
|
|
4087
|
-
["type"
|
|
4088
|
-
"Plays a clip on the targets."
|
|
4089
|
-
),
|
|
4090
|
-
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"]),
|
|
4091
|
-
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"]),
|
|
4092
|
-
command2("follow", "Moves targets along a path node, centre on the path.", {
|
|
4093
|
-
path: { type: "string", minLength: 1, description: "Id of a path node (it can be hidden)." },
|
|
4094
|
-
rotate: { type: "boolean", description: "Turn with the path (default false); moves and shakes made meanwhile turn with it too." },
|
|
4095
|
-
from: FRACTION("Where to start along the path (default 0)."),
|
|
4096
|
-
to: FRACTION("Where to end along the path (default 1).")
|
|
4097
|
-
}, ["path"]),
|
|
4098
|
-
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)." } }),
|
|
4099
|
-
command2("shake", "Shakes side to side (or up and down), settling.", {
|
|
4100
|
-
blend: BLEND("add"),
|
|
4101
|
-
amount: { type: "number", description: "Document units (default 8)." },
|
|
4102
|
-
count: { type: "integer", minimum: 1, description: "Shakes (default 3)." },
|
|
4103
|
-
axis: { type: "string", enum: ["horizontal", "vertical"], description: "Default horizontal." }
|
|
4104
|
-
}),
|
|
4105
|
-
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)." } }),
|
|
4106
|
-
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)." } }),
|
|
4107
|
-
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.", {
|
|
4108
|
-
blend: BLEND("add"),
|
|
4109
|
-
amount: { type: "number", description: "Up to about this far, in document units (default 6)." },
|
|
4110
|
-
frequency: { type: "number", exclusiveMinimum: 0, description: "Wanders per second, in Hz (default 3)." },
|
|
4111
|
-
octaves: { type: "integer", minimum: 1, maximum: 8, description: "Layers of finer detail (default 2)." },
|
|
4112
|
-
rotate: { type: "number", description: "Also turns about the centre by up to about this many degrees (default 0)." },
|
|
4113
|
-
seed: { type: "integer", minimum: 0, description: "Default: one picked from the target id, so each target wanders its own way." }
|
|
4114
|
-
}),
|
|
4115
|
-
command2("color-pulse", "Tints solid paint toward a colour and back (mixed in OKLab). On a group it tints every path in it.", {
|
|
4116
|
-
color: { type: "string", description: 'The tint, a CSS colour (default "#f59e0b").' },
|
|
4117
|
-
paint: { type: "string", enum: ["fill", "stroke"], description: "Which paint (default fill)." },
|
|
4118
|
-
count: { type: "integer", minimum: 1, description: "Pulses (default 1)." }
|
|
4119
|
-
}),
|
|
4120
|
-
command2("effect", "Tweens a numeric parameter of a live path effect on the targets (twist angle, wiggle time, zig zag size, trim offset\u2026).", {
|
|
4121
|
-
effect: { type: "string", minLength: 1, description: `Effect id from get_animation's element "effects".` },
|
|
4122
|
-
param: { type: "string", minLength: 1, description: "A numeric parameter of that effect (listed with it)." },
|
|
4123
|
-
to: { type: "number", description: "Value at the end." }
|
|
4124
|
-
}, ["effect", "param", "to"]),
|
|
4125
|
-
object(
|
|
4126
|
-
{ type: { const: "wait", description: "Waits." }, duration: MS("How long"), with: BASE.with, note: BASE.note },
|
|
4127
|
-
["type", "duration"],
|
|
4128
|
-
"Waits before the next command."
|
|
4156
|
+
["type"]
|
|
4129
4157
|
)
|
|
4130
4158
|
]
|
|
4131
4159
|
};
|
|
4160
|
+
var COMMAND = object(
|
|
4161
|
+
{
|
|
4162
|
+
type: {
|
|
4163
|
+
type: "string",
|
|
4164
|
+
enum: [...MOTION_COMMAND_TYPES],
|
|
4165
|
+
description: `${COMMAND_TYPE_LINES.join(" ")} The fields from blend on say which types take them; play takes no duration, ease, split, cascade, repeat or steps, and wait only duration, with and note. describe_animation_command gives a type's full schema.`
|
|
4166
|
+
},
|
|
4167
|
+
targets: { ...NODE_IDS, description: `Node ids from get_animation's "elements" (a group animates as one; "$" in a clip). Required except for wait.` },
|
|
4168
|
+
duration: MS("Length for each target (each type has a default; draw follows the path length)"),
|
|
4169
|
+
delay: MS("Wait before starting (default 0)"),
|
|
4170
|
+
stagger: MS("Start each further target this much later (default 0)"),
|
|
4171
|
+
with: BASE.with,
|
|
4172
|
+
ease: REF2("ease", "Easing (default ease-out for entrances, ease-in-out for moves)."),
|
|
4173
|
+
note: BASE.note,
|
|
4174
|
+
split: { type: "string", enum: ["letter", "word", "line"], description: "Outlined text (a group of letter paths): animate a letter, word or line at a time, staggered. get_text_layout shows the units." },
|
|
4175
|
+
cascade: { type: "string", enum: ["forward", "backward", "center", "edges", "random"], description: "With split: the order units go in (default forward)." },
|
|
4176
|
+
repeat: { type: "integer", minimum: 1, maximum: 1e3, description: 'Play it this many times (default 1); "duration" is one cycle. Not for enter or exit.' },
|
|
4177
|
+
repeatMode: { type: "string", enum: [...MOTION_REPEAT_MODES], description: "With repeat: loop (default), mirror (every other cycle backwards) or offset (carry on from where the last ended)." },
|
|
4178
|
+
steps: { type: "number", exclusiveMinimum: 0, maximum: 120, description: `Stepped time, frames per second to hold on (12 = "on twos"). Default: the scene's steps, else smooth.` },
|
|
4179
|
+
blend: { type: "string", enum: [...MOTION_BLENDS], description: 'move, rotate, scale, emphasis: "replace" is a change the next takes over from (default for move, rotate, scale), "add" a layer over the pose (default for emphasis).' },
|
|
4180
|
+
style: { type: "string", enum: [.../* @__PURE__ */ new Set([...MOTION_ENTER_STYLES, ...MOTION_EXIT_STYLES])], description: `enter: ${MOTION_ENTER_STYLES.join(", ")} (default fade). exit: ${MOTION_EXIT_STYLES.join(", ")} (default fade).` },
|
|
4181
|
+
direction: { type: "string", enum: [...MOTION_DIRECTIONS], description: "enter / exit slide or wipe: the way it travels (default up for enter slide, down for exit slide, right for wipe)." },
|
|
4182
|
+
distance: { type: "number", description: "enter / exit slide (default 40), enter rise (default 20): document units." },
|
|
4183
|
+
scale: { type: "number", minimum: 0, description: "enter pop (default 0.5) or zoom (default 1.6): the starting scale." },
|
|
4184
|
+
shape: { type: "string", enum: [...MOTION_IRIS_SHAPES], description: "enter iris: open through a circle (default) or a box." },
|
|
4185
|
+
orientation: { type: "string", enum: [...MOTION_SPLIT_ORIENTATIONS], description: "enter split: the line it opens from (default horizontal)." },
|
|
4186
|
+
order: { type: "string", enum: ["together", "sequence"], description: "draw, enter draw, exit undraw on several strokes: together (default) or sequence (one after another)." },
|
|
4187
|
+
pace: { type: "string", enum: ["time", "speed"], description: "With order together: every stroke takes the whole time (default) or all go at one speed." },
|
|
4188
|
+
align: { type: "string", enum: ["start", "end"], description: "With pace speed: start together (default) or finish together." },
|
|
4189
|
+
sortBy: { type: "string", enum: ["document", "distance"], description: "With order sequence: stacking order (default) or distance from origin." },
|
|
4190
|
+
origin: REF2("point", "With sortBy distance: where strokes are drawn out from (default the target's centre)."),
|
|
4191
|
+
from: FRACTION("draw: fraction drawn at the start (default: what is drawn now). follow: where to start along the path (default 0)."),
|
|
4192
|
+
to: { anyOf: [{ type: "number" }, REF2("point")], description: "move: point for the centre. rotate: angle in degrees. scale: factor or { x, y } factors (required). fade: opacity 0\u20131 (required). draw: fraction drawn (default 1). follow: where to end on the path (default 1). effect: the value (required)." },
|
|
4193
|
+
by: { anyOf: [{ type: "number" }, REF2("point")], description: "move: offset { x, y } in document units. rotate: degrees to turn by." },
|
|
4194
|
+
comet: FRACTION("draw: a travelling stroke this fraction of the length long (leave out from and to)."),
|
|
4195
|
+
via: { type: "array", items: REF2("point"), minItems: 1, maxItems: 64, description: 'move: waypoints the centre passes through smoothly on the way to "to" or "by".' },
|
|
4196
|
+
pacing: { type: "string", enum: ["even", "equal"], description: "move with via: steady speed (even, default) or the same time per stretch (equal)." },
|
|
4197
|
+
geometric: { type: "boolean", description: "scale: grow by a steady factor, an even zoom (default false)." },
|
|
4198
|
+
fill: { type: "string", description: "style: fill colour, CSS (hex, rgb(), rgba())." },
|
|
4199
|
+
stroke: { type: "string", description: "style: stroke colour, CSS." },
|
|
4200
|
+
strokeWidth: { type: "number", minimum: 0, description: "style: stroke width, document units." },
|
|
4201
|
+
clip: { type: "string", minLength: 1, description: "play: the clip's name (required)." },
|
|
4202
|
+
speed: { type: "number", minimum: 0.05, maximum: 20, description: "play: this many times as fast (default 1)." },
|
|
4203
|
+
into: { type: "string", minLength: 1, description: "match: id of the group to become. morph: id of the node whose shape to take (required)." },
|
|
4204
|
+
path: { type: "string", minLength: 1, description: "follow: id of a path node (required; it can be hidden)." },
|
|
4205
|
+
rotate: { type: ["boolean", "number"], description: "follow: turn with the path (boolean, default false). wiggle: also turn by up to this many degrees (default 0)." },
|
|
4206
|
+
amount: { type: "number", description: "pulse: extra scale at the peak (default 0.15). shake (8), wave (6), wiggle (6): document units." },
|
|
4207
|
+
count: { type: "integer", minimum: 1, description: "pulse, shake, teeter, wave, color-pulse: how many times." },
|
|
4208
|
+
axis: { type: "string", enum: ["horizontal", "vertical"], description: "shake: default horizontal." },
|
|
4209
|
+
angle: { type: "number", description: "teeter: degrees either way (default 8)." },
|
|
4210
|
+
frequency: { type: "number", exclusiveMinimum: 0, description: "wiggle: wanders per second, Hz (default 3)." },
|
|
4211
|
+
octaves: { type: "integer", minimum: 1, maximum: 8, description: "wiggle: layers of finer detail (default 2)." },
|
|
4212
|
+
seed: { type: "integer", minimum: 0, description: "wiggle: noise seed (default: from the target id)." },
|
|
4213
|
+
color: { type: "string", description: 'color-pulse: the tint, a CSS colour (default "#f59e0b").' },
|
|
4214
|
+
paint: { type: "string", enum: ["fill", "stroke"], description: "color-pulse: which paint (default fill)." },
|
|
4215
|
+
effect: { type: "string", minLength: 1, description: `effect: effect id from get_animation's element "effects" (required).` },
|
|
4216
|
+
param: { type: "string", minLength: 1, description: "effect: a numeric parameter of that effect (required)." }
|
|
4217
|
+
},
|
|
4218
|
+
["type"],
|
|
4219
|
+
'A command. Commands in a shot play one after another unless "with": "previous".'
|
|
4220
|
+
);
|
|
4132
4221
|
var GEOMETRIC_CAMERA = { type: "boolean", description: "Zoom at a steady rate, so a big zoom does not rush at the start (default false)." };
|
|
4133
4222
|
var CAMERA = {
|
|
4134
4223
|
description: `Where the camera looks: a rectangle { x, y, width, height } in document units, or { frame: "<node id>", padding } to frame a node (fitted to the artwork's shape). It eases there over "ms" (default 1000); the first shot cuts.`,
|
|
4135
4224
|
anyOf: [
|
|
4136
|
-
object({ x: { type: "number", description: "Left." }, y: { type: "number", description: "Top." }, width: { type: "number", exclusiveMinimum: 0, description: "Width." }, height: { type: "number", exclusiveMinimum: 0, description: "Height." }, ease:
|
|
4137
|
-
object({ frame: { type: "string", minLength: 1, description: "Node id to frame." }, padding: { type: "number", description: "Margin around it (default 24)." }, ease:
|
|
4225
|
+
object({ x: { type: "number", description: "Left." }, y: { type: "number", description: "Top." }, width: { type: "number", exclusiveMinimum: 0, description: "Width." }, height: { type: "number", exclusiveMinimum: 0, description: "Height." }, ease: REF2("ease"), ms: MS("Camera move length"), geometric: GEOMETRIC_CAMERA }, ["x", "y", "width", "height"]),
|
|
4226
|
+
object({ frame: { type: "string", minLength: 1, description: "Node id to frame." }, padding: { type: "number", description: "Margin around it (default 24)." }, ease: REF2("ease"), ms: MS("Camera move length"), geometric: GEOMETRIC_CAMERA }, ["frame"])
|
|
4138
4227
|
]
|
|
4139
4228
|
};
|
|
4140
4229
|
var SHOT_FIELDS = {
|
|
4141
4230
|
label: { type: "string", description: "What happens, in a few words." },
|
|
4142
|
-
camera:
|
|
4143
|
-
run: { type: "array", items:
|
|
4231
|
+
camera: REF2("camera"),
|
|
4232
|
+
run: { type: "array", items: REF2("command"), description: "Commands, in order." },
|
|
4144
4233
|
hold: MS("Hold after the commands (default 600)"),
|
|
4145
4234
|
speed: { type: "number", minimum: 0.05, maximum: 20, description: "Play the whole shot this many times as fast (default 1; 0.5 is half speed). fit_animation sets it." },
|
|
4146
4235
|
at: object(
|
|
@@ -4161,6 +4250,26 @@ var CONTROL = object(
|
|
|
4161
4250
|
"A colour parameter of the Flair effect made from the scene."
|
|
4162
4251
|
);
|
|
4163
4252
|
var PRESET = object({ name: { type: "string", minLength: 1, description: "Preset name." }, values: { type: "object", additionalProperties: { type: "string" }, description: "Control name \u2192 colour." } }, ["name", "values"], "Named control values.");
|
|
4253
|
+
var DEFS = {
|
|
4254
|
+
point: POINT("A point (or offset) in document units."),
|
|
4255
|
+
ease: EASE_COMPACT,
|
|
4256
|
+
command: COMMAND,
|
|
4257
|
+
camera: CAMERA,
|
|
4258
|
+
shot: SHOT
|
|
4259
|
+
};
|
|
4260
|
+
function withDefs(schema) {
|
|
4261
|
+
const used = /* @__PURE__ */ new Set();
|
|
4262
|
+
const visit = (value) => {
|
|
4263
|
+
for (const [, name] of JSON.stringify(value).matchAll(/"#\/\$defs\/(\w+)"/g)) {
|
|
4264
|
+
if (used.has(name)) continue;
|
|
4265
|
+
used.add(name);
|
|
4266
|
+
visit(DEFS[name]);
|
|
4267
|
+
}
|
|
4268
|
+
};
|
|
4269
|
+
visit(schema);
|
|
4270
|
+
if (!used.size) return schema;
|
|
4271
|
+
return { ...schema, $defs: Object.fromEntries(Object.keys(DEFS).filter((n) => used.has(n)).map((n) => [n, DEFS[n]])) };
|
|
4272
|
+
}
|
|
4164
4273
|
var SETTINGS = {
|
|
4165
4274
|
name: { type: "string", minLength: 1, description: 'Short name, e.g. "logo-reveal".' },
|
|
4166
4275
|
description: { type: ["string", "null"], description: "What it shows; null clears." },
|
|
@@ -4195,11 +4304,11 @@ var EDIT_OP = {
|
|
|
4195
4304
|
description: `One edit (${MOTION_EDIT_OPS.filter((o) => o !== "replace_scene" && o !== "set_artwork").join(", ")}), shaped like the tool of the same name with an "op" field.`,
|
|
4196
4305
|
oneOf: [
|
|
4197
4306
|
object({ op: { const: "set_settings", description: "Like set_animation_settings." }, ...SETTINGS }, ["op"]),
|
|
4198
|
-
object({ op: { const: "insert_shots", description: "Like insert_shots." }, shots: { type: "array", items:
|
|
4307
|
+
object({ op: { const: "insert_shots", description: "Like insert_shots." }, shots: { type: "array", items: REF2("shot"), minItems: 1, description: "Shots to add." }, at: { type: "integer", minimum: 0, description: "Position (default: the end)." } }, ["op", "shots"]),
|
|
4199
4308
|
object({ op: { const: "update_shot", description: "Like update_shot." }, shot: SHOT_ID, set: object({ id: SHOT.properties.id, ...SHOT_FIELDS }, [], "Fields to replace."), remove: { type: "array", items: { type: "string", enum: ["label", "camera", "hold", "speed", "at"] }, description: "Fields to clear." } }, ["op", "shot"]),
|
|
4200
4309
|
object({ op: { const: "delete_shots", description: "Like delete_shots." }, shots: { type: "array", items: SHOT_ID, minItems: 1, description: "Shot ids." } }, ["op", "shots"]),
|
|
4201
4310
|
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"]),
|
|
4202
|
-
object({ op: { const: "add_commands", description: "Like add_commands." }, shot: SHOT_ID, commands: { type: "array", items:
|
|
4311
|
+
object({ op: { const: "add_commands", description: "Like add_commands." }, shot: SHOT_ID, commands: { type: "array", items: REF2("command"), minItems: 1, description: "Commands to add." }, at: { type: "integer", minimum: 0, description: "Index in the shot's run (default: the end)." } }, ["op", "shot", "commands"]),
|
|
4203
4312
|
object({ op: { const: "update_command", description: "Like update_command." }, shot: SHOT_ID, command: { anyOf: [{ type: "integer", minimum: 0 }, { type: "string", pattern: "^\\$(\\d+|last)[.\\[]" }], description: `Index in the shot's run, or a reference to an earlier op's outcome such as "$0.indexes[0]".` }, set: { type: "object", description: "Command fields to replace." }, remove: { type: "array", items: { type: "string" }, description: "Command fields to clear." } }, ["op", "shot", "command"]),
|
|
4204
4313
|
object({ op: { const: "move_command", description: "Like move_command." }, shot: SHOT_ID, command: { anyOf: [{ type: "integer", minimum: 0 }, { type: "string", pattern: "^\\$(\\d+|last)[.\\[]" }], description: `Index in the shot's run, or a reference to an earlier op's outcome such as "$0.indexes[0]".` }, to: { type: "integer", minimum: 0, description: "New index in the run (0 = first)." } }, ["op", "shot", "command", "to"]),
|
|
4205
4314
|
object({ op: { const: "delete_commands", description: "Like delete_commands." }, shot: SHOT_ID, commands: { type: "array", items: { anyOf: [{ type: "integer", minimum: 0 }, { type: "string", pattern: "^\\$(\\d+|last)[.\\[]" }], description: `An index, or a reference to an earlier op's outcome such as "$0.indexes[0]".` }, minItems: 1, description: "Indexes in the shot's run." } }, ["op", "shot", "commands"]),
|
|
@@ -4309,6 +4418,21 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4309
4418
|
};
|
|
4310
4419
|
}
|
|
4311
4420
|
};
|
|
4421
|
+
const describeCommand = {
|
|
4422
|
+
name: "describe_animation_command",
|
|
4423
|
+
title: "Describe command types",
|
|
4424
|
+
description: "Returns the full JSON Schema of each given command type: every field it takes with its type, range, default and meaning, and which are required. The write tools list every field once in short; call this before writing a type you have not used yet or when a write rejects a field. Returns { commands: [{ type, schema }] }.",
|
|
4425
|
+
inputSchema: object(
|
|
4426
|
+
{ types: { type: "array", items: { type: "string", enum: [...MOTION_COMMAND_TYPES] }, minItems: 1, uniqueItems: true, description: `Command types, e.g. ["enter", "move"] (any of ${MOTION_COMMAND_TYPES.join(", ")}).` } },
|
|
4427
|
+
["types"]
|
|
4428
|
+
),
|
|
4429
|
+
annotations: { title: "Describe command types", ...READ },
|
|
4430
|
+
handler: ({ types }) => {
|
|
4431
|
+
for (const type of types)
|
|
4432
|
+
if (!MOTION_COMMAND_TYPES.includes(type)) throw new Error(`There is no command type ${namedWithSuggestion(type, MOTION_COMMAND_TYPES)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`);
|
|
4433
|
+
return { commands: types.map((type) => ({ type, schema: MOTION_COMMAND_TYPE_SCHEMAS[type] })) };
|
|
4434
|
+
}
|
|
4435
|
+
};
|
|
4312
4436
|
const getShot = {
|
|
4313
4437
|
name: "get_shot",
|
|
4314
4438
|
title: "Read one shot",
|
|
@@ -4640,7 +4764,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4640
4764
|
{
|
|
4641
4765
|
name: { type: "string", pattern: "^[A-Za-z_][\\w-]*$", description: 'Clip name, e.g. "pop-settle".' },
|
|
4642
4766
|
clip: {
|
|
4643
|
-
anyOf: [object({ description: { type: "string", description: "What it does, in a few words." }, run: { type: "array", items:
|
|
4767
|
+
anyOf: [object({ description: { type: "string", description: "What it does, in a few words." }, run: { type: "array", items: REF2("command"), minItems: 1, description: 'Commands, timed as in a shot; target "$" for the node it is played on. Clips cannot play clips.' } }, ["run"]), { type: "null" }],
|
|
4644
4768
|
description: "The clip, or null to delete it (refused while a play command uses it)."
|
|
4645
4769
|
}
|
|
4646
4770
|
},
|
|
@@ -4698,7 +4822,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4698
4822
|
name: "insert_shots",
|
|
4699
4823
|
title: "Add shots",
|
|
4700
4824
|
description: "Adds shots (one undo step) at a position (default: the end). Returns every shot's new timing and any issues.",
|
|
4701
|
-
inputSchema: object({ shots: { type: "array", items:
|
|
4825
|
+
inputSchema: object({ shots: { type: "array", items: REF2("shot"), minItems: 1, description: "Shots to add." }, at: { type: "integer", minimum: 0, description: "Position, 0 = first (default: the end)." } }, ["shots"]),
|
|
4702
4826
|
annotations: { title: "Add shots", ...WRITE },
|
|
4703
4827
|
handler: ({ shots, at }) => apply({ op: "insert_shots", shots, at }, "Add shots", () => ({ added: shots.map((s) => s.id) }))
|
|
4704
4828
|
};
|
|
@@ -4737,7 +4861,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4737
4861
|
name: "add_commands",
|
|
4738
4862
|
title: "Add commands to a shot",
|
|
4739
4863
|
description: "Adds commands to a shot's run (one undo step), at an index (default: the end). Returns the indexes they got, their timing and any issues.",
|
|
4740
|
-
inputSchema: object({ shot: SHOT_ID, commands: { type: "array", items:
|
|
4864
|
+
inputSchema: object({ shot: SHOT_ID, commands: { type: "array", items: REF2("command"), minItems: 1, description: "Commands to add." }, at: { type: "integer", minimum: 0, description: "Index in the run (default: the end)." } }, ["shot", "commands"]),
|
|
4741
4865
|
annotations: { title: "Add commands to a shot", ...WRITE },
|
|
4742
4866
|
handler: ({ shot, commands, at }) => {
|
|
4743
4867
|
const before = scene().shots.find((s) => s.id === shot)?.run.length ?? 0;
|
|
@@ -4757,7 +4881,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4757
4881
|
{
|
|
4758
4882
|
shot: SHOT_ID,
|
|
4759
4883
|
command: { type: "integer", minimum: 0, description: "Index in the shot's run (from get_animation)." },
|
|
4760
|
-
set: { type: "object", description: "Command fields to replace (
|
|
4884
|
+
set: { type: "object", description: "Command fields to replace (describe_animation_command lists each type's fields)." },
|
|
4761
4885
|
remove: { type: "array", items: { type: "string" }, description: 'Optional fields to clear (e.g. "delay").' }
|
|
4762
4886
|
},
|
|
4763
4887
|
["shot", "command"]
|
|
@@ -4821,7 +4945,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4821
4945
|
name: "write_animation",
|
|
4822
4946
|
title: "Replace the animation's shots",
|
|
4823
4947
|
description: "Replaces every shot (and optionally the settings and controls), keeping the artwork, as one undo step. For small changes prefer the per-operation tools. Returns the timing and issues.",
|
|
4824
|
-
inputSchema: object({ shots: { type: "array", items:
|
|
4948
|
+
inputSchema: object({ shots: { type: "array", items: REF2("shot"), description: "All shots, in order." }, ...SETTINGS, controls: { type: "array", items: CONTROL, description: "Colour controls." }, presets: { type: "array", items: PRESET, description: "Presets." } }, ["shots"]),
|
|
4825
4949
|
annotations: { title: "Replace the animation's shots", ...DESTRUCTIVE },
|
|
4826
4950
|
handler: ({ shots, controls, presets, ...settings }) => {
|
|
4827
4951
|
const current = scene();
|
|
@@ -4871,11 +4995,15 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
4871
4995
|
return { redone, ...redone ? { label } : {} };
|
|
4872
4996
|
}
|
|
4873
4997
|
};
|
|
4874
|
-
const
|
|
4875
|
-
const
|
|
4998
|
+
const finish = (tools) => tools.map((tool) => ({ ...tool, inputSchema: withDefs(tool.inputSchema) }));
|
|
4999
|
+
const reads = finish([getAnimation, getShot, describeCommand, findElements, getTextLayout, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation]);
|
|
5000
|
+
const writes = finish([setArtworkSvg, importPptx, setDrivers, setClip, copyAnimation, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo]);
|
|
4876
5001
|
return {
|
|
4877
5002
|
id: options.id ?? "animation",
|
|
4878
5003
|
namespace: options.namespace,
|
|
5004
|
+
title: "Animation editor",
|
|
5005
|
+
description: "Vector animation: artwork, shots, animation commands and their timing, Flair and Lottie import and export, PowerPoint import.",
|
|
5006
|
+
skill: "pixerate-animation-editor",
|
|
4879
5007
|
tools: () => readOnlyReason() ? reads : [...reads, ...writes],
|
|
4880
5008
|
subscribe: (notify) => {
|
|
4881
5009
|
let last = readOnlyReason();
|
|
@@ -4924,6 +5052,7 @@ Commands
|
|
|
4924
5052
|
Working method
|
|
4925
5053
|
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).
|
|
4926
5054
|
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).
|
|
5055
|
+
- The write tools list each command field once, saying which types take it; describe_animation_command gives a type's exact fields before you write one you have not used.
|
|
4927
5056
|
- In edit_animation, a later op can use what an earlier one made: "$0.indexes[0]" (the first command op 1 added), "$last.shot".
|
|
4928
5057
|
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.
|
|
4929
5058
|
- For something the viewer plays (a button, a toggle, a step-by-step explainer), set "trigger" with set_animation_settings: click plays the next shot on each click and then starts over (make the last shot put things back for a toggle), hover or press plays and rewinds, scroll scrubs.
|
|
@@ -5245,6 +5374,9 @@ function createAnimationEffectsToolProvider(controller, options = {}) {
|
|
|
5245
5374
|
return createEffectToolProvider({
|
|
5246
5375
|
id: options.id ?? "animation-effects",
|
|
5247
5376
|
namespace: options.namespace,
|
|
5377
|
+
title: "Animation effects",
|
|
5378
|
+
description: "Provider motion effects on nodes of the animation artwork.",
|
|
5379
|
+
skill: "pixerate-animation-editor",
|
|
5248
5380
|
target: { noun: "node", id: "A node id of the artwork from get_animation (a group animates as one)." },
|
|
5249
5381
|
applyUses: ["motion"],
|
|
5250
5382
|
applyDetails: "The provider animates the node and its changes become ordinary commands (enter, fade, move, pulse\u2026), in a new shot after the last one, tagged with the effect so it can be changed or removed as a whole. They preview, play and export to Flair like any command. Vector effects with their own picture go through add_vector_effect. index, enabled and opacity do not apply here.",
|
|
@@ -5318,8 +5450,10 @@ export {
|
|
|
5318
5450
|
MOTION_CAMERA_MS,
|
|
5319
5451
|
MOTION_CASCADES,
|
|
5320
5452
|
MOTION_CLIP_TARGET,
|
|
5453
|
+
MOTION_COMMAND_FIELDS,
|
|
5321
5454
|
MOTION_COMMAND_SCHEMA,
|
|
5322
5455
|
MOTION_COMMAND_TYPES,
|
|
5456
|
+
MOTION_COMMAND_TYPE_SCHEMAS,
|
|
5323
5457
|
MOTION_DEFAULT_DURATIONS,
|
|
5324
5458
|
MOTION_DEFAULT_HOLD,
|
|
5325
5459
|
MOTION_DIRECTIONS,
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* A short authoring guide for a model writing vector animations with the animation editor's
|
|
3
3
|
* tools. Static, so it caches well as part of a system prompt.
|
|
4
4
|
*/
|
|
5
|
-
export declare const ANIMATION_EDITOR_AGENT_INSTRUCTIONS = "You animate vector artwork. A scene is artwork (vector paths and groups, each with an id) plus shots.\n\nHow it plays\n- Shots play in order. A shot optionally moves the camera, plays its commands, then holds (default 600 ms).\n- Commands in a shot play one after another; give \"with\": \"previous\" to start one together with the command before, \"delay\" to wait, \"stagger\" to offset several targets.\n- Timing comes from the content: each command has a default length (enter 600 ms, move 700 ms, draw follows the path length). Only set \"duration\" to change the pace.\n- Anything that enters later is hidden until it enters. Things that never enter are visible from the start.\n- Every frame is a pure function of time: the same scene always plays the same frames.\n\nCommands\n- enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.\n- 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.\n- 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.\n- 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.\n- 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.\n- Fast motion reads better with blur: set_animation_settings { \"motionBlur\": { \"shutter\": 180 } } (stage and rendered frames only).\n- 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.\n- Reuse motion: set_animation_clip defines a clip (commands targeting \"$\"), and { \"type\": \"play\", \"clip\": name, \"targets\": [...] } plays it on any nodes (with stagger and speed). copy_animation gives other nodes one node's motion.\n- move takes \"via\" waypoints for a curved, smooth path that passes exactly through each point (steady speed by default); use it instead of chaining moves, which stop at each point.\n- enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting \"scale\".\n- morph turns a shape into another node's shape (keep the target hidden); match does the same for a whole group, part by part (Smart Animate: draw the end state as a second, hidden group whose parts share names with the first); follow moves along a path node (with \"rotate\", moves made meanwhile turn with the path).\n- Emphasis draws the eye and returns to rest: pulse (swell), shake (side to side, or \"axis\": \"vertical\"), teeter (rock), wave (bob, no settling), wiggle (seeded wander; the same seed wanders the same way) and color-pulse (tint and back).\n- Emphasis stacks on other motion: a shake during a slide shakes as it slides. Give move, rotate or scale \"blend\": \"add\" to stack them too (what they add stays); \"blend\": \"replace\" makes a change take over instead.\n- Any command but enter and exit can \"repeat\" (loop, mirror back and forth, or offset to carry on: rotate by 90, repeat 4 is a full turn); \"duration\" is one cycle.\n- Springs (\"spring-gentle\", \"spring-quick\", \"spring-bouncy\", \"spring-slow\" or { \"type\": \"spring\", \u2026 }) feel physical; leave \"duration\" out and the spring sets it.\n- To time shots to music or a voiceover: set a \"beat\" grid or \"narration\" word timings with set_animation_settings, read them with get_timing_grid, and give a shot \"at\": { \"beat\": n } or { \"word\": i }. The shot before holds until the cue; check_animation warns when a cue is missed.\n- \"steps\": 12 (on a command, or for the whole scene with set_animation_settings) holds poses \"on twos\" for a hand-drawn look. \"geometric\": true on scale or a camera zooms at an even rate.\n- Commands share their names and defaults with Flair's motion primitives (get_animation shows each one's \"flairPrimitive\"), and emphasis, reveals and follows export to Flair exactly.\n- effect tweens a numeric parameter of a live path effect already on the node (twist angle, wiggle time, zig zag size).\n\nWorking method\n1. 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).\n2. 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).\n- In edit_animation, a later op can use what an earlier one made: \"$0.indexes[0]\" (the first command op 1 added), \"$last.shot\".\n3. 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.\n- For something the viewer plays (a button, a toggle, a step-by-step explainer), set \"trigger\" with set_animation_settings: click plays the next shot on each click and then starts over (make the last shot put things back for a toggle), hover or press plays and rewinds, scroll scrubs.\n4. To make a reusable Flair effect, set_animation_controls (colour controls stand for every use of their default colour) and export_flair_effect.\n\nKeep 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.";
|
|
5
|
+
export declare const ANIMATION_EDITOR_AGENT_INSTRUCTIONS = "You animate vector artwork. A scene is artwork (vector paths and groups, each with an id) plus shots.\n\nHow it plays\n- Shots play in order. A shot optionally moves the camera, plays its commands, then holds (default 600 ms).\n- Commands in a shot play one after another; give \"with\": \"previous\" to start one together with the command before, \"delay\" to wait, \"stagger\" to offset several targets.\n- Timing comes from the content: each command has a default length (enter 600 ms, move 700 ms, draw follows the path length). Only set \"duration\" to change the pace.\n- Anything that enters later is hidden until it enters. Things that never enter are visible from the start.\n- Every frame is a pure function of time: the same scene always plays the same frames.\n\nCommands\n- enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.\n- 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.\n- 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.\n- 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.\n- 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.\n- Fast motion reads better with blur: set_animation_settings { \"motionBlur\": { \"shutter\": 180 } } (stage and rendered frames only).\n- 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.\n- Reuse motion: set_animation_clip defines a clip (commands targeting \"$\"), and { \"type\": \"play\", \"clip\": name, \"targets\": [...] } plays it on any nodes (with stagger and speed). copy_animation gives other nodes one node's motion.\n- move takes \"via\" waypoints for a curved, smooth path that passes exactly through each point (steady speed by default); use it instead of chaining moves, which stop at each point.\n- enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting \"scale\".\n- morph turns a shape into another node's shape (keep the target hidden); match does the same for a whole group, part by part (Smart Animate: draw the end state as a second, hidden group whose parts share names with the first); follow moves along a path node (with \"rotate\", moves made meanwhile turn with the path).\n- Emphasis draws the eye and returns to rest: pulse (swell), shake (side to side, or \"axis\": \"vertical\"), teeter (rock), wave (bob, no settling), wiggle (seeded wander; the same seed wanders the same way) and color-pulse (tint and back).\n- Emphasis stacks on other motion: a shake during a slide shakes as it slides. Give move, rotate or scale \"blend\": \"add\" to stack them too (what they add stays); \"blend\": \"replace\" makes a change take over instead.\n- Any command but enter and exit can \"repeat\" (loop, mirror back and forth, or offset to carry on: rotate by 90, repeat 4 is a full turn); \"duration\" is one cycle.\n- Springs (\"spring-gentle\", \"spring-quick\", \"spring-bouncy\", \"spring-slow\" or { \"type\": \"spring\", \u2026 }) feel physical; leave \"duration\" out and the spring sets it.\n- To time shots to music or a voiceover: set a \"beat\" grid or \"narration\" word timings with set_animation_settings, read them with get_timing_grid, and give a shot \"at\": { \"beat\": n } or { \"word\": i }. The shot before holds until the cue; check_animation warns when a cue is missed.\n- \"steps\": 12 (on a command, or for the whole scene with set_animation_settings) holds poses \"on twos\" for a hand-drawn look. \"geometric\": true on scale or a camera zooms at an even rate.\n- Commands share their names and defaults with Flair's motion primitives (get_animation shows each one's \"flairPrimitive\"), and emphasis, reveals and follows export to Flair exactly.\n- effect tweens a numeric parameter of a live path effect already on the node (twist angle, wiggle time, zig zag size).\n\nWorking method\n1. 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).\n2. 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).\n- The write tools list each command field once, saying which types take it; describe_animation_command gives a type's exact fields before you write one you have not used.\n- In edit_animation, a later op can use what an earlier one made: \"$0.indexes[0]\" (the first command op 1 added), \"$last.shot\".\n3. 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.\n- For something the viewer plays (a button, a toggle, a step-by-step explainer), set \"trigger\" with set_animation_settings: click plays the next shot on each click and then starts over (make the last shot put things back for a toggle), hover or press plays and rewinds, scroll scrubs.\n4. To make a reusable Flair effect, set_animation_controls (colour controls stand for every use of their default colour) and export_flair_effect.\n\nKeep 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.";
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* A short authoring guide for a model writing vector animations with the animation editor's
|
|
3
3
|
* tools. Static, so it caches well as part of a system prompt.
|
|
4
4
|
*/
|
|
5
|
-
export declare const ANIMATION_EDITOR_AGENT_INSTRUCTIONS = "You animate vector artwork. A scene is artwork (vector paths and groups, each with an id) plus shots.\n\nHow it plays\n- Shots play in order. A shot optionally moves the camera, plays its commands, then holds (default 600 ms).\n- Commands in a shot play one after another; give \"with\": \"previous\" to start one together with the command before, \"delay\" to wait, \"stagger\" to offset several targets.\n- Timing comes from the content: each command has a default length (enter 600 ms, move 700 ms, draw follows the path length). Only set \"duration\" to change the pace.\n- Anything that enters later is hidden until it enters. Things that never enter are visible from the start.\n- Every frame is a pure function of time: the same scene always plays the same frames.\n\nCommands\n- enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.\n- 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.\n- 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.\n- 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.\n- 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.\n- Fast motion reads better with blur: set_animation_settings { \"motionBlur\": { \"shutter\": 180 } } (stage and rendered frames only).\n- 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.\n- Reuse motion: set_animation_clip defines a clip (commands targeting \"$\"), and { \"type\": \"play\", \"clip\": name, \"targets\": [...] } plays it on any nodes (with stagger and speed). copy_animation gives other nodes one node's motion.\n- move takes \"via\" waypoints for a curved, smooth path that passes exactly through each point (steady speed by default); use it instead of chaining moves, which stop at each point.\n- enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting \"scale\".\n- morph turns a shape into another node's shape (keep the target hidden); match does the same for a whole group, part by part (Smart Animate: draw the end state as a second, hidden group whose parts share names with the first); follow moves along a path node (with \"rotate\", moves made meanwhile turn with the path).\n- Emphasis draws the eye and returns to rest: pulse (swell), shake (side to side, or \"axis\": \"vertical\"), teeter (rock), wave (bob, no settling), wiggle (seeded wander; the same seed wanders the same way) and color-pulse (tint and back).\n- Emphasis stacks on other motion: a shake during a slide shakes as it slides. Give move, rotate or scale \"blend\": \"add\" to stack them too (what they add stays); \"blend\": \"replace\" makes a change take over instead.\n- Any command but enter and exit can \"repeat\" (loop, mirror back and forth, or offset to carry on: rotate by 90, repeat 4 is a full turn); \"duration\" is one cycle.\n- Springs (\"spring-gentle\", \"spring-quick\", \"spring-bouncy\", \"spring-slow\" or { \"type\": \"spring\", \u2026 }) feel physical; leave \"duration\" out and the spring sets it.\n- To time shots to music or a voiceover: set a \"beat\" grid or \"narration\" word timings with set_animation_settings, read them with get_timing_grid, and give a shot \"at\": { \"beat\": n } or { \"word\": i }. The shot before holds until the cue; check_animation warns when a cue is missed.\n- \"steps\": 12 (on a command, or for the whole scene with set_animation_settings) holds poses \"on twos\" for a hand-drawn look. \"geometric\": true on scale or a camera zooms at an even rate.\n- Commands share their names and defaults with Flair's motion primitives (get_animation shows each one's \"flairPrimitive\"), and emphasis, reveals and follows export to Flair exactly.\n- effect tweens a numeric parameter of a live path effect already on the node (twist angle, wiggle time, zig zag size).\n\nWorking method\n1. 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).\n2. 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).\n- In edit_animation, a later op can use what an earlier one made: \"$0.indexes[0]\" (the first command op 1 added), \"$last.shot\".\n3. 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.\n- For something the viewer plays (a button, a toggle, a step-by-step explainer), set \"trigger\" with set_animation_settings: click plays the next shot on each click and then starts over (make the last shot put things back for a toggle), hover or press plays and rewinds, scroll scrubs.\n4. To make a reusable Flair effect, set_animation_controls (colour controls stand for every use of their default colour) and export_flair_effect.\n\nKeep 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.";
|
|
5
|
+
export declare const ANIMATION_EDITOR_AGENT_INSTRUCTIONS = "You animate vector artwork. A scene is artwork (vector paths and groups, each with an id) plus shots.\n\nHow it plays\n- Shots play in order. A shot optionally moves the camera, plays its commands, then holds (default 600 ms).\n- Commands in a shot play one after another; give \"with\": \"previous\" to start one together with the command before, \"delay\" to wait, \"stagger\" to offset several targets.\n- Timing comes from the content: each command has a default length (enter 600 ms, move 700 ms, draw follows the path length). Only set \"duration\" to change the pace.\n- Anything that enters later is hidden until it enters. Things that never enter are visible from the start.\n- Every frame is a pure function of time: the same scene always plays the same frames.\n\nCommands\n- enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.\n- 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.\n- 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.\n- 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.\n- 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.\n- Fast motion reads better with blur: set_animation_settings { \"motionBlur\": { \"shutter\": 180 } } (stage and rendered frames only).\n- 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.\n- Reuse motion: set_animation_clip defines a clip (commands targeting \"$\"), and { \"type\": \"play\", \"clip\": name, \"targets\": [...] } plays it on any nodes (with stagger and speed). copy_animation gives other nodes one node's motion.\n- move takes \"via\" waypoints for a curved, smooth path that passes exactly through each point (steady speed by default); use it instead of chaining moves, which stop at each point.\n- enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting \"scale\".\n- morph turns a shape into another node's shape (keep the target hidden); match does the same for a whole group, part by part (Smart Animate: draw the end state as a second, hidden group whose parts share names with the first); follow moves along a path node (with \"rotate\", moves made meanwhile turn with the path).\n- Emphasis draws the eye and returns to rest: pulse (swell), shake (side to side, or \"axis\": \"vertical\"), teeter (rock), wave (bob, no settling), wiggle (seeded wander; the same seed wanders the same way) and color-pulse (tint and back).\n- Emphasis stacks on other motion: a shake during a slide shakes as it slides. Give move, rotate or scale \"blend\": \"add\" to stack them too (what they add stays); \"blend\": \"replace\" makes a change take over instead.\n- Any command but enter and exit can \"repeat\" (loop, mirror back and forth, or offset to carry on: rotate by 90, repeat 4 is a full turn); \"duration\" is one cycle.\n- Springs (\"spring-gentle\", \"spring-quick\", \"spring-bouncy\", \"spring-slow\" or { \"type\": \"spring\", \u2026 }) feel physical; leave \"duration\" out and the spring sets it.\n- To time shots to music or a voiceover: set a \"beat\" grid or \"narration\" word timings with set_animation_settings, read them with get_timing_grid, and give a shot \"at\": { \"beat\": n } or { \"word\": i }. The shot before holds until the cue; check_animation warns when a cue is missed.\n- \"steps\": 12 (on a command, or for the whole scene with set_animation_settings) holds poses \"on twos\" for a hand-drawn look. \"geometric\": true on scale or a camera zooms at an even rate.\n- Commands share their names and defaults with Flair's motion primitives (get_animation shows each one's \"flairPrimitive\"), and emphasis, reveals and follows export to Flair exactly.\n- effect tweens a numeric parameter of a live path effect already on the node (twist angle, wiggle time, zig zag size).\n\nWorking method\n1. 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).\n2. 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).\n- The write tools list each command field once, saying which types take it; describe_animation_command gives a type's exact fields before you write one you have not used.\n- In edit_animation, a later op can use what an earlier one made: \"$0.indexes[0]\" (the first command op 1 added), \"$last.shot\".\n3. 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.\n- For something the viewer plays (a button, a toggle, a step-by-step explainer), set \"trigger\" with set_animation_settings: click plays the next shot on each click and then starts over (make the last shot put things back for a toggle), hover or press plays and rewinds, scroll scrubs.\n4. To make a reusable Flair effect, set_animation_controls (colour controls stand for every use of their default colour) and export_flair_effect.\n\nKeep 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.";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type MotionCommand, type MotionScene, type MotionShot } from './types.cjs';
|
|
1
|
+
import { type MotionCommand, type MotionCommandType, type MotionScene, type MotionShot } from './types.cjs';
|
|
2
2
|
/**
|
|
3
3
|
* Shape checking: whether a value is a well-formed scene, listing every problem at once.
|
|
4
4
|
* Meaning (do the ids exist, does the timing work) is `checkMotionScene`'s job.
|
|
@@ -7,6 +7,8 @@ export declare class MotionSceneFormatError extends Error {
|
|
|
7
7
|
readonly problems: string[];
|
|
8
8
|
constructor(problems: string[]);
|
|
9
9
|
}
|
|
10
|
+
/** The fields each command type takes (`source` is set by applied effects, not written by hand). */
|
|
11
|
+
export declare const MOTION_COMMAND_FIELDS: Readonly<Record<MotionCommandType, readonly string[]>>;
|
|
10
12
|
/** Problems with one command's shape (empty when well formed). `where` prefixes each. */
|
|
11
13
|
export declare function commandShapeProblems(command: unknown, where: string): string[];
|
|
12
14
|
/** Problems with a scene's `clips`: names, and each clip's commands (which may target `"$"` but not play clips). */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type MotionCommand, type MotionScene, type MotionShot } from './types.js';
|
|
1
|
+
import { type MotionCommand, type MotionCommandType, type MotionScene, type MotionShot } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Shape checking: whether a value is a well-formed scene, listing every problem at once.
|
|
4
4
|
* Meaning (do the ids exist, does the timing work) is `checkMotionScene`'s job.
|
|
@@ -7,6 +7,8 @@ export declare class MotionSceneFormatError extends Error {
|
|
|
7
7
|
readonly problems: string[];
|
|
8
8
|
constructor(problems: string[]);
|
|
9
9
|
}
|
|
10
|
+
/** The fields each command type takes (`source` is set by applied effects, not written by hand). */
|
|
11
|
+
export declare const MOTION_COMMAND_FIELDS: Readonly<Record<MotionCommandType, readonly string[]>>;
|
|
10
12
|
/** Problems with one command's shape (empty when well formed). `where` prefixes each. */
|
|
11
13
|
export declare function commandShapeProblems(command: unknown, where: string): string[];
|
|
12
14
|
/** Problems with a scene's `clips`: names, and each clip's commands (which may target `"$"` but not play clips). */
|