Skip to main content

Movie, Scene & Layer Schema Reference

Every render job submitted to ViralSync is built around a Movie — a structured JSON document that describes the full video. A Movie contains one or more Scenes, and each Scene contains one or more Layers.

Movie
└── Scene[]
└── Layer[] (video | image | audio | text)

This page is the authoritative reference for every property in that hierarchy.

API Access Required

Submitting render jobs via the API requires a Pro plan or higher. Free-plan users can use the visual editor in the dashboard. See Plans & Limits.


Movie

The root object passed as movie in a render job request.

PropertyTypeRequiredDefaultConstraintsDescription
idstringNoauto-generatedStable identifier. Used for scene-level caching: if an identical scene was previously rendered, the cached output is reused.
titlestringNo"Untitled Movie"Display label. Not embedded in the video output.
widthnumberNo1920360–3840Canvas width in pixels. Must match your target aspect ratio.
heightnumberNo1080360–2160Canvas height in pixels.
fpsnumberNo301–60Frames per second. Common values: 24 (cinematic), 30 (standard), 60 (smooth motion).
scenesScene[]YesAt least 1 sceneOrdered list of scenes. Scenes are rendered in parallel; the final video preserves their index order.

Common Resolutions

FormatWidthHeightFPS
YouTube 4K3840216030
YouTube 1080p1920108030
YouTube 720p128072030
Instagram Reels / TikTok1080192030
Instagram Square1080108030
Twitter / X128072030

Example

{
"id": "movie_summer_promo",
"title": "Summer Promo Video",
"width": 1920,
"height": 1080,
"fps": 30,
"scenes": []
}

Scene

A Scene is a self-contained segment of the video with its own duration, background colour, and layers. Scenes are executed in parallel across render workers; the output clips are concatenated in order during the assemble phase.

