The gp reference.

Everything gp offers a script run through python.run_script. This page is generated from the type stub Grapple publishes, the same grapple.pyi a script finds in its working directory, so it says what the API says. For a guided tour, start with Scripts with gp.

Conventions

  • Units are the project's: composition pixels from the top left with x right and y down, degrees, percent for scale and opacity, and seconds.
  • A time is seconds or a gp.Time; a place is a gp.Place. The receiving operation resolves them on its own clock.
  • … marks an argument with a default. Arguments after * are given by name.
  • The edit steps and tools that gp.step and gp.tool call are listed in Steps and tools.
  • The values and number helpers every Python program shares, such as gp.Vec2 and gp.ease, are in Python in Grapple.

Find and read

gp.comp(name: str) → Object

A composition by name or path: exact, then case-folded.

gp.find(name: str = …, kind: str | None = …) → list[Object]

Objects anywhere in the project whose name matches a glob, in authored order.

gp.read(objects: Any, fields: list[str], at: Any = …) → list[dict[str, Any]]

Read project.query fields of many objects at one time: one row per object, in order.

gp.selection: Selection

The person's selection when the run started, as handles.

gp.project: Project

The open project.

Write

gp.set(objects: Any, /, **props: Any) → Result

Set properties on many objects in one step. A list gives one value per object, in order.

gp.relate(kind: str, objects: Any, **arguments: Any) → Result

Relate objects with a registered relate kind.

gp.controller(name: str, drives: dict[str, Prop], active_range: tuple[float, float], source: str, params: list[Any] | None = …, entrypoint: str = …) → Object

Drive several properties from one Python source.

drives maps each output port evaluate(ctx) returns to the property it drives. A whole-vector property needs a vector output; an axis property takes a number. active_range is (start, end) in seconds.

gp.edit(label: str) → Edit

Group the calls in a with block under a label. e.receipt reports what the block staged, with committed false; the run commits once at its end.

gp.speculate(label: str = …) → Edit

Stage the calls in a with block, read and render the result inside it, then discard them.

gp.progress(fraction: float, message: str = …) → None

Report how far the script has got, from 0 to 1, with a short message.

Times and places

gp.frames(n: int) → Time

An exact frame on the receiving operation's composition clock; frames count from 0.

gp.marker(name: Any, offset: float = …) → Marker

A marker, by name, path or handle, and an offset in seconds after it (negative is before).

gp.source(seconds: float) → Time

Seconds on the footage's source clock.

gp.seconds(time: Any, in_: Any) → float

A time in seconds on the clock of in_, resolved by the project.

gp.playhead: Time

A typed time: a frame, a marker and an offset, the playhead or footage source time. It stays symbolic until the operation that receives it resolves it.

gp.world(x: float, y: float, z: float = …) → Place

A point in world pixels: x right, y down, z toward the default camera.

gp.point(of: Any, point: Any = …, at: Any = …) → Place

An evaluated point of an object: anchor, center, top-left, top, top-right, right, bottom-right, bottom, bottom-left or left; or {"path": fraction} of a Path's arc length.

gp.rect(x: float, y: float, width: float, height: float, in_: str = …, at: Any = …) → Place

A rectangle in output pixels from the top left.

gp.mask_region(mask: Any, at: Any = …) → Place

The region a mask covers.

See

gp.render(of: Any, /, *, at: Any = …, times: list[Any] | None = …, range: tuple[Any, Any] | None = …, as_: str = …, size: Any = …, crop: Any = …, columns: int | None = …, camera: Any = …, only: list[Any] | None = …, alpha: bool | None = …, overlay: list[Overlay] | None = …, compare: dict[str, Any] | None = …) → Any

Render synchronously from the run's staged project.

at renders one frame (or a list of frames); times=[...] renders a labelled contact sheet; as_="audio" with range=(start, end) renders the mixed audio and returns its artifact and coverage. size scales the composition's output size (a number) or gives (width, height); crop is (x, y, width, height) in output pixels. camera, only and alpha choose the view; overlay draws gp.overlay(...) items; compare is {"against": ..., "as": "split" or "difference"}.

gp.overlay(of: Any, show: str, **arguments: Any) → Overlay

