kubakub motion guide (ltx)
Your camera stays put, LTX does the repainting
- model
- clip
- vae
- audio_vae
- guide
- upscale_model
- audio
- repaint_mask
- sound
- frames
- fps
- audio
- report
If you've used a video model on a projection-mapping project, you know the failure before I describe it: you ask for a light sweeping across the building, and you get back a gorgeous clip where the camera also drifted, tilted or pushed in two metres. On a wall that's the whole trick broken - the projector doesn't move and the building doesn't move, so nothing in frame may move except the thing you asked for. The usual community answer is depth and canny ControlNets plus hope, or stepping sideways into another model's structural control. It works, sort of, and it's a lot of graph for "please don't touch the camera".
kubakub motion guide (ltx) is better: you hand the model the motion yourself. Connect a rough moving clip as guide - a director sequence, a kubakub shader clip, a 3D previz, or moving masks over a still - and LTX 2.x repaints it into something finished while following the motion it was given.
The mechanism, because it explains the dial
The guide is VAE-encoded and the sampler starts from it instead of from pure noise. repaint is the noise level it starts at, which is why the scale runs the way it does - and the author measured the interesting points on a band of light sweeping a facade at 512×320, 25 frames:
- 0.91 (the default, and the tested value): the stone, the windows and the light are all repainted, and the band ends up about 5 px off the guide's position. That's the "everything is new, motion still follows" setting.
- 0.95–0.98: freer, follows less.
- 0.7–0.725: follows closely and barely repaints - the guide's own look survives.
- 1.0: the guide is ignored. Yes, that's just normal text-to-video with extra steps.
The prompt and the guide have to agree about what's moving: say in prompt what you're showing, and mention the motion. The negative default is already tuned for this job (camera movement, zoom, pan, shaky, blurry, low quality, text, watermark) - that string is doing real work here, keep it.
The mask and the curve are stranger than they look, on purpose
repaint_mask says where the repaint happens (white = LTX's picture, black = your guide untouched, grey = a mix) and curve says when. The catch, and the docs are refreshingly honest about it, is what gets shown versus what gets measured: any untouched guide sitting next to a repainted area anchors the look, so a naive noise mask never gives you "stone here, previz there". Hence two modes. shows the repaint repaints the whole clip and then shows it through the mask and curve over your guide. limits the change is the actual noise mask - LTX may only change things inside the mask and keeps the guide's look, which is what you want when the guide is already a finished picture rather than a previz. keep_exact belongs to that second mode: untouched places get the guide's pixels put back after decoding, so they stay exact.
repaint_mask takes one mask or one per frame, which is the fun part: feed it a mask batch from kubakub mask animate or a shader's masks and the repaint travels across the picture instead of arriving everywhere at once. curve (ramp, saw, triangle, sine, square, sound level, beats, bars, hits) multiplies that, and a kubakub sound on sound lets the repaint ride the music.
Sizes, because LTX is picky
megapixels (0.2 by default, described as safe on 12 GB) is the first stage; the guide is scaled to it and sides snap to steps of 32. stage2_max_mp (0.6) caps the second stage, which is 4× the first stage's pixels - connect LTX's latent spatial upscaler x2 to upscale_model for a much sharper second pass. guide_size then decides whether frames come back at your guide's size or LTX's, and max_frames (121 default) cuts a longer guide. The author's own note: 121 frames at 0.6 megapixels is safe on a 12 GB card.
The four model inputs are the LTX set: model (LTX 2.5 22B distilled via UNETLoader), clip (the Gemma text encoder, CLIPLoader with type ltxv), vae, and audio_vae - a second VAE because this model is audio-video, which is why audio in (from your director or your sound node) comes out cut to the video's length. Outputs are frames, fps, audio and report. The sampling steps are ComfyUI's own LTX implementations, so there's no bespoke sampler to trust here.
Install and models
The node is in kubakubkub/ComfyUI_KubaNodes - ComfyUI Manager, search kubakub nodes, restart - or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/kubakubkub/ComfyUI_KubaNodes
python -m pip install -r ComfyUI_KubaNodes/requirements.txt
The pack adds only OpenCV and wants ComfyUI 0.37.0 or newer.
This is one of the nodes that does need models: the LTX 2.5 set in the pack's docs/MODELS.md - transformer int8 convrot, the Gemma text encoder, the video and audio VAEs, and the latent upscaler x2 - into diffusion_models, text_encoders, vae and latent_upscale_models. The example workflow motion_guide.json runs with no guide connected (a built-in band of light over the sample facade), which is the cheapest way to confirm the model loads and the timing is sane before you build your own guide.
Where it bites
Two things. First, a guide that's 400 frames long and 4K from a maxed-out shader: LTX scales it down anyway, so render the guide small and rough - that's the entire premise. Second, keep_exact does nothing unless mask_does is on limits the change, and people leave it on while using shows the repaint, then wonder why pixels they "protected" got redrawn.
Inputs (25)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | LTX 2.5 22B distilled (UNETLoader). | |
| clip | CLIP | Gemma text encoder for LTX (CLIPLoader, type ltxv). | |
| vae | VAE | LTX video VAE. | |
| audio_vae | VAE | LTX audio VAE (the model is audio-video). | |
| prompt | STRING | a sandstone building facade at night, a bright vertical band of warm light sweeps across the facade from left to right, windows glow, cinematic, detailed stone | What the video should look like. Also say what moves (the same as in the guide): the prompt and the guide should agree. |
| repaint | FLOAT | 0.910.3–1 | How much LTX repaints. 0.91 = everything is repainted, the motion still follows the guide (the tested value). 0.95-0.98 = freer, follows less. 0.7 = follows closely and keeps the guide's own look. 1 = the guide is ignored. |
| seed | INT | 420–18446744073709550000 | Noise seed. Change it for another take of the same motion. |
| fps | FLOAT | 25.001–120 | Frame rate of the guide and of the video. |
| megapixels | FLOAT | 0.200.05–2 | Size of the first stage (the guide is scaled to it, sides in steps of 32). With the upscaler the video is twice as wide and high. 0.2 is safe on 12 GB. |
| max_frames | INT | 1219–1025 | A longer guide is cut here (121 frames at 0.6 megapixels is safe on 12 GB). |
| stage2_max_mp | FLOAT | 0.600.1–8 | Cap for the second stage (4x the first stage's pixels): the first stage shrinks to fit. |
| guide_size | BOOLEAN | false | Scale the frames back to the guide's own size (needs RAM for a large guide). Off = the size LTX rendered. |
| guideopt | IMAGE | The clip whose motion is kept: director sequence frames, a shader, a previz render. Rough is fine, LTX repaints it. Empty = a built-in sample. | |
| upscale_modelopt | LATENT_UPSCALE_MODEL | LTX latent spatial upscaler x2: adds a sharper second stage. | |
| audioopt | AUDIO | A sound the video is sampled with (held as it is), e.g. the director's. It is passed on, cut to the video's length. | |
| negativeopt | STRING | camera movement, zoom, pan, shaky, blurry, low quality, text, watermark | What the video should avoid. |
| repaint_maskopt | MASK | Where the repaint is: white = LTX's picture, black = your guide as it is, grey = a mix. One mask, or one per frame (kubakub mask animate, a shader's masks, an ID pass): a moving mask lets the repaint travel over the picture. Empty = everywhere. | |
| curveopt | COMBO | constant | When the repaint is there: how its amount runs over the clip. constant = all the time. ramp: from your guide to fully repainted, once. saw / triangle / sine / square: again and again. sound level, beats, bars, hits: with the sound connected to 'audio'. Multiplies the repaint mask. |
| cycleopt | FLOAT | 2.000.02–3600 | curve: seconds for one run (ramp: how long it takes; beats and hits: how long each one's ramp is). |
| curve_fromopt | FLOAT | 0.000–1 | curve: the amount of repaint at its low end. 0 = the guide as it is. |
| curve_toopt | FLOAT | 1.000–1 | curve: the amount at its high end. 1 = the full 'repaint'. |
| easingopt | COMBO | linear | curve: how a ramp starts and stops. |
| keep_exactopt | BOOLEAN | true | mask_does = limits the change: where nothing may change the guide's own pixels are put back after decoding, so they stay exact. Off = LTX's decoded picture everywhere. |
| mask_doesopt | COMBO | shows the repaint | What the mask and the curve do. shows the repaint: the whole clip is repainted and shown through them over your guide, so the new look travels over the picture or comes in over time. limits the change: LTX may only change things inside the mask and keeps your guide's look everywhere (for a guide that is a finished picture, when only a part should come alive). |
| soundopt | KUBA_SOUND | From kubakub sound: the sound and how it is heard (tempo, gain, release, band, threshold, gap), set once for every node that listens, so all of them step on the same beat. Connected, it comes before 'audio' and before this node's own sound settings. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| frames | IMAGE | The video, as long as the guide. |
| fps | FLOAT | The frame rate, passed through for Create Video. |
| audio | AUDIO | The connected audio cut or padded with silence to the length of the frames; silence of that length when none is connected. |
| report | STRING | Sizes, the noise levels sampled through, time, and what to try. |