CoachBateShotKeyframes
Start and end frames, placed at the right timestamps, from the shotlist
- conditioning
- latent
- vae
- conditioning
- latent
Anchors without anchor maths
Keyframe conditioning is the most reliable way to make a video model land a shot: give it the
first frame, give it the last frame, let it fill the middle. In a shot-by-shot pipeline it's also
the most annoying thing to keep straight, because the second anchor's position isn't zero - it's
the end of the shot, which is duration × 24 frames, and if the shot continues from a previous
one there's a context prefix in front of all of it.
CoachBateShotKeyframes does that arithmetic and hands the result to the installed H3 keyframe
nodes. Inputs are conditioning, latent, vae and shot_payload; outputs are conditioning
and latent. It reads start_image, end_image, start_image_strength, end_image_strength
and edit_duration_seconds (falling back to duration_seconds) out of the shot record, opens the
images, and places them: the start image at frame 0, the end image at
context + ceil(edit_duration × 24) − 1.
If the shot has no usable anchors - no images, or a strength of 0 - it returns your inputs untouched. No images, no work, no cost.
Soft anchors or hard ones
hard_frame_anchors in the shot record chooses the mechanism, and it's a real difference:
- Off (default): the node calls
MiniMaxH3CustomKeyframes, which applies the images to the conditioning. The frames guide the model. Cheaper, more forgiving, and the model can still move away from them if the prompt argues. - On: it calls
MiniMaxH3CustomKeyframesMaskedand applies them as real masked anchors on the latent, so those frames are held. This is the "the first frame must be this frame" mode.
Hard anchors need a two-stream AV noise mask, so the node compacts Concat AV's channel-expanded masks down to a single channel per stream before handing them over - and it refuses if the mask is channel-dependent, because silently dropping channels would change values rather than just shapes.
One conflict is caught explicitly: with a continuation context present (you're continuing from a
previous shot's output), a start_image isn't allowed, because the model can't start from two
different first frames. The error says exactly that - "Use a source video OR a first-frame still,
not both" - and it's the right call, even if you'll hit it once by accident.
Why the timestamp maths matters
Everything in this pipeline is pinned to 24fps: frame counts are duration × 24, continuation
context lengths are 39/90/141 frames, and the latent grid is 17k+5. If you place an end anchor by
hand at "duration seconds × 24" while a continuation prefix is in front of the clip, the anchor
lands 39 frames early and H3 dutifully builds the shot to end before it should. Letting the node
compute the position from the same fields the rest of the pipeline uses is the whole point; it's
not a convenience wrapper, it's the thing that keeps the anchors on the grid.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/CoachBate/ComfyUI-CoachBate.git
Or ComfyUI Manager → search "CoachBate" → restart. Category CoachBate. It needs ComfyUI's H3
keyframe nodes present - MiniMaxH3CustomKeyframes and, for hard anchors,
MiniMaxH3CustomKeyframesMasked - and the H3 model set (model, text encoder, video and audio VAE)
in the usual folders. No pip dependencies of its own.
Where people get burned
- The shot ignores the end frame.
end_image_strengthis 0, or the image path doesn't exist - which the loader already reports as 0.0 strength with a toast, so check there first. - "Use a source video OR a first-frame still, not both." - continuation plus a
start_image. Pick one; the continuation already supplies the first frames. - Hard anchors error out about the noise mask. Something upstream produced a channel-expanded mask that can't be compacted; check what's feeding the latent.
- The end frame lands a beat early. You set
edit_duration_secondsshorter thanduration_secondson purpose - which is correct if that's your editorial intent, and confusing if it isn't.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| conditioning | CONDITIONING | — | |
| latent | LATENT | — | |
| vae | VAE | — | |
| shot_payload | STRING | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| conditioning | CONDITIONING | — |
| latent | LATENT | — |