by kurbaitaev
AI video editor for talking-head reels: 7 styles, face-safe captions, motion scenes, reverse-engineer any reference edit. A Claude Code / agent skill on HyperFrames.
From $49 · 30 days · terms & refunds
⚠️ Third-Party Software Notice
This skill is third-party open-source software developed and hosted independently on GitHub. SkillsLLM is an informational directory and does not control or maintain the underlying repository.
Any security checks, ratings, or warnings displayed by SkillsLLM are automated and limited in scope. They do not constitute a security certification or guarantee that the software is safe, error-free, or free from malicious code, vulnerabilities, compromised dependencies, or prompt-injection risks.
Review the source code, permissions, dependencies, and configuration before installing or running any third-party skill. Use is at your own risk. To the maximum extent permitted by applicable law, SkillsLLM is not liable for losses arising from third-party software.
Automated security scan — not a certification.
# Add to your Claude Code skills
git clone https://github.com/kurbaitaev/ghost-editorGuides for using ai agents skills like ghost-editor.
One recording in, one reel out. The creative work is choosing takes and planning beats. The scripts do everything else the same way every time: cut math, zoom tweens, captions, SFX levels, asset copying, QA. Nothing on screen says anything the speaker did not say. A meme is a reaction, so it lands ON or just AFTER the punchline, never before it.
Skill dir: ~/.claude/skills/ghost-editor (below: $S). A reel project is any
directory ($P); build.mjs copies what it needs into $P/assets so the
project renders on its own.
prep.sh -> $P/assets/talk.mp4 1080x1920 30 fps, voice at -16 LUFS
transcribe.py -> $P/build/words.whisper.json + take table (all takes)
face_track.py -> $P/build/face.json (captions and cards never cover the face)
choose takes -> $P/reel.json takes (references/take-selection.md)
plan beats -> $P/reel.json beats/zoom (references/reel-json.md; taste.py prompt first)
film_look.py / transitions.py reel optional: graded plate, transition windows (after takes are final)
build.mjs -> $P/index.html + SFX table + rule and taste warnings
approval_sheet.py -> build/approval.html lint, a frame at every cut and beat; WAIT for the user's yes
own_footage.py -> the user's own clips for the lines (face-checked: only them); `sheet` -> show the picked frames, WAIT for yes
insert_prep.py -> every B-roll insert: people + line check, cut, SDR, fps conform, graded onto the speaker's plate as shot (never the reverse)
components.py plan/check -> new components per reel for a named style (catalog.json); record after the user's yes
broll_vision.py picks -> build/broll-picks.jpg: every B-roll shot + stock image, its line, the people check; WAIT for the user's yes
render -> $P/build/reel.mp4
render_report.py -> pass/fail per check + fixes (runs broll_qa.py too); fix and re-render, at most 3 rounds
qa.py -> SFX-vs-voice on a stem, A/V lengths, contact sheet
deliver -> ~/Desktop/<name>-reel.mp4 taste.py log-reel; save_style.py if the user loved it
bash $S/scripts/doctor.sh: tools, GEMINI_API_KEY and the media library,
each with its fix. The B-roll people and line check (broll_vision.py, broll_qa.py) needs GEMINI_API_KEY (the free
tier is enough); without it those checks warn or fail as unchecked. On a fresh machine run python3 $S/scripts/library_restore.py
first (SFX, memes, music and the animated emoji aren't in git). Say what is missing; don't
improvise around it. Lines marked opt are optional tools with their own scripts/setup_<x>.sh
(BiRefNet matte, audio QA, film-look LUTs, caption metrics); the core works without them.
bash $S/scripts/prep.sh <IMG_xxxx.MOV> $P
ffmpeg -v error -i $P/assets/talk.mp4 -vf "fps=1/10,scale=216:384,tile=6x3" -frames:v 1 -update 1 $P/build/sheet.jpg
Look at the sheet. Check that it is the right person (show the frames
and confirm with the user when there is any doubt). Note where the face
sits (the zoom origin, default 50% 29%), where the chin is (the card band
starts at y 990), and how bright the wall is.
python3 $S/scripts/transcribe.py $P/assets/talk.mp4 --out $P/build/words.whisper.json --lang en
The table is the take map in original seconds; * marks restart phrases
("okay, again"). Fix mangled names later in captions.fixes.
python3 $S/scripts/face_track.py $P/assets/talk.mp4 --out $P/build/face.json
Always. The build places captions, cards and reactions around the face, inside the platform's safe area.
Crickets, hum, wind, traffic: bash $S/scripts/denoise.sh $P/assets/talk.mp4 $P/build/voice-clean.wav (DeepFilterNet3,
capped at 20 dB; full strength makes the voice thin and watery). Use the clean track for the cut and the captions.
Band-limited voice (Bluetooth mic, a call, a downloaded clip): voice_enhance.py IN OUT.wav --mode superres (ClearerVoice;
does nothing on full-band phone audio). Speech islands on noisy raw audio: vad_pauses.py / autocut.py --vad (silero-vad).
Both run in the audio QA venv (bash $S/scripts/setup_audioqa.sh prints its python).
references/take-selection.md)Ask for the script if there is one. Pick the take of each sentence that is
fluent and later, keep one-breath runs as one take, and cut on WORD times:
a = first word - 0.10..0.15, b = last word + 0.20..0.30. When a meme
will follow a line, end that take 0.6 to 1 s after the last word so the
meme sound has air. Aim for 45 to 75 s.
Audit the rough cut before building. Whisper merges restarts and false starts into one clean sentence and smears timestamps across them ("And even the… and even the thing that…"). Render the rough cut, re-transcribe THAT voice, and ask Gemini 2.5 Pro (analyze_video) for a verbatim audit: repeats, fillers, clipped words, breaths, look-aways. A long stretch of voice with few words in the transcript is a hidden retake. A throat-clear ("khm") shows up in a pitch scan as a short voiced hum with falling pitch; Gemini's sub-second timestamps are not reliable enough to cut on. Leave ~0.2 s of breath between sentences.
If the recording is already one good take, don't pick takes by hand:
python3 $S/scripts/autocut.py $P/assets/talk.mp4 --noise -30 prints takes with the pauses removed.
references/styles.md, references/reel-json.md)Seven presets: clean, editorial, meme, cinematic, launch, kinetic, pop.
Recipes (custom builds, not reel.json presets; each has its own README, SYSTEM.md and scripts). Follow the README end to end:
recipes/clean-os/, Clean OS: Apple-clean word cards, wide/tight from one 4K camera, literal phone-UI scenes
(date picker, lock-screen notifications, search + stalled loading bar, Photos memory), a red Figma selection box with a cursor.
Call: "Clean OS". Talking heads, reflective or explanatory.recipes/explainer-vector/, Vector explainer: no footage; an ElevenLabs narrator; one continuous SVG world a camera travels
through, a subject that draws itself, serif headlines, word-reveal captions. Call: "animated explainer", "like the tree video".recipes/result-podcast/, RESULT: warm podcast edit: one or two Inter Tight words with a two-tier emphasis, Caveat handwriting,
navy dust cards, polaroids, a stop-motion paper stack, film-burn leaks, comic props, dissolves between lines.
Call: "RESULT style".recipes/pov-montage/, POV montage: several first-person clips cut into a story with an edit list (speed-ups, freezes),
the editorial motion layer, a freeze-frame moment with a meme. Call: "cut these POV clips".recipes/seoul-list/, Seoul list (a format, not a footage source: the footage the user hands over first, then their
library, then stock or AI full screen; one world conformed to the main footage as shot, no posed stock models, the
people rules): a voice-over list of observations
over 1.4 s B-roll shots (no talking head); one big
word per line in Playfair Display Italic (mood, places) or Inter Tight 800 (facts) with a subline, white word flashes,
white collage pages (shot shrinks into a card, red glitch word, photo card, Fluent stickers), triptychs, an Instagram
comment card, a macOS frosted window swapping cut-outs, blue highlight words, an iMessage outro. Built from list.json +
proxies + the VO (build.mjs). Call: "Seoul list", "a list reel over B-roll". Read its SYSTEM.md first.recipes/stan-style/, stan style (NEEDS real screen recordings of the tool; without them say so and propose Clean OS
or RESULT): a seated talking-head tool tutorial on the core pipeline (reel.json beats from
scripts/lib/stan.mjs): panel (a screen recording in the top band, behind the speaker's BiRefNet cut-out; the speaker moves down only
as far as their eyes need, once per run of panels), chest captions (small lowercase phrases at 68 % that cut on their first word; single
words in the hook and the diagram, forehead words near the end), a hook card (icon rows + black-on-white strip title),
one white diagram with drawn-on lines entered by a zoom-blur, step and cta labels under the chin, aside.
Call: "stan style", "tool tutorial". Read its SYSTEM.md first.
The visual inventory of every style (playing loops, soundboard, rules) is docs/PLAYBOOK.md.
Check the style's prerequisite before planning (references/broll.md section 6): stan style needs real screen
recordings, cinematic needs one consistent world of footage. If it is missing, say what is missing and propose another
style; never fill the gap with stock. Seoul list has no footage prerequisite: it is a format (its README
"Footage").
Ask the user which one (show examples/gallery/ or the showcase video) or pick by
the speaker's energy. Start from examples/gallery/<style>.reel.json.
To match a reference edit: python3 $S/scripts/reference_study.py <their-edit.mp4> --out <dir> [--raw <raw>]
writes a 1 fps contact sheet, full-res frames every 2 s and Gemini 2.5 Pro's
second-by-second edit log with a mapping onto our beats. Treat the log as a
draft: verify type, sizes and framing against the frames. Then map every scene
to a word time. Start from the closest file in examples/.
Walk the transcript sentence by sentence. For each one, ask what the speaker
just made the viewer imagine, and show it on the word. Leave some sentences bare;
silence in the band makes the next card land.
B-roll (references/broll.md; broll_qa.py fails the render past these):people-rules.json (empty by default; the user sets what their channel needs, e.g.
exclude women, children or symbols; people-rules.example.json). insert_prep.py refuses a shot that breaks one,
broll_vision.py picks shows the user every shot before the render (WAIT for their yes), and broll_qa.py fails
the render (people). Ask the user once whether they have rules; never invent any.match). Stock images in a
frame, card or collage are welcome and beat several video cutaways.own_footage.py in their Photos library and footage folders and face-checked so
only they appear. Before the render, show them own_footage.py sheet and wait for their yes.recipes/<style>/house.json, the SYSTEM.md "House look" sections): type, captions,
accents and insert framing stay, and the speaker's face as shot. Never a grade on the face: house_look.py apply is
retired and broll_qa.py as_shot fails a regraded plate.components.py plan --style <s> (what the last 7 reels used
and what is free) and fill each slot with something unused; register new ones with components.py add (with a sig);
components.py check / broll_qa.py components warn on a repeat; after the user's yes components.py record.insert_prep.py --ref <plate as shot> --line "<the words under it>", which refuses a shot
that breaks the people rules or doesn't show the line, and grades the insert onto the speaker's plate.cover_windows.py labels them),
cheapest first: trim, tight-crop punch, hold the current graphic, framed insert, full-screen stock last. Memes: 1 to 3 per minute, on
punchlines, from the library:python3 $S/scripts/meme_find.py "the line with the punchline"
python3 $S/scripts/meme_find.py --list
If the library has nothing that fits, say so and offer to add one (step 9). Don't force a meme.
Read the taste first: python3 $S/scripts/taste.py prompt --style <style> lists every correction the user has made across
reels ("you said") and the rules the skill learned ("skill rule"). The build fills its defaults and warns on the rest; plan with them.
v0.3 building blocks (all in references/reel-json.md; restraint still rules: one or two per minute each):
captions.style = hype, explosive, line-focus, neo-minimal, karaoke-fill, highlighter
(one keyword per phrase: heuristic, keywords, or ai: true).textfx beats hook (the first 1.5-3 s), drum (lists, "round and round"), scramble, flipstack, headline
(+ swap for "not X -> Y"), spring (section titles). Give each a to; the build warns on a short reading hold.bg: {"look": "ink-warp"}), the word scene, look.shader film-grain/halftone overlays.name is in library/emoji (size <= 280).transitions at take changes (transitions.py reel $P; hard cuts stay the default, at most 2 punchy ones per reel).look.film film stocks baked into the plate (film_look.py apply ... --look vision3_500t; check one still first).matte: true + behind beats: BiRefNet cut-out, only for the behind seconds (~4-5 min per word); front: true puts the
word over the speaker, through: true slides it through the head (behind on one side, in front on the other).cutout beats (scripts/cutout_fx.py, BiRefNet in the matte venv; references/cutout-fx.md): bg-swap (new place, light wrap
look.cutout. Covers: cover -> build/cover-9x16.jpg + cover-16x9.jpg on the approval sheet. At most 2 cutout beats per reel.node $S/scripts/build.mjs $P
Read its output: the edit timeline (a missing word means a cut inside it), the caption text, the SFX table (time, sound, role, volume, why) and the WARNINGS. Fix every warning in reel.json or explain why it stays.
python3 $S/scripts/approval_sheet.py $P [--upstream <cut list of a pre-cut source>] --open
It rebuilds, lints (0 errors required; sub-composition/track-density warnings are fine), runs the taste checks and
snapshots the first frame, 1.5 s, just after every visible cut, each beat as it lands and fully built, and the end, into
one page (build/approval.html: contact sheet, timeline, takes, beats, captions, SFX, warnings). Look at it yourself first
and fix what is wrong (cards on the chin, text wrapping, a meme clipped by the edge, captions colliding with a card, a wrong
person). Then send the user the page and WAIT: they flag frames and paste a change list, or approve. After their yes:
approval_sheet.py $P --mark-approved. For a quick look without the page: npx hyperframes lint and
npx hyperframes snapshot --at <edit seconds> (edit seconds = the take's edit start + (original t - take a)).
npx hyperframes render -o build/reel.mp4 --quiet
python3 $S/scripts/render_report.py $P build/reel.mp4 # build/render-report.json + .html, exit 1 on a failure
python3 $S/scripts/qa.py $P build/reel.mp4 # SFX stem levels, A/V lengths, matte, transitions, shader flicker
The report checks streams, duration, A/V alignment, loudness, black frames, a frozen speaker, silences inside the speech
(mapped to the take), caption safe area, the first 1.5 s and the SFX levels, each failure with a fix. It also runs
broll_qa.py (the B-roll and motion checks). Run that on its own for custom builds without reel.json:
python3 $S/scripts/broll_qa.py build/reel.mp4 --project $P [--profile talking-head|broll-led|graphics].
QA renders an SFX-only stem and prints each hit's peak against the voice
and its role target. Targets: ui ≈ -14, whoosh -12, impact -8, meme -3 dB
vs voice p95 peak; flags anything louder than the voice or inaudible. It
also checks loudness (-16 ±1.5 LUFS, TP ≤ -0.5), silences > 0.8 s inside
the speech, and writes build/contact.jpg. It never adds gain.
Copy to ~/Desktop/<name>-reel.mp4 (plus a 720p preview under 30 MB if
asked). Handover: the takes chosen (original seconds and why), the beats and
memes in plain words, the SFX count per minute, anything QA flagged, and the
obvious follow-ups (music from the platform's library at post time, a
different meme, the URL for the end card). Then python3 $S/scripts/taste.py log-reel $P --verdict shipped; if the user
loved the look, offer python3 $S/scripts/save_style.py $P <name> --best-for "...".
python3 $S/scripts/trends.py # what's new on imgflip / Know Your Meme, what we lack
python3 $S/scripts/meme_add.py <id> <url|file> --tags ... --use ... --triggers ... --trend hot
python3 $S/scripts/sfx_fetch.py --only <id> --force # after editing KIT in sfx_fetch.py
python3 $S/scripts/audition.py --open # soundboard + meme wall for a human listen
Always look at a new meme's preview.png before using it. Sounds with a
review flag in the manifest have not been confirmed by ear.
references/sound-and-memes.md has the mixing reasoning, sources, licences
and the dead ends not to retry. Animated emoji: python3 -I $S/scripts/emoji_fetch.py (library/emoji, Fluent, MIT).
When the user corrects an edit decision ("too many zooms", "that sound is cheesy"), fix the reel AND record it in their words:
python3 $S/scripts/taste.py add "<what they said>" [--metric punch_ins --max 2 | --set captions.size=50 | --ban-sfx riser-1] --reel <project>.
Only the user's own feedback is from: user (quoted "you said"); a rule you learned yourself is --from skill. taste.py list,
forget <id>, restore <id>, tag <id> user|skill. Taste is a prior: reel.json always wins.
B-roll is the user's world, framed and graded, or nothing (an audit of 29 reels; references/broll.md). Reels went wrong in these ways:
One reel at a time through approval_sheet.py; never batch-render a wave of styles without a sheet per reel (7 styles rendered from one template in 7 minutes came out with 0-2 approval files).
The speaker's plate must cover the whole reel: a talking-head clip that ends at the voice's length leaves the reel's
tail (music fade, 0.3-0.5 s) black, which flashes at Instagram's loop point. Give the plate a held
last frame (tpad=stop_mode=clone) and run it to the end; check the last 0.4 s of every render.
Run hyperframes render as a tracked background job, never nohup ... & from a tool shell: when the parent shell exits
the render cancels itself (render_cancelled_parent_exited). Masters with animated grain can come out as 10-bit HEVC at
~50 Mbit/s: deliver H.264 8-bit capped near 12 Mbit/s.
A style is a SYSTEM, not a template. When breaking down a reference, write the invariants (what makes it the style),
the house look (house.json: what stays fixed reel to reel), the content slots (what follows the script), a
generator per slot, and a catalog of used components (catalog.json, read and written by scripts/components.py;
see recipes/clean-os/SYSTEM.md section 5).
Transcribe the whole recording; choose takes from the table, never by scrubbing.
Cut on word times, never whisper segment times.
Snap zooms, not crossfades, between takes of the same sentence.
Voice loudness is fixed in prep, before SFX. Never lift the finished mix.
SFX level is relative to this voice (build measures it). Never hand-tune data-volume.
A meme sound never sits on top of a word. Give it a pause.
No meme sound twice in one reel. Meme sounds: 1 to 3 per minute.
One card in the band and one thing in the reaction slot at a time.
No em dashes in on-screen text.
Meme sounds and green-screen clips from the internet are usually other people's media: the user adds them at their own risk (fine for many IG and TikTok reactions, not for YouTube Content ID). Say so if the user mentions YouTube.
Shoot or prefer 4K: one camera gives a wide and a tight shot with no upscaling. No 720p B-roll; on Mixkit only clips offered in 2160p carry the free commercial licence. Your own unused frames are often the best B-roll.
HyperFrames: anything tweened more than once gets fromTo with explicit values (a bare to() locks a stale start value
depending on the renderer's seek order). Grow SVG shapes with attr, not scale transforms. Every <video> needs an id.
Lint, then snapshot every beat and look at it, before every render.
Light accent colours (lime, yellow) need dark text on pills and tags: brand.onAccent.
Music ducks under every spoken line (music.duck); under a freeze it nearly disappears. The QA SFX stem excludes the bed.
Calibration (6 top reels): 113 of 119 transitions are hard cuts, median shot ~3 s, audible SFX 0.4-0.9 per 10 s on graphics (not on cuts), B-roll 20-35 % of runtime. Default to restraint.
Hide jump cuts with short dissolves (0.2 s) or a shot-size change, not a zoom on every cut; the user found per-cut zooms annoying (at most three comic punch-ins per reel). Before cutting, build an attempt log of the WHOLE raw take with Gemini 2.5 Pro.
Hide each caption with an explicit fromTo placed after its fade-in; a bare set inside the fade gets overridden.
The person matte rebuilds itself when talk.mp4 or the behind beats change (signature in assets/talk-matte.json). On the u2net fallback (no matte venv), delete assets/talk-matte.webm after a re-cut or old cut-outs float over the new footage.
Cutting picture and voice separately (Clean OS, POV montage): snap every segment to the frame grid and cut both at the same
snapped times; otherwise each piece rounds to whole frames and the voice drifts early (43-54 ms by the end of a 23-piece cut).
qa.py --av-only checks lengths; tests/test_assemble_sync.py is the regression test.
HyperFrames clip times for footage (takes, holds, matte, transition and cutout windows) are frame counts / fps TRUNCATED
to 6 decimals (fgrid in build.mjs), never rounded: the renderer snaps a start only within 0.001 frame and samples a
video at floor((t - start) x fps), so 0.067 for 2/30 shows the clip a frame late and 0.066667 repeats its first frame.
An ffmpeg window cut to match (cutout_fx.py) takes -ss as the exact frame time to 6 decimals and -t half a frame short.
Per-letter or per-shader motion is a pure function of the timeline time (painters, the hf-seek event), never rAF or a
chain of tweens. Animated emoji are WebM <video>, never APNG <img> (APNG animates on the wall clock).
APIs: ElevenLabs through the direct key in .env (the MCP connector's grant budget runs out); Gemini 2.5 Pro for long video (Flash truncates), key checked with one call first; yt-dlp >= 2026.08.19 for YouTube; never pass Instagram cookies.
scripts/prep.sh transcode + voice loudnormscripts/transcribe.py whisper (PATH) → words json + take tablescripts/build.mjs reel.json → HyperFrames index.html, SFX mixing and rulesscripts/qa.py render QA with SFX stem level check, A/V lengths (--av-only), matte, transitions, shader flickerscripts/broll_qa.py B-roll and motion QA (budgets, grade, graphics motion, captions via ocr_text.js / macOS Vision,
faces covered, stock inside a frame, own footage only the speaker, no posed stock models, people rules and line match
(broll_vision.py, Gemini), the speaker's face as shot, 1080p sources, one world and shot pace for B-roll-led styles, freezes,
HDR, keyframes); scripts/broll_vision.py the people / line check and the pick sheet;
scripts/own_footage.py the user's own footage (index + Gemini tags, face check, confirmation sheet; library/me/ stays local);
people-rules.json the configurable B-roll people rules (empty by default; people-rules.example.json);
recipes/<style>/house.json the fixed house look per style (scripts/house_look.py measures; never applied to the face); scripts/insert_prep.py + scripts/grade_lib.py insert cut + SDR + fps +
grade conform; scripts/cover_windows.py / plan_cut.py keep-or-cover verdict per off-lens window; references/broll.mdscripts/sfx_fetch.py build/refresh the SFX kit (Mixkit), normalized, manifestscripts/meme_add.py add a meme clip/still (key, crop, alpha WebM, preview)scripts/meme_find.py shortlist memes and meme sounds for a linescripts/trends.py trending meme names not yet in the libraryscripts/audition.py HTML soundboard + meme wallscripts/doctor.sh checks tools, key and library, with fixesscripts/reference_study.py reverse-engineer a reference edit (sheet, frames, Gemini edit log)references/reference-study-prompt.md the edit-log prompt (improve it here)examples/ real reel.json files from shipped reels (English): one per preset in examples/gallery/, two motion editsREADME.md install, agent setup (Claude Code / Codex / any agent), quick startscripts/lib/motion.mjs scenes (card, stats, fly3d, image, sentence), scene transitions, editorial captions, music bedscripts/autocut.py pause-trimmed takes for a single clean takescripts/broll_gen.py AI still B-roll with Gemini (9:16), needs GEMINI_API_KEYscripts/tts_elevenlabs.py narrator voiceover with word timings (ElevenLabs, takes by seed)scripts/denoise.sh DeepFilterNet3 speech denoise, capped at 20 dB (sets up its own py3.11 venv)recipes/<name>/ named styles beyond the presets (README + SYSTEM.md + scripts; an English worked example for the
vector explainer, Seoul list and stan style)docs/PLAYBOOK.md every style, toolkit and rule in one place (the shareable inventory)library/music/ licensed music beds + manifestlibrary/sfx/ kit + manifest.json; library/memes/<id>/ clips + meta.jsontemplates/fonts/ Geist, Inter, Inter Tight, Playfair Display, Montserrat, Oswald, Unbounded, JetBrains Mono (OFL, latin + cyrillic woff2)references/reel-json.md the spec and beat typesreferences/take-selection.md choosing takes (adapted from mariagorskikh/talking-head-reel, MIT)references/sound-and-memes.md mixing, sources, licences, dead endsscripts/lib/caption-templates.mjs (+ metrics.json, ai-tag.mjs) six caption templates; scripts/font_metrics.py regenerates the metricsscripts/lib/stan.mjs stan style blocks (panel, hook, diagram, step, cta, aside) and the chest captionsscripts/lib/kinetic.mjs textfx blocks; scripts/lib/shader-layer.mjs + templates/vendor/hf-paper.js shader looks; scripts/lib/emoji-pop.mjs + scripts/emoji_fetch.py Fluent emojiscripts/transitions.py, scripts/film_look.py, scripts/gen_luts.py transitions and film stocks (LUTs in library/luts)scripts/matte.py BiRefNet person matte; scripts/vad_pauses.py, scripts/voice_enhance.py audio QAscripts/cutout_fx.py BiRefNet effects (cutout beats, look.cutout, covers, model demos on stills); references/cutout-fx.md;
tests/test_cutout_fx.py (fake model, no GPU: every effect, the frame grid, release); tests/test_decode_levels.py
(RGB decode matches the BT.709 spec, a decode -> Writer round trip keeps the levels)scripts/approval_sheet.py, scripts/render_report.py, scripts/taste.py (+ lib/taste.mjs, taste.json), scripts/save_style.py workflowscripts/setup_{captions,looks,matte,audioqa}.sh the optional venvs; docs/THIRD_PARTY/ sources and licences per packLast scanned: 9/25/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-09-25T09:26:19.989Z",
"npmAuditRan": true,
"pipAuditRan": true,
"promptInjectionRan": true
}See how ghost-editor compares with popular alternatives.
An AI video editor that lives inside your coding agent. Send it a raw video of yourself talking to camera. Get back a finished reel for Instagram, TikTok or YouTube Shorts.
Same raw recording. On the left, the edit I paid a human editor for. On the right, ghost-editor after seeing that edit once.
https://github.com/user-attachments/assets/312f6910-a8a0-4424-9dd4-612cd079a2e7
Two new named styles
B-roll that behaves
people-rules.json. Every stock clip, stock image and backdrop is checked against them, and you see a pick sheet before anything renders. The rules are empty by default; nothing is assumed.Everything else since v0.2
Seven presets. One word in the request:
| style | feels like |
|---|---|
clean |
bold captions, quick zooms, nothing distracting |
editorial |
soft lowercase captions and full-screen stats, like a news explainer |
meme |
emoji, reactions and punchy sounds |
cinematic |
film look, black-and-white B-roll, elegant type |
launch |
app windows and phone chats, made for product launches |
kinetic |
big words flying across the screen, you in a small circle |
pop |
giant words behind you, bright colour blocks |
Six named styles. Each is a full recipe in recipes/ with its own guide:
| style | ask for it | what it is |
|---|---|---|
| Clean OS | "edit this in Clean OS" | An Apple-ad talking head that lives inside your phone: calm word cards that sharpen out of a blur, wide and tight shots from one 4K camera, an iPhone scene for each thing you name, a red Figma box that strikes out the words you reject. |
| Vector explainer | "make an animated explainer" | No camera needed. A narrator tells the story while one continuous illustration draws itself and the camera travels through it. |
| RESULT | "edit this in RESULT style" | A warm podcast-style edit: one or two words at a time, handwritten key words, navy cards with film dust, polaroids, a stop-motion paper stack, film-burn light leaks. |
| POV montage | "cut these POV clips into a reel" | Clips from smart glasses or a GoPro cut into a story: a flash-forward hook, speed-ups, text behind you, and a freeze frame on the moment that matters. |
| Seoul list | "make a Seoul list" | A voice-over list over fast B-roll with big serif words, collage pages and an iMessage ending. |
| stan style | "edit this in stan style" | A tool tutorial with your screen recordings behind your head, chest captions and step labels. Needs real screen recordings. |
The vector explainer:
https://github.com/user-attachments/assets/9d4208d6-a9eb-400f-8a8d-c3b1fbe5dfb9
Or show it a reel you love. It studies how that video was edited (the cuts, captions, animations and sounds) and edits yours the same way. Like the result? Ask it to save the look as your own style.
Everything the skill can do, in one page: docs/PLAYBOOK.md.
How long it takes on an M3 MacBook Air with 16 GB (measured on the release test, 14 Oct 2026):
| step | time |
|---|---|
| one-time download of the sounds, music and emoji | about 3 min |
| transcribing a 30 s voice-over (Whisper turbo) | 25 s |
rendering a 21 s reel in the clean preset |
41 s |
| checking that reel (render report, B-roll check with Gemini, caption check) | 1.5 min |
| Seoul list, 29 s: a snapshot of every beat to approve, then the render | 2.5 min + 2.5 min |
| Seoul list: sound check and B-roll check of 33 shots | 4 min + 4.5 min |
| stan style: cutting your head out over ~15 s of screen panels (BiRefNet) | 23 min, once (about 3 s a frame) |
| stan style, 33 s: the render | 1.5 min |
Our estimate from these numbers: a 60 s talking-head reel takes roughly 15 to 25 minutes of machine time from raw take to checked video. Words behind you and stan-style panels add the slow cut-out (about 3 s per frame of the seconds involved); cut-out effect beats use a faster model (about 0.5 s per frame). Claude's planning and your approval come on top.
1. Install. Paste this into Claude Code:
Install the ghost-editor skill: clone https://github.com/kurbaitaev/ghost-editor into ~/.claude/skills/ghost-editor and follow its docs/INSTALL.md.
It installs everything it needs, asks for your Gemini key, and tells you when it's ready. The sounds, music and emoji take about 3 minutes to download; installing ffmpeg, Node and Whisper on a fresh Mac takes longer.
2. Edit. Start a new Claude Code session and say something like:
Edit ~/Downloads/my-video.mov into a reel in the
popstyle.
Make my video look like this reel: ~/Downloads/reel-i-love.mp4
Make a Seoul list from my voice note ~/Downloads/lisbon.m4a and the clips in ~/Movies/Lisbon.
Same video, but
cinematic, and make it safe for TikTok.
Does it cost anything? ghost-editor is free and open source (MIT). You need Claude Code, which needs a paid Claude plan. Everything renders on your computer. Gemini's free tier covers the B-roll checks for normal use; ElevenLabs is only for the narrated explainer.
What videos work best? Vertical phone videos of one person talking to camera, ideally 4K. Seoul list needs a voice-over and some clips; stan style needs screen recordings. It isn't made for landscape screen recordings on their own.
Where do the sounds and music come from? Mixkit's free library, downloaded t
ghost-editor is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by kurbaitaev. AI video editor for talking-head reels: 7 styles, face-safe captions, motion scenes, reverse-engineer any reference edit. A Claude Code / agent skill on HyperFrames. It has 77 GitHub stars.
Yes. ghost-editor passed SkillsLLM's automated security scan — a dependency vulnerability audit plus prompt-injection heuristics — with no high-severity issues. You can read the full report in the Security Report section on this page.
Clone the repository with "git clone https://github.com/kurbaitaev/ghost-editor" and add it to your Claude Code skills directory (see the Installation section above). ghost-editor ships a SKILL.md manifest, so compatible agents can discover and load it automatically.
ghost-editor is primarily written in Python. It is open-source under kurbaitaev on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh ghost-editor against similar tools.
No comments yet. Be the first to share your thoughts!