TextEncodeJoyImageEdit
It's called 'text encode', but the image does half the work
- clip
- vae
- images
- CONDITIONING
The one-line take
This is the node that makes JoyAI-Image-Edit work, and its name undersells it badly. It's not just "CLIP encode this prompt" - it bundles your reference image into the conditioning, which is the whole trick behind instruction-based editing. If you've built a Qwen-Image-Edit or Flux Kontext graph, you've seen this shape before: a "text encoder" that quietly carries pixels. This is that node for JD's JoyAI model, and it ships as part of the ComfyUI-JoyAI pack.
Where it sits in the workflow
JoyAI is an edit model: 16B multimodal diffusion transformer plus an 8B Qwen3-VL vision-language encoder. Unlike an inpainting or ControlNet setup, there's no mask, no control map, no IP-Adapter. You hand it a picture and a sentence, and the change happens. That means every conditioning - positive and negative - must carry the reference image, or the model has no idea what it's editing. So this node appears twice in the graph: once for the positive prompt, once for the negative. Yes, even an empty negative prompt needs a full wiring. The community's first reaction to the model was that it's unusually strong at spatial awareness - "turn the mug so its handle faces left" type edits actually land - but only if the conditioning is right.
What it actually does
The mechanics are worth knowing because they explain the node's weird second output. Internally the node:
- Center-crops your image onto JoyAI's trained 1024-pixel aspect-ratio bucket grid.
- Tokenizes the prompt with the image attached as a visual token, and encodes it.
- Runs the same bucketed image through your VAE and stashes the latent as a
reference_latentinside the conditioning.
Then it returns both the CONDITIONING and the bucketed image. That second output is a convenience: you feed it into VAE Encode to size the sampling latent to exactly what the model expects, then into KSampler with denoise = 1.0. The reference latent isn't passed through the KSampler's regular latent path - it rides inside the conditioning - so don't try to skip the image output and VAE-encode something else at a different size. The model re-emits the whole frame, and it wants the bucket it was trained on.
Inputs and outputs that matter
Four inputs, all required, all obvious: clip, prompt, vae, and image. Wire the same clip (Load CLIP, type joyimage), the same vae (Wan 2.1), and the same image into both the positive and negative copies of the node. The image input must be exactly one image - the node raises if you hand it a batch, so run one edit per execution.
Install
Via ComfyUI Manager (search "ComfyUI JoyAI"), or:
cd ComfyUI/custom_nodes
git clone https://github.com/Nynxz/ComfyUI-JoyAI
Then restart ComfyUI. No extra Python packages - the pack's dependencies list is empty, and it reuses stock components. What you do need to download: the JoyAI-Image-Edit transformer into ComfyUI/models/diffusion_models/, the Qwen3-VL-8B text encoder into models/text_encoders/, and the Wan 2.1 VAE into models/vae/ - all linked from the README's jdopensource/JoyAI-Image-Edit-ComfyUI page. Load Diffusion Model auto-detects the transformer.
Common issues
- The official integration was janky, this one isn't. The original ComfyUI support shipped as a self-contained PR that wanted checkpoints inside the custom node folder and no VRAM offloading - Reddit's polite verdict was "whoever made this doesn't use ComfyUI." This pack vendors that integration but routes it through the normal model paths, so the usual model management and memory handling apply. Still, it's a bf16 16B model: plan for a big GPU.
- Forgot the negative node's image. The graph runs, the result just drifts or ignores parts of your edit. Wire both nodes fully.
- Don't add a CFGNorm or custom
sampler_cfg_functionnode. JoyAI self-installs its own CFG guidance-rescale at sample time and rejects an override rather than silently fighting you. - No ControlNet on this path. JoyAI doesn't consume control maps, and the pack deliberately doesn't support them.
If the model won't auto-detect, check it's actually in models/diffusion_models/ (not a subfolder the loader misses) and that you loaded the encoder as joyimage.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| clip | CLIP | — | |
| prompt | STRING | — | |
| vaeopt | VAE | — | |
| imagesopt | COMFY_AUTOGROW_V3 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| CONDITIONING | CONDITIONING | — |