Commit Graph
35 Commits
Author SHA1 Message Date
alisson-anjos bb2e19a8b2 Add clickable SAM 3.1 cast bindings and experimental H3 token weight editor 2026-10-24 11:21:49 +00:00
alisson-anjos 5997aadcf0 Add experimental per-Picture reference attention binding with target masks 2026-10-24 10:54:43 +00:00
alisson-anjos 4ec0b28d47 Add standalone native H3 shot loop with optional image continuity and workflow examples 2026-10-24 10:48:02 +00:00
alisson-anjos c99fdb623e Add native H3 automatic prompt stages and source-derived video geometry 2026-10-23 15:08:11 +00:00
alisson-anjos be21e891dd Add experimental H3 native temporal node and Planner conditioning mode (1.115.9) 2026-10-22 21:30:46 +00:00
alisson-anjos 5a4191f56c Add H3 guide video context in CLIP without native guide references 2026-10-21 08:48:27 +00:00
alisson-anjosandClaude Opus 5.5 ea9841662a Add BFS Video Compare and a guide output on Shot Join (1.106.0)
BFS Video Compare plays two videos in one player (wipe, overlay or side by
side, any of guide / target / difference on top) and measures a per-pixel
difference map on the real frames, with the difference per frame as a
clickable strip. Shot Join gains a 'guide' output: the original frames under
each output frame (the comparison's original column), so the two connect
straight into the compare node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 12:18:48 +00:00
alisson-anjosandClaude Opus 5.5 29cedad7be Shot loop: one-shot split mode, BFS Shot Seed, BFS Shot Noise, BFS Sigmas Preview (1.94.0)
- Planner: Mode "One shot (whole range)" (the range as a single shot, Max seconds / shot not applied) and
  "Range length, seconds" next to it, so a whole shot or pieces of at most X are set in the Video tab alone.
- BFS Shot Seed: one seed per shot from a base seed (same / increment / random per shot) with per-shot overrides.
- BFS Shot Noise (experimental, optional): starting noise for SamplerCustomAdvanced on H3's video + audio latent;
  every amount at 0 is exactly RandomNoise. shared_base (the coarse pattern from a base seed, the same across shots,
  resolutions and lengths), static_share, distribution, spectrum_tilt, pyramid, guide_structure, ref_tint.
- BFS Sigmas Preview: chart of a sigma schedule (steps on layout / shapes / detail), pass-through.

Tested: split logic, seed logic, noise statistics (unit variance, identity at 0) and the chart, in Python.
Not tested yet inside ComfyUI / the panel in a browser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:47:53 +00:00
alisson-anjosandClaude Opus 5.5 51a622c457 H3 Duet / Side Panel nodes (training-free pinned panel); cast on CPU with top faces per frame; Unpack shot output (1.50.0)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:03:00 +00:00
alisson-anjosandClaude Opus 5.5 bf473e1dbd Shot Planner / Shot Loop: split long videos into model-sized shots (1.48.0)
A video model only follows a guide inside the clip length it was trained on, so long
sources are split into shots that fit and run once per shot.

- BFS Shot Planner: interactive Vue timeline (thumbnails, cut-detector curve, draggable
  boundaries, split/merge, per-shot reference gallery with upload, per-shot prompt).
  Splits at camera cuts via PySceneDetect (adaptive/content, built-in fallback), fixed
  length, or by hand; lengths snap to the model grid (H3 17n+5, LTX/Wan 8n+1, 4n+1).
  Outputs the shots as a ComfyUI list so everything downstream runs once per shot.
- BFS Shot Unpack: guide frames, references, prompt, length, audio of one shot.
- BFS Shot H3 Conditioning: native MiniMax H3 conditioning per shot (aligned guide,
  native reference video, or both).
- BFS Shot Join: concatenates in order, trims each shot to its true length, cross-fades
  soft joins with the real overlap frames, returns the soundtrack.
- Queue loop mode: one shot per run stored on disk, auto re-queue, nodes after the join
  blocked until the last shot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 17:32:32 +00:00
Codex bd23236bdd Add aligned downscaled MiniMax H3 guides and image/video targets 2026-09-30 17:26:56 +00:00
alisson-anjosandClaude Opus 5 e9a27c765c BFS LoRA Surgery: read any LoRA's layers and blocks, scale or drop them live
A defect a LoRA learned — smoothed skin, identity drifting at distance, a pose it
refuses to copy — usually lives in one module family and a range of blocks, not in the
whole adapter. This node makes that testable without retraining: pick a family, pick
blocks, set a scale, queue. Nothing is written to disk, so iterating is a slider away.

Model-agnostic by construction. The structure is discovered from key names rather than
hardcoded, covering the diffusers (lora_A/lora_B) and kohya (lora_down/lora_up + alpha)
conventions. Verified against three architectures with different naming: Qwen-Image-2.1
(transformer_blocks, 32), Krea 2 (blocks 28 + txtfusion) and MiniMax-H3 (blocks 50 +
token_refiner).

Scaling multiplies only the up/B factor, since (sB)A = s(BA) — exact under either alpha
convention, and negative scales stay usable.

The panel is a Vue app in a DOM widget, with Vue vendored so it works offline. It lists
each family's module types sorted by ||dW||, which reads as a map of where training
invested. Selections convert to a regex on demand for cases the tree cannot express.
Rules are ordered and later ones win, so the UI says so and lets you reorder.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 11:26:37 +00:00
alisson-anjos df32bdc0fe BFS Sampler: optional identity, and put the new widgets back at the end (1.38.0)
Three things.

`identity_image` moves from required to optional. The node was never head-swap
specific below the surface -- the reference slot is simply not packed when it is
empty, and everything else (crop, mask, inpainting, chunking, paste-back) is
indifferent to which LoRA is running. An instruction-edit, restyle or sharpening
IC-LoRA now runs on the guide alone. IMAGE is a link, not a widget, so this
costs no widget position.

Renamed to "BFS Sampler (crop · mask · loop)" and "BFS Paste Back". The
registration keys are deliberately unchanged: saved workflows reference those,
and only the display name is free to move.

And the fix for the reason this was noticed: 1.37.0 inserted auto_config and
identity_headroom BEFORE crop_mode. ComfyUI stores widgets_values positionally,
so every later value in every saved workflow shifted two slots -- crop_mode's
string landed in auto_config, crop_scale's float in identity_headroom, and the
graph failed validation with "input out of range" on crop_scale and
crop_divisible_by. Both widgets are appended at the end now, with a comment
saying why, and a test pins the historical order so the next addition cannot
repeat it. ltx_multiple_controls.py already carried that rule in a comment;
this file did not follow it.

48 tests.
2026-09-03 14:07:39 +00:00
alisson-anjos 3e77a11908 Add the Head Swap masked sampler: stable crop, native mask inpainting, temporal loop (1.30.0)
The LoRA keeps doing only its job -- guide on source_id 1, identity on
source_id 2. The mask never reaches it: it becomes latent["noise_mask"],
which the guider consumes as denoise_mask, so only the masked region is
denoised and the original face stays visible to the model.

Masks are reduced to the latent grid with MAX rather than ComfyUI's
trilinear resize, which blurs a mask across frames and lets the original
content bleed through the edit.

Crop exists for the case a LoRA cannot fix: a face too small to carry
identity. tracked/zoomed borrow drozbay/MaskVidExperiments' planner when
that pack is installed -- its boxes hold still through mask noise and
occlusion, and a jittering crop reads as camera motion to a video model.
Without it, one static box around the subject's whole travel.

Helpers are unit-tested; the sampling path still needs a GPU run.
2026-08-31 19:38:25 +00:00
Claude 8eb8a0546c Add deterministic Edit Anything prompt fixer (1.28.0)
Two formatting rules the VLM breaks consistently, and that no amount of prompt
work fixed — five rounds of rewriting plus temperature 0 still produced the same
violations:

  no reference  -> the marker sentence must not exist, and a swap is a plain
                   Replace. The model emits Add + marker + Remove instead, which
                   is the reference form applied where it does not belong.
  reference     -> the marker may only follow a sentence starting with Add. When
                   it lands on a Replace, that pair appears in zero training
                   samples.

Both are decidable in code: the caller already knows whether it attached a
reference image, so the node takes that boolean rather than asking the model to
infer it. Add+Remove is recomposed into Replace, and Replace+marker into
Add+Remove, preserving the object description the VLM did get right.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 09:51:52 +00:00
Claude 8ba0ea9620 Add nested-safe H3 latent saver (1.27.0)
The stock SaveLatent calls .contiguous() straight on samples["samples"], which
fails on H3 because the latent is a NestedTensor holding the video and audio
components. This unbinds them first and writes each as its own tensor, so an H3
latent can be taken out of the graph and decoded or inspected offline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 02:04:42 +00:00
Claude eff6017e43 Add MiniMax-H3 direct single-frame decode node (1.26.0)
Decoding a DiT-generated H3 latent through the stock VAEDecode produces a visible
grid. The reference path does not use vae.decode() at all: both the checkpoint
card and the multimodalart/MiniMax-H3-images Space call the decoder directly.
This node is that recipe, with the four details its author flags as silently
corrupting if changed:

  1. vae.decoder(vae.post_quant_conv(z)) directly, never vae.decode(), whose
     temporal chunker cannot form a chunk from the few latent slices an image
     generation produces;
  2. decoded[:, :, -1] -- the last output slice, not index 0;
  3. latent denormalisation, z * latents_std + latents_mean;
  4. ImageNet pixel denormalisation, without which the frame comes out dark and
     over-contrasted like a tone-mapping bug.

Reconstruction check against a real image: 22.43 dB, block ratio 1.30 at the
32px patch boundary -- matching the raw decoder path measured separately, which
is what confirms the node reproduces the reference rather than approximating it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:30:07 +00:00
Claude b193b6b0b1 Add Sharpest Frame / Laplacian node (1.25.0)
Ports the sharpest-frame selection from scanpe_experiments/h3_image.py, which
takes it from IF-Edit (arXiv:2511.19435): decoded frames carry different amounts
of residual motion blur, so score by Laplacian variance and keep the crispest
instead of a fixed index.

Pairs with running MiniMax-H3 as an image generator: the VAE's minimum clip is 5
pixel frames (2 latents), decode yields frames of uneven sharpness, and the best
one is not always at the same index.

The node documents a limitation found while testing it, because it is easy to
misuse: Laplacian variance is a BLUR heuristic, not a quality metric -- artifacts
are high-frequency too. On a real H3 decode it picked the frame with the WORST
PSNR of its block (19.72 dB against 23.19 for its neighbour) because that frame
was the most artifacted. It is sound when the candidates are the same content
differing only in blur, which is the IF-Edit setting; it is meaningless for
choosing among frames from different moments.

Also relevant and not obvious: the "last frame of each decoded block is the valid
one" rule (decoded[:, :, -1] in the upstream example) held for the first block
here (34.49 dB against 26.80 for its neighbour) but inverted on the second.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 13:04:16 +00:00
Claude 0795e3fda2 Add MiniMax-H3 single-frame VAE loaders with tile control (1.24.0)
The published single-frame decoder (iamkaikai/MiniMax-H3-Single-Frame-VAE-500K)
cannot be loaded by the stock VAELoader: detection in comfy/sd.py requires an
encoder key, and the file is decoder-only in diffusers naming, so it falls back
to Stable Diffusion geometry (4 latent channels, 8x upscale) and decodes blocks.

Two nodes:
- MiniMaxH3SingleFrameVAELoader: combines the official H3 VAE with the author's
  decoder-only checkpoint, translating the naming in memory. Validated against
  the author's own diffusers path (load_decoder.py) on the same latent: 72.92 dB,
  i.e. fp16 noise.
- MiniMaxH3VAELoaderTiled: loads an already complete H3 VAE and exposes tile_size,
  which the stock loader does not.

Two key conversions are not derivable from names, and getting either wrong
produces wrong output with no load error. Both were settled by correlating
against the official VAE:
- to_qkv is interleaved per head (heads, 3, dim_head), not stacked [q;k;v]
  (see qkv.view(B, S, -1, 3*dim_head) in comfy/ldm/minimax/vae.py); corr 0.998.
- ff.w1 halves are swapped relative to diffusers, since ComfyUI reads gate first;
  correlation: straight -0.013, swapped +2.00.

tile_size defaults to 512 rather than the constructor's 256. Measured on a
1056x640 image: 512 gives 26.00 dB with a seam ratio of 0.91 (indistinguishable),
against 22.17/1.49 at 256 and 21.35/2.42 at 1024. The author trained 475k of
500k images at <=512px, so 512-wide tiles keep each piece inside the regime that
has training mass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 12:14:33 +00:00
alisson-anjos 3cec31ed42 Add multi-subject reference nodes with learned slot tags (1.23.0)
Three nodes for checkpoints trained with several references on distinct slots:

- LTX Reference Images collects up to six references into one ordered list. A
  plain IMAGE batch cannot carry references of different sizes, and subject
  references routinely differ — a portrait crop next to a landscape product
  shot — so the list keeps each at its own size and puts the slot order in one
  visible place.
- LTX Multi Reference Slots attaches them as separate reference blocks, each
  with its own source_id and, when the LoRA carries one, its trained slot
  embedding. The embedding is read straight from the LoRA file: ComfyUI's LoRA
  loader applies only LoRA weights and drops everything else, so without this
  the references are untagged and the checkpoint is sampled without a signal it
  was trained to use. Pointing it at a LoRA that has no slot embedding fails
  with an explanation rather than silently ignoring the setting.
- LTX Reference Tags builds the "<Image 1> is the woman." prompt prefix.
  Nothing in the model ties a tag to a slot — that correspondence exists only
  because the training captions used it consistently, so sampling with a
  different convention simply does not bind.

The identity node gains one hook: a spec may now carry a slot_vector, applied
to the raw patchified tokens before patchify_proj, which is exactly where the
trainer adds it. Specs without the key are untouched, so existing workflows
behave identically.
2026-08-18 04:57:42 +00:00
alisson-anjosandClaude Opus 5 f03f012fce Add LTX Multishot Prompt + Refs node for the shotplan strata LoRA
Builds a ShotPlan-format multishot prompt (global preamble + "Shot N: <modifier>
<size> <move> <action>" blocks) plus the ordered, gray-padded reference batch that
the multishot strata LoRA expects.

No new conditioning node is needed: LTX Identity Transfer already assigns
seg_value = (source_id + i) * phase_scale and strata_slot = i over the image batch,
so source_id=2 with layout="strata" over 4 refs reproduces the trained convention
(source_id 2/3/4/5 on slots 0/1/2/3). Batch order is shot order -- the LoRA was
trained with shuffle_reference_slots=false. Unused slots get a flat RGB-128 frame,
matching the dataset's blank.jpg placeholder.

The dropdown vocabularies are extracted from the 12,470 "Shot N:" headers of
Pensioner/shotplan train_meta_16fps.json (the span between "Shot N:" and the start
of the action sentence), covering 98% of size terms and 97% of move terms.
Modifiers (over-the-shoulder, low/high angle, POV) are a separate axis that
combines with a size rather than replacing it, as in the source captions.

Bump version to 1.21.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 10:03:55 +00:00
alisson-anjos f5e0b18f77 Add identity_mask slot to LTX Multiple Controls + LTX Color Mask node
LTX Multiple Controls now supports a 4th slot (identity_mask_image) for
scail2v2-style color-pointer masks, defaulting to inherit the identity
slot's own source_id/phase_scale (matches training convention). Also
updated guide/mask/identity default source_ids to match the scail2v2
3-phase recipe (1/2/3 instead of 0/0/2).

New LTX Color Mask node recolors plain white/binary SAM2-style masks
into the trained convention: 'silhouette' style (recolor, keep shape)
for the guide mask slot, or 'flat_marker' style (recolor + collapse to
a small dot at centroid, no shape) for the identity mask slot -- a
shaped identity mask re-injects a competing pose signal, the same bug
flatten_ref_masks.py fixes on the training-data side.

Bump version to 1.18.0.
2026-07-24 15:31:44 +00:00
alisson-anjos e0c4c94661 Add LTX Multiple Controls node: guide+mask+identity in one call
Chaining multiple LTXIdentityOverlapConditioning nodes silently drops all
but the last one's reference -- each apply() overwrites transformer_options
["_id_ref_specs"] instead of merging with what the upstream node set. This
node builds every active slot's ref_specs in a single call so guide, mask,
and identity references all combine correctly. Each slot (all optional) has
its own source_id/phase_scale/layout/ref_resize_mode, defaulted (not
hardcoded) to match the trained recipe.
2026-07-22 07:08:41 +00:00
alisson-anjos 2ab178f20c feat: Multi-Ref Sheet Builder — combine 1-5 ref images into the fixed 1536x1024 composite sheet
Same grid convention as the multi-ref LTX-2 LoRA training pipeline
(build_multiref_sheet.py): deterministic layout by ref count (1x1, 2x1,
3x1, 2x2, 3-top+2-bottom), 512x512 panels, centered onto a fixed
1536x1024 canvas regardless of how many refs are plugged in. Panel
order matches the image0/image1/... indexing used in training.
2026-07-14 10:59:34 +00:00
alisson-anjosandClaude Fable 5 74590b3169 feat: LTX Identity Transfer (Multiple Angles) — multi-view refs with per-view source_id
Copy of LTX Identity Transfer generalized to N reference blocks: reference_face_front
(required, sid 2, drives ArcFace projector) + optional reference_back_head (sid 3),
reference_body_front (sid 4), reference_side_profile (sid 5). Empty optional inputs are
omitted, matching the multi-view training's view-dropout. Distinct patch flags so it
never collides with the single-ref node.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 16:55:32 +00:00
alisson-anjosandClaude Opus 4.8 2987893262 1.10.4: remove CAN/AdaLN from the nodes — it degrades the video
Empirically the AdaLN (CAN) modulation destroys the generation; the identity gain came from the
overlap + projector + LoRA, not the CAN. Reverted the Identity Transfer node to overlap + projector,
unregistered the standalone CAN node (file kept).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 00:31:01 +00:00
alisson-anjosandClaude Opus 4.8 5ce4840242 Add LTX Identity CAN node: apply trained AdaLN identity modulation at inference
The ArcFace projector (appended text tokens) has ~0 impact (cross-attn can ignore them). CAN
injects identity into the self-attn AdaLN (shift+gate) of even blocks — a channel the model can't
ignore. Trained on top of the reference LoRA it lifts identity a lot (humo 0.52 -> 0.69) with no
first-frame leak. Node rebuilds CANModulation per even block from identity_adapters_*.safetensors
(can.<i>.*), extracts the reference ArcFace, and patches each even block's native forward with
shift_msa += dshift; gate_msa += tanh(dgate) — the exact training formula. Lazy imports; defensive
__init__. Weight-load + CAN forward validated headless; block patch untested in ComfyUI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 22:31:46 +00:00
alisson-anjosandClaude Opus 4.8 521c28a970 Add LTX Identity Gemma-Vision node (Caminho2): native-space identity conditioning
Feeds the reference image through the ALREADY-LOADED ComfyUI CLIP (LTX's own multimodal Gemma 3
vision) -> feature_extractor -> connector -> CONDITIONING. Identity is in Gemma's native space
(the reason foreign CLIP/DINO/ArcFace adapters fail on LTX); no reference latent (no copy-paste/
mask), no DiT surgery. Reuses the loaded CLIP (only loads a lightweight AutoProcessor for the
multimodal chat template). Mirrors ComfyUI-LTXVideo LTXVGemmaTextEncoderModel, run multimodally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 11:59:23 +00:00
alisson-anjosandClaude Opus 4.8 ef64f26dfd Add LTX Identity Transfer node (IPT2V: overlap ref + source-phase RoPE)
- av_model model-patch: ref tokens at overlap positions + source_phase RoPE, sliced from output (not I2V)
- optional ArcFace projector (dropdown from loras, 'None' = overlap only), debug_log toggle, arcface auto-adjust
- bump 1.7.0 -> 1.8.0; deps: opencv-python, insightface==0.7.3, onnxruntime

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 17:08:14 +00:00
alisson-anjosandClaude Opus 4.8 13e663101e Add AMV Guide Builder node + bump to 1.7.0
BFSAmvGuideBuilder builds the keyframes+blank guide for the AMV av2av LoRA:
auto_scene / manual_indices / external_images, with audio-beat placement
(librosa beat_track, RMS-onset fallback) to sync cuts to the music. Adds
librosa to requirements.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 07:25:29 +00:00
alisson-anjosandClaude Opus 4.8 fe278c7bf9 Add BFSAnime2RealBerniniConditioning node
Pure v2v anime->real conditioning for the Bernini-R anime2real LoRA
(trained without reference). Mirrors training: guide -> source_id 1 on
both positive and negative, empty latent -> source_id 0, no source_id 2
and no amplify_reference (no reference to amplify; text-only CFG).

Reuses bernini_patches; registered in __init__.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 10:58:29 +00:00
alisson-anjosandClaude Opus 4.8 7e457ddc93 Add Head-Swap Bernini Conditioning + LoRA Debug nodes
Standalone head-swap nodes for the Bernini-R LoRA (Wan2.2-A14B):
- HeadSwapBerniniConditioning: guide video -> source_id 1, head image ->
  source_id 2; output follows the guide's native size, head keeps its own.
- HeadSwapLoRADebug: reports applied LoRA patch count on a MODEL.

Bundles the WanModel context_latents patch (vendored from ComfyUI-RH-Bernini,
GPL-3.0) so no external Bernini node package is required.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 08:08:13 +00:00
Alisson Anjos d1b2290c50 Add LTXV Edit Anything nodes 2026-05-10 17:21:30 +01:00
Alisson Anjos 724862df3f add FrameRangedFaceLoader 2026-03-19 08:20:51 +00:00
Alisson Anjos ed0e2f66fb initial commit 2026-03-17 08:43:45 +00:00