Kandinsky 6 Image to Video+Audio
The Node That Splices Your Start Frame Into a Video+Audio Generation
- positive
- negative
- empty_latent
- reference_latent
- positive
- negative
- joint_latent
Text-to-video+audio is the easy sell, but image-to-video is where the useful work is: you already have the frame you want, you already like the character's face, and you want five seconds of them moving and talking. The catch is that this model doesn't take an image. It takes a latent, encoded a specific way, sitting in a specific slot.
Why a dedicated node
Kandinsky 6's I2VA conditioning scheme is called tail_cond_first_frame, and what it means in practice is that the reference frame isn't an extra input bolted on the side - it's an extra latent frame appended to the video stream, with a mask that keeps it clean for the entire denoise.
You can build that by hand if you enjoy rebuilding it every time the shape changes. This node fixes the layout and keeps ComfyUI's stock interfaces intact: the image is scaled with ImageScale, encoded with the normal VAEEncode (the Hunyuan video VAE), and this node does the one K6-specific bit - concatenate it on the temporal axis and mask it.
How it works
It validates the empty latent, pulls out the video stream, and checks your reference latent hard. It must be a plain, non-nested video latent, exactly one latent frame, and it must match the empty latent's batch, channels, height and width. Then it concatenates the reference onto the end of the video stream, sets noise_mask to 1s everywhere except that final frame (which stays 0, so the reference is never noised), flags the latent with k6_reference_tail plus a record of how many frames are actually yours, and stamps the same flag onto both conditionings.
That mask is why the reference survives. Under ComfyUI's standard inpaint semantics the zeroed frame is held at its clean value every step, and the pack's model adapter additionally hands back the clean latent from scale_latent_inpaint - the validation notes put the round-trip error around 1e-7, i.e. the reference comes back essentially untouched.
Inputs and outputs
positive / negative - the CONDITIONING from your Kandinsky 6 Text Encode nodes (prompt and the junk negative, in the shipped workflows).
empty_latent - from Kandinsky 6 Empty Latent. Same resolution you scaled the image to.
reference_latent - the single-frame latent from a stock VAEEncode.
Three outputs, all of which go somewhere: positive and negative into the sampler (they now carry the reference-tail flag), and joint_latent into the sampler's latent_image.
The one thing you can't tune here is denoise. Leave it at 1.0. The reference frame is preserved by the mask, not by a partial denoise, and dialling denoise down just degrades the whole clip.
The image has to match. Really match.
Resize before encoding. The node compares the reference latent's batch/channels/height/width against the empty latent and refuses on mismatch, with a message telling you to resize the input image to the generation width and height. A portrait photo at 832×1216 dropped into an 864×480 workflow will fail here, not later - which is a mercy, because the alternative is five minutes of sampling followed by a shape error.
The shipped I2VA workflows do exactly this: LoadImage → ImageScale → VAEEncode → this node. The pack also copies a sample portrait into ComfyUI/input on install, so the template runs out of the box.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/T8mars/Comfyui-Kandinsky-T8.git
cd Comfyui-Kandinsky-T8
python -m pip install -r requirements.txt
Restart ComfyUI afterwards. If the official Kandinsky 6 extension is installed, disable it - the node names collide. ComfyUI 0.39.0+ required, and an NVIDIA GPU with INT8 tensor cores, because the released DiTs are single-file INT8 ConvRot conversions loaded through the stock UNETLoader. That format is worth knowing about: ConvRot INT8 is community-invented, native to ComfyUI since mid-2026, and it works on 20/30/40/50-series cards - including 30-series, which have no fp8 acceleration at all.
Where it goes wrong
Tail mismatch. Two paths to it: your image wasn't resized to the generation size, or the "latent" you fed in was already nested (i.e. you wired the joint latent back in by mistake instead of a VAEEncode output). The error names which.
Forgetting the cleanup node. After sampling, the joint latent still contains that reference frame as a real entry. Decode it as-is and your clip starts with a duplicate first frame. Kandinsky 6 Remove I2VA Reference strips it - and it will tell you off if the metadata isn't there, which is a strong hint that you wired the sampler's input rather than its output.
Distilled + masks. PiFlow distilled checkpoints require CFG=1, denoise=1, and one global full-range conditioning. The only masking the pack guarantees is the clean reference tail in this workflow, so don't bolt extra masks onto a distilled I2VA run and expect the same behaviour you'd get from a base model.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| positive | CONDITIONING | — | |
| negative | CONDITIONING | — | |
| empty_latent | LATENT | — | |
| reference_latent | LATENT | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| positive | CONDITIONING | — |
| negative | CONDITIONING | — |
| joint_latent | LATENT | — |