UltraTex Foreground VAE Decoder
The swap that stops your texture fringing at the edges
- vae
- VAE
Of the nine nodes in this pack, this is the one that looks most pointless on the canvas - VAE in, VAE out, one dropdown - and the one whose absence you'd notice most in the final texture.
The short version: UltraTex doesn't decode six pictures of your object so much as it decodes six foreground cut-outs sitting on black, with the silhouette masks composited over white afterwards. The project ships its own decoder (decoder.pt) trained for exactly that job. Stock FLUX VAE decoders aren't. This node swaps the decoder weights into the VAE you already loaded.
What it actually does
It loads decoder.pt, takes the VAE's state dict, and replaces the decoder tensors one by one - it also matches post_quant_conv against the top-level key, and prefixing everything else with decoder.. The encoder is left completely alone; nothing here changes how images or latents are encoded, only how latents become pixels. Then it builds a new VAE object from the patched state dict and validates it before handing it over.
That's a genuinely conservative implementation, and it pays off in the error messages. If a key in your decoder.pt has no counterpart in the VAE you loaded, you get "has no counterpart in this VAE (wrong backbone?)". If the shapes don't match, you get the specific tensor and both shapes. Both of those mean the same thing in practice: you're mixing FLUX.1 and FLUX.2 parts. They are not interchangeable, they're separate checkpoints (flux1/decoder.pt and flux2/decoder.pt), and this is the most likely way to break this node.
Inputs and output
vae is your loaded VAE - the FLUX.2 one (flux2-vae.safetensors) if you're on the Klein path. decoder_name is a dropdown built from the models/ultratex folder plus the regular models/vae folder, which is a nice touch: you can drop the file in either place and it shows up. Output is a VAE, and it slots between Load VAE and UltraTex Sampler.
The pack registers the models/ultratex folder itself, so it gets created the first time you load the pack. If you're adding the file while ComfyUI is running, restart rather than refresh - folder scanning happens at import. And do rename on the way in: a bare decoder.pt sitting next to an ultratex_flux2_decoder.pt is exactly the kind of ambiguity that costs you twenty minutes six months later.
Where it sits in the graph
Load VAE (flux2-vae) ─ UltraTex Foreground VAE Decoder ─ UltraTex Sampler.vae
Only the sampler uses it in a normal workflow, but note the node output is a full VAE object - anything downstream that decodes will use the foreground decoder too. In this pipeline that's fine and in fact what you want, since the bake reads the decoded views.
What happens if you skip it
The workflow still runs. You get views that are recognisably your object with the colours in roughly the right places, and then the bake back-projects them onto the UVs and you find white-ish rims and halos along every silhouette boundary - sleeves, boot edges, the thin band where the model's painted outline sits a few pixels inside the true one. Some of that the baker now claws back on its own, by dropping near-white pixels in a thin band just inside each silhouette, and it explicitly exists because this model sometimes draws its outline inside the real one. But that's mitigation for a symptom, not a substitute for decoding with the decoder the model was trained against. Same principle as the VAE in general: the right one is the one the checkpoint was trained with, not the one with the best reputation.
Install
Manager → ComfyUI-UltraTex, or:
cd ComfyUI/custom_nodes
git clone https://github.com/visualbruno/ComfyUI-UltraTex
Pack dependencies are trimesh, moderngl, xatlas and scipy. On top of that you need the two decoder files from the UltraTex release (ModelScope, Yibo-Zhang/UltraTex) - flux2/decoder.pt for FLUX.2, flux1/decoder.pt if you're running the FLUX.1 path - placed in models/ultratex.
Gotchas
- Empty dropdown. No files in
models/ultratexormodels/vaethat it recognises means nothing to pick. Add the file, restart. - Shape mismatch on load. Wrong family's decoder. This one fails loudly and early, which is the good news.
- It does not validate that the decoder matches your diffusion model, only that it fits the VAE you gave it. A FLUX.2 decoder on a FLUX.2 VAE is always going to pass that test, even if you've paired it with something unusual downstream.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| vae | VAE | — | |
| decoder_name | COMBO | 0 options: |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| VAE | VAE | — |