fablecut_status
FableCut video editor: ensure the editor web server is running (auto-starts it), and get the editor URL, project summary and media library. Call this first in a session.
Takes no parameters.

io.github.ronak-createPublished by GitHub account ronak-createv1.18.0Updated Nov 3, 2026
Zero-dependency browser video editor AI agents drive via a JSON timeline over MCP; ffmpeg export.
FableCut is a local browser-based video editor whose JSON timeline an AI assistant can read, patch, analyze and export over MCP.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Follow the launch instructions in the repository.
A browser video editor that AI agents can drive.
[ronak-create%2FFableCut | Trendshift]
[Hacker News — front page] [DEV — Top 7 of the week] [Official MCP registry] [Mentioned in Awesome MCP Servers] [Glama score] [Glama — #18 Best Browser Automation MCP Servers] [Docs] [Discord]
English · 简体中文 · 日本語 · Español · Português (BR)
[Watch the FableCut Studio demo: an agent cuts a reel live (58 s)]
FableCut is a Premiere-style non-linear video editor that runs entirely in your browser — and exposes its whole timeline as one JSON document. Edit it by hand, from the UI, or let an AI agent (Claude Code, Claude Desktop, or anything that speaks MCP/REST) cut your video for you while you watch the timeline update live.
Zero npm dependencies. One node server.js. That's it.
Sidrune AI — One API for GPT, Claude, and other leading AI models. Sign up and get $3 in API credit.
Most "AI video" tools hide the edit behind an API. FableCut flips that: the
project file is the interface. project.json describes media, clips,
tracks, effects, keyframes and transitions — any process that can write JSON
can edit video, and the open browser UI hot-reloads within ~150 ms via
server-sent events. A human and an agent can work on the same timeline at the
same time.
Taking back what the agent did. Every agent edit is one undo step of its
own: Ctrl+Z takes back the agent's last change first (and says so), then
goes on to yours, so the two never get mixed. For bigger rollbacks there are
Versions: one is kept when an agent starts editing (again at most every
10 minutes while it works), before it rewrites the whole project, before every
big operation (cutting silences, snapping to the beat, reframing), and every
10 minutes while you edit. Restore one from the Versions panel, or ask the agent
(fablecut_versions), and compare any version with now first.
Editing
localStorage. Enable Link timeline and Project bin selection so picking a
timeline clip highlights its media in Project, and clicking a Project item
selects every timeline clip that uses it (off by default).fablecut_patch_project refuses to edit locked clips unless the
op says force: true.
fablecut_auto_duck.setFx patch op.setFxKeys.fablecut_denoise.fablecut_reframe.fablecut_highlights.fablecut_silence.fablecut_beats.fablecut_transcribe to read an interview, find a line and cut it.fablecut_captions.#tag; filter by favorites, used / unused, kind, tag or collection; sort by any detail or by times used; a list view with metadata columns; favorites, tags and collections; Find timeline instances and Reveal in project; offline files flagged with a "Media offline" slate, Relink… (finds moved files by name and size) and Replace file…project.json is recovered at startup./media/ (same-origin after import). Remote SVG is refused. Agents use
fablecut_import_media with an https:// path. The URL is not kept as
media.src — that would taint the canvas and break export.exportFrame in project.json). Preview dims the overscan; drag the
Export frame handle to reframe (e.g. 16:9 canvas → 9:16 export). Fast export
crops to the frame; WebCodecs and Realtime export are disabled while a frame is set01:15:00,
1500, +30, 12.5; the IN / OUT readouts take typed times toocurrent / sequence duration; when markers are set, IN, marked duration, and OUT stack on the right. Export has a Range dropdown (Entire timeline / IN–OUT; defaults to IN–OUT when markers exist) so you can keep markers for split/trim and still export the full sequence. Enabling Limit constrains playback to the marked range and maps Home / End to the IN and OUT positions rather than the full timeline. t splits clips at the markers; ⇧t trims clips to the work (between marker in and marker out) area.fablecut_patch_project ops, on the same code.Look
setGrade patch op and read the result as numbers
with fablecut_scopes (levels, clipping, colour cast)setMask patch op and measure with fablecut_scopessetShape and setParent patch opssetMotionPath and setTextPath
patch opsaddComp, inComp and precompose patch opsapplyPreset, addTemplate and setTemplate patch opsfablecut_tracksetMatteMotion
speed and the engine time-remaps video and the
export audio mix (the fast-into-slow-mo reel move)Text
library/fonts/), and any
Google Font by name — loaded automaticallyboxW / boxH); further corner drags resize it (opposite
corner stays fixed; Ctrl/Cmd resizes from center; Shift
locks aspect). Inside a box, text wraps at the fixed font size by default;
enable Scale to fit to shrink the font so the whole block fits. V-align
(top / middle / bottom) places the text block vertically in the box. Set Box
W/H to 0 to return to hug-content sizing.Animated SVG clips
svg clip kind: CSS-@keyframes-animated SVGs render
frame-accurately in preview and export (the compositor freezes the
animation at any time). Agents can author their own vector overlays —
lower-thirds, confetti, sparkles — as plain .svg files. Starters included.Remake a reference video
node analyze.js ref.mp4, POST /api/analyze, or the
fablecut_analyze_reference MCP tool.Look at the footage
GET /api/frame?src=/media/x.mp4&t=3.2 returns a JPEG of that frame, and
&frames=12 returns a 4×3 contact sheet across the clip — a cheap survey
of everything a 3-minute take holds. Grabs are cached under analysis/frames/.fablecut_frame MCP tool wraps it and returns the image inline, so a
multimodal model can look. Pass a time instead of a path and it renders
the composed timeline through the editor's own compositor — graded, all
tracks, identical to what export produces — so "is this grade right?" and "what
did I actually build?" have a visual answer.Asset library
library/ folders surface as tabs in the UI: Elements (overlay art),
Sound FX, SVG — drop files in, the open editor refreshes liveExport
encoding-profiles.json (keeps rendering if you switch tabs). Encode and
upload run ahead of the compositor so a fast timeline is not stalled by
toBlobfablecut_export runs the Fast export in the open editor,
or in a headless Chrome / Edge the server starts, and returns the file path;
preset and delivery pick and adjust a delivery preset; outputs makes
several files in one goprojDur().Your projects, media and exports go to ~/FableCut. Or run it from a clone:
Requirements: Node 18+ and a Chromium-based browser. ffmpeg on PATH is optional but recommended (fast export + upload remuxing). AI background removal fetches its model from a CDN on first use.
The server binds 127.0.0.1 only (v1.3.1+). To use it from another device on
your LAN, opt in explicitly: HOST=0.0.0.0 FABLECUT_ALLOWED_HOSTS=<your-ip> node server.js.
Drop media into the window (or ./media/), paste an HTTPS URL via + URL,
drag clips onto the timeline, edit, export.
To keep your work outside the checkout, set FABLECUT_DATA_DIR — it moves
project.json, media/, exports/, analysis/ and library/ to a directory
you choose. Leave it unset and everything stays in the repo, exactly as before.
That registers the MCP server for you and adds three skills — edit-video,
remake-reel and motion-graphics. Your timeline and footage live in the plugin's own data
directory, so an update never touches them. Node 18+ and (optionally) ffmpeg
still need to be on your machine.
Everything an agent needs is in CLAUDE.md — the complete schema, semantics and recipes. Point any capable model at that file and it can operate the editor end to end.
📖 Browsable docs: the same manual as web pages, one page per topic (MCP tools, the
project.jsonschema, clip props, recipes, REST API, export): fablecut.space/docs.
Three equivalent control surfaces:
MCP (best for Claude Code / Claude Desktop) — register the bundled zero-dependency MCP server once:
No clone or path needed; your work lives in ~/FableCut. From a clone,
point at the file instead:
OpenCode can use the same stdio server from its project or global
opencode.json configuration:
For another MCP client, register a local stdio server with this equivalent command. The exact key names vary by client, but the command and arguments do not:
(From a clone: "command": "node", "args": ["/absolute/path/to/FableCut/mcp-server.js"].)
The server is intentionally client-neutral. It speaks MCP over stdio and does not require Claude-specific environment variables. With a clone, keep the path absolute. Node 18 or newer either way.
Tools: fablecut_status (auto-starts the editor), fablecut_docs,
fablecut_get_project, fablecut_set_project, fablecut_patch_project,
fablecut_import_media, fablecut_analyze_reference, fablecut_frame,
fablecut_encode_profiles, fablecut_normalize_audio, fablecut_auto_duck,
fablecut_denoise, fablecut_silence, fablecut_beats, fablecut_reframe, fablecut_highlights, fablecut_transcribe, fablecut_captions, fablecut_export, fablecut_scopes, fablecut_track.
FableCut is also published on the official MCP registry as
io.github.ronak-create/fablecut
— each release ships an MCPB bundle (fablecut.mcpb) that MCPB-capable
clients can install directly.
The surface is token-efficient by design: agents patch the timeline with
small ops (fablecut_patch_project) instead of round-tripping the whole
document, read a compact one-line-per-clip summary
(fablecut_get_project {compact:true}), and fetch only the manual sections
they need (fablecut_docs {section:"props"}).
The file — read project.json, modify, bump revision, write. The UI
live-reloads.
REST — GET/PUT /api/project, POST /api/upload, POST /api/import-url,
GET /api/library, GET /api/export/profiles, SSE at /api/events. See
CLAUDE.md for the full list.
Example: ask Claude Code "cut these six clips to the beat markers, add a teal-orange grade, put a word-pop caption on top and a whoosh on every cut" — and watch the timeline rebuild itself.
Or hand it a reference: "here's a reel I like — analyze it and remake it with
my clips, same music". The agent calls fablecut_analyze_reference, gets the
blueprint (cuts, beats, BPM, energy, drop, extracted music), and rebuilds the
structure shot-for-shot with your footage.
The agent can see, not just measure. fablecut_analyze_reference gives it
the ears — where the cuts land, which shots hit hard. fablecut_frame gives it
the eyes: ask for any moment of any clip ({path, t:3.2}) and the call comes
back with an actual image the model can look at, or ask for a 12-frame contact
sheet to survey a whole clip in one call ({path, frames:12}). Pass a time
with no path and it renders the composed timeline — graded, all tracks, exactly
as export would. So footage gets chosen by looking at it rather than guessing
from a number, and a grade gets checked against the real picture.
Conflict-safe concurrent editing: the UI, the MCP tools, and direct
project.json writes all agree on a revision counter. If you edit a clip in
the UI while an agent is mid-task, the agent's next write is rejected (409 from
the REST API / a conflict error from fablecut_set_project) instead of
silently overwriting your change. The UI similarly detects when an agent write
supersedes a not-yet-saved local tweak and tells you with a toast instead of
dropping it silently.
SVGs animate with plain CSS @keyframes. One convention: never hardcode
animation-delay — set --d: 0.4s instead, and the compositor drives time by
pausing all animations and rebasing their delays. Full rules + a skeleton in
CLAUDE.md; working
examples in library/svg/.
library/fonts/, OFL — see
LICENSES.md there) and a set of self-authored SVG overlays and animated
elements (library/elements/, library/svg/, MIT like the rest of the repo).library/sfx/ is yours to fill (gitignored): sound-effect sites typically
don't allow redistributing their files in a public repo, so FableCut doesn't —
library/sfx/README.md lists good free sources.media/).Questions, ideas, showing off an edit, or want to help shape what's next? Join the FableCut Discord. Bugs and feature requests are still best filed as GitHub issues. Rather email? Write to [email protected], or [email protected] for help.
Source: README.md at commit 61bf46b
FableCut video editor: ensure the editor web server is running (auto-starts it), and get the editor URL, project summary and media library. Call this first in a session.
Takes no parameters.
Return the FableCut project schema documentation: clips, tracks, props, keyframe animation, transitions, and editing recipes. Read this before editing. TOKEN TIP: pass `section` to fetch only the '## …' section(s) you need (substring match, e.g. "props", "Recipes", "Remake") instead of the whole manual.
sectionGet the FableCut project (the timeline document). TOKEN TIP: pass compact:true for a one-line-per-clip summary (ids, tracks, timings, non-default props) — usually all you need to plan an edit; fetch the full JSON only when you must inspect exact keyframes.
compactApply targeted edits to the FableCut project WITHOUT round-tripping the whole document — PREFER THIS over get+set for every edit (it is ~10-100x cheaper in tokens and merge-safe by design: it re-reads the latest document from disk, applies your ops in order, bumps revision once, saves atomically). Ops: {op:'addClip', clip:{…}} (id auto-generated if omitted) · {op:'updateClip', id, set:{…}} · {op:'removeClip', id} · {op:'addMedia', media:{…}} · {op:'removeMedia', id} · MEDIA BIN: {op:'updateMedia', id | ids, set:{name?, favorite?:true|false, tags?:[…], folderId?}, addTags?:[…], removeTags?:[…]} (organize media; fps, codec, audio channels and size are probed from the file and read-only) · {op:'setCollection', id?, name?, media?:[…ids] (replaces), add?:[…], remove?:[…]} (a collection groups media across folders; a new id or name creates it) · {op:'removeCollection', id} · {op:'relinkMedia', id, src:'/media/…'} (the same footage found elsewhere — an OFFLINE file in the compact view; clips keep their In points) · {op:'replaceMedia', id, src, name?} (a different file behind the media — every clip using it switches, keeping its timing, trimmed to fit a shorter file; import the new file first with fablecut_import_media) · {op:'setProject', set:{name|width|height|fps|background|markers|disabledTracks|lockedTracks|untargetedTracks|encodeProfile|delivery|outputs|master}} (markers = the full list [{t, label?, color?}], color: gold|red|orange|green|cyan|blue|purple|pink; master = {gain}, the master fader in dB; delivery = a delivery preset id or spec — see fablecut_export — that exports use by default; outputs = the batch list, [preset id | spec, …] up to 16, exported together by fablecut_export {outputs:true}) · {op:'setTrack', id:'A1', set:{gain?, pan?, out?}} (audio-track fader in dB −60…+12, pan −1…1, out = a submix bus id or 'master'; null or 0 resets) · {op:'setBus', id:'B1', set:{name?, gain?, pan?, mute?}} (submix bus, created if missing; route tracks into it with setTra
opsrequiredbaseRevisionReplace the FableCut project JSON. Pass the COMPLETE document (read with fablecut_get_project, modify, send back whole). Revision is auto-bumped; the open editor UI hot-reloads instantly so the user sees the edit live. CONFLICT-SAFE: if the project changed on disk since your last fablecut_get_project (e.g. the user tweaked something in the UI), the call errors instead of overwriting — re-read, re-apply your edit on top of the latest document, and retry.
forceprojectrequiredLOOK at the footage — returns an actual image, not just numbers. REQUIRES A VISION-CAPABLE MODEL: if you cannot read images, pass `text:true` instead (or skip this tool and use fablecut_analyze_reference). Three modes. (1) One frame of a source clip: pass `path` (an absolute file path, or a '/media/…' src — read where it lies, never copied) and `t` in seconds. (2) A contact sheet: pass `frames` (2–60) for one grid image with that many moments spread across the clip (`from`/`to` to survey part of it) — the cheap way to see what a whole clip holds. (3) With no `path`, `time` renders the COMPOSED TIMELINE at that moment through the editor's own compositor, graded and multi-track, exactly as export would. Use it before choosing a clip's `in` point, or to pick footage matching a blueprint's shots[] energy — seeing beats guessing. Needs ffmpeg on PATH (timeline mode runs in the open editor tab, else a headless browser).
ttocolsfrompathtexttimewherewidthframestimeoutAnalyze a reference video into an EDIT BLUEPRINT so a similar edit can be rebuilt with different footage over the same music. Returns: shot boundaries (cuts) with per-shot audio energy, music beats + BPM, a loudness curve, the detected drop, and extracts the reference's music track into media/ (registered in the project, ready to place on A1). Remake recipe: copy the reference's width/height/fps to the project, write `beats` into project `markers`, lay the extracted music on A1, then place one clip per blueprint `shot` at the same start/duration — pick calm footage for low-energy shots and action for high-energy ones, and make the biggest moment land on `drop`. See the 'Remake a reference video' section of fablecut_docs.
pathrequiredthresholdregisterMusicImport a media file into FableCut's media library and register it in the project. Pass a local absolute path (copied, including .svg) or an https:// URL (downloaded into ./media/; video/audio/image only — remote SVG is refused). The URL is never kept as the playback src — CORS would break export. Returns the created media entry (use its id in clips).
pathrequiredList what fablecut_export can make. DELIVERY PRESETS (structured settings, the Export dialog's Preset list): youtube, youtube-shorts, instagram-reels, tiktok, x, linkedin, master (project size), broadcast (ProRes 422 HQ), web (720p), archive (lossless FFV1), custom — plus presets the user saved — each a spec of resolution, fps, codec (h264, hevc, av1, vp9, prores, dnxhr, mpeg2 XDCAM, ffv1), rate control (crf / vbr / cbr), keyframe interval, pixel format, color, container, audio, a file-name template and metadata. {preset:'youtube'} returns one preset's full spec; the encoders this ffmpeg can use are listed (hardware ones only when they work on this machine). ENCODING PROFILES (encoding-profiles.json): raw ffmpeg argument lists plus jpegQuality, extension and color, for anything the presets do not cover; edit the file on disk (hot-reloaded); {profile:'hq'} returns one, detail:true includes every args array. Both are dry-run against ffmpeg when an export starts, so bad settings are refused before rendering.
detailpresetprofileLoudness-normalize clips: measures each clip's source audio (ITU-R BS.1770 integrated LUFS, or sample peak) after its channel routing and sets `props.gain` (clip gain, dB) so it lands on the target — the same measurement as the editor's Normalize button. Linked stems (a video's per-channel audio clips) are measured together and get one shared gain, so a stereo pair stays balanced; passing a video clip normalizes its stems. Volume keyframes / fades are untouched (they ride on top). Typical targets: -14 LUFS streaming/social, -16 LUFS podcast/dialogue, -23 LUFS broadcast, or mode 'peak' at -1 dBFS. Needs ffmpeg + ffprobe on PATH. Refuses locked clips unless force:true.
modeforcetargetclipIdsrequiredDuck music under dialogue: finds where the voice tracks have sound (RMS above `threshold`, short gaps bridged so the music doesn't pump between words) and writes `duck` keyframes (dB) on the given music clips — a dip of `amount` dB ramping down `attack` s before speech and back up `release` s after. The duck multiplies the clip's volume, so its own level, volume keyframes and fades are untouched, and re-running replaces the previous dips (amount 0 clears them). Voice = every audio clip on `under` tracks (default: all audio tracks the music isn't on). Linked stems of a music clip get the same keys. The same pipeline as the editor's Auto-duck. Needs ffmpeg + ffprobe on PATH. Refuses locked clips unless force:true.
forceunderamountattackclipIdsrequiredreleasethresholdFind the silences in speech and, with cut:true, cut them out. Listens to the given clips (a video's linked audio stems, after channel routing, gain and volume) and reports every stretch where none of them is above `threshold` for at least `minSilence` seconds, keeping `padding` seconds of quiet beside each phrase so words aren't clipped. Gaps between clips are left alone. With cut:true each silence is removed with an `extract` on the targeted tracks (or `tracks`), last first, in one revision: later material moves up, linked stems stay in sync, locked tracks and clips stay put — lock the music bed first if it should keep running. A version is saved before the cut. Without cut it only reports, so check the spans (and fablecut_frame them) first. The same as the inspector's Silence section. Needs ffmpeg + ffprobe on PATH.
cutforcetracksclipIdsrequiredpaddingthresholdminSilenceThe music's beat on the timeline, and cuts that land on it. Listens to a music clip (an audio clip, or a video's sound) and finds its tempo (BPM), a steady beat grid phased to the hits, and the drop — all in timeline seconds, through the clip's in point and speed. Then, in one revision: markers:true puts a cyan marker on every beat; snap:true rolls each cut on the video tracks (the targeted ones, or snap:{tracks}) to the nearest beat within half a beat (snap:{maxShift} seconds) — nothing else moves, linked stems follow; retime:{track?, every?, from?} lays the clips on a track (default the lowest video track with clips) back to back on the beat, `every` beats each (1, 2, 4, 8 or 16; default 2), from the first beat at or after `from` (default the music's start) — a clip whose footage runs out gets fewer beats, and the order is kept. Locked clips are left alone (snap) or refuse (retime) unless force:true. A version is saved before snap or retime (if that fails the edit still goes ahead and the reply warns). Without markers / snap / retime it only reports. The same as the Inspector's Beats section. Needs ffmpeg on PATH.
snapeveryforceclipIdrequiredretimemarkersReframe for another shape, following the subject: a 16:9 edit made 9:16 (Reels, Shorts, TikTok), 1:1 or 4:5. With aspect, a copy of the open sequence is made on that canvas (the project's shorter side kept, e.g. 1920×1080 → 1080×1920) and opened, so the original cut stays as it was; without aspect, the open sequence is reframed on its own canvas. Each full-frame shot (a video or still that isn't moved, scaled, cropped or animated by hand) is fitted to cover the canvas, and its position follows what matters in it: frames are sampled 5 times a second, the subject is found by motion against the shot's own movement, detail and colour, and a virtual camera operator holds still until the subject leaves a dead zone, then eases after it no faster than a pan speed. The result is ordinary x (or y) keyframes, thinned to a few, or one steady position — edit them like any keys. Shots without a clear subject are centred. Titles, picture-in-picture, clips placed by hand and locked clips are left alone (listed in the reply) — check them with fablecut_frame on the new canvas. clipIds limits it to some clips; follow:false only fits and centres; smooth 0…1 (default 0.5) — higher holds longer and pans slower. A version is saved first. Needs ffmpeg on PATH.
nameforceaspectfollowsmoothclipIdsThe best moments of long footage, cut into a short edit: a 30 s reel from a 20-minute vlog, a match, a talk, a day of B-roll. Looks at the video clips on the open timeline (or clipIds, or whole files with mediaIds) — frames twice a second and the sound — and scores every half second: movement, sound louder than around it (a cheer, a laugh, a hit), a clear picture. Cuts already in the footage are found and never crossed. It takes the best moments of `shot` seconds (default: duration / 8, 1.5–4 s), apart from each other and spread over the shots, until the edit is `duration` seconds (default 30), and nudges each end to a quiet point so no word or hit is cut through. They go back to back on V1 of a new sequence, in story order, with their linked sound, and the sequence is opened; the timeline you started from is left as it was. aspect makes the new sequence 9:16, 1:1 or 4:5 (then fablecut_reframe {} fits the shots and follows the subject). The reply lists each moment (source, times, why it was picked). A version is saved first. Then: music under it and fablecut_beats {clipId, retime:{every:2}} cuts it on the beat. Needs ffmpeg on PATH.
nameshotaspectclipIdsdurationmediaIdsWhat is said, word by word, with times — and text-based editing. Transcribes the clips' speech with Whisper in the editor (an open tab, else headless Chrome / Edge; the speech model downloads once, the audio never leaves the machine), keeps one transcript per file (analysis/transcripts/), and answers with the timeline's words as timed lines (timeline seconds), so you can read an interview, pick the good takes, or find where something is said. find:"phrase" (or a list) reports every place it is said — case, punctuation and spacing ignored, whole words only — with the exact span; cut:true then extracts each of them on the targeted tracks (or `tracks`), the words and the pause after them, last first, in one revision: later material moves up, linked stems stay in sync, locked clips stay put (lock the music bed first). A version is saved before a cut. Files already transcribed aren't done again unless again:true. Default clips: every video / audio clip with sound on the open timeline. mediaIds reads whole files instead (file seconds; no cut). The same as the editor's Transcript tab.
tocutfindfromagainforcemodelwheretracksclipIdstimeoutlanguage+1 moreCaptions from what is said: makes caption clips on the timeline from the clips' transcripts (transcribing first when there is none, like fablecut_transcribe), each one a text clip with `wordTimes` so its words follow the speech. Captions are cut at pauses and sentences, one or two lines as wide as the canvas allows. Styles: subtitle (plain, on a dark bar), karaoke (words light up as they are said), highlight (bold, the word being said in a colour — the reel look), pop (one to three big words at a time, each popping in). They go on the lane captions are already on, else the top video lane, else a new lane above it, and replace the captions there (replace:false keeps them). export:"srt"|"vtt" writes the timeline's captions to a subtitle file in exports/; import: a path to an SRT / WebVTT file (or its text) places its captions instead of the transcript's. remove:true deletes the captions. Captions are text clips: restyle them with updateClip, and make them after the cutting is done (a cut through a caption doesn't re-time its words — run this again). The same as the Transcript tab's Captions row.
tofromsizeforcelinesmodelstyletrackwherewordsexportimport+4 moreReduce background noise (hiss, hum, room tone) on audio clips: ffmpeg's FFT denoiser renders a cleaned FLAC of each clip's whole source file into media/, and the clip — with its linked stems — switches to it (the picture keeps its own file, so links and timing stay intact). The same as the inspector's Noise control. amount 'off' switches back to the original. Re-running reuses a file already rendered. Needs ffmpeg + ffprobe on PATH. Refuses locked clips unless force:true.
forceamountclipIdsrequiredSeveral projects in one FableCut: the projects dashboard. ./project.json (what every other tool reads and edits) is always the OPEN project; the others are stored beside it and share media/, exports/ and the library, so a duplicate or a template copies no footage. Actions: list (default; archived:'only'|'all' to see archived ones) · open {id} — switches the editor to that project (the open one is saved first; editor tabs reload; your next fablecut_get_project reads the new one) · new {name, template?, fps?, width?, height?, notes?, tags?, open?:true} — template is a built-in canvas (landscape-1080 default, vertical-1080, square-1080, portrait-1350, uhd-4k, landscape-720) or a saved template id · duplicate {id, name?, open?:false} · update {id, name?, notes?, tags?} · archive / unarchive {id} · delete {id} (archived projects only) · templates · save_template {id, name} (the project's canvas, tracks, clips and media references) · delete_template {template}. Opening another project changes what the user sees — only open, archive or delete when the user asked for it.
idfpsnameopentagsnoteswidthactionheightarchivedtemplateA project's version history: saved copies you can go back to, never destructive. Actions: list (default) · save {name?, note?, final?} — keep the project as it is now (do this before big or risky edits, and when the user is happy with a cut) · diff {version, to?} — what changed from that version to now (or to another version): clips added / removed / changed, length, media, settings · restore {version} — put that version back; the current state is saved as a version first, so a restore can itself be undone · update {version, name?, note?, final?} — rename, annotate, or mark the one final cut · delete {version}. project defaults to the open one (fablecut_projects lists ids). Versions are also made on their own: every 10 minutes while the project changes, and before an agent's first edit of a session or a fablecut_set_project rewrite. Restoring changes what the user sees: only when they asked.
tonamenotefinalactionprojectversionProxies: light H.264 copies (540p by default, 720p or 1080p; never larger than the source) of heavy footage — 4K, HEVC, ProRes, long phone clips — that the editor plays while the user edits, so playback and scrubbing stay smooth. Export, fablecut_frame, fablecut_scopes and every measurement always read the original, so a proxy never changes the result. Without create or delete it reports each video's proxy (ready, being made with its progress, failed, none). create:true makes them (one at a time, in the background on the server) and waits until they are done unless wait:false; delete:true removes them. mediaIds defaults to every video in the project. The user turns proxy playback on or off with the monitor's Proxy button. Needs ffmpeg on PATH.
waitcreatedeleteheighttimeoutmediaIdsRender the timeline to a video file in exports/ — the editor's own Fast export (same compositor, audio mix and encoding profile as the Export button), so the file matches what the user sees. It runs in a browser: an open editor tab takes the job (the user sees the progress bar), or with no tab open the server starts headless Chrome / Edge (set FABLECUT_CHROME to pick one) and closes it afterwards. Waits for the file by default and returns its path. Range: the project's inPoint→outPoint when set, else the whole timeline (or pass range). Needs ffmpeg on PATH. One export at a time. Long edits: pass wait:false, then poll with {job}; {cancel:job} stops one.
jobwaitrangewherecancelpresetoutputsprofiletimeoutdeliveryMeasure the graded picture at one moment — what the editor's scopes show, as numbers: luma levels (min, 1st percentile, median, mean, 99th percentile, max on 0–1), the % of pixels crushed to black / clipped to white, mean R/G/B, average saturation, and the colour cast of the midtones (hue name + strength; neutral below 0.01), plus the clips on screen with their grades, masks, track mattes and blend modes. Rendered by the same compositor as export (an open editor tab, else headless Chrome / Edge), over the export frame when one is set. Use it to check a grade: e.g. a cast strength above ~0.03 on footage that should be neutral, whitePct above ~1 (clipped highlights), or a median far from ~0.4 for a normally exposed shot. The user's playhead does not move.
masktimemattewheretimeoutFollow something in a video clip frame by frame (motion tracking, in the editor: an open tab, else headless Chrome / Edge) and store it on the clip as a named track (props.tracks). Then, in the same call, make a mask follow it (apply:{mask}) or pin another clip to it (apply:{clip} — a title, sticker, blur box… its x / y, and optionally scale / rotation, get keyframes that ride on the track, keeping where it is at `at`). What to follow: region {x, y, w, h} or point {x, y} (+ size), as fractions of the clip's picture (0…1, y down) at time `at`; or leave both out with apply:{mask} to follow what that mask covers. To re-apply an existing track, pass its name with apply and no region. Pick something with detail (a corner, a logo, text, an eye), not a flat area; the result reports match quality (≥ 0.8 is solid) and where the region was lost, if it was. Check the outcome with fablecut_scopes or by looking at the keyed clip.
attocliprequirednamesizeapplyforcepointscalewhereregiontimeout+2 more90% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
npx -y fablecut # → http://localhost:7777git clone https://github.com/ronak-create/FableCut.gitcd FableCutnode server.js # → http://localhost:7777/plugin marketplace add ronak-create/FableCut/plugin install fablecut@fablecutclaude mcp add -s user fablecut -- npx -y fablecut mcpclaude mcp add -s user fablecut -- node "<path-to>/fablecut/mcp-server.js"{ "$schema": "https://opencode.ai/config.json", "mcp": { "fablecut": { "type": "local", "command": ["node", "/absolute/path/to/FableCut/mcp-server.js"], "enabled": true } }}{ "name": "fablecut", "transport": "stdio", "command": "npx", "args": ["-y", "fablecut", "mcp"]}server.js zero-dependency HTTP server: static hosting, REST API, SSE, ffmpeg export pipelineapp.js the editor: timeline UI, compositor, keyframes, text engine, SVG rasterizer, chroma key, exportersindex.html single-page UIstyle.css dark editor thememcp-server.js stdio MCP server exposing the editor to AI agentsanalyze.js reference-video analyzer: shots, beats/BPM, energy, drop, music extraction (module + CLI)CLAUDE.md the agent manual (schema + recipes) — also served by fablecut_docsencoding-profiles.json Fast-export ffmpeg presets (hot-reloaded)project.json your timeline (created on first run; gitignored)media/ project footage (gitignored)analysis/ cached edit blueprints from /api/analyze (gitignored)library/ default assets: elements/ sfx/ svg/ fonts/exports/ finished renders (gitignored)flowchart TD
subgraph group_interaction["Editing Experience"] node_browser_ui["Browser Editor<br/>[app.js]"] node_timeline_model["Timeline Model<br/>[app.js]"] node_ruler_worker["Ruler Worker<br/>[ruler-worker.js]"]end
subgraph group_project_media["Project And Media"] node_project_store[("Project Store<br/>[paths.js]")] node_media_store[("Media Store<br/>[paths.js]")] node_asset_library[("Asset Library<br/>[server.js]")] node_url_importer["URL Importer<br/>[import-url.js]"]end
subgraph group_agent_api["Agent Control"] node_rest_api["REST Server<br/>[server.js]"] node_mcp_server["MCP Server<br/>[mcp-server.js]"] node_sse_hub["Change Notifications<br/>[server.js]"]end
subgraph group_playback_export["Playback And Export"] node_compositor["Canvas Compositor<br/>[app.js]"] node_audio_engine["Audio Engine<br/>[app.js]"] node_audio_meter["Audio Meter<br/>[meter-worklet.js]"] node_export_engine["Export Engine<br/>[server.js]"] node_encoding_profiles["Encoding Profiles<br/>[encode-profiles.js]"]end
subgraph group_analysis["Analysis Tools"] node_reference_analyzer["Reference Analyzer<br/>[analyze.js]"]end
node_human(("Human Editor"))node_ai_agent(("AI Agent"))node_ffmpeg["FFmpeg"]
node_human -->|"edits timeline"| node_browser_uinode_ai_agent -->|"sends tools"| node_mcp_servernode_browser_ui -->|"updates project"| node_timeline_modelnode_timeline_model -->|"persists JSON"| node_project_storenode_browser_ui -->|"calls REST"| node_rest_apinode_rest_api -->|"reads writes"| node_project_storenode_rest_api -->|"serves media"| node_media_storenode_rest_api -->|"lists assets"| node_asset_librarynode_mcp_server -->|"checks server"| node_rest_apinode_mcp_server -->|"patches project"| node_project_storenode_mcp_server -->|"imports media"| node_url_importernode_url_importer -->|"stores downloads"| node_media_storenode_rest_api -->|"downloads URLs"| node_url_importernode_rest_api -->|"broadcasts changes"| node_sse_hubnode_sse_hub -->|"pushes changes"| node_browser_uinode_timeline_model -->|"renders timeline"| node_compositornode_timeline_model -->|"routes clips"| node_audio_enginenode_audio_engine -->|"measures audio"| node_audio_meternode_browser_ui -->|"uploads frames"| node_rest_apinode_rest_api -->|"streams export"| node_export_enginenode_export_engine -->|"loads profile"| node_encoding_profilesnode_export_engine -->|"encodes video"| node_ffmpegnode_reference_analyzer -->|"analyzes media"| node_ffmpegnode_reference_analyzer -->|"writes music"| node_media_storenode_ai_agent -.->|"requests analysis"| node_reference_analyzernode_browser_ui -.->|"draws ruler"| node_ruler_worker
click node_browser_ui "https://github.com/ronak-create/fablecut/blob/main/app.js"click node_timeline_model "https://github.com/ronak-create/fablecut/blob/main/app.js"click node_compositor "https://github.com/ronak-create/fablecut/blob/main/app.js"click node_audio_engine "https://github.com/ronak-create/fablecut/blob/main/app.js"click node_audio_meter "https://github.com/ronak-create/fablecut/blob/main/meter-worklet.js"click node_rest_api "https://github.com/ronak-create/fablecut/blob/main/server.js"click node_mcp_server "https://github.com/ronak-create/fablecut/blob/main/mcp-server.js"click node_sse_hub "https://github.com/ronak-create/fablecut/blob/main/server.js"click node_project_store "https://github.com/ronak-create/fablecut/blob/main/paths.js"click node_media_store "https://github.com/ronak-create/fablecut/blob/main/paths.js"click node_asset_library "https://github.com/ronak-create/fablecut/blob/main/server.js"click node_url_importer "https://github.com/ronak-create/fablecut/blob/main/import-url.js"click node_export_engine "https://github.com/ronak-create/fablecut/blob/main/server.js"click node_encoding_profiles "https://github.com/ronak-create/fablecut/blob/main/encode-profiles.js"click node_reference_analyzer "https://github.com/ronak-create/fablecut/blob/main/analyze.js"click node_ruler_worker "https://github.com/ronak-create/fablecut/blob/main/ruler-worker.js"
classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172aclassDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350fclassDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532dclassDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4aclass node_browser_ui,node_timeline_model,node_ruler_worker toneBlueclass node_project_store,node_media_store,node_asset_library,node_url_importer toneAmberclass node_rest_api,node_mcp_server,node_sse_hub toneMintclass node_compositor,node_audio_engine,node_audio_meter,node_export_engine,node_encoding_profiles toneRoseclass node_reference_analyzer,node_human,node_ai_agent,node_ffmpeg toneIndigo