Nodes/saya-comfy-couple-plus/Saya Comfy Couple
ComfyUI Node

Saya Comfy Couple

Two characters, one image — Saya Comfy Couple stops their prompts from melting together

By alphaziod·Created 3 months ago·Updated about 15 hours ago· 3
Saya Comfy Couple
  • model_main
  • main_positive
  • person_1_positive
  • person_2_positive
  • negative
  • latent
  • dual_sampling_model
  • support_model_1
  • support_model_2
  • support_model_3
  • patched_model_main
  • patched_dual_sampling_model
  • patched_support_model_1
  • patched_support_model_2
  • patched_support_model_3
  • positive_final
  • detailer_positive
  • negative
  • mask_person_1
  • mask_person_2
  • couple_config
use_couple_attentiontrue
orientationhorizontal
center0.50
transition0.03
mask_floor0.00
swap_person_positionsfalse
binding_modeLEGACY
attn1_strength0.60
attn1_max_tokens1024
attn1_ambiguous_band0.15
attn1_apply_lowres_onlytrue
attn1_hires_strength0.30
v2_ownership_strength0.80
v2_confidence_floor0.10

If you've ever prompted two girls, blue hair, pink hair and watched the model hand both hairstyles to the same character, you know the exact problem this node exists for. A diffusion model reads all of those tags as one soup - it has no idea that blue hair belongs to the left person and pink hair to the right. Saya Comfy Couple is the fix: it spatially separates your conditioning into two character regions so each half of the image only "sees" its own identity prompt.

It's a modified, expanded take on the old Comfy Couple idea, and it's aimed squarely at SDXL-family anime and illustration workflows with one or two characters. The genuinely useful twist is the prompt architecture. Instead of the usual positive_1 / positive_2 / negative, you write four things:

  • main_positive - the scene: what's happening, where, framing, lighting, shared action.
  • person_1_positive - who character 1 is: hair, eyes, outfit, body.
  • person_2_positive - who character 2 is.
  • negative - your normal shared negative.

The node then builds region_1 = MAIN + PERSON 1 and region_2 = MAIN + PERSON 2 internally, and attaches a mask to each. Both characters get the full scene; each only gets its own identity. Keep identity traits out of MAIN unless both characters genuinely share them - that's the whole point of the separation, and it's the most common way people dilute it.

What it does under the hood

The required inputs are model_main, the four conditionings, a latent, and a handful of knobs. It derives two complementary masks from the latent's dimensions, so they always match the resolution you're actually sampling (the README talks about width/height inputs; the shipped code reads them straight off the latent - trust the node, not the doc). What you'll actually set:

  • orientation - horizontal (side by side, the usual) or vertical.
  • center - where the split sits. 0.5 is an even split; 0.4 makes person 1's region smaller. Range is clamped to 0.15–0.85.
  • transition - how soft the mask edge is. 0.03 default is a fairly hard split; bump it if you get a visible seam.
  • swap_person_positions - flips which side person 1 owns. If your characters come out reversed, this (or your center) is the first thing to check.
  • use_couple_attention - the master switch. Turn it off and you get a plain concatenated prompt, which is handy as an A/B baseline.

The optional binding_mode (LEGACY default, plus experimental V0/V1/V1.1/V2 modes with attn1_strength, attn1_max_tokens, and friends) drives how strongly the regional-attention patch binds each character's tokens. Leave it on LEGACY until you understand what you're changing - this is the bleeding edge of the pack and it's still labeled experimental.

The outputs that matter

Wire it like this:

Checkpoint Loader → Saya Comfy Couple → KSampler
                                         ├── patched_model_main → model
                                         ├── positive_final → positive
                                         └── negative → negative

positive_final is the regional couple conditioning; patched_model_main is your model with the regional-attention patch baked in. mask_person_1 / mask_person_2 are the two masks - feed them to each character's IPAdapter attn_mask so your two reference images stay on their own side of the image. detailer_positive is a character-local conditioning with the scene stripped out, made for detailer crops that shouldn't waste tokens on background prose. couple_config is the important bit for bigger builds: it's a serialized copy of every setting this node used, which the Copy and bundle nodes in this pack consume so later passes rebuild the exact same couple.

Solo generation works too - leave person_2_positive as an empty conditioning and the node auto-detects it and runs a single-region pass.

Install and honest caveats

Install is painless: ComfyUI Manager → search saya-comfy-couple-plus, or

cd ~/ComfyUI/custom_nodes
git clone https://github.com/alphaziod/saya-comfy-couple-plus.git

then restart. Dependencies are just numpy and Pillow - torch comes from ComfyUI, and there are no model files to download.

Be aware: this pack is openly work-in-progress, and the README says so. Internal ports and behavior can change between updates - keep a backup of important workflows, and if a saved workflow shows stale ports after an update, restart ComfyUI fully (delete and re-add the node if needed). And set expectations: regional prompting works best when your characters are spatially separated in the frame. Overlapping, touching characters still blend - no mask fixes that. It gives the model clean information, not magic.

Categorysaya/rescue

Inputs (24)

NameTypeDefaultDescription
model_mainMODEL
main_positiveCONDITIONING
person_1_positiveCONDITIONING
person_2_positiveCONDITIONING
negativeCONDITIONING
latentLATENT
use_couple_attentionBOOLEANtrue
orientationCOMBOhorizontal2 options: horizontal, vertical
centerFLOAT0.500.15–0.85
transitionFLOAT0.030.01–0.2
mask_floorFLOAT0.000–0.2
swap_person_positionsBOOLEANfalse
binding_modeoptCOMBOLEGACY5 options: LEGACY, V0_PRE_SOFTMAX, V1_ATTN1, V1_1_HIRES, V2_QUERY_OWNERSHIP
attn1_strengthoptFLOAT0.600–1.5
attn1_max_tokensoptINT1024256–16384
attn1_ambiguous_bandoptFLOAT0.150.02–0.45
attn1_apply_lowres_onlyoptBOOLEANtrue
attn1_hires_strengthoptFLOAT0.300–0.8
v2_ownership_strengthoptFLOAT0.800–1
v2_confidence_flooroptFLOAT0.100–0.45
dual_sampling_modeloptMODEL
support_model_1optMODEL
support_model_2optMODEL
support_model_3optMODEL

Outputs (11)

NameTypeDescription
patched_model_mainMODEL
patched_dual_sampling_modelMODEL
patched_support_model_1MODEL
patched_support_model_2MODEL
patched_support_model_3MODEL
positive_finalCONDITIONING
detailer_positiveCONDITIONING
negativeCONDITIONING
mask_person_1MASK
mask_person_2MASK
couple_configSAYA_COUPLE_CONFIG