FableCut
Control and automate the FableCut browser video editor by managing its JSON project/timeline, media, analysis, export, and agent workflows.
Check/start the editor server and get the editor URL, project summary, and media library.
Read FableCut documentation, optionally fetching only needed sections.
Read the full project document or compact one-line-per-clip summaries.
Patch the project safely with targeted operations, or replace the whole project; handles revisions, conflicts, and locks.
Edit clips, tracks, project settings, markers, audio faders, submix buses, effects/automation, color grades, masks, and track mattes.
Create/edit shapes, null parents, motion paths, text-on-path, compositions, sequences, animation presets, and templates.
Run timeline edits: split, ripple delete, close gap, lift/extract, insert/overwrite, ripple trim, roll, slip, slide, and crossfade.
Import local or HTTPS media and manage folders, tags, collections, relinking, and file replacement.
Analyze reference videos into edit blueprints: shots, beats/BPM, energy, drop, and extracted music.
View frames, contact sheets, or composed timeline renders; return text measurements when vision is unavailable.
Normalize audio, auto-duck music under dialogue, denoise, detect/cut silences, and detect beats for snapping or retiming.
Reframe edits for vertical/square aspects with subject following, and generate highlight edits.
Transcribe speech with Whisper, find phrases, cut matches, and create/import/export captions.
Measure color scopes: luma levels, clipping, saturation, color cast, mask/matte coverage.
Motion-track regions or points and apply tracking to masks or clips.
Manage the projects dashboard: list, open, create, duplicate, update, archive, delete, and use templates.
Manage project versions: save, list, diff, restore, update, and delete.
Create, list, or delete proxies for heavy footage.
Inspect encoding presets/profiles and export timelines to video files, including batch outputs, ranges, presets/profiles, delivery overrides, and job polling/cancel.
Provides fast video export and reference video analysis, including shot detection and beat extraction.
Allows loading any Google Font by name for use in text clips, with automatic fetching.
Enables AI-powered background removal (person cut-out) directly in the browser for video clips.
A browser video editor that AI agents can drive.
English · 简体中文 · 日本語 · Español · Português (BR)

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.

