Nodes/comfyui-timesaver/TS Latent Upscale
ComfyUI Node

TS Latent Upscale

The right way to upscale MiniMax H3 video without melting your GPU

By AlexYez·Created 2 years ago·Updated a day ago· 11
TS Latent Upscale
  • model
  • conditioning
  • latent
  • noise
  • sampler
  • sigmas
  • negative
  • latent
  • segments_info
upscale_model
width1280
height704
chunk_length136
temporal_overlap17
anchor_strength1.00
precisionfp16
devicecuda
cfg1.0

MiniMax H3 renders its clips in a fixed latent box - 1280×704 by default - and if you want the final video bigger than that, decoding and then upscaling pixels is the wrong move. The detail lives in the latent; that's where you enlarge it, then re-sample so the model redraws at the new size. TS Latent Upscale is the node that does that for H3's audio+video latent, chunked so your VRAM only ever holds one slice of the clip instead of the whole thing.

It's a merge of three nodes from Comfyui-MMH3-UltimateUpscale (MIT, by bbaudio-2025) into one. The pipeline, the upscale-model settings and the temporal-split settings were separate nodes that nobody used apart, so Timesaver just turned them into inputs. It also fixed the original's blind spots: subfolders in models/latent_upscale_models actually show up now, and precision handling got a safe fallback.

How it works

Per chunk of the clip: cut along time with an overlap → upscale that chunk's video latent with the H3 3D upscaler (audio untouched, since H3's soundtrack doesn't live in the video latent) → re-anchor the conditioning and pin the chunk's frame 0 to the previous chunk's result → sample → stitch back over the overlap. Peak VRAM is one chunk, not one clip, and the diffusion model is offloaded while the upscaler works because the two are never needed on the card at once. Chunks get upscaled in groups, so that multi-gigabyte reload happens once per batch instead of once per chunk.

The inputs that matter

  • upscale_model - the dropdown. The minimax_h3_latent_upscaler_3d checkpoints from models/latent_upscale_models (subfolders listed as subfolder/file.safetensors), or the Interpolation: entries, which need no model at all. Those are quicker and lighter, but they invent no detail.
  • chunk_length and temporal_overlap - your VRAM dials. Both must be multiples of 17, the model's keyframe grid, and that's checked before the run rather than half an hour into it. 136 ≈ 5.7 s at 24 fps. The tooltip's starting points: 34–68 frames on 8 GB, 51–102 on 12 GB, 102–153 on 16 GB, 136–170 on 24 GB.
  • width / height - target size, snapped to multiples of 32, and must match what the conditioning was made for.
  • anchor_strength - how firmly each chunk's first frame is held to the previous chunk's result. 0.999 is the model's default; drop toward 0 and the seam drifts.
  • precision - fp16 default, and on H3 it's also the more accurate half-precision path (0.38% deviation vs 2.67% for bf16, which spends mantissa bits on a range the weights never use).

Everything else - model, conditioning, latent, noise, sampler, sigmas - comes straight from your existing H3 graph: the model that generated the clip, its conditioning, a noise source, a sampler and a sigma schedule. Wire the optional negative plus cfg and you get CFG-guided sampling; leave negative unconnected and it samples on the positive alone. Output is the latent you decode, plus segments_info, a debug dict of per-chunk frame and token ranges for when a seam misbehaves.

Install

Install is just the pack: ComfyUI Manager → search "Timesaver", or cd ComfyUI/custom_nodes && git clone https://github.com/AlexYez/comfyui-timesaver, then restart. No extra pip packages for this node. The one thing to fetch yourself is the upscaler weights - the minimax_h3_latent_upscaler_3d safetensors into models/latent_upscale_models/. And before you start generating at all: H3's weights are geofenced. The community licence excludes the US, EU, UK and South Korea, so check you're licensed to run them before spending an afternoon upscaling.

Common issues

Where people get burned: picking an upscaler from another model family, which fails with Missing key(s) in state_dict - these weights are H3-only. And running bf16 on a Turing-era card where it's emulated in software; the node notices and falls back to fp16 by itself. If it still won't fit, shorten the chunks. There's no tiling option to reach for - spatial tiling was deliberately dropped, because seams need their own fade and blend settings and a clip that needs tiling is better served by shorter chunks.

CategoryTS/Video

Inputs (16)

NameTypeDefaultDescription
modelMODELDiffusion model used to re-sample every chunk (the guider is built internally).
conditioningCONDITIONINGConditioning this latent was generated with. It is re-anchored in time per chunk, and its frame-0 keyframe is pinned to the previous chunk's re-sampled frame.
latentLATENTDenoised MiniMax H3 audio+video latent to enhance.
noiseNOISENoise source; one noise tensor per chunk.
samplerSAMPLERSampler used for every chunk.
sigmasSIGMASSigma schedule used for every chunk.
upscale_modelCOMBOHow to enlarge each chunk. The H3 latent upscale checkpoints come from models/latent_upscale_models, subfolders included and listed as 'subfolder/file.safetensors' — these are the minimax_h3_latent_upscaler_3d weights, and an upscaler for another model family will not load here. The 'Interpolation' entries need no model at all: quicker and lighter, but they invent no detail.
widthINT128064–4096Target frame width in pixels, snapped to a multiple of 32 (the upscaler's grid). Must match the size the conditioning was made for.
heightINT70464–4096Target frame height in pixels, snapped to a multiple of 32. Must match the size the conditioning was made for.
chunk_lengthINT13617–100000Pixel frames per chunk at 24 fps, and a multiple of 17 — one keyframe grid step. 136 ≈ 5.7 s, 153 ≈ 6.4 s. Aim for the longest chunk that keeps peak VRAM just under capacity: the original author's starting points are 34–68 frames on 8 GB, 51–102 on 12 GB, 102–153 on 16 GB and 136–170 on 24 GB. Shorter chunks are safer but pay the overlap tax on every seam.
temporal_overlapINT170–100000Frames shared between consecutive chunks, a multiple of 17 and smaller than chunk_length. This is the material the seam cross-fades over; 17 is the usual choice.
anchor_strengthFLOAT1.000–1How firmly each chunk's first frame is held to the previous chunk's result. 1.0 = exactly that frame, 0.999 = the model's own default, 0.0 = no anchoring at all (expect the seam to drift).
precisionCOMBOfp16Precision the upscaler runs at. fp16 is the usual choice — measured against fp32 on the H3 checkpoint it is also the more accurate of the two half-precision paths (0.38% vs 2.67% deviation), because bf16 trades mantissa bits for a range these weights never use. On a card without native bfloat16 (Turing and older) bf16 falls back to fp16 automatically.
deviceCOMBOcudaWhere the upscaler runs. On cuda the diffusion model is offloaded first, so the two never sit on the card together.
negativeoptCONDITIONINGNegative conditioning. Connected, sampling uses a CFG guider with the value below; otherwise the positive prompt alone.
cfgoptFLOAT1.00–100CFG scale, used only when 'negative' is connected.

Outputs (2)

NameTypeDescription
latentLATENTUpscaled, re-sampled and stitched H3 audio+video latent.
segments_infoDICTDebug: per-chunk frame ranges, token ranges and the size each chunk was upscaled to.