Nodes/ComfyUI-PainterNodes/Painter Video Upscale
ComfyUI Node

Painter Video Upscale

Wan video upscale, VAE-encode, and first/last frame lock in one node

By princepainter·Created 7 months ago·Updated 3 days ago· 191
Painter Video Upscale
  • positive
  • negative
  • vae
  • video
  • start_image
  • end_image
  • positive
  • negative
  • latent
upscale_method
width512
height512
length81
crop

If you've stared at a Wan 2.1/2.2 "upscale" workflow and wondered why it needs six nodes just to get the video ready for the sampler, this is the node that collapses them into one. Painter Video Upscale takes your video, resizes it, encodes it to latent space, and bakes first/last frame anchors into the conditioning - all in a single pass. It's from the same "Painter" author behind the LTXV2 and LongVideo packs, but unlike those it's a humble prep utility, not a magic feature.

The name oversells it slightly. This node doesn't upscale and stop - the whole point is that it sets up the next step. Your source video arrives as an IMAGE (a stack of frames), gets scaled to your target width/height, and is pushed through the vae with vae.encode(). That encoded result comes out the latent output, ready to feed a KSampler. Then the sampler denoises it back up at the higher resolution - that's the actual "upscale." Set the KSampler's denoise low and you're refining pixels; crank it and Wan is reimagining the whole clip. The node itself just does the prep.

What the three outputs actually are

  • latent - the VAE-encoded version of your (possibly resized) video. This goes into the sampler's latent input. Note the README's warning: this latent is only the processed video, nothing else.
  • positive and negative - your conditioning, but with two extra keys injected: concat_latent_image and concat_mask. This is Wan's first/last frame mechanism. The node builds a mid-gray placeholder video of length frames, drops start_image into the front and end_image onto the back, encodes that whole thing, and computes a mask where those anchored frames are "keep this" (0) and everything else is "denoise" (1). Both outputs carry the same keys, so wire both into the KSampler.

That concat trick is how Wan lets you lock the opening and closing frames of a clip so they don't drift - you're literally giving the model a picture of the boundaries and telling it to preserve them. length (default 81) only affects that conditioning prep, not your input video, so leave it near your actual frame count. And if you skip start_image/end_image, the node degrades gracefully to a plain upscale-and-encode.

The inputs that matter

Only a few need your attention:

  • video - needs to be a frame stack, so load it with Video Helper Suite or a Load Video-style node first. One obvious thing to get right: keep width/height sane for Wan (multiples of 16; 1280×720 is the native 14B sweet spot), because it's a 3D causal VAE with 8× spatial and 4× temporal compression and it'll silently hate weird dims. Set either to 0 and it auto-preserves aspect ratio; set both to 0 and it skips resizing entirely.
  • vae - must be a Wan-family VAE (16 latent channels). Drop an SDXL VAE in here and you'll get noise, not video.
  • upscale_method - the usual ComfyUI suspects: nearest-exact, bilinear, area, bicubic, lanczos. lanczos is the safe default for upscaling a source video before re-sampling.
  • crop - center crops after resizing instead of squishing; useful when your source aspect ratio doesn't match the target.

Installing it

This is the easiest part, because the whole pack is one Python file with zero dependencies - no requirements.txt, nothing to pip-install. Either use ComfyUI Manager and search for ComfyUI-PainterVideoUpscale, or:

cd ComfyUI/custom_nodes
git clone https://github.com/princepainter/ComfyUI-PainterVideoUpscale

Then restart ComfyUI. There are no model files to download beyond the Wan checkpoints and VAE you're already running.

Where people get burned

The common failure is wiring it up wrong, not the node itself. A few real gotchas:

  • Wrong VAE. If your latent output decodes into static, you're almost certainly feeding a non-Wan VAE. Match the VAE to the model family.
  • Frame count mismatch. length is about the conditioning buffer. If your start_image has more frames than length, it gets truncated; keep the placeholder long enough for what you're anchoring.
  • Decoding the output. The latent comes back out as a latent - you still need a VAEDecode with the same VAE to get pixels, then a video-save or Video Combine node. People forget the round trip and think the node ate their video.

One more thing worth saying: because custom nodes run arbitrary Python on load, it's nice that this pack's entire logic is ~100 lines of stock ComfyUI API calls (common_upscale, vae.encode, conditioning_set_values). You can read all of it in two minutes before you trust it. For a Wan upscale-and-refine pipeline, it's the one node I'd reach for first.

CategoryPainter/Video

Inputs (11)

NameTypeDefaultDescription
positiveCONDITIONING
negativeCONDITIONING
vaeVAE
videoIMAGE
upscale_methodCOMBO5 options: nearest-exact, bilinear, area, bicubic, lanczos
widthINT5120–16384
heightINT5120–16384
lengthINT811–16384
cropCOMBO2 options: disabled, center
start_imageoptIMAGE
end_imageoptIMAGE

Outputs (3)

NameTypeDescription
positiveCONDITIONING
negativeCONDITIONING
latentLATENT