Skip to main content

Scenes

Scenes split a project into a sequence of self-contained segments that play one after another. Each scene has its own local timeline (where 0 is the start of that scene), its own elements, and an optional transition into the next scene. Zvid renders every scene independently and then stitches them together, so scenes are the easiest way to build multi-part videos — intros, chapters, product shots, outros — without hand-computing global timestamps.

Add scenes with the project-level scenes array:

{
"name": "my-video",
"resolution": "hd",
"scenes": [
{ "id": "intro", "duration": 4, "visuals": [] },
{ "id": "main", "duration": -1, "visuals": [] },
{ "id": "outro", "duration": 3, "visuals": [] }
]
}

When scenes is present and non-empty, it drives the timeline. The project-level visuals and audios still render, but as a global overlay that spans the whole video (see Global overlay layer).

Why scenes?

Without scenes, every element shares one global timeline, so a clip that starts at second 12 needs enterBegin: 12, and inserting a new section means shifting every timestamp after it. With scenes:

  • Each scene's elements use times relative to that scene, so enterBegin: 0 is "the start of this scene."
  • Reordering, adding, or removing a scene never breaks the timing of the others.
  • Per-scene backgroundColor and auto-fitting duration remove most manual bookkeeping.
  • Scene-to-scene transitions reuse the same xfade effects as video transitions.

Scene Interface

interface Scene {
id?: string;
visuals?: Item[];
audios?: AudioItem[];
duration?: number;
transition?: XFadeEffect | null;
transitionId?: string | null;
transitionDuration?: number;
backgroundColor?: string;
}
PropertyTypeDefaultNotes
idstringscene-<index>Unique scene id. Auto-generated from the array index when omitted. Duplicate ids are rejected.
visualsItem[][]Visual elements on the scene-local timeline (0 = scene start).
audiosAudioItem[][]Audio tracks on the scene-local timeline.
durationnumber-1 (auto)Scene length in seconds. -1 (or omitted) auto-fits the scene to its content.
transitionXFadeEffect | nullnullEffect blending into the next scene. null is a hard cut.
transitionIdstring | nullnext sceneId of the next scene. Optional; scenes always play in array order (see below).
transitionDurationnumber0.5 (when transition set)Overlap length in seconds. Must be shorter than both adjacent scene durations.
backgroundColorstringproject backgroundColorPer-scene background. Falls back to the project background, then #ffffff.
Resolution and frame rate are project-wide

Scenes never set their own resolution, width, height, or frameRate. Every scene is rendered on the parent project's canvas so all intermediates match. Set those on the project.

Scene Duration

Each scene resolves to a concrete length before rendering:

  • A positive duration is used as-is.
  • duration: -1 (or omitted) auto-fits the scene: Zvid uses the latest end time among the scene's elements.
    • Videos and audios without an explicit end contribute their intrinsic (probed) length.
    • Images, text/HTML, SVG, and GIF elements stretch or loop to any length, so without an explicit exitEnd they do not constrain the scene.
    • If nothing constrains the scene, it falls back to a default of 10 seconds.
{
"id": "hero-clip",
"duration": -1,
"visuals": [
{
"type": "VIDEO",
"src": "https://videos.pexels.com/video-files/1409899/1409899-sd_640_360_25fps.mp4",
"resize": "cover",
"position": "center-center",
"volume": 0
}
]
}

Here the scene auto-fits to the clip's length. To pin an auto-fit scene to a text element, give that element an explicit exitEnd.

Transitions Between Scenes

Scenes always play in array order. A transition blends the current scene into the one that follows it:

{
"scenes": [
{
"id": "intro",
"duration": 4,
"transition": "fade",
"transitionDuration": 0.8,
"visuals": []
},
{ "id": "main", "duration": 5, "visuals": [] }
]
}

Key rules:

  • transition is the xfade effect into the next scene. null (the default) is a hard cut.
  • A transition overlaps the two scenes: the next scene starts transitionDuration seconds before the current one ends, exactly like video transitions.
  • transitionDuration defaults to 0.5 and must be shorter than both adjacent scene durations.
  • transitionId is optional. Because scenes play in array order, you may omit it. If you do set it, it must match the next scene's id (or be null / "none"); pointing it anywhere else disables the transition and falls back to a hard cut.
  • A transition on the last scene is ignored (there is nothing to blend into).

