VEDL Language Reference

The complete reference for .vedl — the small, human-readable video-edit language behind 5AM's AI highlight reels and Clip Maker. Cuts, transitions, titles, overlays, color, a ducked music bed, and loudness — one op per line.

.vedl is the small, line-based video-edit language at the heart of 5AM's AI editing tools. When 5am media highlight plans a reel or Clip Maker cuts a short, the AI's plan is written as a .vedl file: a script you can read, edit by hand, and re-render deterministically — same script, same output, every time, no second AI call.

sh
5am media edit render talk.vedl --output cut.mp4

A complete script (every line optional except source):

source "talk.mp4"
cut 01:12 01:48.5   # the origin story — sets up everything that follows
cut 04:03 04:41     # the key insight, stated in one clean take
transition xfade 0.5
text "The Origin Story" atsrc 01:12 for 3 pos=bottom size=56
overlay "logo.png" pos=top-right scale=0.2 opacity=0.8
grade exposure=0.3 saturation=1.15
grade hsl reds hue=5 sat=10
music "bed.mp3" style=podcast
normalize target=-16
fade in 0.5
fade out 1

File format

  • One op per line. Keywords are case-insensitive; blank lines are ignored.
  • Comments start with # — at the start of a line, or after whitespace (so a color value like color=#ffee00 is safe). The AI writes its editorial reasoning as trailing comments on each cut, and they round-trip.
  • Strings are double-quoted, with \" and \\ escapes. Relative media paths resolve against the .vedl file's own directory.
  • TIME values accept SS[.mmm], MM:SS[.mmm], or HH:MM:SS[.mmm]90, 1:30, and 0:01:30 all mean ninety seconds.
  • DUR values are seconds: 0.5, 3, 3s.
  • Everything is UTF-8. One deliberate exception: a straight apostrophe (') inside text is rejected with a hint to use the typographic instead — FFmpeg's text renderer cannot reliably consume the straight one, and a script that renders must also re-parse.

Op reference

OpFormNotes
sourcesource "clip.mp4"Exactly one per script. The video everything else refers to.
cutcut START END # whyKeep [START, END). Cuts must be chronological and non-overlapping; a script uses cut lines or delete lines, never both. Ranges shorter than 50 ms are dropped with a warning.
deletedelete START ENDRemove the range and keep everything else (the complement of cut). Order-independent; overlapping deletes merge.
prepend / appendprepend "intro.mp4"Place a whole clip before/after the edited timeline. At most one of each.
transitiontransition cut|xfade|fadeblack|wipe [DUR]The join used between all adjacent segments. Duration is clamped to 45% of the shortest segment so a long crossfade can't swallow a short cut. No transition line means hard cuts.
texttext "S" at|atsrc TIME for DUR [pos=…] [size=…] [color=…]A timed title. at is output-timeline time; atsrc is source time (see Two clocks). pos is one of top, bottom, center, or the four corners; size is px on a 1080-wide canvas and scales with width; color is a named color or #hex. Long titles word-wrap at render time.
overlayoverlay "img.png" [from|fromsrc TIME] [for DUR] [pos=…] [scale=…] [opacity=…]An image layer (logo, lower third). Omitting for runs it to the end. scale is a fraction of canvas width.
gradegrade [exposure=±3] [brightness=±1] [contrast=0..3] [saturation=0..3] [gamma=0.1..3]Global color. Multipliers use 1 = identity; exposure is in stops.
grade hslgrade hsl reds|yellows|greens|cyans|blues|magentas [hue=±180] [sat=±100] [lum=±100]Per-band color, one line per band — warm the reds without touching the sky. Needs FFmpeg 5.0+; older builds skip these lines with a warning.
musicmusic "bed.mp3" [style=podcast|documentary|promo|ambient] [level=±dB] [duck=dB]A looped, measured, voice-ducked music bed — the same broadcast-style pipeline as 5am media mix. At most one.
normalizenormalize [target=LUFS] [peak=dBTP]Measured loudness staging to the target plus a true-peak limiter. Defaults: −16 LUFS, −1.5 dBTP.
fadefade in DUR / fade out DURVideo + audio fades at the edges of the output.

Defaults when options are omitted: text uses pos=bottom size=48 color=white; overlay uses pos=top-right scale=0.2 opacity=1 and runs to the end; bare normalize means −16 LUFS / −1.5 dBTP; music without options uses the podcast preset; a script with no cut/delete lines keeps the whole source. The output canvas and frame rate default to the source's own; override with --aspect, --width/--height on edit render.

Two clocks: at vs atsrc

An edit has two timelines, and VEDL is explicit about which one you mean:

  • at / from — seconds on the output timeline: what you see in the rendered file.
  • atsrc / fromsrc — seconds in the source video: what a transcript refers to.

The AI always writes atsrc, because it reasons in transcript time. The renderer remaps source times through the kept segments — correctly across removed footage and transition overlaps — and if an anchor falls inside a span you cut away, it snaps to the nearest kept moment with a warning rather than failing. Hand-edit whichever clock is more natural for the change you're making.

The audio pipeline

music and normalize aren't effects slapped on at the end — they're the measured, staged pipeline from automatic music ducking:

  1. The edit's joined voice track is measured for integrated loudness.
  2. The music file is measured too.
  3. The style preset (or your level=/duck= overrides) computes the staging: voice at the target loudness, bed at its level underneath, a voice-keyed ducker with the mid band (where speech lives) ducked deeper — the EQ pocket.
  4. A true-peak limiter holds the ceiling.

normalize alone is the same staging without the bed. Either way the output arrives sounding mixed, at broadcast loudness, not assembled.

Where .vedl files come from

  • 5am media highlight writes one next to every reel it renders — along with the transcript and the raw model response — so a cut you disagree with is a two-number edit, not a re-roll.
  • 5am media clips and Clip Maker write one per clip. In Clip Maker's Script tab you edit it right in the browser: save, and the clip re-renders in place, with parse errors shown against their line numbers.
  • 5am media edit generate turns any transcript into one, steered by --brief and --target-duration.
  • You — a .vedl is a text file. Write one from scratch and render it; a hand-written script needs no account and no API key at all.

And where they go: 5am media edit export turns a script into a Video Editor project — cuts, crossfades, titles, and compatible grading — for frame-level polish in the browser. (Ducking, fades, and gamma/HSL aren't representable on the web timeline; they stay CLI-render features and are carried along on the project so nothing is lost.)

Gotchas worth knowing

  • Straight apostrophes in titles are rejected with a hint — use . The AI repairs this automatically in generated scripts.
  • Title size is width-relative: size=48 means 48 px on a 1080-px-wide canvas, so a title spans the same fraction of the line at every aspect ratio. Long titles wrap to at most three lines at render time (the script itself stays single-line); a single word too wide to fit shrinks the font instead.
  • Titles handle every script when ffmpeg has libass. On a libass build (any full ffmpeg), titles burn through the same engine as subtitles: right-to-left scripts, CJK, and per-script font fallback all just work, with no --font needed. Only on a libass-less build do titles fall back to drawtext, which renders through a single font file (--font, or a system font) and needs one that covers the title's script — and can't reorder right-to-left text.
  • Duration: N/A in a probe error means a broken container — remux the file first.
  • Rendering needs a local FFmpeg (4.4+; grade hsl wants 5.0+, and the music bed's ducker is a hard requirement when a music line is present). Free/unauthenticated renders carry a small "Powered by 5AM" watermark; 5am login (free) removes it.

See also