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.

JSON
{
  "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#

VideoStructure
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 slideSeparate pages, no film. Rendered page by page
Everything else: longer than 8 seconds, more than one scene, or one deliverable videoA 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#

FieldTypeDescription
vNumberRequired. Always 1
backgroundStringA 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
outputObjectEncoding: { "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
tracksArrayUp to 8 tracks that run across scenes
combineBooleanAccepted for forward compatibility. A film always renders as one video today, so the value has no effect
posterObject{ "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.

JSON
{ "type": "colorFlood", "duration": 0.8, "color": "#FF4D2E", "origin": { "x": 0.5, "y": 0.72 } }
FieldTypeDescription
typeStringOne of the transition types. "none" is a hard cut (used with overlay)
durationNumberSeconds, 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
easeString1 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
directionStringleft, right, up or down. Used by slide, push, wipe, flip, cube and whip. Default left
colorStringA CSS colour (same rules as film.background). Used by dip and colorFlood
originObject{ "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 }
fromStringgrow only, required: the id of the layer on the previous page that grows into this page
targetStringzoomThrough only, required: the id of the layer on the previous page the camera dives into
pairsArraymatch 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
othersStringmatch only. What the unpaired layers do: "clear" (default) fades the old ones out first and the new ones in last; "dissolve" crossfades everything
revealStringmatch only. How this page appears around the morph: "iris" (default) opens a circle from behind the paired layer; "fade" crossfades
overlayObjectAn 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.

TypeDefaultEffect
fade0.9 s, power1.inOutThe two pages blend into each other
dip1.0 s, #000000Fades to color, then into this page
slide0.9 s, leftThis page slides in over the previous one
push0.9 s, leftThis page pushes the previous one out
wipe0.9 s, leftAn edge sweeps across to show this page
iris1.0 sA circle opens from origin
clockWipe1.0 sA clock hand sweeps around origin
flip1.0 s, leftThe page flips over like a card
cube1.0 s, leftThe pages turn like the sides of a cube
whip0.6 s, left, power3.inOutA fast, blurred pan into this page
blurSwap1.0 sThe previous page blurs out as this one blurs in
zoom1.0 sZooms into this page from origin
colorFlood1.1 s, #111111color floods the frame from origin, then clears to this page

Continuity transitions: a layer of the previous page carries the cut.

TypeDefaultEffect
grow1.2 s, power3.inOutThe 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
zoomThrough1.0 s, power3.inThe camera moves through the layer named by target into this page. Falls back to zoom the same way
match1.1 s, power3.inOutEach 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.

  • type must be a known type; direction one of the four directions. Unknown values fail with a did-you-mean suggestion.
  • A cut has either a type or an overlay, not both (error).
  • duration over 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.
  • grow without from and zoomThrough without target are errors; the named layer must exist on the previous page.
  • match: every pairs[].from must exist on the previous page and every pairs[].to on this page. Without pairs, at least one layer id should appear on both pages (warning). A matched layer that also has its own entrance (wake, reveal, typewriter or transitions.enter) plays both at once (warning: drop the entrance).
  • pairs, others and reveal on a non-match type 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:

FieldTypeDescription
idStringRequired, unique
nameStringOptional label (Studio shows it on the timeline)
startNumberAbsolute film seconds. Ignored when anchor is set
anchorObject{ "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
durationNumberSeconds from the clip's start
untilObject{ "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.

JSON
{ "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.

JSON
{ "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#

LimitValue
Scenes400
Film length1,800 s, and your plan's maximum video length
Tracks8, with 400 clips each
Transition or overlay duration3 s, and at most half of either neighbouring scene
match pairs24
Audio sources mixed into one film (page tracks, video layers with sound, audio clips)64; the rest are dropped with a warning
CanvasEvery scene has the same canvas size

How a film renders#

  • A whole-template render with response.format: "mp4" returns one video: data is a single object (like a single-page template) with content and videoDuration set to the film's length. See Render as a video.
  • includePages renders 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.muted silences the film; videoOptions.fps sets the frame rate and wins over film.output.fps. A film never renders above 30 fps. combinePages, pageTransition, duration, audioSource and 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.
  • size renders the film at another size, and extraSizes adds 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).

Was this page helpful?

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