Painter Video Upscale
Wan video upscale, VAE-encode, and first/last frame lock in one node
- positive
- negative
- vae
- video
- start_image
- end_image
- positive
- negative
- latent
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'slatentinput. Note the README's warning: this latent is only the processed video, nothing else.positiveandnegative- your conditioning, but with two extra keys injected:concat_latent_imageandconcat_mask. This is Wan's first/last frame mechanism. The node builds a mid-gray placeholder video oflengthframes, dropsstart_imageinto the front andend_imageonto 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 aLoad Video-style node first. One obvious thing to get right: keepwidth/heightsane 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 to0and it auto-preserves aspect ratio; set both to0and 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.lanczosis the safe default for upscaling a source video before re-sampling.crop-centercrops 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
latentoutput decodes into static, you're almost certainly feeding a non-Wan VAE. Match the VAE to the model family. - Frame count mismatch.
lengthis about the conditioning buffer. If yourstart_imagehas more frames thanlength, 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
VAEDecodewith 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.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| positive | CONDITIONING | — | |
| negative | CONDITIONING | — | |
| vae | VAE | — | |
| video | IMAGE | — | |
| upscale_method | COMBO | 5 options: nearest-exact, bilinear, area, bicubic, lanczos | |
| width | INT | 5120–16384 | — |
| height | INT | 5120–16384 | — |
| length | INT | 811–16384 | — |
| crop | COMBO | 2 options: disabled, center | |
| start_imageopt | IMAGE | — | |
| end_imageopt | IMAGE | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| positive | CONDITIONING | — |
| negative | CONDITIONING | — |
| latent | LATENT | — |