Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38207e93e5 | ||
|
|
8bca327a07 | ||
|
|
23294fa8df | ||
|
|
f0cc7aee26 | ||
|
|
ba9e2f8d78 | ||
|
|
1b159d81f9 | ||
|
|
e6040e1bad | ||
|
|
4d98a77639 | ||
|
|
c1c4557096 | ||
|
|
df0a760c70 | ||
|
|
1cce96f64f | ||
|
|
b31d511a27 |
30
README.md
30
README.md
@@ -8,6 +8,10 @@ All of my nodes are created with the help of AI, so there may or may not be redu
|
|||||||
|
|
||||||
## ▶️ YouTube Tutorial Videos
|
## ▶️ YouTube Tutorial Videos
|
||||||
|
|
||||||
|
<a href="https://youtu.be/j28z5PZXkKk?si=TPeWKm2BW-uA3BAx">
|
||||||
|
<img width="642" height="718" alt="Capture d'écran 2026-06-17 234136" src="https://github.com/user-attachments/assets/89433110-8b78-4971-8098-3a9e9226f460" />
|
||||||
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
@@ -28,13 +32,31 @@ All of my nodes are created with the help of AI, so there may or may not be redu
|
|||||||
## ❓ How to install nodes
|
## ❓ How to install nodes
|
||||||
|
|
||||||
- Navigate to your `/ComfyUI/custom_nodes/ folder`
|
- Navigate to your `/ComfyUI/custom_nodes/ folder`
|
||||||
- Run `git clone https://github.com/WhatDreamscost/WhatDreamsCost-ComfyUI`
|
- Delete your old "WhatDreamsCost-ComfyUI" Folder
|
||||||
- Or download through the ComfyUI Manager.
|
- Run `git clone -b main_cs https://github.com/CGlide/WhatDreamsCost-ComfyUI.git`
|
||||||
|
|
||||||
|
|
||||||
**❗❗IMPORTANT❗❗**
|
**❗❗IMPORTANT❗❗**
|
||||||
|
|
||||||
If you don't see the latest version (v1.3.5) yet in the manager then just downloaded the nightly version (or fetch the updates to update the list to see the latest version).
|
|
||||||
Also you will need to update ComfyUI-LTXVideo and ComfyUI-KJNodes to the latest version as well. You cannot use this node without updating ComfyUI-LTXVideo!
|
This is a Modded LTX director node with some extra options to help you create videos with references sheets
|
||||||
|
|
||||||
|
This node uses Ollama Locally : you will need to install it (very lightweight) and
|
||||||
|
|
||||||
|
- In your Ollama model folder run this command to install qwen 3.5 2b q4 (1.9gb) "ollama run huihui_ai/qwen3.5-abliterated:2B"
|
||||||
|
|
||||||
|
- The model won't eat memory while generating since there is an auto clear VRAM when you hit Run or after 5min.
|
||||||
|
|
||||||
|
- You can still enter your description manually if you don't want to install it but it works very well!
|
||||||
|
|
||||||
|
- Both references mode work (fixed), Licon MSR and Ghost Mask.
|
||||||
|
|
||||||
|
- Use their Lora, that is an important step : https://huggingface.co/LiconStudio/LTX-2.3-Multiple-Subject-Reference/tree/main
|
||||||
|
|
||||||
|
- Enjoy!
|
||||||
|
|
||||||
|
<img width="596" height="668" alt="Capture d'écran 2026-06-13 234036" src="https://github.com/user-attachments/assets/2dfe7992-a72a-4eda-a103-41b3a8f77714" />
|
||||||
|
|
||||||
|
|
||||||
# 🔄 Recent Updates
|
# 🔄 Recent Updates
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
example_workflows/LTX Director MSR_Ghost_V5.json
Normal file
1
example_workflows/LTX Director MSR_Ghost_V5.json
Normal file
File diff suppressed because one or more lines are too long
1
example_workflows/LTX Director Workflow_v4.json
Normal file
1
example_workflows/LTX Director Workflow_v4.json
Normal file
File diff suppressed because one or more lines are too long
1366
js/ltx_director.js
1366
js/ltx_director.js
File diff suppressed because it is too large
Load Diff
1118
ltx_director.py
1118
ltx_director.py
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@ class LTXDirectorGuide(LTXVAddGuide):
|
|||||||
GuideData.Input("guide_data", tooltip="Guide data produced by Prompt Relay Encode (Timeline)."),
|
GuideData.Input("guide_data", tooltip="Guide data produced by Prompt Relay Encode (Timeline)."),
|
||||||
io.Float.Input("scale_by", default=1.0, min=0.01, max=8.0, step=0.01, tooltip="Scale the latent by this factor."),
|
io.Float.Input("scale_by", default=1.0, min=0.01, max=8.0, step=0.01, tooltip="Scale the latent by this factor."),
|
||||||
io.Combo.Input("upscale_method", options=["nearest-exact", "bilinear", "area", "bicubic", "bislerp"], default="bicubic", tooltip="Method used to upscale/downscale the latent."),
|
io.Combo.Input("upscale_method", options=["nearest-exact", "bilinear", "area", "bicubic", "bislerp"], default="bicubic", tooltip="Method used to upscale/downscale the latent."),
|
||||||
|
io.Float.Input("msr_strength", default=0.0, min=0.0, max=1.0, step=0.05, tooltip="Licon MSR only: per-stage reference strength override. 0 = use the Director's value (full pull, right for stage 1). On a refinement/upscale stage set ~0.4 to hold detail without the references repainting the opening (fixes stage-2 mist/ghosting)."),
|
||||||
],
|
],
|
||||||
outputs=[
|
outputs=[
|
||||||
io.Conditioning.Output(display_name="positive"),
|
io.Conditioning.Output(display_name="positive"),
|
||||||
@@ -33,7 +34,7 @@ class LTXDirectorGuide(LTXVAddGuide):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def execute(cls, positive, negative, vae, latent, guide_data, scale_by=1.0, upscale_method="bicubic") -> io.NodeOutput:
|
def execute(cls, positive, negative, vae, latent, guide_data, scale_by=1.0, upscale_method="bicubic", msr_strength=0.0) -> io.NodeOutput:
|
||||||
scale_factors = vae.downscale_index_formula
|
scale_factors = vae.downscale_index_formula
|
||||||
|
|
||||||
# Clone latents to avoid mutating upstream nodes
|
# Clone latents to avoid mutating upstream nodes
|
||||||
@@ -68,6 +69,12 @@ class LTXDirectorGuide(LTXVAddGuide):
|
|||||||
|
|
||||||
_, _, latent_length, latent_height, latent_width = latent_image.shape
|
_, _, latent_length, latent_height, latent_width = latent_image.shape
|
||||||
|
|
||||||
|
# MSR mode: the Director handed us the raw references; inject them at THIS node's
|
||||||
|
# resolution (so a half-res Stage 1 and a full-res Stage 2 each stay self-consistent).
|
||||||
|
msr = guide_data.get("msr")
|
||||||
|
if msr is not None:
|
||||||
|
return cls._inject_msr(positive, negative, vae, latent_image, noise_mask, msr, msr_strength)
|
||||||
|
|
||||||
images = guide_data.get("images", [])
|
images = guide_data.get("images", [])
|
||||||
insert_frames = guide_data.get("insert_frames", [])
|
insert_frames = guide_data.get("insert_frames", [])
|
||||||
strengths = guide_data.get("strengths", [])
|
strengths = guide_data.get("strengths", [])
|
||||||
@@ -88,3 +95,60 @@ class LTXDirectorGuide(LTXVAddGuide):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return io.NodeOutput(positive, negative, {"samples": latent_image, "noise_mask": noise_mask})
|
return io.NodeOutput(positive, negative, {"samples": latent_image, "noise_mask": noise_mask})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _inject_msr(cls, positive, negative, vae, latent_image, noise_mask, msr, msr_strength=0.0):
|
||||||
|
"""Inject the Licon MSR references at this node's current resolution."""
|
||||||
|
from nodes import NODE_CLASS_MAPPINGS
|
||||||
|
from .ltx_director import _execute_comfy_node, _unpack
|
||||||
|
|
||||||
|
IC = NODE_CLASS_MAPPINGS.get("LTXAddVideoICLoRAGuide")
|
||||||
|
AG = NODE_CLASS_MAPPINGS.get("LTXVAddGuide")
|
||||||
|
if IC is None or AG is None:
|
||||||
|
raise ValueError("MSR mode needs LTXAddVideoICLoRAGuide (ComfyUI-LTXVideo) and LTXVAddGuide (core LTXV nodes).")
|
||||||
|
|
||||||
|
def clamp01(v):
|
||||||
|
return max(0.0, min(1.0, float(v)))
|
||||||
|
|
||||||
|
slideshow = msr["slideshow"]
|
||||||
|
keyframes = msr["keyframes"]
|
||||||
|
prefix_latents = int(msr["prefix_latents"])
|
||||||
|
# Per-stage override: msr_strength > 0 wins (set it low on a refinement stage so the
|
||||||
|
# references hold detail without repainting the opening); 0 = use the Director's value.
|
||||||
|
strength = clamp01(msr_strength) if float(msr_strength) > 0.0 else clamp01(msr["strength"])
|
||||||
|
downscale = float(msr["downscale"])
|
||||||
|
|
||||||
|
# Pad the generated region so (pad + keyframes) == prefix_latents, so the downstream crop
|
||||||
|
# (which trims the slideshow's temporal footprint) lands on the true clean length.
|
||||||
|
pad_latents = max(0, prefix_latents - len(keyframes))
|
||||||
|
if pad_latents > 0:
|
||||||
|
B, C, F, H, W = latent_image.shape
|
||||||
|
latent_image = torch.cat(
|
||||||
|
[latent_image, torch.zeros((B, C, pad_latents, H, W), dtype=latent_image.dtype, device=latent_image.device)],
|
||||||
|
dim=2,
|
||||||
|
)
|
||||||
|
mb, mc, mf, mh, mw = noise_mask.shape
|
||||||
|
noise_mask = torch.cat(
|
||||||
|
[noise_mask, torch.ones((mb, mc, pad_latents, mh, mw), dtype=noise_mask.dtype, device=noise_mask.device)],
|
||||||
|
dim=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
latent = {"samples": latent_image, "noise_mask": noise_mask}
|
||||||
|
|
||||||
|
# CONDITIONING PATH: slideshow -> IC-LoRA -> keep conditioning, discard latent.
|
||||||
|
cp, cn, _ = _unpack(_execute_comfy_node(
|
||||||
|
IC, positive=positive, negative=negative, vae=vae, latent=latent, image=slideshow,
|
||||||
|
frame_idx=0, strength=strength, latent_downscale_factor=downscale,
|
||||||
|
crop="center", use_tiled_encode=False, tile_size=256, tile_overlap=64,
|
||||||
|
))
|
||||||
|
|
||||||
|
positive, negative = cp, cn
|
||||||
|
|
||||||
|
# LATENT PATH: one frozen keyframe per reference at frame 0 -> keep latent, drop cond.
|
||||||
|
for kf in keyframes:
|
||||||
|
_p, _n, latent = _unpack(_execute_comfy_node(
|
||||||
|
AG, positive=positive, negative=negative, vae=vae, latent=latent,
|
||||||
|
image=kf, frame_idx=0, strength=strength,
|
||||||
|
))
|
||||||
|
|
||||||
|
return io.NodeOutput(positive, negative, latent)
|
||||||
Reference in New Issue
Block a user