Timestep Keyframe ππ π π
Schedule ControlNet strength across your sampling steps
- prev_timestep_kf
- cn_weights
- latent_keyframe
- mask_optional
- TIMESTEP_KF
A regular ControlNet apply node gives you one strength number for the whole sample. TimestepKeyframe is what lets you say "80% strength for the first third of sampling, then fade to 20% for the rest" - or swap in a completely different weight curve or mask partway through. It's the scheduling primitive underneath everything Advanced-ControlNet does, and if you've ever wired a timestep_kf input into the Apply Advanced ControlNet node, this is the node that was feeding it.
The pack comes from Kosinkadink, the same person behind ComfyUI-AnimateDiff-Evolved - which matters here, because this node is the one that makes ControlNet play nicely with AnimateDiff's sliding-context sampling. It's actively maintained; the AnimateDiff sibling pack got migrated to ComfyUI's V3 node API in mid-2026, so this isn't an abandoned corner of the ecosystem.
How it works
You chain Timestep Keyframes together through prev_timestep_kf, and each one carries a start_percent - the point in the sampling process (0.0 to 1.0) where it takes over. Here's the part that trips people up: the order you wire them in doesn't matter. The chain sorts itself by start_percent automatically, so you can build it in any sequence and it'll still play back correctly. If two keyframes in the chain end up with the same start_percent, the later one silently overwrites the earlier - worth knowing if you're generating these programmatically.
Once a keyframe's start_percent is reached, it stays active until the next one kicks in. guarantee_steps forces a keyframe to actually be used for at least that many steps even if a later one's start point looks closer - useful so a brief transition doesn't get skipped at low step counts.
The other thing worth understanding is inherit_missing (on by default). Skip cn_weights, latent_keyframe, or mask_optional on a given keyframe and it reuses whatever was last set earlier in the chain instead of resetting to nothing. In practice: set your base weights and mask once on keyframe zero, and every keyframe after that only needs to change what's actually changing - usually just strength.
The inputs and outputs that matter
start_percent(required, 0β1) - the position key. This is the one thing every keyframe needs.strength(default 1.0) - multiplies the ControlNet's effect for as long as this keyframe is active, stacking with whatever strength you set on the Apply node itself. Set it to 0.0 during a stretch of sampling and the node skips the work entirely for that window, which is a free speed-up if you only need ControlNet influence early on.cn_weights- plug in the output of a weights node here (SoftControlNetWeights, SoftT2IAdapterWeights, ScaledSoftMaskedUniversalWeights). Must match the type of ControlNet you loaded, or you'll get an explicit error naming which weight types are compatible.latent_keyframe- per-latent strength overrides for this window, typically from a Latent Keyframe node.mask_optional- an attention mask limiting where the ControlNet applies during this keyframe's window. Note this stacks with (doesn't override) anymask_optionalyou set on the Apply Advanced ControlNet node itself.prev_timestep_kf- chains to the previous keyframe to build the schedule.null_latent_kf_strengthandinherit_missing- the fallback strength for latents not covered by your latent keyframes, and the inherit toggle described above.
Output is a single TIMESTEP_KF, which either feeds the next keyframe's prev_timestep_kf or plugs straight into the timestep_kf input on Apply Advanced ControlNet.
How to install it
Through ComfyUI Manager: search "ComfyUI-Advanced-ControlNet", install, restart. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/Kosinkadink/ComfyUI-Advanced-ControlNet
then restart ComfyUI. No model downloads or heavy Python dependencies - this pack is pure scheduling logic layered on top of whatever ControlNet model you've already loaded.
Common issues & troubleshooting
Nothing happens no matter what you set. TimestepKeyframe only does anything if it's wired into the Apply Advanced ControlNet node (or, less commonly, into Load Advanced ControlNet Model). The vanilla Apply ControlNet node from core ComfyUI has no timestep_kf input and will just ignore this entirely.
"weight types are compatible" error. This means the cn_weights you plugged in was built for a different ControlNet architecture than the one you loaded - a T2I-Adapter weights node won't validate against a standard ControlNet, for example. Match the weights node to the model type.
ComfyUI Manager says you're up to date and you're not. This pack shows up in the "fails to update" bucket in community reports fairly often - Manager reports "most up to date version" while a manual git pull in the custom_nodes folder actually pulls new commits. If errors don't match the current README, pull manually before assuming the node's broken.
You set a timestep_keyframe on Load Advanced ControlNet Model and a timestep_kf on Apply Advanced ControlNet. The Apply node's input wins - the loader's version gets overridden. If you're using the Apply node at all (the normal case), skip wiring anything into the loader and set your schedule there instead.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| start_percent | FLOAT | 0.0000β1 | β |
| prev_timestep_kfopt | TIMESTEP_KEYFRAME | β | |
| strengthopt | FLOAT | 1.0000β10 | β |
| cn_weightsopt | CONTROL_NET_WEIGHTS | β | |
| latent_keyframeopt | LATENT_KEYFRAME | β | |
| null_latent_kf_strengthopt | FLOAT | 0.0000β10 | β |
| inherit_missingopt | BOOLEAN | true | β |
| guarantee_stepsopt | INT | 10β9007199254740991 | β |
| mask_optionalopt | MASK | β |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| TIMESTEP_KF | TIMESTEP_KEYFRAME | β |