From 433079d8900742d6e19a689fbfad3f1358994f02 Mon Sep 17 00:00:00 2001 From: Abdelrahman Essawy Date: Tue, 22 Sep 2026 22:27:30 +0300 Subject: [PATCH 01/16] docs(compose): rewrite the page for the shape the next release ships The page taught the pre-release timeline: per-clip `color`, `blur`, `chromaKey` and `filter` fields, `animateTo` for movement, shapes that placed themselves with their own `position`, `size` and `anchor`, and `output.frameTime` for a still. Ten of the twelve complete examples on it used at least one field that has moved. It now teaches one `effects` list on a clip, a track or the timeline, keyframes with 33 easings on anything that moves, and one `transform` that places every clip including text and shapes. New sections cover timers, subtitles from cues or an .srt file, Lottie animations, masks and LUTs, the `engine` entry, `output.range`, a transparent background, and the free `validate` endpoint. The transition table carries all six kinds, with wipes by shape or by your own greyscale map. Every JSON example was run through the API's own validator: 30 of them, no refusals, no warnings, nothing left in the old shape. That caught three examples I had written wrong, including an engine parameter that takes a number and a transparent background on mp4, which has no alpha. --- jobs/compose.mdx | 491 +++++++++++++++++++++++++++++------------------ 1 file changed, 303 insertions(+), 188 deletions(-) diff --git a/jobs/compose.mdx b/jobs/compose.mdx index 7a73390..e914d4b 100644 --- a/jobs/compose.mdx +++ b/jobs/compose.mdx @@ -1,7 +1,7 @@ --- title: "Compose: render from a timeline" sidebarTitle: "Compose" -description: "Render a video from a declarative JSON timeline. Tracks, clips, transitions, text, and per-clip effects." +description: "Render a video from a declarative JSON timeline: tracks, clips, transitions, text, shapes, keyframes and effects." icon: "film" keywords: ["video compose api", "json timeline to video", "video transitions api", "video editing api", "compose"] canonical: "https://rendobar.com/docs/jobs/compose" @@ -15,7 +15,7 @@ canonical: "https://rendobar.com/docs/jobs/compose" "@type": "TechArticle", "@id": "https://rendobar.com/docs/jobs/compose#article", "headline": "Compose: render from a timeline", - "description": "Render a video from a declarative JSON timeline. Tracks, clips, transitions, text, and per-clip effects.", + "description": "Render a video from a declarative JSON timeline: tracks, clips, transitions, text, shapes, keyframes and effects.", "datePublished": "2026-06-21", "author": { "@type": "Organization", "@id": "https://rendobar.com/#organization" }, "publisher": { "@type": "Organization", "@id": "https://rendobar.com/#organization" } @@ -140,7 +140,7 @@ curl -X POST https://api.rendobar.com/jobs \ -**Assets:** video, image, text, audio, composition · **Output:** mp4 / webm / gif / mp3 (audio only) / jpg / png (still frame) +**Assets:** video, image, audio, text, timer, subtitles, shape, animation (Lottie), composition · **Output:** mp4 / webm / gif / mp3 (audio only) / jpg / png (still frame) Without `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. @@ -171,14 +171,21 @@ Writing the timing out by hand gives the same render. The second clip starts `du ] ``` -`slide` also accepts `direction: "left" | "right" | "up" | "down"`. - | Transition | Effect | | --- | --- | | `crossfade` | A dissolves directly into B | | `fade` | A dips through black, then B fades up | -| `slide` | B slides in over A from an edge (directional) | -| `zoom` | B grows in from the center | +| `slide` | B slides in over A from an edge | +| `push` | B pushes A off the frame | +| `wipe` | An edge travels across, in a shape or along your own greyscale map | +| `zoom` | B grows in from the centre | +| `none` | A hard cut, no blend | + +`slide`, `push` and `wipe` take a `direction`: `left`, `right`, `up` or `down`. A wipe takes a `shape` instead (`circle`, `box`, `barnDoorHorizontal`, `barnDoorVertical`), or a `map`: a greyscale image of your own, where black turns over first and white last. + +```json +{ "type": "transition", "transition": "wipe", "shape": "circle", "duration": 0.8 } +``` @@ -273,110 +280,185 @@ A second track renders over the first. This lays an animated title over the vide ] ``` -## Effects on a clip +## Effects -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](#clip-fields). +Effects are one ordered list. The same list sits on a clip, on a track, or on the whole timeline, and it runs in the order you write it. ```json { "asset": { "type": "video", "src": "https://cdn.rendobar.com/assets/examples/sea.mp4" }, "start": 0, "length": 3, - "color": { "saturation": 1.2, "temperature": 6800 }, - "speed": 0.8, - "transform": { "scale": 1.1, "animateTo": { "scale": 1.3 } } + "effects": [ + { "type": "color", "saturation": 1.2, "temperature": 6800 }, + { "type": "vignette" } + ] +} +``` + +On a **track**, the list covers every clip on it. On the **timeline**, it covers the finished video, which is where one grade for the whole edit belongs. + +```json +"timeline": { + "effects": [{ "type": "look", "name": "muted" }], + "tracks": [ + { "effects": [{ "type": "grain" }], "clips": [{ "asset": { "type": "video", "src": "https://cdn.rendobar.com/assets/examples/sea.mp4" } }] } + ] } ``` -### Color and filters +Every entry takes an optional `start` and `length`, in seconds or as a percent of what it sits on, so an effect can run for part of a clip. Numeric parameters take keyframes, so they can move while it runs. -`color` grades a clip with `contrast`, `saturation`, `temperature`, `brightness`, `gamma`, and `hue`. `filter` applies a one-shot look like `greyscale` or `boost`. +```json +{ "type": "blur", "radius": [{ "time": "0%", "value": 14, "easing": "easeOutCubic" }, { "time": 1, "value": 0 }] } +``` + +There are 34 effects, for picture and for sound, each with its own parameters in real units. The full list, with a rendered before and after for each one, is the [effects reference](https://rendobar.com/compose/effects/). The groups: + +| Group | Examples | +| --- | --- | +| Colour and looks | `color`, `look`, `lut`, `denoise`, `glow`, `grain`, `vignette`, `sharpen`, `blur` | +| Stylise | `shake`, `glitch`, `mosaic`, `posterize`, `rgbShift`, `scanLines`, `sketch`, `trails` | +| Layers and masking | `chromaKey`, `mask`, `blurRegion`, `outline`, `dropShadow` | +| Sound | `eq`, `compressor`, `limiter`, `gate`, `highPass`, `lowPass`, `loudness`, `pitch`, `echo`, `reverb`, `voiceDenoise` | +| Sound made visible | `visualizer` | + +Two of them read a file, which is fetched and checked like any clip source: `lut` takes a `.cube` grade, and `mask` takes a picture that decides what of the clip shows. + +```json +{ "type": "mask", "src": "https://cdn.rendobar.com/assets/brand/logo-mark.png", "channel": "alpha" } +``` + +An effect that changes the picture is refused on a clip that has none, and one that changes the sound is refused on a silent clip, so a mistake is a 400 rather than a render that ignores it. Text and shapes draw their own outline and shadow, so `outline` and `dropShadow` are refused on them. - + -### Motion and speed +### Anything the engine can do -`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. +`{ "type": "engine" }` reaches the rest of the render engine by its own names, for the case a promoted effect does not cover. Every service and property is checked before the job starts, so a typo is a 400 and not a failed render. - -