Status: Draft v0.1 · July 2026 (kept as design history; the shipped behavior is documented in USAGE.md) Platform: macOS (local-only, no cloud services)
Editing a talking-head vlog takes far longer than shooting it. A 10-minute video built from a few takes costs an hour or more in a timeline editor, and almost all of that time goes into four mechanical chores:
- Picking the best take out of several attempts
- Cutting out filler words ("ehm", "uh") and awkward pauses
- Adding styled captions in sync with speech
- Dropping in the occasional picture overlay
None of these require creative timeline work. They require knowing what was said and when — which speech recognition already provides.
vlogcut is a local CLI that turns vlog editing into a text-editing task.
The core insight (the Descript model): once you have per-word timestamps for everything spoken, the video edit is a transcript edit. The user never scrubs a timeline. They delete lines of text they don't want, and the tool derives all cuts, caption timing, and overlay placement from the word-level transcript.
vlogcut ingest takes/*.mov # transcribe → edit.md + words.json
$EDITOR edit.md # keep/delete takes as lines of text
vlogcut render -o final.mp4 # auto-cut + captions + overlays
Everything runs on-device: whisper.cpp (Metal-accelerated) for transcription, ffmpeg for cutting and rendering. No uploads, no subscriptions.
Solo vlog creators comfortable with a terminal and a text editor. Initially a single user (the author); design decisions favor scriptability and speed over GUI discoverability.
The user films one or more takes with any camera/phone and drops the files into a folder. Multiple retakes of the same passage are expected and normal.
For each input file the tool:
- Extracts mono 16 kHz audio (
afconvert, built into macOS) - Transcribes with
whisper-cliusing a shared ggml-large-v3 model — found in the machine's existing model caches when possible (never download a duplicate model;vlogcut setupdownloads one only when none exists) - Writes two artifacts into the project:
words.json— every word with start/end timestamps and source fileedit.md— the human-facing edit file: one sentence per line, prefixed with a timestamp and take/file reference
The user opens edit.md in any editor and deletes the lines (or whole takes)
they don't want. What remains is the edit decision list.
Conventions:
- A deleted line = cut that span entirely
- Lines are re-orderable — the final video follows
edit.mdorder, enabling restructuring across takes - Optional spoken marker support: saying a keyword on camera (e.g. "keep that") auto-preselects the preceding take at ingest time
This selection step is the only manual step in the pipeline, deliberately: a human has to choose which take was best. The goal is that it takes ~2 minutes, not 20.
Within the kept ranges, the tool automatically:
- Removes filler words — a configurable blocklist ("ehm", "uh", "äh",
standalone "like"…) matched against
words.json, each removal using exact word boundaries - Tightens pauses — inter-word gaps longer than a threshold (default 0.4 s) are shortened to a natural beat (default 0.15 s)
- Pads cuts by a few frames on each side so edits don't sound clipped
- Merges all cuts into a single cut list and renders one ffmpeg pass
- Burns in captions and composites overlays (below)
Generated from the same word timestamps, so they stay perfectly synced after cutting. Two tiers:
| Tier | Tech | Look |
|---|---|---|
| v1 (default) | Styled .ass subtitles burned in by ffmpeg |
Custom font/colors, per-word pop-in, karaoke-style highlight |
| v2 (later) | Remotion (React/Node) render pass | CapCut/TikTok-level animated captions: springs, emphasis colors, emoji |
Caption style is defined in a preset file (captions.yaml): font, size,
colors, position, highlight behavior, max words per line.
Declared in a small manifest, overlays.yaml:
- at: "01:23" # timestamp in final-cut time, or an anchor word/phrase
img: assets/map.png
duration: 4
style: polaroid # preset: plain | polaroid | shadow-card
position: top-rightAnchoring to a word or phrase ("when I say 'Lisbon'") is preferred over raw
timestamps because it survives re-cutting. v1 renders overlays with ffmpeg's
overlay filter (static, with fade in/out); v2 moves them into Remotion for
animated entrances.
ingest: afconvert + whisper-cli →words.json+edit.mdrender: transcript-driven cutting, filler-word removal, pause tightening, ASS caption burn-in, static image overlays- Config:
vlogcut.yaml(thresholds, filler list),captions.yaml(style),overlays.yaml - Single ffmpeg render pass, H.264/AAC MP4 output
- Remotion caption/overlay renderer (animated, word-by-word)
- Spoken take-markers ("keep that") for automatic preselection
- Multi-resolution export (16:9 master + 9:16 vertical crop with re-positioned captions)
- No GUI / timeline editing — text is the interface
- No cloud transcription or rendering; everything stays local
- No music/b-roll editing beyond static picture overlays (for now)
- Not a general-purpose video editor — talking-head vlogs only
| Concern | Tool | Notes |
|---|---|---|
| Transcription | whisper-cli (brew whisper-cpp) |
Metal-accelerated; shared ggml-large-v3 model resolved from config/env/model caches (see README); JSON output with word timestamps |
| Audio extraction | afconvert |
Built into macOS, no dependency |
| Cutting / rendering / captions | ffmpeg |
Not yet installed — brew install ffmpeg; select/aselect filters or segment-concat; subtitles= filter for ASS burn-in |
| CLI | Python 3 | Already installed; stdlib + PyYAML; ~200–300 LOC for v1 |
| v2 captions/overlays | Remotion (Node) | Node already installed |
The single source of truth connecting transcription, editing, cutting, captions, and overlays:
{
"source": "takes/take2.mov",
"words": [
{"w": "welcome", "start": 3.42, "end": 3.81},
{"w": "ehm", "start": 3.95, "end": 4.20, "filler": true}
]
}All downstream timing (cut list, caption karaoke, overlay anchors) is computed
from this file, so cuts can be re-derived at any time by re-running render —
edits are non-destructive and reproducible.
- A 10-minute vlog from 3–4 takes goes from raw files to finished MP4 in
under 10 minutes of user time, of which the only manual step is editing
edit.md - Filler-word removal catches ≥ 90 % of "ehm"/"uh" instances without clipping adjacent words
- Captions never drift from speech (guaranteed by construction — same timestamps drive both)
- Re-running
renderafter tweakingedit.mdor a style preset is a one-command, no-thought operation
- Pause-tightening threshold: fixed default vs. adaptive to speaking rhythm?
- Should
edit.mdsupport inline overlay markers (e.g.on its own line) instead of / in addition tooverlays.yaml? - Vertical (9:16) export in v1 or defer entirely to v2?
- Crossfade vs. hard cut at tightened pauses — does a 2-frame audio crossfade sound better at scale?