agentleFS
JakeschincariolJakeschincariol/master-skills/skills/edit/SKILL.md

edit

Skill1 starsChanged 39 days agoMITView on GitHub

Edit talking-head and short-form video end to end: cut dead space, ums and retakes, add word-timed captions, dynamic visuals and stop motion, then finish the audio at -14 LUFS and export for Reels, TikTok and Shorts. Combines the HyperFrames, Remotion and video-use editing skills with local ffmpeg tools. Use whenever someone wants to edit, cut, tighten or caption a video, or says "cut the dead space", "remove the silences", "cut the ums", "jump cuts", "add captions" or "subtitles", "make this a reel", "add b-roll" or "motion graphics", "make a stop motion", "fix my audio", or drops raw footage that needs to become postable.

  • Reads credentials
  • Installs packages

15 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use daily-arxiv, exp-eval and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • LambenthanSkill

    daily-arxiv

    每日从 arXiv 拉取新论文,过滤相关性,auto-ingest 高优先级论文,检测 SOTA 更新

    Also in 5 projects that use this

  • LambenthanSkill

    exp-eval

    实验判决门:Review LLM 独立评判实验结果 → 4 种判决路径 → 自动更新 claims confidence、ideas status、graph edges

    Also in 5 projects that use this

  • skyllwtSkill

    exp-pilot-eval

    Pilot result evaluation — read pilot results, apply success criteria, update idea page (pilot_result, failure_reason if failed), generate PILOT_VERDICT_REPORT. Called by /ideate Phase 5 after /exp-pilot-run.

    Also in 4 projects that use this

  • skyllwtSkill

    exp-pilot-run

    Pilot experiment execution — read Pilot Spec YAML, write pilot code, run experiment(Confirm with the user before operation and require the applicant to conduct manual inspection), return results. Called by /ideate Phase 5. Does NOT modify wiki pages or judge pass/fail.

    Also in 4 projects that use this

  • phanghonghaoSkill

    poster

    HTML/CSS A4 海报生成。从沙龙/活动 Markdown 文件生成科技风 A4 海报 PDF/PNG。Use when user mentions: poster, 海报, 海报生成, make poster, generate poster, 活动海报, 沙龙海报.

    Also in 4 projects that use this

  • +6 more from Lambenthan
  • +1 more from skyllwt

The file

Show its rules and text

We split this skill into the rules it gives an agent

13 rules. 0 are common, 7 are distinctive, and 6 are very specific to this project.

  • 0

    Common

    Most of the 13 edited versions we read keep these.

  • 7

    Distinctive

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Put every output in <footage folder>/edit/, never inside this skill's folder.

    line 41
  2. Very specific:

    No faster-whisper? Exit 3 with install steps.

    line 72
  3. Very specific:

    After rendering, edit/take.cut.words.json holds the words on the cut timeline.

    line 106
  4. Distinctive:

    Keep the face on screen during the hook (split screen or cutout), no slow push-in.

    line 112
  5. Very specific:

    Default look: UPPERCASE bold, white with a black outline, the spoken word in an accent colour (--accent), fillers hidden.

    line 128
  6. Very specific:

    Never over the face. Extract a still to check: ffmpeg -ss 3 -i edit/take.cut.mp4 -frames:v 1 edit/check.png.

    line 132
  7. Distinctive:

    No scanner effects: no light sweeps, sheens, glows, halos, pulse rings.

    line 163
  8. Distinctive:

    Every beat gets a different object, not one template repeated.

    line 168
  9. Distinctive:

    If peaks would be limited by more than about 6 dB, say so and offer -16 LUFS instead.

    line 225
  10. Distinctive:

    Before you show the user, check:

    line 238
  11. Distinctive:

    No audio: no dead-space cut.

    line 250
  12. Very specific:

    No libass: use the HyperFrames route (step 6).

    line 257
  13. Distinctive:

    No generative video or images are made here.

    line 266

“Common” is measured: kept by at least 6 in 10 of the 13 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Edit

