Pixerate animation editor
A scene is artwork (an SVG parsed into vector paths and groups, each with an id) plus an
ordered list of shots. A shot optionally moves the camera, plays its run of commands,
then holds (default 600 ms). Commands play one after another unless "with": "previous";
each has a default length taken from the content (enter 600 ms, exit 450, move 700, draw
follows the path length), so leave duration out unless you mean to change the pace. Every
frame is a pure function of time.
Ids: element ids come from get_animation (elements) or find_animation_elements; shot ids
are ones you choose ("intro"); commands are addressed by shot id plus their index in the run.
Times are milliseconds, positions are document units of the artwork. Anything that enters
later is hidden until its enter; anything that never enters is visible from the start.
For errors, namespaced tool names and the generic command tools, see pixerate-agent-tools.
The full command vocabulary (every type, option and default) is in
references/commands.md.
Workflow skills
For these jobs, load the workflow skill too: it has the method, the checks between steps and the pitfalls, and uses the tools below.
pixerate-animation-motion-graphics: shots, staggered entrances, easing, holds, fitting a length.pixerate-animation-logo-reveal: a short reveal from the logo's parts, on the beat, ending held.
Working method
- Read.
get_animationfor elements, shots with timing, clips, drivers and issues. If there is no artwork,set_animation_artwork_svgfirst (give every element you will animate an id), or start fromimport_flair_effect/import_pptx_animation. For outlined text,get_text_layoutshows the letter, word and line units. - Plan shots, one idea each. Write down what the viewer should notice in each shot and in what order, then map each beat to a command. Hidden end states (morph / match targets, follow paths) must exist in the artwork before you reference them.
- Write in batches.
insert_shotsfor whole shots;edit_animationfor several related edits as one undo step (dry_run: truefirst when unsure;"$0.indexes[0]"and"$last.shot"refer to earlier ops). Refine withadd_commands,update_command,move_command,delete_commands. Usewrite_animationonly to replace every shot. For a command type you have not written before,describe_animation_commandreturns its exact fields first. For motion that should feel performed rather than keyed (a hand-drawn swoop, a jittery drag, a colour picked mid-move),record_animation_takewith timed samples records it as one shot, the way a person records live on the stage. - Fit and cue.
fit_animationto hit a length (keep shots whose pace matters). For music or voiceover,set_animation_settingswithbeatornarration, read cues withget_timing_grid, and give shots"at": { "beat": n }or{ "word": i }. - Check.
check_animation; fix every error and warning (codes such astoo-fast,overlap,out-of-frame,enter-visible,cue-missed). Useget_motion_pathfor spacing and arcs as numbers. - Look.
render_animation_framewithshot+at: "end", ortimesfor a contact sheet, plusonion_skin/motion_pathsto see motion in one picture. Render after a batch, not after every edit.seek_animationshows the person a moment. - Export when asked:
export_flair_motion,export_flair_effect(afterset_animation_controls) orexport_lottie; read the returned notes on what was sampled or dropped.
Best practices
- One idea per shot, one focal motion at a time. Stage the action so the eye knows where
to look; secondary elements move less, later, or not at all. Use the camera (
framea node) to direct attention rather than moving everything. - Ease every change. Arrivals ease out (decelerate into place; the default for
enter), exits ease in (exitwithease: "ease-in"), moves ease in-out (the default). Uselinearonly for mechanical motion (a constant spin, a progress bar) or loops. - Timing by size and distance. Small UI changes 150-300 ms, element entrances 300-600 ms,
large moves and camera moves 600-1200 ms. Nothing under 120 ms (
too-fast). Big things move slower than small things. - Anticipation and follow-through.
ease-in-backfor a wind-up before a fast exit;pop,rise,ease-out-backor a spring preset (spring-gentle,spring-quick) for overshoot and settle on arrival. Usespring-bouncysparingly; it reads as playful. - Overlapping action. Stagger related items 40-120 ms (
stagger, orsplitwithcascadefor text) instead of moving them in lockstep; start secondary motion with"with": "previous"plus a smalldelayso it trails the lead. - Arcs. Natural movement curves: use
movewithviawaypoints (one smooth path) instead of chained moves that stop at each point, orfollowa path node. - Recorded takes. Sample a performance at 30-60 per second; the recorder keeps only the
points that matter (raise
tolerancefor fewer, cleaner commands). Begin each moving element with a sample at its current pose (get_motion_path's last point, or its bounds' centre at rest) or it jumps there at its first sample. A take is a new shot after the others (or atat); it cannot be layered over an existing shot. Refine it like any shot: it is ordinarymove(withviaandtimes),scale,rotate,fadeandstylecommands. - Hold long enough to read. Leave each result on screen (shot
hold, default 600 ms); roughly 250 ms per word for text that must be read, longer for the final frame or logo. - Exaggeration with restraint. Emphasis (
pulse,shake,teeter,color-pulse) is for one thing that needs attention, once; it returns to rest on its own. - Motion blur only for genuinely fast motion (
motionBlur: { shutter: 180 }); it affects the stage and rendered frames, not Flair or Lottie exports. - Accessibility. Avoid flashing: never more than three flashes a second (WCAG 2.3.1), so
keep
color-pulseand fades on large areas slow and few. Avoid large-scale parallax, zooms and spinning for essential UI motion; ship a reduced-motion alternative (the host should swap in a fade or the end state underprefers-reduced-motion; this editor does not generate one). Loops that run longer than 5 s need a way to pause (WCAG 2.2.2). - Interactive pieces. For a button or toggle set
trigger(click,hover,press,scroll); for a click toggle, make the last shot restore the starting state.
Tool reference
Read
| Tool | Use it to |
|---|---|
get_animation | Start here. Returns name, artwork size, length (ms), loop, elements (id, type, name, parent, bounds, solid paints, live effects with numeric params), every shot with each command's index, start, end and flairPrimitive, clips, drivers, controls and an issue summary, plus readOnly when edits are refused. includeElements: false (default true) skips the element list on large artwork. |
get_shot | Read one shot as stored (shot id) with its start/end and each command's start/end in ms; cheaper than get_animation while refining one shot. |
describe_animation_command | Before writing a command type you have not used yet, or when a write rejects a field: returns the full JSON Schema of each of types (e.g. ["enter", "move"]), with every field's type, range, default and meaning and which are required. The write tools list every command field once in short, prefixed with the types that take it. |
find_animation_elements | Find elements whose id or name contains query (case-insensitive; limit default 20, max 200) when the artwork is large. Returns id, type, name, parent, bounds, paints, effects. |
get_text_layout | Before animating outlined text with split: returns the group's lines, words and letter ids in reading order. Errors if the element is not a group of paths (convert text to outlines, one path a letter, and group it). |
get_motion_path | Check spacing, arcs and landing points as numbers: samples a node's centre (document units) from from to to ms every step ms (default 33, at most 400 samples), with where each moving change starts and ends. |
get_timing_grid | List beats (number, ms, bar, beat in bar) and narration words (index, text, start, end) between from and to (limit default 200), and which shot plays at each, to choose at cues. Empty, with a hint, when no beat grid or narration is set. |
check_animation | After every batch of writes. Lists issues with a code, severity, shot, command index, node ids, measured vs needed values and how to fix it. Fix errors and warnings; notes are advisory. |
render_animation_frame | Look at the result: time (ms) or shot + at (start, middle, end; default end). times (2-16 moments) makes a labelled contact sheet (columns 1-8). onion_skin adds ghost frames (before default 2, after 0, spacing ms or "commands"); motion_paths (true or ids) draws travel paths. SVG by default; format: "png" only when the host can rasterize. |
export_flair_motion | Get the scene as a Flair SvgMotion { svg, animate } with hold, sampled-step count and notes. fps (default scene fps, else 30), curves and behaviors (default true), flair target version (default 0.39; older versions get springs, steps, behaviours and curves sampled). |
export_flair_effect | Get a Flair catalog vector effect (id kebab-case, name, description, category default icon, tags, plus curves / behaviors / flair as above). Call set_animation_controls first so colours become {{name: color}} controls. |
export_lottie | Get Lottie (Bodymovin v5) JSON for lottie-web and mobile players, with a marker per shot, fps (default scene fps, else 30), the sampled keyframe count and notes on what was not carried over (gradients, dashes, reveal clips, morphs that change point counts). |
Write
| Tool | Use it to |
|---|---|
seek_animation | Show the person a moment: time (ms) or the start of a shot, with play true or false. Does not change the scene. |
set_animation_artwork_svg | Replace the artwork with a standalone svg (with a viewBox) as one undo step. Put an id on every element you will animate; refused if existing shots name ids the new artwork lacks. Returns the elements. |
import_pptx_animation | Replace the whole scene with a PowerPoint slide's shapes and animation pane (data base64 .pptx, slide default 1): one shot per click, delays, repeats and acceleration kept; text, pictures and charts are left out with notes. Run with dry_run: true first. |
set_animation_drivers | Replace all drivers (empty list clears): a target's x, y, rotation, scaleX, scaleY or opacity follows a source node's property as change · factor + offset, optionally clamped. For parallax, wheels that turn as they roll, shadows that fade as something rises. |
set_animation_clip | Define, replace or (with clip: null) delete a named reusable clip whose run targets "$"; play it with a play command on any nodes. Prefer a clip over repeated identical commands. |
copy_animation | Give the nodes in to every command that animates from (all shots or shots), each copy starting with its original, optionally staggered (ms). Quick for one-off duplication; use a clip for motion you will reuse. |
record_animation_take | Record performed motion as a new shot (one undo step): samples of { node, t (ms into the take), x, y (centre), scaleX, scaleY, rotation, opacity, fill, stroke, strokeWidth } become a move through waypoints at the recorded times and a few eased scale / rotate / fade / style commands, each starting when it happened. Optional length, id, label, at, tolerance; dry_run: true returns the run first. Returns the shot id, its start and each command's index, type, start and end; check_animation and render_animation_frame after. |
fit_animation | Make the scene last seconds by setting shot speed, keeping proportions; shots in keep play as written. dry_run: true reports the new length and speeds first. |
import_flair_effect | Replace the whole scene with a Flair vector effect or SvgMotion motion (give exactly one; optional name). Placeholders become colour controls; each Flair step becomes a shot. Use dry_run: true first. |
insert_shots | Add one or more complete shots (id, run, optional label, camera, hold, speed, at) at position at (default the end). Returns every shot's timing and issues. |
update_shot | Change one shot's label, camera, run, hold, speed, at or id via set, and clear label, camera, hold, speed or at via remove. |
delete_shots | Remove shots by id (one undo step). |
move_shot | Reorder a shot to index to (0 = first). |
add_commands | Add commands to a shot's run at index at (default the end). Returns the indexes they got and their timing; use those indexes for later updates. |
update_command | Change one command (by shot and command index): fields in set replace, names in remove clear (e.g. "delay"). Returns the command and its timing. |
delete_commands | Remove commands from a shot by index; later commands move up, so re-read indexes afterwards. |
move_command | Move one command to index to in its run; a "with": "previous" command then starts with its new neighbour. |
set_animation_settings | Set name, description, loop (none, loop, ping-pong), trigger (click, hover, press, scroll, or null), export fps (default 30), scene steps (12 = on twos; null smooth), motionBlur, beat (bpm, offset, meter), narration word timings, or target length [min, max] seconds. |
set_animation_controls | Set the colour controls (name, type: "color", default #rrggbb used in the scene, label) and presets a Flair effect exposes. Replaces existing controls; an empty list clears. |
edit_animation | Apply several ops (set_settings, insert_shots, update_shot, delete_shots, move_shot, add_commands, update_command, move_command, delete_commands, set_controls) as one all-or-nothing undo step; refer to earlier outcomes with "$0.indexes[0]", "$last.shot". dry_run: true validates without applying. The default for multi-step changes. |
write_animation | Replace every shot (and optionally settings, controls, presets) while keeping the artwork. Only for a full rewrite; per-operation tools give better errors. |
undo_animation | Undo your last edit (one tool call or one edit_animation batch). |
redo_animation | Redo the edit you just undid. |
Effects
These tools come from createAnimationEffectsToolProvider and work when the host has registered an
effects provider (for example Flair). Without one, search_effects and describe_effect return
available: false, list_applied_effects still lists what the scene holds, and the write tools
refuse.
| Tool | Use it to |
|---|---|
search_effects | Find effects: kind motion (primitives to apply to nodes) or vector (effects with their own picture), query, category. kind camera lists camera moves (with camera: role transition or hold, durationMs, cut); give them to a shot with set_shot_camera_move, not apply_effect. |
describe_effect | Read an effect's controls (names, ranges, units), defaults and presets, and whether it appliesHere (a motion effect). |
list_applied_effects | See the provider effects in the scene: their instance ids, the nodes they animate, their shots and values. |
apply_effect | Animate a node (target, a group animates as one) with a motion effect: the changes become ordinary commands, tagged with the effect, in a new shot after the last. Returns the instance id. |
update_effect | Make an applied effect again with new values, in the same place (effect is its instance id). |
remove_effect | Remove an applied effect: its commands, shots it alone filled and a vector effect's group. |
add_vector_effect | Add a vector effect's own picture as an artwork group (fitted into box) with its motion as new shots. For an effect that draws along a path (search_effects accepts: ["path"]: a signature, a route), path: { node } runs it along a path node and lands it on the node, path: { text } writes words. Use it when the effect should trace the path itself; use follow or a draw-on to move or reveal your own art. Returns the instance and group ids. |
set_vector_effect_path | Give a vector effect already added (instance from add_vector_effect or list_applied_effects) a new path in place: path: { node } runs it along a path node and lands it on the node, path: { text } writes words and keeps the picture where it was. Call it after reshaping the node an effect runs along (the path is a copy), or to switch between a node and words; clear the path with update_effect setting the path control to "". One undo step. Returns the instance, the control set and its new path data value. |
list_camera_moves | List the provider's camera moves for a role (transition: how the camera gets into a shot; hold: how it moves while the shot holds), with durationMs and cut. Returns available: false without camera moves. Call before set_shot_camera_move; describe_effect gives a move's controls and presets. |
set_shot_camera_move | Give a shot a camera move (shot, role, move, optional ms for a transition, preset, values): it is saved on the shot's camera as in or during. Returns the shot's camera and the window (ms) the move plays in. A wrong-role id is refused naming the moves that fit. |
clear_shot_camera_move | Remove a shot's move for a role, keeping its framing. Returns the shot's camera (null when nothing is left). |
list_shot_layers | See every shot's layers (ids, effect, subject, role, rect, start / end in ms) and its transition. Works without a provider. Call before changing a layer. |
add_shot_layer | Add a layer to a shot: a provider effect (a generator background, a filter applied to a subject, an overlay or title) or a bare subject (picture, SVG, words). Fills the screen unless given a rect; shows until the next shot unless until says. Returns the layer with its id. |
update_shot_layer | Change a layer's fields; list optional ones in clear to remove them. Returns the layer. |
move_shot_layer | Restack a layer in its shot (index, 0 = bottom). |
remove_shot_layer | Remove a layer. |
set_shot_transition | Set the transition into a shot from the one before (a provider effect with use transition, its ms, preset, values). Not on the first shot. Returns the transition with start / end. |
clear_shot_transition | Remove a shot's transition, so it cuts (or the camera eases) again. |
list_templates | List the provider's sequence templates (query, tags): ids, names, shot counts, lengths. Returns available: false without templates. Call before describe_template. |
describe_template | Read a template's slots (type, label, default, limits), its valuesSchema and exampleValues. Call before fill_template. |
fill_template | Fill a template (template, values, name, mode replace or append) and load its shots as one undo step. Every value that does not fit is refused at once. Returns the new shots, layers, openSlots and notes. |
Save and open
The host may add the shared document tools (see pixerate-agent-tools). An animation document is the MotionScene (artwork, shots, clips, drivers); the playhead is not part of it.
| Tool | Use |
|---|---|
get_animation_document | Take a copy of the whole animation as { kind, formatVersion, revision, document } before a risky rewrite, or to hand it on. To read the animation, use get_animation: it is smaller and says more. Refuses very large documents. |
load_animation_document | Put back a copy from get_animation_document (its document, or the whole result). Checked first: when anything is wrong nothing changes and the error says what. One undo step (undo_animation brings the previous scene back). Refused while the editor is read-only. To edit part of a scene use edit_animation. |
save_animation_document | Save the animation under a name in the host's storage (the same name replaces that copy). Returns the key. Only listed when the host has storage. Save when the user asks, not after every edit. |
list_saved_animation_documents | List saved animations (key, name, savedAt), newest first. |
open_saved_animation_document | Replace the animation with a saved one by key. One undo step. Ask before opening over changes the user has not saved. |
Camera moves
With a provider that has camera moves (Flair: camera-glide, camera-whip-pan,
camera-punch-zoom, camera-cut to get in; camera-ken-burns, camera-crash-zoom while
holding), a shot's camera can play one as it arrives and one while it holds:
- Frame the shot as usual (
update_shotwithcamera: { frame: "<id>" }or a rectangle). A move without a framing keeps the one the camera has. list_camera_moveswith therole, pick bydescription, thenset_shot_camera_move. Use a preset (describe_effectlists them) before hand-tuningvalues.- A transition's
mssets how long it takes (default the move's own, written out on the shot); a hold move plays across the shot'shold, so lengthen the hold for a slower drift. The next shot's move starts from where a hold move ends. render_animation_framemid-move to look, andcheck_animation:camera-move-first-shot(the first shot cuts, so its transition does not play),camera-move-unknown,camera-move-values,camera-move-not-played(no provider with camera moves: the camera eases between framings instead).
Exports to Flair tag each camera change with <move>@<shot>; with the provider set the camera
is sampled from the move, and a cut stays a jump.
Shot layers and transitions
With a provider that draws pixels (Flair: gradients, light, film looks, lower thirds, image filters, 30 transitions), a shot can show effects as layers over and under its artwork, as Flair's scenes do:
search_effectswithusegenerator(backgrounds),filter(changes a picture),overlayortitle, thenadd_shot_layer. A filter needs asubject({ image },{ svg },{ text }); a generator or title draws its own picture and takes none.roleplaces it:backgroundunder the artwork,subjectover it,overlayover everything. A layer with arectsits on the artwork and moves with the camera; without one it fills the screen.until: { shots: 2 }keeps a background going under the next shot too;fadesoftens its start and end.search_effectswithusetransition, thenset_shot_transitionon the shot it leads into (never the first). With no camera move in, the camera cuts and the transition does the move; with one (set_shot_camera_move), both play together.render_animation_frameto look (it waits for the provider's pictures), andcheck_animation:layer-effect-unknown,layer-effect-values,layer-slot-empty(a{ slot }subject nobody filled),transition-unknown,transition-first-shot,layer-not-drawnandtransition-not-played(no provider: effect layers are left out and transitions crossfade).
A provider's sequence templates are whole scenes of such shots with slots to fill (a
product reveal, before and after, a stat countdown): list_templates, describe_template, then
fill_template with values (start from exampleValues). mode replace (default) makes a new
scene the size of the template's stage; append adds its shots after yours, scaled to the
artwork. Titles and captions become overlay word layers. Fill the openSlots it reports with
update_shot_layer (subject), then animate artwork over the shots as usual.
Layers are pixels: the Flair SvgMotion export leaves them out. Use them for backgrounds, looks
and titles, and keep what should animate node by node in the artwork.
Pitfalls
-
A transition belongs to the shot it leads into. Setting one on the first shot is refused; moving a shot with a transition to the front makes it a
transition-first-shotnote. -
Layer effects are not motion effects. A transition or a camera move is refused as a layer, and a motion effect (
fade-in) goes on nodes withapply_effect. -
One move per role per shot. Whip pans and cuts jump half way: put them between framings that differ, and do not follow a cut with a long glide into the same framing.
-
With agent playback on, the cursor clicks the shot a call names in the timeline and visits the stage elements its commands target. Results are unchanged.
-
Effect commands are ordinary commands. You can retime or edit them with
edit_animationlike any command, butupdate_effectreplaces all of an effect's commands. Change values through the effect, and timing through the commands. -
Some provider motion cannot be carried over. Counting, writing text and similar changes are skipped. The result's
notessay what was left out. -
Fields belong to types. The write tools' command schema lists every field of every type once; a field the type does not take (
clipon amove,toas a point on afade) is refused when the edit is applied, naming the shot, command and field. Calldescribe_animation_commandfor the exact fields of a type rather than guessing. -
Unknown ids are refused with a "did you mean" suggestion. Take ids from
get_animationor the elementsset_animation_artwork_svgreturns; never guess them. -
enter-visible: an element that enters while already showing blinks out first. Give an element that should appear later anenterbefore anything else moves it; do notenteran element that should be visible from the start.exit-hiddenis the reverse: enter it first. -
overlap: two commands changing the same property at once; the later takes over. Sequence them, or use"blend": "add"on move, rotate or scale to stack. Emphasis already stacks. -
Reveals need a box:
wipe,iris,spliton a lone straight line fade instead (reveal-no-box); usedraw/undrawfor lines. -
Morph and match targets stay hidden. Draw the end state as a separate hidden node or group; for
match, parts the end state adds need a partner (same name) in the start group, or they never appear (match-unpaired). -
Draw a group one way. Do not mix per-stroke drawing (
order,pace,comet) with a plaindrawon the same group in one scene. -
Indexes shift. After
delete_commandsormove_command, indexes change; use what the write returned orget_shotbefore the next index-based edit. -
Springs set their own length. Leave
durationout with a spring; a shortdurationcuts it off (spring-cut-short). -
Click triggers play nothing until the first click; each click plays the next shot. A triggered scene ignores
loop(trigger-loop), and clicks decide when shots start, so do not give its shotsatcues (click-cue). -
Exports approximate. Motion blur is never exported; Lottie drops gradients, dashes and reveal clips; back eases on colours or opacity are sampled for Flair. Read the notes and tell the user what changed.
-
Read-only: when
get_animationreturnsreadOnly, write tools are hidden; read, render and export still work. Tell the user rather than working around it.