An overlay for gp.render: what to show for which object, from the render contract's overlays.

Learn

gp.search(text: str) → None

Print every class, method, adapter, step, tool and measure kind matching text.

gp.examples(topic: str | None = …) → None

Print short runnable examples: gp.examples() lists the topics, gp.examples("keys") shows one.

gp.api() → None

Print the type stub of this run's API.

gp.objects.Object

Every handle: an identity in the project. Facts are read-only attributes; any other attribute is a property.

A project object. A handle is an identity; every read goes to the project.

Facts: name, path, kind, id, start, end, duration, parent, children, layer, comp, z_order, driven_by, used_by. Properties are attributes: obj.opacity, obj.position.x; obj.prop(id) reaches any registered id.

obj.id

The object's id; an owned item's id is its owner, kind and key.

obj.name

The object's name.

obj.path

The identity path of names from the composition down.

obj.kind

The object's kind.

obj.start

Start in seconds on the object's own composition clock.

obj.end

End in seconds on the object's own composition clock.

obj.z_order

Stacking order; higher is in front.

obj.driven_by

Objects that drive this one.

obj.used_by

Objects that use this one.

obj.duration

end - start, in seconds.

obj.created

The native result of the call that created this handle's object, when this run created it.

obj.parent

The object that contains this one, or None at the top.

obj.children

The objects directly inside this one, in authored order.

obj.layer

The layer this object is on, or None.

obj.comp

The composition this object is in, or None.

obj.relations

The relations this object owns, as handles.

obj.find(name: str = …, kind: str | None = …) → list[Object]

Objects inside this one whose name matches a glob (* and ?), in authored order.

obj.presented_transform(at: Any) → dict[str, Any]

Position, scale, rotation and opacity after parents and layout, at a time.

obj.bounds(at: Any) → Any

Evaluated bounds at a time.

obj.screen_bounds(at: Any) → Any

Bounds on the rendered frame at a time, in output pixels.

obj.in_frame(at: Any) → Any

Whether the object shows in the rendered frame at a time.

obj.props(at: Any = …) → PropTable

This object's properties with units, choices, whether each is settable and animated.

obj.prop(name: str) → Prop

A property by any registered spelling, including its full id.

gp.Prop

A property of one object, reached as an attribute: title.opacity, title.position.x.

A property of one object.

The name is the registry's: the property id, its label or the last part of its id, without case, spaces or underscores; .x, .y and .z name one axis. Values use the property's units: pixels from the top left, degrees, percent, seconds.

prop.value

The authored value, before keys, drivers and programs are sampled.

prop.at(time: Any) → Any

The sampled value at a time on the object's own clock: keys, drivers and programs.

prop.keyframes

Every stored key, with every field the writer takes.

prop.animated

Whether keys, a driver or a program animate this property.

prop.address

The bound property address: ownerNodeId, propertyId and componentIndex for one axis.

prop.set(value: Any) → Result

Set the static value. On a keyed property this writes a key at the playhead.

prop.keys(keys: list[Any], mode: str = …) → Result

Write keys: (time, value) or (time, value, ease) tuples, or gp.Key records.

A tuple's time is on the object's composition clock; a gp.marker time anchors the key to the marker. ease is how the value leaves that key: hold, linear, ease_in, ease_out, ease_in_out, smooth_through or overshoot. mode replace sets the whole schedule; merge adds keys and replaces keys at the same times.

prop.key(time: Any, value: Any, ease: str | None = …) → Result

Add or replace one key.

prop.clear() → Result

Remove every key.

prop.shift(seconds: float) → Result

Move every key later by seconds on the property's key clock; negative is earlier.

prop.drive(expression: str | None) → None

Drive the property every frame with a Python expression, or remove the driver with None.

