EmberFrame SamplerCustomAdvanced Capture
A SamplerCustomAdvanced that hands PiD a mid-denoise latent
- noise
- guider
- sampler
- sigmas
- latent_image
- output
- denoised_output
- pid_latent
- pid_sigma
- capture_info
Stock SamplerCustomAdvanced has one problem for the PiD crowd: it keeps its intermediate latents to itself. If you want NVIDIA's Pixel Diffusion Decoder to work its magic on a latent from partway through denoising - which is the whole trick of the low-VRAM PiD path - you need the latent and the sigma value at that exact step. Regular sampler nodes just don't hand those out.
EmberFrame SamplerCustomAdvanced Capture is a drop-in clone of Comfy's SamplerCustomAdvanced that also grabs a snapshot on the way through. Same inputs, same final outputs, plus three extra outputs carrying the captured state. It's GPL-3.0 precisely because it mirrors Comfy's own sampler implementation.
How it works
It runs the sampler exactly like SamplerCustomAdvanced - noise, guider, sampler, sigmas, latent_image in, one wrapped callback inside - and the callback decides when to freeze a frame. Three trigger modes:
- from_end (default): capture
capture_stepsteps back from the end of sampling. - one_based_step: capture a specific 1-based step.
- sigma_threshold: capture the first step whose sigma drops at or below
sigma_threshold.
When it triggers, it copies whichever tensor you asked for, moves it to CPU if store_latent_on_cpu is on (default true, and you usually want it on), and picks the sigma value to report. One subtlety from the source: Comfy's sampler doesn't forward sigma into the callback, so the node selects sigma from your external sigmas input - current, next, previous, or forced zero.
The inputs that matter
- capture_tensor_source -
x(default, the raw sampler state),x0/denoised(the predicted clean image), orfinal_latent(deferred until sampling finishes). - capture_mode + capture_step - pick where the snapshot happens.
- sigma_source - the README's diagnostic recipe uses
nextwithcapture_tensor_source = x. - fail_if_not_captured - off by default, and that's a trap (below).
Outputs: output and denoised_output behave like the stock node's, pid_latent is the captured latent (with pid_sigma embedded in the dict), pid_sigma is the sigma as a plain FLOAT, and capture_info is a long diagnostic string.
Using it in the PiD path
The README's intermediate capture route is:
ZiT sampler capture pid_latent -> PiD Prepare latent
ZiT sampler capture pid_sigma -> PiD Prepare sigma
PiD Prepare -> PiD Sample -> PiD Finalize
So pid_latent and pid_sigma wire straight into PiD Prepare. For debugging, set capture_tensor_source = x, sigma_source = next, and flip on capture_debug - you'll get a full printout of every sigma around the capture point. If you're capturing final_latent instead, normalize it with EmberFrame Normalize ZImage/Flux Latent before PiD; raw callback x usually skips that step.
Installing it
Same pack as the rest of EmberFrame Nodes:
cd ComfyUI/custom_nodes
git clone https://github.com/emberframe/emberframe-nodes.git
Restart Comfy, or grab it via ComfyUI Manager ("EmberFrame Nodes"). No pip dependencies, no model files. Remember the actual PiD nodes (PiD Prepare, PiD Sample, PiD Finalize, PiD Decode) live in the separate ComfyUI-PiD pack by Merserk, which fetches the NVIDIA checkpoints itself.
Where people get burned
- Silent fallback. If nothing matches your capture settings and
fail_if_not_capturedis false (the default), the node quietly falls back to the final latent with sigma 0.0 and keeps going. Setfail_if_not_captured = truewhile you're dialing incapture_step- especially on split-sigma Z-Image Base/Turbo workflows where effective step counts surprise people - so a bad target fails loudly instead of handing PiD the wrong frame. - Step semantics differ per mode.
from_endcounts backwards from the final step;one_based_stepcounts from 1. Keepcapture_from_endoff unless you actually want to force the end-counting behavior.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| noise | NOISE | — | |
| guider | GUIDER | — | |
| sampler | SAMPLER | — | |
| sigmas | SIGMAS | — | |
| latent_image | LATENT | — | |
| capture_mode | COMBO | from_end | 3 options: from_end, one_based_step, sigma_threshold |
| capture_step | INT | 41–10000 | — |
| capture_from_end | BOOLEAN | false | — |
| sigma_threshold | FLOAT | 0.0000–1000 | — |
| fail_if_not_captured | BOOLEAN | false | — |
| store_latent_on_cpu | BOOLEAN | true | — |
| print_debug | BOOLEAN | false | — |
| capture_tensor_source | COMBO | x | 4 options: x, x0, denoised, final_latent |
| sigma_source | COMBO | current | 4 options: current, next, previous, zero |
| capture_debug | BOOLEAN | false | — |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| output | LATENT | — |
| denoised_output | LATENT | — |
| pid_latent | LATENT | — |
| pid_sigma | FLOAT | — |
| capture_info | STRING | — |