Global overlay layer

Project-level visuals and audios still apply when scenes are used. They are composited on top of the stitched scenes and span the entire video — ideal for a persistent watermark, logo, or background music bed:

{
"name": "branded-video",
"resolution": "hd",
"scenes": [
{ "id": "a", "duration": 3, "visuals": [] },
{ "id": "b", "duration": 3, "visuals": [] }
],
"visuals": [
{
"type": "TEXT",
"html": "<div class=\"wm\">© zvid</div>",
"position": "bottom-right",
"opacity": 0.6,
"customCode": {
"css": ".wm { color: #ffffff; font-family: Montserrat; font-size: 32px; }"
}
}
],
"audios": [
{
"src": "https://cdn.pixabay.com/audio/2026/02/24/audio_3f375fdf97.mp3",
"volume": 0.2
}
]
}

Scene elements always render below every global visual, so overlays stay on top regardless of track values inside scenes.

Total Duration

The video length is the sum of all scene durations minus their transition overlaps. The project duration field interacts with that total:

  • If duration is omitted, the video is exactly the scenes' total length.
  • If duration is shorter than the scenes' total, it is extended to fit the scenes (a warning is logged).
  • If duration is longer than the scenes' total, the video is extended to duration; the global overlay layer keeps playing over the final frame.

Complete Example

Three scenes, two transitions, a global watermark and music bed — the payload below, rendered by Zvid

A three-scene promo: a title built with an HTML element, a background video clip, and an outro — with cross-scene transitions and a global watermark.

{
"name": "scenes-demo",
"resolution": "hd",
"frameRate": 30,
"backgroundColor": "#000000",
"outputFormat": "mp4",
"scenes": [
{
"id": "intro",
"duration": 4,
"backgroundColor": "#1a1a2e",
"transition": "fade",
"transitionId": "clip",
"transitionDuration": 0.8,
"visuals": [
{
"type": "TEXT",
"html": "<div class=\"title\">Welcome</div>",
"position": "center-center",
"enterBegin": 0.5,
"exitEnd": 4,
"customCode": {
"css": ".title { color: #ffffff; font-family: Montserrat; font-size: 96px; font-weight: 800; } .title { animation: rise 0.8s ease-out both; } @keyframes rise { from { opacity: 0; transform: translateY(40px); } to { opacity: 1; transform: translateY(0); } }"
}
}
]
},
{
"id": "clip",
"duration": -1,
"transition": "slideleft",
"transitionId": "outro",
"transitionDuration": 0.6,
"visuals": [
{
"type": "VIDEO",
"src": "https://www.pexels.com/download/video/4927963/",
"resize": "cover",
"position": "center-center",
"anchor": "center-center",
"volume": 0,
"videoBegin": 0,
"videoEnd": 5
}
]
},
{
"id": "outro",
"duration": 3,
"backgroundColor": "#16213e",
"visuals": [
{
"type": "TEXT",
"html": "<div class=\"thanks\">Thanks for watching</div>",
"position": "center-center",
"customCode": {
"css": ".thanks { color: #f3efa2; font-family: Montserrat; font-size: 72px; font-weight: 800; }"
}
}
]
}
],
"visuals": [
{
"type": "TEXT",
"text": "© zvid",
"position": "bottom-right",
"track": 5,
"opacity": 0.6,
"style": {
"fontFamily": "Montserrat",
"fontSize": "32px",
"color": "#ffffff"
}
}
],
"audios": [
{
"src": "https://cdn.pixabay.com/audio/2026/02/24/audio_3f375fdf97.mp3",
"volume": 0.2
}
]
}

Best Practices

  • Keep timings scene-local: prefer enterBegin: 0 inside a scene over large global offsets.
  • Use duration: -1 for video/audio-driven scenes and an explicit duration for text-only scenes.
  • Reach for scenes when sections have distinct backgrounds or you want clean cross-section transitions; reach for a single visuals timeline when elements overlap continuously.
  • Put persistent branding (logo, watermark, music) on the project level so it spans every scene.
  • Keep transitionDuration well under the shorter of the two scenes it joins.