Pops_Sampler
Two images in, an embedding pair out — the brains of the pOps pack
- model
- clip
- tokenizer
- image_a
- image_b
- positive_emb
- ng_image_embeds
- img_emb_file
Pops_Sampler is where the pOps magic actually happens. The loader hands you the machinery; this node is the operation. You feed it one or two input images (or an object plus a word), it runs the trained diffusion prior, and it spits out an embedding pair that Pops_Decode turns into the final picture. Think of it as the "conditioning" step of a workflow that never touches a normal text prompt.
How it works
pOps works directly in CLIP image-embedding space - the same space IP-Adapter made famous, where operations on embeddings produce semantically meaningful results. The Sampler has two modes, and which one runs depends on whether you fed it a tokenizer:
- Binary mode (the default): two inputs, zero text. Your images get CLIP-encoded, normalized against the prior's
clip_mean/clip_std, and the trained prior maps the pair into an output embedding. The pack hardcodes the object-plus-texture framing here, so this is the "paint this object with that texture" operator in practice.drop_condition_a/drop_condition_bzero out one of the two embeddings before the prior runs - the README's "drop cond" example uses exactly this to force the model to imagine the missing half, so you get diverse outputs from different seeds with only one input. - Instruct mode: needs the tokenizer output from Pops_Repo_Loader (which only exists when
function_typeisinstruct). One image plus a single word intexts- "smooth", "wooden" - and the text hidden states get concatenated onto the image embedding before the prior runs.
Either way the result is the same shape: an output image embedding plus a negative embedding, both of which Pops_Decode needs.
The inputs that matter
You only really set a handful of these:
model,clip- straight from Pops_Repo_Loader. Required, not optional.image_a,image_b- your two input images. You can also hand inembeds_a/embeds_bas paths to.pthembedding files saved from a previous run, which skips the CLIP encoding entirely and lets you reuse a generation's embeddings.texts- the adjective, used only in instruct mode. Default is"smooth".prior_guidance_scale- classifier-free guidance for the prior, not the decoder. Default 1.0; crank it up if outputs look mushy.prior_steps- how many diffusion steps the prior runs (default 25).seed- the prior sampling is stochastic, so this changes the resulting embeddings, not just the final decode.
The outputs
positive_emb(CONDITIONING) - the produced image embedding. Wire intoPops_Decode.positive_emb.ng_image_embeds(CONDITIONING) - the negative embedding, wired intoPops_Decode.negative_emb. The name is a little misleading; it's the negative image embeds, and you feed both or the decode won't do classifier-free guidance properly.img_emb_file(STRING) - a path to where the embeddings were saved as a.pthfile (named with the seed and CFG). Hand that path back in asembeds_a/embeds_blater to reproduce a generation without re-running the prior. Nice touch.
Gotchas
If you connect more than two of image_a, image_b, embeds_a, embeds_b, the code just random.choices two of them - there's no warning, so don't feed three unless random selection sounds fun. Feed fewer than two and it pads the gap with a blank white image. And height/width here aren't the output resolution; they're where your input images get resized to (nearest-neighbor upscale) before encoding. Keep them aligned with what the Decoder will generate.
The bigger trap is treating this like a normal ComfyUI sampler. The CONDITIONING outputs are Kandinsky prior embeddings, not text conditioning - they only make sense wired into Pops_Decode, and they only make sense if they came from the same Pops_Repo_Loader instance and operator. Mix a texture operator's embeddings with an instruct checkpoint's decode and you'll get noise that vaguely looks like a picture.
Troubleshooting
The classic failure is silent: instruct mode not working because the loader's function_type was left on Binary, so no tokenizer exists and your texts input is ignored. Re-check the loader. Low-quality or washout results usually mean raising prior_guidance_scale or changing the seed - this pack's README itself admits the outputs are high-variance, so don't assume you broke something if a seed looks off. First run may also stall while the Kandinsky prior downloads, so give it a minute before calling it frozen.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| clip | CLIP | — | |
| texts | STRING | smooth | — |
| drop_condition_a | BOOLEAN | false | — |
| drop_condition_b | BOOLEAN | false | — |
| prior_guidance_scale | FLOAT | 1.00.1–24 | — |
| seed | INT | 21–2147483647 | — |
| prior_steps | INT | 251–4096 | — |
| height | INT | 768256–4096 | — |
| width | INT | 768256–4096 | — |
| use_mean | BOOLEAN | false | — |
| tokenizeropt | MODEL | — | |
| image_aopt | IMAGE | — | |
| image_bopt | IMAGE | — | |
| embeds_aopt | STRING | — | |
| embeds_bopt | STRING | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| positive_emb | CONDITIONING | — |
| ng_image_embeds | CONDITIONING | — |
| img_emb_file | STRING | — |