Nodes/MOSS i2i/MOSS i2i Reference
ComfyUI Node

MOSS i2i Reference

Image-to-image for a model that has no image input

By sorryhyun·Created 23 days ago·Updated a day ago· 4
MOSS i2i Reference
  • model
  • vae
  • image
  • MODEL
  • LATENT
◄lora_name▾►
◄strength1.00►
◄resolution1024►
◄ref_scale1►
◄taskauto►
◄ref_cachegpu►
◄bypassfalse►

MOSS-Image is a text-to-image DiT. Nothing in it accepts a picture. This node is the workaround, and it's the reason the pack exists at all: hand it the page and a MOSS-Image MODEL and it splices that page into the diffusion model's token sequence as a clean VAE latent, so the model can copy line work instead of hallucinating it.

Take: if you install exactly one node from this pack, install this one. The text encode is optional depending on which LoRA generation you have; this node is not.

How the page gets in

The DiT's sequence becomes [image | ref | text]. The reference tokens go through the model's latent embedder and get no noise - they're clean latents of your page, not a partially-denoised guess, and the output head reads only the image rows, so the ref never leaks into what you decode.

On the rotary embeddings, the reference sits on a reserved axis (r = 1, image rows at 0), with its own height/width positions stretched onto the target grid - (i + 0.5)·H/h_ref − 0.5. That's the detail that makes a half-size reference line up position for position with the target, which is how a LoRA trained with quarter-area refs still transfers.

The plumbing is an APPLY_MODEL wrapper: for the length of each apply_model call, the live diffusion model runs a ref-aware copy of the moss-image forward. Translation: it works under any sampler that calls apply_model (a plain KSampler, or the pack's MOSS Spectrum KSampler), and the ref is present in every forward step and in every CFG branch.

Two behaviours come out of the LoRA's metadata rather than from anything you click. If the file stamps ref_timestep, the reference rows get their own block modulation at that timestep while image and text keep the step's. If it stamps ref_isolate (the colorize v3 recipe), the reference queries attend only to other reference queries - image and text still read the ref. Isolated and timestep-pinned, the ref depends on the page alone, so the pack runs it through the 42 blocks once and caches each block's keys and values - about 2.1 GB in bf16 at 1 MP - and logs the number. That cache dies when the model's weight patches or the target size change; older v1/v2 LoRAs with a joint reference run the ref rows on every forward and don't get that shortcut.

The inputs and outputs that matter

  • model - a MOSS-Image MODEL. Wire an SDXL or Flux checkpoint and it raises "needs a MOSS-Image MODEL (moss-image node)" - the check is real, not cosmetic.
  • vae - used to encode the page into the reference latent. It has to be MOSS-Image's VAE; a borrowed SDXL VAE gives you a reference in the wrong latent space.
  • image - the page, straight from Load Image. It's fit to the target size with cover + centre crop, Lanczos, so aspect ratio differences are cropped, not squashed.
  • resolution - the author's own description is worth quoting because it's precise: target area ≈ resolution², native aspect, sides multiples of 16, matching the training cache's target_size. It defaults to 1024. Keep it identical on this node and on the text encode - one is where the vision tower sees the page, the other where the reference latent is laid out, and a mismatch means two different pages.
  • ref_scale - reference side = target side ÷ this. Default 2, i.e. half the side, a quarter of the area: that's the colorize v2 recipe. Set 1 for a full-size reference, which is what the v3 LoRAs trained at.

Outputs are MODEL and LATENT. The MODEL is the patched model - send it to your sampler. The LATENT is an empty latent already sized to the target grid, so it goes straight into the sampler's latent input: don't wire your own Empty Latent at some other resolution, because the reference was positioned for this grid.

Install

ComfyUI Manager → search "MOSS i2i" (the repo was renamed to MOSS Toolkit; the old URL redirects), or:

cd ComfyUI/custom_nodes
git clone https://github.com/sorryhyun/ComfyUI-MOSS-i2i

Restart, then populate the model folders: DiT, Qwen3.5 text encoder and VAE under models/moss_image/<name>/, the i2i LoRA in models/loras. The TE alone is 16.8 GB bf16, or 9.2 GB if you grab the INT8 or fp8 file from sorryhyun/MOSS-Image-Qwen3.5-9B-int8 / -fp8 - the README's table puts INT8 W8A8 at ~1321 tokens/s against 873 for the dequantise-by-default path, so the quantised encoder is the one most people should run. Python deps for the i2i nodes are only torch/numpy/pillow; the anime-tools dependency in the README is for the caption/layout nodes, not this one.

Where people get burned

Resolution mismatch is the classic: 1024 here and 768 on the text encode, and the model is reasoning about one page while being handed another. Same for ref_scale - the node logs a warning when the value you set disagrees with what the LoRA was trained at, and it's worth reading instead of closing the console.

The negative prompt is a plain CLIP Text Encode of "", which is what the colorize LoRA was evaluated against. Stuffing text in there doesn't make it a "negative"; it puts the model somewhere it was never tuned for.

And expect to babysit VRAM. A full-size reference plus its cache is a real cost at 1 MP. Lower resolution if you must, but lower it on every node in the chain - a reference laid out for one grid and sampled at another is worse than a small image.

CategoryMOSS-Image/i2i

Inputs (10)

NameTypeDefaultDescription
modelMODEL—
vaeVAE—
imageIMAGE—
lora_nameCOMBOA LoRA trained with references (reference_latents in its metadata, or an ai-toolkit edit LoRA). Fused (proj.qkv) or separate q/k/v keys, on either DiT layout.
strengthFLOAT1.00-4–4—
resolutionINT1024256–2048Target area ≈ resolution², native aspect, sides multiples of 16 (the training cache's target_size). Keep it equal on the Text Encode and Reference nodes so the vision tower and the ref see the same page.
ref_scaleINT11–8Read only by workflows saved with task = custom; auto takes the ref size from the LoRA (isolated ref: 1, full size; joint ref: 2, 1/4 area).
taskCOMBOautoauto: the recipe the LoRA trained with. Isolated ref (ref_isolate in its metadata): full size, prompt through a plain CLIP Text Encode. Joint ref: half size, prompt through MOSS i2i Text Encode. An ai-toolkit edit LoRA (no ref metadata): full size at t = 0, isolated (its kv_cache); pick 'ai-toolkit, kv_cache off' for one trained without.
ref_cacheCOMBOgpuAn isolated ref depends on the page alone: run it through the blocks once per prompt and keep its keys / values (~2.1 GB bf16 at 1 MP), so each forward runs the image and text rows only. cpu: kept in host memory, copied in per forward. off: the ref rows in every forward.
bypassoptBOOLEANfalseAdd the LoRA in the forward instead of patching the weights. A patch requantizes every patched linear of an INT8 DiT, which loses a GPTQ file's weights; bypass keeps them and takes longer per forward.

Outputs (2)

NameTypeDescription
MODELMODEL—
LATENTLATENT—