FableCut: The Project File Is the Interface
Ronak Parmar open-sourced FableCut, a Premiere-style video editor that runs in the browser. The key design decision: the entire timeline lives in a single JSON document (project.json). This means any tool that can write JSON—Claude Code via MCP, a Python script, jq, or a human with a text editor—can edit video.
Why the Project File as Interface?
Most AI video tools hide the edit behind an API: addClip(), applyFilter(). The tool owns the state. If you want a human to touch the result, you need a collaboration layer. FableCut flips that. The editor UI reads project.json. The export renders it. Writing to the file IS creating the video.
Example clip definition:
{
"id": "c_title",
"kind": "text",
"track": "V3",
"start": 0,
"duration": 2.2,
"props": {
"text": "HANDMADE",
"font": "Bebas Neue",
"glow": 45,
"textAnim": "letter-pop"
}
}
No API call creates that glowing kinetic caption. Writing it into the file does.
SSE as a Doorbell, Not a Data Channel
The server uses fs.watch on project.json, debounces 150ms, and pushes a literal string change to the browser via SSE. No payload. The browser re-fetches the project and re-renders. The mechanism is about 15 lines on a bare node:http server.
Why not WebSockets? Data only flows one way. Everything that writes (UI, agent, shell script) goes through REST or the filesystem. The browser only needs to hear "something changed, go look." An event with no payload can't arrive out of order, and a missed event costs nothing because the next fetch has the latest state.
Concurrency: One Integer
The file carries an integer revision. Every write must bump it. If a write arrives with a revision not newer than what's on disk, the server rejects with 409. This is the entire concurrency model. If you drag a clip in the UI while an agent is mid-edit, the agent's stale write bounces, it re-reads, re-applies its change on top of yours, and writes again. No operational transforms, no CRDTs, no lock files. It works because edits are coarse (whole document) and rare (human speed).
Frame-Accurate CSS Animations
FableCut has animated SVG overlays (lower thirds, confetti, sparkles) as plain .svg files animated with CSS @keyframes. Problem: a video compositor needs to render the animation state at an exact time, and export isn't realtime. Solution: pause every animation and drive time by hand. The compositor sets animation-delay: calc(var(--d, 0s) - t) where t is the clip's local time. A negative delay means "you started in the past," so a paused animation with delay -1.3s displays exactly its 1.3 second frame. Deterministic, scrubbable, identical in preview and export. The only rule for SVG authors: never hardcode animation-delay; use the --d custom property for staggering.
"You Can Just Give Claude Access to ffmpeg"
Someone on HN pointed out that for trims, concats, and batch transcodes, ffmpeg works fine. The difference is the creative loop. ffmpeg is write-only: the agent builds a filter graph, renders for minutes, and cannot see what it made. In FableCut, an edit is a JSON diff, the open browser updates in 150ms, and the timeline stays editable. It's not a replacement for ffmpeg—the export pipeline renders frames in the browser and pipes them to ffmpeg for encoding. FableCut is the state and preview layer between the agent and ffmpeg.
Honest Limitations
The compositor is the browser, so export needs a browser open (headless export not there yet). It's Chromium-first. An AI can misjudge a cut just fine, which is why the human-in-the-loop part matters more than the AI part: the agent does the labor, you do the taste.
Next Steps
Clone the repo: https://github.com/ronak-create/FableCut. It's MIT, zero dependencies, one node server.js. Try editing project.json manually or via an agent. Build something weird with it.




