@pixerate/editor 0.69.0 → 0.70.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.
@@ -174,7 +174,7 @@ type MotionSplitOrientation = 'horizontal' | 'vertical';
174
174
  * Brings hidden targets in. Targets entered in a shot are hidden before it. Each style is a
175
175
  * Flair motion primitive (`entrance.<style>`) with the same defaults.
176
176
  */
177
- interface MotionEnterCommand extends MotionCommandBase {
177
+ interface MotionEnterCommand extends MotionCommandBase, MotionDrawOrder {
178
178
  type: 'enter';
179
179
  /**
180
180
  * Default `fade`. `draw` draws the outline on, then fades the fill in. `pop` scales up past
@@ -198,7 +198,7 @@ interface MotionEnterCommand extends MotionCommandBase {
198
198
  orientation?: MotionSplitOrientation;
199
199
  }
200
200
  /** Takes targets out. */
201
- interface MotionExitCommand extends MotionCommandBase {
201
+ interface MotionExitCommand extends MotionCommandBase, MotionDrawOrder {
202
202
  type: 'exit';
203
203
  /** Default `fade`. `wipe` hides the target behind an edge travelling `direction` (a wipe in, reversed). */
204
204
  style?: MotionExitStyle;
@@ -206,9 +206,33 @@ interface MotionExitCommand extends MotionCommandBase {
206
206
  direction?: MotionDirection;
207
207
  distance?: number;
208
208
  }
209
+ /**
210
+ * How the strokes of a group (or several paths) draw on or off together. Default: all at once,
211
+ * each over the whole time.
212
+ */
213
+ interface MotionDrawOrder {
214
+ /** `together` (default) or `sequence`: one stroke after another, each for a time in proportion to its length. */
215
+ order?: 'together' | 'sequence';
216
+ /** With `together`: `time` (default) gives every stroke the whole time; `speed` draws them all at one speed, so short ones take less. */
217
+ pace?: 'time' | 'speed';
218
+ /** With `pace: "speed"`: `start` (default) starts them together, `end` finishes them together. */
219
+ align?: 'start' | 'end';
220
+ /** With `sequence`: `document` (default, stacking order) or `distance` from `origin` (a radial reveal). */
221
+ sortBy?: 'document' | 'distance';
222
+ /** With `sortBy: "distance"`: the point (document units) strokes are drawn out from (default the target's centre). */
223
+ origin?: {
224
+ x: number;
225
+ y: number;
226
+ };
227
+ }
209
228
  /** Draws a stroke on (or off) between two fractions of its length. */
210
- interface MotionDrawCommand extends MotionCommandBase {
229
+ interface MotionDrawCommand extends MotionCommandBase, MotionDrawOrder {
211
230
  type: 'draw';
231
+ /**
232
+ * A travelling stroke this fraction of the length long (0–1): it runs along the path and off
233
+ * the end, instead of drawing it on and leaving it.
234
+ */
235
+ comet?: number;
212
236
  /** Fraction drawn at the end (default 1). */
213
237
  to?: number;
214
238
  /** Fraction drawn at the start (default: what is drawn now). */
@@ -1674,6 +1698,14 @@ declare function describeMotionShots(scene: MotionScene): {
1674
1698
  repeat?: number;
1675
1699
  repeatMode?: "loop" | "mirror" | "offset";
1676
1700
  steps?: number;
1701
+ order?: "together" | "sequence";
1702
+ pace?: "time" | "speed";
1703
+ align?: "start" | "end";
1704
+ sortBy?: "document" | "distance";
1705
+ origin?: {
1706
+ x: number;
1707
+ y: number;
1708
+ };
1677
1709
  index: number;
1678
1710
  } | {
1679
1711
  flairPrimitive?: string | undefined;
@@ -1693,12 +1725,21 @@ declare function describeMotionShots(scene: MotionScene): {
1693
1725
  repeat?: number;
1694
1726
  repeatMode?: "loop" | "mirror" | "offset";
1695
1727
  steps?: number;
1728
+ order?: "together" | "sequence";
1729
+ pace?: "time" | "speed";
1730
+ align?: "start" | "end";
1731
+ sortBy?: "document" | "distance";
1732
+ origin?: {
1733
+ x: number;
1734
+ y: number;
1735
+ };
1696
1736
  index: number;
1697
1737
  } | {
1698
1738
  flairPrimitive?: string | undefined;
1699
1739
  start: number;
1700
1740
  end: number;
1701
1741
  type: "draw";
1742
+ comet?: number;
1702
1743
  to?: number;
1703
1744
  from?: number;
1704
1745
  targets: string[];
@@ -1711,6 +1752,14 @@ declare function describeMotionShots(scene: MotionScene): {
1711
1752
  repeat?: number;
1712
1753
  repeatMode?: "loop" | "mirror" | "offset";
1713
1754
  steps?: number;
1755
+ order?: "together" | "sequence";
1756
+ pace?: "time" | "speed";
1757
+ align?: "start" | "end";
1758
+ sortBy?: "document" | "distance";
1759
+ origin?: {
1760
+ x: number;
1761
+ y: number;
1762
+ };
1714
1763
  index: number;
1715
1764
  } | {
1716
1765
  flairPrimitive?: string | undefined;
@@ -2060,7 +2109,7 @@ declare function createAnimationEditorToolProvider(controller: AnimationEditorCo
2060
2109
  * A short authoring guide for a model writing vector animations with the animation editor's
2061
2110
  * tools. Static, so it caches well as part of a system prompt.
2062
2111
  */
2063
- 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- 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 to start from a Flair effect and edit it).\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).\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; 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.";
2112
+ 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- 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- 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 to start from a Flair effect and edit it).\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).\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; 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.";
2064
2113
 
2065
2114
  /**
2066
2115
  * Helpers for hand-editing UIs (React's and Svelte's command inspector, ease picker, cue picker,
@@ -2207,4 +2256,4 @@ declare function parseMotionNarration(text: string): {
2207
2256
  error: string;
2208
2257
  };
2209
2258
 
2210
- export { ANIMATION_EDITOR_AGENT_INSTRUCTIONS, AnimationEditorController, type AnimationEditorOptions, type AnimationEditorSelection, type AnimationEditorState, type AnimationEditorToolProviderOptions, FLAIR_EASES, FLAIR_EXPORT_VERSION, type FlairEase, type FlairEaseName, type FlairEffectDocument, type FlairEffectOptions, type FlairExportOptions, type FlairImportOptions, type FlairImportResult, type FlairMotionExport, type FlairSpringEase, type FlairSvgAnimation, type FlairSvgMotion, type FlairVectorEffect, type LottieAnimation, type LottieExport, type LottieExportOptions, type LottieKeyframe, type LottieShape, type LottieValue, MOTION_ADDITIVE_PROPERTIES, MOTION_BLENDS, MOTION_CAMERA_MS, MOTION_CLIP_TARGET, MOTION_COMMAND_SCHEMA, MOTION_COMMAND_TYPES, MOTION_DEFAULT_DURATIONS, MOTION_DEFAULT_HOLD, MOTION_DIRECTIONS, MOTION_DRAW_EFFECT_ID, MOTION_DRAW_MS_PER_UNIT, MOTION_DRAW_RANGE, MOTION_EASE_CHOICES, MOTION_EASE_IN_OUT, MOTION_EASE_OUT, MOTION_EDIT_OPS, MOTION_ENTER_STYLES, MOTION_EXIT_STYLES, MOTION_IRIS_SHAPES, MOTION_ISSUE_CODES, MOTION_MIN_CHANGE_MS, MOTION_REPEAT_MODES, MOTION_SPEED_RANGE, MOTION_SPLIT_ORIENTATIONS, MOTION_TRIGGERS, type MotionBeatGrid, type MotionCamera, type MotionClip, type MotionClipItem, type MotionClipShape, type MotionColorPulseCommand, type MotionCommand, type MotionCommandBase, type MotionCommandTiming, type MotionCommandType, type MotionControl, type MotionCue, type MotionDirection, type MotionDrawCommand, type MotionEasingCurve, type MotionEdit, type MotionEditOp, type MotionEditResult, type MotionEffectCommand, type MotionEnterCommand, type MotionEnterStyle, type MotionExitCommand, type MotionExitStyle, type MotionFadeCommand, type MotionFieldInput, type MotionFieldKind, type MotionFieldSpec, type MotionFit, type MotionFitOptions, type MotionFollowCommand, type MotionFrame, type MotionFrameOptions, type MotionGhost, type MotionIrisShape, type MotionIssue, type MotionIssueCode, type MotionIssueSeverity, type MotionMatch, type MotionMatchCommand, type MotionMorphCommand, type MotionMoveCommand, type MotionNarration, type MotionNodeEntry, type MotionOnionSkin, type MotionOverlayOptions, type MotionPath, type MotionPathOptions, type MotionPlayCommand, type MotionPreset, type MotionProperty, type MotionPulseCommand, type MotionRect, type MotionReveal, type MotionRotateCommand, type MotionScaleCommand, type MotionScene, MotionSceneFormatError, type MotionSegment, type MotionShakeCommand, type MotionShot, type MotionShotTiming, type MotionSmoothLeg, type MotionSplitOrientation, type MotionStyleCommand, type MotionSvgOptions, type MotionTeeterCommand, type MotionTimeline, type MotionTrigger, type MotionValue, type MotionWaitCommand, type MotionWaveCommand, type MotionWiggleCommand, activeSegment, applyMotionControlValues, applyMotionEdits, checkMotionScene, clipsShapeProblems, commandShapeProblems, compileMotionScene, createAnimationEditorToolProvider, createMotionScene, defaultMotionCommand, describeMotionElements, describeMotionShots, duplicateMotionCommandEdit, fitMotionRect, fitMotionScene, fitMotionSceneEdits, flairAtLeast, flairCurveFor, flairEaseFor, formatMotionNarration, freshShotId, fromFlairSvgMotion, fromFlairVectorEffect, highlightMotionSvg, indexMotionNodes, interpolateMotionValue, isMotionCommand, isMotionShot, matchMotionNodes, motionAddTrackKey, motionBeatAt, motionBeatTime, motionClipAttrs, motionClipLayout, motionCommandDuration, motionCommandFields, motionCommandRepeat, motionCommandRows, motionCommandSummary, motionCueChoices, motionCueFromKey, motionCueKey, motionCueTime, motionCycleDuration, motionEaseKey, motionEasingCurve, motionEasingGuides, motionEasingPath, motionFieldEdit, motionFieldLabel, motionFlairPrimitive, motionFollowRoute, motionFrameAt, motionFrameToSvg, motionGhosts, motionIssue, motionIssueKey, motionIssueLine, motionMovingIds, motionNodeAtElement, motionNodeClips, motionNodeOffset, motionPath, motionPathLength, motionPathsSvg, motionRestValue, motionRevealClip, motionRevealPadding, motionRulerTicks, motionSceneShapeProblems, motionSceneToJson, motionShotAt, motionShotCueTime, motionShotTimeScale, motionStageSvg, motionTrackKey, namedWithSuggestion, parseMotionFieldInput, parseMotionNarration, parseMotionScene, resolveMotionCamera, segmentProgress, segmentValue, shotShapeProblems, smoothMotionLegs, smoothMotionTimes, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
2259
+ export { ANIMATION_EDITOR_AGENT_INSTRUCTIONS, AnimationEditorController, type AnimationEditorOptions, type AnimationEditorSelection, type AnimationEditorState, type AnimationEditorToolProviderOptions, FLAIR_EASES, FLAIR_EXPORT_VERSION, type FlairEase, type FlairEaseName, type FlairEffectDocument, type FlairEffectOptions, type FlairExportOptions, type FlairImportOptions, type FlairImportResult, type FlairMotionExport, type FlairSpringEase, type FlairSvgAnimation, type FlairSvgMotion, type FlairVectorEffect, type LottieAnimation, type LottieExport, type LottieExportOptions, type LottieKeyframe, type LottieShape, type LottieValue, MOTION_ADDITIVE_PROPERTIES, MOTION_BLENDS, MOTION_CAMERA_MS, MOTION_CLIP_TARGET, MOTION_COMMAND_SCHEMA, MOTION_COMMAND_TYPES, MOTION_DEFAULT_DURATIONS, MOTION_DEFAULT_HOLD, MOTION_DIRECTIONS, MOTION_DRAW_EFFECT_ID, MOTION_DRAW_MS_PER_UNIT, MOTION_DRAW_RANGE, MOTION_EASE_CHOICES, MOTION_EASE_IN_OUT, MOTION_EASE_OUT, MOTION_EDIT_OPS, MOTION_ENTER_STYLES, MOTION_EXIT_STYLES, MOTION_IRIS_SHAPES, MOTION_ISSUE_CODES, MOTION_MIN_CHANGE_MS, MOTION_REPEAT_MODES, MOTION_SPEED_RANGE, MOTION_SPLIT_ORIENTATIONS, MOTION_TRIGGERS, type MotionBeatGrid, type MotionCamera, type MotionClip, type MotionClipItem, type MotionClipShape, type MotionColorPulseCommand, type MotionCommand, type MotionCommandBase, type MotionCommandTiming, type MotionCommandType, type MotionControl, type MotionCue, type MotionDirection, type MotionDrawCommand, type MotionDrawOrder, type MotionEasingCurve, type MotionEdit, type MotionEditOp, type MotionEditResult, type MotionEffectCommand, type MotionEnterCommand, type MotionEnterStyle, type MotionExitCommand, type MotionExitStyle, type MotionFadeCommand, type MotionFieldInput, type MotionFieldKind, type MotionFieldSpec, type MotionFit, type MotionFitOptions, type MotionFollowCommand, type MotionFrame, type MotionFrameOptions, type MotionGhost, type MotionIrisShape, type MotionIssue, type MotionIssueCode, type MotionIssueSeverity, type MotionMatch, type MotionMatchCommand, type MotionMorphCommand, type MotionMoveCommand, type MotionNarration, type MotionNodeEntry, type MotionOnionSkin, type MotionOverlayOptions, type MotionPath, type MotionPathOptions, type MotionPlayCommand, type MotionPreset, type MotionProperty, type MotionPulseCommand, type MotionRect, type MotionReveal, type MotionRotateCommand, type MotionScaleCommand, type MotionScene, MotionSceneFormatError, type MotionSegment, type MotionShakeCommand, type MotionShot, type MotionShotTiming, type MotionSmoothLeg, type MotionSplitOrientation, type MotionStyleCommand, type MotionSvgOptions, type MotionTeeterCommand, type MotionTimeline, type MotionTrigger, type MotionValue, type MotionWaitCommand, type MotionWaveCommand, type MotionWiggleCommand, activeSegment, applyMotionControlValues, applyMotionEdits, checkMotionScene, clipsShapeProblems, commandShapeProblems, compileMotionScene, createAnimationEditorToolProvider, createMotionScene, defaultMotionCommand, describeMotionElements, describeMotionShots, duplicateMotionCommandEdit, fitMotionRect, fitMotionScene, fitMotionSceneEdits, flairAtLeast, flairCurveFor, flairEaseFor, formatMotionNarration, freshShotId, fromFlairSvgMotion, fromFlairVectorEffect, highlightMotionSvg, indexMotionNodes, interpolateMotionValue, isMotionCommand, isMotionShot, matchMotionNodes, motionAddTrackKey, motionBeatAt, motionBeatTime, motionClipAttrs, motionClipLayout, motionCommandDuration, motionCommandFields, motionCommandRepeat, motionCommandRows, motionCommandSummary, motionCueChoices, motionCueFromKey, motionCueKey, motionCueTime, motionCycleDuration, motionEaseKey, motionEasingCurve, motionEasingGuides, motionEasingPath, motionFieldEdit, motionFieldLabel, motionFlairPrimitive, motionFollowRoute, motionFrameAt, motionFrameToSvg, motionGhosts, motionIssue, motionIssueKey, motionIssueLine, motionMovingIds, motionNodeAtElement, motionNodeClips, motionNodeOffset, motionPath, motionPathLength, motionPathsSvg, motionRestValue, motionRevealClip, motionRevealPadding, motionRulerTicks, motionSceneShapeProblems, motionSceneToJson, motionShotAt, motionShotCueTime, motionShotTimeScale, motionStageSvg, motionTrackKey, namedWithSuggestion, parseMotionFieldInput, parseMotionNarration, parseMotionScene, resolveMotionCamera, segmentProgress, segmentValue, shotShapeProblems, smoothMotionLegs, smoothMotionTimes, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
@@ -174,7 +174,7 @@ type MotionSplitOrientation = 'horizontal' | 'vertical';
174
174
  * Brings hidden targets in. Targets entered in a shot are hidden before it. Each style is a
175
175
  * Flair motion primitive (`entrance.<style>`) with the same defaults.
176
176
  */
177
- interface MotionEnterCommand extends MotionCommandBase {
177
+ interface MotionEnterCommand extends MotionCommandBase, MotionDrawOrder {
178
178
  type: 'enter';
179
179
  /**
180
180
  * Default `fade`. `draw` draws the outline on, then fades the fill in. `pop` scales up past
@@ -198,7 +198,7 @@ interface MotionEnterCommand extends MotionCommandBase {
198
198
  orientation?: MotionSplitOrientation;
199
199
  }
200
200
  /** Takes targets out. */
201
- interface MotionExitCommand extends MotionCommandBase {
201
+ interface MotionExitCommand extends MotionCommandBase, MotionDrawOrder {
202
202
  type: 'exit';
203
203
  /** Default `fade`. `wipe` hides the target behind an edge travelling `direction` (a wipe in, reversed). */
204
204
  style?: MotionExitStyle;
@@ -206,9 +206,33 @@ interface MotionExitCommand extends MotionCommandBase {
206
206
  direction?: MotionDirection;
207
207
  distance?: number;
208
208
  }
209
+ /**
210
+ * How the strokes of a group (or several paths) draw on or off together. Default: all at once,
211
+ * each over the whole time.
212
+ */
213
+ interface MotionDrawOrder {
214
+ /** `together` (default) or `sequence`: one stroke after another, each for a time in proportion to its length. */
215
+ order?: 'together' | 'sequence';
216
+ /** With `together`: `time` (default) gives every stroke the whole time; `speed` draws them all at one speed, so short ones take less. */
217
+ pace?: 'time' | 'speed';
218
+ /** With `pace: "speed"`: `start` (default) starts them together, `end` finishes them together. */
219
+ align?: 'start' | 'end';
220
+ /** With `sequence`: `document` (default, stacking order) or `distance` from `origin` (a radial reveal). */
221
+ sortBy?: 'document' | 'distance';
222
+ /** With `sortBy: "distance"`: the point (document units) strokes are drawn out from (default the target's centre). */
223
+ origin?: {
224
+ x: number;
225
+ y: number;
226
+ };
227
+ }
209
228
  /** Draws a stroke on (or off) between two fractions of its length. */
210
- interface MotionDrawCommand extends MotionCommandBase {
229
+ interface MotionDrawCommand extends MotionCommandBase, MotionDrawOrder {
211
230
  type: 'draw';
231
+ /**
232
+ * A travelling stroke this fraction of the length long (0–1): it runs along the path and off
233
+ * the end, instead of drawing it on and leaving it.
234
+ */
235
+ comet?: number;
212
236
  /** Fraction drawn at the end (default 1). */
213
237
  to?: number;
214
238
  /** Fraction drawn at the start (default: what is drawn now). */
@@ -1674,6 +1698,14 @@ declare function describeMotionShots(scene: MotionScene): {
1674
1698
  repeat?: number;
1675
1699
  repeatMode?: "loop" | "mirror" | "offset";
1676
1700
  steps?: number;
1701
+ order?: "together" | "sequence";
1702
+ pace?: "time" | "speed";
1703
+ align?: "start" | "end";
1704
+ sortBy?: "document" | "distance";
1705
+ origin?: {
1706
+ x: number;
1707
+ y: number;
1708
+ };
1677
1709
  index: number;
1678
1710
  } | {
1679
1711
  flairPrimitive?: string | undefined;
@@ -1693,12 +1725,21 @@ declare function describeMotionShots(scene: MotionScene): {
1693
1725
  repeat?: number;
1694
1726
  repeatMode?: "loop" | "mirror" | "offset";
1695
1727
  steps?: number;
1728
+ order?: "together" | "sequence";
1729
+ pace?: "time" | "speed";
1730
+ align?: "start" | "end";
1731
+ sortBy?: "document" | "distance";
1732
+ origin?: {
1733
+ x: number;
1734
+ y: number;
1735
+ };
1696
1736
  index: number;
1697
1737
  } | {
1698
1738
  flairPrimitive?: string | undefined;
1699
1739
  start: number;
1700
1740
  end: number;
1701
1741
  type: "draw";
1742
+ comet?: number;
1702
1743
  to?: number;
1703
1744
  from?: number;
1704
1745
  targets: string[];
@@ -1711,6 +1752,14 @@ declare function describeMotionShots(scene: MotionScene): {
1711
1752
  repeat?: number;
1712
1753
  repeatMode?: "loop" | "mirror" | "offset";
1713
1754
  steps?: number;
1755
+ order?: "together" | "sequence";
1756
+ pace?: "time" | "speed";
1757
+ align?: "start" | "end";
1758
+ sortBy?: "document" | "distance";
1759
+ origin?: {
1760
+ x: number;
1761
+ y: number;
1762
+ };
1714
1763
  index: number;
1715
1764
  } | {
1716
1765
  flairPrimitive?: string | undefined;
@@ -2060,7 +2109,7 @@ declare function createAnimationEditorToolProvider(controller: AnimationEditorCo
2060
2109
  * A short authoring guide for a model writing vector animations with the animation editor's
2061
2110
  * tools. Static, so it caches well as part of a system prompt.
2062
2111
  */
2063
- 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- 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 to start from a Flair effect and edit it).\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).\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; 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.";
2112
+ 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- 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- 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 to start from a Flair effect and edit it).\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).\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; 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.";
2064
2113
 
2065
2114
  /**
2066
2115
  * Helpers for hand-editing UIs (React's and Svelte's command inspector, ease picker, cue picker,
@@ -2207,4 +2256,4 @@ declare function parseMotionNarration(text: string): {
2207
2256
  error: string;
2208
2257
  };
2209
2258
 
2210
- export { ANIMATION_EDITOR_AGENT_INSTRUCTIONS, AnimationEditorController, type AnimationEditorOptions, type AnimationEditorSelection, type AnimationEditorState, type AnimationEditorToolProviderOptions, FLAIR_EASES, FLAIR_EXPORT_VERSION, type FlairEase, type FlairEaseName, type FlairEffectDocument, type FlairEffectOptions, type FlairExportOptions, type FlairImportOptions, type FlairImportResult, type FlairMotionExport, type FlairSpringEase, type FlairSvgAnimation, type FlairSvgMotion, type FlairVectorEffect, type LottieAnimation, type LottieExport, type LottieExportOptions, type LottieKeyframe, type LottieShape, type LottieValue, MOTION_ADDITIVE_PROPERTIES, MOTION_BLENDS, MOTION_CAMERA_MS, MOTION_CLIP_TARGET, MOTION_COMMAND_SCHEMA, MOTION_COMMAND_TYPES, MOTION_DEFAULT_DURATIONS, MOTION_DEFAULT_HOLD, MOTION_DIRECTIONS, MOTION_DRAW_EFFECT_ID, MOTION_DRAW_MS_PER_UNIT, MOTION_DRAW_RANGE, MOTION_EASE_CHOICES, MOTION_EASE_IN_OUT, MOTION_EASE_OUT, MOTION_EDIT_OPS, MOTION_ENTER_STYLES, MOTION_EXIT_STYLES, MOTION_IRIS_SHAPES, MOTION_ISSUE_CODES, MOTION_MIN_CHANGE_MS, MOTION_REPEAT_MODES, MOTION_SPEED_RANGE, MOTION_SPLIT_ORIENTATIONS, MOTION_TRIGGERS, type MotionBeatGrid, type MotionCamera, type MotionClip, type MotionClipItem, type MotionClipShape, type MotionColorPulseCommand, type MotionCommand, type MotionCommandBase, type MotionCommandTiming, type MotionCommandType, type MotionControl, type MotionCue, type MotionDirection, type MotionDrawCommand, type MotionEasingCurve, type MotionEdit, type MotionEditOp, type MotionEditResult, type MotionEffectCommand, type MotionEnterCommand, type MotionEnterStyle, type MotionExitCommand, type MotionExitStyle, type MotionFadeCommand, type MotionFieldInput, type MotionFieldKind, type MotionFieldSpec, type MotionFit, type MotionFitOptions, type MotionFollowCommand, type MotionFrame, type MotionFrameOptions, type MotionGhost, type MotionIrisShape, type MotionIssue, type MotionIssueCode, type MotionIssueSeverity, type MotionMatch, type MotionMatchCommand, type MotionMorphCommand, type MotionMoveCommand, type MotionNarration, type MotionNodeEntry, type MotionOnionSkin, type MotionOverlayOptions, type MotionPath, type MotionPathOptions, type MotionPlayCommand, type MotionPreset, type MotionProperty, type MotionPulseCommand, type MotionRect, type MotionReveal, type MotionRotateCommand, type MotionScaleCommand, type MotionScene, MotionSceneFormatError, type MotionSegment, type MotionShakeCommand, type MotionShot, type MotionShotTiming, type MotionSmoothLeg, type MotionSplitOrientation, type MotionStyleCommand, type MotionSvgOptions, type MotionTeeterCommand, type MotionTimeline, type MotionTrigger, type MotionValue, type MotionWaitCommand, type MotionWaveCommand, type MotionWiggleCommand, activeSegment, applyMotionControlValues, applyMotionEdits, checkMotionScene, clipsShapeProblems, commandShapeProblems, compileMotionScene, createAnimationEditorToolProvider, createMotionScene, defaultMotionCommand, describeMotionElements, describeMotionShots, duplicateMotionCommandEdit, fitMotionRect, fitMotionScene, fitMotionSceneEdits, flairAtLeast, flairCurveFor, flairEaseFor, formatMotionNarration, freshShotId, fromFlairSvgMotion, fromFlairVectorEffect, highlightMotionSvg, indexMotionNodes, interpolateMotionValue, isMotionCommand, isMotionShot, matchMotionNodes, motionAddTrackKey, motionBeatAt, motionBeatTime, motionClipAttrs, motionClipLayout, motionCommandDuration, motionCommandFields, motionCommandRepeat, motionCommandRows, motionCommandSummary, motionCueChoices, motionCueFromKey, motionCueKey, motionCueTime, motionCycleDuration, motionEaseKey, motionEasingCurve, motionEasingGuides, motionEasingPath, motionFieldEdit, motionFieldLabel, motionFlairPrimitive, motionFollowRoute, motionFrameAt, motionFrameToSvg, motionGhosts, motionIssue, motionIssueKey, motionIssueLine, motionMovingIds, motionNodeAtElement, motionNodeClips, motionNodeOffset, motionPath, motionPathLength, motionPathsSvg, motionRestValue, motionRevealClip, motionRevealPadding, motionRulerTicks, motionSceneShapeProblems, motionSceneToJson, motionShotAt, motionShotCueTime, motionShotTimeScale, motionStageSvg, motionTrackKey, namedWithSuggestion, parseMotionFieldInput, parseMotionNarration, parseMotionScene, resolveMotionCamera, segmentProgress, segmentValue, shotShapeProblems, smoothMotionLegs, smoothMotionTimes, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
2259
+ export { ANIMATION_EDITOR_AGENT_INSTRUCTIONS, AnimationEditorController, type AnimationEditorOptions, type AnimationEditorSelection, type AnimationEditorState, type AnimationEditorToolProviderOptions, FLAIR_EASES, FLAIR_EXPORT_VERSION, type FlairEase, type FlairEaseName, type FlairEffectDocument, type FlairEffectOptions, type FlairExportOptions, type FlairImportOptions, type FlairImportResult, type FlairMotionExport, type FlairSpringEase, type FlairSvgAnimation, type FlairSvgMotion, type FlairVectorEffect, type LottieAnimation, type LottieExport, type LottieExportOptions, type LottieKeyframe, type LottieShape, type LottieValue, MOTION_ADDITIVE_PROPERTIES, MOTION_BLENDS, MOTION_CAMERA_MS, MOTION_CLIP_TARGET, MOTION_COMMAND_SCHEMA, MOTION_COMMAND_TYPES, MOTION_DEFAULT_DURATIONS, MOTION_DEFAULT_HOLD, MOTION_DIRECTIONS, MOTION_DRAW_EFFECT_ID, MOTION_DRAW_MS_PER_UNIT, MOTION_DRAW_RANGE, MOTION_EASE_CHOICES, MOTION_EASE_IN_OUT, MOTION_EASE_OUT, MOTION_EDIT_OPS, MOTION_ENTER_STYLES, MOTION_EXIT_STYLES, MOTION_IRIS_SHAPES, MOTION_ISSUE_CODES, MOTION_MIN_CHANGE_MS, MOTION_REPEAT_MODES, MOTION_SPEED_RANGE, MOTION_SPLIT_ORIENTATIONS, MOTION_TRIGGERS, type MotionBeatGrid, type MotionCamera, type MotionClip, type MotionClipItem, type MotionClipShape, type MotionColorPulseCommand, type MotionCommand, type MotionCommandBase, type MotionCommandTiming, type MotionCommandType, type MotionControl, type MotionCue, type MotionDirection, type MotionDrawCommand, type MotionDrawOrder, type MotionEasingCurve, type MotionEdit, type MotionEditOp, type MotionEditResult, type MotionEffectCommand, type MotionEnterCommand, type MotionEnterStyle, type MotionExitCommand, type MotionExitStyle, type MotionFadeCommand, type MotionFieldInput, type MotionFieldKind, type MotionFieldSpec, type MotionFit, type MotionFitOptions, type MotionFollowCommand, type MotionFrame, type MotionFrameOptions, type MotionGhost, type MotionIrisShape, type MotionIssue, type MotionIssueCode, type MotionIssueSeverity, type MotionMatch, type MotionMatchCommand, type MotionMorphCommand, type MotionMoveCommand, type MotionNarration, type MotionNodeEntry, type MotionOnionSkin, type MotionOverlayOptions, type MotionPath, type MotionPathOptions, type MotionPlayCommand, type MotionPreset, type MotionProperty, type MotionPulseCommand, type MotionRect, type MotionReveal, type MotionRotateCommand, type MotionScaleCommand, type MotionScene, MotionSceneFormatError, type MotionSegment, type MotionShakeCommand, type MotionShot, type MotionShotTiming, type MotionSmoothLeg, type MotionSplitOrientation, type MotionStyleCommand, type MotionSvgOptions, type MotionTeeterCommand, type MotionTimeline, type MotionTrigger, type MotionValue, type MotionWaitCommand, type MotionWaveCommand, type MotionWiggleCommand, activeSegment, applyMotionControlValues, applyMotionEdits, checkMotionScene, clipsShapeProblems, commandShapeProblems, compileMotionScene, createAnimationEditorToolProvider, createMotionScene, defaultMotionCommand, describeMotionElements, describeMotionShots, duplicateMotionCommandEdit, fitMotionRect, fitMotionScene, fitMotionSceneEdits, flairAtLeast, flairCurveFor, flairEaseFor, formatMotionNarration, freshShotId, fromFlairSvgMotion, fromFlairVectorEffect, highlightMotionSvg, indexMotionNodes, interpolateMotionValue, isMotionCommand, isMotionShot, matchMotionNodes, motionAddTrackKey, motionBeatAt, motionBeatTime, motionClipAttrs, motionClipLayout, motionCommandDuration, motionCommandFields, motionCommandRepeat, motionCommandRows, motionCommandSummary, motionCueChoices, motionCueFromKey, motionCueKey, motionCueTime, motionCycleDuration, motionEaseKey, motionEasingCurve, motionEasingGuides, motionEasingPath, motionFieldEdit, motionFieldLabel, motionFlairPrimitive, motionFollowRoute, motionFrameAt, motionFrameToSvg, motionGhosts, motionIssue, motionIssueKey, motionIssueLine, motionMovingIds, motionNodeAtElement, motionNodeClips, motionNodeOffset, motionPath, motionPathLength, motionPathsSvg, motionRestValue, motionRevealClip, motionRevealPadding, motionRulerTicks, motionSceneShapeProblems, motionSceneToJson, motionShotAt, motionShotCueTime, motionShotTimeScale, motionStageSvg, motionTrackKey, namedWithSuggestion, parseMotionFieldInput, parseMotionNarration, parseMotionScene, resolveMotionCamera, segmentProgress, segmentValue, shotShapeProblems, smoothMotionLegs, smoothMotionTimes, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
@@ -223,10 +223,11 @@ var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips",
223
223
  var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
224
224
  var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric"];
225
225
  var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps"];
226
+ var DRAW_ORDER_KEYS = ["order", "pace", "align", "sortBy", "origin"];
226
227
  var COMMAND_KEYS = {
227
- enter: [...BASE_KEYS, "style", "direction", "distance", "scale", "shape", "orientation"],
228
- exit: [...BASE_KEYS, "style", "direction", "distance"],
229
- draw: [...BASE_KEYS, "from", "to"],
228
+ enter: [...BASE_KEYS, ...DRAW_ORDER_KEYS, "style", "direction", "distance", "scale", "shape", "orientation"],
229
+ exit: [...BASE_KEYS, ...DRAW_ORDER_KEYS, "style", "direction", "distance"],
230
+ draw: [...BASE_KEYS, ...DRAW_ORDER_KEYS, "from", "to", "comet"],
230
231
  move: [...BASE_KEYS, "by", "to", "via", "pacing", "blend"],
231
232
  rotate: [...BASE_KEYS, "by", "to", "blend"],
232
233
  scale: [...BASE_KEYS, "to", "geometric", "blend"],
@@ -270,6 +271,14 @@ function commandShapeProblems(command2, where) {
270
271
  if (command2[key] !== void 0 && !isNum(command2[key])) p(`"${key}" must be a number.`);
271
272
  };
272
273
  if (command2.with !== void 0 && command2.with !== "after" && command2.with !== "previous") p(`"with" must be "after" or "previous".`);
274
+ if (DRAW_ORDER_KEYS.some((k) => command2[k] !== void 0)) {
275
+ if (type === "enter" && command2.style !== "draw" || type === "exit" && command2.style !== "undraw") p(`"order", "pace", "align", "sortBy" and "origin" go with drawing: style "${type === "enter" ? "draw" : "undraw"}".`);
276
+ if (command2.order !== void 0 && command2.order !== "together" && command2.order !== "sequence") p(`"order" must be "together" or "sequence" (one stroke after another).`);
277
+ if (command2.pace !== void 0 && command2.pace !== "time" && command2.pace !== "speed") p(`"pace" must be "time" (each stroke takes the whole time) or "speed" (all at one speed).`);
278
+ if (command2.align !== void 0 && command2.align !== "start" && command2.align !== "end") p(`"align" must be "start" or "end".`);
279
+ if (command2.sortBy !== void 0 && command2.sortBy !== "document" && command2.sortBy !== "distance") p(`"sortBy" must be "document" or "distance".`);
280
+ if (command2.origin !== void 0 && !isPoint(command2.origin)) p(`"origin" must be { "x": number, "y": number } (document units).`);
281
+ }
273
282
  if (command2.note !== void 0 && typeof command2.note !== "string") p(`"note" must be a string.`);
274
283
  if (type === "wait") {
275
284
  if (!isNum(command2.duration) || command2.duration < 0) p(`"duration" must be a number of milliseconds \u2265 0.`);
@@ -303,6 +312,8 @@ function commandShapeProblems(command2, where) {
303
312
  case "draw":
304
313
  fraction("from");
305
314
  fraction("to");
315
+ fraction("comet");
316
+ if (command2.comet !== void 0 && (command2.from !== void 0 || command2.to !== void 0)) p(`"comet" runs the whole path; leave out "from" and "to".`);
306
317
  break;
307
318
  case "move":
308
319
  if (command2.by === void 0 && command2.to === void 0) p(`give "by" (an offset) or "to" (a point).`);
@@ -1003,6 +1014,43 @@ function compileMotionScene(scene) {
1003
1014
  return typeof v === "number" ? v : 0;
1004
1015
  };
1005
1016
  const ease = command2.ease;
1017
+ const drawWindows = (s, e, o) => {
1018
+ const order2 = o.order ?? "together";
1019
+ const pace = o.pace ?? "time";
1020
+ if (order2 === "together" && pace === "time") return null;
1021
+ const paths = entry.node.type === "path" ? [entry.node] : collectPathNodes(entry.node);
1022
+ let list = paths.map((p) => {
1023
+ const at = nodes.get(p.id);
1024
+ let first = { x: 0, y: 0 };
1025
+ try {
1026
+ const m = vectorPathWorldBezier(p, at?.parentWorld ?? IDENTITY_MATRIX, { effects: false })[0];
1027
+ if (m && m.type === "M") first = { x: m.x, y: m.y };
1028
+ } catch {
1029
+ }
1030
+ return { id: p.id, len: Math.max(1e-6, motionPathLength(p, at?.parentWorld)), first };
1031
+ });
1032
+ if (!list.length) return null;
1033
+ const span = Math.max(0, e - s);
1034
+ if (order2 === "sequence") {
1035
+ if (o.sortBy === "distance") {
1036
+ const b = entry.bounds;
1037
+ const origin = o.origin ?? (b ? { x: b.x + b.width / 2, y: b.y + b.height / 2 } : { x: 0, y: 0 });
1038
+ list = [...list].sort((a, c) => Math.hypot(a.first.x - origin.x, a.first.y - origin.y) - Math.hypot(c.first.x - origin.x, c.first.y - origin.y));
1039
+ }
1040
+ const total = list.reduce((sum, p) => sum + p.len, 0);
1041
+ let at = s;
1042
+ return list.map((p) => {
1043
+ const w = { id: p.id, start: at, end: at + span * p.len / total };
1044
+ at = w.end;
1045
+ return w;
1046
+ });
1047
+ }
1048
+ const longest = Math.max(...list.map((p) => p.len));
1049
+ return list.map((p) => {
1050
+ const d = span * p.len / longest;
1051
+ return o.align === "end" ? { id: p.id, start: e - d, end: e } : { id: p.id, start: s, end: s + d };
1052
+ });
1053
+ };
1006
1054
  switch (command2.type) {
1007
1055
  case "enter": {
1008
1056
  const style = command2.style ?? "fade";
@@ -1015,7 +1063,9 @@ function compileMotionScene(scene) {
1015
1063
  break;
1016
1064
  }
1017
1065
  if (style === "draw") {
1018
- seg("drawEnd", 1, ease ?? MOTION_EASE_IN_OUT, start, start + duration2 * 0.75, { from: 0 });
1066
+ const windows = drawWindows(start, start + duration2 * 0.75, command2);
1067
+ if (windows) for (const w of windows) push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: 0, to: 1, ease: ease ?? MOTION_EASE_IN_OUT, ...where });
1068
+ else seg("drawEnd", 1, ease ?? MOTION_EASE_IN_OUT, start, start + duration2 * 0.75, { from: 0 });
1019
1069
  seg("fillOpacity", 1, MOTION_EASE_OUT, start + duration2 * 0.6, end, { from: 0 });
1020
1070
  break;
1021
1071
  }
@@ -1049,7 +1099,9 @@ function compileMotionScene(scene) {
1049
1099
  if (wipe) seg(wipe.property, wipe.to, ease ?? "ease-in", start, end, { from: wipe.from });
1050
1100
  else if (style === "undraw") {
1051
1101
  seg("fillOpacity", 0, "ease-in", start, start + duration2 * 0.4);
1052
- seg("drawEnd", 0, ease ?? MOTION_EASE_IN_OUT);
1102
+ const windows = drawWindows(start, end, command2);
1103
+ if (windows) for (const w of windows) push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: valueAt(w.id, "drawEnd", w.start), to: 0, ease: ease ?? MOTION_EASE_IN_OUT, ...where });
1104
+ else seg("drawEnd", 0, ease ?? MOTION_EASE_IN_OUT);
1053
1105
  } else if (style === "shrink") {
1054
1106
  seg("scaleX", 0, ease ?? "ease-in");
1055
1107
  seg("scaleY", 0, ease ?? "ease-in");
@@ -1064,8 +1116,18 @@ function compileMotionScene(scene) {
1064
1116
  break;
1065
1117
  }
1066
1118
  case "draw": {
1067
- const drawn = tracks.has(motionTrackKey(node, "drawEnd"));
1068
- seg("drawEnd", command2.to ?? 1, ease ?? MOTION_EASE_IN_OUT, start, end, command2.from !== void 0 ? { from: command2.from } : drawn ? {} : { from: 0 });
1119
+ const e = ease ?? MOTION_EASE_IN_OUT;
1120
+ const comet = command2.comet !== void 0 ? Math.min(1, Math.max(0, command2.comet)) : void 0;
1121
+ const windows = drawWindows(start, end, command2) ?? [{ id: node, start, end }];
1122
+ for (const w of windows) {
1123
+ if (comet !== void 0) {
1124
+ push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: 0, to: 1 + comet, ease: e, ...where });
1125
+ push({ node: w.id, property: "drawStart", start: w.start, end: w.end, from: -comet, to: 1, ease: e, ...where });
1126
+ continue;
1127
+ }
1128
+ const drawn = tracks.has(motionTrackKey(w.id, "drawEnd"));
1129
+ push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: command2.from ?? (drawn ? valueAt(w.id, "drawEnd", w.start) : 0), to: command2.to ?? 1, ease: e, ...where });
1130
+ }
1069
1131
  break;
1070
1132
  }
1071
1133
  case "move": {
@@ -1510,7 +1572,11 @@ function visibleAt(timeline, id, time, node) {
1510
1572
  const circle = clip("clipCircle");
1511
1573
  if (Array.isArray(circle) && circle[2] <= 1e-4) return false;
1512
1574
  const hasFill = node.type === "path" ? !!node.fill && node.fill !== "none" : collectPathNodes(node).some((p) => p.fill && p.fill !== "none");
1513
- return num("drawEnd", 1) > 0.01 || hasFill && num("fillOpacity", 1) > 0.01;
1575
+ const drawn = num("drawEnd", 1) > 0.01 && (node.type === "path" || collectPathNodes(node).length === 0 || collectPathNodes(node).some((p) => {
1576
+ const v = trackValue(timeline.tracks.get(motionTrackKey(p.id, "drawEnd")), time);
1577
+ return typeof v !== "number" || v > 0.01;
1578
+ }));
1579
+ return drawn || hasFill && num("fillOpacity", 1) > 0.01;
1514
1580
  }
1515
1581
  function checkMotionScene(scene) {
1516
1582
  const issues = [];
@@ -2681,11 +2747,13 @@ function toLottie(scene, options = {}) {
2681
2747
  const widthFrom = owner(path, "strokeWidth");
2682
2748
  const fadeFrom = owner(path, "fillOpacity");
2683
2749
  const drawFrom = owner(path, "drawEnd");
2684
- if (drawFrom) {
2685
- const draw = track(drawFrom, "drawEnd");
2686
- items.push({ ty: "tm", nm: "Draw on", s: { a: 0, k: 0 }, e: animate(draw, (t) => [Math.min(1, Math.max(0, Number(trackValue(draw, t) ?? 1))) * 100]), o: { a: 0, k: 0 }, m: 1 });
2750
+ const tailFrom = owner(path, "drawStart");
2751
+ if (drawFrom || tailFrom) {
2752
+ const pct = (track2, fallback) => (t) => [Math.min(1, Math.max(0, Number(trackValue(track2, t) ?? fallback))) * 100];
2753
+ const head = drawFrom ? track(drawFrom, "drawEnd") : [];
2754
+ const tail = tailFrom ? track(tailFrom, "drawStart") : [];
2755
+ items.push({ ty: "tm", nm: "Draw on", s: tail.length ? animate(tail, pct(tail, 0)) : { a: 0, k: 0 }, e: head.length ? animate(head, pct(head, 1)) : { a: 0, k: 100 }, o: { a: 0, k: 0 }, m: 1 });
2687
2756
  }
2688
- if (owner(path, "drawStart")) notes.push(`"${path.id}": drawing from a start other than 0 is not exported.`);
2689
2757
  const stroke = paintOf(path.stroke, "stroke", path.id);
2690
2758
  if (stroke || strokeFrom) {
2691
2759
  const colour = strokeFrom ? track(strokeFrom, "stroke") : [];
@@ -3071,11 +3139,19 @@ var BLEND = (fallback) => ({
3071
3139
  enum: [...MOTION_BLENDS],
3072
3140
  description: `"add" makes it a layer over the pose that stacks with other changes (a shake on a slide); "replace" makes it a change the next one takes over from (default ${fallback}).`
3073
3141
  });
3142
+ var DRAW_ORDER = {
3143
+ order: { type: "string", enum: ["together", "sequence"], description: "For drawing a group or several paths: together (default) or sequence (one stroke after another, each for a time in proportion to its length)." },
3144
+ pace: { type: "string", enum: ["time", "speed"], description: "With together: time (default, every stroke takes the whole time) or speed (all at one speed, so short strokes take less)." },
3145
+ align: { type: "string", enum: ["start", "end"], description: "With pace speed: start them together (default) or finish them together." },
3146
+ sortBy: { type: "string", enum: ["document", "distance"], description: "With sequence: stacking order (default) or distance from origin (a radial reveal)." },
3147
+ 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).")
3148
+ };
3074
3149
  var command = (type, description, extra = {}, required = []) => object({ type: { const: type, description }, ...BASE, ...extra }, ["type", "targets", ...required], description);
3075
3150
  var MOTION_COMMAND_SCHEMA = {
3076
3151
  description: `A command (one of ${MOTION_COMMAND_TYPES.join(", ")}). Commands in a shot play one after another unless "with": "previous".`,
3077
3152
  oneOf: [
3078
3153
  command("enter", "Brings hidden targets in; they are hidden before this shot.", {
3154
+ ...DRAW_ORDER,
3079
3155
  style: {
3080
3156
  type: "string",
3081
3157
  enum: [...MOTION_ENTER_STYLES],
@@ -3088,11 +3164,12 @@ var MOTION_COMMAND_SCHEMA = {
3088
3164
  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." }
3089
3165
  }),
3090
3166
  command("exit", "Takes targets out.", {
3167
+ ...DRAW_ORDER,
3091
3168
  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)." },
3092
3169
  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)." },
3093
3170
  distance: { type: "number", description: "For slide: document units (default 40)." }
3094
3171
  }),
3095
- command("draw", "Draws strokes on (or off) to a fraction of their length.", { to: FRACTION("Fraction drawn at the end (default 1)."), from: FRACTION("Fraction drawn at the start (default: what is drawn now).") }),
3172
+ command("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).") }),
3096
3173
  command("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.") }),
3097
3174
  command("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." } }),
3098
3175
  command("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"]),
@@ -3840,6 +3917,7 @@ Commands
3840
3917
  - enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.
3841
3918
  - 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.
3842
3919
  - 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.
3920
+ - 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.
3843
3921
  - 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.
3844
3922
  - 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.
3845
3923
  - enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting "scale".