Nodes/comfyui-moonpack/Reference Concat
ComfyUI Node

Reference Concat

Feed several identity references to a video model without losing the subject

By moonwhaler·Created about a year ago·Updated 19 days ago· 16
Reference Concat
  • reference_images
  • main_image
  • image
  • mask
sidetop
force_sidefalse
ref_scale0.50
offset0
fillblack
interpolationbicubic
max_ref_side0
invert_maskfalse

Video models love a first frame that tells them what the subject should look like. That's the entire trick behind image-to-video and the reference-to-video family - anchor frame one to a known image and a lot of identity drift problems vanish. But what do you do when one image isn't enough? Front view and back view, the outfit, a prop - the more angles the model sees, the better the identity survives. And you can't feed it five separate frames.

Reference Concat is the node that glues your reference images onto a main image as a strip, so you can hand a video model a single composite first frame that contains several views of the subject at once. It's a pixel-level tool: no training, no adapter, no API - just concatenation done carefully.

How it works

The strip goes on the main image's longest side, sized to exactly match that side's length. The main image is never shrunk or cropped - that's a hard rule. ref_scale sets the strip's thickness as a fraction of the main image's cross-side, and the long side is a cap: if the natural strip would overflow, it scales down; it never stretches to fill.

The fun part is offset. Positive values slide the strip into the main image, overlapping it by that many pixels; negative values pull it away, leaving a gap filled with the fill color. Everything is clamped so the main image stays intact. fill supports edge_average, which samples the main image's edge nearest the strip - useful when black or white would scream.

There's a hidden mode too: leave main_image unconnected and it outputs a contact-sheet grid of just the references, sized to the largest one. Fine in a pinch, but it's an auto-layout - if you want control, that's what Reference Grid is for.

The inputs that matter

  • reference_images - connect a MoonPack Image List to keep each reference's native resolution (recommended for mixed-res refs), or a plain stacked batch.
  • main_image - the first-frame image. If a batch lands here, only the first frame is used. Unconnected = contact-sheet mode.
  • side (top/bottom/left/right) and ref_scale - where the strip goes and how thick it is.
  • offset, fill, interpolation, max_ref_side - the knobs above. max_ref_side caps each reference's longest side before sizing (downscale only, 0 = no cap), so one oversized photo can't blow up the whole composite.
  • invert_mask - flips the output mask.

Outputs: the composite image, plus a mask marking the reference area. Some video pipelines use that mask to tell the model which region is reference versus first frame; if yours doesn't, ignore it.

Installing it

Reference Concat ships in MoonPack (comfyui-moonpack). Via ComfyUI Manager, search MoonPack; or:

cd ComfyUI/custom_nodes
git clone https://github.com/moonwhaler/comfyui-moonpack.git

Restart ComfyUI. No models, no extra dependencies.

Where people get burned

Two things. First, if you pass references as a stacked batch, they were already resized to match each other upstream - the Image List input exists precisely to avoid that, so use it when your refs have different resolutions. Second, that hidden contact-sheet mode: if you unplug main_image to test something and forget, your "strip" output suddenly becomes a grid. The node warns you in its own docs, but it's the kind of silent mode switch that's easy to miss.

CategoryMoonPack/image

Inputs (10)

NameTypeDefaultDescription
reference_imagesIMAGEReference images to concatenate. Connect a MoonPack Image List to keep each image's native resolution (recommended for mixed-resolution references), or a plain stacked IMAGE batch.
sideCOMBOtopWhich side of the main image the strip goes on. By default the strip's row-vs-column layout is auto-picked from the main image's longest side, and 'top'/'left' place the strip before the main image along that axis while 'bottom'/'right' place it after. Enable force_side to make this side always win instead. Ignored if main_image is unconnected.
force_sideBOOLEANfalseForce the strip onto the exact side chosen above, overriding the automatic row-vs-column pick: 'left'/'right' always stack the strip as a full-height column, 'top'/'bottom' always stack it as a full-width row. The resulting strip may end up thin if this fights the main image's orientation. Ignored if main_image is unconnected.
ref_scaleFLOAT0.500.01–4Strip thickness as a fraction of the main image's cross-side. The main image's long side is a cap: the strip is only scaled down (never stretched) if it would overflow. Ignored if main_image is unconnected.
offsetINT0-8192–8192Positive: slide the strip into the main image, covering that many pixels of it. Negative: pull the strip away from the main image, leaving a filled gap. Clamped so the main image is never cropped or shrunk. Ignored if main_image is unconnected.
fillCOMBOblackBackground color for any gap/leftover space. 'edge_average' samples the main image's edge nearest the strip, or the average of all references when main_image is unconnected.
interpolationCOMBObicubicResampling filter used whenever a reference image is resized, including upscaling references smaller than the target size.
max_ref_sideINT00–8192Caps each reference's longest side to this many pixels before any other processing (downscale only, never upscales). Keeps one oversized reference from blowing up the contact-sheet or strip size. 0 = no cap.
invert_maskBOOLEANfalseFlip the output mask (main-image/empty-cell area becomes 1.0 instead of the reference area).
main_imageoptIMAGEMain / first-frame image. If a batch is passed, only the first frame is used. Leave unconnected to instead output a contact-sheet grid of the reference images.

Outputs (2)

NameTypeDescription
imageIMAGE
maskMASK