Sponsors
Sidrune AI — One API for GPT, Claude, and other leading AI models. Sign up and get $3 in API credit.
Related MCP server: premiere-pro-mcp
Why it's interesting
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.
Features
Editing
Video + audio tracks (default 3+4; add more with +V / +A in the track header; right-click an empty header → Remove track), drag/trim/split/snap, undo/redo
Settings (cog in the top bar) — optional prefs stored in this browser via
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).Video + audio tracks (default 3+4), drag/trim/split/snap, undo/redo
+V / +A in the track header add a video or audio lane (up to 16 each)
Right-click an empty track header → Remove track (disabled if the lane has clips, or if it would leave you with zero video/audio tracks)
Track header S solos that lane (mutes all others); click again to restore the previous mute state. Using the mute toggle while soloed exits solo.
Track targeting — click a track's name to target / untarget it (lit = targeted). Split, insert, ripple, close gap and jump-to-cut touch targeted tracks only; the eye / speaker toggle is output-only (hide from preview and export) and no longer blocks edits. A selected clip is edited wherever it sits.
Track lock — the padlock in the track header. Nothing on a locked track can be moved, trimmed, split or deleted, and ripples leave it in place while the other tracks shift — lock the music bed and re-cut the picture freely.
Clip lock, disable and unlink — right-click a clip (or use the toggles at the top of the inspector): Lock pins it like a locked track; Disable (⇧E) keeps it on the timeline but hides it from preview and export; Unlink (Ctrl/Cmd+L) splits a video from its audio so they move separately, and Link re-joins them once they line up again. Agents see locks too:
fablecut_patch_projectrefuses to edit locked clips unless the op saysforce: true.Dropping a video with more audio channels than A-tracks adds the missing lanes automatically (up to 16) and toasts how many were added; each channel becomes a linked stem on its own A-track
Direct manipulation on the monitor — click a clip or title on the preview to move, resize (corner handles), or rotate (top handle, Shift-snap) it directly
Timeline multi-select — rubber-band marquee (drag on empty track area), Ctrl/Cmd/Shift+click to add/remove clips, Ctrl+A to select all, Esc to deselect. Drag any selected clip to move the whole group; Delete removes all selected; S splits all selected at the playhead. Inspector shows an "N clips selected" banner.
Beat & cue markers (tap m on the beat during playback) — name and colour them, drag them on the ruler, jump with ⇧m / Alt+⇧m or the Markers list; snapping targets (clip edges, playhead, markers, IN/OUT, keyframes, frame grid) are picked from the ▾ beside Snap
Press Alt+t to add an in/out transition based on the playhead position over the selected clip. The last used transition is remembered as the default. Drag the overlay triangle to adjust duration; Delete clears the focused transition.
Real decoded audio waveforms on clips
Mixer — the Mixer tab beside the Inspector has a strip per audio track (fader, pan, mute, solo, meter) and a master fader with a live LUFS readout. Preview and export run through the same mix, so what you hear is what renders.
Clip gain, channels and Normalize — each audio clip has a Gain (dB, before volume and keyframes), a Channels mode (stereo, mono, left, right, swap) and Normalize: measure the selected clips (ITU-R BS.1770 loudness or sample peak) and set their gain to hit −14 / −16 / −23 LUFS or −1 dBFS. Linked stems share one gain so a stereo pair stays balanced.
Volume line, fades and crossfades — every audio clip shows its volume as a line you drag; Ctrl/Cmd-click adds a keyframe, Alt-click removes one. Corner grips drag fades in and out, drawn with their real curve (constant power, constant gain or exponential). Shift+D crossfades the cut next to the selection, borrowing spare media from both sides so nothing else moves.
Auto-duck — select the music, pick the dialogue track and an amount, and the music dips wherever someone speaks (ramping down just before, back up after). It rides on top of the music's own volume, so re-running or clearing it never touches your levels. Agents use
fablecut_auto_duck.Audio effects and presets — EQ, high/low-pass, compressor, limiter, noise gate, delay, reverb, distortion, stereo width and pitch shift, chained per clip, per track (Mixer → FX), per bus and on the master. Presets: Clean voice, Podcast, Radio, Deep voice, Telephone, Cinematic, Wide and Muffled, all tweakable afterwards. Preview and export run the same effects. Agents use the
setFxpatch op.Effect automation — the ◆ beside an effect setting keys it at the playhead, like clip keyframes: sweep a filter into the drop, open up a reverb at the end. Agents use
setFxKeys.Submix buses — + Bus in the Mixer adds a bus with its own effects, fader, pan, mute and meter; route tracks into it from the menu under each track's name (all the dialogue through one compressor and one fader).
Noise reduction — the inspector's Noise control (Light / Medium / Strong) measures the file's noise floor and renders a cleaned copy with ffmpeg; the clip's audio switches to it and Off switches back. Agents use
fablecut_denoise.Reframe — make a 9:16, 1:1 or 4:5 copy of your edit whose shots follow the subject: a virtual camera pans after what matters in each shot and writes ordinary position keys you can still edit. From New sequence… or the Inspector's Reframe section; agents use
fablecut_reframe.Highlights — the best moments of long footage (movement, sound, a clear picture) cut into a short edit in a new sequence, in story order and never across a cut. From the sequence menu's Highlights…; agents use
fablecut_highlights.Silence removal — the inspector's Silence section (or right-click → Find silences) listens to a take and marks every pause on the timeline; Cut extracts them all in one undo step, keeping a little quiet beside each phrase so words aren't clipped. Agents use
fablecut_silence.Beats — the inspector's Beats section finds a music clip's tempo, a steady beat grid and the drop, and shows the beat across the timeline. Mark the beats, snap every cut onto the nearest one, or re-cut a track so each shot lasts 1, 2, 4, 8 or 16 beats. Agents use
fablecut_beats.Transcripts and text-based editing — the Transcript tab turns speech into words with times, in the browser (Whisper; the model downloads once and the audio never leaves your machine). Click a word to go there, select words and press Delete to cut them, or find a phrase and cut every time it is said. Agents use
fablecut_transcribeto read an interview, find a line and cut it.Captions — one click makes captions from the transcript, timed word by word: subtitle, karaoke, a highlighted word or big popping words, sized for the canvas. Export or import SRT and WebVTT. Agents use
fablecut_captions.Project bin folders — tree view with expand/collapse; drag media or folders to nest; right-click the Project tab → New folder; drop files onto a folder to import into it
Media management — each file's frame rate, codecs, audio channels and size (ffprobe); search by name, codec, resolution or
#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…Projects — a dashboard of every project with pictures, notes and tags: open, create from a canvas or a saved project template, duplicate, rename, archive and delete, import an old project file; media is shared, so copies cost no footage
Sequences — several timelines in one project (a 16:9 and a 9:16 cut, cut-downs, alternatives) sharing its media and compositions, each with its own canvas, frame rate, mix and delivery settings; switch from the menu at the left of the timeline toolbar
Versions — non-destructive history: save a version (Ctrl/Cmd+S), automatic versions every 10 minutes and before an agent edits, compare a version with now, restore (the current state is kept as a version first), mark the final cut; backups carry every version, and an unreadable
project.jsonis recovered at startupProxies — light, frame-accurate H.264 copies of 4K / HEVC / ProRes footage made in the background (ffmpeg); edit on the proxy with the monitor's Proxy button, export always renders the originals
Import from URL — + URL downloads an HTTPS video/audio/image into
./media/(same-origin after import). Remote SVG is refused. Agents usefablecut_import_mediawith anhttps://path. The URL is not kept asmedia.src— that would taint the canvas and break export.Audio Hold — timeline toolbar toggle: while paused, loops one frame of audio at the playhead (useful when stepping frame-by-frame). Scrubbing or frame-step retargets the held slice; meters stay live. Play / Pause turns it off.
Canvas aspect presets (16:9, 9:16 reels, 4:5, 1:1) + project FPS select (24 / 25 / 30 / 50 / 60; non-preset rates show as Custom) + safe-area guides
Export frame / reframing — composition canvas can be larger than the delivery crop (
exportFrameinproject.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 setProgram Monitor zoom — mouse-wheel over the preview zooms the composition toward the cursor (fit → up to 2 screen pixels per canvas pixel). Magnified view uses native scrollbars so overflow stays reachable; middle-click or Alt+drag pans. The Fit button (shown while zoomed) resets to the fit-to-stage baseline
Full J/K/L shuttle — L plays forward, J in reverse; tap again for 1.5×/2×/4×, the other key turns around, K stops. Hold K and tap J/L to step a frame, or hold both to crawl at ¼ speed. Preview only, never the export
Typed timecode — click the playhead readout (or type digits) to jump:
01:15:00,1500,+30,12.5; the IN / OUT readouts take typed times tooResizable workspace: drag the divider between monitor and timeline (double-click resets), plus S/M/L timeline track-density presets (S hides thumbnails for compact tracks)
Zoom to selection (⇧Z) frames all selected clips, not just one
IN/OUT work area — set markers with i and o (⇧I / ⇧O to clear). The Program Monitor shows playhead as
current / 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.Find & close gaps — a gap is a stretch where every targeted track is empty (black frames). g jumps the playhead to the next shared gap (wraps; respects IN/OUT when both are set). ⇧G closes the gap under the playhead by pulling later clips left on all targeted tracks (locked clips stay put).
Trim tools — a tool picker in the timeline toolbar (or V B R Y U): Selection, Ripple edit (drag a clip edge and everything after it follows, so no gap opens), Rolling edit (drag a cut between two clips; nothing else moves), Slip (change which part of the source a clip shows without moving it) and Slide (move a clip while its neighbours trim to make room). Every tool respects source length, targeting, locks and linked audio, and shows the offset beside the pointer while you drag. Agents run the same edits — split, ripple delete, lift / extract, insert / overwrite, ripple / roll / slip / slide and crossfade — as
fablecut_patch_projectops, on the same code.Lift / Extract — ; removes the IN→OUT range on the targeted tracks and leaves the gap; ' removes it and closes the gap. Both also sit in the timeline toolbar.
Jump to cut — ↑ / ↓ move the playhead to the previous / next edit (clip In or Out). With a clip selected, the first taps land on that clip’s start then end (Premiere-style); with no selection they walk cuts on targeted tracks. In the Source monitor they jump among 0, In, Out, and duration. Left/right still step frames; Home/End still go to the sequence (or IN/OUT with Limit).
Ripple delete — the timeline Ripple delete button (or ⇧Del) removes the selection and pulls later clips left on each targeted track to close the gap; plain Del still lifts (leaves a gap). Linked AV partners always move together, even on untargeted tracks (sync lock); locked clips are never deleted or moved.
Reset a property — Ctrl/Cmd+click an inspector label or slider restores that effect/prop to its default and clears every keyframe on the channel (scale → 1, opacity → 1, paired fields like Crop L/R reset together; transition labels clear the in/out transition). Shift+click a label is playhead-local: if you are parked on a keyframe it removes that keyframe only; otherwise it sets the value at the playhead to the default (auto-keys if the channel is already animated).
Replace media — the inspector's Source button (any video/audio/image/svg clip) swaps the underlying file while keeping position, trim, keyframes, transitions and every effect. Pick another item already in the bin or Browse file… to import and replace in one step. A video's linked L/R audio companions are swapped along with it; a shorter replacement clamps the trim to fit and toasts that it did so.
Multi-channel video audio — a video with more than 2 audio channels gets a linked audio clip per channel, not just L/R (5.1, 7.1…). Extra audio tracks (A5, A6, …, capped at 16) are created automatically as needed; replacing a clip's media re-syncs the linked channel clips to the new source's channel count, adding/dropping extras and new tracks as needed.
Look
14 one-click filter presets (cinematic, teal-orange, noir, vintage, cyberpunk, sunset, midnight…)
Adjustment layers — one clip grades everything below it, Premiere-style
Color workspace (top bar → Color): live waveform, RGB parade, vectorscope and histogram beside the program monitor, and a Color tab that grades the selected clip on the GPU — lift / gamma / gain / offset wheels, exposure, white balance with a picker (click something white), blacks / shadows / midtones / highlights / whites, log-style contrast with a pivot, soft rolloff and saturation, plus curves — luma and R / G / B, hue vs hue, hue vs saturation, hue vs luma and saturation vs luma, with a picker that marks a colour from the monitor, and layers (secondaries): a correction limited by an HSL qualifier and / or an ellipse, rect, polygon, bezier or free-hand mask (feathered, invertible, keyframable, dragged on the monitor), with a matte view. Copy / paste a grade across shots. Agents grade with the
setGradepatch op and read the result as numbers withfablecut_scopes(levels, clipping, colour cast)Quick filter sliders: brightness/contrast/saturation/hue, temperature & tint, blur, grayscale/sepia/invert, vignette, animated film grain
17 blend modes (screen, multiply, overlay, color-burn, exclusion, hue, luminosity…), fit modes (contain/cover/stretch), per-edge cropping, corner radius, flip H/V
Masks — isolate any part of a clip (video, image, SVG, text or an adjustment layer): rectangle, ellipse, bezier pen and free-hand shapes, several per clip, combined with add / subtract / intersect / difference, each with feather, expansion, invert and opacity, all keyframable (outlines morph). Draw and edit them on the monitor, with a matte view. Agents use the
setMaskpatch op and measure withfablecut_scopesShapes and motion graphics — shape layers of rectangles, ellipses, polygons, stars, lines and pen-drawn bezier paths in groups, with fill, stroke, dashes and trim paths for draw-ons; null objects, parenting and an anchor point on every clip; every value keyframes, edited right on the monitor. Agents use the
setShapeandsetParentpatch opsMotion paths, motion blur and text on a path — bend a clip's travel into a curve with handles on the monitor, turn it along the way, blur fast moves with a shutter angle (preview and export), and set titles along lines, arcs, circles or drawn paths. Agents use the
setMotionPathandsetTextPathpatch opsCompositions — nested sequences: build a lower third, a logo sting or a scene once and place it anywhere as one clip that moves, masks, grades and blends like a picture, while its video and audio play and export as usual. Open one to edit it on the timeline, or precompose a selection. Agents use the
addComp,inCompandprecomposepatch opsAnimation presets and templates — 33 ready-made entrances, exits, emphases and loops that fit any clip where it sits, and templates (lower thirds, logo animations, 9:16 / 1:1 / 16:9 social layouts) whose text, colours and logo you fill in, each placed as its own comp. Save your own animations and comps to the library for every project. Agents use the
applyPreset,addTemplateandsetTemplatepatch opsMotion tracking — follow a point or a region (with its scale and rotation) through a video clip, then make a mask follow it or pin a title, sticker or any clip to it; the result is ordinary editable keys. Agents use
fablecut_trackTrack mattes — cut a clip with the picture on the track above by its alpha or its luma (inverted or not): text filled with video, shape reveals, texture cut-outs. The matte track hides itself. Agents use
setMatteChroma key (green screen) with tolerance/softness + spill suppression
AI background removal (person cut-out, in-browser via MediaPipe)
Motion
Keyframe animation on ~25 properties with easing
Keyframe markers on clips — diamonds on the clip body at each unique keyframe time (tooltip lists channels; a count badge when several share a time). Ctrl/Cmd+← / Ctrl/Cmd+→ jumps the playhead to the previous / next keyframe (selected clips first, else clips under the playhead). Inspector fields show the interpolated value at the playhead; changing one updates the keyframe you’re on, or inserts one if that channel is already keyed. Dragging a clip in the program monitor (move / scale / rotate) writes the same way. The ◆ button adds a keyframe at the playhead, or removes the one you’re parked on; ✕ clears the whole channel. When the playhead is outside the selected clip, keyframed fields and ◆ buttons are disabled (they show the nearest edge value) — keyframe edits only apply where the playhead actually is; unanimated properties stay editable anywhere
Keyframe graphs — toggle a property’s curve in the inspector to show an interpolated value graph beside the program monitor; click the graph to seek
Speed ramps — keyframe
speedand the engine time-remaps video and the export audio mix (the fast-into-slow-mo reel move)Camera shake and RGB-split/chromatic aberration, both animatable
17 transitions: fades, slides, wipes (4 directions), zoom, iris, spin, blur, whip-pan, glitch, pop
Text
Title styles — one-tap cohesive looks (Impact, Elegant, Kinetic cut, Neon, Handwritten, Luxury, and more); new titles vary the font, placement and animation automatically instead of defaulting to one flat style
Kinetic captions: typewriter, word-pop, word-slide, karaoke, letter-pop, wave, bounce, shake, clip-reveal, zoom-in, font-cut (rhythmic typeface cuts), rise-mask
Neon glow for that TikTok caption look
Font editor: system fonts, drop-in custom fonts (
library/fonts/), and any Google Font by name — loaded automaticallyGradient fills, outline, background pills, letter-spacing, line-height, weights, italic, uppercase, soft shadows
Text layout — horizontal Align: left / center / right / justify (extra spaces between words). Drag a title’s corner handles to create a text box (
boxW/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 to0to return to hug-content sizing.
Animated SVG clips
A first-class
svgclip 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.svgfiles. Starters included.
Remake a reference video
Give it a reference edit (a reel you like) and get back an edit blueprint: shot boundaries, music beats + BPM, a loudness curve, per-shot energy, the drop — plus the reference's music track extracted into your media, ready to rebuild the same idea with your own footage. Zero extra dependencies (ffmpeg does the decoding; onset/tempo detection is plain Node).
node analyze.js ref.mp4,POST /api/analyze, or thefablecut_analyze_referenceMCP tool.
Look at the footage
An agent (or you, over REST) can fetch an actual image of any moment:
GET /api/frame?src=/media/x.mp4&t=3.2returns a JPEG of that frame, and&frames=12returns a 4×3 contact sheet across the clip — a cheap survey of everything a 3-minute take holds. Grabs are cached underanalysis/frames/.The
fablecut_frameMCP tool wraps it and returns the image inline, so a multimodal model can look. Pass atimeinstead of apathand 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.Together with the analyzer above, agents pick footage by looking at it instead of guessing from an energy number.
Asset library
library/folders surface as tabs in the UI: Elements (overlay art), Sound FX, SVG — drop files in, the open editor refreshes live
Export
Delivery presets: YouTube, YouTube Shorts, Instagram Reels, TikTok, X, LinkedIn, Master, Broadcast (ProRes 422 HQ), Web, Archive (lossless FFV1) and Custom. Every setting is a control: resolution and reframing (crop, fit or stretch to another shape), frame rate, codec (H.264, HEVC, AV1, VP9, ProRes, DNxHR, XDCAM HD422, FFV1) and hardware encoder, CRF / VBR / CBR, max rate, keyframe interval, pixel format, color, container, audio codec, bitrate and rate, loudness normalization (−14 / −16 / −23 / −24 LUFS with a true-peak ceiling), a file-name template and metadata. Save your own presets; the dialog warns about upscaling, crops and platform limits before it renders, and every finished file is read back and checked — size, frame rate, frame count, codecs, length, loudness, true peak and file size
Batch export: one project → many files (master, YouTube 1080p, a 9:16 reel, a square, a 720p preview…) from one render per frame rate and range (up to 8 outputs each) — every frame is drawn once and each output's ffmpeg encodes it. Batch outputs are saved with the project; an export queue runs them back to back with progress, stop, retry and open
Fast export: browser renders every frame + an offline audio mix; ffmpeg encodes them with a delivery preset, or a raw encoding profile from
encoding-profiles.json(keeps rendering if you switch tabs). Encode and upload run ahead of the compositor so a fast timeline is not stalled bytoBlobWebCodecs export: the browser HW-encodes Annex-B H.264; the server stream-copies and muxes audio. Faster uploads; bitrate/VBR-CBR in the Export dialog. Unavailable while an export frame is set (use Fast)
Realtime MediaRecorder fallback when ffmpeg or WebCodecs isn't available
Agents export too:
fablecut_exportruns the Fast export in the open editor, or in a headless Chrome / Edge the server starts, and returns the file path;presetanddeliverypick and adjust a delivery preset;outputsmakes several files in one goExport Range dropdown: Entire timeline or IN–OUT (defaults to IN–OUT when markers are set). Effective IN/OUT export bounds are clamped to
projDur().
Quick start
npx -y fablecut # → http://localhost:7777Your projects, media and exports go to ~/FableCut. Or run it from a clone:
git clone https://github.com/ronak-create/FableCut.git
cd FableCut
node server.js # → http://localhost:7777Requirements: 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.
Or install it as a Claude Code plugin
/plugin marketplace add ronak-create/FableCut
/plugin install fablecut@fablecutThat 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.
Driving it with an AI agent
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:
claude mcp add -s user fablecut -- npx -y fablecut mcpNo clone or path needed; your work lives in
~/FableCut. From a clone, point at the file instead:claude mcp add -s user fablecut -- node "<path-to>/fablecut/mcp-server.js"OpenCode can use the same stdio server from its project or global
opencode.jsonconfiguration:{ "$schema": "https://opencode.ai/config.json", "mcp": { "fablecut": { "type": "local", "command": ["node", "/absolute/path/to/FableCut/mcp-server.js"], "enabled": true } } }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:
{ "name": "fablecut", "transport": "stdio", "command": "npx", "args": ["-y", "fablecut", "mcp"] }(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, bumprevision, 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.
Project layout
server.js zero-dependency HTTP server: static hosting, REST API, SSE,
ffmpeg export pipeline
app.js the editor: timeline UI, compositor, keyframes, text engine,
SVG rasterizer, chroma key, exporters
index.html single-page UI
style.css dark editor theme
mcp-server.js stdio MCP server exposing the editor to AI agents
analyze.js reference-video analyzer: shots, beats/BPM, energy, drop,
music extraction (module + CLI)
CLAUDE.md the agent manual (schema + recipes) — also served by fablecut_docs
encoding-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)Architecture Overview
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_ui
node_ai_agent -->|"sends tools"| node_mcp_server
node_browser_ui -->|"updates project"| node_timeline_model
node_timeline_model -->|"persists JSON"| node_project_store
node_browser_ui -->|"calls REST"| node_rest_api
node_rest_api -->|"reads writes"| node_project_store
node_rest_api -->|"serves media"| node_media_store
node_rest_api -->|"lists assets"| node_asset_library
node_mcp_server -->|"checks server"| node_rest_api
node_mcp_server -->|"patches project"| node_project_store
node_mcp_server -->|"imports media"| node_url_importer
node_url_importer -->|"stores downloads"| node_media_store
node_rest_api -->|"downloads URLs"| node_url_importer
node_rest_api -->|"broadcasts changes"| node_sse_hub
node_sse_hub -->|"pushes changes"| node_browser_ui
node_timeline_model -->|"renders timeline"| node_compositor
node_timeline_model -->|"routes clips"| node_audio_engine
node_audio_engine -->|"measures audio"| node_audio_meter
node_browser_ui -->|"uploads frames"| node_rest_api
node_rest_api -->|"streams export"| node_export_engine
node_export_engine -->|"loads profile"| node_encoding_profiles
node_export_engine -->|"encodes video"| node_ffmpeg
node_reference_analyzer -->|"analyzes media"| node_ffmpeg
node_reference_analyzer -->|"writes music"| node_media_store
node_ai_agent -.->|"requests analysis"| node_reference_analyzer
node_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:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_browser_ui,node_timeline_model,node_ruler_worker toneBlue
class node_project_store,node_media_store,node_asset_library,node_url_importer toneAmber
class node_rest_api,node_mcp_server,node_sse_hub toneMint
class node_compositor,node_audio_engine,node_audio_meter,node_export_engine,node_encoding_profiles toneRose
class node_reference_analyzer,node_human,node_ai_agent,node_ffmpeg toneIndigoAuthoring animated SVG overlays
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/.
Notes
The repo ships with 20 Google Fonts (
library/fonts/, OFL — seeLICENSES.mdthere) 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.mdlists good free sources.Export runs in the browser because the compositor is the browser; agents ask you to click Export (or render directly with ffmpeg from
media/).
Community
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 hello@fablecut.space, or support@fablecut.space for help.
License
Available Tools
24 toolsfablecut_analyze_referenceA
Analyze 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.
Inputs: path (required), threshold, registerMusic.
fablecut_auto_duckA
Duck 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.
Inputs: clipIds (required), force, under, amount, +3 more.
fablecut_beatsA
The 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.
Inputs: clipId (required), snap, every, force, +2 more.
fablecut_captionsA
Captions 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.
Inputs: to, from, size, force, +12 more.
fablecut_denoiseA
Reduce 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.
Inputs: clipIds (required), force, amount.
fablecut_docsA
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.
Inputs: section.
fablecut_encode_profilesA
List 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.
Inputs: detail, preset, profile.
fablecut_exportA
Render 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.
Inputs: job, wait, range, where, +6 more.
fablecut_frameA
LOOK 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).
Inputs: t, to, cols, from, +7 more.
fablecut_get_projectA
Get 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.
Inputs: compact.
fablecut_highlightsA
The 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.
Inputs: name, shot, aspect, clipIds, +2 more.
fablecut_import_mediaA
Import 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).
Inputs: path (required).
fablecut_normalize_audioA
Loudness-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.
Inputs: clipIds (required), mode, force, target.
fablecut_patch_projectA
Apply 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 setTrack out) · {op:'removeBus', id} · {op:'setFx', target:'clip'|'track'|'bus'|'master', id?, preset?:'podcast'|… OR fx:[{type,…params}], append?:true} (audio effects — validated; presets: clean-voice, podcast, radio, deep-voice, telephone, cinematic, wide, muffled; fx:null clears; on a clip it applies to its linked stems too) · {op:'setFxKeys', target, id?, index?|type?, param, keys:[{t, v, ease?}]|null} (automate one effect parameter: t is clip-local for a clip's effects, timeline seconds otherwise; see the 'Audio mix' docs section) · {op:'setGrade', id | ids:[…], grade:{exposure?, temp?, tint?, lift?, gamma?, gain?, offset?, contrast?, pivot?, blacks?, shadows?, midtones?, highlights?, whites?, lowSoft?, highSoft?, saturation?, curves?:{y?, r?, g?, b?}, hueHue?, hueSat?, hueLuma?, satLuma?, layers?:[…], on?}, replace?:true} (color grade on video / image / svg / adjust clips — wheels are [r, g, b, master]; curves are [[x, y], …] point lists on 0…1 and merge per channel; hue curves are [[hue°, value], …] — one point = a ±40° band; layers replaces the whole layer list; merges key by key, null resets a key, replace:true starts from neutral, grade:null clears; see the 'Color' docs section; measure the result with fablecut_scopes) · {op:'setGradeLayer', id | ids, layer: index | 'name', set:{name?, on?, qualifier?:{hue?:[centre°, width°, soft°], sat?:[lo, hi, soft], luma?:[lo, hi, soft], invert?}, mask?:{shape:'ellipse'|'rect'|'poly', x, y, w, h, rotation?, feather?, invert?, points?, keys?:[{t, x?, y?, …}]}, …any grade key}, replace?:true, remove?:true} (a secondary: a grade applied only where the qualifier × mask select; a new name or index = length adds a layer; qualifier and mask merge key by key; check what it selects with fablecut_scopes matte:{clip, layer}) · {op:'setMask', id | ids, mask?: index | 'name', set:{shape?:'rect'|'ellipse'|'bezier'|'freehand', mode?:'add'|'subtract'|'intersect'|'difference', invert?, opacity?, feather? (px), expand? (px, − shrinks), x?, y? (centre, 0…1 of the clip's picture), w?, h?, scale?, rotation?, points?:[[dx, dy, inX?, inY?, outX?, outY?], …] (bezier, around x, y), stroke?:[[u, v], …] (freehand: fitted into a bezier), keys?:[{t, ease?, x?, y?, w?, h?, scale?, rotation?, feather?, expand?, opacity?, points?}], name?, on?}, replace?:true, remove?:true} (clip masks on video / image / svg / text / adjust clips: the clip shows only where its masks combine to, bottom-up; mask left out, an unknown name or index = length adds one — a new mask needs shape; set merges key by key; masks follow the clip's transform; check with fablecut_scopes mask:{clip}) · {op:'removeMask', id, mask} · {op:'setMaskKeys', id, mask, keys:[…]|null} (animate a mask; t = seconds from the clip's start) · {op:'setMatte', id | ids, matte:'alpha'|'alpha-inverted'|'luma'|'luma-inverted'|null, track?:'V3'|null} (track matte: the picture on the video track directly above — or track — cuts the clip by its alpha or its brightness, inverted or not; that track stops drawing while it is a matte; null clears). · {op:'removeTrack', id, track: name | index} (delete a motion track stored by fablecut_track; what follows it keeps its keys). MOTION GRAPHICS: a shape layer is addClip {kind:'shape', track, start, duration, props:{shapes:[…]}} (no mediaId); a null is addClip {kind:'null', …} — invisible, a parent for other clips. {op:'setShape', id | ids, shape?: index | 'name' | '2.0' (path into a group), set:{type?:'rect'|'ellipse'|'polygon'|'star'|'line'|'path'|'group', name?, on?, x?, y? (px from the layer's origin), rotation?, scale?, opacity?, w?, h?, radius? (rect corners), sides?, inner? (star 0.05…1), points?:[[x, y, inX?, inY?, outX?, outY?], …] (line: 2, path: 2…128, px around x, y), closed? (path), fill?, stroke? ('#rrggbb' | '#rrggbbaa' | 'none'), strokeWidth?, lineCap?, lineJoin?, dash?:[on, off…], trimStart?, trimEnd? (0…100 — a draw-on), trimOffset?, items?:[…] (group), keys?:[{t, ease?, …any of x y rotation scale opacity w h radius inner strokeWidth trimStart trimEnd trimOffset fill stroke points}]}, replace?:true, remove?:true} (shape left out, an unknown name or index = length adds one — a new shape needs type; set merges key by key) · {op:'removeShape', id, shape} · {op:'setParent', id | ids, parent: clip id | null, keep?: true, at?} (the clip moves, turns and scales with its parent; keep:true — the default — keeps it where it is at time at, default its start; opacity and effects are not inherited). COMPOSITIONS (nested sequences): project.comps = [{id, name, width, height, duration, background?, tracks?, clips:[…]}]; a clip {kind:'comp', compId, start, in, duration} places one (draws like a picture of the comp's size — transform, masks, grade, blend, blur all apply — and its media plays and exports). {op:'addComp', comp:{id?, name, duration, width?, height?, background?, clips?:[…]}} · {op:'updateComp', id, set:{name?, width?, height?, duration?, background?, tracks?}} · {op:'removeComp', id} (refused while used) · {op:'precompose', ids:[…], name?, id?} (the clips move into a new comp; a comp clip takes their place) · {op:'inComp', comp, ops:[…]} (run clip and timeline ops on the comp's own clips — addClip, updateClip, setShape, split, …; nests). SEQUENCES (several timelines in one project — e.g. a 16:9 cut and a 9:16 cut sharing the media and comps; the open one is the top level of the document, which every op, export and the compact view use): {op:'addSequence', name?, from?:'empty'|'open'| (empty takes the open one's canvas and frame rate; a copy takes its whole timeline), width?, height?, fps?, open?:true} · {op:'openSequence', id} (changes what the user's editor shows — only when asked, or to work on it) · {op:'updateSequence', id, set:{name?, index?}} · {op:'removeSequence', id} (only when the user asked) · {op:'inSequence', sequence, ops:[…]} (run any clip, timeline, track or setProject op on a sequence without opening it). PRESETS AND TEMPLATES: {op:'applyPreset', id | ids, preset, length?, at?} keys a named animation onto visual clips, relative to where they sit (in: fade-in, pop-in, slide-up-in, slide-down-in, slide-left-in, slide-right-in, drop-in, zoom-in, spin-in, whip-in, rise-blur, draw-on · out: fade-out, pop-out, slide-up-out, slide-down-out, slide-left-out, slide-right-out, zoom-out, spin-out, whip-out, sink-blur, draw-off · at (an emphasis at timeline time at): pulse, shake, wobble, bounce, flash · loop (the whole clip): float, breathe, sway, spin, wiggle — or a saved one, or an inline {anchor:'in'|'out'|'at'|'whole', length, keys:{channel:[{t, v, ease?}]}} where scale / opacity multiply and the rest add). {op:'addTemplate', template, start?, track?, duration?, fields?:{key: value}, id?, compId?, name?} places a template as its own comp + a comp clip (lower-third-bar, lower-third-underline, lower-third-boxes [name, title, accent…] · logo-ring, logo-slam, logo-lines [logo = a media id, brand / tagline, accent] · social-story 1080x1920, social-quote 1080x1080, social-end-card [text fields, accent, background]); {op:'setTemplate', id: its clip or comp, fields?, duration?} changes the fields or the length (the exit keeps its timing). {op:'savePreset', id, name, anchor?} / {op:'saveTemplate', comp, name?, fields?} save to library/presets and library/templates for every project.MOTION PATHS: x and y keyed at the same time are a position key; curve handles pin / pout (px) on those x and y keys bend the path between keys ({op:'setMotionPath', id | ids, path:'smooth'|'straight', autoOrient?:bool} sets them for you; props.autoOrient turns the clip along its path). props.motionBlur = shutter angle 0…720 (180 = film look), props.motionBlurSamples 2…32. TEXT ON A PATH: {op:'setTextPath', id | ids, path:'line'|'arc'|'circle'|'wave'|{type:'path'|'line'|'ellipse'|'rect'|'polygon'|'star', …shape item geometry, keys?}|null, offset? (% along, keyable as pathOffset), align?:'start'|'center'|'end'} — the title runs along the path (more lines on parallel curves below it), every textAnim plays along it. Every visual clip also has props.anchorX / anchorY (px from its picture's centre: the point x / y place and rotation / scale turn around) and shape clips props.trimStart / trimEnd / trimOffset (trim every path in the layer) — all keyframable. props.blend: normal · multiply · screen · overlay · darken · lighten · color-dodge · color-burn · hard-light · soft-light · difference · exclusion · hue · saturation · color · luminosity · lighter. TIMELINE EDITS — the editor's own split / ripple / trim code, so linked stems, track targeting (untargetedTracks) and locks behave exactly as in the UI; times in seconds: {op:'split', at, ids?} (no ids: every targeted track) · {op:'rippleDelete', ids} (later clips close the hole) · {op:'closeGap', at} · {op:'lift'|'extract', from?, to?} (remove a range; extract closes it; default = project inPoint/outPoint, which then clear) · {op:'insert'|'overwrite', mediaId, at, in?, duration?} (three-point edit: insert pushes later clips right, overwrite replaces what is there; a video brings one audio stem per channel) · {op:'rippleTrim'|'roll', id, side:'in'|'out', delta} · {op:'slip'|'slide', id, delta} (clamped to the media; the note says what was applied) · {op:'crossfade', ids? | at, duration?} (constant-power audio crossfade, borrowing handles from both sides). Any of these takes tracks:[…] to target lanes for that op only. setProject also takes inPoint / outPoint. updateClip merge rules: top-level keys are replaced (keyframes/transitionIn/transitionOut wholesale), props merges key-by-key, and setting any key to null deletes it. LOCKS: the user can lock clips (locked:true) and tracks (lockedTracks); updateClip / removeClip on a locked clip — or on a clip linked to one — and addClip onto a locked track are refused. Leave locked material alone; only if the user asked you to change it, pass force:true on that op (or unlock first: updateClip set:{locked:null}, which is always allowed). All-or-nothing: an invalid op aborts the whole patch unsaved. Optional baseRevision: the revision your ops were planned against (from fablecut_get_project, fablecut_status or the previous patch result) — if the project has moved past it (e.g. the user edited in the UI meanwhile), the patch is refused with CONFLICT and the current revision, nothing saved; re-check the clips you touch, then retry with the new revision. Omit it to apply on top of whatever is latest.
Inputs: ops (required), baseRevision.
fablecut_projectsA
Several 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.
Inputs: id, fps, name, open, +7 more.
fablecut_proxyA
Proxies: 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.
Inputs: wait, create, delete, height, +2 more.
fablecut_reframeA
Reframe 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.
Inputs: name, force, aspect, follow, +2 more.
fablecut_scopesA
Measure 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.
Inputs: mask, time, matte, where, +1 more.
fablecut_set_projectA
Replace 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.
Inputs: project (required), force.
fablecut_silenceA
Find 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.
Inputs: clipIds (required), cut, force, tracks, +3 more.
fablecut_statusA
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.
Inputs: no named parameters.
fablecut_trackA
Follow 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.
Inputs: clip (required), at, to, name, +10 more.
fablecut_transcribeA
What 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.
Inputs: to, cut, find, from, +9 more.
fablecut_versionsA
A 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.
Inputs: to, name, note, final, +3 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 24 tools
Most tools have clearly distinct purposes: status/get/patch/set project, import, export, scopes, frame, transcription, captions, audio cleanup, reframing, highlights, tracking, proxies, versions, and projects are separable. The main ambiguity is that fablecut_patch_project is a very broad generic editing tool whose surface overlaps specialized tools like silence cutting, captions, reframe, tracking, and audio effects, though the specialized descriptions generally clarify when to use them.
All tools use the fablecut_ prefix and snake_case, giving a predictable namespace. However, action naming is mixed: some are verb_noun (get_project, set_project, import_media, analyze_reference) while others are noun/feature names (status, silence, beats, captions, highlights, docs).
Twenty-four tools is on the heavy side, but the server is a full video editor with many distinct workflows. Each tool maps to a recognizable capability, so the count is reasonable though slightly over a compact ideal.
The surface covers project lifecycle, media import, timeline inspection and editing, audio processing, transcription and captions, export and encoding, measurement, tracking, reframing, highlights, proxies, versions, and multi-project management. There are no obvious domain-level dead ends for an agent editing video through this server.
Maintenance
Related MCP Connectors
The agentic video editor for ChatGPT and Claude. Ask in your chat and it cuts, captions, adds music, titles and motion graphics on a real timeline you can open and adjust.
AI video editor your agent can drive: plan scenes, edit a multi-track timeline, and render MP4s.
A video editor in your browser that your AI drives: cuts, captions, multicam, motion titles, export.
Orccut: a real timeline video editor for AI agents - journaled edits, FFmpeg/MLT rendering
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn async video generation MCP server with multi-provider support. Currently in skeleton phase with stub implementations, it will eventually enable video generation through providers like Veo 3.1, Grok Imagine Video, and Sora 2 Pro.MIT
- AlicenseAqualityCmaintenanceMakes Claude a real operator for Adobe Premiere Pro 2025, providing 59 tools to control projects, timelines, media, exports, and even create cinematic intros with beat detection and style presets.59159 npmMIT
- AlicenseBqualityCmaintenanceLocal MCP server that uses Playwright browser automation to enable Claude Code to generate images, create variations, expand, and remove backgrounds via Adobe Firefly, requiring manual sign-in once.1123 npm1MIT
- AlicenseNot gradedqualityCmaintenanceA real video editor for AI agents, served over MCP, enabling journaled timeline editing, rendering via FFmpeg/MLT, and deterministic CLI operation.1MIT