Nodes/ComfyUI-BFSNodes/BFS Shot H3 Duet (render one shot)
ComfyUI Node

BFS Shot H3 Duet (render one shot)

One shot, rendered with the clip pinned beside it

By alisson-anjos·Created 7 months ago·Updated about 10 hours ago· 129
BFS Shot H3 Duet (render one shot)
  • shot
  • model
  • clip
  • vae
  • audio_vae
  • vlm
  • images
  • audio
  • canvas
  • layout_text
  • prompt
◄modeduet (pin the shot, no LoRA needed)►
◄taskcharacter swap►
◄instruction►
◄use_ref_2true►
◄positionleft►
◄size1.00►
◄fitcontain►
◄gap0►
◄panel_noise0.00►
◄ref_image_sizematch►
◄steps20►
◄sampler_nameeuler►
◄schedulerbeta►
◄seed42►
◄decode_canvasfalse►
◄rope_modecanvas►
◄rope_gap0►
◄source_bluroff►
◄source_blur_strength1.00►
◄source_blur_segmenterSAM 3.1►
◄source_blur_effectblur►

Where it sits

The shot loop has two ways to render a shot with H3. BFS Shot H3 Conditioning stops at conditioning and lets you sample with whatever you like; this one goes all the way - it takes the shot, builds the conditioning, pins the shot's own clip as a duet panel, samples, crops and decodes, and hands you frames for BFS Shot Join. Pick it when you don't want to think about guiders, and pick the conditioning node when you do.

It runs once per shot, because the planner's shots list reaches it. It's the per-shot version of BFS H3 Duet, with the difference that the panel and guide come from the shot: the shot's own frames, the shot's own prompt, the shot's own references.

The three modes

mode is the decision that shapes the result:

  • duet (pin the shot, no LoRA needed) - the default, and the reason this node exists. The shot's clip is pinned beside the video and copied in sync. No trained LoRA, no guide: H3 copies motion, camera and cuts from the panel while the prompt swaps who's in the frame.
  • guide (aligned, for body-swap LoRAs) - the shot sits on the generated frames as an aligned latent guide, the same conditioning the H3 body-swap LoRAs were trained with.
  • duet + guide - both. Tempting, and the author's own tests are honest about it: with a LoRA and a guide, the guide alone kept the room better than guide plus panel, because the pinned panel drags the background toward the reference picture's backdrop. Use one mechanism until a LoRA is trained for both.

In duet modes, the prompt rules are the same ones that make or break the standalone duet node. The panel has no tag - it isn't <Picture n>, it isn't <Video n>, and the text encoder never sees it - so name it by position ("the LEFT half is the kept footage") or write {layout} and let the node fill in the sentence for the current side and size. Never describe the panel's performer, clothes or room, not even to rule them out: whatever you leave unspecified is what gets copied. Restate the new identity in every shot, and give exact times for cuts.

task and instruction only kick in when the shot has no prompt at all (no per-shot and no global prompt in the planner) - otherwise the planner's text wins. position, size, fit, gap and panel_noise are the panel geometry; panel_noise at 0 pins it exactly, 0.05–0.2 loosens it when the result copies too much of the reference. rope_mode (canvas or shifted) and rope_gap are optional, and with shifted you keep rope_gap small or the model draws its own split screen. Yes, this is the third place in the pack you'll read that warning - it's the single most common way to ruin a duet render.

Sampling, and the panel you'll never see

steps (default 20), sampler_name (euler), scheduler (beta) and seed are here, so this node is the whole render. seed is offset by the shot index, which is a small kindness - otherwise every shot of your video would start from the same noise.

decode_canvas (off by default) decodes the full split-screen canvas as well as the cropped output. Turn it on when something looks wrong: it's the fastest way to see whether the two halves are actually in sync, because canvas on the output is otherwise just a preview frame.

