H3 Motion Context Save Video With Latent (Distributed)
Save the Clip and the Continuation State as One File, Then Delete the Bookkeeping
- video
- video
- video_path
Every long-video pipeline ends up with two artifacts per take: the clip you watch, and the state blob you continue from. Keep them as separate files and you've signed up for a naming discipline that fails the first time you rename one, overwrite one, or continue from the wrong take without noticing until forty seconds of render later.
This node squashes them into one file. The video you save carries its own H3 latent inside the container, so picking a winner is just picking a video.
How it works
The latent arrives as a base64 blob (roughly 1.33× its raw size) in the video's container metadata, under a tag named h3_motion_context_latent_v1. Same mechanism ComfyUI itself uses to embed workflow JSON in saved media - which is the useful part, because this node also writes the standard prompt and workflow chunks. So the file is still draggable back into ComfyUI to restore the graph, and it still drops those chunks under --disable-metadata the way core does.
The latent key, though, gets written either way. Disabling metadata hides your prompt, not your chain state. Worth knowing before you assume a save is clean.
It also does a piece of translation you'd otherwise get wrong. Each latent is stored under a key tied to which participant produced it, but Image Batch Divider numbers its outputs batch_1, batch_2, … participant_index maps one to the other. Whether batch_1 is Master's own take or the first worker depends on delegate_only, which is only readable here because this node always runs on Master.
The inputs that matter, and the outputs
Four required fields:
video- a VIDEO fromCreate Video, fed by the matchingbatch_N.participant_index(1–64, default 1). Must match thebatch_Nthat video came from;batch_2means2. Get this wrong and you either fail loudly or embed the wrong take's context - the loud failure is the lucky case.filename_prefix(defaulth3_chain/clip) - same semantics as any save node, subfolder included.format-mp4,mkvorwebm.
Two outputs: video (pass-through, so you can keep chaining downstream) and video_path (a STRING, relative to the output directory - deliberately relative, since the file may be picked up on a different machine and an absolute OS path wouldn't resolve there). It's an output node, and it returns the same UI payload shape as core's Save Video, so you get an inline player in the graph. That's how you compare candidates: press queue, watch videos, pick one.
Installing it
Prerequisites: ComfyUI-Distributed and ComfyUI-H3-Motion-Context, both working, on Master and every worker.
cd ComfyUI/custom_nodes
git clone https://github.com/ymiyad/ComfyUI-H3MC-Distributed.git
Restart ComfyUI. Manager will find it by pack title too. The single declared dependency is av (PyAV); torch and safetensors ship with ComfyUI. This node hard-errors if PyAV isn't importable, because it has to open the container to write the tag.
Where it goes wrong
"no latent stored for job=… participant_index=…". The save node looks up what Upload Latent stored this run and finds nothing. Two causes, both common. Either participant_index doesn't match the batch_N the video came from, or too much time passed: uploaded latents live in ComfyUI/temp/h3_distributed_latents/ and are pruned after six hours. Six hours is generous for a round, but it is not "come back tomorrow."
The clip plays but won't continue the chain. Something re-encoded it. Uploading to a host and re-downloading, transcoding, trimming in an editor - all of it strips container metadata. This is the same failure that eats ComfyUI workflow metadata out of PNGs (why), and it has the same fix: keep the original, treat the re-encoded copy as a preview. For long or high-resolution clips, try mkv: base64 in MP4 metadata works fine in testing, but Matroska is the more natural container for arbitrary embedded payloads, and the README suggests it as the fallback if MP4 gives you trouble.
You're on one machine and don't need any of this. It still works. With no Distributed graph, Upload Latent stores locally, this node's participant_index = 1 hits that local slot, and the loader reads the file back. The "one file is the continuation state" model is genuinely nicer than a folder full of sidecars even at a single-GPU desk - and given how much of H3 long-form work is still manual clip-by-clip assembly (the pattern across every video model right now, Wan included), anything that removes a bookkeeping step is worth the ten minutes.
One caveat: this pack is new and has no community footprint in the reddit corpus yet, so there's no pile of other people's error messages to search. The save log prints the embedded payload size - a sudden 13 MB-versus-84 MB jump means keep_tail_frames changed upstream.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| video | VIDEO | From Create Video, fed by the matching batch_N from Image Batch Divider. | |
| participant_index | INT | 11–64 | Must match the batch_N this video came from (batch_1 -> 1, batch_2 -> 2, ...). |
| filename_prefix | STRING | h3_chain/clip | — |
| format | COMBO | mp4 | 3 options: mp4, mkv, webm |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| video | VIDEO | — |
| video_path | STRING | — |