You are the editor. This skill is an opinionated workflow plus small local tools (Python 3 standard library + ffmpeg). The tools do the measurable work: dead-space cuts, caption files, stop-motion timing, probing. You do the judgement: what to cut, what to show, when. For motion graphics you route to HyperFrames (default), Remotion, or video-use.

You cannot watch or listen. Measure, extract stills, read the transcript, and say plainly what you checked and what you could not.

Tools live in tools/ next to this file. Below, T means that folder: python3 "$T/deadspace.py" --help works for every tool. All tools exit 0 on success, 1 on an ffmpeg/runtime failure, 2 on bad input, 3 when a program or feature is missing.

ToolDoesWrites
probe.pymedia facts (rotation, VFR, HDR, audio layout, loudness); --doctor checks the machinestdout / JSON
deadspace.pycuts silences, plus fillers and retakes with a transcript; frame-accurate, crossfaded joins<name>.cut.mp4, .edl.json, .words.json
captions.pytranscribes (faster-whisper, optional) or reads word timings; 1-3 word phrases.srt, .ass, .cues.json, .words.json, .phrases.txt
stopmotion.pyframes folder or live clip to stop motion: 8/10/12 drawings/s, holds, seeded jitter.mp4

0. Setup check (once per session)

python3 "$T/probe.py" --doctor

It reports: ffmpeg filters (is ass/subtitles there for burned-in captions?), encoders, faster-whisper, and Node (HyperFrames needs Node 22+). Do not install anything without asking. Put every output in <footage folder>/edit/, never inside this skill's folder.

1. Brief, then a plan the user approves

Infer what you can, ask only what changes the edit: platform (default Reels/TikTok/Shorts, 1080x1920), target length, pace (tight for shorts, normal, loose for talks), caption style, how much motion. Then state the plan in 3 to 6 lines (what gets cut, caption style, which beats get visuals, the engine) and wait for an OK before rendering, unless the user said "just do it".

2. Probe

python3 "$T/probe.py" take.mov --loudness

Note the display size after rotation, fps and VFR, HDR, channels and loudness. The tools handle rotation (ffmpeg autorotates), VFR (deadspace renders constant frame rate), mono/stereo (kept as recorded) and HDR (kept as 10-bit HEVC with its tags). If there is no audio stream, dead-space cutting is impossible: say so and cut by hand from stills.

3. Transcribe once, read the take

python3 "$T/captions.py" take.mov --words-only --verbatim -o edit/
  • Writes edit/take.words.json (cached: reruns reuse it unless the file changed) and edit/take.phrases.txt, one timed line per phrase. Read phrases.txt; it is your view of the take at a fraction of the tokens.
  • --verbatim nudges Whisper to keep "um/uh" so they can be cut. Whisper still drops some, so never promise every filler is caught.
  • --model small is the default; use --model medium or large-v3 when words matter (finals, accents). --prompt "Claude, HyperFrames, Remotion" helps with names and brands.
  • No faster-whisper? Exit 3 with install steps. Any word-level JSON works instead via --words (ElevenLabs Scribe, Whisper, whisper.cpp, Deepgram, AssemblyAI, HyperFrames transcript.json), and SRT/VTT works with approximate word times.
  • Proofread names and brands in words.json by hand (keep the timings). A wrong word on screen is worse than no caption.

4. Cut the dead space (dry run, review, render)

python3 "$T/deadspace.py" take.mov -o edit/take.cut.mp4 --transcript edit/take.words.json --dry-run
# read the printed cuts and edit/take.cut.edl.json, then:
python3 "$T/deadspace.py" take.mov -o edit/take.cut.mp4 --from-edl edit/take.cut.edl.json

