ComfyUI Node
BFS Head Swap Sampler (crop · mask · loop)
Head swap with an optional stable crop around the subject, native mask inpainting and temporal chunking. Connect only what you need: guide + identity is a plain swap; add a mask to restrict the edit; add a crop mode to sample the subject full-frame when the face is too small to carry identity.
BFS Head Swap Sampler (crop · mask · loop)
- model
- vae
- noise
- sampler
- sigmas
- guider
- positive
- negative
- guide_video
- identity_image
- latent
- subject_mask
- images
- mask_over_source
- cropped_guide
- crop_mask
- latent_mask
- latent
- crop_bboxes
- debug
◄crop_modeoff►
◄crop_scale1.50►
◄crop_divisible_by32►
◄uncrop_feather16►
◄paste_backtrue►
◄paste_confine_to_masktrue►
◄inpaint_with_masktrue►
◄mask_grow8►
◄mask_blur4►
◄mask_hard_for_inpainttrue►
◄latent_mask_dilate0►
◄latent_mask_dilate_frames0►
◄mask_strength1.00►
◄decodefull►
◄decode_tile_size768►
◄decode_overlap64►
◄decode_temporal_size32►
◄decode_temporal_overlap4►
◄temporal_tile_size0►
◄temporal_overlap16►
◄guide_source_id1►
◄identity_source_id2►
◄debug_logfalse►
CategoryBFS/video
Inputs (35)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| vae | VAE | — | |
| noise | NOISE | — | |
| sampler | SAMPLER | — | |
| sigmas | SIGMAS | — | |
| guider | GUIDER | Provides CFG/STG settings; its conds are replaced per chunk. | |
| positive | CONDITIONING | — | |
| negative | CONDITIONING | — | |
| guide_video | IMAGE | Source clip: body, motion, camera, scene. Output geometry follows it. | |
| identity_image | IMAGE | Head/face reference. Crop to the head. | |
| latentopt | LATENT | Empty latent from EmptyLTXVLatentVideo, sized to the CROP when cropping is on. Strongly recommended: LTX-2.5 latents are AV (video+audio) and this node cannot fabricate that structure -- without it a plain video latent is built and the model may ignore the guide entirely. | |
| subject_maskopt | MASK | Per-frame mask of the region to edit (head, with margin). Drives the crop box and, with inpaint_with_mask on, restricts denoising to it. Leave unconnected for a plain swap. | |
| crop_modeopt | COMBO | off | Sample inside a box around the subject instead of the whole frame -- the fix for faces that are too small to carry identity. combined: one static box for the clip. tracked: a constant-size box that stays still until the subject would leave it. zoomed: the box follows the subject's size too, planned over the whole clip. |
| crop_scaleopt | FLOAT | 1.501–4 | Box size as a multiple of the subject. 1.5 leaves a third as margin. Keep neck and shoulders in: a face-tight crop is a framing the LoRA never saw in training. |
| crop_divisible_byopt | INT | 328–128 | — |
| uncrop_featheropt | INT | 160–256 | Blend width when pasting the crop back, in pixels. Sides sitting on the image edge are never feathered -- there is nothing outside to blend into. |
| paste_backopt | BOOLEAN | true | Composite the crop into the original frames before returning. Turn OFF for a second pass: images/latent then stay in the crop's own space, so you can upscale and refine the crop -- where the face actually has pixels -- and composite at the end with the Head Swap Paste Back node, feeding it the crop_bboxes output. |
| paste_confine_to_maskopt | BOOLEAN | true | Paste only inside the mask instead of the whole crop rectangle, so anything the model changed in the crop's background never reaches the frame. Off pastes the full box. |
| inpaint_with_maskopt | BOOLEAN | true | Send the mask to the sampler as a denoise mask, so only the masked region changes and everything else stays the guide's own pixels. Native ComfyUI inpainting -- the LoRA never sees the mask and the original face stays visible to the model. |
| mask_growopt | INT | 80–256 | Dilate the mask before use, in pixels. The new head can be bigger than the old one. |
| mask_bluropt | INT | 40–256 | Soften the mask edge, in pixels, to avoid a hard seam. |
| mask_hard_for_inpaintopt | BOOLEAN | true | Binarise the mask before it becomes the denoise mask. Blur belongs to the paste-back, where a soft edge hides the seam; in the DENOISE mask a soft edge means partial denoising, which blends the original latent -- and the original identity -- back in exactly at the edge of the head. Off passes the soft mask through to the sampler as well. |
| latent_mask_dilateopt | INT | 00–16 | Grow the mask by whole LATENT cells after the reduction. One cell is 32 px, so this is much coarser than mask_grow -- and it is what guarantees the head sits inside editable blocks instead of clipping at a cell boundary. Check the latent_mask output to see the effect. |
| latent_mask_dilate_framesopt | INT | 00–8 | Same, along time: grow by whole latent frames (one covers 8 video frames). |
| mask_strengthopt | FLOAT | 1.000–1 | How completely the masked region is replaced. 1.0 = fully regenerated. Below that the original latent is blended back, which keeps the original geometry and expression in pixels -- and drags the original identity back with them, so the result becomes an average of both faces. Expression does NOT need this: it reaches the model through the aligned guide, which carries the whole source performance regardless of the mask. |
| decodeopt | COMBO | full | How to turn the sampled latent into frames. full: one shot, fine at the size the sampler ran at. tiled: for a big latent (a second pass after a 2x upscaler), where a full decode thrashes VRAM and looks like a hang. none: skip decoding and return the latent only -- use your own VAE Decode (Tiled) downstream. With none there is nothing to paste back, so images comes out empty. |
| decode_tile_sizeopt | INT | 76864–4096 | — |
| decode_overlapopt | INT | 640–1024 | — |
| decode_temporal_sizeopt | INT | 324–4096 | Frames decoded at once in tiled mode. |
| decode_temporal_overlapopt | INT | 40–256 | — |
| temporal_tile_sizeopt | INT | 00–1000 | Frames per chunk. 0 samples the whole clip in one pass. Use the length the LoRA trained at (73 for the LTX head-swap recipe) for clips longer than that. |
| temporal_overlapopt | INT | 160–256 | — |
| guide_source_idopt | FLOAT | 10–8 | — |
| identity_source_idopt | FLOAT | 20–8 | — |
| debug_logopt | BOOLEAN | false | — |
Outputs (8)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | Final frames, with the crop pasted back when cropping is on. |
| mask_over_source | IMAGE | The mask painted over the ORIGINAL frames, plus the crop box outline. The quickest way to see whether the mask is where you think it is, at the scale you think it is, on the frames it belongs to. |
| cropped_guide | IMAGE | Exactly what the model was fed as the guide: cropped and resized. If this does not look like the region you meant to edit, nothing downstream will. |
| crop_mask | MASK | The mask after grow/blur (and cropping), in the crop's pixel space. |
| latent_mask | MASK | The mask as the sampler actually sees it: reduced to the latent grid with max and upsampled back for viewing. One frame per latent frame -- this is the real resolution of the edit, and where a too-thin mask disappears. |
| latent | LATENT | Sampled latent. With cropping on this is the CROP's latent, which is what you want to upscale and refine in a second pass. |
| crop_bboxes | BOUNDING_BOX | The crop boxes, one per frame. Feed to Head Swap Paste Back after a second pass. |
| debug | STRING | What the node decided: crop mode and box, mask ops, tiling. |