Nodes/SComfyUI-Keyframe/Keyframe Apply
ComfyUI Node

Keyframe Apply

The node that makes ComfyUI actually honor per-frame denoise

By Scholar01·Created 3 years ago·Updated 2 years ago· 17
Keyframe Apply
  • model
  • latent
  • part_group
  • vae
  • model
  • latent

The name undersells it. "Apply" makes it sound like the last step, but Keyframe Apply is really the translator - the node that turns a pile of keyframe definitions into something the sampler will actually obey. You build those definitions with Keyframe Part and Keyframe Interpolation Part, then this node takes them plus your model, latent, and vae and hands back a model and latent that are ready to sample. Nothing about the per-frame effect exists until this node runs.

Why you'd reach for it: the gradual-denoiser effect. You've got real footage, and you want it to slowly transform into AI frames - starts faithful to the source, ends fully redrawn. The pre-pack way to do that was chaining several KSamplers at different denoise values and sampling the whole batch multiple times. That works, it's just brutally slow. This pack does it in a single pass, with a different denoise strength per batch index.

How it works

Keyframe Apply does two jobs. First, it VAE-encodes each keyframe image and writes it straight into your latent batch at that keyframe's batch_index - no decode-encode round trip, the source frame becomes the actual starting latent for that index. Second, it pins the keyframe group onto the model object. When sampling starts, the pack's wrapped sampler reads that payload and rebuilds a per-batch sigma schedule: a keyframe at denoise 0.1 gets a short, late slice of the noise schedule (barely touches your frame), one at 1.0 gets the full ramp (pure redraw). That's the standard denoise-truncation trick ComfyUI uses for img2img, applied per index instead of per whole batch.

The gotcha that trips everyone: the sampler

The per-frame magic only lives in three samplers the pack injects into ComfyUI at import - k_euler, k_euler_a, and k_lcm. If your KSampler is on plain euler or dpmpp_2m, the keyframe images still get baked into the latent, but your carefully-built denoise ramp is silently ignored. That's the classic report for this pack: "it loads, it prints apply keyframe messages to the console, and my video doesn't change." The fix is one dropdown.

The inputs and outputs that matter

  • model (MODEL) - from your checkpoint loader. The output model feeds your KSampler.
  • latent (LATENT) - the batch. Keyframe images get written into it at their indices.
  • part_group (LATENT_KEYFRAME_PART) - the definitions from Keyframe Part / Interpolation Part.
  • vae (VAE) - used to encode the keyframe images.

Outputs: model and latent, wired straight into a KSampler set to one of the three k_ samplers.

Installing it

ComfyUI Manager (search "ComfyUI-Keyframe", listed as SComfyUI-Keyframe), or manually:

cd ComfyUI/custom_nodes
git clone https://github.com/Scholar01/ComfyUI-Keyframe

Then restart ComfyUI. There's no requirements.txt, no model download, no heavy dependency - it only needs numpy and tqdm, which ComfyUI already ships. About as painless as a custom node gets.

Troubleshooting

  • "model is not injected, please use LatentKeyframeApply node to inject model" - you're on a k_ sampler but skipped this node. The k_ samplers demand it.
  • "Nothing changed" - check the sampler first, then check that your batch_index values are actually inside your latent's batch size.
  • The reported batch-slice bug - if a keyframe's IMAGE input carries more than one frame, apply_latent_keyframe writes the whole encoded batch into a single index. The fix reported in the wild is slicing the encode: self.encode(vae, part.image)[part.batch_index]. Easiest dodge: feed one frame per Keyframe Part node.
  • Resolution mismatch - the encoded keyframe has to match your latent batch's spatial size. The node auto-crops to a multiple of 8, but keep keyframe images at the same resolution as your batch anyway.

Fair warning, this is a small, unmaintained pack from the AnimateDiff era (last touched January 2025, with a fix for a calculate_sigmas import that had already rotted). It patches ComfyUI internals at import, so a 2026 ComfyUI update can break it without notice. Worth knowing who's behind it though: Scholar01 is the author of sd-webui-mov2mov, the A1111 vid2vid extension that started the "anime dancing" trend - this is his ComfyUI port of that same per-frame control idea, and it's one of the few places you'll find that idea in node form.

CategoryLatentKeyframeApply

Inputs (4)

NameTypeDefaultDescription
modelMODEL
latentLATENT
part_groupLATENT_KEYFRAME_PART
vaeVAE

Outputs (2)

NameTypeDescription
modelMODEL
latentLATENT