Guides

    Lip sync breaks on fast speech and plosives

    Rapid consonants expose a 1–3 frame lag slower speech hides. Target a 120ms window, nudge the clip, and rewrite lines that keep tripping it.

    Versely Team9 min read

    A slow read can hide a bad lipsync. A fast one cannot. Plosives (p, b, t, d, k, g) are the test: the lips have to close, or the tongue has to stop the air, on a specific frame. Older lipsync stacks, and plenty of current ones on rapid dialogue, land that closure one to three frames late. On a pause-heavy founder story you never see it. On a 12-second ad that stacks "big product pack" three times, every viewer does.

    The useful target is not zero error. It is about 120ms — a working number in the same band as the ITU detectability tests (audio lag around 125ms), not a broadcast delivery spec. Below that, most viewers still read the clip as synced. At 25 fps (Versely's default video rate) 120ms is three frames. A one-frame lag is 40ms and almost nobody flags it. A four-frame lag is 160ms and should not ship.

    Slow speech hides a lag that plosives put on screen

    Visemes are coarser than phonemes. Several sounds share a mouth shape, which is why a model can look "right" on vowels while missing the closures. Fast speech shrinks the time each viseme is allowed to occupy. The model still has a small lag in feature extraction and in the mouth-crop tracker. Slow speech pads that lag with vowels. Rapid consonants do not.

    Wav2Lip-lineage tools are the clearest example: a 96×96 mouth crop, a couple of frames of lag on fast speech, a jaw that flaps rather than closes. Newer re-sync models (on Versely, Sync Lipsync 2.0 is the close-up pick) reduced that, they did not delete it. If your script is a list of plosive-heavy product names, you will still see it.

    QC on mute first. A closure that looks late with sound off is late. Sound-on QC lets the brain average the two streams and forgive more than the feed will.

    What you see Likely size First move
    One late "p" on an otherwise calm take 1 frame (40ms at 25 fps) Leave it
    Every plosive a beat behind, gap does not grow 1–3 frames (40–120ms) Nudge, then recast the line if still visible
    Fine at the start, worse at the end Growing This is export drift, not plosive lag. Re-export before you nudge.
    Jaw flaps, lips never fully close Not a timing offset Different model, or the source mouth is occluded

    The third row is the trap. Accumulating drift looks like "fast speech broke it" because the dense lines sit later in the script. Measure the gap on the first plosive and the last. If they differ, you have a clock problem, not a viseme problem.

    The 120ms window is the target, not zero

    Broadcast specs are tighter than this. You do not need them for a talking-head Reel. You need the clip to sit inside what viewers actually flag.

    Practical translation at 25 fps:

    • 1 frame = 40ms. Invisible in a feed, visible only if you are stepping.
    • 2 frames = 80ms. Inside the window. Nudge if it bothers you on a close-up.
    • 3 frames = 120ms. The edge. Nudge on hero ads; often leave on medium shots.
    • 4+ frames = 160ms and up. Do not ship. Nudge or regenerate.

    At 30 fps the same 120ms is closer to four frames (4 × 33.3ms = 133ms). Count in milliseconds, not in a mixed-rate "a couple of frames." Confirm the clip's rate before you count.

    Picture leading the audio a little is more forgivable than audio leading the picture. That matches everyday physics (you see the clap, then hear it). If you have to pick a side when you nudge, put the mouth early, not the voice late.

    Do not chase zero. A model that hits every closure on the exact sample will still look off if the source performance never closed its lips. Some speakers do not fully close on "p" in rapid speech. The model copied them. That is a script and direction problem, covered below.

    A manual nudge that takes a minute

    Only do this when the offset is constant. Two measurements, same gap.

    1. Find two closures. A "b" or "p" in the first second, and another after the midpoint. Step frame by frame. Note how many frames the closed mouth sits behind the waveform transient (the spike on the "p").
    2. Convert to milliseconds. Frames × (1000 / fps). At 25 fps, 2 frames is 80ms.
    3. If both measurements agree and the gap is over ~80ms on a close-up, slip the picture earlier (or the audio later) by that amount. One global slip. Not a timewarp. Not a speed ramp.
    4. If they disagree, stop. You are looking at drift. Re-export at native frame rate, optimized rendering off, WAV in. A nudge that saves the first line will miss the last.
    5. Re-QC on mute, then with sound, at delivery size. A 2-frame slip that looks perfect at 200% on a monitor can look like a hiccup on a phone if you overshot.

    Where to do the slip:

    • In an NLE, slip the video clip 1–3 frames earlier on the timeline and leave the audio where the waveform is honest.
    • If the talking head was built as a still-plus-audio generate, regenerate only after the nudge on a bounce still looks late. generate_lipsync takes an image and an audio URL; feed it WAV. It will not see a timeline slip you never bounced.

    Do not slip captions and mouth independently. If you already burned karaoke captions against the old clock, either re-caption after the slip or you have invented a third clock. Caption last.

    A request that keeps the agent from regenerating first:

    "This take is 25 fps. The 'p' in 'pack' is two frames late at 0:01 and at 0:09, so it's a constant offset, not drift. Slip the picture two frames earlier against the WAV. Do not re-run lipsync unless that slip still leaves the closure past 120ms."

    Script edits that stop exposing the lag

    Nudging treats a take you already like. Rewriting treats the next twenty takes.

    Break the clusters. "Big product pack" is three closures in a row with no vowel rest. "The pack is big" gives the mouth a place to recover. You are not dumbing the line down. You are putting a viseme rest on a model that has a one-frame lag.

    Put a beat before the word you care about. A 150–200ms pause in front of the product name is a gift to both the aligner and the viewer. TTS will honour an explicit pause if you write it; a human talent will honour it if you mark it on the script.

    Stop packing lists into one breath. "One, two, three, four benefits" on a talking head is a plosive machine. Cut to b-roll for the list, or split into two sentences. The mouth only has to be perfect on the lines where the face is the shot.

    Record or generate slightly slower than the feed cut. You can always cut pauses out. You cannot add closures that were never performed. For text-to-speech, a calm delivery with style_instructions that ask for clean consonants beats a "fast, energetic" read that eats every "t". The same instruction works when you write and generate a voiceover in one request.

    Sync the isolated vocal, then mix. Music in the voice band smears the features the model uses for closures. Isolate, lipsync, mix. This is the same isolation rule as captions, and plosives are why it matters here.

    When the source is a still, lipsync the photo to audio. When the source is already footage, use a current video-to-lipsync model rather than a talking-photo path. Fast speech on a profile or a bearded mouth is still a bad input; no nudge will close lips the camera never saw. How lipsync models work is the source-condition table. This article assumes the face was frontal and you still lost the "p".

    FAQ

    Is 120ms a broadcast spec?

    No. Broadcast windows are tighter (ATSC recommends audio lead no more than 15ms and lag no more than 45ms). 120ms is a perceptual working number for generated talking heads, near the ITU detectability band for audio lag. If you are delivering to a network, use their spec. If you are delivering a Reel, 120ms is the number worth targeting so you stop regenerating for one-frame errors.

    Should I regenerate or nudge?

    Nudge when the gap is constant and inside about three frames at 25 fps. Regenerate when the jaw never closes, when the gap grows down the clip, or when a nudge past 120ms still looks late on a close-up. Regenerating a constant 80ms lag is how you spend twice for the same viseme.

    Why is the same model fine on my founder video and broken on the ad?

    The founder video is full of vowels and pauses. The ad is a stack of product names. The lag was always there. The script started exposing it. Slow the ad read, or split the plosive clusters, before you change models.

    Can I fix this by captioning karaoke-style so the word "proves" the mouth?

    No. Karaoke that is timed to interpolated word clocks will disagree with a late mouth and make the miss louder. Caption after the mouth is inside the window, from the same WAV, and prefer a line-level style until the closures land.