Relight
A 3D Light Ball in a Comfy Node
- 3d light
- light_prompt
Relighting an image is one of those "should be easy" tasks that's actually a pain in the neck. You describe a mood, the model guesses the direction, the highlights land on the wrong side of the face, and you iterate for an hour. ComfyTV's Relight stage attacks the real problem first: nailing the light direction before you ever touch a model.
It's an input stage, not a generator. Drop it on the canvas and the node body becomes a 3D light-ball editor - you place lights around a sphere, position them, and the node hands the whole setup downstream as two outputs: a 3d light render (a COMFYTV_IMAGE, the auto-uploaded picture of your light rig) and light_prompt (a COMFYTV_TEXT - the free-form lighting description you type in main_prompt, emitted verbatim). That text is the bridge into a relight workflow like the bundled flux2klein-relight one: your words become the prompt, your light-ball render becomes the reference that tells the model where the light actually comes from.
What you're actually setting
The schema is almost all internal. project_id, parent_output_id, lights_data (the light-ball editor state as JSON), and light_render_url (the /view URL of the rendered light ball) are all populated by the node's own UI - you never touch them by hand. The one field you own is main_prompt: a plain-English lighting description ("warm key light from upper left, cool fill from the right, soft shadows"). Whatever you type there is what flows out of light_prompt, so write it like you'd prompt a relight model - because that's literally where it's going.
Why this division of labor is smart
Most relight tooling in the ComfyUI world (IC-Light and friends) is a one-shot generation: prompt in, relit image out, direction mostly implicit. ComfyTV splits it - you design the light explicitly in the ball editor, then the generation stage does the honest work of applying it. The downside is that it's a two-node workflow: this stage alone won't relight anything, and the heavy lifting (the actual model, VRAM, download) lives in the relight generation stage. If you just want to tweak shadows on one image, that's overhead. If you're building a repeatable look - same three-light rig, re-prompted per shot - this is the node that makes the look reproducible instead of accidental.
Install
Same as every ComfyTV stage - the whole pack installs at once. ComfyUI Manager, search "ComfyTV", or:
cd ComfyUI/custom_nodes
git clone https://github.com/jtydhr88/ComfyTV
Restart ComfyUI (a real backend restart, not a tab refresh). On ComfyUI Desktop/macOS, find the running instance's base path in the startup log and clone into that custom_nodes folder explicitly - the relative cd silently targets the wrong install and the nodes never appear. Note this node itself pulls no model; the relight workflow you wire it into is where any checkpoint downloads happen.
Gotchas
- The light ball render is the reference, not a light map. Downstream stages read it as a lighting guide, so make the render actually match your
main_prompt- an empty ball with a "sunset from the west" prompt will fight itself. - No light render URL, empty output. If
light_render_urlis empty the node returns an empty image; that usually means the node body never rendered its ball. Nudge the editor and Run again.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| project_id | STRING | Internal — populated by the projectStore on the frontend. | |
| parent_output_id | INT | 00–2147483647 | Internal — lineage parent set by spawn handlers on the frontend. |
| main_prompt | STRING | Free-form lighting description; emitted verbatim on the light_prompt output. | |
| lights_data | STRING | [] | Internal — light-ball editor state (LightInfoEntry[] JSON). |
| light_render_url | STRING | Internal — /view URL of the auto-uploaded light-ball render. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| 3d light | COMFYTV_IMAGE | — |
| light_prompt | COMFYTV_TEXT | — |