@pixerate/editor 0.72.0 → 0.73.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.
@@ -61,6 +61,11 @@ interface MotionScene {
61
61
  * foreground (parallax), a wheel turning as it rolls. Each adds to what its target's commands do.
62
62
  */
63
63
  drivers?: MotionDriver[];
64
+ /**
65
+ * Motion blur on the stage and in rendered frames (not in exports): each frame averages a few
66
+ * moments across the shutter, more for faster motion.
67
+ */
68
+ motionBlur?: MotionBlur;
64
69
  /** Parameters a Flair effect made from this scene exposes (see `toFlairVectorEffect`). */
65
70
  controls?: MotionControl[];
66
71
  /** Named sets of control values. */
@@ -336,6 +341,13 @@ interface MotionClip {
336
341
  /** Commands, timed as in a shot; `"$"` in `targets` stands for the node played on. Clips cannot play clips. */
337
342
  run: MotionCommand[];
338
343
  }
344
+ /** Motion blur: how long the shutter is open and how many moments a frame averages at most. */
345
+ interface MotionBlur {
346
+ /** Shutter angle in degrees of a frame at the scene's fps (default 180: half a frame; 360 is a whole frame). */
347
+ shutter?: number;
348
+ /** Most moments a frame averages (default 8, at most 32); fewer for slower motion. */
349
+ samples?: number;
350
+ }
339
351
  /** Properties a driver reads and drives: offsets (document units), turn (degrees), scales and opacity. */
340
352
  type MotionDrivenProperty = 'x' | 'y' | 'rotation' | 'scaleX' | 'scaleY' | 'opacity';
341
353
  declare const MOTION_DRIVEN_PROPERTIES: readonly MotionDrivenProperty[];
@@ -1147,7 +1159,15 @@ interface MotionOverlayOptions {
1147
1159
  motionPaths?: boolean | readonly string[];
1148
1160
  /** Colour of motion paths (default `#f43f5e`). */
1149
1161
  motionPathColor?: string;
1162
+ /** Motion blur (default: the scene's `motionBlur`; false for none). */
1163
+ motionBlur?: MotionBlur | false;
1150
1164
  }
1165
+ /**
1166
+ * The moments a frame at `time` averages for motion blur: spread across the shutter (centred on
1167
+ * `time`), as many as the fastest moving node needs to look smooth (about one per 1.5 document
1168
+ * units it travels), and just `[time]` when nothing moves.
1169
+ */
1170
+ declare function motionBlurTimes(scene: MotionScene, time: number, blur?: MotionBlur): number[];
1151
1171
  /**
1152
1172
  * The frame at `time` as SVG with overlays: ghost frames under it (each with its own id prefix,
1153
1173
  * element ids dropped so they never clash) and motion paths over it. Without overlays it is
@@ -1190,6 +1210,7 @@ type MotionEdit = {
1190
1210
  fps?: number;
1191
1211
  steps?: number | null;
1192
1212
  beat?: MotionScene['beat'] | null;
1213
+ motionBlur?: MotionScene['motionBlur'] | null;
1193
1214
  narration?: MotionScene['narration'] | null;
1194
1215
  target?: [number, number] | null;
1195
1216
  } | {
@@ -2203,7 +2224,7 @@ declare function createAnimationEditorToolProvider(controller: AnimationEditorCo
2203
2224
  * A short authoring guide for a model writing vector animations with the animation editor's
2204
2225
  * tools. Static, so it caches well as part of a system prompt.
2205
2226
  */
2206
- 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- 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 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).\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.";
2227
+ 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- 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 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).\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.";
2207
2228
 
