Add an expression
- Select the object and find the property in the Inspector.
- Open the row's More menu, or right-click the row, and choose Add expression. Code opens beside the Timeline with the expression ready to write.
- Type the expression. Code evaluates it at the playhead as you type and shows the result in its footer, after the time, or names the problem.
- Press Apply, or Ctrl+Enter. The property now follows the rule at every frame.
Expressions you've added are listed under Expressions in Code, named by the object and property, so you can find and change them later. To change an expression, choose Edit expression from the same row menu.
Write one line
On a title's Opacity, this makes it breathe on top of its animation:
value * (0.85 + 0.15 * math.sin(time * 2))
value is what the property would be without the expression: its keys, or its static value. The expression's result replaces it at that frame. Keep the keys you set, and the expression works on top of them.
The names you can use
value- The property's own value at this frame, with its keys.
time- The composition time in seconds.
- Your inputs
- Each property you linked, by the name you gave it.
gp- Grapple's values and helpers:
gp.Vec2,gp.Vec3,gp.ease,gp.wiggleand the rest. math- Python's math module:
math.sin,math.pi,math.floorand so on. ctx- The same things as attributes:
ctx.time,ctx.base_value(the same asvalue),ctx.inputs["name"], andctx.fps, the composition's frame rate as a fraction.
Python's built-ins such as min, max, abs, round and int work too.
What it returns
The result must be the property's own kind of value:
- a number for Opacity, Size, a slider or an angle;
- a
gp.Vec3with x, y and z for Position, Rotation, Scale and Anchor. Rotation is degrees about each axis, and a flat layer turns about z; TrueorFalsefor a switch, and text for text.
Positions and sizes are composition pixels, and scale and opacity are percent. A result of the wrong kind is refused with a sentence such as "Expected number; received gp.Vec2.", and Code shows it in its footer and Problems tab before you apply.
Link inputs
An expression reads other properties only through inputs you link, so you can always see where a value comes from.
- In the expression's Inputs section in Code, press Add an input property.
- Search for the property, such as another layer's Rotation, and pick it.
- Double-click the input's name to rename it. Use a name Python accepts that isn't already taken, such as
wheel.
Now wheel in the expression is that property's value at this frame. Pressing an input's source selects it, and an input whose source has gone reads "Unavailable property".
Grow it into a function
When a line isn't enough, choose Convert to function from Code's More menu. Your line becomes the body of a function, with your inputs unpacked for you:
def evaluate(ctx):
value, time = ctx.base_value, ctx.time
wheel = ctx.inputs["wheel"]
return value + wheel * 0.5
Now you can use several statements, helper functions and imports, including your project's own modules as grapple_project. and the module's name. gp and math are there without importing.
from grapple_project.motion import pulse
def evaluate(ctx):
return ctx.base_value * pulse(ctx.time, rate=0.5)
Helpers for motion
gp.ease(v, in0, in1, out0, out1)- A smooth move from
out0toout1whilevgoes fromin0toin1, holding at either end. gp.remap(v, in0, in1, out0, out1)- The same in a straight line, without holding at the ends.
gp.loop(v, period)vwrapped into 0 up toperiod.gp.wiggle(t, seed, frequency, amplitude)- Smooth random movement within plus or minus
amplitude,frequencytimes a second. The seed is a whole number; the same seed repeats the same wiggle. gp.noise(seed, key, t)- Smooth noise from −1 to 1 along
t, with a word or number as the key. gp.random(seed, key)- A fixed random number from 0 up to 1 for that seed and key.
All of them are in Python in Grapple.
Recipes
- Handheld wobble on Rotation
gp.Vec3(value.x, value.y, value.z + gp.wiggle(time, 7, 1.5, 2))
Two degrees of drift either way, a gentle 1.5 times a second.- Drift on Position
value + gp.Vec3(gp.wiggle(time, 1, 0.5, 12), gp.wiggle(time, 2, 0.5, 8), 0)
Different seeds for x and y, so the two axes don't move together.- Spin forever on Rotation
gp.Vec3(value.x, value.y, value.z + time * 90)
A quarter turn a second, added to any rotation you key.- Blink on Opacity
value if gp.loop(time, 1.0) < 0.5 else 0
On for half a second, off for half a second.- Flicker on Opacity
value * (0.85 + 0.15 * gp.noise(3, "flicker", time * 8))- Fade in over a second on Opacity
value * gp.ease(time, 1, 2, 0, 1)
Starts at one second, fully in at two.- Follow another layer, a beat behind
- Link the other layer's Position as
leader, thenleader + gp.Vec3(-120, 0, 0)keeps 120 pixels to its left. - Turn with a wheel
- Link the wheel's Rotation as
wheel, thengp.Vec3(value.x, value.y, -wheel.z * 2)turns twice as fast the other way, like a gear.
What the property row shows
The row reads "Set by an expression". Typing a value there is refused with a sentence that says where to change it: "An expression sets this value. Edit it in Code, or turn the expression off to set a value." The property's keys stay editable on the Timeline and in the Graph, because they're the expression's value.
A driven property can't take a second driver: Drive with says "Remove this property's driver or expression to drive it another way."
Turn it off or remove it
In Code's More menu, Enabled switches the expression off and on. Off, the property uses its keys and value, and the expression is kept for later. Remove expression takes it away. Revert throws away edits you haven't applied.
Expressions from scripts and Ape
The same expressions can be set from Python. In a script run from Code, a property's set_expression adds one (see Your scripts in Code). In Ape's scripts it's one call: title.opacity.drive("value * (0.85 + 0.15 * math.sin(time * 2))"), and drive(None) removes it.
When Ape changes many objects at once, it works out each value in Python and writes them in one step, leaving ordinary values and keys. Behaviour that must stay live, such as a wobble that keeps going, uses an expression, a driver or a program.
Expression, driver or keys
- Keys
- When you want to see and shape the motion by hand in the Graph.
- A driver
- When the rule is a common one: a wave, a spring, following another value, or following the sound. No code, and every setting is a control. See Drivers.
- An expression
- When the rule is your own, on one property.
- A program
- When one rule moves several properties or objects, or works on pictures. See Python programs and effects.