Guides
Keyframes and easing
How keyframes work on a layer's own clock, the verbs that write them, easing and speed, loops, wiggles, motion paths and parenting.
Anything that moves in Ymotion moves because one of its properties has keyframes. A fade is two keys on opacity, and a pop is three keys on scale. This page covers how keys work, the verbs that write them, how to shape the motion between them, and some starting points for timing.
How a keyframe works
Every animatable number on a layer has a path, such as opacity, transform.y or filters.0.amount. A property with no keys holds its static value for the whole layer. Once it has keys, the curve through them decides the value at every moment, and the static value is no longer used.
Key times are seconds from the layer's own start, not from the start of the timeline. A layer that begins at 2 s and fades in over its first half-second has keys at 0 and 0.5. Because of this, moving a layer in time takes its animation with it.
To see what a layer can animate, with each property's range, current value and the verbs that set and key it, ask for its properties:
ymotion_read {"what":"properties","layerId":"<layer id>","like":"transform"}
Writing keys
Two keys: keyRamp
keyRamp is the shortest way to say "from here to there". It takes the path, the two values and, optionally, when the move starts and ends and the ease:
ymotion_edit {"label":"title in","ops":[
{"verb":"keyRamp","args":{"layerId":"<layer id>","path":"opacity","from":0,"to":1,"opts":{"start":0,"end":0.4,"ease":"cubicOut"}}},
{"verb":"keyRamp","args":{"layerId":"<layer id>","path":"transform.y","from":0.04,"to":0,"opts":{"start":0,"end":0.5,"ease":"cubicOut"}}}
]}
If you leave out start it is 0, and if you leave out end it is the end of the layer. The ease defaults to cubicOut.
The two values are where the property is, not offsets from where it rests. The rise above suits a title resting at the centre; one resting at y 0.3 would ramp from 0.34 to 0.3.
keyRamp replaces everything already on that path. That makes it easy to redo, but running it again on the same path to add a fade-out loses the fade-in.
Several keys: putTracks
For more than two keys, or for handles, holds, loops or a wiggle, write the whole track with putTracks. It merges by path: keys at new times are added, and a key at the same time as an existing one replaces it. Here is a fade in and a fade out on one track:
ymotion_edit {"ops":[{"verb":"putTracks","args":{"layerId":"<layer id>","tracks":[
{"path":"opacity","keys":[{"t":0,"value":0,"ease":"cubicOut"},{"t":0.4,"value":1},{"t":3.6,"value":1,"ease":"cubicIn"},{"t":4,"value":0}]}
]}}]}
Pass "options":{"replace":true} to replace the path's whole track, removing omitted modifiers. A scalar position track replaces only that coordinate and keeps the other motion-path coordinate exactly. A supplied paired track owns both named coordinates. Other paths stay. Without replacement, omitted modifiers are retained and incoming ones win. ymotion_help {"topic":"types","name":"Keyframe"} lists every field a key can carry.
One key at a time
keyOnpins a value atlocalT. Leave outvalueand it pins the curve's current value before its wiggle, so live noise is not added twice. An existing key retains its ease, handles, hold and geometry unless an ease is explicitly given. On either motion-path coordinate it updates that waypoint and keeps the other coordinate.setPropwithatfollows After Effects' auto-keyframing. On a property that already has keys, it adds or updates a key at that moment. On one with no keys, it sets the static value, so usekeyOnorkeyRampto start an animation.setKeyValue,moveKeyandunkeychange, move or delete one key.moveKeykeeps the key's ease and handles.clearKeysdeletes a whole track, and with nopathit deletes every track on the layer.
To read back what you wrote, use ymotion_read {"what":"keys","layerId":"<layer id>","path":"opacity"}. For the resolved value at a moment, use ymotion_read {"what":"value","layerId":"<layer id>","path":"opacity","t":0.2}, where t is seconds from the layer's start.
Easing
A key's ease shapes the segment from that key to the next one. You can name a curve:
linear, hold, easyEase, easyEaseIn, easyEaseOut, sineIn, sineOut, sineInOut, quadIn, quadOut, quadInOut, cubicIn, cubicOut, cubicInOut, quartIn, quartOut, quartInOut, quintIn, quintOut, quintInOut, expoIn, expoOut, expoInOut, circIn, circOut, circInOut, backIn, backOut, backInOut, elasticIn, elasticOut, elasticInOut, bounceIn, bounceOut, bounceInOut
or give four numbers in the same form as CSS cubic-bezier, such as [0.16,1,0.3,1].
The suffix says where the slow part is. An Out curve starts fast and settles, which suits things arriving. An In curve starts slow and leaves fast, which suits things exiting. An InOut curve or easyEase suits a move between two resting places, and linear suits constant motion such as a steady spin. The one-sided names follow the same rule, so easyEaseIn is a slow start. That differs from After Effects' Easy Ease In, which eases a key's arriving side; here, that's the key's in handle.
Easy Ease, handles and speed
easyEase is After Effects' F9. It gives the key at localT a third of influence on either side and zero speed:
ymotion_edit {"ops":[{"verb":"easyEase","args":{"layerId":"<layer id>","path":"transform.scale","localT":0.5}}]}
For finer control, use setKeyHandles. A handle's x is its influence, as a fraction of the segment's duration, and its y is how far up the change it reaches. {"x":0.33,"y":0} is F9, and a longer x such as 0.75 gives a stronger ease. out shapes the segment leaving the key and in the one arriving, so a landing can be softened without touching the start. Between two keys with the same value, a handle's slope (units per second) makes a bump. smoothKey and smoothTrack make speed carry through a key (After Effects' auto-bezier), and breakKey lets a key's two handles move independently.
setKeyEase changes the whole segment leaving its key, replacing handles or Auto Bezier that would otherwise hide the requested curve. Its neighboring segments keep their actual motion. A manual setKeyHandles converts that key out of Auto Bezier and keeps its untouched side; stated slopes work on numeric, colour, outline and motion-path tracks alike.
Holds
holdKey, or an ease of "hold", keeps a key's value until the next key and then jumps, which is how step animation is made. posterizeKeys with a step of 8 or 12 samples a whole track that many times a second, for a stop-motion feel.
Loops and wiggle
A track can repeat beyond its last key. loopKeys sets After Effects' loopOut and loopIn on an existing track, through modes such as {"out":"pingpong"}: cycle repeats, pingpong goes back and forth, offset repeats while adding the change each time, and continue carries on at the final speed. A pulse that runs for the life of the layer is one cycle of keys and a loop:
ymotion_edit {"ops":[{"verb":"putTracks","args":{"layerId":"<layer id>","tracks":[
{"path":"transform.scale","keys":[{"t":0,"value":1,"ease":"sineInOut"},{"t":0.6,"value":1.08,"ease":"sineInOut"},{"t":1.2,"value":1}],"loopOut":"cycle"}
]}}]}
putTracks also accepts a finite window on a track: {"start":1,"end":3} makes its keys and modifiers inactive before 1 and at or after 3 layer-local seconds, leaving the property's flat value there. "after":"hold" instead holds the value sampled at the exact end. The boundary is checked before posterizing time. This works for numeric and spatial tracks, paints, outlines and Source Text; omitting the field keeps their existing unbounded behavior. Whole-track offsets, speed retiming, splits and trims carry the window with its keys.
wiggleProp adds a smooth random drift. freq is wobbles per second, and amp is in the property's own units: degrees for rotation, a fraction of the frame for position. A wiggle renders the same every time, and two tracks with the same seed move together:
ymotion_edit {"ops":[{"verb":"wiggleProp","args":{"layerId":"<layer id>","path":"transform.rotation","wiggle":{"freq":1.5,"amp":0.8,"octaves":2,"seed":3}}}]}
For a hand-held feel on a title, try freq 1–2 and an amp of about 0.004 on transform.x and transform.y, with different seeds. clearKeys on the path removes a wiggle together with that path's keys (wiggleProp takes a wiggle object here, not null), and bakeKeys writes out what a loop or wiggle is doing as one key per frame.
Baking leaves keyed source text and keyed shapes unchanged, with their words, geometry and complete metadata. Simplifying those tracks also keeps every key. Straight numeric tracks can still be simplified; nonlinear, handled, held, smooth or roving keys remain intact. Both axes of a spatial track count when simplifying, so a vertical corner is retained.
Motion paths
By default, transform.x and transform.y are keyed separately. After Effects calls this Separate Dimensions. Each axis can have its own ease, so an x that's linear paired with a y that's quadOut already traces an arc.
For a path you shape directly, keyMotionPath drives both axes from one set of waypoints. out2 and in2 are tangent offsets from the waypoint, in the same fractions of the frame as the position. This one arcs from the lower left, over the top and down to the lower right:
ymotion_edit {"ops":[{"verb":"keyMotionPath","args":{"layerId":"<layer id>","points":[
{"t":0,"x":-0.35,"y":0.3,"ease":"easyEaseIn","out2":[0.1,-0.25]},
{"t":0.8,"x":0,"y":-0.1,"ease":"easyEaseOut","in2":[-0.12,0],"out2":[0.12,0]},
{"t":1.6,"x":0.35,"y":0.3,"in2":[-0.1,-0.25]}
]}}]}
Two details make it read as one gesture. A waypoint with no tangents of its own is a corner, so the top one gets level tangents on both sides. And each ease shapes only the segment after its key, so easyEase on the first key alone would bring the layer to a stop at the top and land at full speed; a slow start on the first segment and a slow finish on the second keep it moving through the top and settle it at the end.
Spatial tangent and roving commands require a motion path, including an exact projected coordinate; a plain scalar track is refused. The path is stored under transform.x, with each key carrying its y. setSpatialTangents on transform.x bends it at one waypoint, roveKeys re-times the waypoints you name so each leg between fixed ones takes time in proportion to its length (eases still shape the speed within a leg), and setProp with at on either axis moves a waypoint along that axis. keyMotionPath replaces any keys already on the two axes, and clearKeys on transform.x removes the path. To check the path, read the keys on transform.x or render it; ymotion_read with "what":"value" resolves either axis off the path.
A scalar ramp, wiggle or one-coordinate copy separates a motion path without sampling it into approximate keys. Only the requested coordinate changes; the other retains its exact curve, spatial and temporal easing, roving, loops, steps and own noise. Selecting a y path copies that coordinate alone; toYPath explicitly copies both coordinates as a pair. A saved paired track's legacy wiggle applies only to its primary coordinate. continue extends both edge velocities.
The editor's Separate Dimensions switch retains those exact projections. Compatible untouched twins rejoin exactly; independent curves remain separate with a reason, rather than changing their motion to make a shared path.
Motion blur
Motion blur is a per-layer switch in the editor's Properties panel, and there's no verb for the switch itself. Once it's on, its settings are ordinary properties: motionBlur.shutter (degrees, where 180 is the film default), motionBlur.phase and motionBlur.samples. Each composition's defaults live on its own canvas, and its layers with the switch on use them unless they set their own, including when that comp is placed, retimed or reversed. A smaller angle gives a shorter, crisper smear: ymotion_edit {"ops":[{"verb":"setCanvas","args":{"patch":{"motionBlur":{"shutter":90}}}}]}.
Parenting
A parented layer moves inside its parent's transform and keeps its own animation. A null layer ({"kind":"null"}) is a transform with nothing to draw, made for this. With keep, the child stays where it is on screen, as in After Effects. Without it, the child jumps by however much the parent has already moved, turned or scaled:
ymotion_edit {"ops":[{"verb":"setParent","args":{"layerId":"<child id>","parentId":"<null id>","opts":{"keep":true}}}]}
parentAll parents several layers in one go. clearParent removes the link and leaves the child's own numbers as they are, so it shifts on screen by whatever the parent was adding. setParent and parentAll accept parentId: null to lift layers out. With opts: {keep: true}, they keep the displayed transform at t (each own in point by default), including when unparenting.
Timing, as a starting point
These are places to begin, not rules:
- Durations. A small accent such as a tick or a pop takes about 0.2–0.3 s, a title arriving 0.4–0.7 s, and a move across the frame 0.6–1.2 s. Exits usually feel right at about two-thirds of their entrance. At 30 fps, anything under about four frames (0.13 s) reads as a cut rather than a move.
- Ease out for arrivals, ease in for exits.
cubicOutorquartOutlands softly,expoOutlands with more snap, andcubicInleaves cleanly. - Overshoot sparingly. A
backOut, or a key at 1.05 before settling at 1, gives a moment character. On everything, it looks nervous. - Stagger. Offset related elements by 0.05–0.1 s.
copyKeysputs one layer's curve onto others, andoffsetKeysnudges a layer's keys later. For words inside one text layer, use a text animator; see Text animators and presets. - Let it settle. Give an arrival half a second to a second of stillness before the next beat, so the eye can read what landed.
Shaping a passage
Motion has a job within the passage: introduce something, direct attention to it, reveal a relationship, or carry the viewer to the next thought. Choose that job before the preset. An arrow arriving before the relevant control is used can orient the eye; an arrow continuously pulsing over it can compete with the action it was meant to explain.
Build contrast across time. Let an ordinary phrase remain calm, build toward the decisive word or action, land the stronger gesture there, and hold the result long enough to understand it. A move that arrives and immediately leaves gives the viewer no resting state. Constant loops and evenly spaced punch-ins flatten this pattern because nothing becomes more important than what preceded it.
A punch-in belongs to a real emphasis and a useful closer view. Read the footage's existing transform and keys first, then use putTracks for the approach, hold and return on transform.scale, with position keys when the crop needs them. A fit leaves its proportions in scaleX and scaleY and resets scale to 1; an already enlarged layer may have another resting scale. Preserve that resting value and any motion that still belongs to the film rather than replacing the whole path with a guessed ramp. Inspect the start, the closest crop and the return, keeping faces, hands, controls and full-body action visible where they are the point.
Keep related gestures in one motion vocabulary: compatible direction, easing and energy, with the largest travel or overshoot reserved for the largest change of meaning. If a title, caption, graphic and footage move together, choose which should lead and let the others follow or stay still. Each move takes its sound; Sound effects for motion has the pairings and the timing.
Good to know
keyPaintwith no paint pins the current animated paint, not the hidden flat style. Replacing a paint key keeps its ease, handles and hold unless an ease is explicitly given.- Colours, mask shapes and the words of a text layer are keyed with their own verbs:
keyPaintorpaintRampfor a colour,keyOutlinefor a shape andkeyTextfor source text. A numeric writer refuses a colour field and names the paint verbs. ThekeyWithcolumn of the properties list says which verb each path takes. - Type at rest is drawn from cached glyphs and, a hair away from rest, from outlines. A move that crawls its last fraction of a pixel into place can therefore snap slightly on its final frame, which is why the built-in presets land while still moving.
- Check a move by looking at it.
ymotion_render {"times":[0.1,0.3,0.6]}shows the frames at those timeline seconds, so pick the moments where the motion happens.