Nodes/Pulse Studio/Pulse Lip-Sync Paste
ComfyUI Node

Pulse Lip-Sync Paste

Paste the fixed mouth back — at exactly those frames, and nowhere else

By Addis-Pulse-Studio·Created 2 months ago·Updated 5 days ago· 3
Pulse Lip-Sync Paste
  • images
  • corrected_images
  • segment
  • images
  • report
schema_version3.0.0
feather_px12

Your lip-sync model just handed you back a batch of frames with corrected mouths. They're a subset of the film, they've been through a model that pads batches to its own grid, and you have to put them back without touching anything else. Pulse Lip-Sync Paste is the other half of the pair: Pulse Lip-Sync Segment cut one character out, this writes the result back in.

It's a compositor, not an encoder

Think of it as the paste half of a mask operation. The segment you wire in is the map Segment produced: the list of frame indices, the pixel region, and the frame count and dimensions of the film it was cut from. Paste validates all three against the images you hand it, then replaces only the listed frames, only inside that region, blending at the edges.

That blend is the whole trick. A corrected mouth dropped in with a hard edge is a visible rectangle of different noise character - the lip-sync model's output never quite matches H3's grain. feather_px (default 12) ramps a weight from 0 to 1 across that many pixels from each flagged edge, and the paste is a lerp: region plus mask × (corrected − region). At 0 you get a hard paste, which is what you want when you're A/B-ing the correction and don't want the blend hiding the seam. An edge that already lies on the frame border isn't blended at all - there's nothing to blend into.

Two things it handles for you, both reported rather than silent. If the corrector returns a different frame count - LatentSync pads to its own grid - it's mapped back by nearest frame. If it returns a different resolution, the corrected frames are resized to the region. Both show up as notes in the report, so a model quietly mangling your geometry doesn't pass as a clean run.

Inputs and outputs

The three that matter: images is the film the segment was cut from - or, when you're correcting several characters, the previous paste's output, which is how the chain works. corrected_images is your lip-sync model's output. segment comes straight off the Segment node's third output.

feather_px is the only real dial. 8–16 px is invisible-to-good on a 1344×768 render; push it much past that and the corrected mouth starts losing purchase against the original lip line.

Output is images - write it to a video node - plus report, a string like @Ada: 412 frame(s) replaced, with any notes appended. Wire images into a second Segment if another character needs the same treatment, or into CreateVideo for the final mux. Note that Paste has no audio output: the mouths come from here, the sound comes from Pulse Render's audio output. In the shipped dialogue example that's exactly the wiring - last Paste's images and Pulse Render's audio both land in CreateVideo, then SaveVideo.

Install

Same pack, so the same install - and you only do it once for all nine nodes. ComfyUI Manager, search the pack title - or:

cd ComfyUI/custom_nodes
git clone https://github.com/Addis-Pulse-Studio/comfyui-pulse-studio

Restart afterwards. No pip install step exists: requirements.txt in the repo is a comment block explaining that torch, numpy, Pillow and av are already present in any working ComfyUI and pinning them would only let the pack fight your host install. You do need ComfyUI 0.30.0 or newer with comfy_extras/nodes_minimax_h3.py and comfy/ldm/minimax/ present. Model weights are separate: the ref2va/fl2va DiTs (~20 GB each), the 15 GB qwen3vl_32b_minimax_h3_nvfp4_awq text encoder and the two VAEs, into models/*/minimax/. Linux and macOS users will see the shipped graphs' loader widgets load red - ComfyUI stores those paths with Windows separators - so re-pick the same files and nothing else changes.

Where it goes wrong

The one failure you'll actually hit is a hard stop on mismatched footage, and the message names both sides: these frames (N, H, W) are not the ones the segment was cut from (M x HxW). It means the images you wired isn't the film those frames came from - usually an upscale, an interpolation pass, or a re-render that went through the film but changed its length. Paste is deliberately strict here; guessing a frame alignment is how you desync a whole film by a few frames and only notice at the end.

Less dramatic: a corrector that returns a wildly different frame count gets nearest-frame mapped, which is fine if it's off by one or two and smeared if it's off by a lot. Watch the notes. And if you chain two pastes, both keep the full film batch in memory, so a long film corrected character-by-character is a genuinely heavy graph node - worth knowing before you blame the sampler.

CategoryAddisPulse/H3

Inputs (5)

NameTypeDefaultDescription
imagesIMAGEThe film the segment was cut from, or the previous paste's output when several characters are corrected in a chain.
corrected_imagesIMAGEThe lip-sync model's output.
segmentPULSE_LIPSYNC_SEGMENT
schema_versionSTRING3.0.0Which widget layout this node was saved with. Written by the node, read at load time to restore values by name. Do not edit.
feather_pxINT120–256Blend width at the region's edges. Edges on the frame border are not blended.

Outputs (2)

NameTypeDescription
imagesIMAGE
reportSTRING