The expression can use time (composition seconds), value (the property's own keyed or static value), gp and math.

prop.x

The x axis.

prop.y

The y axis.

prop.z

The z axis.

gp.Key

One stored key, as prop.keyframes returns it.

One stored key with every field the writer takes.

keyframe_id; time on the schedule's clock (composition or source) and its time_anchor (a marker and an offset, or None); value, or endpoint when the key stands for its channel's loop start; interpolation, how the value leaves this key; dimensions (joined or separated) and component_index for one axis; hold_until and hold_until_anchor for a source-time hold; incoming_tangent and outgoing_tangent. prop.keys(prop.keyframes) writes the same animation back. Build new keys as (time, value, ease) tuples; change a stored key with replace().

key.replace(**changes: Any) → Key

A copy of this key with the given fields changed.

gp.Image

What gp.render returns for frames and contact sheets.

The images of one render: its frames, or its contact sheet. show(caption) returns them to you with this run's result. result is the render's native result: resolved times, extents, view and problems.

image.problems

What the render reports about these images.

image.show(caption: str) → Image

Return these images to you with the run's result, under a caption.

gp.Result

What a step, a tool or an adapter returns.

A step's or tool's native result. id is the object the call created, when it creates one.

result.id
result.object

The created object as a handle.

gp.Error

The exception every failed operation raises.

A Grapple operation failed.

code names the failure; message says what happened and what to do next; path is the argument that failed; got and expected are the supplied and accepted values; candidates lists the objects a name could mean, closest first; next suggests a tool call that can help.

gp.Time

A typed time. gp.frames, gp.marker, gp.source and gp.playhead make them.

A typed time: a frame, a marker and an offset, the playhead or footage source time. It stays symbolic until the operation that receives it resolves it.

gp.Place

A typed place or region. gp.world, gp.point, gp.rect and gp.mask_region make them.

A place or region, resolved by the operation that receives it.

gp.objects

One handle class for each kind of object. Each has everything gp.objects.Object has, and the kinds below add their own methods.

gp.objects.Asset

A project object of kind asset.

gp.objects.Camera

A project object of kind camera.

gp.objects.Clip

A project object of kind clip.

clip.rename(name: str) → None

Rename this clip.

gp.objects.Collection

A project object of kind collection.

gp.objects.Comp

A project object of kind composition.

comp.clips

Every clip inside this object, in authored order.

comp.layers

Every layer inside this object, in authored order.

comp.add_layer(name: str, kind: str) → Object

Create a layer on top: kind is visual, audio or adjustment.

comp.add_camera(name: str, focal_length: float | None = …, **fields: Any) → Object

Create a camera. focal_length is millimetres; other fields use the step's registered names.

gp.objects.Effect

A project object of kind effect.

gp.objects.Layer

A project object of kind layer.

layer.clips

Every clip inside this object, in authored order.

layer.add_text(text: str, start: Any, end: Any, font: str | None = …, size: float | None = …) → Object

Create a text clip from start to end. font is an exact font family; size is pixels. Without them the text is Inter at 48 px, white, centred in a box 80% wide and 25% high. The result's layout (clip.created["layout"]) reports overflow. A new text clip has no name; give it one with rename().

layer.add_media(asset: Any, *, start: Any, source_range: tuple[Any, Any], duration: float | None = …) → Object

Place an asset's picture on this layer: source_range is (start, end) in source seconds. With duration, the clip spans start to start + duration. Place the audio component with gp.step("timeline.place_media", ...).

gp.objects.Light

A project object of kind light.

gp.objects.Marker

A project object of kind marker.

gp.objects.Member

A project object of kind member.

gp.objects.Relation

A project object of kind relation.

gp.measure

Measurements of evaluated motion, rendered pixels, output audio or analysis results. Each kind takes the keywords shown, inside one call: gp.measure.colour(of=main, at=2.0, region=…).

gp.measure.bounds(*, at = …, of = …, view = …)

Visible pixel bounds of each requested object inside the output frame, with alpha strictly above the visibility threshold. This is rendered support, not geometric query bounds.

gp.measure.colour(*, at = …, of = …, region = …, view = …)

Region- and alpha-weighted straight working-linear RGBA and luminance: mean, minimum, maximum and weighted empirical 5/50/95 percent quantiles. Display pixels and overlays do not contribute.

gp.measure.contrast(*, at = …, of = …, regions = …, view = …)

Relative-luminance contrast and signed delta L* from the first region to the second. Give two regions for their alpha- and region-weighted mean luminances. Omit regions and give one placed visual object in of for median luminances of its covered pixels and the surrounding ring, in the full composition. The ring lies outside object coverage above 1/255 alpha, within the greater of 8 output pixels and 10% of its visible bounding-box short side, using Euclidean distance on the rendered mask. An empty object or ring reports a problem. Regions retain their own mask sampling moments.

gp.measure.cuts(*, of = …, range = …, view = …)

Cut times over a half-open range at the composition's frame cadence, through the temporal cut detector. The first sample is the baseline; each later time names the right frame of its detected interval. Detector scores are not probabilities. Overlays do not contribute.

gp.measure.difference(*, against = …, at = …, of = …, view = …)

Matching resolution and working profile are required. Mean and maximum absolute premultiplied working-linear RGBA difference and the fraction of pixels whose largest channel difference exceeds the changed-pixel threshold; no optical alignment.

gp.measure.flicker(*, of = …, range = …, region = …, view = …)

Population standard deviation of signed frame-to-frame changes in region- and alpha-weighted mean working-linear luma, and the maximum absolute change. Samples follow the composition's frame cadence over the half-open range; at least two frames are required. A region without at follows each frame; region.at fixes its coverage. Overlays do not contribute.

gp.measure.landing(*, near = …, of = …, range = …, view = …)

Observe each clip's evaluated screen-space approach over a half-open range. The destination is the first key after the approach whose following interval holds or stays below 1 px/frame until the next key; without a rest inside the range, use its last delivered frame. Landing is the first run of at least two frames below 1 px/frame at that rest, measured with motion's one-frame difference, one-sided at clip or delivered-range edges. Overshoot is the furthest excursion past that destination along the start-to-destination direction, in pixels and as a percentage of the approach distance. near adds the landing-time offset. Missing placement, an unsettled interval or a zero approach distance reports a named problem.

gp.measure.loop(*, of = …, thresholds = …, view = …)

Measure each footage, layer and periodic driver's seam, with numerical pass or fail and a note to look at it. Of is one composition; T is its duration in whole frames N and L = (N - 1) / fps its last delivered frame. Each footage and layer item, isolated, compares frame L with frame 0 over the pixels either covers: the excess is the seam's mean premultiplied working-linear difference beyond the larger of its neighbouring frame differences (L - 1 to L, and 0 to 1); fewer than three frames leaves continuation unavailable. Each Wave, Spring and Audio level compares its own state at T with 0: a Spring's position and velocity, a Wave's phase in cycles (whole cycles close the loop) and an Audio level's smoothed power. The output mix's continuation is fitted per channel by a two-sample linear predictor on each side of the seam; the residual is the forecast error across the seam beyond each side's own. Each driver component gives its change from 0 to T and its residual. An item the renderer withholds from a frame is unavailable, with the reason. Rows are footage, then layers, then drivers, then sound. Missing evidence is unavailable, never a pass.

gp.measure.loudness(*, of = …, range = …)

Measure the composition's native stereo output mix over range: EBU R128 integrated LUFS, maximum three-second short-term LUFS, and ITU-R BS.1770-4 Annex 2 FIR true peak in dBTP. Both absolute and relative gates apply. Silence and insufficient duration return null with a reason. Also each output channel's RMS and sample peak in dBFS, the peak and the number of samples over full scale before the delivery clamp, the intervals where a playing clip's source has no PCM, and how many seconds are exactly silent or quiet (stereo RMS below -80 dBFS over a 20 ms window).

gp.measure.motion(*, at = …, of = …, view = …)

Screen-space velocity of the whole-object transform position and evaluated Euler angular velocity of each placed visual clip. A central difference spans one composition frame interval; at a clip edge it uses a one-sided difference inside the clip's presence. Position projects through the same view as render; angular components retain the evaluated degrees about x, y and z. An absent, failed or unprojectable placement reports a named problem.

gp.measure.overlap(*, at = …, of = …, view = …)

Give two placed visual objects in of, ordered A then B. Return the fraction of A's visible output pixels covered by B, and their area in square output pixels. The front object is determined by the view's render order; B covers none of A when it is drawn behind A. A is visible above 1/255 alpha; B covers a pixel at alpha at least 0.5. Mask holes and fractional coverage come from the render, not geometric boxes. Empty A reports a problem.

gp.measure.plane_fit(*, of = …, plane = …)

How well each camera solve plane fits its measured cloud points: the support count, the points' RMS distance from the plane in solve depth units (one unit is the solve's median scene depth) and as a share of their depth, their spread across the plane, the fit's state and the camera axis its frame follows. Read from each solve's stored result; nothing is solved again.

