Nodes/ComfyUi-MpiNodes/Mpi Bernini Conditioning
ComfyUI Node

Mpi Bernini Conditioning

One graph for every Bernini combo instead of one per combo

By MadPonyInteractive·Created 11 months ago·Updated 4 days ago· 3
Mpi Bernini Conditioning
  • positive
  • negative
  • vae
  • source_video
  • reference_video
  • ref_image_1
  • ref_image_2
  • ref_image_3
  • ref_image_4
  • positive
  • negative
  • latent
width832
height480
length81
ref_max_size848

Bernini is the best open video-editing model of 2026 - ByteDance's fine-tune of Wan 2.2 that does instruction-driven v2v with no mask, no SAM and no ControlNet in front of it, plus reference-to-video from a handful of images. It's also heavy: the clip you're editing goes into the model as part of its input sequence, so editing costs roughly double the equivalent Wan 2.2 generation in time and VRAM.

The annoying part was never the model. It was wiring. Core's BerniniConditioning takes its references through autogrow slots - you drag one out, then another, then another. By hand that's fine. It falls apart the moment a host app has to compile a saved workflow and pass in "however many references the user happened to supply," because a graph can't grow a socket at inject time. Every reference slot here exists up front, always, and you leave the ones you don't need empty.

What it actually does

You get one flat node with source_video, reference_video and ref_image_1 through ref_image_4. Connect what you have. The node drops the empty slots, renumbers the survivors from 0, and hands the result to core's own BerniniConditioning - it doesn't reimplement the tensor maths, so it can't drift away from ComfyUI when core changes.

"Empty" means either nothing wired, or an Mpi loader feeding it a 1×1 image with block_if_empty off. It is not a guess about content, so a genuinely black reference image or a black first frame passes through as a real reference instead of being silently deleted. That distinction matters more than it sounds.

The task is then inferred from what survives, exactly as core documents it: nothing → t2v, source only → v2v, source plus references → rv2v, references alone → r2v, source plus reference_video → ads2v.

The inputs you'll actually touch

  • length - default 81, and the step is 4 for a reason. Bernini returns 4n+1 frames; anything off that grid comes back short and nothing says so. Don't type a number here, feed it from MpiBerniniLength.
  • width / height - 832×480 by default. source_video is resized to this with a centre cover-crop and trimmed to length, so the plate and the conditioning agree on geometry.
  • ref_max_size - 848 by default, and it caps the long edge of reference_video and ref_image_* only, aspect kept, snapped to 16px. It never upscales, so setting it at or above a reference's own long edge does nothing. It has no effect on source_video, which follows width/height - that asymmetry trips people up.
  • positive, negative, vae - the usual conditioning and the VAE the reference streams get encoded through.

Outputs are positive, negative and latent: conditioner in, conditioner out, and the latent that goes to your sampler. Note there are no prompt tags to rewrite here. Bernini tells its streams apart with a source_id rotation in the spatial RoPE, never by text, so the surviving slot order carries no meaning a prompt can depend on - dropping empties is purely about not handing the model a garbage stream.

Four image slots, not core's eight - each stream rides through every sampling step and costs accordingly. Need more? Batch several images into one slot. The trade is that a batch shares one resolution while separate slots each keep their native aspect.

Install

No models in this pack; you still need Bernini-R weights, its text encoder and the Wan VAE separately. The pack itself is pure Python - no requirements.txt, no pip step, and the numpy/scipy/Pillow it uses are already ComfyUI dependencies.

Search ComfyUi-MpiNodes in ComfyUI Manager (publisher mad-pony-interactive on the registry), or:

cd ComfyUI/custom_nodes
git clone https://github.com/MadPonyInteractive/ComfyUi-MpiNodes

Restart ComfyUI afterwards. The nodes land under the MpiNodes/* categories - search "Mpi Bernini" in the node list. Since v1.2.7 the pack is AGPL-3.0 (older versions were MIT, and that grant still stands for them).

Where people get burned

Your ComfyUI is too old. The node imports comfy_extras.nodes_bernini at run time and raises a message naming that file if it's missing - you need a build with core Bernini support. That import is deliberately lazy so the whole pack still loads on older ComfyUI; only this node fails.

A stale connection changes the task. Because the mode is inferred, an old source_video link you forgot about turns a plain r2v graph into rv2v. It won't error, it'll just be a different model run than you intended.

Frames going missing. Ask for 48 and you get 45 - off-grid requests snap down and the plate has to be trimmed to the same number or your stitch downstream refuses two different frame counts. This node can't report the count it will actually return, because the plate it needs to trim is upstream of its own source_video, and reading it off here would close a dependency cycle ComfyUI refuses to execute. That's the entire reason MpiBerniniLength exists as a separate node - wire both length inputs from it and they cannot disagree.

You typed ref_max_size and nothing happened. Expected, if your references are already smaller than it.

CategoryMpiNodes/Utils

Inputs (13)

NameTypeDefaultDescription
positiveCONDITIONING
negativeCONDITIONING
vaeVAE
widthINT83216–16384
heightINT48016–16384
lengthINT811–8192Requested frame count. Off the 4n+1 grid it comes back SHORT - read the length output for what you will actually get.
ref_max_sizeINT84816–16384Cap for the LONG EDGE of reference_video and ref_image_*, aspect kept, snapped to 16px. Never upscales, so setting it at or above a reference's own long edge does nothing. Does NOT affect source_video, which uses width/height.
source_videooptIMAGEThe clip being edited (v2v / rv2v). Resized to width x height with a centre cover-crop, and trimmed to length. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
reference_videooptIMAGEMoving content to insert into the source video (ads2v). Scaled to ref_max_size, aspect kept.
ref_image_1optIMAGEReference image injected as in-context tokens (r2v / rv2v), encoded at its own native aspect. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_2optIMAGEReference image injected as in-context tokens (r2v / rv2v), encoded at its own native aspect. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_3optIMAGEReference image injected as in-context tokens (r2v / rv2v), encoded at its own native aspect. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_4optIMAGEReference image injected as in-context tokens (r2v / rv2v), encoded at its own native aspect. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.

Outputs (3)

NameTypeDescription
positiveCONDITIONING
negativeCONDITIONING
latentLATENT