Image to Video
Animate a still — feed it a hosted URL, get a clip back
- client
- video_url
- generation_id
The most common way people actually use this pack: generate a still in ComfyUI (with whatever local model you like), then hand it to Luma's Ray model and let it breathe. LumaImage2Video ("Image to Video") turns a hosted image URL into a motion clip, and it's the node everyone reaches for when they want their own renders to move without training a video model locally.
The trick, and it's a real one: the Luma API only accepts image URLs, not image tensors. You can't drag a LoadImage output straight in. The pack gives you ImgBBUpload for exactly this - wire LoadImage → ImgBBUpload → image_url, then feed that string into init_image_url. It's an extra hop and an ImgBB API key, and yes, it feels backwards if you're used to local pipelines. That's just how hosted APIs work.
How it works
You provide one or two image URLs plus a text prompt, and the node builds keyframes for the API call:
init_image_urlbecomesframe0- the first frame of the video. This is the classic "animate my still" mode.final_image_urlbecomesframe1- the last frame, so the video animates toward your target image.- Provide both and you get a morph from A to B, which is how people build the transition shots Luma is known for.
At least one URL is required; the node raises "At least one image URL is required" if you give it neither. The rest of the inputs are the Ray family standard: model (ray-flash-2, ray-2, ray-1.6), prompt, duration (5s/9s), loop, resolution (540p/720p), save. Outputs are video_url and generation_id, same as every other generation node here - feed that id onward into upscale, extend, or audio.
Where people get burned
- The prompt still matters. This is image-to-video, not "the image does everything." The prompt drives the motion and any elements that aren't in the source frame. A blank prompt produces a limp, barely-moving clip.
- Hosted URLs must be publicly reachable. A URL that requires auth, or one from a host that blocks hotlinking, fails on Luma's side with an opaque error. ImgBB is the path of least resistance because the pack was built around it.
- Duration and resolution are Ray 2 / Ray 2 Flash only - the README is explicit that
ray-1.6ignores them. - First frame vs last frame confusion. If your clip starts wrong and ends right, you've swapped which URL went where.
init_image_urlis what the video starts from,final_image_urlis what it ends at.
Installing
Same as the rest of the pack: ComfyUI Manager → search "ComfyUI-LumaAI-API", or git clone https://github.com/lumalabs/ComfyUI-LumaAI-API into ComfyUI/custom_nodes and install requirements.txt (lumaai==1.7.0, requests, numpy, Pillow). No local models, no VRAM. You need a LumaAI API key in a LumaAIClient node (or the env var / config.ini fallback), plus an ImgBB key if you're uploading stills from local disk.
Troubleshooting
- "At least one image URL is required" - both URL inputs are empty. Even a single frame satisfies this.
- Generation fails right after queue - usually the hosted image can't be fetched by Luma's servers. Re-upload to ImgBB and use the fresh URL; some hosts return URLs that work in a browser but time out for the API.
- Clip looks nothing like the source image - either the prompt overpowered the image (simplify the prompt), or you're on
ray-1.6where the input handling is older. Tryray-flash-2.
One honest note: the community verdict when these nodes landed was mixed - "I haven't found Luma to be as good as Kling or Runway" was a common take, with the counter that having an official vendor node at all was the win. Ray 2 has improved the motion quality since, and for animating your own ComfyUI stills with full control of the graph around it, nothing else drops in this cleanly.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| client | LUMACLIENT | — | |
| prompt | STRING | — | |
| model | COMBO | 3 options: ray-flash-2, ray-2, ray-1.6 | |
| duration | COMBO | 2 options: 5s, 9s | |
| loop | BOOLEAN | false | — |
| resolution | COMBO | 2 options: 540p, 720p | |
| save | BOOLEAN | true | — |
| init_image_urlopt | STRING | — | |
| final_image_urlopt | STRING | — | |
| filenameopt | STRING | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| video_url | STRING | — |
| generation_id | STRING | — |