PropertyTypeRequiredDefaultConstraintsDescription
idstringYesUnique within the movieStable identifier for this scene. Used for caching and progress reporting.
namestringNoHuman-readable label. Useful for debugging; not embedded in output.
durationnumberYes> 0Scene duration in seconds. All layers must have startTime + duration ≤ scene.duration.
bgColorstringNo"#000000"Any CSS colourBackground colour rendered behind all layers. Supports hex (#1a1a2e), RGB (rgb(26,26,46)).
widthnumberNoinherits movie.width360–3840Override the canvas width for this scene only.
heightnumberNoinherits movie.height360–2160Override the canvas height for this scene only.
layersLayer[]No[]Ordered list of layers. Rendered in zIndex order (lowest = bottom).
descriptionstringNoOptional description. Ignored by the renderer; useful for AI-generated scripts.
indexnumberNoarray positionExplicit ordering hint. Defaults to the scene's position in scenes[].

Example

{
"id": "scene_intro",
"name": "Introduction",
"duration": 5,
"bgColor": "#1a1a2e",
"layers": []
}

Layer

Layers are the building blocks of a scene. Every layer has a type that determines which properties are valid. There are four types:

TypeDescriptionRequires source
videoA video clip rendered at the specified position and sizeYes
imageA static image or GIFYes
audioAn audio track (no visual output)Yes
textRendered text using system fontsNo

Base Properties (all layer types)

PropertyTypeRequiredDefaultConstraintsDescription
idstringYesUnique within the sceneStable identifier for this layer.
namestringNoDisplay label. Not embedded in output.
type"video" | "image" | "audio" | "text"YesLayer type. Determines which additional properties are valid.
role"background" | "overlay"No"overlay"Semantic role hint. "background" layers are placed behind overlay layers in the editor UI, but zIndex controls actual render ordering.
startTimenumberYes≥ 0Offset in seconds from the start of the scene at which this layer becomes visible/audible.
durationnumberYes> 0How long this layer is visible/audible, in seconds.
maxDurationnumberNo> 0For video and audio layers: the total available duration of the source clip. Used by the editor to enforce trim limits. Not validated by the renderer.
zIndexnumberYesAny integerStacking order. Higher values render on top. Layers with the same zIndex are stacked in declaration order.
position{ x: number, y: number }YesTop-left corner of the layer in pixels, relative to the scene canvas. { x: 0, y: 0 } = top-left corner.
size{ width: number, height: number }Yes> 0Dimensions of the layer in pixels. The layer is scaled to fit this box.
transformTransformObjectNoAdditional geometric transformation applied after position and size. See Transform.
sourcestring (URL)For video / image / audioMust be publicly accessible HTTP/HTTPS URLThe media file to render. Must be a stable, publicly accessible URL — no auth tokens, no short-lived presigned URLs. The render worker downloads this URL at render time.
volumenumberNo1.00.0–2.0Audio gain. 0 = silent, 1 = original volume, 2 = double gain. Applies to video and audio layers.
mutebooleanNofalseMute the audio track. For video layers: video renders but audio is silent. Has no effect on image or text layers.
Public URLs required

The source field must be a publicly accessible URL that the render worker can download without authentication. Do not use:

  • Auth-gated URLs (requiring Authorization headers)
  • Short-lived presigned URLs (AWS S3, GCS) that may expire before the render starts
  • localhost or private network URLs

Use CDN URLs (Cloudflare R2, Cloudflare Images, Bunny CDN, public S3 buckets) for reliable rendering.


Transform

The optional transform object applies geometric modifications on top of position and size.

PropertyTypeDefaultDescription
xnumber0Additional horizontal offset in pixels, applied after position.x.
ynumber0Additional vertical offset in pixels, applied after position.y.
scaleXnumber1.0Horizontal scale multiplier. 2.0 = double width. Applied from the layer centre.
scaleYnumber1.0Vertical scale multiplier. 0.5 = half height. Applied from the layer centre.
scalenumber1.0Uniform scale applied after scaleX/scaleY. 1.5 = 50% larger.
rotationnumber0Rotation in degrees, clockwise. 180 = upside down. Applied from the layer centre.
opacitynumber1.0Opacity multiplier. 0 = fully transparent, 1 = fully opaque.

Example:

"transform": {
"rotation": 15,
"opacity": 0.85,
"scale": 1.2
}

Text Layer Additional Properties

When type is "text", the following additional properties control how the text is rendered.

PropertyTypeDefaultDescription
textstring""The text content to render. Supports \n for line breaks.
fontSizenumber48Font size in pixels.
fontFamilystring"Inter, Arial, sans-serif"CSS font-family stack. The renderer uses system fonts available on the render worker.
colorstring"#ffffff"Text colour. Any CSS colour string.
textAlign"left" | "center" | "right""center"Horizontal alignment of text within the size bounding box.
fontWeightstring | number"normal"CSS font-weight. Use "bold" or a numeric weight like 700.
fontStylestring"normal""normal" or "italic".
textDecorationstring"none""underline" or "line-through".
lineHeightnumber1.1Line height multiplier relative to fontSize.
letterSpacingnumber0Additional space between characters in pixels.
strokestringOutline colour for the text. Any CSS colour. Requires strokeWidth to be visible.
strokeWidthnumberWidth of the text outline in pixels.

Layer Type Compatibility Matrix

Propertyvideoimageaudiotext
source (URL)✅ Required✅ Required✅ Required❌ Not used
position❌ Ignored
size❌ Ignored
zIndex❌ Ignored
transform❌ Ignored
volume / mute
text, fontSize, color, …✅ Required

Complete Example

A 2-scene movie with all four layer types:

{
"id": "movie_demo",
"title": "API Demo Video",
"width": 1920,
"height": 1080,
"fps": 30,
"scenes": [
{
"id": "scene_opening",
"name": "Opening — Background Video with Title",
"duration": 6,
"bgColor": "#000000",
"layers": [
{
"id": "bg_video",
"type": "video",
"role": "background",
"source": "https://cdn.example.com/footage/city-timelapse.mp4",
"startTime": 0,
"duration": 6,
"zIndex": 0,
"position": { "x": 0, "y": 0 },
"size": { "width": 1920, "height": 1080 },
"transform": { "opacity": 0.6 },
"mute": true
},
{
"id": "bg_music",
"type": "audio",
"source": "https://cdn.example.com/audio/background-loop.mp3",
"startTime": 0,
"duration": 6,
"zIndex": 0,
"position": { "x": 0, "y": 0 },
"size": { "width": 0, "height": 0 },
"volume": 0.4
},
{
"id": "logo",
"type": "image",
"source": "https://cdn.example.com/brand/logo-white.png",
"startTime": 0.5,
"duration": 5,
"zIndex": 2,
"position": { "x": 80, "y": 60 },
"size": { "width": 200, "height": 60 }
},
{
"id": "headline",
"type": "text",
"text": "Welcome to ViralSync",
"startTime": 1,
"duration": 4,
"zIndex": 3,
"position": { "x": 360, "y": 420 },
"size": { "width": 1200, "height": 120 },
"fontSize": 80,
"fontFamily": "Inter, Arial, sans-serif",
"fontWeight": "bold",
"color": "#ffffff",
"textAlign": "center",
"transform": { "opacity": 0.95 }
}
]
},
{
"id": "scene_cta",
"name": "Call to Action",
"duration": 4,
"bgColor": "#0f172a",
"layers": [
{
"id": "cta_text",
"type": "text",
"text": "Start building at viralsync.io",
"startTime": 0,
"duration": 4,
"zIndex": 1,
"position": { "x": 360, "y": 460 },
"size": { "width": 1200, "height": 80 },
"fontSize": 52,
"color": "#00d4ff",
"textAlign": "center",
"fontWeight": "600"
}
]
}
]
}

Next Steps