compose renders a video from a JSON timeline. Start with one clip, then layer up: more clips, transitions, overlays, and effects. This page builds from the smallest render to the full model. Each step adds one idea.
Your simplest render
The smallest timeline is one track with one clip. This renders the first three seconds of a video to MP4. The whole API call:trim, a clip plays its source from the start for length seconds, or for the whole source when length is left off. To use a specific segment instead, add trim: { from, to } (in source seconds) to the asset. length is always the timeline duration. trim only chooses which part of the source fills it.
That is the shape of every render. Everything below is one more clip, one more track, or one more field.
Join two clips
Put a second clip on the same track and a transition between them.duration. You do not need to know how long either file is.
Writing the timing out by hand gives the same render. The second clip starts duration seconds before the first ends, which is what the engine works out for you above.
slide also accepts direction: "left" | "right" | "up" | "down".
crossfade
fade
slide (left)
zoom
How the timeline works
The model is two ideas:- Tracks stack. The first track is the background. Each later track composites on top of the ones below it: overlays, titles, picture-in-picture.
- Clips sit in time. A clip can carry a
startand alengthin seconds, and it can leave both out. Two clips on the same track are joined by a transition. A gap between them plays nothing.
Timing is optional
Every clip sits in a container: the scene it belongs to, or the whole video. Two sentences cover every case.- Omit
lengthand the clip runs as long as its content does, never past its container. - Write
length: "end"and it runs to the end of its container, whatever its content says.
speed (so speed: 0.5 on a 4 second clip occupies 8 seconds), or a composition’s own end.
Text and images have no duration of their own, so for them the two sentences say the same thing. A title with no length stays up for the whole video, which is what a watermark wants.
start follows the same shape: omit it and the clip begins after everything already placed on its track, pulled back by any transition immediately before it. Give it a number and that is seconds from the start of its container.
Set either field wherever you want something else. Every timeline written with full timing keeps rendering exactly as it did.
Worked examples
A music bed. The source is three minutes long, the video is not, and"end" is how you say so without totalling the clips above it.
The rules that fall out of it
A clip running to the end of the video is measured against every clip that is not, so two of them on different tracks both land on the real end rather than chasing each other. It runs to the last frame, so nothing may follow it on the same track, and a timeline where nothing has a length of its own has no end to measure and is rejected. A clip never runs past its container, so a 6 second video in a 3 second scene plays 3 seconds, and a 2 second video in a 5 second scene plays 2. That applies to a length you wrote as well as one the engine worked out."end" is the opposite request and does not cap: it asks for the container’s full extent whatever the source holds. On a source shorter than the container that is impossible, and the job is rejected for outrunning its source. Leave the length off instead, or trim less.
Inside a composition, start and length both stay required. A nested timeline’s length is set by the clip hosting it, so there is nothing to append to and no container to measure against.
Add a layer
A second track renders over the first. This lays an animated title over the video.Effects on a clip
Effects are fields on a clip. Stack as many as you like on one clip. Each example below shows the source on the left and the rendered result on the right. Exact fields and ranges are in the Reference.Color and filters
color grades a clip with contrast, saturation, temperature, brightness, gamma, and hue. filter applies a one-shot look like greyscale or boost.
Cinematic color grade for mood (color)
Lift flat, hazy footage (color)
Dramatic black and white (filter: greyscale)
Motion and speed
transform positions, scales, and rotates a clip. Add animateTo for a Ken Burns move, or scale a clip down and place it on an overlay track for picture-in-picture. speed is a playback multiplier: below 1 for slow motion, above 1 for a timelapse.
Picture-in-picture webcam (transform.scale)
Compositing
chromaKey keys out a solid background color so you can drop a presenter onto any scene. blendMode controls how an overlay blends with the track below. opacity (a number or keyframes) and blur handle fades and soft backdrops.
Chroma key onto any background (chromaKey)
Cinematic light-leak glow (blendMode: screen)
Clean fade in and out (opacity keyframes)
Blurred backdrop keeps text readable (blur)
Text and titles
Atext asset renders a styled title. Set the font, size, weight, color, position, and an animate entrance (fade, slideUp, slideDown, slideLeft, slideRight). Put one text clip on its own track for a title card, another low and left for a lower-third name tag. font takes any Google Fonts family by name, or a family from your own file. See Fonts.
Add a title card and a lower-third name tag (text)
Shapes
Ashape asset draws a rect, ellipse, circle, triangle, diamond, or any SVG
path you paste in. No image to make, no file to host, and it stays sharp at any
output resolution.
a bar, plus a text track
animateTo on the width
radius with a shadow
a circle, two colours
a stroke with no fill
pasted path data
type and size are required. Everything else on this page is optional,
and the defaults are chosen so the common cases need almost none of it.
Two things to know up front. position is the centre of the shape unless
you set anchor, so a full-width bar sits at x: "50%" whatever its height.
And there is no length, because a shape has no duration of its own: like text
and images it runs to the end of its container unless you give it one.
width is a percent of the frame’s width, height a percent of its height.
Leave the height out to get a circle
Omitsize.height and the shape is made square in pixels. That is the only
way to get a true circle or square on a frame that is not square, and it is the
one thing about shapes worth memorising.
A 10% by 10% box on a 16:9 frame is 192 by 108 pixels. Rounding it fully
gives a pill, not a circle. Omit the height and the engine derives 17.8% for
you.
shape: "circle" is ellipse with that rule applied, so it rejects an explicit
height rather than quietly ignoring one. The same omission works on every kind:
a rect with no height is a square, a diamond with no height is a regular one.
Anchor
anchor: "topLeft" points position at the corner instead of the centre. It is
what makes letterbox bars arithmetic-free.
Fills, flat and gradient
color takes #RRGGBB, or the 8-digit #RRGGBBAA for a constant translucency
the way #0A0A0ACC does above.
Do not reach for the clip’s opacity instead. opacity dims the fill as well
as fading it, so a half-opacity white box renders grey rather than white you can
see through. Keep opacity for animated fades.
Give color two colours and it is a gradient. gradient names the
direction: vertical (the default), horizontal, diagonal or radial.
["#0A0A0A00", "#0A0A0AFF"].
Outlines, with a real hole
stroke draws a border just inside the shape’s edge, its width in pixels of
the output frame. Give the shape a color too and you get a filled shape with a
border; radius rounds both together.
Leave color out and only the outline draws. What it surrounds is genuinely
transparent, not filled with black, so the footage shows through the middle.
That works on every kind except a path.
Rounded corners
radius runs from 0 (square) to 1 (fully round) on a rect. At 1 a wide
box becomes a pill and a square one becomes a circle.
Drop shadows
shadow follows the shape, including its outline, its rotation and its
animation. Every field has a default, so "shadow": {} is a sensible shadow.
Rotation turns about the shape, not the frame
rotate is degrees clockwise about the shape’s own centre, so a shape spins
where it sits rather than orbiting the middle of the frame. A diagonal rule is a
thin rect and one field:
line type for the same reason there is no square type: a line is
a rect with a small height, and rotate is what makes it diagonal.
Softness
softness runs 0 to 1 and feathers the edge. At 0.2 to 0.4 an ellipse reads as
a spotlight or a vignette rather than a hard-edged disc. A full-frame ellipse
with softness: 0.5 and a radial ["#00000000", "#000000CC"] fill is a
vignette with no image asset at all.
Paths
shape: "path" takes SVG path data straight out of a design tool. viewBox
gives the coordinate space it was drawn in, defaulting to "0 0 100 100", and
the path is scaled into size so the same data works at any size on any frame.
M L H V C S Q T Z are supported, absolute and relative. Elliptical arcs (A)
are refused rather than approximated, so re-export with arcs converted to
curves. A path takes a fill, a gradient, a shadow, rotation and softness, but
not a stroke: outlining arbitrary path data needs true path offsetting.
Animation
animateTo moves position, size, rotate, color and radius over the
clip. easing is linear by default, which is what a progress bar or a timer
wants, or smooth for an entrance.
animateTo keeps its starting value, so the bar
above grows sideways without changing height. A shape that is square in pixels
stays square as it grows, so an animated circle does not turn into an ellipse
halfway through. A solid colour can animate into a gradient, and a square can
round itself off with animateTo.radius.
An animated rotate has no limit: rotation is baked into the shape’s own
outline, so animating from 0 to 720 is two full turns.
Combinations the API refuses
Two engine primitives draw shapes and they have different abilities, so a few combinations are rejected at submit time rather than rendered wrong. Each error names the fix.What else a shape takes
blendMode mixes it with the layer below, blur softens the whole thing,
colour grading tints it, and opacity keyframes fade it in and out. A track
holding only shapes composites as a base layer, so a solid colour background is
a timeline that references no files at all.
There is no arbitrary path stroke and no per-corner radius. Anything past that
is still an image asset.
Fonts
Name any Google Fonts family instyle.font and it
is fetched at render time. Nothing to upload, no configuration.
Inter, Roboto, Montserrat, Poppins, Oswald, Anton,
Bebas Neue.
Your own font files
Put the file URLs in the job’sfonts input, each under a family name you
choose, then reference that name in style.font.
src like any other input URL.
Naming your own font is the point. The alternative is to reference the family
name buried inside the file, which you have to discover with a font inspector
and which is frequently not what the file is called. Omit family and that
embedded name is read for you, so { "src": "..." } on its own is also valid.
A family you declare shadows a bundled one of the same name, exactly the way an
@font-face rule beats a system font in CSS. Declare a font called Inter and
yours is the one that renders.
For a single file, inputs.font is the shorthand. It is addressed as custom:
Fallback stacks
style.font takes a CSS-style list, and it falls through in order:
style.font instead of into fonts.
Weights and languages
weight runs 100 to 1000. Variable fonts honour it exactly; a static family
snaps to its nearest available cut, rounding up on a tie.
Latin, Cyrillic, Greek, Vietnamese, Turkish, Arabic, Hebrew, Thai, Devanagari,
Bengali, Tamil, Amharic, Khmer, Chinese, Japanese and Korean all render, with
right-to-left joining and conjunct shaping handled by the engine. Colour emoji
does not render in text assets.
Set the canvas
output controls the resolution, frame rate, and format. A 9:16 canvas with a crop on the clip turns landscape footage into a vertical Reel that fills the frame, no black bars.
Landscape footage reframed to a vertical 9:16 Reel (crop)
Scene-first authoring
Tracks give you precise multi-track control. For a sequential edit, you can instead describe a list of scenes. Each scene is a self-contained segment with its own clips. A scene’stransition blends INTO it from the previous scene, so put it on the second of two scenes. overlays is a flat list of clips that sit over the whole composition, like a persistent logo or watermark.
start and length to span the whole scene, and a scene can omit its own duration to take the length of the video inside it. Every clip field works the same as in tracks mode. scenes and tracks are mutually exclusive: a timeline uses one or the other.
Edit like a pro
You do not need editing experience to get professional results. These are the conventions working editors follow, translated into compose fields. AI agents get the same rules automatically through the MCP compose reference.Pacing
Cliplength is the pacing lever. Social clips run 0.8 to 3 seconds each with a visual change at least every 3 seconds, vlogs 2 to 6, tutorials 5 to 15 (cut at step boundaries), cinematic 4 to 8 with varied lengths. Shorten clips as the video builds, then hold the final shot about twice as long. The first clip is the hook: no fade-in, no logo, the payoff visible or promised within 3 seconds. A 20 to 35 second total is the highest-completion band on social.
Cutting to music: seconds per beat is 60 divided by BPM. Cut every 2 or 4 beats, every beat only at the climax. For 120 BPM music that means 1 or 2 second clips.
Transitions
Professionals cut. Keep crossfades under 10% of your joins and pick ONE decorative style (slide or zoom) per video, at section boundaries only.Text placement and size
On vertical video keep every text element inside x 8 to 92%, y 13.5 to 83% (platform UI covers the rest). Captions sit at y 60 to 75%. Sizes at 1080x1920: titles 135 to 190px, lower thirds 70 to 80px, captions 90 to 105px. Always add a stroke (black, width 4 to 8), a shadow, or a background box. Titles are 6 words or fewer, 2 lines maximum. Pair one display font (Oswald, Anton, Bebas Neue) with one body font (Inter, Roboto).Color looks
Apply one look to every clip in the video:Audio levels
volume is linear gain. With speech at 1.0: music under speech 0.10 to 0.12, music alone 0.35 to 0.5, sound effects 0.25 to 0.32. Fade music in over 1 to 2 seconds and out over 3 to 5, ending on the last frame. To duck music under speech, split the music into three clips: before speech at 0.4 with a 0.4s fadeOut, under speech at 0.11, after speech at 0.4 with a 1.5s fadeIn.
Photos need motion
A static photo in a video reads as a mistake. Give every image clip a gentle Ken Burns move:"transform": { "scale": 1, "position": { "x": "50%", "y": "50%" }, "animateTo": { "scale": 1.12 } }.
Reference
Output
Theoutput object controls the render target. Provide either an explicit resolution or a named size preset.
Assets
A clip’sasset is one of:
Clip fields
Every clip has anasset. start and length are optional, and length also accepts "end" (see Timing is optional). Plus any of:
Transitions
Place between two clips on a track:{ "type": "transition", "transition": <kind>, "duration": <seconds>, "direction"?: <dir> }.
Scenes
The scene-first shape, when you usescenes instead of tracks:
Text style
Fields on a text asset’sstyle:
See also
- Job output: the output shape every job returns
- Animated captions: word-level captions over a rendered video
- Compress: shrink the render to a size or quality budget
- FFmpeg: drop to a raw command when the timeline cannot express it
- Webhooks: receive
job.completedinstead of polling - Plan limits: render duration and file-size caps per plan