Hypernatural

TechniqueBy HypernaturalVersion 1, Oct 21, 2026

ffmpeg-frame-exact-trim

Cut a render or clip to an exact number of frames at its native frame rate with ffmpeg, re-encoded, so it drops into a cut frame for frame: trim to shot length, skip an idle opening, drop pulldown duplicates. Reach for it after every render, before review and delivery, instead of speeding a clip up to fit.

SKILL.md

Frame-exact trim

Give it a clip, a start frame and a frame count; get back a re-encoded clip with exactly that many frames at the clip's own frame rate. Use it on every render: models run past the shot (a 3–4 s floor for a 1 s shot), idle before acting, or come back padded to another frame rate. To put picked clips into a source timeline, use ffmpeg-splice-into-source-cut, which trims each clip itself.

Inputs

  • The clip, untrimmed. Keep it in raw/ next to the trimmed file and never overwrite it.
  • Its frame rate and frame count (ffprobe-inspect-media). Cut at that rate; never resample to fit.
  • The start frame (0 unless the take idles) and the frame count you want:
    • review takes and per-shot delivery files: the shot's length plus a 0.5 s tail (12 frames at 24 fps), so a word or action that runs past the cut is still there;
    • a cut: exactly the shot's length (the splice leaf does this for you).
  • Upscale first. Run topaz-upscale on the raw render, then trim the upscaled file.

Run it

By frame (exact by construction; use it whenever you think in frames). Shot 01 is 25 frames at 24 fps; this take idles, so start 22 frames in and keep 25 + 12 frames:

exec ffmpeg -hide_banner -loglevel error -y
  -i <job>/video/raw/shot01_kling_d.mp4
  -vf "trim=start_frame=22:end_frame=59,setpts=PTS-STARTPTS"
  -af "atrim=start=0.916667:end=2.458333,asetpts=PTS-STARTPTS"
  -r 24
  -c:v libx264 -crf 14 -preset slow -pix_fmt yuv420p
  -c:a aac -b:a 192k -movflags +faststart
  <job>/video/shot01_kling_d.mp4
  • end_frame is exclusive: start + count. atrim takes the same span in seconds (frame / fps, six decimals). Drop -af and add -an for a clip with no sound.
  • -r 24 on the output is required, not decoration (Tips and traps).
  • The encode settings are the house ones for intermediate and delivery files: CRF 14, preset slow, yuv420p, AAC 192k, +faststart.

By time (the same cut, written as seconds; decode-accurate because it re-encodes):

exec ffmpeg -hide_banner -loglevel error -y -i <raw clip>
  -ss 0.9167 -t 1.5417 -r 24
  -c:v libx264 -crf 14 -preset slow -pix_fmt yuv420p -c:a aac -b:a 192k
  -movflags +faststart <out clip>

-ss after -i seeks by decoding, so the first frame is exact. Write times to four decimals; frames / fps.

Picking a late start

When a take holds its opening pose before acting, skip the hold rather than speeding the clip up. Make a strip of every 4th frame and read the frame where the action starts (tile index × 4):

exec ffmpeg -v error -y -i <raw clip>
  -vf "select='not(mod(n,4))',scale=320:-2,tile=8x4:padding=4"
  -frames:v 1 -update 1 <job>/video/raw/shot01_kling_d_strip.jpg

Look at the strip, then trim from that frame.

Renders padded from 24 to 30 fps

Some providers return a 24 fps model padded to 30 fps by repeating every 5th frame (a visible stutter). Drop exactly the duplicates and get the native 24 back, then trim:

-vf "decimate=cycle=5,setpts=N/24/TB" -r 24

Never use fps=24 on a 30 fps file: it drops real frames evenly and judders.

What you get

A clip of exactly the frames asked for, at the source rate, H.264 with its own audio trimmed to match. Record the trim in the take's notes (start frame, frame count), so a later round can re-trim from raw/.

Tips and traps

  • ffmpeg 7 drops the last frame without -r. A trimmed segment encoded to MP4 without an explicit output rate comes out one frame short (25 in, 24 out). Always pass -r <fps> on the output.
  • No fps= inside per-segment filter chains before a concat: it lost one frame per shot (472 of 484 frames).
  • Don't retime to fit. Sped-up action reads badly. Brief the model to play the action in real time and then hold, and trim. Every model spreads the action over its whole clip, so a trim may stop short of a pinned end pose: that is expected, and the full render stays in raw/.
  • Trimming the start of a take with a pinned first frame loses the pinned frame. Do it only when the opening is an idle hold.

Check it

Count the frames after every cut. framemd5 decodes every frame and prints one line per frame; count the lines that don't start with #:

exec ffmpeg -v error -i <out clip> -map 0:v -f framemd5 -

It must equal the count you asked for. Then look at the first and last frame (a select='eq(n,0)' still) against the shot's stills before the take goes on a review page.

Go make something cool.

Install the app, open your agent, describe the video. That's the whole onboarding.

Sticker HypernaturalSticker BannerSticker TVBoy