Animations
Animations make things move. They can live on blueprints, instances, and parametric define bodies. Blueprint animations are inherited by instances; instance animations are added on top and can target the same property.
From/To Syntax
The most common form: animate a property from one value to another, over a duration.
imagine card
animate position.x from -80 to 0 over 0.4s ease "ease-out" delay 0.1s
create cardease, delay, repeat, and direction are retained when written inline.
speed, blend, weight, and disabled are reliably represented as indented
options. The same animation can be written as an indented property block
instead of the inline form:
imagine card
animate opacity
from: 0
to: 1
duration: 0.4s
ease: "ease-out"
create cardPercent keyframes animate a relative size or position: values interpolate in
percent space and resolve against the parent each frame, so they track a
parent that resizes mid-animation. A transition that mixes units on an axis,
such as from 100 to 50%, resolves both keyframes against the parent and
interpolates smoothly.
imagine dot
shape: circle
size: (10%, 10%)
animate size from (10%, 10%) to (80%, 80%) over 1s
create dotMulti-property Animations
Use one animate block when several properties describe one transition. The
optional alias names the behavior; every property shares one duration, easing,
delay, repeat count, playback direction, speed, disabled state, selector, and
stagger.
imagine title
text: "Hello world"
animate as riseFade
selector: all words
stagger: 0.08s
duration: 0.5s
ease: "ease-out"
from:
opacity: 0
position.y: 24
to:
opacity: 1
position.y: 0
create titleThe from and to maps must contain the same property paths. Omit the as
alias when the behavior does not need a name. Child properties cannot
override timing; use another animate block when a channel needs different
timing.
For text transitions, the selector is resolved once for the block. Every child property then samples the same selected units with the same stagger offsets.
Grouped transforms use transition-friendly composition: position and rotation are additive offsets, while scale and opacity multiply the authored base value. Other properties use normal replacement. This lets the example rise relative to its authored position and fade to its authored opacity.
Keyframes
For multi-stop motion, list times and values:
imagine ball
animate position.y
0s: 0
0.3s: 120 ease "ease-out"
0.6s: 0 ease "ease-in"
repeat: infinite
direction: alternate
create ballBoth 0.3s: value and at 0.3s: value are accepted. Named easing values are
defined by EasingType; cubic bezier easing uses a four-number tuple.
An ease belongs to the outgoing segment: the ease at 0s controls motion
from 0s to the next key. The final key's ease has no following segment.
Boolean keys switch at the next key's exact time. Their switch is independent
of easing, including hold, back and elastic curves. Numeric values retain
their selected interpolation. Camera active uses these ordinary boolean
tracks; camera pose transitions also use this animation engine and
its existing blend modes.
Named easing presets include expo, quint, back, bounce and elastic variants. Back and elastic can overshoot.
A cubic bezier ease shapes timing. By default, on a numeric 2D position, it
also bends the path between keys. Add interpolation: timing to keep the path
straight, or interpolation: spatial to request that existing curved behavior.
Omitting the option preserves old scenes. Components such as position.x,
3D or relative-length tuples, and every non-position tuple (size, start,
end, effect offsets) always use timing only. Spatial control does not turn
an arbitrary tuple into a motion path.
imagine dot
shape: circle
animate position from (-100, -50) to (100, 50) over 1s
ease: (0.42, 0, 0.58, 1)
interpolation: timing
create dotConstant defines, including aliases and tuple components, resolve before key
interpolation in root, parent and local scope. Local names win. The saved keys
retain their references. Expression-valued defines and formulas inside key
values are not evaluated by this constant-key path; use animate property:
for formulas. Unresolved or cyclic names stay unresolved, never an invented
numeric zero. Parametric define arguments continue to substitute before playback.
Keyframed text animations accept the same selector and stagger options as
from/to animations; filtering does not renumber each.index.
See examples for scenes you can copy and edit.
imagine ball
animate position.y
at 0s: 0
at 0.3s: 120 ease "ease-out"
create ballOne Component of a Tuple
Add .x, .y, or .z to a tuple property to animate one component and keep
the others. This works on transforms and on any other tuple, such as a line's
start and end. Here a line draws itself from left to right:
imagine underline
shape: line
start: (0, 0)
end: (0, 0)
stroke: "#ffffff"
strokeWidth: 4
animate end.x from 0 to 300 over 0.5s ease "ease-out"
create underline with
position: (-150, -40)A component animation wins over an animation of the whole tuple on the same
axis. When the tuple isn't set, the component starts from its documented
default, so end starts from (100, 0).
Expression Animations
An animation with a colon right after the property path is evaluated every frame. See expressions for the available expression scope.
imagine wiggler
animate position.x: sin(time * 2) * 30
blend: add
create wigglerPer-letter / word / line animation
On a text object, an animation can target individual graphemes, words, or lines
with a selector, and stagger each unit in time with stagger:
imagine title
text: "Hello world"
animate opacity
from: 0
to: 1
duration: 0.5s
selector: all
stagger: 0.05s
create titleSelector values read like prose — a pattern and a unit, or a unit and an index/range:
| Value | Targets |
|---|---|
all / even / odd / first / last |
Grapheme pattern. |
letters / words / lines |
Every unit of that kind. |
all words · even words · odd words · first word · last word |
Word pattern. |
all lines · even lines · odd lines · first line · last line |
Line pattern. |
3 · letter 3 · word 2 · line 0 |
One unit by index. |
"2-5" · letters 2-5 · words 1-3 · lines 0-2 |
Unit range (inclusive). |
Unit words are letter/letters, word/words, line/lines; the pattern
and unit may appear in either order (even words or words even). A bare
pattern, index, or range means letters — the common case.
Selectors address graphemes, not raw characters — combining marks belong to
their base letter, and spacing stays addressable. A word is a run containing
letters or digits: punctuation is never a word ("Hello, world!" has two
words). An apostrophe between letters or digits stays inside the word (don't,
it’s), and so does a . or , between digits (3.14, 1,000). A line is
a laid-out line, so wrapped text has one line per visual row. Empty lines hold
no units and are skipped: in "A\n\nB", line 1 is B. stagger is the per-unit
delay in seconds (or a parameter reference): letters advance one at a time,
words and lines advance as whole units.
On text, a property or animation expression that reads each.index,
each.count, each.progress, or each.seed implicitly targets all letters.
The common per-letter gradient can be written directly on the property:
imagine title
text: "Gradient"
fill: mix("#ff0000", "#0000ff", each.progress)
create titleThe same expression works in animate fill:. Add an explicit selector only to
target another unit or subset, such as even, all words, or line 0.
each.index is the stable zero-based index in the complete grapheme, word, or
line domain, and each.count is that complete domain's size. each.progress is
each.index / (each.count - 1), or 0 for one unit. A selector filters the
domain without renumbering these values; only stagger follows selected order.
each.seed is a hashed seed for random(each.seed); it is stable for the same
domain index.
Text selectors animate position, rotation, scale, opacity, and color channels.
Position, rotation, and scale support .x, .y, and .z component paths;
full tuple values animate all supplied axes. Scalar rotation is the z axis and
scalar scale applies uniformly to x/y/z. This is the same transform model used
by whole objects, so per-letter XYZ motion composes with parent transforms.
Percentage position offsets resolve against the laid-out text block's width and
height; percentage opacity resolves as a fraction of 1. Other selected
properties are ignored rather than changing an unrelated glyph channel.
Animating fill (or color) through a selector sets a per-glyph color. By
default it replaces the text's paint for the selected glyphs; with
blend: multiply it tints the existing paint instead.
Moving a sequence
Use one scene timeline. Share a start value across animation delays and visibility:
define start: 2
define arrive(at: 0s):
animate position.x from -100 to 0 over 0.5s delay at ease "ease-out"
duration: 5
imagine title
text: "One timeline."
fontFamily: "Inter"
create title as headline
visible: time >= start && time < start + 2
arrive(start)Change start to move the entrance and its visibility together. delay accepts
static numeric defines and aliases, with the same scope as key values. It shifts
keyframe playback; it does not reset time in expressions. Write time - start
when a formula needs an elapsed value. Nested groups share the scene timeline;
a hidden parent hides its descendants, and overlapping groups keep paint order.
visible and camera active keys or expressions switch at exact scene times,
even when artwork uses reduced FPS. Other motion keeps its existing FPS and
per-unit stagger sampling. Set root duration for a finished film, especially
when visibility or repeating expressions determine its end: arbitrary formulas
cannot provide a finite inferred duration.
Shared modifiers and repeated type
Text units and copies share selection, stagger, expression, and animation
evaluation. Add ordered modifier blocks to a text blueprint, or repeat the
blueprint with for. See replication.