Compose, by Rendobar
Video composition API
Rendobar's compose API renders finished video from a JSON timeline. Tracks hold clips. Clips reference video, image, audio, or text. Transitions sit between them. You POST the timeline and an MP4 comes back. A typical composition renders in about 6 seconds. No template editor, no render farm to run.
$5 in free credits. No credit card required.
What it is
What is a video composition API?
A video composition API renders finished video from a structured description instead of an editing UI. With compose, that description is a JSON timeline: tracks hold clips, clips reference video, image, audio, or text assets, and transitions sit between them. You POST the timeline to the Rendobar API and get an MP4 back, with progress streamed while it renders.
There is no template to build first and no editor to click through. The timeline is plain data, so it can come from your backend, a spreadsheet, a form, or a coding agent. One schema covers a single clip trim and a multi-track composition with nested timelines.
The whole model in five steps
Start with one clip. Layer up.
Each step adds one idea to the JSON. The preview is the real render at that step.
One track, one clip
The smallest timeline. Three seconds of one video, rendered to MP4.
{ "timeline": { "tracks": [{
"clips": [
{ "asset": { "type": "video", "src": ".../sea.mp4" },
"start": 0, "length": 3 }
] }] } }Join two clips with a crossfade
A transition is an item between two clips. Video dissolves and audio crossfades, automatically.
"clips": [
{ "asset": { "src": ".../sea.mp4" }, "length": 3 },
{ "type": "transition",
"transition": "crossfade", "duration": 1 },
{ "asset": { "src": ".../city.mp4" }, "length": 4 }
]Layer a title on top
A second track renders above the first. Text is an asset like any other, with style, timing, and an entrance animation.
"tracks": [
{ "clips": [ ...video clips... ] },
{ "clips": [
{ "asset": { "type": "text", "text": "Summer '26",
"style": { "size": 72, "color": "#FFFFFF",
"animate": { "type": "slideUp" } } },
"start": 0.5, "length": 3 } ] }
]Give a clip an effect
Effects are a list on the clip, run in the order you write them. Motion lives in the transform, and keyframes move it: a Ken Burns push-in is two scale keyframes.
{ "asset": { "src": ".../photo.jpg" }, "length": 4,
"effects": [{ "type": "color", "saturation": 1.2 }],
"transform": { "scale": [{ "time": "0%", "value": 1 },
{ "time": "100%", "value": 1.35 }] } }Or think in scenes
For slideshows and data-driven video, write scenes instead of tracks. Overlays span the whole video. Same engine underneath.
"scenes": [
{ "clips": [{ "asset": { "src": ".../intro.mp4" } }] },
{ "transition": { "transition": "slide", "duration": 0.6 },
"clips": [{ "asset": { "src": ".../product.mp4" } }] }
],
"overlays": [{ "asset": { "type": "image", "src": ".../logo.png" } }]The full vocabulary
Everything in the timeline
Every tile below is a real compose render. Hover to play. Split tiles show the source next to the result. For every effect with its settings and a request you can run, see the effects reference.
Transitions
A transition is an item between two clips. Video blends and audio crossfades automatically. Crossfade, fade to black, slide or push from any edge, a wipe along an edge or through a shape, zoom, or a hard cut.
{ "type": "transition", "transition": "crossfade", "duration": 1 }Motion
Animate a clip's position, scale, and rotation with keyframes, 33 easings included, for Ken Burns moves. Change playback speed for slow motion or timelapse. Crop by edge percentages. Flip on either axis.
"transform": { "scale": [{ "time": "0%", "value": 1 }, { "time": "100%", "value": 1.4 }] }Color
Effects are a list on the clip, run in the order you write them. Grade with brightness, contrast, saturation, gamma, hue and color temperature, pick one of nine named looks, or blur and sharpen with one entry each.
"effects": [{ "type": "color", "saturation": 1.2, "temperature": 5200 }]Compositing
Tracks stack bottom to top. Scale a clip down for picture-in-picture, key out a green screen, blend with seven modes, and animate opacity with keyframes and easing. A clip can even hold a nested timeline.
"opacity": [{ "time": 0, "value": 0 }, { "time": 1, "value": 1, "easing": "smooth" }]Text and titles
Text is an asset like any other. Any Google Fonts family by name, or your own font files under names you pick, plus size, weight, color, stroke, background, position, entrance animations and a drop shadow.
"animate": { "type": "slideUp", "duration": 0.6 }More than video and text
A timer counts up or down over its own clip in the format you name. One subtitles clip holds every line, written in the timeline or read from an .srt file. A Lottie animation plays from the JSON a designer exports, transparent background kept.
{ "asset": { "type": "timer", "direction": "down", "format": "MM:SS" } }Shapes
A shape clip draws a rect, ellipse, circle, triangle, diamond or any SVG path straight from JSON, with no file to upload. Solid or gradient fills, outlines with a real hole, drop shadows, rotation, feathered edges, and geometry, colour and rounding that animate.
{ "asset": { "type": "shape", "color": "#0A0A0ACC" }, "transform": { "size": { "width": "100%", "height": "22%" } } }Audio
Every video clip carries its audio with per-clip volume. Add music as an audio asset with fade in and fade out, balance a clip left or right with stereo pan, and let transitions crossfade the mix automatically.
{ "type": "audio", "src": ".../bed.mp3", "volume": 0.4, "fadeIn": 1 }Output
MP4 with H.264, WebM with VP9, animated GIF, MP3 for audio-only exports, and JPG or PNG to capture a single frame at any timestamp. Any resolution up to 4K on every plan, any frame rate, codec overrides when you want them. No resolution tiers.
"output": { "format": "gif", "resolution": { "width": 480, "height": 854 } }The alternative is a filtergraph
The same edit, twice
Two clips, a crossfade, a title. On the left, the FFmpeg filter_complex you would maintain by hand. On the right, the compose timeline. Both run on Rendobar. Pick the one you want to debug at 2am.
ffmpeg -i beach.mp4 -i city.mp4 \ -filter_complex "\ [0:v]trim=0:4,setpts=PTS-STARTPTS,\ scale=1080:1920:force_original_aspect_ratio=increase,\ crop=1080:1920,format=yuv420p[v0]; \ [1:v]trim=3:7,setpts=PTS-STARTPTS,\ scale=1080:1920:force_original_aspect_ratio=increase,\ crop=1080:1920,format=yuv420p[v1]; \ [v0][v1]xfade=transition=fade:duration=1:offset=3[vx]; \ [vx]drawtext=fontfile=Inter.ttf:text='Summer 26':\ fontsize=72:fontcolor=white:x=(w-tw)/2:y=h-320:\ enable='between(t,0.5,3.5)'[vt]; \ [0:a]atrim=0:4,asetpts=PTS-STARTPTS[a0]; \ [1:a]atrim=3:7,asetpts=PTS-STARTPTS[a1]; \ [a0][a1]acrossfade=d=1[ax]" \ -map "[vt]" -map "[ax]" -c:v libx264 -crf 20 out.mp4 # plus the retry logic, the temp files, # the machine it runs on, and the queue in front of it
{
"output": { "format": "mp4",
"resolution": { "width": 1080, "height": 1920 } },
"timeline": {
"tracks": [
{ "clips": [
{ "asset": { "type": "video", "src": ".../beach.mp4" },
"start": 0, "length": 4 },
{ "type": "transition",
"transition": "crossfade", "duration": 1 },
{ "asset": { "type": "video", "src": ".../city.mp4" },
"start": 3, "length": 4 }
] },
{ "clips": [
{ "asset": { "type": "text", "text": "Summer 26",
"style": { "size": 72, "color": "#FFFFFF" } },
"start": 0.5, "length": 3 }
] }
]
}
}When the timeline cannot express something, Rendobar's FFmpeg API takes the raw command. Same platform, same credits, one job type apart.
Built for coding agents
Your agent writes the timeline
A JSON timeline is exactly what coding agents are good at producing. Rendobar ships a native MCP server, so Claude Code, Cursor, and Codex can submit compose jobs, watch progress, and fetch the output without leaving the editor.
Where it sits
compose, template platforms, or raw FFmpeg
| Capability | compose | Template platforms | DIY FFmpeg |
|---|---|---|---|
| You write | a JSON timeline | a template in their editor | filter_complex strings |
| Template editor required | none | yes | none |
| Multi-track layering | yes | varies by plan | yes, by hand |
| Infrastructure to run | none | none | servers, queues, retries |
| Live render progress | percent, fps, speed | rarely | parse stderr yourself |
| Escape hatch to raw FFmpeg | same platform, one job type over | no | you are the escape hatch |
Comparing a specific platform? See the comparison pages.
Three ways in
Submit from anything that can POST
import { createClient, outputUrl } from "@rendobar/sdk";
const client = createClient({ apiKey: process.env.RENDOBAR_API_KEY });
const job = await client.jobs.create({ type: "compose", params: { schemaVersion: 1, output: { format: "mp4", resolution: { width: 1080, height: 1920 }, fps: 30 }, timeline: { tracks: [{ clips: [ { asset: { type: "video", src: "https://cdn.rendobar.com/assets/examples/sea.mp4" }, start: 0, length: 4 }, { type: "transition", transition: "crossfade", duration: 1 }, { asset: { type: "video", src: "https://cdn.rendobar.com/assets/examples/sample.mp4" }, start: 3, length: 4 }, ], }], }, },});
const result = await client.jobs.wait(job.id);console.log(outputUrl(result)); // the rendered MP4import os, requests
resp = requests.post( "https://api.rendobar.com/jobs", headers={"Authorization": f"Bearer {os.environ['RENDOBAR_API_KEY']}"}, json={ "type": "compose", "params": { "schemaVersion": 1, "output": {"format": "mp4", "resolution": {"width": 1080, "height": 1920}, "fps": 30}, "timeline": { "tracks": [{ "clips": [ {"asset": {"type": "video", "src": "https://cdn.rendobar.com/assets/examples/sea.mp4"}, "start": 0, "length": 4}, {"type": "transition", "transition": "crossfade", "duration": 1}, {"asset": {"type": "video", "src": "https://cdn.rendobar.com/assets/examples/sample.mp4"}, "start": 3, "length": 4}, ] }] }, }, },)print(resp.json())curl -X POST https://api.rendobar.com/jobs \ -H "Authorization: Bearer $RENDOBAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "compose", "params": { "schemaVersion": 1, "output": { "format": "mp4", "resolution": { "width": 1080, "height": 1920 }, "fps": 30 }, "timeline": { "tracks": [{ "clips": [ { "asset": { "type": "video", "src": "https://cdn.rendobar.com/assets/examples/sea.mp4" }, "start": 0, "length": 4 }, { "type": "transition", "transition": "crossfade", "duration": 1 }, { "asset": { "type": "video", "src": "https://cdn.rendobar.com/assets/examples/sample.mp4" }, "start": 3, "length": 4 } ] }] } } }'FAQ
Questions developers actually search
What is a video composition API?
An API that renders finished video from a structured description instead of an editing UI. With compose the description is a JSON timeline of tracks, clips, transitions, text, and effects. You POST it to the Rendobar API and get an MP4 back.
How do I create a video from JSON?
Write a timeline object with at least one track and one clip, then POST it to /jobs with type "compose". The response carries the job id. When the job completes, the output URL points at the rendered file. The five-step section above walks the whole model.
Which transitions does the compose API support?
Crossfade, fade to black, slide or push from any of four directions, a wipe along an edge or through a circle, box or barn doors, zoom, and a hard cut. A transition sits between two clips on a track, or between two scenes in scene mode. Audio crossfades automatically.
Can I add text overlays to a video with an API?
Yes. Text is an asset type in the timeline with font, size, weight, color, stroke, background, position, entrance animation, and drop shadow. Put it on an upper track and it renders over the video below.
Can I use my own brand font in a video API?
Yes. Put your font file URLs in the job's fonts input, each under a family name you choose, then reference that name in a text clip. TTF, OTF, TTC, WOFF and WOFF2 all work, and there is no limit on how many you declare. You never have to open the file to find the family name buried inside it.
Does compose support Google Fonts?
Name any Google Fonts family in a text clip's font and it is fetched at render time. Nothing to upload. Seven families are bundled into the render image and resolve instantly: Inter, Roboto, Montserrat, Poppins, Oswald, Anton, and Bebas Neue.
What output formats does compose support?
MP4 with H.264, WebM with VP9, animated GIF, MP3 for audio-only exports, and JPG or PNG to capture a single frame at any timestamp. Any resolution up to 4K renders on every plan with no resolution tiers, and frame rate is a free choice.
How is compose different from running FFmpeg commands directly?
Both run on Rendobar. compose takes a declarative timeline and handles the filter graphs, sync, and audio mixing for you. The FFmpeg API takes the raw command when you need something the timeline does not express. Same platform, one job type apart.
How much does it cost to render a video?
Pricing is cost-plus per second of compute, and a typical short composition renders in about 6 seconds. Signup includes $5 of free credit with no card required.
Can AI agents like Claude Code use the compose API?
Yes. Rendobar ships a native MCP server, and a JSON timeline is exactly the kind of structured output coding agents are good at producing. Agents can submit compose jobs, watch progress, and fetch the output without leaving the editor.
Render your first composition
$5 of free credit on signup. One POST request to your first MP4.
Recent changes
All updates- Fixed
Overlapping compose clips crossfade
Fixes compose renders that failed as incomplete when two clips on one track overlapped with nothing between them. They crossfade over the overlap now.
- Fixed
Compose zooms and pans stop flashing black
Fixes a single black frame that could appear at a random point in a long compose render with an animated zoom, pan or crop.
- Fixed
Long compose timelines render to the end
Fixes compose renders that went black after 500 seconds of one still, and timelines with around 90 transformed stills that failed part way through.
