Hypernatural

TechniqueBy HypernaturalVersion 1, Oct 21, 2026

python-find-line-in-render

Find where in a video render a recorded dialogue line is spoken, by matching loudness envelopes in 10 ms steps, and get the offset and start frame to cut the render on so its line lands where the original's does. Use on dialogue takes rendered with an untimed audio reference (they speak the line late or early), or to align any clip to a reference line; check the result by ear.

SKILL.md

Find a recorded line in a render

Give it one or more renders and the recorded line they should speak; get, per render, the offset where the line starts, the correlation of the match, and the start frame. Cut each render from that frame to the shot's length, with the recorded line as its audio, and the line lands where the original's does.

It lines up the start only. A render that re-paced the line (spoke it slower, added a pause) still drifts after the start; fix that with a mouth-only re-sync (heygen-v3-resync-existing-take, veed-v2-resync-existing-take) or a render with the line timed in the prompt.

Inputs

  • The renders: videos with their own soundtrack (the model's re-voiced line).
  • The line: the original's recorded line as WAV, starting at the shot's first frame and ending with the line (ffmpeg-cut-audio-window). Each render must be at least as long as the line.
  • The shot's length in frames and its fps, from the original.

Run it

Write references/find_line.md's script into the project folder as find_line.py, unchanged, and run it:

exec("python", ["find_line.py", "--line", "audio/shot03_line.wav", "--fps", "24",
  "video/raw/shot03_seedance_a.mp4", "video/raw/shot03_seedance_b.mp4"], cwd="<job>")
[
  {"render": "video/raw/shot03_seedance_a.mp4", "offset_s": 0.53, "envelope_corr": 0.874, "start_frame": 13},
  {"render": "video/raw/shot03_seedance_b.mp4", "offset_s": 1.31, "envelope_corr": 0.412, "start_frame": 31}
]

Then cut each render from start_frame for the shot's length plus a 0.5 s margin (here 33 + 12 frames), with the recorded line as its audio, so the review judges lip sync against what will air:

exec ffmpeg -v error -y -i video/raw/shot03_seedance_a.mp4 -i audio/shot03_line.wav \
  -filter_complex "[0:v]trim=start_frame=13:end_frame=58,setpts=PTS-STARTPTS[v]" \
  -map "[v]" -map 1:a -c:v libx264 -crf 14 -preset slow -pix_fmt yuv420p -c:a aac \
  video/shot03_seedance_a.mp4

Keep the untrimmed render in raw/, and record each take's offset and correlation next to the takes.

Reading the numbers

  • offset_s: where the line starts in the render, to 10 ms.
  • envelope_corr: the normalized correlation at that offset, −1 to 1. A low value usually means extra words or noise past the line in the render, or a line performed with a different rhythm; listen before trusting its offset.
  • start_frame: round(offset_s × fps), the first frame to keep.

Tips and traps

  • Check by ear. Play the cut with the recorded line under it; the offset is a measurement, not a verdict.
  • The search slides the line over the whole render, one 10 ms step at a time; it takes seconds on a shot and grows with render length. Search a short render, not a full programme.
  • A model that re-performs an untimed reference line can start up to 1.3 s late and run about 10% long. The cut fixes the start; the length difference shows as drift by the end of the line. Check the cut take with hn4a-lipsync-check against the line.
  • Never pick where one speaker ends and the next begins from envelope minima: they were about 0.1 s off on a line that ran into the next speaker's. Pick that by ear (ffmpeg-cut-audio-window).

Go make something cool.

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

Sticker HypernaturalSticker BannerSticker TVBoy