MiniMax H3 Per-scene Keyframe Timing
Your MiniMax H3 keyframes are anchored to the wrong frames — one node fixes the indices
- conditioning
- CONDITIONING
This is the smallest node in this batch and possibly the most confusing to look at. Two integers, a conditioning passthrough, no help text. It's also the fix for a subtle class of "why is my image-to-video ignoring my start frame" bug, so it's worth ten minutes.
The underlying situation: in MiniMax H3 image-to-video conditioning, the keyframes you supply don't live where you'd expect. They're not a separate conditioning channel with a count attached. They're metadata on the conditioning - an entry called minimax_keyframes holding a list of frames, each with a resolved_frame_index saying which frame of the generated clip it should land on. If that index is wrong, the model puts your carefully prepared start pose somewhere it doesn't belong, and the whole scene drifts from frame one.
That happens all the time in a multi-scene project, which is the workflow this pack is built around (LTX 2.3 and MiniMax H3, scene by scene, in a music video or storyboard). The first scene runs the default 48-frame window, so index 0 and index 47 are right. Then scene four gets trimmed, or the retained range shifts because of how the sequence was assembled, and the conditioning coming in still thinks it's working on a 0–47 clip. Your first frame is no longer frame 0 of what's actually being rendered.
What it actually does
It copies the conditioning metadata without copying any tensors, and rewrites exactly two numbers inside minimax_keyframes:
- the first frame entry's
resolved_frame_indexbecomesfirst_frame_index - the last frame entry's
resolved_frame_indexbecomeslast_frame_index- but only if there's more than one keyframe
Everything else in the metadata dict is preserved, so if your conditioning carries other keys (and H3 conditioning usually does), nothing gets dropped by accident. The embedding tensor itself is passed through untouched; this is a label change, not a re-encode. And if the conditioning has no minimax_keyframes at all, the node shrugs and hands it back unchanged - it's safe to leave in a graph that only sometimes uses keyframes.
Inputs and outputs
Three required inputs, no optionals, one output.
conditioning is whatever your H3 text/keyframe encode gives you. first_frame_index defaults to 0 and last_frame_index to 47 - the stock 48-frame scene. Both are INT with a minimum of 0. The output is a CONDITIONING that goes straight into your sampler's positive input, in place of the encode you'd otherwise have wired there.
Those two numbers are the whole configuration. Set them to the frame range the scene is actually going to keep after trimming - the same range the rest of your graph is rendering - not to the model's maximum.
One guard worth knowing: it raises if first_frame_index is negative or if last_frame_index comes before first_frame_index. That's the author saving you from a silent no-op. If you're driving these values from elsewhere and the graph blows up with a range error, the upstream number is the bug, not the node.
Install
ComfyUI Manager → search vrgamedev, or:
cd ComfyUI/custom_nodes
git clone https://github.com/vrgamegirl19/comfyui-vrgamedevgirl
Restart ComfyUI and hard-refresh the browser tab - the pack ships a lot of front-end JavaScript and a stale cache will make you think the install failed.
You do not need the pack's requirements.txt for this node. It's pure Python over conditioning dicts; no torch work, no models, no downloads. If you install the requirements anyway because you want the Builder elsewhere in the pack, budget time for it - demucs, stable-ts, torchcodec and llama-cpp-python all come along, and llama-cpp-python in particular may try to compile on Windows.
Where to reach for it
You need this when you're chaining scenes with first/last-frame anchors - the chained First/Last Frame sequences that keep a multi-scene render continuous instead of having every scene restart from a fresh pose. In that setup, each scene's keyframes are computed for that scene's range, and every scene's range is different. This node is how you tell the conditioning the truth.
If you're rendering single self-contained clips, you can ignore it entirely. The default 0/47 is already correct, and adding the node just gives you two more widgets to misconfigure.
The other honest use: debugging. When someone posts "my i2v keyframe shows up in the middle of the clip," the usual answer is that the retained range and the declared range disagreed. Drop this in, set the range explicitly, and watch whether the symptom moves. If it does, you found it.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| conditioning | CONDITIONING | — | |
| first_frame_index | INT | 0 | — |
| last_frame_index | INT | 47 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| CONDITIONING | CONDITIONING | — |