the first cut is always clumsy

Video editing, compiled.

Clumsy turns a prompt into a timeline, then a timeline into an MP4. It arranges footage you already own — no diffusion, no generated pixels, no black box. The plan is JSON you can read, diff, and re-render.

Get started Read the spec MIT · ffmpeg 6 · Coming soon
timeline_compiler Coming soon
INPUT PROMPT "dawn city..." FOOTAGE INDEX 142 shots BEAT GRID 118 BPM CLUMSY SOLVER TIMELINE IR v1.0 ZERO-DIFFUSION out.mp4 V1 A1 shot_01 shot_04 (beat snap) shot_09 shot_12
DAWN_IN_AN_EMPTY_CITY 00:00:32:00 · 30 FPS
V1
A1
00:00:12:00

The rule everything rests on

Coming soon

The model never writes ffmpeg. It emits a declarative timeline, and a compiler turns that into a filter graph. Generated shell commands can't be tested, diffed, cached, or re-rendered at another resolution. A JSON plan can be all four.

InputA prompt and your asset library
Timeline IRValidated, repairable, reproducible
OutputOne ffmpeg pass, one encode
00:00:24:00

Five stages

Coming soon

Two run once per asset. Three run once per video. The index is the seam between them.

Once per asset
01 IngestDETERMINISTIC Shot-splits every file into atomic clips, normalizes to a fixed frame rate and mezzanine codec, then captions and embeds each shot. Cached forever.
02 IndexDETERMINISTIC Vectors, motion scores, shot scale, subject boxes, palettes, licences. For music: BPM, key, and a beat grid the cutter snaps to.
Once per video
03 PlanMODEL Writes a beat sheet first — order, roles, intent — then binds each slot to a real shot by search and rerank. The only stage a model touches.
04 SolveDETERMINISTIC Quantizes to frame boundaries, closes gaps, recomputes transition offsets, enforces reuse windows and shot variation, snaps every cut to the beat.
05 RenderDETERMINISTIC Compiles the timeline to a single filter graph. One invocation, one encode, correct colour tags. Preview and final share the code path.
00:00:38:00

Three things you'd otherwise build yourself

Coming soon

Most of the difficulty in automated editing isn't stitching clips together. It's these.

source.mp4 · 04:12 6 shots · indexed separately retrieved

Shots, not files

Nothing retrieves well at file granularity. Ingest cuts every source at its scene boundaries, so the unit of search is a single shot with its own caption and embedding.

shot_0412 · source time 3.20 6.10 timeline v0 · 0.00 → 2.90

Two clocks per clip

Every clip stores where it came from and where it lands, separately. Nothing is positional, so clips render in parallel, cache independently, and two plans diff cleanly.

bed.wav · 118 bpm cuts land on beats ± 120 ms

Cuts land on beats

The single largest gain in perceived quality per line of code. Ordinary shot choices cut on the beat read as deliberate; excellent ones cut off it read as accidental.

00:00:52:00

The plan is the product

Coming soon

The same seed always produces the same file. Read it, edit it by hand, commit it next to your code.

// clumsy plan "dawn in an empty city" --dur 32 --ar 16:9
{
  "schema_version": "1.0",
  "seed": 8412,
  "canvas": { "w": 1920, "h": 1080, "fps": 30 },
  "tracks": [{
    "id": "v0",
    "clips": [{
      "asset_id": "shot_0412",
      "src_in":  3.200,   // where in the source
      "src_out": 6.100,
      "t_start": 0.000,   // where on the timeline
      "t_end":   2.900,
      "transition_in": { "kind": "xfade", "dur": 0.5 }
    }]
  }]
}
00:01:04:00

What it isn't

Coming soon

This is a crowded category. Here's the honest map, so you can tell quickly whether Clumsy is the wrong tool for you.

 Footage agentsRender APIsClumsy
InputWhat you upload for one projectJSON you write by handA prompt and a library you keep
UnderstandingSpeech transcriptsNone — you bring the planVisual embeddings and captions
Silent footageStruggles without dialogueNot applicableWorks the same either way
Generated pixelsUsually yesNoNever — by design
Same input, same fileNoYesYes, seeded and versioned
00:01:18:00

Start with a rough cut

Coming soon

Point it at a folder. Ingest runs once and caches. After that, a render is a single command.

$ clumsy ingest ./footage --fps 30 --canvas 1920x1080
$ clumsy render "dawn in an empty city" --dur 32 --music ./bed.wav
out/dawn_8412.mp4 · plan saved to out/dawn_8412.json