@pixerate/editor 0.66.1 → 0.67.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animation-editor/index.cjs +55 -11
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +39 -3
- package/dist/animation-editor/index.d.ts +39 -3
- package/dist/animation-editor/index.js +54 -10
- package/dist/animation-editor/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -29,6 +29,15 @@ interface MotionScene {
|
|
|
29
29
|
shots: MotionShot[];
|
|
30
30
|
/** Playback past the end: stop (`none`, default), `loop` or `ping-pong`. */
|
|
31
31
|
loop?: AnimationLoopMode;
|
|
32
|
+
/**
|
|
33
|
+
* Plays in answer to the viewer instead of on its own (exported to Flair's player):
|
|
34
|
+
* - `click`: nothing plays until the viewer clicks; each click plays the next shot, and after the
|
|
35
|
+
* last one a click plays the first again, so a last shot that puts things back makes a toggle.
|
|
36
|
+
* - `hover` / `press`: plays forward while the pointer is over (or down on) it, and back when it leaves.
|
|
37
|
+
* - `scroll`: scrubs through the scene as it scrolls through the viewport.
|
|
38
|
+
* The editor previews it played through; `loop` does not apply.
|
|
39
|
+
*/
|
|
40
|
+
trigger?: MotionTrigger;
|
|
32
41
|
/** Frame rate used to sample motion that a target format cannot express exactly (default 30). */
|
|
33
42
|
fps?: number;
|
|
34
43
|
/**
|
|
@@ -47,6 +56,9 @@ interface MotionScene {
|
|
|
47
56
|
/** Named sets of control values. */
|
|
48
57
|
presets?: MotionPreset[];
|
|
49
58
|
}
|
|
59
|
+
/** What the viewer does to play a triggered scene (see `MotionScene.trigger`). */
|
|
60
|
+
type MotionTrigger = 'click' | 'hover' | 'press' | 'scroll';
|
|
61
|
+
declare const MOTION_TRIGGERS: readonly MotionTrigger[];
|
|
50
62
|
/** A rectangle of the artwork, in document units. */
|
|
51
63
|
interface MotionRect {
|
|
52
64
|
x: number;
|
|
@@ -540,6 +552,18 @@ declare const MOTION_ISSUE_CODES: {
|
|
|
540
552
|
readonly severity: "warning";
|
|
541
553
|
readonly wording: "A shot starts after its cue, because the shot before runs past it.";
|
|
542
554
|
};
|
|
555
|
+
readonly 'trigger-loop': {
|
|
556
|
+
readonly severity: "note";
|
|
557
|
+
readonly wording: "A scene that plays on a trigger ignores its loop.";
|
|
558
|
+
};
|
|
559
|
+
readonly 'click-cue': {
|
|
560
|
+
readonly severity: "warning";
|
|
561
|
+
readonly wording: "A shot of a click-triggered scene is cued, but clicks decide when its shots start.";
|
|
562
|
+
};
|
|
563
|
+
readonly 'click-one-shot': {
|
|
564
|
+
readonly severity: "note";
|
|
565
|
+
readonly wording: "A click-triggered scene has one shot, so every click replays it.";
|
|
566
|
+
};
|
|
543
567
|
readonly 'scene-too-long': {
|
|
544
568
|
readonly severity: "warning";
|
|
545
569
|
readonly wording: "The scene runs past its target length.";
|
|
@@ -1001,6 +1025,7 @@ type MotionEdit = {
|
|
|
1001
1025
|
name?: string;
|
|
1002
1026
|
description?: string | null;
|
|
1003
1027
|
loop?: MotionScene['loop'];
|
|
1028
|
+
trigger?: MotionScene['trigger'] | null;
|
|
1004
1029
|
fps?: number;
|
|
1005
1030
|
steps?: number | null;
|
|
1006
1031
|
beat?: MotionScene['beat'] | null;
|
|
@@ -1207,8 +1232,15 @@ interface FlairMotionExport {
|
|
|
1207
1232
|
sampled: number;
|
|
1208
1233
|
/** What could not be carried over, in sentences. */
|
|
1209
1234
|
notes: string[];
|
|
1235
|
+
/** How the viewer plays it: pass to Flair's `SvgPlayer` as `{ trigger }` (from the scene's `trigger`). */
|
|
1236
|
+
trigger?: MotionTrigger;
|
|
1210
1237
|
}
|
|
1211
1238
|
interface FlairExportOptions {
|
|
1239
|
+
/**
|
|
1240
|
+
* Play in answer to the viewer (default: the scene's `trigger`; null for none). With `click`
|
|
1241
|
+
* shot n is Flair step n + 1: nothing plays until the first click, and each click plays the next shot.
|
|
1242
|
+
*/
|
|
1243
|
+
trigger?: MotionTrigger | null;
|
|
1212
1244
|
/** Sampling rate for changes Flair cannot express exactly (default: the scene's `fps`, else 30). */
|
|
1213
1245
|
fps?: number;
|
|
1214
1246
|
/** Decimal places (default 3). */
|
|
@@ -1255,7 +1287,6 @@ interface FlairEffectOptions extends FlairExportOptions {
|
|
|
1255
1287
|
/** Flair catalog category (default `icon`). */
|
|
1256
1288
|
category?: string;
|
|
1257
1289
|
tags?: string[];
|
|
1258
|
-
trigger?: FlairVectorEffect['trigger'];
|
|
1259
1290
|
}
|
|
1260
1291
|
/** A scene as a Flair catalog vector effect, with its colour controls and presets. */
|
|
1261
1292
|
declare function toFlairVectorEffect(scene: MotionScene, options?: FlairEffectOptions): FlairVectorEffect;
|
|
@@ -1286,6 +1317,11 @@ interface FlairImportOptions {
|
|
|
1286
1317
|
name?: string;
|
|
1287
1318
|
/** Hold after the last shot, ms (default: the effect's `hold`, else 600). */
|
|
1288
1319
|
hold?: number;
|
|
1320
|
+
/**
|
|
1321
|
+
* The motion plays on click: Flair plays step 0 together with step 1 on the first click, so
|
|
1322
|
+
* both become the first shot (as `toFlairSvgMotion` writes them).
|
|
1323
|
+
*/
|
|
1324
|
+
clickSteps?: boolean;
|
|
1289
1325
|
}
|
|
1290
1326
|
/** A Flair `SvgMotion` as a scene (see the module notes for what carries over). */
|
|
1291
1327
|
declare function fromFlairSvgMotion(input: FlairSvgMotion, options?: FlairImportOptions): FlairImportResult;
|
|
@@ -1925,7 +1961,7 @@ declare function createAnimationEditorToolProvider(controller: AnimationEditorCo
|
|
|
1925
1961
|
* A short authoring guide for a model writing vector animations with the animation editor's
|
|
1926
1962
|
* tools. Static, so it caches well as part of a system prompt.
|
|
1927
1963
|
*/
|
|
1928
|
-
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- 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.\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.";
|
|
1964
|
+
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- 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.";
|
|
1929
1965
|
|
|
1930
1966
|
/**
|
|
1931
1967
|
* Helpers for hand-editing UIs (React's and Svelte's command inspector, ease picker, cue picker,
|
|
@@ -2072,4 +2108,4 @@ declare function parseMotionNarration(text: string): {
|
|
|
2072
2108
|
error: string;
|
|
2073
2109
|
};
|
|
2074
2110
|
|
|
2075
|
-
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_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, type MotionBeatGrid, type MotionCamera, 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 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 MotionSplitOrientation, type MotionStyleCommand, type MotionSvgOptions, type MotionTeeterCommand, type MotionTimeline, type MotionValue, type MotionWaitCommand, type MotionWaveCommand, type MotionWiggleCommand, activeSegment, applyMotionControlValues, applyMotionEdits, checkMotionScene, 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, 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, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
|
|
2111
|
+
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_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 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 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 MotionSplitOrientation, type MotionStyleCommand, type MotionSvgOptions, type MotionTeeterCommand, type MotionTimeline, type MotionTrigger, type MotionValue, type MotionWaitCommand, type MotionWaveCommand, type MotionWiggleCommand, activeSegment, applyMotionControlValues, applyMotionEdits, checkMotionScene, 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, 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, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
|
|
@@ -29,6 +29,15 @@ interface MotionScene {
|
|
|
29
29
|
shots: MotionShot[];
|
|
30
30
|
/** Playback past the end: stop (`none`, default), `loop` or `ping-pong`. */
|
|
31
31
|
loop?: AnimationLoopMode;
|
|
32
|
+
/**
|
|
33
|
+
* Plays in answer to the viewer instead of on its own (exported to Flair's player):
|
|
34
|
+
* - `click`: nothing plays until the viewer clicks; each click plays the next shot, and after the
|
|
35
|
+
* last one a click plays the first again, so a last shot that puts things back makes a toggle.
|
|
36
|
+
* - `hover` / `press`: plays forward while the pointer is over (or down on) it, and back when it leaves.
|
|
37
|
+
* - `scroll`: scrubs through the scene as it scrolls through the viewport.
|
|
38
|
+
* The editor previews it played through; `loop` does not apply.
|
|
39
|
+
*/
|
|
40
|
+
trigger?: MotionTrigger;
|
|
32
41
|
/** Frame rate used to sample motion that a target format cannot express exactly (default 30). */
|
|
33
42
|
fps?: number;
|
|
34
43
|
/**
|
|
@@ -47,6 +56,9 @@ interface MotionScene {
|
|
|
47
56
|
/** Named sets of control values. */
|
|
48
57
|
presets?: MotionPreset[];
|
|
49
58
|
}
|
|
59
|
+
/** What the viewer does to play a triggered scene (see `MotionScene.trigger`). */
|
|
60
|
+
type MotionTrigger = 'click' | 'hover' | 'press' | 'scroll';
|
|
61
|
+
declare const MOTION_TRIGGERS: readonly MotionTrigger[];
|
|
50
62
|
/** A rectangle of the artwork, in document units. */
|
|
51
63
|
interface MotionRect {
|
|
52
64
|
x: number;
|
|
@@ -540,6 +552,18 @@ declare const MOTION_ISSUE_CODES: {
|
|
|
540
552
|
readonly severity: "warning";
|
|
541
553
|
readonly wording: "A shot starts after its cue, because the shot before runs past it.";
|
|
542
554
|
};
|
|
555
|
+
readonly 'trigger-loop': {
|
|
556
|
+
readonly severity: "note";
|
|
557
|
+
readonly wording: "A scene that plays on a trigger ignores its loop.";
|
|
558
|
+
};
|
|
559
|
+
readonly 'click-cue': {
|
|
560
|
+
readonly severity: "warning";
|
|
561
|
+
readonly wording: "A shot of a click-triggered scene is cued, but clicks decide when its shots start.";
|
|
562
|
+
};
|
|
563
|
+
readonly 'click-one-shot': {
|
|
564
|
+
readonly severity: "note";
|
|
565
|
+
readonly wording: "A click-triggered scene has one shot, so every click replays it.";
|
|
566
|
+
};
|
|
543
567
|
readonly 'scene-too-long': {
|
|
544
568
|
readonly severity: "warning";
|
|
545
569
|
readonly wording: "The scene runs past its target length.";
|
|
@@ -1001,6 +1025,7 @@ type MotionEdit = {
|
|
|
1001
1025
|
name?: string;
|
|
1002
1026
|
description?: string | null;
|
|
1003
1027
|
loop?: MotionScene['loop'];
|
|
1028
|
+
trigger?: MotionScene['trigger'] | null;
|
|
1004
1029
|
fps?: number;
|
|
1005
1030
|
steps?: number | null;
|
|
1006
1031
|
beat?: MotionScene['beat'] | null;
|
|
@@ -1207,8 +1232,15 @@ interface FlairMotionExport {
|
|
|
1207
1232
|
sampled: number;
|
|
1208
1233
|
/** What could not be carried over, in sentences. */
|
|
1209
1234
|
notes: string[];
|
|
1235
|
+
/** How the viewer plays it: pass to Flair's `SvgPlayer` as `{ trigger }` (from the scene's `trigger`). */
|
|
1236
|
+
trigger?: MotionTrigger;
|
|
1210
1237
|
}
|
|
1211
1238
|
interface FlairExportOptions {
|
|
1239
|
+
/**
|
|
1240
|
+
* Play in answer to the viewer (default: the scene's `trigger`; null for none). With `click`
|
|
1241
|
+
* shot n is Flair step n + 1: nothing plays until the first click, and each click plays the next shot.
|
|
1242
|
+
*/
|
|
1243
|
+
trigger?: MotionTrigger | null;
|
|
1212
1244
|
/** Sampling rate for changes Flair cannot express exactly (default: the scene's `fps`, else 30). */
|
|
1213
1245
|
fps?: number;
|
|
1214
1246
|
/** Decimal places (default 3). */
|
|
@@ -1255,7 +1287,6 @@ interface FlairEffectOptions extends FlairExportOptions {
|
|
|
1255
1287
|
/** Flair catalog category (default `icon`). */
|
|
1256
1288
|
category?: string;
|
|
1257
1289
|
tags?: string[];
|
|
1258
|
-
trigger?: FlairVectorEffect['trigger'];
|
|
1259
1290
|
}
|
|
1260
1291
|
/** A scene as a Flair catalog vector effect, with its colour controls and presets. */
|
|
1261
1292
|
declare function toFlairVectorEffect(scene: MotionScene, options?: FlairEffectOptions): FlairVectorEffect;
|
|
@@ -1286,6 +1317,11 @@ interface FlairImportOptions {
|
|
|
1286
1317
|
name?: string;
|
|
1287
1318
|
/** Hold after the last shot, ms (default: the effect's `hold`, else 600). */
|
|
1288
1319
|
hold?: number;
|
|
1320
|
+
/**
|
|
1321
|
+
* The motion plays on click: Flair plays step 0 together with step 1 on the first click, so
|
|
1322
|
+
* both become the first shot (as `toFlairSvgMotion` writes them).
|
|
1323
|
+
*/
|
|
1324
|
+
clickSteps?: boolean;
|
|
1289
1325
|
}
|
|
1290
1326
|
/** A Flair `SvgMotion` as a scene (see the module notes for what carries over). */
|
|
1291
1327
|
declare function fromFlairSvgMotion(input: FlairSvgMotion, options?: FlairImportOptions): FlairImportResult;
|
|
@@ -1925,7 +1961,7 @@ declare function createAnimationEditorToolProvider(controller: AnimationEditorCo
|
|
|
1925
1961
|
* A short authoring guide for a model writing vector animations with the animation editor's
|
|
1926
1962
|
* tools. Static, so it caches well as part of a system prompt.
|
|
1927
1963
|
*/
|
|
1928
|
-
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- 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.\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.";
|
|
1964
|
+
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- 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.";
|
|
1929
1965
|
|
|
1930
1966
|
/**
|
|
1931
1967
|
* Helpers for hand-editing UIs (React's and Svelte's command inspector, ease picker, cue picker,
|
|
@@ -2072,4 +2108,4 @@ declare function parseMotionNarration(text: string): {
|
|
|
2072
2108
|
error: string;
|
|
2073
2109
|
};
|
|
2074
2110
|
|
|
2075
|
-
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_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, type MotionBeatGrid, type MotionCamera, 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 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 MotionSplitOrientation, type MotionStyleCommand, type MotionSvgOptions, type MotionTeeterCommand, type MotionTimeline, type MotionValue, type MotionWaitCommand, type MotionWaveCommand, type MotionWiggleCommand, activeSegment, applyMotionControlValues, applyMotionEdits, checkMotionScene, 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, 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, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
|
|
2111
|
+
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_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 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 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 MotionSplitOrientation, type MotionStyleCommand, type MotionSvgOptions, type MotionTeeterCommand, type MotionTimeline, type MotionTrigger, type MotionValue, type MotionWaitCommand, type MotionWaveCommand, type MotionWiggleCommand, activeSegment, applyMotionControlValues, applyMotionEdits, checkMotionScene, 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, 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, suggestName, toFlairEffectDocument, toFlairSvgMotion, toFlairVectorEffect, toLottie, trackValue, withMotionLayers, withViewBox };
|
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
} from "../chunk-AGR4P4UZ.js";
|
|
56
56
|
|
|
57
57
|
// src/animation-editor/types.ts
|
|
58
|
+
var MOTION_TRIGGERS = ["click", "hover", "press", "scroll"];
|
|
58
59
|
var MOTION_COMMAND_TYPES = [
|
|
59
60
|
"enter",
|
|
60
61
|
"exit",
|
|
@@ -153,6 +154,9 @@ var MOTION_ISSUE_CODES = {
|
|
|
153
154
|
"spring-cut-short": { severity: "warning", wording: "A spring is given a duration shorter than it takes to settle, so it jumps to its end." },
|
|
154
155
|
"unknown-cue": { severity: "error", wording: "A shot is cued to a beat with no beat grid, or to a word the narration does not have." },
|
|
155
156
|
"cue-missed": { severity: "warning", wording: "A shot starts after its cue, because the shot before runs past it." },
|
|
157
|
+
"trigger-loop": { severity: "note", wording: "A scene that plays on a trigger ignores its loop." },
|
|
158
|
+
"click-cue": { severity: "warning", wording: "A shot of a click-triggered scene is cued, but clicks decide when its shots start." },
|
|
159
|
+
"click-one-shot": { severity: "note", wording: "A click-triggered scene has one shot, so every click replays it." },
|
|
156
160
|
"scene-too-long": { severity: "warning", wording: "The scene runs past its target length." },
|
|
157
161
|
"scene-too-short": { severity: "warning", wording: "The scene ends before its target length." },
|
|
158
162
|
"unknown-control-color": { severity: "warning", wording: "A control stands for a colour the scene never uses." },
|
|
@@ -210,7 +214,7 @@ ${problems.map((p) => `- ${p}`).join("\n")}`);
|
|
|
210
214
|
this.problems = problems;
|
|
211
215
|
}
|
|
212
216
|
};
|
|
213
|
-
var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "loop", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
|
|
217
|
+
var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
|
|
214
218
|
var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
|
|
215
219
|
var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric"];
|
|
216
220
|
var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps"];
|
|
@@ -403,6 +407,7 @@ function motionSceneShapeProblems(input) {
|
|
|
403
407
|
const art = input.artwork;
|
|
404
408
|
if (!isObject(art) || !isNum(art.width) || !isNum(art.height) || !(art.width > 0) || !(art.height > 0) || !Array.isArray(art.nodes))
|
|
405
409
|
problems.push('Scene: "artwork" must be a vector document { width, height, nodes }.');
|
|
410
|
+
if (input.trigger !== void 0 && !MOTION_TRIGGERS.includes(input.trigger)) problems.push(`Scene: "trigger" must be one of ${MOTION_TRIGGERS.join(", ")}.`);
|
|
406
411
|
if (input.loop !== void 0 && !["none", "loop", "ping-pong"].includes(input.loop)) problems.push('Scene: "loop" must be "none", "loop" or "ping-pong".');
|
|
407
412
|
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.');
|
|
408
413
|
if (input.beat !== void 0) {
|
|
@@ -1493,6 +1498,15 @@ function checkMotionScene(scene) {
|
|
|
1493
1498
|
}
|
|
1494
1499
|
});
|
|
1495
1500
|
});
|
|
1501
|
+
if (scene.trigger) {
|
|
1502
|
+
if ((scene.loop ?? "none") !== "none") issues.push(motionIssue("trigger-loop", `The scene plays on ${scene.trigger}, so its "${scene.loop}" loop does not apply; set loop to "none" or remove the trigger.`, {}));
|
|
1503
|
+
if (scene.trigger === "click") {
|
|
1504
|
+
if (scene.shots.length === 1) issues.push(motionIssue("click-one-shot", "The scene plays on click but has one shot, so every click replays it from the start; split it into shots (each click plays the next one).", { shot: scene.shots[0].id }));
|
|
1505
|
+
scene.shots.forEach((shot, i) => {
|
|
1506
|
+
if (i > 0 && shot.at) issues.push(motionIssue("click-cue", `Shot "${shot.id}" is cued, but on click a shot starts when it is clicked to; remove its "at" or the trigger.`, { shot: shot.id }));
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1496
1510
|
scene.shots.forEach((shot, i) => {
|
|
1497
1511
|
if (!shot.at) return;
|
|
1498
1512
|
const timing = timeline.shots[i];
|
|
@@ -1600,6 +1614,11 @@ function applyOne(scene, edit) {
|
|
|
1600
1614
|
if (edit.description === null) delete next.description;
|
|
1601
1615
|
else if (edit.description !== void 0) next.description = edit.description;
|
|
1602
1616
|
if (edit.loop !== void 0) next.loop = edit.loop;
|
|
1617
|
+
if (edit.trigger === null) delete next.trigger;
|
|
1618
|
+
else if (edit.trigger !== void 0) {
|
|
1619
|
+
if (!["click", "hover", "press", "scroll"].includes(edit.trigger)) fail('"trigger" must be click, hover, press or scroll, or null to play on its own.');
|
|
1620
|
+
next.trigger = edit.trigger;
|
|
1621
|
+
}
|
|
1603
1622
|
if (edit.fps !== void 0) next.fps = edit.fps;
|
|
1604
1623
|
if (edit.steps === null) delete next.steps;
|
|
1605
1624
|
else if (edit.steps !== void 0) {
|
|
@@ -2044,9 +2063,25 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2044
2063
|
}
|
|
2045
2064
|
}
|
|
2046
2065
|
animate.sort((x, y) => (x.delay ?? 0) - (y.delay ?? 0));
|
|
2066
|
+
const lastChange = animate.reduce((m, a) => Math.max(m, (a.delay ?? 0) + (a.ms ?? 0)), 0);
|
|
2067
|
+
const trigger = options.trigger === null ? void 0 : options.trigger ?? scene.trigger;
|
|
2068
|
+
if (trigger === "click" && timeline.shots.length) {
|
|
2069
|
+
for (const a of animate) {
|
|
2070
|
+
const at = a.delay ?? 0;
|
|
2071
|
+
let step = 0;
|
|
2072
|
+
timeline.shots.forEach((shot, i) => {
|
|
2073
|
+
if (shot.start <= at + 1e-6) step = i;
|
|
2074
|
+
});
|
|
2075
|
+
const delay = round2(at - timeline.shots[step].start);
|
|
2076
|
+
delete a.delay;
|
|
2077
|
+
if (delay > 0) a.delay = delay;
|
|
2078
|
+
a.step = step + 1;
|
|
2079
|
+
}
|
|
2080
|
+
animate.sort((x, y) => (x.step ?? 0) - (y.step ?? 0) || (x.delay ?? 0) - (y.delay ?? 0));
|
|
2081
|
+
}
|
|
2082
|
+
if (trigger && (scene.loop ?? "none") !== "none") notes.push(`The scene plays on ${trigger}, so its loop does not apply in Flair.`);
|
|
2047
2083
|
let svg = vectorDocumentToSvg({ ...scene.artwork, nodes: expandVectorAppearances(scene.artwork.nodes) }, { pretty: false, precision, wrap });
|
|
2048
2084
|
if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
|
|
2049
|
-
const lastChange = animate.reduce((m, a) => Math.max(m, (a.delay ?? 0) + (a.ms ?? 0)), 0);
|
|
2050
2085
|
let motion = { svg, animate };
|
|
2051
2086
|
if (scene.controls?.length) {
|
|
2052
2087
|
const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
|
|
@@ -2056,7 +2091,7 @@ function toFlairSvgMotion(scene, options = {}) {
|
|
|
2056
2091
|
svg = svg.slice(0, header) + swap(svg.slice(header));
|
|
2057
2092
|
motion = { svg, animate: animate.map((a) => a.attrs ? { ...a, attrs: Object.fromEntries(Object.entries(a.attrs).map(([k, [x, y]]) => [k, [typeof x === "string" ? swap(x) : x, typeof y === "string" ? swap(y) : y]])) } : a) };
|
|
2058
2093
|
}
|
|
2059
|
-
return { motion, duration: timeline.duration, hold: Math.max(0, round2(timeline.duration - lastChange)), sampled, notes: [...new Set(notes)] };
|
|
2094
|
+
return { motion, duration: timeline.duration, hold: Math.max(0, round2(timeline.duration - lastChange)), sampled, notes: [...new Set(notes)], ...trigger ? { trigger } : {} };
|
|
2060
2095
|
}
|
|
2061
2096
|
var kebab = (text) => text.trim().replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "animation";
|
|
2062
2097
|
function toFlairVectorEffect(scene, options = {}) {
|
|
@@ -2071,7 +2106,7 @@ function toFlairVectorEffect(scene, options = {}) {
|
|
|
2071
2106
|
motion: out.motion,
|
|
2072
2107
|
hold: out.hold,
|
|
2073
2108
|
...scene.presets?.length ? { presets: scene.presets } : {},
|
|
2074
|
-
...
|
|
2109
|
+
...out.trigger ? { trigger: out.trigger } : {}
|
|
2075
2110
|
};
|
|
2076
2111
|
}
|
|
2077
2112
|
function toFlairEffectDocument(scene, options = {}) {
|
|
@@ -2083,7 +2118,8 @@ function toFlairEffectDocument(scene, options = {}) {
|
|
|
2083
2118
|
values: Object.fromEntries((scene.controls ?? []).map((c) => [c.name, c.default])),
|
|
2084
2119
|
tracks: {},
|
|
2085
2120
|
duration: out.duration,
|
|
2086
|
-
|
|
2121
|
+
// Flair's editor documents have no trigger: a click scene keeps its steps, and plays through there.
|
|
2122
|
+
loop: !out.trigger && (scene.loop ?? "none") !== "none",
|
|
2087
2123
|
presets: scene.presets ?? []
|
|
2088
2124
|
};
|
|
2089
2125
|
}
|
|
@@ -2224,7 +2260,8 @@ function fromFlairSvgMotion(input, options = {}) {
|
|
|
2224
2260
|
const nodes = indexMotionNodes(artwork.nodes);
|
|
2225
2261
|
const byStep = /* @__PURE__ */ new Map();
|
|
2226
2262
|
for (const anim of motion.animate ?? []) {
|
|
2227
|
-
const
|
|
2263
|
+
const raw = Math.max(0, Math.floor(anim.step ?? 0));
|
|
2264
|
+
const step = options.clickSteps ? Math.max(1, raw) : raw;
|
|
2228
2265
|
if (!byStep.has(step)) byStep.set(step, []);
|
|
2229
2266
|
byStep.get(step).push(anim);
|
|
2230
2267
|
}
|
|
@@ -2275,12 +2312,11 @@ function presetColor(value) {
|
|
|
2275
2312
|
}
|
|
2276
2313
|
function fromFlairVectorEffect(effect, options = {}) {
|
|
2277
2314
|
if (!effect || effect.kind !== "vector" || !effect.motion) throw new Error('Give a Flair vector effect: { kind: "vector", id, name, motion: { svg, animate } }.');
|
|
2278
|
-
const result = fromFlairSvgMotion(effect.motion, { name: options.name ?? effect.id ?? effect.name, hold: options.hold ?? effect.hold });
|
|
2315
|
+
const result = fromFlairSvgMotion(effect.motion, { name: options.name ?? effect.id ?? effect.name, hold: options.hold ?? effect.hold, ...effect.trigger === "click" ? { clickSteps: true } : {} });
|
|
2279
2316
|
const names = new Set((result.scene.controls ?? []).map((c) => c.name));
|
|
2280
2317
|
const presets = (effect.presets ?? []).map((p) => ({ name: p.name, values: Object.fromEntries(Object.entries(p.values).flatMap(([k, v]) => names.has(k) && presetColor(v) ? [[k, presetColor(v)]] : [])) })).filter((p) => Object.keys(p.values).length);
|
|
2281
|
-
const scene = { ...result.scene, ...effect.description ? { description: effect.description } : {}, ...presets.length ? { presets } : {} };
|
|
2318
|
+
const scene = { ...result.scene, ...effect.description ? { description: effect.description } : {}, ...presets.length ? { presets } : {}, ...effect.trigger ? { trigger: effect.trigger } : {} };
|
|
2282
2319
|
const notes = [...result.notes];
|
|
2283
|
-
if (effect.trigger) notes.push(`The effect plays on ${effect.trigger}; scenes play through, so the trigger is not kept (pass it back to toFlairVectorEffect).`);
|
|
2284
2320
|
return { scene, notes, issues: checkMotionScene(scene) };
|
|
2285
2321
|
}
|
|
2286
2322
|
|
|
@@ -2359,6 +2395,7 @@ function toLottie(scene, options = {}) {
|
|
|
2359
2395
|
const timeline = compileMotionScene(scene);
|
|
2360
2396
|
const nodes = indexMotionNodes(scene.artwork.nodes);
|
|
2361
2397
|
const notes = [];
|
|
2398
|
+
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).`);
|
|
2362
2399
|
let sampled = 0;
|
|
2363
2400
|
const track = (id, p) => timeline.tracks.get(motionTrackKey(id, p)) ?? [];
|
|
2364
2401
|
const layers = (id, p) => timeline.tracks.get(`${motionTrackKey(id, p)}\0add`) ?? [];
|
|
@@ -2987,6 +3024,10 @@ var SETTINGS = {
|
|
|
2987
3024
|
name: { type: "string", minLength: 1, description: 'Short name, e.g. "logo-reveal".' },
|
|
2988
3025
|
description: { type: ["string", "null"], description: "What it shows; null clears." },
|
|
2989
3026
|
loop: { type: "string", enum: ["none", "loop", "ping-pong"], description: "Playback past the end (default none)." },
|
|
3027
|
+
trigger: {
|
|
3028
|
+
anyOf: [{ type: "string", enum: ["click", "hover", "press", "scroll"] }, { type: "null" }],
|
|
3029
|
+
description: "Play in answer to the viewer when exported to Flair: click (nothing plays until a click; each click plays the next shot, then the first again), hover or press (plays while the pointer is over or down, rewinds when it leaves), scroll (scrubs as it scrolls past). null plays on its own (default). The editor previews it played through."
|
|
3030
|
+
},
|
|
2990
3031
|
fps: { type: "number", minimum: 1, maximum: 120, description: "Sampling rate for exports (default 30)." },
|
|
2991
3032
|
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).' },
|
|
2992
3033
|
beat: {
|
|
@@ -3109,6 +3150,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3109
3150
|
artwork: { width: s.artwork.width, height: s.artwork.height },
|
|
3110
3151
|
duration: compileMotionScene(s).duration,
|
|
3111
3152
|
loop: s.loop ?? "none",
|
|
3153
|
+
...s.trigger ? { trigger: s.trigger } : {},
|
|
3112
3154
|
...s.target ? { target: s.target } : {},
|
|
3113
3155
|
...includeElements ? { elements: describeMotionElements(s) } : {},
|
|
3114
3156
|
shots: describeMotionShots(s),
|
|
@@ -3454,7 +3496,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
|
|
|
3454
3496
|
const setSettings = {
|
|
3455
3497
|
name: "set_animation_settings",
|
|
3456
3498
|
title: "Change animation settings",
|
|
3457
|
-
description: "Sets the name, description, loop mode, export frame rate, stepped time, beat grid, narration word timings or target length. Returns the timing.",
|
|
3499
|
+
description: "Sets the name, description, loop mode, trigger (click, hover, press or scroll), export frame rate, stepped time, beat grid, narration word timings or target length. Returns the timing.",
|
|
3458
3500
|
inputSchema: object(SETTINGS),
|
|
3459
3501
|
annotations: { title: "Change animation settings", ...WRITE_IDEMPOTENT },
|
|
3460
3502
|
handler: (args) => apply({ op: "set_settings", ...args }, "Change settings")
|
|
@@ -3580,6 +3622,7 @@ Working method
|
|
|
3580
3622
|
1. get_animation to learn the element ids (set_animation_artwork_svg first if there is no artwork: give every element you will animate an id; or import_flair_effect to start from a Flair effect and edit it).
|
|
3581
3623
|
2. Plan a few shots, each one idea. Add them with insert_shots (add_commands, update_command, move_command and delete_commands refine a shot), or edit_animation to make several edits as one step (dry_run first when unsure).
|
|
3582
3624
|
3. To hit a length, fit_animation (keep the shots whose pace matters). check_animation and fix every error and warning; render_animation_frame (shot + "end") to look at the result; add onion_skin or motion_paths to see the motion in one picture, or get_motion_path for the numbers.
|
|
3625
|
+
- 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.
|
|
3583
3626
|
4. To make a reusable Flair effect, set_animation_controls (colour controls stand for every use of their default colour) and export_flair_effect.
|
|
3584
3627
|
|
|
3585
3628
|
Keep motion purposeful: one thing moving at a time reads best, ease-out for arrivals, ease-in for exits, and hold long enough to see each result.`;
|
|
@@ -3885,6 +3928,7 @@ export {
|
|
|
3885
3928
|
MOTION_REPEAT_MODES,
|
|
3886
3929
|
MOTION_SPEED_RANGE,
|
|
3887
3930
|
MOTION_SPLIT_ORIENTATIONS,
|
|
3931
|
+
MOTION_TRIGGERS,
|
|
3888
3932
|
MotionSceneFormatError,
|
|
3889
3933
|
activeSegment,
|
|
3890
3934
|
applyMotionControlValues,
|