EmberFrame Normalize ZImage/Flux Latent
The adapter that keeps PiD from warping your Z-Image latent
- latent
- latent
- info
If you're here, the PiD output is probably warped, smeared, or just wrong, and this is the node that fixes it. PiD - NVIDIA's Pixel Diffusion Decoder - doesn't live in Comfy's latent space. It treats latent-to-image decoding as conditional pixel diffusion, merging decode and upscale into one step, and it was trained on latents with a different scale and offset than the ones your Z-Image or Flux sampler actually writes. Shove a raw Comfy latent into PiD Decode and you're feeding the model numbers it never saw in training. Garbage in, garbage out, at 4x resolution.
This node is a two-line affine transform sitting between your sampler and PiD. In one direction it rescales Comfy latents into PiD's range; in the other it maps them back. That's the whole job, and it does it without touching model weights or calling anything external.
The mechanism
The math is (samples - shift) * scale for comfy_to_pid, and the inverse (samples / scale) + shift for pid_to_comfy. The defaults - scale_factor 0.3611, shift_factor 0.1159 - are the values the EmberFrame author calibrated for their Z-Image Base / Turbo workflows, and they're the numbers you should keep. The README's known-good setup is direction comfy_to_pid with exactly those two values on the final latent.
The info output is worth a glance: it prints the formula it applied plus min/max/mean/std of the latent before and after. When something downstream looks off, that string tells you instantly whether the transform actually ran.
Inputs and outputs that matter
Only two widgets are worth touching:
- direction -
comfy_to_pid(default) for feeding PiD Decode,pid_to_comfyif you're going back into a Comfy sampler after a PiD pass. - latent - wire this from your sampler's output (see the gotcha below about which one).
Leave scale_factor and shift_factor at 0.3611 / 0.1159 unless you have a reason not to. They're per-backbone values, and for Z-Image/Flux these are the known-good ones.
Outputs: latent (the transformed LATENT, goes into PiD Decode) and info (STRING diagnostics).
Installing it
This is part of the EmberFrame Nodes pack, so install once:
cd ComfyUI/custom_nodes
git clone https://github.com/emberframe/emberframe-nodes.git
Then restart Comfy. Or use ComfyUI Manager and search "EmberFrame Nodes". No pip deps, no bundled models - but the PiD nodes themselves (PiD Decode, PiD Prepare) come from the separate ComfyUI-PiD pack by Merserk, which auto-downloads the NVIDIA PiD checkpoints. You need both.
Where people get burned
- Only normalize the right latent. The README is explicit: if you feed the sampler's
output,denoised_output, or a capturedfinal_latentinto PiD, normalize it first. But if you feed the callbackxdirectly (the sampler's internal state), test without normalization - callbackxis already in the sampler/model latent space and double-normalizing will break it. - Scale is not negotiable. For Z-Image/Flux, PiD is a 4x decoder - both the
2kand2kto4kcheckpoints are 4x. RunningPiD Decodeat scale 1 or 2 produces exactly the warped, distorted output you're probably googling. Keepscale = 4and the2kcheckpoint if you want roughly 1088×1920 out of a ~272×480 generation. pid_to_comfywith a zero scale throws a clear error, so you can't silently blow up the math backwards.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| latent | LATENT | — | |
| direction | COMBO | comfy_to_pid | 2 options: comfy_to_pid, pid_to_comfy |
| scale_factor | FLOAT | 0.3611-100–100 | — |
| shift_factor | FLOAT | 0.1159-100–100 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | — |
| info | STRING | — |