Zura · Anchor Approved H3 Start Frame
Tired of H3 drifting off your approved first frame? Pin it instead
- latent
- start_frame_latent
- anchored_av_latent
The problem it solves
MiniMax H3 generates picture and audio in one joint pass - one latent holding video frames and an audio stream. When you spend five minutes building a starting frame you're happy with and then animate it, you want frame one of the render to be that frame. What H3 gives you instead is a render that starts near it: same face, slightly different jaw, different framing, sometimes a different person entirely if the conditioning is loose.
The usual answer is an image guide. Guides are strong suggestions, not constraints - they're conditioning, and conditioning loses to noise whenever the sampler feels like it.
ZuraH3LockStartFrame - Zura · Anchor Approved H3 Start Frame - takes the other route. It reaches into the joint AV latent before sampling and overwrites frame one with your encoded still, then zeroes the video noise mask on that frame so the sampler has nothing to re-roll there. Conditioning persuades; a zero noise mask just is.
What it does, exactly
Two latents in, one out. Both have to be real H3 objects:
latentmust be aNestedTensorof exactly two tensors - video and audio. The video tensor must be[1, 24, frames, H, W], the audio[1, 32, 2, …]. Anything else and you get "Connect a native H3 joint video/audio latent."start_frame_latentmust be a single encoded frame, and its shape must equalvideo[:, :, :1]- same channels, same spatial dimensions. In practice that means one image, encoded through the H3 video VAE, at the target render resolution. A different VAE, a batch of frames, or a mismatched size each trip a specific error.
It then clones the video latent, writes your still into position zero, and builds the mask: if the latent came in with no mask, both streams get all-ones; if it had one, that mask is broadcast to the take. Either way, video_mask[:, :, :1] = 0. The audio mask is untouched - you're pinning a picture, not the sound.
Output anchored_av_latent goes into your H3 sampler exactly where the original latent went. The visible VAEEncode and sampler stay in the graph; this is a data-only adapter, not a replacement for your pipeline.
Why you still need the image guide
The node's own description says it: use it alongside a native image guide, not instead of performance conditioning. It guarantees the first frame matches your still. It does not tell the model what the person should be doing in frame thirty. The guide does that, and both jobs are separate.
It's also worth knowing the pack rates its two H3 starting-image routes differently - "use references directly" is the tested path, while "build from references" adds a native first-frame guide but is explicitly less qualified. If the generated-frame path is drifting on you, this node is the belt to the guide's braces.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/ZURAVFX/ComfyUI_zura_nodes
cd ComfyUI_zura_nodes && pip install -r requirements.txt
or search Zura Nodes in ComfyUI Manager, install the ZURAVFX entry, restart. No new dependencies for this node - it imports torch and ComfyUI's own NestedTensor and does tensor slicing. You do of course need H3 weights, which are separate downloads (the transformer, the Qwen3-VL text encoder, and both the video and audio VAEs), plus the H3 community licence, which excludes several territories - check that before you download 30 GB.
Where to look when it errors
The error strings are unusually diagnostic here, so read them literally:
- "Expected one MiniMax H3 video/audio take." The shapes didn't match - usually you're on an image-model latent, or an H3 latent that's been through something that flattened the nested structure.
- "Encode exactly one approved image at the target resolution using the H3 video VAE." Three failure modes in one sentence: wrong VAE, more than one image, or a resolution that doesn't match the take. Encode at the same width and height you're sampling at.
- "Existing H3 masks do not match this take." Something upstream produced a mask that can't be broadcast to your latent shape - usually a re-used mask from a differently sized previous take.
And the honest caveat: a pinned first frame makes drift visible at the join. If frame one is exactly your still and frame two has wandered, you've traded a soft open for a possible pop. Check the first half-second before rendering the whole thing.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| latent | LATENT | — | |
| start_frame_latent | LATENT | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| anchored_av_latent | LATENT | — |