Sphere-Light-Render-ComfyUI
ComfyUI widget for defining sun light direction for Flux 2 Klein 9B, designed for use with Sun_direction_Lora.
Nodes (4)
Sphere-Light-Render-ComfyUI
Widget to tell Flux 2 Klein 9B and 4B where the sun light comes from — set it by hand, from a real place and time, or straight from a photo's EXIF. To be used with Sun_direction_Lora for Flux2Klein.
Credits — the original node, the concept, and the companion Sun-Direction LoRA are by eric-venti-seeds. The sun position, city/coordinates, EXIF and graph-driven features described below were contributed by Christopher Connock and merged in #4. CHANGELOG.md lists them in order; authorship and licensing are in NOTICE.md.
Install
Clone into your ComfyUI/custom_nodes/:
cd ComfyUI/custom_nodes/
git clone https://github.com/eric-venti-seeds/Sphere-Light-Render-ComfyUI.git
Restart ComfyUI. No additional Python dependencies for the core node.
Quick start
Download the Loras from here:
https://huggingface.co/eric-venti-seeds/Sun-Direction-Lora-Flux2Klein9B https://huggingface.co/eric-venti-seeds/Sun-Direction-Lora-Flux2Klein4B
The Node renders a 1024 x 1024 image as reference for the LoRA to understand where the light comes from.
All the examples below use one real photo — a New Year's Day pickup soccer game
at Penn Park, Philadelphia (bundled as
docs/media/penn-soccer-pickup-shadows.jpg) —
whose EXIF places it at 39.9508, -75.1852, facing 85.48°, on
2017-01-01 12:59. The low winter sun gives it long, unambiguous shadows.
Nodes
Four nodes are registered under render/3d — the node you pick is the mode, so there are no mode toggles:
- 🔆 Sphere Light — Manual — set the light directly with
rotation/elevation/intensity. - 🔆 Sphere Light — Sun (City) — position the light from the real sun: type a
city (e.g.
Austin, TX,London, UK,Tokyo, Japan), set date/time andheading. - 🔆 Sphere Light — Sun (Coordinates) — same, but enter
latitude/longitudedirectly (timezone borrowed from the nearest listed city). Exactly0, 0is treated as "not set yet" — for a point in the Gulf of Guinea, nudge either value (e.g.0.0001, 0). - 📷 Sphere Light — Photo (EXIF) — upload a photo; its EXIF supplies
latitude/longitude, the nearestcity,heading(GPSImgDirection), and the capture date/time as outputs — wire them into the Sun nodes to light the sphere the way the sun actually was when and where the photo was taken. The photo itself comes out asIMAGE, so it can stand in for a Load Image node for ordinary photos (noMASKoutput).
On the Sun nodes, heading is the direction the camera faces (degrees clockwise
from North, matching EXIF GPSImgDirection); a small compass in the corner of
the preview shows it at a glance. A status line shows what was resolved
(☀ London, England) or warns when a city isn't found. Timezone and
daylight-saving are handled automatically. The bundled city list covers cities
over ~15k population; rebuild it with python tools/build_cities.py.
Driving inputs from the graph
Every positioning parameter (heading, city, lat/lon, date/time, intensity, and Manual's rotation/elevation) can be driven by an upstream node — wire a Primitive (or any node whose value the browser can read) into the corresponding input. A connected input wins over the on-node control, and the control mirrors the driven value so the field always shows what's actually used; disconnect it and the widget (still holding the last driven value) drives again.
The sphere renders client-side (Three.js), and the browser bakes the resolved value into the rendered image before each run — so the output matches the driven value on the same queue (incrementing an animation frame-by-frame works). This means an open ComfyUI browser tab is required for driven inputs, and the driving value must be one the browser can resolve (a Primitive/static source, not a value computed mid-run by another node). A headless/API run, or a value that only exists during execution, isn't reflected — use the widgets for those.
The baked render travels inside the workflow itself (the hidden render_b64
widget), so a saved workflow JSON carries roughly 100–400 KB per sphere-light
node — that's expected, not corruption.
From a photo's EXIF
The Photo (EXIF) node reads the metadata in the browser when you pick the
image and writes the values onto its widgets (a status line shows what was
found). Tags the photo doesn't carry — phones only record GPSImgDirection
when the compass was active — leave their widgets untouched, so you can type a
correction by hand. Like all driven inputs, an open browser tab is what bakes
fresh values in; headless runs reuse the last-saved ones. JPEG, PNG (eXIf),
and WebP files carry EXIF; HEIC is not supported (ComfyUI can't decode it
either).
Wire the outputs into a Sun node and the sphere is lit the way the sun actually was when and where the photo was taken — here the bundled Penn Park photo drives Sun (Coordinates), whose widgets mirror the driven values:
<p align="center"> <img src="docs/media/photo-to-sun-workflow.png" width="640" alt="Photo (EXIF) node wired into Sun (Coordinates): the photo's GPS, heading and capture time drive the sphere light" /> </p>Development
- JS unit tests:
npm test(Node's built-in runner overtests/). - Python node tests: run the scripts in
tools/(test_decode.py,test_new_nodes.py,test_photo_exif.py,test_comfy_load.py). js/is theWEB_DIRECTORYComfyUI serves — every.jsfile in it is auto-imported by the browser, so only runtime modules live there.
License & credits
- Original concept and node implementation, and the companion LoRAs: Sun-Direction LoRA 9B and Sun-Direction LoRA 4B, by eric-venti-seeds.
- Sun position, city/coordinates, EXIF and graph-driven inputs — including the solar and timezone math, the city dataset, the Photo (EXIF) node and the test suite — by Christopher Connock.
- Released under the MIT License; NOTICE.md records who wrote what and the third-party terms.
- City data derived from GeoNames (CC BY 4.0).
- Three.js r128 (MIT) is vendored as
js/three.module.js. - The demo photo in the README (
docs/media/penn-soccer-pickup-shadows.jpg) was taken by Christopher Connock — chosen because its EXIF carries GPS coordinates, a compass heading, and the capture time, and its low winter sun casts clear shadows to compare against.