Understanding the EDL JSON Format: How to Structure an Edit Decision List for video-use

The EDL JSON format in video-use is a structured JSON document that defines video sources, cut ranges, color grading, overlays, and subtitles to drive the entire automated rendering pipeline.

The browser-use/video-use repository treats the Edit Decision List (EDL) as the single source of truth that powers every stage of post-production, from segment extraction and color grading to overlay compositing and subtitle burning. Mastering the EDL JSON format is essential for anyone automating video workflows with this tool, as the schema directly dictates how helpers/render.py constructs the final output.

Core Structure of the EDL JSON Format

A valid EDL file is a JSON object with seven top-level fields. The specification is documented in SKILL.md (lines 268-287) and consumed by the render pipeline in helpers/render.py.

Root-Level Fields

The EDL requires these mandatory and optional fields:

  • version – Integer schema version (currently 1).
  • sources – Object mapping short identifiers (e.g., "C0103") to absolute or relative video file paths.
  • ranges – Ordered array of cut objects defining which segments to extract from which sources.
  • grade – Color grading instruction: either a preset name, a raw ffmpeg filter string, or "auto" to trigger per-segment analysis.
  • overlays – Optional array of animation clips to composite on top of the final video.
  • subtitles – Optional path to an SRT file burned in after overlays.
  • total_duration_s – Float representing the computed total length of the final video in seconds.

The ranges Array

Each object in ranges defines a single cut with precise timing and metadata:

{
  "source": "C0103",
  "start": 2.42,
  "end": 6.85,
  "beat": "HOOK",
  "quote": "…",
  "reason": "Cleanest delivery, stops before slip at 38.46"
}

The source value must match a key in the sources object. Timestamps are in seconds and support floating-point precision for frame-accurate cuts.

How the Render Pipeline Consumes the EDL

The render.py module transforms the ELD JSON into a series of ffmpeg commands through four distinct stages.

Grade Resolution and Filter Conversion

First, resolve_grade_filter (lines 66-85 in helpers/render.py) interprets the grade field:

  • "auto" – Returns the sentinel "__AUTO__" to trigger auto_grade_for_clip during segment extraction.
  • Preset name – Looks up the corresponding ffmpeg filter string via grade.get_preset.
  • Raw filter – Passes the string directly to ffmpeg unchanged.

Per-Segment Extraction with Audio Fades

For each entry in ranges, extract_all_segments builds a command that:

  • Seeks to the start timestamp using -ss for fast, accurate seeking.
  • Scales output to 1080p (or 720p for draft previews) while preserving portrait orientation via is_portrait_source (lines 73-78).
  • Applies HDR tone-mapping if the source uses PQ/HLG via TONEMAP_CHAIN (lines 95-117).
  • Injects the resolved color grade filter.
  • Adds a 30ms audio fade-in/out using afade to eliminate clicks at cut points (lines 88-90).

Lossless Concatenation

After extraction, concat_segments (lines 67-82) uses the ffmpeg concat demuxer to join all MP4 segments with stream copy (-c copy), avoiding generational loss between cuts.

Overlay and Subtitle Composition

If overlays or subtitles are present, the pipeline builds a final filter graph that:

  • Inserts each overlay clip at its specified start_in_output time (PTS shift).
  • Applies the subtitles filter last, using the style constants defined in SUB_FORCE_STYLE (lines 51-56) to ensure readability on social platforms.
  • Writes the final output with +faststart for web streaming optimization.

Critical Implementation Details

Several hardcoded behaviors in helpers/render.py affect how you should structure your EDL:

  • HDR Handling – Sources detected as HDR via is_hdr_source automatically receive tone-mapping to prevent oversaturation on SDR displays.
  • Portrait Orientation – Vertical videos are identified via is_portrait_source and scaled accordingly to maintain aspect ratio.
  • Auto-Grade Logic – When grade is "auto", the pipeline executes auto_grade_for_clip (lines 34-38) to analyze histogram and contrast per segment.
  • Subtitle Priority – The SRT specified in subtitles is always burned in last, appearing over both video and overlays.
  • Animation Overlays – Each overlay object requires file, start_in_output, and duration fields to position the animation correctly on the timeline.

Code Examples

Building an EDL Programmatically

import json
import pathlib

edl = {
    "version": 1,
    "sources": {
        "C0103": "/abs/path/C0103.MP4",
        "C0108": "/abs/path/C0108.MP4",
    },
    "ranges": [
        {
            "source": "C0103",
            "start": 2.42,
            "end": 6.85,
            "beat": "HOOK",
            "quote": "…",
            "reason": "Cleanest delivery, stops before slip at 38.46."
        },
        {
            "source": "C0108",
            "start": 14.30,
            "end": 28.90,
            "beat": "SOLUTION",
            "quote": "…",
            "reason": "Only take without the false start."
        },
    ],
    "grade": "warm_cinematic",
    "overlays": [
        {"file": "edit/animations/slot_1/render.mp4", "start_in_output": 0.0, "duration": 5.0}
    ],
    "subtitles": "edit/master.srt",
    "total_duration_s": 87.4
}

path = pathlib.Path("edit/edl.json")
path.write_text(json.dumps(edl, indent=2))

Rendering from the Command Line

python helpers/render.py edit/edl.json -o final.mp4 --build-subtitles

Loading and Inspecting an EDL

with open("edit/edl.json") as f:
    edl = json.load(f)

first_cut = edl["ranges"][0]
print(f"First cut: {first_cut['source']} from {first_cut['start']}s to {first_cut['end']}s")

Summary

  • The EDL JSON format is the declarative blueprint that video-use uses to drive automated video editing.
  • Key fields include sources, ranges, grade, and optional overlays/subtitles.
  • The render pipeline in helpers/render.py resolves grades, extracts segments with 30ms audio fades, concatenates losslessly, and composites overlays.
  • HDR sources are automatically tone-mapped, and portrait videos are preserved during scaling.
  • Subtitles are burned last in the filter chain, ensuring they appear above all other visual elements.

Frequently Asked Questions

What values are valid for the grade field in an EDL?

The grade field accepts three types of values: a preset name (like "warm_cinematic") that maps to a predefined ffmpeg filter, a raw ffmpeg filter string for custom color correction, or the string "auto" to trigger per-segment histogram analysis via auto_grade_for_clip in the render pipeline.

How does video-use handle portrait-oriented source videos?

When extracting segments, the pipeline checks is_portrait_source (lines 73-78 in helpers/render.py) and adjusts the scale filter to maintain the vertical orientation, ensuring the output matches the original aspect ratio rather than forcing a landscape crop.

Can I use relative paths in the sources object?

Yes. The sources mapping accepts both absolute paths and relative paths. The render pipeline resolves these paths relative to the working directory where render.py is executed, though absolute paths are recommended for CI/CD environments to avoid ambiguity.

Why is there a 30-millisecond audio fade applied to every segment?

The 30ms fade-in and fade-out (implemented via afade on lines 88-90 of helpers/render.py) prevents audible clicks and pops that occur when cutting audio at non-zero crossings, ensuring clean transitions between concatenated clips without re-encoding the audio stream.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →