A command-line video editor. Edits are JSON documents; titles and graphics are HTML and CSS, drawn without a browser.
One binary for Linux (x64, arm64), macOS (Apple silicon) and Windows (x64). The codecs come from FFmpeg's libraries; the planner, compositor and layout engine are written in Rust. MIT licensed.
Install
curl -fsSL https://raw.githubusercontent.com/geneva-render/geneva/main/scripts/install.sh | sh
irm https://raw.githubusercontent.com/geneva-render/geneva/main/scripts/install.ps1 | iex
Or download an archive from Releases. H.264 is encoded with the bundled OpenH264, or with x264 when it is installed on the system.
Everyday commands
geneva trim match.mp4 -o goal.mp4 --from 41:10 --to 41:40 geneva concat day1.mp4 day2.mp4 -o trip.mp4 --crossfade 1s geneva convert talk.mov -o talk.mp4 --for web geneva subtitles talk.mp4 -o talk-subbed.mp4 --burn talk.srt geneva probe talk.mp4
Each command is turned into a JSON document and rendered. --show-timeline prints it. All commands: docs/cli.md.
A document
A name card over ten seconds of footage. The card is an HTML file; it plays the same in a browser.
<style>
@keyframes slide-in { from { translate: -100% } to { translate: 0 } }
@keyframes fade-out { from { opacity: 1 } to { opacity: 0 } }
.card {
animation: slide-in 0.5s ease-out, fade-out 0.3s 3.7s;
position: absolute; left: 4.4%; top: 7.5%; width: 33%;
display: flex; flex-direction: column; gap: 6px; padding: 14px 24px;
background: #0a0f14cc; border-left: 5px solid #c4362f;
}
.card h1 { margin: 0; font: 600 29px Liberation Sans; color: #f2f5f7 }
.card p { margin: 0; font: 500 13px Liberation Sans; color: #94a6b6 }
</style>
<div class="card">
<h1>Dragon CRS-17</h1>
<p>BERTHING AT THE ISS · NASA</p>
</div>
{
"geneva": "1.0",
"output": { "width": 1280, "height": 720, "fps": 30 },
"assets": { "iss": { "src": "iss.mp4" }, "card": { "src": "card.html" } },
"layers": [
{ "id": "footage", "clips": [ { "source": { "kind": "video", "asset": "iss" } } ] },
{ "id": "card", "clips": [ { "source": { "kind": "html", "asset": "card" },
"start": "2s", "duration": "4s" } ] }
]
}
$ geneva render edit.json -o dragon.mp4 note[N600]: smart cut: 165 of 300 frames copied from the source, 135 encoded in 1 run around the cuts and overlays note[N600]: H.264 runs encoded with the system's x264 (build 164) at CRF 18 wrote dragon.mp4 (300 frames, 10s of video)
Frames with nothing drawn on them are copied from the source when it is H.264 and x264 is installed, and otherwise go from decoder to encoder without passing through the compositor. Errors are reported before rendering, with a code and the path in the document: error[E200]: unknown asset "crad".
Motion graphics
Both of these are one HTML file and a short JSON document. No footage in the first; the second cuts to footage at the end.
What the markup supports
Flexbox and block layout, absolute positioning, gradients, box-shadow, filter: blur(), clip-path: polygon(), mix-blend-mode, background-clip: text, web fonts shipped as assets, and CSS @keyframes played as written.
Not supported: CSS grid, floats, transitions, static transform (transforms come from animations), and JavaScript. An unsupported declaration is reported by name and skipped. The full list is in docs/timeline.md.
Speed
Seven jobs, rendered by geneva, by Playwright screenshotting each frame for ffmpeg, and by Remotion. Time to render, median of three rounds. One machine: 4 vCPUs of an Intel Xeon at 2.1 GHz, 16 GB, no GPU. All three encode x264 CRF 23, preset medium.
| Job | geneva | Playwright + ffmpeg | Remotion |
|---|---|---|---|
| Social clip, 60 s, 1080x1920 | 60.8 s | 140.6 s | 270.3 s |
| Broadcast package, 3 min | 52.2 s | 244.2 s | 324.3 s |
| Static captions, 4 min | 95.6 s | 300.4 s | 444.7 s |
| Dynamic captions, 90 s | 58.1 s | 190.9 s | 164.7 s |
| Opening, 13 s | 10.0 s | 64.2 s | 19.1 s |
| Intro, 14 s | 30.4 s | 145.0 s | 63.4 s |
| Kinetic typography, 16 s | 14.2 s | 56.2 s | 30.2 s |
geneva with its defaults, which copy frames the edit leaves alone. With frame copying off and the encoder pinned to the others' settings, the broadcast package takes 99.4 s and the static captions 140.7 s. Method, caveats and scripts: docs/benchmarks.md.
For scripts and agents
geneva guide prints the manual, geneva explain <code> explains any diagnostic, and --format json works on every command. The document format has a published JSON schema. See docs/agents.md.
Status
- Version 1.0. The document format is
"1.0"; 1.x adds only optional fields. - No GUI and no hosted service.
- If you are using it or want to, tell me what you are making. Issues and discussions are on GitHub.