Nodes/ComfyUI-WanKeyframeBuilder/Wan Keyframe Builder
ComfyUI Node

Wan Keyframe Builder

Lock a pose, let Wan fill the gap

By ckinpdx·Created 9 months ago·Updated 9 months ago· 6
Wan Keyframe Builder
  • image1
  • image2
  • image3
  • image4
  • image5
  • image6
  • image7
  • image8
  • images
  • masks
  • keyframes
num_frames81
spacing_mode
first_strength1.00
last_strength1.00
middle_strength0.80
frame_10
frame_220
frame_340
frame_460
frame_580
frame_6100
frame_7120
frame_8140

Wan image-to-video is great at the between - the motion, the physics, the camera drift. What it's bad at is hitting specific poses you've already decided on. If you've hand-built a start-frame + mask timeline for WanVideoImageToVideoEncode before, you know it's a stack of PadImage, ImageConcat, and mask-strength nodes that always ends in an off-by-one and a re-render. This node is that whole stack in one box: feed it up to eight keyframe images, and it returns a full-length image timeline plus a matching strength-mask timeline, ready to drop straight into Kijai's WanVideoWrapper.

The idea is simple and it's the standard trick for Wan I2V: every frame you don't care about gets filled with mid-gray (0.5) so the model generates freely there, and each keyframe sits at a fixed position with a mask strength that says how locked that frame is. The output timeline is [T, H, W, C], the masks are [T, H, W], and they plug into WanVideoImageToVideoEncodeWanVideoSampler exactly like a single start image would. It doesn't call any API and needs no model files of its own - it's pure tensor assembly on top of ComfyUI's built-in IMAGE/MASK types.

The inputs that actually matter

  • image1image8: your keyframes, oldest to newest. image1 is required; the rest are optional. Any connected image becomes a keyframe.
  • num_frames: total timeline length. Default 81, and the tooltip is right - Wan expects 4n+1, so think 81, 121, 161. Wander off that and you can get odd end-frame behavior.
  • spacing_mode: even auto-distributes your keyframes across the whole timeline (the node computes round(i * (T-1) / (N-1))), which is what you want 90% of the time. manual uses the frame_1frame_8 positions instead - but those only matter in manual mode, so leave them alone unless you're timing a beat precisely.
  • first_strength / last_strength / middle_strength: the mask weights. First and last default to 1.0 (fully locked), middle to 0.8. The 0.8 default is a deliberate choice: it gives the model room to reinterpret the pose and animate smoothly between keyframes instead of snapping. Drop it toward 0.5 for looser guidance, keep it high if the model keeps wandering off your composition.

Outputs

Three, and they're named honestly. images is the full timeline with keyframes placed and gray fill everywhere else. masks is the strength map - 1.0 means the frame is locked, 0.5 gray means free generation, and the middle-keyframe positions carry your middle strength. keyframes is just the keyframe images stacked back into one batch [N, H, W, C], which you can wire anywhere you'd want the raw inputs (multi-reference encoders, preview, whatever). For the normal single-pass workflow you want images and masks going into WanVideoImageToVideoEncode.

Installing it

Via ComfyUI Manager, search "ComfyUI-WanKeyframeBuilder" and install. Or by hand:

cd ComfyUI/custom_nodes
git clone https://github.com/ckinpdx/ComfyUI-WanKeyframeBuilder
# restart ComfyUI

That's the whole install - there's no requirements.txt and nothing to download. This one lives in the category WanKeyframeBuilder, and there are only two nodes in the pack, so you can't miss it.

Where people get burned

The resolution check is the big one: all connected keyframes must match dimensions, and the node deliberately raises an error if they don't - the author's call, and a good one, because mismatched sizes mean your workflow is broken, not that the node is. Also remember the gray fill is intentional. If your output looks like it has "holes" where nothing's happening, that's the free-generation space working as designed. And if you're used to Hunyuan-style last-frame locking, recalibrate: with a single keyframe, only first_strength applies and it sits at frame 0 - a locked start, free everything after. The author (who also maintains a public ComfyUI workflows repo) built this to match the way Wan I2V actually conditions, and it shows.

CategoryWanKeyframeBuilder

Inputs (21)

NameTypeDefaultDescription
image1IMAGE
num_framesINT811–4096Total frames in the output timeline. Should be 4n+1 (e.g., 81, 121, 161) for Wan models.
spacing_modeCOMBOEven: auto-distribute keyframes. Manual: use frame position inputs.
first_strengthFLOAT1.000–1Mask strength for the FIRST keyframe. 1.0 = fully locked.
last_strengthFLOAT1.000–1Mask strength for the LAST keyframe. 1.0 = fully locked.
middle_strengthFLOAT0.800–1Mask strength for middle keyframes. 0.8 gives the model some freedom to interpret the pose.
frame_1INT00–4095Position for keyframe 1 (used in manual mode)
frame_2INT200–4095Position for keyframe 2 (used in manual mode)
frame_3INT400–4095Position for keyframe 3 (used in manual mode)
frame_4INT600–4095Position for keyframe 4 (used in manual mode)
frame_5INT800–4095Position for keyframe 5 (used in manual mode)
frame_6INT1000–4095Position for keyframe 6 (used in manual mode)
frame_7INT1200–4095Position for keyframe 7 (used in manual mode)
frame_8INT1400–4095Position for keyframe 8 (used in manual mode)
image2optIMAGE
image3optIMAGE
image4optIMAGE
image5optIMAGE
image6optIMAGE
image7optIMAGE
image8optIMAGE

Outputs (3)

NameTypeDescription
imagesIMAGE
masksMASK
keyframesIMAGE