2208
2229
  /**
2209
2230
  * Helpers for hand-editing UIs (React's and Svelte's command inspector, ease picker, cue picker,
@@ -2358,4 +2379,4 @@ declare function parseMotionDrivers(text: string): {
2358
2379
  error: string;
2359
2380
  };
2360
2381
 
2361
- 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_DRIVEN_PROPERTIES, 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 MotionContactSheetOptions, type MotionControl, type MotionCue, type MotionDirection, type MotionDrawCommand, type MotionDrawOrder, type MotionDrivenProperty, type MotionDriver, type MotionEasingCurve, type MotionEdit, type MotionEditOp, type MotionEditOutcome, 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, applyMotionDrivers, applyMotionEdits, checkMotionScene, clipsShapeProblems, commandShapeProblems, compileMotionScene, createAnimationEditorToolProvider, createMotionScene, defaultMotionCommand, describeMotionElements, describeMotionShots, driversShapeProblems, duplicateMotionCommandEdit, fitMotionRect, fitMotionScene, fitMotionSceneEdits, flairAtLeast, flairCurveFor, flairEaseFor, formatMotionDrivers, formatMotionNarration, freshShotId, fromFlairSvgMotion, fromFlairVectorEffect, highlightMotionSvg, indexMotionNodes, interpolateMotionValue, isMotionCommand, isMotionShot, matchMotionNodes, motionAddTrackKey, motionBeatAt, motionBeatTime, motionClipAttrs, motionClipLayout, motionCommandDuration, motionCommandFields, motionCommandRepeat, motionCommandRows, motionCommandSummary, motionContactSheetSvg, motionCueChoices, motionCueFromKey, motionCueKey, motionCueTime, motionCycleDuration, motionDrivenNodes, motionDriverSources, motionEaseKey, motionEasingCurve, motionEasingGuides, motionEasingPath, motionFieldEdit, motionFieldLabel, motionFlairPrimitive, motionFollowRoute, motionFrameAt, motionFrameToSvg, motionGhosts, motionIssue, motionIssueKey, motionIssueLine, motionMovingIds, motionNodeAtElement, motionNodeClips, motionNodeOffset, motionPath, motionPathLength, motionPathsSvg, motionPropertyValue, motionRestValue, motionRevealClip, motionRevealPadding, motionRulerTicks, motionSceneShapeProblems, motionSceneToJson, motionShotAt, motionShotCueTime, motionShotTimeScale, motionStageSvg, motionTrackKey, namedWithSuggestion, parseMotionDrivers, parseMotionFieldInput, parseMotionNarration, parseMotionScene, resolveMotionCamera, resolveMotionEditRefs, segmentProgress, segmentValue, shotShapeProblems, smoothMotionLegs, smoothMotionTimes, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
2382
+ 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_DRIVEN_PROPERTIES, 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 MotionBlur, type MotionCamera, type MotionClip, type MotionClipItem, type MotionClipShape, type MotionColorPulseCommand, type MotionCommand, type MotionCommandBase, type MotionCommandTiming, type MotionCommandType, type MotionContactSheetOptions, type MotionControl, type MotionCue, type MotionDirection, type MotionDrawCommand, type MotionDrawOrder, type MotionDrivenProperty, type MotionDriver, type MotionEasingCurve, type MotionEdit, type MotionEditOp, type MotionEditOutcome, 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, applyMotionDrivers, applyMotionEdits, checkMotionScene, clipsShapeProblems, commandShapeProblems, compileMotionScene, createAnimationEditorToolProvider, createMotionScene, defaultMotionCommand, describeMotionElements, describeMotionShots, driversShapeProblems, duplicateMotionCommandEdit, fitMotionRect, fitMotionScene, fitMotionSceneEdits, flairAtLeast, flairCurveFor, flairEaseFor, formatMotionDrivers, formatMotionNarration, freshShotId, fromFlairSvgMotion, fromFlairVectorEffect, highlightMotionSvg, indexMotionNodes, interpolateMotionValue, isMotionCommand, isMotionShot, matchMotionNodes, motionAddTrackKey, motionBeatAt, motionBeatTime, motionBlurTimes, motionClipAttrs, motionClipLayout, motionCommandDuration, motionCommandFields, motionCommandRepeat, motionCommandRows, motionCommandSummary, motionContactSheetSvg, motionCueChoices, motionCueFromKey, motionCueKey, motionCueTime, motionCycleDuration, motionDrivenNodes, motionDriverSources, motionEaseKey, motionEasingCurve, motionEasingGuides, motionEasingPath, motionFieldEdit, motionFieldLabel, motionFlairPrimitive, motionFollowRoute, motionFrameAt, motionFrameToSvg, motionGhosts, motionIssue, motionIssueKey, motionIssueLine, motionMovingIds, motionNodeAtElement, motionNodeClips, motionNodeOffset, motionPath, motionPathLength, motionPathsSvg, motionPropertyValue, motionRestValue, motionRevealClip, motionRevealPadding, motionRulerTicks, motionSceneShapeProblems, motionSceneToJson, motionShotAt, motionShotCueTime, motionShotTimeScale, motionStageSvg, motionTrackKey, namedWithSuggestion, parseMotionDrivers, parseMotionFieldInput, parseMotionNarration, parseMotionScene, resolveMotionCamera, resolveMotionEditRefs, segmentProgress, segmentValue, shotShapeProblems, smoothMotionLegs, smoothMotionTimes, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
@@ -61,6 +61,11 @@ interface MotionScene {
61
61
  * foreground (parallax), a wheel turning as it rolls. Each adds to what its target's commands do.
62
62
  */