gp.measure.reprojection(*, of = …)

Reprojection error of camera solves, read from each solve's stored result: the inlier RMS and p95 over its measured features in source pixels, the inlier share, weak and unposed frames, and which lens and depth values were determined. Samples give each frame's own error. Nothing is solved again.

gp.measure.signal(*, of = …, power = …, property = …, range = …, step = …)

Sample one object's signal over range, in the clock of the composition that holds it or of the root composition that holds its outermost use. With property, the property's value as the runtime evaluates it for that occurrence, drivers and instance inputs included, every step seconds, in the units set uses. With power, an audio clip's power in dBFS over completed 20 ms windows of a tap, band-filtered and smoothed as an Audio level on that clock hears it: on a seamless loop its windows start one period before 0, and a window whose smoothing remembers a window with no source PCM is unavailable. Each sample is the window ending at its time, and silence is null with a reason. The result shows the first samples; every sample is in its artifact. Give property or power.

gp.presets

Readable motion presets. Each writes ordinary keys that merge into the property's schedule.

gp.presets.ease(prop: Any, *, at: Any, to: Any = …, from_: Any = …, duration: float = …, amount: Real | None = …)

Ease from one value to another, landing at the end. Amount 0 is linear, 100 is a full ease.

prop is a property such as title.scale. at is the beat in seconds of the object's composition clock, or gp.marker(name, offset=...), which anchors every key to the marker. to defaults to the property's authored value, from_ to zero and duration to one second. The keys merge into the property's schedule.

