Compose animate flakes onto flake_anim_data: LoRAs model-only (high/low on Wan 2.2), joined prompts, stems and an optional start image. The Flake Stack/Combo widgets, load picker and queue combos take an anim kind.
FlakeStack logs one line per applied Anima ControlNet (kind, file, image, fit size, strength, start/end and the sigma window from model_sampling); FlakeGenerate logs the model patches present on the model it samples. README explains how to read them and compare with the Anima LLLite blueprint.
An Anima ControlNet entry's model now wins over the type-inferred LLLite file when it resolves to a file in models/model_patches/anima/ or a VACE file in models/controlnet/anima/; anything else falls back to Auto. GET /flakes/cn_models?family= replaces the unused /flakes/cnmodels and lists those files with their kind; the flake editor's CN entries (flake and variant choices) get a Model dropdown with Auto (by type) for Anima, saved as model.
Three behaviours that are right for SDXL but wrong for the new families.
clip_layer() drops the last N layers of a CLIP text encoder. Anima, Krea2
and Z-Image encode with Qwen3 / Qwen3-VL, where it is meaningless and can
raise. Presets carry clip_skip: -2 by default regardless of family, so
gate on the family flag rather than on the value being set.
Distilled models sample at cfg 1 with a zeroed negative, as every shipped
template does. Key it off the effective cfg rather than the family: Anima
base at cfg 4 keeps its real negative, Anima + turbo LoRA at cfg 1 does
not, and no per-family flag can drift from what was actually sampled.
Applied in FlakeGenerate, the one point where conditioning and cfg are
both final — upstream nodes re-encode on every hop and cfg can still move
via a per-instance override (#279). Verified ConditioningZeroOut copies
the metadata dict, so a ControlNet's control key survives.
Flow-matching families also get their ModelSamplingAuraFlow shift, preset
value winning over the family default.
_load_preset_bundle had exactly one loading strategy, load_checkpoint_
guess_config on a file in models/checkpoints/. Anima, Krea2 and Z-Image
all ship as a bare diffusion model plus a separate text encoder and VAE,
so selecting those families and generating could never work.
Reproducible with cyberrealisticZImage_v40.safetensors, whose 453 tensors
are all under model.diffusion_model.*: the call returns clip=None and
vae=None, and the next CLIPTextEncode raises.
- honour the new diffusion_model preset field via load_diffusion_model
- when a checkpoint yields no clip/vae, keep the model it did build and
source the text encoder and VAE from the preset. Only on success, so a
genuine load failure still propagates rather than being masked
- load standalone text encoders with comfy.sd.load_clip and an explicit
CLIPType instead of load_checkpoint_guess_config, which cannot produce
a lumina2 or krea2 CLIP. Members are looked up by name, not value
- missing files named by a preset now fail loudly instead of silently
generating with the wrong components
The 4-vs-16 channel latent difference needs no handling: common_ksampler
calls fix_empty_latent_channels, which reshapes an all-zero latent to the
model's channel count.
The family definition was copy-pasted across eight places: _FAMILY_MAP,
_FAMILY_COMPAT, _CN_MODEL_MAP and _CN_SUBFOLDER in flake_io.py,
_MODEL_FAMILIES in full_flake_node.py, and four more literals in the web
layer. Adding a family meant eight edits and the copies drifted.
Add flake_families.py with a FamilySpec dataclass and a FAMILIES tuple as
the single source of truth, and derive every Python map from it. The
derived dicts keep their original names, shapes and contents, so all call
sites are untouched.
Verified the five derived maps compare equal to the pre-refactor literals.
Adds a per-CN 'Img res' checkbox (resolution_from_image) that drives the
generation resolution from the control image's dimensions, taking
precedence over the flake resolution. Restructures the strength/start/end
row to labels-on-top / fields-on-bottom and places the checkbox alongside
them. Backend reads the flagged entry's image size before the CN apply
loop (so _fit_cn_image is a no-op for it).
Each Flake node re-encodes the accumulated prompt text, producing fresh
conditioning that dropped the 'control' chain attached by upstream nodes
— so a controlnet on an earlier FlakeStack/FlakeCombo was silently
discarded and only the last node's controlnets applied. Snapshot the
incoming conditioning and carry its 'control' (and control_apply_to_uncond)
onto the re-encoded conditioning so this node's controlnets chain on top
via set_previous_controlnet.
The control image was applied before the target resolution was known, so
ComfyUI stretched the hint to the latent size at sample time, distorting
the pose whenever the control image aspect differed from the generation
resolution. Resolve the resolution first and crop-and-resize each hint to
it (lanczos, center crop) before apply_controlnet, matching A1111's
default. Also logs the fitted size.
SDXL controlnets live under models/controlnet/sdxl/ and ZImage under
.../zimage/. Add resolve_cn_model_name() which prefers the family's
controlnet subfolder and fuzzy-matches dash/version-named files (e.g.
controlnet-scribble-sdxl-1.0) against the inferred name, falling back to
the generic global resolver for flat layouts. Wire it into FlakeStack.
After #217 dropped the preset's yaml folder path from
filename_state["preset"], the structural img/<family>/ segment was
also lost — outputs landed at output/<rest>/... instead of
output/img/<family>/<rest>/...
Re-introduce it explicitly: _load_preset_bundle now takes model_family
and prepends "img/<family>/" to the stems list (it contains "/", so
_build_filename_prefix routes it into folder_parts). The explicit
filename_prefix field still contributes its own non-folder segment
afterwards. Thread model_family through FlakeModelPreset.execute, and
FlakeModelCombo inherits it automatically.
Closes#240
Two bugs in one:
1. `_load_preset_bundle` used the preset's full yaml-relative name
(e.g. img/illustrious/nova/nova_anime_xl_v17) as filename_state["preset"],
which leaked into the output directory structure. The user expects
the output path to derive only from the explicit Filename Prefix
field on the preset — not from where the yaml file happens to live
on disk. Set preset to "" and let the explicit prefix (added via
stems) be the sole contributor.
2. The preset modal's syncOutputPath() unconditionally rewrote
filenamePrefixInput.value from the Name field every time the user
typed in Name. The user could never keep an empty or customized
prefix. Add filenamePrefixManuallyEdited tracking (mirroring the
existing pathManuallyEdited pattern) so once the user touches the
field, sync stops clobbering it.
Closes#217
Skip empty stem values when building the filename prefix so that
generations without prefixes produce 09-58-35_00001.png instead of
09-58-35_00001_.png
Stems no longer reset to [] on each FlakeStack — they accumulate across
the chain by preserving the incoming list. Runtime output_stem overrides
from the option panel dropdown are now applied by resolve() reading
_pendingData.output_stem from the serialised entry.
Creates FlakeGenerate node that takes flake_data input, runs KSampler, VAE Decode, and SaveImage internally. Displays seed widget with randomize/increment/decrement controls, 2x2 preview grid (reusing flake-preview.js), and generated image preview in a single DOM widget.
- Clicking the ribbon toggles a flake between active and bypassed states
- Bypassed flakes show greyed out appearance with a red strikethrough line
- Bypassed ribbon is dimmed with click-to-activate tooltip
- Backend (FlakeStack.execute) skips bypassed flakes during processing
- Bypassed state stored as 'bypassed' field in flakes_json entries
- Works in both FlakeStack and FlakeCombo grid items
Closes#121
The _shorten_filenames function was adding both the full filename and the
stem (without extension) to dropdown lists, causing models like VAEs and
text encoders to appear twice (e.g. 'ae' and 'ae.safetensors'). Now only
the stem is returned.
Backend resolution helpers (_resolve_model_name) are added to translate
stem-only names back to full filenames when loading checkpoin/vae/
text_encoder/controlnet models, ensuring backwards compatibility with
existing YAML files that store full filenames.
- FlakeModelPreset now outputs a single FLAKE_DATA pin
- FlakeStack now takes and returns a single FLAKE_DATA pin
- FlakeDataSplit(All/Select) now output all 12 individual types directly
- IntoFlakeData(All/Select) now take individual Comfy types as optional inputs
- Removed FlakesModel, FlakesCond, FlakesSampler (replaced by FlakeDataSplitAll)
- Removed flake_unpack_nodes.py entirely
FlakeStack.execute() was appending to generation_data[7]['stems'] in
place. When ComfyUI re-used the cached tuple from a prior run, each
queued generation compounded the output_stem, producing paths like
frieren/frieren/frieren/... after a few runs.
Build a fresh stems list every execution; preserve only the preset name
from any upstream filename state.
Backend:
- Add LoraEntry dataclass with name, url, path, strength
- Flake dataclass now has loras[] list; legacy lora_path/strength kept for compat
- _flake_from_raw parses both new multi-LoRA and legacy single-LoRA formats
- resolve() applies multi-LoRA strength overrides from grid entries
- full_flake_node.py applies all LoRAs in order
Frontend:
- Flake edit modal: each LoRA gets its own section with name, URL, path picker,
strength slider. +Add LoRA button to add more. [...] button edits name/URL.
- Grid dropdown: shows one strength slider per LoRA, labeled with LoRA name
- Grid entries store loras[] array of strengths for overrides
- Backward compatibility: old entries with single strength auto-converted
Closes#30
- Model Preset initializes filename prefix with <PresetName>/
- New optional 'Output Filename Stem' field in flakes editor
- FlakeStack collects stems from all flakes and builds prefix:
- Folder stems (containing '/') are appended to path
- Date folder <YYYY-MM-DD> inserted after last folder stem
- Filename starts with <HH-MM-SS> followed by _ separated file stems
- FlakesGenerationData converter outputs filename_prefix as 6th pin
Closes#24