VACE Mask Generator
The node that tells Wan what to keep and what to invent
- trimmed_clip
- inpaint_mask
- control_frames
- mask
- target_frames
Wan's native video generation is short. The stock workflow gives you roughly 81 frames, and once you want to extend a clip - stretch it, loop it, fill a gap, remove a section - you're in VACE territory. VACE is Alibaba's control framework for Wan (the video answer to ControlNet, which by mid-2026 is effectively how all video control is done), and it works off two signals: a mask saying what to keep versus regenerate, and control frames giving the model visual context. Building those two sequences by hand is fiddly. This node builds them for you.
Feed it a video, pick one of eleven modes, and it outputs the exact mask + control_frames pair a VACE encode expects. For a beginner this is the difference between a workflow that "just extends" and a pile of broken tensor shapes.
How it works
The convention is simple and worth internalizing: black = keep the original frame, white = generate a new one. Where the mask is black, control_frames shows the real source pixels; where it's white, the source is replaced with a solid grey (#7f7f7f) fill. VACE then sees grey and thinks "here's where I should invent." Every mode is just a different arrangement of that black/white pattern - End Extend appends white frames after your clip, Middle Extend sandwiches a white gap between two black halves, Edge Extend takes the clip's end and start as black edges with a white gap between (that's the looping one), and so on through Pre, Join, Bidirectional, Frame Interpolation, Replace/Inpaint, Video Inpaint, Keyframe, and the newer Upscale.
The one number to know is the target_frames output. It's snapped up to the nearest 4n+1 (…, 77, 81, …), which is what Wan's VAE - with its temporal downsampling factor of four - tiles cleanly. You wire that integer straight into your VACE encode. Don't fight the snapping; 4n+1 is the format the model wants.
The inputs that matter
mode- the eleven-way enum. This decides everything, so pick deliberately (or drive it from VACE Mode Select if you're templating).target_frames(default 81) - total output length for the modes that use it.split_index- where to split. Meaning changes per mode: the middle cut for Middle Extend, the number of frames before the clip for Bidirectional, frames-per-gap for Frame Interpolation, the start of the replace region for Replace/Inpaint. 0 usually means "auto" for the mode that uses it.edge_frames(default 8) - context size for Edge and Join, replacement length for Replace/Inpaint.inpaint_mask- only for Video Inpaint: a per-pixel MASK where white regions get regenerated and black regions are preserved (a single-frame mask broadcasts across all frames).keyframe_positions- for Keyframe mode, comma-separated indices like0,20,50,80; leave empty for even auto-spread.
Outputs: control_frames and mask (both IMAGE) go to your VACE encode, and the snapped target_frames INT goes to the encode's length input.
Where people get burned
The big one: for any mode that uses target_frames, your trimmed_clip must not exceed target_frames. The node checks and raises a clear error telling you exactly that - which is the pack's way of saying "put VACE Source Prep upstream." That's not a bug; you're supposed to trim first. If you see that error, that's the pack working as designed.
How to install it
VACEMaskGenerator is one of seven nodes in ethanfel's ComfyUI-VACE-Tools pack (he's the same dev behind ComfyUI-LoRA-Optimizer and ComfyUI-Krea2TexTEncoder):
cd ComfyUI/custom_nodes/
git clone https://github.com/ethanfel/Comfyui-VACE-Tools.git
Restart ComfyUI, or search "VACE Tools" in ComfyUI Manager. The pack declares zero Python dependencies - it needs only the torch and numpy ComfyUI already ships. What it does not download is the actual Wan + VACE model files; those are separate downloads you handle in your WanVideoWrapper setup, and the mask/control-frames this node produces are exactly what those extension models consume.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| trimmed_clip | IMAGE | — | |
| mode | COMBO | End Extend | 11 options: End Extend, Pre Extend, Middle Extend, Edge Extend, Join Extend, Bidirectional Extend, +5 |
| target_frames | INT | 811–10000 | — |
| split_index | INT | 0-10000–10000 | — |
| edge_frames | INT | 81–10000 | — |
| inpaint_maskopt | MASK | — | |
| keyframe_positionsopt | STRING | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| control_frames | IMAGE | Visual reference for VACE — source pixels where mask is black, grey (#7f7f7f) fill where mask is white. |
| mask | IMAGE | Mask sequence — black (0) = keep original, white (1) = generate. Per-frame for most modes; per-pixel for Video Inpaint. |
| target_frames | INT | Total frame count snapped to 4n+1 (1, 5, 9, …, 81, …) — wire directly to VACE encode. |