Write a rule, a shader or a frame function, and get controls back.
Grapple has three ways past the built-in controls: property scripts that drive animation from time and parameters, GLSL functions that become effects on the GPU, and Python functions that process frames as NumPy arrays. Whichever you write, its parameters appear in Properties as sliders, colours and points you can key like any other value.
Pick the lightest tool that does the job.
| Approach | Good for | Written in |
|---|---|---|
| Keyframes and live drivers | Deliberate beats, and one value following another with spring or pendulum physics | No code |
| Property script | Movement that follows a rule: a seeded drift, a loop, one range mapped onto another | A small expression language |
| GLSL effect | Per-pixel looks that need to play back smoothly: colour treatments, distortions, patterns | A GLSL function |
| Python effect | Pixel processing that is easier to write with NumPy, or that reads a project file such as a data table | Python 3 with NumPy |
Property scripts drive animation from rules.
A property script sets a layer's position, scale, rotation or opacity, a camera's position, zoom, focal length or focus, a 3D layer's depth and material, or a shape's size, corner radius and path trim. Each value is an expression built from time, parameters, arithmetic and four functions: ease, remap, loop and a seeded wiggle.
import grapple as gp
def drift():
layer = gp.target("layer")
layer.position.x = gp.wiggle(gp.time(), 7, gp.param("frequency"), gp.param("amount"))
layer.rotation_degrees = gp.wiggle(gp.time(), 8, gp.param("frequency"), gp.param("tilt"))The wiggle is deterministic: the same seed gives the same movement every time the project renders. Frequency, amount and tilt become sliders in Properties, so you can dial the drift down for a calmer shot, or key the amount so it builds towards a cut.
Property script referenceGLSL functions become effects.
Write one function that receives a coordinate and returns a colour. Grapple supplies the rest of the shader: the version line, the inputs, the uniforms and main. Sample the incoming frame with gp_sample_<input>(uv), and read each parameter as gp_<name> along with the current time and the resolution.
vec4 shade(vec2 uv) {
vec2 offset = vec2(gp_split / gp_composition_resolution.x, 0.0);
float r = gp_sample_input_frames(uv + offset).r;
vec4 c = gp_sample_input_frames(uv);
float b = gp_sample_input_frames(uv - offset).b;
return vec4(r, c.g, b, c.a);
}That is a red and blue channel split measured in composition pixels, with split as a slider you can key. Shader effects run on Grapple's Vulkan renderer.
Python functions process frames.
A Python effect defines render(ctx, inputs, params). Each input arrives as a NumPy array of shape height × width × 4 in RGBA, and the function returns an array of the same shape for each output. The context gives the time, the frame size, the render quality, a seed, and read-only copies of any project files you list for it.
def render(ctx, inputs, params):
rgba = inputs["input_frames"].copy()
grey = rgba[..., :3].mean(axis=2, keepdims=True)
mix = params["amount"]
rgba[..., :3] = (rgba[..., :3] * (1 - mix) + grey * mix).astype("uint8")
return {"frames": rgba}Python effects run on the CPU with the Python runtime bundled with Grapple, so they suit treatments that are easier to write with NumPy, or ones that need data from a file.
Python frame effect referenceThe parameters you define become controls.
Each parameter has a name, a label, a one-line description and a type, and it appears in Properties in the group and order you give it. Numeric controls can be keyed like any other property. Shaders accept sliders, angles, toggles, colours, points and vectors.
- Slider
- A number with a minimum, maximum and optional step.
- Angle
- A rotation in degrees.
- Toggle
- On or off.
- Colour
- A colour picker.
- Point
- A 2D position you can drag on the Stage.
- Vector
- A 2D direction or offset.
- Choice
- A list of named options.
- Text and asset
- A line of text, or a reference to a project asset of an accepted kind.
Adding code to a project.
You write the source; Ape adds it to the project. Paste your function into the Ape panel, list the parameters with their ranges, and say where the effect should apply: to one track, to everything under an adjustment layer, or to the finished composition. Ape installs it, fills in the project details, and renders a preview so you can check it. You can also describe the effect and let Ape write the code.
For scripted workflows, grapple-cli can call the same authoring operation on a project folder with a JSON arguments file. The shader reference shows the request.
Try it on footage you already know.
Pick a short clip and one job, such as a lower third or a trimmed opening. The getting-started guide takes you from import to an exported file.