gp.presets.overshoot(prop: Any, *, at: Any, to: Any = …, from_: Any = …, duration: float = …, amount: Real | None = …)

Pass the target by amount percent at the beat, then settle.

prop is a property such as title.scale. at is the beat in seconds of the object's composition clock, or gp.marker(name, offset=...), which anchors every key to the marker. to defaults to the property's authored value, from_ to zero and duration to one second. The keys merge into the property's schedule.

gp.presets.bounce(prop: Any, *, at: Any, to: Any = …, from_: Any = …, duration: float = …, amount: Real | None = …)

Arrive at the beat and bounce back twice, the second bounce a quarter of the first.

prop is a property such as title.scale. at is the beat in seconds of the object's composition clock, or gp.marker(name, offset=...), which anchors every key to the marker. to defaults to the property's authored value, from_ to zero and duration to one second. The keys merge into the property's schedule.

gp.presets.anticipate(prop: Any, *, at: Any, to: Any = …, from_: Any = …, duration: float = …, amount: Real | None = …)

Pull back by amount percent first, then move to the target at the beat.

prop is a property such as title.scale. at is the beat in seconds of the object's composition clock, or gp.marker(name, offset=...), which anchors every key to the marker. to defaults to the property's authored value, from_ to zero and duration to one second. The keys merge into the property's schedule.

gp.presets.pop(prop: Any, *, at: Any, to: Any = …, from_: Any = …, duration: float = …, amount: Real | None = …)

Pop to amount percent at the beat, then settle with two smaller swings.

prop is a property such as title.scale. at is the beat in seconds of the object's composition clock, or gp.marker(name, offset=...), which anchors every key to the marker. to defaults to the property's authored value, from_ to zero and duration to one second. The keys merge into the property's schedule.

gp.presets.hold(prop: Any, *, at: Any, to: Any = …, from_: Any = …, duration: float = …, amount: Real | None = …)

Hold the first value, then step to the target at the beat. Amount has no effect.

prop is a property such as title.scale. at is the beat in seconds of the object's composition clock, or gp.marker(name, offset=...), which anchors every key to the marker. to defaults to the property's authored value, from_ to zero and duration to one second. The keys merge into the property's schedule.