How it decides:

  • A 10 ms envelope with an adaptive gate: the noise floor is the 10th percentile, speech the loud frames, and the gate sits 30 dB under speech but never within 8 dB of the floor. It works on quiet phone takes and noisy rooms. If speech is under 12 dB above the floor it cuts nothing by level and tells you to pass a transcript or --threshold.
  • Pace presets (pause cut when longer than / air kept before speech / after speech): tight 0.25 / 0.06 / 0.10 s, normal 0.35 / 0.08 / 0.14 s, loose 0.60 / 0.12 / 0.22 s. A cut pause leaves about 0.2 s of air at normal: tight, never breathless.
  • With a transcript: fillers are cut with their gap, and repeated lines are cut so the last take wins (--retakes exact for stutters and false starts only, fuzzy (default) also catches a re-said sentence with small changes, off). Silence cuts never pass through a transcribed word that has real energy.
  • Joins: keep ranges snap to the frame grid, audio gets 30 ms equal-power crossfades (no clicks), and A/V stays in sync (the summary prints the drift, normally under 1 ms).

Review before rendering. The tool is mechanical: you read phrases.txt and also cut semantic retakes it missed (a line said twice with different words, a restart after "wait, let me redo that"). The EDL's cuts[] is the source of truth: set "apply": false to veto a cut, append {"start": s, "end": e, "reason": "manual"} to add one, then render with --from-edl. Keep the speaker's best delivery, keep laughs and reactions after punchlines.

After rendering, edit/take.cut.words.json holds the words on the cut timeline. Use it for captions and visuals; never re-transcribe the cut.

5. Pace and structure

  • Hook: the first 1 to 2 s land a concrete payoff (a number, money made or saved, the result). Keep the face on screen during the hook (split screen or cutout), no slow push-in.
  • Cut, don't hold: in a short, no shot runs past about 1.5 s; aim for a median shot of 1 s or less. A beat longer than that gets 2 or 3 genuinely different shots (a reframe of the same take counts, two moments of a locked camera do not).
  • Plan with a beat table keyed to the words: time, the noun being said, the visual. Measure the finished cut: ffmpeg -i final.mp4 -vf "select='gt(scene,0.25)',showinfo" -f null - 2>&1 | grep -o "pts_time:[0-9.]*" lists cut times; compute the median gap.

6. Captions

python3 "$T/captions.py" edit/take.cut.mp4 --words edit/take.cut.words.json -o edit/
  • 1 to 3 word phrases. They break after . ! ?, after commas once a phrase has 2 words, on pauses of 0.3 s or more, and at 18 characters. A phrase never ends on a weak opener ("the", "to", "a"), and a phrase too quick to read grows by a word.
  • Default look: UPPERCASE bold, white with a black outline, the spoken word in an accent colour (--accent), fillers hidden. The text bottom sits at y 1440 of 1920 (chest or collar) with 140 px side margins, so it stays inside the safe zone. --position seam --y 960 centres the captions on a split-screen seam, and --position top puts them under the header.
  • Never over the face. Extract a still to check: ffmpeg -ss 3 -i edit/take.cut.mp4 -frames:v 1 edit/check.png. If the chin sits low, move the captions with --y.
  • Burn in: --burn edit/captioned.mp4 works only when ffmpeg has libass. Without it, the tool exits 3 with the routes. HyperFrames route: render the captions in HyperFrames (/embedded-captions). Copy take.cut.words.json into that project as transcript.json; it uses the same {text, language_code, words[{text, start, end}]} shape, so the proofread words are reused instead of re-transcribed. For custom kinetic captions in any engine, feed take.cut.cues.json (phrases, per-word times, size, safe area). On macOS, an ffmpeg with libass comes from the homebrew-ffmpeg tap: brew uninstall ffmpeg, brew trust homebrew-ffmpeg/ffmpeg, brew tap homebrew-ffmpeg/ffmpeg, brew install homebrew-ffmpeg/ffmpeg/ffmpeg.

7. Dynamic visuals (route to an engine)

