In this chapter
In this chapter
Less purple everywhere
The first lighting plan named a nicely specific problem: a broad lavender ambient light and a pink rim light were tinting too many materials the same way. The town had atmosphere, but roofs, walls and trim were starting to look alike.
Day, golden hour and night became matched profiles, so the key light, ambient fill, sky, water, windows, glow and reflections all shift together. Rain is a separate setting, which means you can have a rainy afternoon or a dry night.
Daylight turned out to be the most useful test. Night makes a lot of architectural mistakes look romantic. In daylight the same building needs clear planes and believable material colours, with no warm windows to carry it.

A whole town on sixteen lights
A glowing window doesn’t always need a real light of its own. PixelPunk keeps the glow you see separate from the small pool of lights that actually illuminate nearby geometry, so hundreds of fixtures can look lit while the pool stays capped at sixteen.
The light sources come from the generated fixtures themselves. A lamp’s position, colour and direction follow a mesh that exists, and a dark window can’t throw a mysterious streak across the canal. Guessing where lights ought to be from a building’s rough shape was less reliable.
Four times a second, a selection pass ranks the sources by camera focus and screen coverage. Additive halos and emissive surfaces keep everything outside the pool looking lit. Reflections on the water are stylised streaks, tinted and placed from the same source data and clipped to the terrain footprint. They aren’t full scene reflections.
Fine in a screenshot, wrong in a drag
The fifth lighting review found that rebuilding fixtures threw away the whole light pool, and every replacement lamp faded in from zero. During repeated edits the town never finished lighting up before the next rebuild knocked it back down.
At the measured drag cadence, the town got only 53% of the light energy it should have. Still images barely showed it, because taking a screenshot paused things long enough for the fades to catch up. The problem only existed over time, so finding it took a per-frame measurement.
The fix keeps a lamp if its fixture still has the same identity, position, colour and range. Identity alone wasn’t enough, since a reused batch index might now point at a different window. With that check in place, unchanged lamps survive a rebuild.
The trade-off
The second fault was a pool full of lights that were still fading out. A new source could be turned away while an outgoing one held its slot. In the recorded orbit, seven slots could be stuck that way, and 27 wanted sources were refused.
Now, when the pool needs room, it takes back the dimmest outgoing light. The ceiling stays at sixteen and the recorded refusals go away. The price is that a fade-out sometimes gets cut short, ideally at the edge the camera is leaving, which beats an unlit fixture in the view it’s moving into.
Later passes gave the sky and water more depth, made the neon properly HDR and put the sun on a continuous path. After the light-pool bug, though, a good-looking still frame no longer counted as proof that anything looked good in play.
From the project notebook
This chapter draws on the project’s records as they stood on 23 September 2026.
- docs/lighting-and-texture-plan.md · Direction and lighting foundation
- docs/visual-handoff.md · Passes 3–6, water, neon and sun path
- artifacts/lighting-pass6/g-drag/performance.json



