Apply CN Extras Masks
Where the temporal masks actually bite into the control images
- timestep_keyframes
- timestep_kf
- info
Upstream of this node, your temporal mask schedule exists as data - masks sitting in each keyframe's cn_extras alongside a control image. This node is the moment they meet: it takes each keyframe's image, multiplies it by that keyframe's mask, and hands back keyframes whose control images are actually masked. No masks applied, no temporal masking. It's the unglamorous workhorse that makes the whole schedule real.
How it works
For every keyframe in timestep_keyframes, it looks inside the keyframe's cn_extras for both a mask and an image, expands the mask to match the image's channels, and multiplies: masked = image * mask. White in the mask keeps the control content, black removes it - the standard "white keeps" convention. It handles the ComfyUI/ControlNet format mismatch (HWC vs NCHW) automatically and verifies dimensions before applying, so mismatched masks fail loudly instead of silently corrupting. It clones keyframes rather than mutating the originals, which means your upstream schedule survives for reuse.
The invert_mask toggle flips the convention if your masks are black-keeps (there are nodes out there that paint that way). print_debug dumps a per-keyframe processing summary - the README tells you to look for Processed N keyframes when debugging a dead workflow.
Where it sits in the workflow
This is near the end of the temporal pipeline:
Multi-Mask Combiner (Batch) → Advanced Curved ControlNet Scheduler (batch_masks)
→ Redistribute Keyframe Percents → Batch Images to Timestep Keyframes
→ Apply CN Extras Masks → Apply Advanced ControlNet
It needs the TIMESTEP_KEYFRAME output from a node that has already populated cn_extras - meaning it needs the modified Advanced ControlNet fork in the loop, because per-keyframe images in cn_extras are exactly what that fork adds. Outputs are timestep_kf (the masked keyframes, into Apply Advanced ControlNet's timestep_kf) and info (a text summary of what got processed).
Installing it
Same pack, same caveats:
cd ComfyUI/custom_nodes
git clone https://github.com/diffussy69/comfyui-curved_weight_schedule
pip install matplotlib pillow numpy torch scipy
Temporal masking here specifically wants the modified Advanced ControlNet fork (git checkout per-keyframe-images on diffussy69's fork). Restart and hard-refresh afterward.
Where people get burned
Black or white images after applying = mask convention is flipped or the mask never matched the image's region. Check invert_mask, then verify the masks are actually painted and the dimensions line up (the node checks, but garbage in, garbage out). And the error you'll actually see first is Could not import TimestepKeyframe - that's the Advanced ControlNet dependency missing, not anything this node did wrong. One more: Apply Advanced ControlNet still demands an image input even when every keyframe carries its own masked image; that's what the pack's Extract First Keyframe Image helper is for, or just feed any image as a placeholder.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| timestep_keyframes | TIMESTEP_KEYFRAME | — | |
| invert_maskopt | BOOLEAN | false | — |
| print_debugopt | BOOLEAN | false | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| timestep_kf | TIMESTEP_KEYFRAME | — |
| info | STRING | — |