SituationEngineInstall (verified from each repo's README)
Default: overlays, kinetic type, b-roll cards, zooms, captions on footageHyperFrames (HTML to video, deterministic render)claude plugin marketplace add heygen-com/hyperframes then claude plugin install hyperframes@hyperframes, or standalone npx skills add heygen-com/hyperframes (agents: npx hyperframes skills update). Needs Node.js 22+ and FFmpeg.
The user already has a Remotion project or React brand componentsRemotion agent skillsnpx skills add remotion-dev/skills
Many takes, transcript-driven selection, a self-checking render loopvideo-usegit clone https://github.com/browser-use/video-use ~/Developer/video-use, ln -sfn ~/Developer/video-use ~/.claude/skills/video-use, then in that folder uv sync (or pip install -e .). Needs an ElevenLabs API key in .env (cp .env.example .env).

In HyperFrames, start at /hyperframes. It routes designed overlays on footage to /talking-head-recut, plain captions to /embedded-captions, short motion graphics to /motion-graphics, and re-cuts or reframes to /general-video. Hand every engine the same data: the cut video, *.cut.words.json (output timeline), *.cues.json, the EDL.

House rules for visuals:

  • Show the noun on the word: the visual lands on the frame the word is said, and shows the literal thing named (sales means a cart and money, a schedule means something landing on a calendar). If no honest asset exists, stay on the face and reframe.
  • Real UI at real proportions: capture the real page or app and zoom uniformly. Never invent a condensed card with inflated type, never slice text with a card edge.
  • No scanner effects: no light sweeps, sheens, glows, halos, pulse rings. Crisp motion is a fast entrance (4 to 8 frames, strong ease out, 2 to 4 frame stagger), then a clean hold.
  • Safe zone on 1080x1920: keep text and key UI inside x 90 to 950, y 240 to 1470. The header covers the top, the caption block the bottom, and the button rail covers x > 950 below y 1000. Text under about 30 px is texture, not information.
  • Every beat gets a different object, not one template repeated. Keep the main element on screen from frame 1 of its beat. A face shown between two graphics needs at least 0.8 s.
  • Several animations: brief one sub-agent per animation in parallel, each writing its own file.

8. Stop motion

python3 "$T/stopmotion.py" frames/ -o edit/stop.mp4                  # 12 drawings/s on twos, 24 fps
python3 "$T/stopmotion.py" frames/ -o edit/loop.mp4 --fps 8 --hold 3 --pingpong --loop 2
python3 "$T/stopmotion.py" --from-video edit/take.cut.mp4 -o edit/take.stop.mp4 --fps 12
  • --fps sets drawings per second (8 for chunky, 10, 12 for smooth). --hold sets frames per drawing (2 means "on twos"). Output fps = fps x hold.
  • The hand-made feel comes from per-drawing jitter (--jitter px, default 0.5% of the short side) and rotation (--rotate deg, default 0.5). It is seeded: the same --seed gives an identical render, and each loop pass wobbles differently. --flicker 0.01 adds exposure drift; it is off by default. --end-hold 1 holds the last pose.
  • Mixed sizes and formats are fitted to the canvas (--size 1080x1920 --fit cover|contain). Transparent PNGs go on --bg. From-video mode keeps the original audio in sync.

Making the frames, any style:

  • One subject, locked: write a model sheet first (shape, palette as hex, materials, camera height and lens, light direction). Every frame prompt or drawing reuses it word for word, and only the pose or position changes. Keep the camera locked; movement belongs to the subject.
  • With the user's image tool: generate a hero frame, then each next frame from the previous one as a reference with one small change (2 to 5% motion). Use 8 to 24 frames for a 1 to 2 s move. Styles: clay (fingerprints, soft key light, matte), paper cut-out (flat layers, drop shadows, visible paper grain), bricks (studs, plastic sheen, snapped positions), sticky notes (one note per frame on a wall, marker text), pixel (fixed grid, limited palette, no anti-aliasing).
  • Drawing it yourself: write each frame as SVG with the character as reusable <g> groups and move only transforms between frames. Add 1 to 2 px random offsets to path points for line boil. Rasterize with what exists (rsvg-convert, ImageMagick, headless Chrome screenshots) or build it as a HyperFrames composition with stepped timing. Then run stopmotion.py on the PNGs.

9. Audio finishing (one fixed gain, -14 LUFS, limiter)

Rules: never compress, gate or AGC the voice (it lifts room echo between words and chops word tails). Never use single-pass loudnorm, which is dynamic and acts as an AGC. Apply one fixed gain to -14 LUFS integrated, then a look-ahead limiter at -1.5 dBTP oversampled for true peak. A music bed sits about 15 dB under the voice at a fixed level.

# 1) measure (same pre-filter as the master)
ffmpeg -hide_banner -nostats -i edit/final.mp4 -map 0:a:0 -af "highpass=f=75,ebur128=peak=true:framelog=verbose" -f null - 2>&1 | grep -E "^\s+(I|Peak):"
# 2) G = -14 - I   (example: I = -21.3 gives G = 7.3)
ffmpeg -i edit/final.mp4 -map 0:v -map 0:a -c:v copy \
  -af "highpass=f=75,volume=7.3dB,aresample=192000,alimiter=limit=0.841:attack=5:release=50:level=false:latency=true,aresample=48000" \
  -c:a aac -b:a 256k -movflags +faststart edit/final.master.mp4
# 3) measure again: I within 0.5 LU of -14, Peak at or under -1.5 (AAC can add a few tenths)
  • level=false matters: the limiter's default auto-level raises everything. latency=true removes its 5 ms delay. Older ffmpeg builds lack it: check probe.py --doctor.
  • Music bed: measure the voice (I_v) and the music (I_m), then gain the music by I_v - 15 - I_m dB and mix with amix=inputs=2:duration=first:normalize=0, then master the mix as above. Fade the bed out about 1 s before the end. Use a bed at least as long as the video; a looped file with a faded ending dips every loop.
  • -ac 1 sums stereo without scaling (+6 dB). Downmix with pan=mono|c0=0.5*c0+0.5*c1.
  • If peaks would be limited by more than about 6 dB, say so and offer -16 LUFS instead.
  • You cannot hear the result. Report the numbers, and when a change is a judgement by ear, give the user a short A/B of the same excerpt.

10. Export and self-check before showing anything

Reels / TikTok / Shorts: 1080x1920 (9:16), H.264 High yuv420p, 30 fps (or the source rate up to 60), AAC 48 kHz, -movflags +faststart, -14 LUFS, -1.5 dBTP. Platform limits change, so check length limits when they matter.

  • Reframe 16:9 to 9:16 without bars: -vf "scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920". With bars: -vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2".
  • Encode: -c:v libx264 -crf 18 -preset slow -profile:v high -pix_fmt yuv420p -r 30.

Before you show the user, check:

  1. probe.py final.mp4: right size, fps and duration, audio present, video and audio durations within a frame.
  2. Loudness measured (step 9), numbers reported.
  3. Stills at the first frame, each join, and 3 caption moments: nothing over the face, all text inside the safe zone, no frozen hold over 1.5 s, and the first frame works as a cover.
  4. Captions read the words actually said (spot-check against words.json).
  5. Fix and re-check at most 3 times, then hand over with the open issues listed.

Failure handling

  • probe.py --doctor says ffmpeg is missing: give the install command and stop.
  • No audio: no dead-space cut; offer a manual cut list from stills.
  • "Unreliable" gate (noisy room or music under the voice): use --transcript, or set --threshold from the printed levels.
  • Too much cut (clipped words): use --pace loose or larger --pad-before/--pad-after. Too little: use --pace tight.
  • VFR phone footage: fine, it is rendered at constant frame rate. HDR: kept 10-bit; convert to SDR once before an engine that renders SDR.
  • No libass: use the HyperFrames route (step 6). No faster-whisper: use --words or the venv install it prints. Node under 22: HyperFrames will not run; use Remotion if installed, or ship captions + cuts without overlays and say so.

Limits (honest)

  • The tools never watch or listen. Cuts come from levels and word timings, so review the EDL. Retake detection is a heuristic and the last take wins.
  • Transcripts are only as good as the model. Whisper drops some fillers and misspells names.
  • No generative video or images are made here. Stop-motion frames come from your image tool or from SVG you draw.
  • Nothing logs into or posts to any account.

Credits and licenses for the merged upstream skills: CREDITS.md.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.