IC-LoRA Curve Apply
The node that turns IC-LoRA strength into a timeline, not a slider
- model
- video_latent
- curve
- ic_layout
- model
- video_latent
- schedule_info
Why this node exists
Every LTX IC-LoRA you load the normal way gets one strength slider for the whole clip. That's fine when you want a control effect everywhere, but the moment you want an effect to arrive - a body-shape change that eases in, a control hint that fades out so the end of the shot is clean - you're stuck rendering twice and cross-fading in edit.
IC-LoRA Curve Apply is the fix, and it's the heart of the Burgstall-labs Gradual-IC-LoRA pack. You hand it an LTX-2.3 model, your IC-LoRA, and a strength curve, and it patches the model so the LoRA's effect follows that curve over the clip: frame 0 at 1.5, frame 6 at 0.7, fading to 0 by the last frame, all in one sampling run. The author (u/Burgstall) built it for LTX-2.3's IC-LoRA machinery, and it shows - smoke tests on an RTX 5090 and a hard-fail design for the worst-case failure mode.
How it works
The LoRA is applied as a runtime, per-token-masked adapter - the weights are never merged. The node intercepts every projection layer the LoRA touches (all 480 of them in the author's test) and wraps each one in a tiny adapter:
out = base(x) + s ⊙ (α/r)·B(A·x)
s is a per-token strength mask. Reference tokens - the conditioning tokens your IC-LoRA reads - stay at a constant reference_strength (default 1.0) so the hint stays fully readable for the whole run. Output tokens get the curve value for their latent frame, times strength_global. LTX compresses time 8× (the 8n+1 convention: latent_frames = (rendered_frames − 1) / 8 + 1), so the curve is resampled per latent frame and the mask is cached per unique sequence length.
The detail that separates this from a half-baked LoRA hack is the token-layout check. Every forward pass verifies seq_len == ref_token_count + output_tokens and that output tokens divide evenly by num_latent_frames. If your ref_token_count is wrong, it raises with a detailed message instead of silently mis-aligning the curve to the wrong frames.
Two limits before you get excited: it's video-only (audio-branch keys are skipped with a warning) and torch.compile is unsupported - SageAttention keeps working fine.
Inputs and outputs that matter
model- your LTX-2.3 MODEL, after all static LoRAs. Place this node last in the MODEL chain, right before the sampler.video_latent- the final video-only latent. Used only as a timing reference; it passes straight through.lora_name- your IC-LoRA.safetensorsfrom the loras folder (video-branch keys).curve- theIC_CURVEfrom an IC Strength Curve node.strength_global- multiplies the whole curve (default 1.0). This is where you push past 1.0 when a ramp reads weak.reference_strength- constant mask for reference tokens. Leave at 1.0 unless your hint is bleeding into output.ref_token_count- set this, or wireic_layoutif your IC-LoRA inference node exposes one. Left at 0 with no layout, it auto-detects the common 50/50 reference/output split and warns you to override it.
Outputs: model (patched - wire into the sampler), video_latent (passthrough, so you can stack a second Curve Apply after it), and schedule_info (a STRING with the resolved frame count, per-frame strengths, ref token count, and patched-module count - handy for verifying the layout). Two chained Curve Apply nodes with different LoRAs compose additively, each wrapping the previous adapter.
Install
Via ComfyUI Manager (search "Gradual-IC-LoRA"), or:
cd ComfyUI/custom_nodes
git clone https://github.com/Burgstall-labs/ComfyUI-Gradual-IC-LoRA
Then restart ComfyUI. No extra Python deps - the pack uses only torch/numpy/Pillow, which ComfyUI already ships (its requirements.txt lists just numpy and Pillow). Nothing to download except your own LTX-2.3 IC-LoRA; the author tests with his Bodypositivity IC-LoRA if you want a known variable.
Common issues
- Token-layout hard fail. By far the most common stumble. A wrong
ref_token_count(or a latent shape that doesn't match what the node assumed) produces the hard-fail error. The message tells you what's mismatched - cross-check against your IC-LoRA inference node's layout and the latent's temporal dim. - "Why won't it work with a regular LoRA?" The author's own answer: regular LoRAs operate differently - the reference-token structure is what makes a per-frame mask meaningful. Expect IC-LoRAs only.
- Temporal-consistency dilution. The big one. LTX enforces a strong prior that a continuous shot holds one coherent body/style/scene. Style and colour ramps track cleanly; spatially-drastic ones (body size, object insertion) get pulled toward the average and read diluted. Reliable fix: two constant-strength renders cross-faded in edit, or the pack's induced-camera-motion trick (
smoketest/fake_motion.py), which roughly doubles the visible ramp. - fp8 accuracy floor. On fp8 models a constant-1.0 curve differs from the standard loader by ~9–10% latent RMS - visually imperceptible, but not bit-exact.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| video_latent | LATENT | — | |
| lora_name | COMBO | 0 options: | |
| curve | IC_CURVE | — | |
| strength_global | FLOAT | 1.00-5–5 | — |
| reference_strength | FLOAT | 1.00-5–5 | — |
| ref_token_count | INT | 00–1000000 | — |
| ic_layoutopt | IC_LAYOUT | — | |
| num_latent_framesopt | INT | 00–100000 | — |
| rendered_framesopt | INT | 00–100000 | — |
| ref_tokens_firstopt | BOOLEAN | true | — |
| token_orderopt | COMBO | frame_major | 2 options: frame_major, spatial_major |
| low_vramopt | BOOLEAN | false | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| model | MODEL | — |
| video_latent | LATENT | — |
| schedule_info | STRING | — |