ComfyUI Node

PrepareControlVideo

Build the control video that keeps your Wan loop from drifting

By heheok·Created about a year ago·Updated about a year ago· 2
PrepareControlVideo
  • video_frames
  • control_video
  • preview_video
tail_count15
pad_count46
width640
height640

Wan 2.1 VACE doesn't have a native "infinite" mode. What it has is control videos: you condition the next segment on the tail of the previous one, and the result is a video that looks like it never ended. The fiddly, manual part is slicing off the last N frames and padding them so the transition is smooth. PrepareControlVideo does exactly that in one node, and it's the piece that makes the author's infinite-VACE loop actually loop. It comes from heheok's comfyui_wan2.1_vace_infinite_helpers pack.

How it works

You feed it the just-generated segment straight out of VAEDecode, and it returns the control video for the next segment. Three knobs matter:

  • video_frames - the frames of your finished segment (the IMAGE output from VAE Decode).
  • tail_count (default 15) - how many frames from the end of the segment become the control content. The 15 default isn't arbitrary: the community's standard VACE extension recipe literally ran "in 4s chunks, each extension brought only 3s extra length as the last 15 frames of the previous video were used to start the next one." Fifteen is the sweet spot people landed on.
  • pad_count (default 46) - how many mid-gray frames (RGB 128, i.e. 0.5 normalized) get appended to the end. That gray buffer is what gives the model a soft runway into the unknown instead of slamming into a hard cut.

Then width and height (defaults 640×640) size those gray frames. Output is the padded sequence: tail frames first, gray padding after, which is what makes the next segment "continue" rather than jump.

Two outputs, same frames

The node returns the same padded sequence in two tensor layouts:

  • control_video - channel-first [N, 3, H, W], sized for feeding a VACE control input directly.
  • preview_video - normal ComfyUI [N, H, W, 3], what you'd preview or save.

Don't mix them up. control_video is deliberately channel-first, which is not the usual ComfyUI IMAGE layout - route it to a node expecting standard HWC and you'll get weird results. In the author's own gist workflow, the preview_video output is what gets saved to your "padded" folder, and on the next cycle LatestVideoFromFolder loads it back in to become the VACE control input. That's the loop: generate → tail it → pad it → save → reload → generate.

The gotcha that bites everyone

width and height must match the actual resolution of your segment. The gray frames are built at exactly width×height, then everything is torch.stacked into one batch - stack requires every frame to be the same shape, so a mismatch is a hard runtime error, not a warning. If your VACE segment comes out at 480×832, set width 480, height 832, or the node dies mid-run. Also: if tail_count exceeds your frame count it just takes everything, and pad_count 0 gives you the bare tail with no gray - useful if you want to inspect it.

Install and context

ComfyUI Manager (search comfyui_wan2.1_vace_infinite_helpers) or:

cd path/to/ComfyUI/custom_nodes
git clone https://github.com/heheok/comfyui_wan2.1_vace_infinite_helpers

Restart ComfyUI. No requirements.txt - just torch and stdlib. This node does zero heavy lifting itself; the weight sits in the Wan 2.1 VACE model (14B is slow, 15–40 minutes per segment on a 4090 - CausVid is the speed LoRA people reach for) and in Kijai's ComfyUI-WanVideoWrapper plus VideoHelperSuite, which the pack assumes you already have.

One honest caveat before you run a marathon loop: chaining this way accumulates drift. Identity and scene quality hold for a few extensions, then degrade - several segments in, the character is "similar" more than "the same." This node automates the mechanics of extension, not the quality ceiling. For a handful of segments it's the smoothest path there is; for hour-long projects, expect to re-seed or re-reference every so often. Remember the pack's own rule too: disable the previous-video group for the very first segment - there's nothing to tail yet.

Categoryvideo_utils

Inputs (5)

NameTypeDefaultDescription
video_framesIMAGE
tail_countINT151–256
pad_countINT460–256
widthINT640
heightINT640

Outputs (2)

NameTypeDescription
control_videoIMAGE
preview_videoIMAGE