63
63
  drivers?: MotionDriver[];
64
+ /**
65
+ * Motion blur on the stage and in rendered frames (not in exports): each frame averages a few
66
+ * moments across the shutter, more for faster motion.
67
+ */
68
+ motionBlur?: MotionBlur;
64
69
  /** Parameters a Flair effect made from this scene exposes (see `toFlairVectorEffect`). */
65
70
  controls?: MotionControl[];
66
71
  /** Named sets of control values. */
@@ -336,6 +341,13 @@ interface MotionClip {
336
341
  /** Commands, timed as in a shot; `"$"` in `targets` stands for the node played on. Clips cannot play clips. */
337
342
  run: MotionCommand[];
338
343
  }
344
+ /** Motion blur: how long the shutter is open and how many moments a frame averages at most. */
345
+ interface MotionBlur {
346
+ /** Shutter angle in degrees of a frame at the scene's fps (default 180: half a frame; 360 is a whole frame). */
347
+ shutter?: number;
348
+ /** Most moments a frame averages (default 8, at most 32); fewer for slower motion. */
349
+ samples?: number;
350
+ }
339
351
  /** Properties a driver reads and drives: offsets (document units), turn (degrees), scales and opacity. */
340
352
  type MotionDrivenProperty = 'x' | 'y' | 'rotation' | 'scaleX' | 'scaleY' | 'opacity';
341
353
  declare const MOTION_DRIVEN_PROPERTIES: readonly MotionDrivenProperty[];
@@ -1147,7 +1159,15 @@ interface MotionOverlayOptions {
1147
1159
  motionPaths?: boolean | readonly string[];
1148
1160
  /** Colour of motion paths (default `#f43f5e`). */
1149
1161
  motionPathColor?: string;
1162
+ /** Motion blur (default: the scene's `motionBlur`; false for none). */
1163
+ motionBlur?: MotionBlur | false;
1150
1164
  }
1165
+ /**
1166
+ * The moments a frame at `time` averages for motion blur: spread across the shutter (centred on
1167
+ * `time`), as many as the fastest moving node needs to look smooth (about one per 1.5 document
1168
+ * units it travels), and just `[time]` when nothing moves.
1169
+ */
1170
+ declare function motionBlurTimes(scene: MotionScene, time: number, blur?: MotionBlur): number[];
1151
1171
  /**
1152
1172
  * The frame at `time` as SVG with overlays: ghost frames under it (each with its own id prefix,
1153
1173
  * element ids dropped so they never clash) and motion paths over it. Without overlays it is
@@ -1190,6 +1210,7 @@ type MotionEdit = {
1190
1210
  fps?: number;
1191
1211
  steps?: number | null;
1192
1212
  beat?: MotionScene['beat'] | null;
1213
+ motionBlur?: MotionScene['motionBlur'] | null;
1193
1214
  narration?: MotionScene['narration'] | null;
1194
1215
  target?: [number, number] | null;
1195
1216
  } | {
@@ -2203,7 +2224,7 @@ declare function createAnimationEditorToolProvider(controller: AnimationEditorCo
2203
2224
  * A short authoring guide for a model writing vector animations with the animation editor's
2204
2225
  * tools. Static, so it caches well as part of a system prompt.
2205
2226
  */
2206
- 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- 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 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).\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.";
2227
+ 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- 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 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).\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.";
2207
2228
 
