Nodes/LTX-2 MLX (Apple Silicon)/LTX-2 MLX Generate (T2V/I2V)
ComfyUI Node

LTX-2 MLX Generate (T2V/I2V)

Text or Image In, Video Out — and It Saves Itself

By tanis2000·Created 3 months ago·Updated 22 days ago· 3
LTX-2 MLX Generate (T2V/I2V)
  • pipeline
  • image
  • VIDEO
◄prompt►
◄height480►
◄width704►
◄num_frames97►
◄seed0►
◄cfg_scale3.0►
◄frame_rate24.00►
◄filename_prefixltx2mlx/video►

This is where the generation actually happens. Wire an LTX2MLXModelLoader pipeline in, type a prompt, and you get a video file. Connect an image to the optional image input and the same node switches to image-to-video with no mode toggle to find - the presence of the image is the mode.

It's the second half of the two-node core of comfyui-ltx2-mlx: loader → generate. If you're looking for why this pack exists at all, the short version is that LTX-2.3's fp8 checkpoints need CUDA kernels that Apple's MPS backend doesn't have, so this runs the model through MLX instead. The generated output is a real mp4 at a real path - see the save behaviour below.

What it does under the hood

pipeline.generate_and_save(...) in the upstream ltx_pipelines_mlx package does the sampling; this node's job is translation. Two details of that translation matter to you.

First, frame counts are snapped. LTX-2.3's VAE compresses temporally by 8x, so valid frame counts are 8k+1: 9, 17, 25, 33, 49, 97, 257. Set num_frames to 33 and you get 33. Set it to 30 and it rounds to the nearest valid value (33 here), because the tooltip says so and the helper does exactly that. Don't fight it - just think in 8k+1 and your clip lengths stop surprising you.

Second, an image input is written to a temp PNG and passed upstream as a file path, not a tensor. Only the first frame of the batch is used (image_tensor[0]). If you're feeding a batch expecting a batch of videos, that isn't what happens - connect one image.

The node is also flagged is_output_node, so it runs even with nothing connected downstream, writes into ComfyUI's output folder under filename_prefix, and previews the result inline. You don't need a SaveVideo node after it.

The inputs a beginner actually sets

  • prompt - multiline, and LTX punishes short prompts. That's a family-wide property, not this node's quirk; a lazy pixel-level prompt gets you near-static video with drifting detail.
  • width / height - defaults 704x480, both in multiples of 8. Remember that two-stage pipelines snap further to multiples of 64, so 480 can land at 448.
  • num_frames - default 97, which is about 4 seconds at 24fps. Max is 257, ~10.7 seconds. This is a clip-scale model, not a one-shot long-form renderer.
  • cfg_scale - default 3.0. Guidance on LTX is the thing to raise first if your video ignores the prompt, and the first thing to lower if it looks fried.
  • frame_rate - 24 by default. Note it's a float here, so 23.976 is legal; the prompt and sampling don't change, only playback timing and the derived duration.
  • seed - with the standard control_after_generate widget next to it in the UI. Seed hunting is a more effective use of an afternoon than prompt rewording on this model family.
  • filename_prefix - defaults to ltx2mlx/video.

The output is a single VIDEO socket carrying the saved file, so you can still hand it to another node - but you rarely need to.

Installing it

ComfyUI Manager: search LTX-2 MLX (Apple Silicon). Manual:

cd ComfyUI/custom_nodes
git clone https://github.com/tanis2000/comfyui-ltx2-mlx.git
cd comfyui-ltx2-mlx
pip install -r requirements.txt

macOS on Apple Silicon only, Python 3.11+, and a ComfyUI new enough for the V3 node schema. The first run pulls the LTX-2.3 MLX weights plus a Gemma 3 12B 4-bit text encoder from Hugging Face - authenticate with hf auth login first if you'd like that download to finish before your coffee does.

The pack ships a minimal example you can open via Workflow → Open (examples/ltx2mlx_text_to_video.json): loader → generate at 256x256, 25 frames, distilled pipeline. Load it, generate once, confirm your install works, then scale up. Every non-distilled pipeline takes 10-40+ minutes even at modest settings, so a smoke test at tiny resolution is genuinely worth the 90 seconds.

What usually goes wrong

The render is overnight-slow and nothing looks broken. You're probably on two_stage or one_stage rather than distilled. In the pack's benchmark, distilled was 88 seconds where two_stage was 16 minutes and one_stage was 41 - same prompt, same q4 tier, same machine. There is no subtlety here: for anything you haven't finalised, use distilled.

You asked for 704x480 and got 704x448. Two-stage snapping to multiples of 64. Not a bug, and not fixable from this node.

The video barely moves. Check the prompt first (be specific about the action and the camera), then raise cfg_scale, then try another seed. LTX-2.3's I2V was specifically retrained to stop producing static clips, but above roughly a 5-second window you're still working against how the model conditions, and long prompts with one clear action beat short prompts with three.

You swapped the loader's LoRA or pipeline type and now it's reloading for minutes. Expected - the pack keeps exactly one pipeline resident, because the 22B model won't fit twice in unified memory. Batch your experiments instead of A/B-ing LoRAs between every render.

And the one that catches Mac users out: if this node refuses to run at all on a Mac, your Python is probably running under Rosetta. The loaders hard-fail on a non-arm64 interpreter, and the error message is explicit about it.

CategoryLTX2MLX

Inputs (10)

NameTypeDefaultDescription
pipelineLTX2MLX_PIPELINE—
promptSTRING—
heightINT48064–2160—
widthINT70464–3840—
num_framesINT979–257Snapped to 8k+1 (VAE 8x temporal compression).
seedINT00–4294967295—
cfg_scaleFLOAT3.00–20—
frame_rateFLOAT24.001–60—
filename_prefixSTRINGltx2mlx/video—
imageoptIMAGE—

Outputs (1)

NameTypeDescription
VIDEOVIDEO—