What is a film?
The film block and page transitions: how a multi-page template renders as one video with scenes, cuts, music and cross-page layers. Schema and limits.
Published ·Updated
A film is a template whose pages play one after another as a single video. Each page is a scene, each scene after the first can have a transition from the previous one, and tracks carry music or layers across scenes. The template stores two things for this:
film: a template-level object. Its presence makes the template a film.transitionIn: an optional object on each page, describing how that page starts.
Everything else about the template stays the same: pages, elements, animations, motion, audio and subtitles and parameters work per scene exactly as they do on a normal page. Times inside a scene (showAt, keyframes, reveals) count from that scene's own start.
In Studio, films are made with Film mode. Through the API, send film and transitionIn with Create Template or Update Template.
{
"name": "Launch film",
"canvas_width": 1080,
"canvas_height": 1920,
"film": { "v": 1, "background": "#17171C", "output": { "profile": "film" } },
"pages_data": [
{ "id": "hook", "videoDuration": 3.2, "canvas": { "width": 1080, "height": 1920, "backgroundColor": "#17171C" }, "elements": [] },
{ "id": "proof", "videoDuration": 4, "transitionIn": { "type": "whip", "direction": "left", "duration": 0.6 }, "elements": [] },
{ "id": "end", "videoDuration": 3, "transitionIn": { "type": "grow", "from": "stamp" }, "elements": [] }
]
}When a video is a film#
| Video | Structure |
|---|---|
| A quick animation: one idea, up to 8 seconds (a logo sting, an animated post, a loop) | One page, no film |
| A carousel: each page is posted as its own slide | Separate pages, no film. Rendered page by page |
| Everything else: longer than 8 seconds, more than one scene, or one deliverable video | A film: one page per scene, 2 to 8 seconds each, plus film |
A single page longer than 8 seconds is flagged by Studio and by the API's design checks; past 15 seconds it is always flagged. One long page with layers appearing and disappearing in time windows is hard to edit and keeps no clean thumbnail per scene. Scenes can be reordered, swapped and retimed on their own.
The film object#
| Field | Type | Description |
|---|---|---|
v | Number | Required. Always 1 |
background | String | A CSS colour shown under the scenes while a transition reveals part of the frame. 1 to 100 characters; the characters < > { } ; " ' \ are refused. Default: page 1's canvas backgroundColor, else #000000 |
output | Object | Encoding: { "profile": "default" | "film", "fps": 24 | 25 | 30 }. profile: "film" uses a slower x264 preset at constant quality (CRF 18) with 192 kbps AAC: a higher quality tier that is usually a much smaller file. fps sets the film's frame rate. A render's videoOptions.fps wins when you send it. Films render at 30 fps at most. Default: the normal video encode at 30 fps |
tracks | Array | Up to 8 tracks that run across scenes |
combine | Boolean | Accepted for forward compatibility. A film always renders as one video today, so the value has no effect |
poster | Object | { "page": "<page id>", "at": <seconds from that scene's start> }. Validated (the page must exist; a moment inside the scene's incoming transition is a warning). Reserved: renders and thumbnails do not read it yet |
Unknown keys are kept and reported as warnings with a did-you-mean suggestion. Studio's Film mode switch writes { "v": 1, "output": { "profile": "film" } }.
Orshot may add preview fields to the block (thumbnail_url, thumbnail_meta, video_thumbnail_url, video_thumbnail_meta). They are derived, never part of the design; send them back unchanged or leave them out.
Page transitionIn#
Set on a page in pages_data. It describes how that page starts from the previous one; page 1 has nothing to start from, so its transitionIn is ignored with a warning. No transitionIn (or null) is a hard cut.
{ "type": "colorFlood", "duration": 0.8, "color": "#FF4D2E", "origin": { "x": 0.5, "y": 0.72 } }| Field | Type | Description |
|---|---|---|
type | String | One of the transition types. "none" is a hard cut (used with overlay) |
duration | Number | Seconds, 0 to 3. Default per type (table below). A value under 0.05 plays as 0.05. A transition may take at most half of either neighbouring scene's length |
ease | String | 1 to 120 characters. GSAP names (power1 to power4, expo, sine, circ, back, each with .in, .out or .inOut; none, linear) or cubic-bezier(a, b, c, d). Unknown names play as power2.inOut |
direction | String | left, right, up or down. Used by slide, push, wipe, flip, cube and whip. Default left |
color | String | A CSS colour (same rules as film.background). Used by dip and colorFlood |
origin | Object | { "x": 0..1, "y": 0..1 } as a fraction of the frame. Used by iris, clockWipe, zoom and colorFlood. Default the centre { 0.5, 0.5 } |
from | String | grow only, required: the id of the layer on the previous page that grows into this page |
target | String | zoomThrough only, required: the id of the layer on the previous page the camera dives into |
pairs | Array | match only, up to 24 { "from": "<id on the previous page>", "to": "<id on this page>" }. Default: layers that have the same id on both pages |
others | String | match only. What the unpaired layers do: "clear" (default) fades the old ones out first and the new ones in last; "dissolve" crossfades everything |
reveal | String | match only. How this page appears around the morph: "iris" (default) opens a circle from behind the paired layer; "fade" crossfades |
overlay | Object | An effect on a hard cut: { "type": "flash" | "leak", "duration": <s, up to 3>, "color": <CSS colour> }. Defaults: flash 0.25 s white, leak 0.4 s #ffb36b. An overlay never changes timing |
Transition types#
Overlapping transitions: the previous scene keeps playing while this one starts, and the film is shorter by the transition's length.
| Type | Default | Effect |
|---|---|---|
fade | 0.9 s, power1.inOut | The two pages blend into each other |
dip | 1.0 s, #000000 | Fades to color, then into this page |
slide | 0.9 s, left | This page slides in over the previous one |
push | 0.9 s, left | This page pushes the previous one out |
wipe | 0.9 s, left | An edge sweeps across to show this page |
iris | 1.0 s | A circle opens from origin |
clockWipe | 1.0 s | A clock hand sweeps around origin |
flip | 1.0 s, left | The page flips over like a card |
cube | 1.0 s, left | The pages turn like the sides of a cube |
whip | 0.6 s, left, power3.inOut | A fast, blurred pan into this page |
blurSwap | 1.0 s | The previous page blurs out as this one blurs in |
zoom | 1.0 s | Zooms into this page from origin |
colorFlood | 1.1 s, #111111 | color floods the frame from origin, then clears to this page |
Continuity transitions: a layer of the previous page carries the cut.
| Type | Default | Effect |
|---|---|---|
grow | 1.2 s, power3.inOut | The layer named by from grows to fill the frame and becomes this page. Needs a visible box; if the layer is gone it plays as zoom |
zoomThrough | 1.0 s, power3.in | The camera moves through the layer named by target into this page. Falls back to zoom the same way |
match | 1.1 s, power3.inOut | Each pair moves from its place on the previous page to its place on this page while the rest of the page is revealed (reveal) and the unpaired layers hand over (others) |
Cut overlays (type: "none" plus overlay): flash peaks on the cut (a short rise before, a longer fall after); leak sweeps a warm light across the frame around the cut.
Transition rules#
Errors block the save; warnings come back in the response.
typemust be a known type;directionone of the four directions. Unknown values fail with a did-you-mean suggestion.- A cut has either a
typeor anoverlay, not both (error). durationover half of the shorter neighbouring scene is an error, so a 0.8 s transition needs scenes of at least 1.6 s on both sides.growwithoutfromandzoomThroughwithouttargetare errors; the named layer must exist on the previous page.match: everypairs[].frommust exist on the previous page and everypairs[].toon this page. Withoutpairs, at least one layer id should appear on both pages (warning). A matched layer that also has its own entrance (wake,reveal,typewriterortransitions.enter) plays both at once (warning: drop the entrance).pairs,othersandrevealon a non-matchtype are ignored (warning).- Unknown keys are ignored (warning).
Timeline#
Nothing about timing is stored; it is derived from the pages and the film block:
- A scene lasts its page's
videoDuration. Without one, a still page holds for 2 seconds. A page with animations lasts until they end, and a page with a video lasts as long as the video. - A transition overlaps the end of one scene with the start of the next, so the film's total length is the scenes added up minus each transition's length. Scene 2 starts at
scene1.end - transition.duration. - Studio shows the overlaps as striped parts of the timeline.
Tracks and clips#
film.tracks holds things that run across scenes. A track is { "id", "kind": "audio" | "layers", "name"?, "clips": [...] }, with up to 8 tracks and up to 400 clips per track. Later layers tracks draw above earlier ones. Track and clip ids must be unique.
A clip's window on the film:
| Field | Type | Description |
|---|---|---|
id | String | Required, unique |
name | String | Optional label (Studio shows it on the timeline) |
start | Number | Absolute film seconds. Ignored when anchor is set |
anchor | Object | { "page": "<page id>", "edge": "start" | "end", "offset": <s> }. The clip starts at that moment and follows the scene when scenes move. Default edge start, offset 0 |
duration | Number | Seconds from the clip's start |
until | Object | { "page", "edge", "offset" } or { "edge": "filmEnd", "offset" }. Wins over duration. With neither, the clip runs to the end of the film |
Audio clips (kind: "audio"): src (required), volume 0 to 2, fadeIn, fadeOut, trimStart (seconds into the file), loop.
{ "id": "music", "kind": "audio", "clips": [
{ "id": "bed", "src": "https://cdn.example.com/bed.mp3", "start": 0, "until": { "edge": "filmEnd" }, "volume": 0.6, "fadeOut": 1.5, "loop": true }
] }Layers clips (kind: "layers"): elements (required, at least one, the same schema as page elements). Times inside the clip count from the clip's start. Use them for a logo, a progress bar or a background video that keeps playing under the cuts.
{ "id": "brand", "kind": "layers", "clips": [
{ "id": "logo", "anchor": { "page": "proof" }, "until": { "edge": "filmEnd" }, "elements": [ { "id": "logo-mark", "type": "image", "content": "https://..." } ] }
] }Rules: an anchor or until must name an existing page; a clip that ends before it starts is an error; page audioTracks (narration per scene) still play inside each scene.
Limits#
| Limit | Value |
|---|---|
| Scenes | 400 |
| Film length | 1,800 s, and your plan's maximum video length |
| Tracks | 8, with 400 clips each |
| Transition or overlay duration | 3 s, and at most half of either neighbouring scene |
match pairs | 24 |
| Audio sources mixed into one film (page tracks, video layers with sound, audio clips) | 64; the rest are dropped with a warning |
| Canvas | Every scene has the same canvas size |
How a film renders#
- A whole-template render with
response.format: "mp4"returns one video:datais a single object (like a single-page template) withcontentandvideoDurationset to the film's length. See Render as a video. includePagesrenders the listed pages one by one, as for any multi-page template. Other video formats (webm,mov,mkv,gif) also render page by page. Image and PDF formats are unchanged.videoOptions.mutedsilences the film;videoOptions.fpssets the frame rate and wins overfilm.output.fps. A film never renders above 30 fps.combinePages,pageTransition,duration,audioSourceand the subtitle options do not apply to a film.- Audio: each scene's
audioTracks, unmuted video layers and the film's audio clips are mixed into one soundtrack with a limiter. Captions are not burned into films yet, and audio waveform layers are not animated inside films; both are reported as render warnings. sizerenders the film at another size, andextraSizesadds up to 4 more sizes per call. Each size is a full film render and is billed as one. Per-page size maps are refused: a film has one canvas.- Motion follows the resized layers, so 9:16 to 1:1 or 4:5 work well; 9:16 to 16:9 gives a centred column, so design 16:9 separately.
Validation on write#
Create Template and Update Template validate film and every transitionIn together with the pages they refer to. Shape and limit problems, missing layers and bad timings fail with 400 and "error": "Validation failed"; details lists each problem by path, e.g. pages.2.transitionIn.from: No layer "stamp" on page 2 (the previous page). Soft problems come back in the response warnings. On an update, problems that were already in the stored template never block an unrelated change; they are listed as pre-existing (not blocking) warnings. A film value that is not an object or null fails with the code invalid_film.
Update Pages re-checks the stored film against the pages after the operations and refuses, with the code invalid_film, only operations that would newly break it. Studio saves check the block's shape and limits the same way (Invalid film, code invalid_film).
Related#
- Film mode in Studio
- Motion for keyframes, reveals, counters and groups inside a scene
- Template Anatomy
- Render from Studio Template
Ready to automate?
Start rendering images, PDFs and videos from your templates in under 2 minutes. Free plan, no credit card.
Get your API key- Image, PDF and video generation via API
- Visual editor with AI and smart layouts
- Zapier, Make, MCP and 40+ integrations
- White-label embed for your own app
- 100 free credits a month, no credit card required