2208
2229
  /**
2209
2230
  * Helpers for hand-editing UIs (React's and Svelte's command inspector, ease picker, cue picker,
@@ -2358,4 +2379,4 @@ declare function parseMotionDrivers(text: string): {
2358
2379
  error: string;
2359
2380
  };
2360
2381
 
2361
- 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_DRIVEN_PROPERTIES, 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 MotionContactSheetOptions, type MotionControl, type MotionCue, type MotionDirection, type MotionDrawCommand, type MotionDrawOrder, type MotionDrivenProperty, type MotionDriver, type MotionEasingCurve, type MotionEdit, type MotionEditOp, type MotionEditOutcome, 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, applyMotionDrivers, applyMotionEdits, checkMotionScene, clipsShapeProblems, commandShapeProblems, compileMotionScene, createAnimationEditorToolProvider, createMotionScene, defaultMotionCommand, describeMotionElements, describeMotionShots, driversShapeProblems, duplicateMotionCommandEdit, fitMotionRect, fitMotionScene, fitMotionSceneEdits, flairAtLeast, flairCurveFor, flairEaseFor, formatMotionDrivers, formatMotionNarration, freshShotId, fromFlairSvgMotion, fromFlairVectorEffect, highlightMotionSvg, indexMotionNodes, interpolateMotionValue, isMotionCommand, isMotionShot, matchMotionNodes, motionAddTrackKey, motionBeatAt, motionBeatTime, motionClipAttrs, motionClipLayout, motionCommandDuration, motionCommandFields, motionCommandRepeat, motionCommandRows, motionCommandSummary, motionContactSheetSvg, motionCueChoices, motionCueFromKey, motionCueKey, motionCueTime, motionCycleDuration, motionDrivenNodes, motionDriverSources, motionEaseKey, motionEasingCurve, motionEasingGuides, motionEasingPath, motionFieldEdit, motionFieldLabel, motionFlairPrimitive, motionFollowRoute, motionFrameAt, motionFrameToSvg, motionGhosts, motionIssue, motionIssueKey, motionIssueLine, motionMovingIds, motionNodeAtElement, motionNodeClips, motionNodeOffset, motionPath, motionPathLength, motionPathsSvg, motionPropertyValue, motionRestValue, motionRevealClip, motionRevealPadding, motionRulerTicks, motionSceneShapeProblems, motionSceneToJson, motionShotAt, motionShotCueTime, motionShotTimeScale, motionStageSvg, motionTrackKey, namedWithSuggestion, parseMotionDrivers, parseMotionFieldInput, parseMotionNarration, parseMotionScene, resolveMotionCamera, resolveMotionEditRefs, segmentProgress, segmentValue, shotShapeProblems, smoothMotionLegs, smoothMotionTimes, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
2382
+ 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_DRIVEN_PROPERTIES, 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 MotionBlur, type MotionCamera, type MotionClip, type MotionClipItem, type MotionClipShape, type MotionColorPulseCommand, type MotionCommand, type MotionCommandBase, type MotionCommandTiming, type MotionCommandType, type MotionContactSheetOptions, type MotionControl, type MotionCue, type MotionDirection, type MotionDrawCommand, type MotionDrawOrder, type MotionDrivenProperty, type MotionDriver, type MotionEasingCurve, type MotionEdit, type MotionEditOp, type MotionEditOutcome, 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, applyMotionDrivers, applyMotionEdits, checkMotionScene, clipsShapeProblems, commandShapeProblems, compileMotionScene, createAnimationEditorToolProvider, createMotionScene, defaultMotionCommand, describeMotionElements, describeMotionShots, driversShapeProblems, duplicateMotionCommandEdit, fitMotionRect, fitMotionScene, fitMotionSceneEdits, flairAtLeast, flairCurveFor, flairEaseFor, formatMotionDrivers, formatMotionNarration, freshShotId, fromFlairSvgMotion, fromFlairVectorEffect, highlightMotionSvg, indexMotionNodes, interpolateMotionValue, isMotionCommand, isMotionShot, matchMotionNodes, motionAddTrackKey, motionBeatAt, motionBeatTime, motionBlurTimes, motionClipAttrs, motionClipLayout, motionCommandDuration, motionCommandFields, motionCommandRepeat, motionCommandRows, motionCommandSummary, motionContactSheetSvg, motionCueChoices, motionCueFromKey, motionCueKey, motionCueTime, motionCycleDuration, motionDrivenNodes, motionDriverSources, motionEaseKey, motionEasingCurve, motionEasingGuides, motionEasingPath, motionFieldEdit, motionFieldLabel, motionFlairPrimitive, motionFollowRoute, motionFrameAt, motionFrameToSvg, motionGhosts, motionIssue, motionIssueKey, motionIssueLine, motionMovingIds, motionNodeAtElement, motionNodeClips, motionNodeOffset, motionPath, motionPathLength, motionPathsSvg, motionPropertyValue, motionRestValue, motionRevealClip, motionRevealPadding, motionRulerTicks, motionSceneShapeProblems, motionSceneToJson, motionShotAt, motionShotCueTime, motionShotTimeScale, motionStageSvg, motionTrackKey, namedWithSuggestion, parseMotionDrivers, parseMotionFieldInput, parseMotionNarration, parseMotionScene, resolveMotionCamera, resolveMotionEditRefs, segmentProgress, segmentValue, shotShapeProblems, smoothMotionLegs, smoothMotionTimes, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
@@ -221,7 +221,7 @@ ${problems.map((p) => `- ${p}`).join("\n")}`);
221
221
  this.problems = problems;
222
222
  }
223
223
  };
224
- var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "drivers", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
224
+ var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "drivers", "motionBlur", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
225
225
  var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
226
226
  var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric"];
227
227
  var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps"];
@@ -471,6 +471,11 @@ function motionSceneShapeProblems(input) {
471
471
  problems.push('Scene: "artwork" must be a vector document { width, height, nodes }.');
472
472
  if (input.clips !== void 0) problems.push(...clipsShapeProblems(input.clips));
473
473
  if (input.drivers !== void 0) problems.push(...driversShapeProblems(input.drivers));
474
+ if (input.motionBlur !== void 0) {
475
+ const b = input.motionBlur;
476
+ if (!isObject(b) || Object.keys(b).some((k) => k !== "shutter" && k !== "samples") || b.shutter !== void 0 && !(isNum(b.shutter) && b.shutter > 0 && b.shutter <= 720) || b.samples !== void 0 && !(Number.isInteger(b.samples) && b.samples >= 2 && b.samples <= 32))
477
+ problems.push('Scene: "motionBlur" must be { "shutter"?: degrees above 0 up to 720 (default 180), "samples"?: 2 to 32 (default 8) }.');
478
+ }
474
479
  if (input.trigger !== void 0 && !MOTION_TRIGGERS.includes(input.trigger)) problems.push(`Scene: "trigger" must be one of ${MOTION_TRIGGERS.join(", ")}.`);
475
480
  if (input.loop !== void 0 && !["none", "loop", "ping-pong"].includes(input.loop)) problems.push('Scene: "loop" must be "none", "loop" or "ping-pong".');
476
481
  if (input.fps !== void 0 && !(isNum(input.fps) && input.fps > 0 && input.fps <= 120)) problems.push('Scene: "fps" must be a number from 1 to 120.');
@@ -1574,12 +1579,49 @@ function motionPathsSvg(paths, camera, color = "#f43f5e") {
1574
1579
  (p) => `<g data-motion-path="${p.id.replace(/"/g, "&quot;")}" fill="none" stroke="${color}" stroke-width="${f(w)}" stroke-linecap="round" stroke-linejoin="round" opacity="0.8"><polyline points="${p.points.map((q) => `${f(q.x)},${f(q.y)}`).join(" ")}" stroke-dasharray="${f(w * 3)} ${f(w * 2)}"/>${p.keys.map((k) => `<circle cx="${f(k.x)}" cy="${f(k.y)}" r="${f(w * 2.5)}" fill="${color}" stroke="none"/>`).join("")}</g>`
1575
1580
  ).join("");
1576
1581
  }
1582
+ function motionBlurTimes(scene, time, blur = {}) {
1583
+ const shutter = Math.min(720, Math.max(0, blur.shutter ?? 180));
1584
+ const most = Math.max(1, Math.min(32, Math.floor(blur.samples ?? 8)));
1585
+ const span = 1e3 / (scene.fps ?? 30) * shutter / 360;
1586
+ if (span <= 0 || most <= 1) return [time];
1587
+ const ids = motionMovingIds(scene);
1588
+ if (!ids.length) return [time];
1589
+ const a = indexMotionNodes(motionFrameAt(scene, time - span / 2).document.nodes);
1590
+ const b = indexMotionNodes(motionFrameAt(scene, time + span / 2).document.nodes);
1591
+ let travel = 0;
1592
+ for (const id of ids) {
1593
+ const p = a.get(id)?.bounds;
1594
+ const q = b.get(id)?.bounds;
1595
+ if (p && q) travel = Math.max(travel, Math.abs(p.x - q.x), Math.abs(p.y - q.y), Math.abs(p.x + p.width - q.x - q.width), Math.abs(p.y + p.height - q.y - q.height));
1596
+ }
1597
+ const n = Math.min(most, Math.ceil(travel / 1.5));
1598
+ if (n <= 1) return [time];
1599
+ return Array.from({ length: n }, (_, k) => time - span / 2 + span * (k + 0.5) / n);
1600
+ }
1601
+ function averagedFrames(scene, times, options, prefix) {
1602
+ const n = times.length;
1603
+ return `<g data-motion-blur="${n}" style="isolation:isolate">${times.map((t, k) => {
1604
+ const own = `${prefix}blur${k}-`;
1605
+ const frame = motionFrameToSvg(scene, t, { ...options, idPrefix: own, background: false });
1606
+ const view = /viewBox="([^"]*)"/.exec(frame)?.[1] ?? "";
1607
+ const inner = k === n - 1 ? innerSvg(frame) : innerSvg(frame).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
1608
+ return `<svg viewBox="${view}" preserveAspectRatio="none" style="mix-blend-mode:plus-lighter" opacity="${Math.round(1e4 / n) / 1e4}">${inner}</svg>`;
1609
+ }).join("")}</g>`;
1610
+ }
1577
1611
  var innerSvg = (svg) => svg.slice(svg.indexOf(">") + 1, svg.lastIndexOf("</svg>"));
1578
1612
  function motionStageSvg(scene, time, options = {}) {
1579
- const { onionSkin, motionPaths, motionPathColor, ...svgOptions } = options;
1580
- const current = motionFrameToSvg(scene, time, svgOptions);
1581
- if (!onionSkin && !motionPaths) return current;
1613
+ const { onionSkin, motionPaths, motionPathColor, motionBlur, ...svgOptions } = options;
1582
1614
  const prefix = svgOptions.idPrefix ?? "vg-";
1615
+ let current = motionFrameToSvg(scene, time, svgOptions);
1616
+ const blur = motionBlur === false ? void 0 : motionBlur ?? scene.motionBlur;
1617
+ const blurTimes = blur ? motionBlurTimes(scene, time, blur) : [time];
1618
+ if (blurTimes.length > 1) {
1619
+ const open2 = current.indexOf(">") + 1;
1620
+ const body2 = current.slice(open2, current.lastIndexOf("</svg>"));
1621
+ const bg2 = svgOptions.background !== false && scene.artwork.background ? /^\s*<rect[^>]*\/>/.exec(body2)?.[0] ?? "" : "";
1622
+ current = `${current.slice(0, open2)}${bg2}${averagedFrames(scene, blurTimes, svgOptions, prefix)}</svg>`;
1623
+ }
1624
+ if (!onionSkin && !motionPaths) return current;
1583
1625
  const ghosts = onionSkin ? motionGhosts(scene, time, onionSkin).map((g, i) => {
1584
1626
  const own = `${prefix}ghost${i}-`;
1585
1627
  const inner = innerSvg(motionFrameToSvg(scene, g.time, { ...svgOptions, idPrefix: own, background: false })).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
@@ -1934,12 +1976,12 @@ function applyOne(scene, edit) {
1934
1976
  if (!(typeof edit.steps === "number" && edit.steps > 0 && edit.steps <= 120)) fail('"steps" must be frames per second from above 0 to 120 (12 is "on twos" at 24 fps), or null for smooth.');
1935
1977
  next.steps = edit.steps;
1936
1978
  }
1937
- for (const key of ["beat", "narration"]) {
1979
+ for (const key of ["beat", "narration", "motionBlur"]) {
1938
1980
  if (edit[key] === null) delete next[key];
1939
1981
  else if (edit[key] !== void 0) next[key] = edit[key];
1940
1982
  }
1941
1983
  {
1942
- const problems = motionSceneShapeProblems(next).filter((p) => /"beat"|"narration"/.test(p));
1984
+ const problems = motionSceneShapeProblems(next).filter((p) => /"beat"|"narration"|"motionBlur"/.test(p));
1943
1985
  if (problems.length) fail(problems.join(" "));
1944
1986
  }
1945
1987
  if (edit.target === null) delete next.target;
@@ -2469,6 +2511,7 @@ function toFlairSvgMotion(scene, options = {}) {
2469
2511
  }
2470
2512
  animate.sort((x, y) => (x.step ?? 0) - (y.step ?? 0) || (x.delay ?? 0) - (y.delay ?? 0));
2471
2513
  }
2514
+ if (scene.motionBlur) notes.push("Motion blur is drawn on the stage only; Flair plays the scene sharp.");
2472
2515
  if (trigger && (scene.loop ?? "none") !== "none") notes.push(`The scene plays on ${trigger}, so its loop does not apply in Flair.`);
2473
2516
  let svg = vectorDocumentToSvg({ ...scene.artwork, nodes: expandVectorAppearances(scene.artwork.nodes) }, { pretty: false, precision, wrap });
2474
2517
  if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
@@ -2785,6 +2828,7 @@ function toLottie(scene, options = {}) {
2785
2828
  const timeline = compileMotionScene(scene);
2786
2829
  const nodes = indexMotionNodes(scene.artwork.nodes);
2787
2830
  const notes = [];
2831
+ if (scene.motionBlur) notes.push("Motion blur is drawn on the stage only; the Lottie plays sharp.");
2788
2832
  if (scene.trigger) notes.push(`The scene plays on ${scene.trigger}; Lottie has no trigger, so it plays through (markers show where each shot starts, for a player to stop at).`);
2789
2833
  let sampled = 0;
2790
2834
  const track = (id, p) => timeline.tracks.get(motionTrackKey(id, p)) ?? [];
@@ -3451,6 +3495,10 @@ var SETTINGS = {
3451
3495
  },
3452
3496
  fps: { type: "number", minimum: 1, maximum: 120, description: "Sampling rate for exports (default 30)." },
3453
3497
  steps: { anyOf: [{ type: "number", exclusiveMinimum: 0, maximum: 120 }, { type: "null" }], description: 'Stepped time for every command without its own: changes hold on a grid of this many frames per second (12 = "on twos" at 24 fps) for a hand-drawn look; null makes it smooth again (default).' },
3498
+ motionBlur: {
3499
+ anyOf: [object({ shutter: { type: "number", exclusiveMinimum: 0, maximum: 720, description: "Shutter angle in degrees of a frame (default 180; 360 is a whole frame, more blur)." }, samples: { type: "integer", minimum: 2, maximum: 32, description: "Most moments a frame averages (default 8)." } }), { type: "null" }],
3500
+ description: "Motion blur on the stage and in rendered frames (not exported to Flair or Lottie); null turns it off."
3501
+ },
3454
3502
  beat: {
3455
3503
  anyOf: [
3456
3504
  object({ bpm: { type: "number", minimum: 1, maximum: 1e3, description: "Beats a minute." }, offset: { type: "number", description: "When beat 0 falls, ms (default 0)." }, meter: { type: "integer", minimum: 1, description: "Beats a bar (default 4)." } }, ["bpm"]),
@@ -3577,6 +3625,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
3577
3625
  shots: describeMotionShots(s),
3578
3626
  ...s.clips ? { clips: Object.fromEntries(Object.entries(s.clips).map(([name, c]) => [name, { ...c.description ? { description: c.description } : {}, commands: c.run.length, length: Math.round(motionClipLayout(s, name, "$").length) }])) } : {},
3579
3627
  ...s.drivers ? { drivers: s.drivers } : {},
3628
+ ...s.motionBlur ? { motionBlur: s.motionBlur } : {},
3580
3629
  ...s.controls ? { controls: s.controls } : {},
3581
3630
  ...s.presets ? { presets: s.presets } : {},
3582
3631
  issues: issueSummary(controller.getState().issues),
@@ -4138,6 +4187,7 @@ Commands
4138
4187
  - 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.
4139
4188
  - 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.
4140
4189
  - Drawing a group of strokes: "order": "sequence" draws them one after another (a signature, a diagram), "sortBy": "distance" from "origin" reveals outward, "pace": "speed" keeps one speed; draw with "comet": 0.2 sends a short stroke along a path and off the end.
4190
+ - Fast motion reads better with blur: set_animation_settings { "motionBlur": { "shutter": 180 } } (stage and rendered frames only).
4141
4191
  - 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.
4142
4192
  - 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.
4143
4193
  - 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.
@@ -4527,6 +4577,7 @@ export {
4527
4577
  motionAddTrackKey,
4528
4578
  motionBeatAt,
4529
4579
  motionBeatTime,
4580
+ motionBlurTimes,
4530
4581
  motionClipAttrs,
4531
4582
  motionClipLayout,
4532
4583
  motionCommandDuration,