H3 Drift Control (alpha)
The node that stops chained segments from going mushy
- model
- latent
- full_sigmas
- model
- report
Chain H3 clips together long enough and the joins stop being clean in a way that's hard to put your finger on. The culprit is subtle: a chained segment's carried video prefix is bit-clean - the exact same conditioning fed to the model every single step. One seam loves that. A chain doesn't. Repeated clean conditioning accumulates contrast and texture error, and the pack measured the join decaying from about 0.9 at the first join to about 0.65 by the second, across every variant tested. That's H3 Drift Control's problem to solve.
The fix is delightfully counterintuitive: add a little of the sampler's own noise back to the disposable carried prefix, at every model evaluation, tapering to exact at the seam end. The model stops treating the prefix as impossibly clean - because it isn't anymore - and the accumulated error stops compounding. The README's numbers: joins hold 0.85-0.89 through link 4 on the newer chain, where the pre-fix chain fell to the 0.65 class by its second join.
How it works and what it demands
It clones your model and installs a dynamic denoise-mask patch, sized from the latent you give it. The wiring is short but specific:
model- the same base H3 model your pass-1 guider would use.latent- the H3 V2V Init output, which supplies the video shape. It must already carry the noise mask - wire H3 V2V Init first; this node rewrites that mask, it doesn't create one, and it will error if there's nothing to rewrite.prefix_frames(39),matched_steps(8),taper_steps(4) - the recipe. 39 frames = 12 latent steps on the 17k+5 grid, andmatched_steps+taper_stepsmust sum to exactly that. 8 + 4 is the field-validated combination; the node enforces the constraint rather than guessing.
Feed your guider the node's model output, and it handles the rest. Audio is deliberately untouched - the frozen per-tick audio prefix stays hard, so dialogue continuity isn't disturbed by the fix that's saving the video.
The two refusals (both are features)
The node refuses to stack on another dynamic denoise-mask patch - two of them can't share a model, and it will tell you so. And it does not support sigma-split samplers: the pack's own graphs run one SamplerCustomAdvanced per pass, and this node assumes that shape. If you're running a split schedule, restructure before you add this.
Honest status
The matched+taper recipe is still one recipe, not a swept space - it's been replicated across two chains and new seeds, but the "one right setting" hasn't been mapped. Treat it as a well-measured default rather than a tuned answer. And remember it's adapted from Contex-Loop's Drift-Control AV (GPL-3.0), with the credit lines in h3_drift.py spelling out what was ported and what wasn't.
Installing it
Pure Python:
cd ComfyUI/custom_nodes
git clone https://github.com/matlowai/ComfyUI-MAINodes
Restart, look under MAINodes/alpha. Example graphs want ComfyUI-KJNodes; the nodes don't. H3 weights are community-licensed (US, EU, UK, South Korea excluded). If you're chaining segments, this plus H3 Delta Color Carry are the two hygiene nodes worth knowing - drift for the conditioning, color carry for the VAE round trips, and they don't overlap.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | the base H3 model your pass-1 guider would use | |
| latent | LATENT | H3 V2V Init output: supplies the video shape and must carry the static noise_mask | |
| prefix_framesopt | INT | 395–3600 | carried handle in pixel frames, on the 17k+5 grid; 39 -> 12 latent steps |
| matched_stepsopt | INT | 80–400 | older prefix steps held at full matched noise |
| taper_stepsopt | INT | 41–400 | steps ramping matched -> exact toward the seam end; matched+taper must equal the prefix's latent steps |
| full_sigmasopt | SIGMAS | optional: the complete schedule if the sampler only sees a partial one; usually leave unwired |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| model | MODEL | — |
| report | STRING | — |