Outputs: images (the shot's frames, panel cropped off), audio, canvas, layout_text and prompt. The frames go to BFS Shot Join, which re-assembles everything with the source's timing and soundtrack and cuts the panel off by itself - so nothing else in your graph needs to know the duet happened. Give it audio_vae or the audio output is a silent track of the right length, which is fine for Create Video and useless as a soundtrack.

Install

Manager → ComfyUI-BFSNodes, or:

cd ComfyUI/custom_nodes
git clone https://github.com/alisson-anjos/ComfyUI-BFSNodes
cd ComfyUI-BFSNodes && pip install -r requirements.txt

Then restart and reload the browser tab - the planner panel is frontend code, and a stale tab is the usual explanation for a half-working shot loop.

Worth knowing before you start

You need H3 to be usable on your hardware at all, and that's a real constraint: it's a 33B omni-modal model with ~42.5 GB of full-precision weights, and the community licence excludes the US, EU, UK and South Korea, so check which side of that line you're on before investing a weekend. Auto loop keeps every decoded shot in memory; if you're short on VRAM, run the planner in queue loop and let the join fire once at the end. And continuity - a shot continuing from the previous result - only works here or in queue loop, since both keep the previous shot's frames around.

CategoryBFS/shot loop

Inputs (27)

NameTypeDefaultDescription
shotBFS_SHOT—
modelMODEL—
clipCLIP—
vaeVAE—
modeCOMBOduet (pin the shot, no LoRA needed)duet: the shot's own clip is pinned beside the video and copied in sync. guide: the shot sits on the generated frames as a latent guide (use with a body-swap LoRA). duet + guide: both.
taskCOMBOcharacter swapWrites the prompt when the shot has none (no per-shot or global prompt in the Planner).
instructionSTRINGWhat changes, in a few seen words (see BFS H3 Duet).
use_ref_2BOOLEANtrue—
positionCOMBOleftSide of the video the strip is added to (TSC's duet pins the source clip on the left).
sizeFLOAT1.000.1–1.5Strip size as a fraction of the video's height (top/bottom) or width (left/right), snapped to 32 px.
fitCOMBOcontaincontain keeps the whole clip (smaller, with grey around) so nothing is cropped
gapINT00–8Gray separator between panel and video, in 32 px patches (held like the panel).
panel_noiseFLOAT0.000–10 pins the panel exactly. 0.05-0.15 lets the model loosen it a little when the result copies too much of it (TSC's SOURCE NOISE).
ref_image_sizeCOMBOmatch2 options: match, max
stepsINT201–200—
sampler_nameCOMBOeuler44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38
schedulerCOMBObeta9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3
seedINT420–18446744073709550000—
decode_canvasBOOLEANfalse—
audio_vaeoptVAE—
rope_modeoptCOMBOcanvas2 options: canvas, shifted
rope_gapoptFLOAT00–256—
source_bluroptCOMBOoffBlur the source person in what the model sees (the panel / the guide): '<region> (<what stays sharp>)'. keep mouth: lips, teeth and tongue stay sharp; keep lips + tongue: the teeth are blurred too; mouth too: nothing stays sharp. masked area: the shot's own mask (elsewhere: the whole person). It reads the pose and motion but has no face to copy. The output is never blurred.
source_blur_strengthoptFLOAT1.000.1–1—
source_blur_segmenteroptCOMBOSAM 3.1What finds the face / head / hands / person and the mouth for source_blur. SAM 3.1: text prompts. Sapiens2: body-part classes in one pass, finer lips and teeth (downloads facebook/sapiens2-seg-0.4b, 1.6 GB, to models/sapiens2 the first time). 'keep lips + tongue' always uses Sapiens2 for the lips.
source_blur_effectoptCOMBOblurblur: no detail left. invert colours: keeps the shapes and the expression but not the skin tone or colours.
vlmoptCLIPOptional VLM (Qwen3-VL CLIPLoader): fills {details} in the shot's prompt from its references when the planner left it.

Outputs (5)

NameTypeDescription
imagesIMAGE—
audioAUDIO—
canvasIMAGE—
layout_textSTRING—
promptSTRING—