Apply Anima ControlNet-LLLite (Auto Remap)
The LLLite node that survives Anima's block growth
- model
- image
- mask
- model
- remap_info
Anima keeps growing, and it grows in the worst possible way for adapters. The original base is a 28-block DiT; Anima-2.9B has 40 blocks; Anima-3.8B has 52. Each jump was made by inserting new blocks in between the existing ones, not by appending to the end. So block 7 in a 40-block model is not the thing block 7 was in the base.
That's fine if you only run the base. It's a wall if you have LLLite weights - the only ControlNet that exists for Anima - because the published weights were trained against the 28-block model. Feed them to upstream's apply node on a 40- or 52-block model and it stops with depth_embed slices missing: the file's block indices point at slots that no longer mean what they meant.
This node is kohya's apply node with one idea bolted on - renumber the blocks in the weights to match the model you actually connected, using the expansion manifests from this pack.
What it actually does
The module is built from the checkpoint's own metadata rather than from knobs on the node - embedding dims, target layers, conditioning channels, the inpaint flag all come out of the file - so there's no "wrong preset" failure mode to hit.
Then, at load time, the block indices in the weights' keys get renumbered before anything is loaded onto the model. Upward - 28-block weights on a 40- or 52-block model - each trained module lands on the block it corresponds to. Nothing is invented for the inserted blocks, and that's deliberate: LLLite modules have a zero-initialised final layer, so a module that never had weights loaded onto it outputs exactly zero. Those new blocks are skip connections for the control, not garbage. Downward (40-block weights on a 28-block model) drops the extra tensors instead of guessing.
Application is scoped the way you'd hope: it installs a model_function_wrapper on its own model clone, converts start_percent/end_percent into a sigma range, and skips LLLite entirely on steps outside it - so two of these nodes with different ranges won't fight.
The inputs you'll actually touch
lllite_name- a dropdown of whatever is inmodels/controlnet. Your weights live there, same as upstream.image- the conditioning map (lineart, depth, scribble).strength- −10 to 10, default 1.0. If the effect feels invisible, move this first.start_percent/end_percent- the window the control is active over. Defaults 0 → 1, i.e. all of it.extend_to_new_layers+extend_strength(0–2, default 0.5) - the optional part. Turn it on and the inserted blocks each get a copy of their predecessor's module rather than nothing, on the logic that Anima's new blocks were created by copying their predecessor at expansion time. Averaging two neighbouring modules is explicitly not done: an LLLite correction is a product of low-rank factors, and averaging factors from two different modules doesn't mean anything.extend_strengthscales only the final layer.mask- optional, only for 4-channel (inpaint) weights. White is the area to repaint, black is keep. With 3-channel weights it's ignored with a warning; with 4-channel weights and no mask, the node stops and tells you so.auto_remapandmanifest- leavemanifestonAuto (Recommended). It resolves the right expansion from the block-count pair it detects. Forcing a specific file is only for debugging.
Two outputs. model goes to your KSampler. remap_info is a plain string - something like 28->40 via expand_manifest_28_40.json, 84 tensors remapped, 0 dropped. Preview it while you set up: it's the only place that tells you whether remapping actually fired.
Install
ComfyUI Manager, search for the pack title, or:
cd ComfyUI/custom_nodes/
git clone https://github.com/shin131002/ComfyUI-Anima-Remap.git
Restart, drop your LLLite weights in models/controlnet. You don't need kohya-ss's package installed - the code is vendored, and the node ID is different, so this coexists with upstream's node and ComfyUI's built-in one.
If ComfyUI-Anima29B-Remap is installed, delete it first - same node IDs, so both at once is a registration conflict.
Where people get burned
The effect is weak, and that's the method, not your settings. These weights only add a correction to each block's self-attention query, so the prompt never loses its grip - a prompt or LoRA that contradicts your conditioning image usually wins. Raise strength, lower CFG, strip contradicting prompt terms, and only then conclude it's broken. For hard structure, use a VACE-type ControlNet instead.
Stacking without preserve_wrapper. ComfyUI's model_options has one model_function_wrapper slot, so a second wrapper-installing node silently no-ops the first. The node captures any pre-existing wrapper and delegates to it from inside its own, which is what preserve_wrapper (default on) controls. Leave it on when you chain two of these.
Legacy weight files won't load. Older v1-format LLLite checkpoints use internal module names directly and would land in the wrong places, so the node refuses them outright. Retrain with current code. fp8 checkpoints, by contrast, are fine - they get upcast on load.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| lllite_name | COMBO | 0 options: | |
| image | IMAGE | — | |
| strength | FLOAT | 1.00-10–10 | — |
| start_percent | FLOAT | 0.0000–1 | — |
| end_percent | FLOAT | 1.0000–1 | — |
| auto_remap | BOOLEAN | true | — |
| manifest | COMBO | 4 options: Auto (Recommended), expand_manifest_28_40.json, expand_manifest_28_52_composed.json, expand_manifest_40_52.json | |
| extend_to_new_layers | BOOLEAN | false | — |
| extend_strength | FLOAT | 0.500–2 | — |
| preserve_wrapper | BOOLEAN | true | — |
| maskopt | MASK | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| model | MODEL | — |
| remap_info | STRING | — |