Nodes/ComfyUI LC Modelbuilder Nodes/LC MOSS Block Merge Advanced
ComfyUI Node

LC MOSS Block Merge Advanced

MOSS Image Merging Without 42 Sliders and a Spreadsheet

By lonecatone23·Created about a month ago·Updated a day ago· 5
LC MOSS Block Merge Advanced
  • model1
  • model2
  • model
◄preset50_50►
◄edit_modesmooth►
◄smooth_radius2►
◄blocks_curve0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5►
◄image_in0.50►
◄text_in0.50►
◄timestep0.50►
◄modulation0.50►
◄head_modulation0.50►
◄final_norm0.50►
◄final_layer0.50►
◄save_name►
◄save_curvefalse►

Most checkpoints on CivitAI are merges, and most merges are one ratio dragged across the whole file - which is why half the front page ends up with the same face. Block merging is the way out: instead of averaging everything, you decide that these layers come from model B and the rest stays model A. LC MOSS Block Merge Advanced does that for MOSS Image: 42 layers on a curve you drag, seven sliders for the named parts outside them, presets so you don't start from flat grey every time.

ComfyUI core ships no MOSS merge node at all, so before this you didn't merge.

Why per-block beats a flat ratio

A flat 0.5 merge doesn't give you a model good at both parents. It gives you one that's worse at both, because you're averaging weights that encode incompatible targets - the classic "realistic Pony merge" problem, hybrid artifacts that no amount of prompting fixes. Per-block ratios are the long-standing workaround, with SuperMerger's block-weight box and the manual ritual of flipping blocks to 0 or 1 until you found the one holding what you wanted. This node is that idea with a mouse instead of a comma list.

How it works

No hand-rolled tensor math. It subclasses ComfyUI's own ModelMergeBlocks: clone model1, take model2's key patches, and for each key pick the longest matching prefix in the kwargs for that layer's ratio. The LC node's only job is building those prefixes - layers.0. through layers.41. from your curve, plus the named ones - and handing them over.

One convention quirk, already handled: core's underlying ratio is model1's strength, not model2's. Every value in this node's UI means 0 = all model1, 1 = all model2, and it inverts at the boundary. So the curve, presets, sliders and graph axis all agree with each other.

The inputs that matter

model1 is the ratio-0 side, model2 the ratio-1 side - two Load Diffusion Model nodes, or a loader plus another merge's output. MOSS Image is single-stream (text and picture tokens travel the same 42 layers), so one continuous curve makes sense here in a way it wouldn't for a double-stream model.

preset starts at 50_50, flat 0.5 everywhere. The other three are the useful ones: model2_early takes layers 0-13 from model2, model2_look takes 14-27, model2_late takes 28-41 - and the author's tooltip notes that in his SFT-vs-Base test those late layers carried most of the pose and face. If you came for model2's look, model2_look is the one to try first.

edit_mode (smooth or spike) and smooth_radius (0-8) control dragging: smooth blends neighbours, spike moves one block. Both are browser-side conveniences - the node only ever sees the resulting blocks_curve string, so copy a node around and the curve travels, not the drag settings.

Of the seven named sliders, the ones a beginner should think about:

  • image_in - the video_embedder, turning the picture latent into tokens before layer 0. Pull it toward model1 to keep model1's structure.
  • text_in - the text_embedder, which maps the Qwen3.5 text encoder's output into the model. This is how your prompt gets read; it changes how obedient the merge is.
  • final_layer / final_norm - the output end, where texture and the final colour mapping live.

modulation, head_modulation and timestep are the shared modulation table, the head's, and the timestep embedder. Leave those at 0.5 unless you know why - that's the "whole image feels wrong" region, not a tuning knob.

save_curve with a save_name writes <name>.json into web/moss_block_presets/ on the next queue, curve and sliders together. The output is a single model wire - into your sampler.

Install

Manager, search ComfyUI_LC_ModelBuilder_nodes. Or:

cd ComfyUI/custom_nodes
git clone https://github.com/lonecatone23/ComfyUI_LC_ModelBuilder_nodes

Restart, then confirm __init__.py sits directly in the pack folder - a nested copy warns and silently loads nothing. No requirements.txt and this node needs none: it's core comfy_extras plus a JS curve widget. Hard-refresh (Ctrl+Shift+R) after updating, or you get the node with no graph on it.

Common issues

Your saved preset isn't in the combo. The list is built from the preset folder when ComfyUI reads the node's inputs, so a preset saved mid-session usually shows up after a restart. The JSON in web/moss_block_presets/ is plain text and editable - and worth copying out, since it lives inside the custom-node folder.

You pasted three numbers into the curve. A curve that isn't 42 values gets evenly stretched across the layers, so a short list gives you a smooth ramp instead of the spikes you thought you typed. Paste all 42, or generate them with the pack's LoRA Editor / Block Scan.

The merge fails on mixed precision. This node rides the same ModelMergeBlocks path as core, so it inherits core's behaviour: bf16 model1 with fp8 model2 is a bad time, and an fp8 model1 rounds the whole result back down to fp8. For a mismatched pair, use LC Model Merge (any precision) from the same pack, which decodes to full precision first.

It looks nothing like either parent. Usually a named slider rather than the curve - text_in and image_in do more work than people expect. Set a flat preset and put all seven sliders at 0 or 1 to check which side is actually winning.

CategoryLC ModelBuilder/MOSS Image

Inputs (15)

NameTypeDefaultDescription
model1MODELRatio 0 side. Blocks/regions at 0.0 come entirely from this checkpoint.
model2MODELRatio 1 side. Blocks/regions at 1.0 come entirely from this checkpoint.
presetCOMBO50_50Bundled: 50_50, model2_early (layers 0-13 from model2), model2_look (14-27), model2_late (28-41: SFT + Base test, these carried most of the pose and face), plus anything you save. Loading one sets the curve and the named sliders. Custom keeps what you dragged.
edit_modeCOMBOsmoothsmooth = drag one block and blend neighbors. spike = move one block only.
smooth_radiusINT20–8Neighbor window (in blocks) for smooth mode (0 = spike-like).
blocks_curveSTRING0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5Comma list of 42 ratios (layers.0. - layers.41.). 0 = model1, 1 = model2. Drag the graph to set it.
image_inFLOAT0.500–1video_embedder. Turns the picture latent into tokens, before layer 0.
text_inFLOAT0.500–1text_embedder. Maps the Qwen3.5 text encoder's output into the model (how the prompt is read).
timestepFLOAT0.500–1time_embedding. The timestep (how noisy the picture is).
modulationFLOAT0.500–1shared_block_modulation. One modulation table every layer shares: how strongly each layer acts per step.
head_modulationFLOAT0.500–1video_head_modulation. Modulation of the output head.
final_normFLOAT0.500–1final_norm_video. Norm before the output layer.
final_layerFLOAT0.500–1final_linear_video. Output layer, after layer 41.
save_nameSTRINGFilename under web/moss_block_presets/ (no extension).
save_curveBOOLEANfalseOn run, write save_name.json into web/moss_block_presets/.

Outputs (1)

NameTypeDescription
modelMODEL—