· 9 min read · updated
When the Lights Come On
How Traluno's day night cycle works in three.js: unlit glow meshes for windows and lamps, sixteen real lights at most, and a garden sky of point stars.

The layout has a day night cycle, and its clock runs faster than real time. At the CLOCK lever's starting position a day passes in about four and a half minutes; with the lever at its maximum it takes about a minute and a half, and at zero the clock stops. The light in the room shifts from morning through afternoon into dusk, and at some point the windows come on.
That last part is the interesting one, and it is not implemented the way people assume. The tour of buildings that light up at night is the view from the front of the table; this is how the night is built.
Model railway lighting, without the lights
A lit window in Traluno is not a light. It is a second mesh, drawn in a colour that reads as light, in a material that ignores lighting altogether.
The obvious approach is a light source inside each building. It is also impractical: a town has hundreds of windows, and three.js's standard renderer shades every lit surface against every light in the scene, so each real light adds to the cost of every pixel on the table. The engine allows sixteen, gives them to the first sixteen lamp-carrying models in the order they were placed, and fakes everything else.
The fake is a glow mesh, drawn in a MeshBasicMaterial, which three.js documents as "not affected by lights". It is shown in the evening and hidden in the morning, it emits nothing, and it lights nothing around it. It is a picture of a lit window, and at the distance you view the layout from, a picture of a lit window is indistinguishable from one.

The same trick runs the street lamps, the Station's platform lamps, both aspects on the Signal Mast, the Zebra Crossing's beacons, the bulb strings on the Ferris Wheel's legs and the lamps on the trains and road vehicles.
A glow the size of the pane
Physical model railway lighting has a familiar leak: a bulb or LED inside a plastic building glows through the walls as well as the windows, which is why modellers paint or line the inside of a structure before they light it (Trains.com forum). A glow mesh cannot leak, because it only lights where it is drawn. Its failure is being drawn in the wrong place.
The window glow used to be drawn larger than the pane. The glow material is pulled slightly towards the camera so that it always wins against the glass it sits on, and that meant the oversized halo covered the frame and the mullions too: at night every window lit up as one rectangle. The glow is now no larger than the pane, only thicker, and a framed window carries one glow per pane, so it reads as the two or four panes it is divided into.
Two meshes, one model
Every built model can therefore produce two pieces of geometry: the ordinary mesh, lit by the scene, and the glow mesh. Both come out of the same draw function in the model definition, which receives two builders and decides what goes into each. The glow from every model in a four-by-four block of cells is merged into one mesh, so switching the town on is one flag per block rather than one per window.
This is where it gets easy to make a mistake, because the two meshes are drawn from the same code and it is not always obvious which one a given piece of geometry ended up in.
The window helper puts the glass box into the ordinary mesh and the tint into the glow mesh. That is correct for a window: by day you see near-black glass, by night a warm rectangle.
It is wrong for anything meant to read as clear glazing. A bus shelter drawn with it is a solid dark box all day and a glowing one all night, neither of which is what a bus shelter does, so the Bus Stop's shelter is drawn in pale solid panels instead. The fact that this is not obvious from the function name is a genuine wart, and two material languages has more on where glass sits in the art direction.
Animated parts get one builder
There is a harder limitation, and it shapes what several models look like.
An animated part (a rotating wheel, a swinging boom, a turning carousel) is built with a single builder and no second one, so there is nowhere for a lamp's glow to go.
The escape hatch is to mark a whole part as glowing, which makes all of it the glow material. That is no use for a wheel with bulbs on it, which would become a glowing wheel. The Carousel shows the way round it: its twenty-four bulbs are a part of their own, marked as glowing, which turns with the canopy because the two read the same angle every frame. The Lighthouse beam is the same kind of part and hides itself in daylight.
Glowing parts are not switched by the LAMPS toggle. The glow material is shared, and the night loop scales its brightness with the dark, so by day the Carousel's ring is a row of muted beads at about a quarter of its night brightness and after dark a lit ring. The windows and lamps share that material but are hidden outright by day, so the daytime dimming is only ever seen on the Carousel.
The Ferris Wheel has not had the Carousel's treatment. Its rim bulbs are plain caps, picked out at night by the ride's own point light, and the bulbs that do light are strung up the legs of the fixed frame. That is why the frame is strung with lights and the wheel is not, and why it reads slightly differently from a real fairground wheel.

The proper fix is to give animated parts a second builder. It is not hard, and it has not been done. Two models have now worked round the gap in two different ways, which is about the point where a workaround should become a feature.
The windows that came back
When the glTF vehicle assets arrived, the code-drawn railcar was superseded: the Kenney model loads, the code model is hidden, and the better-looking one is what you see.
Except at night, when the code railcar's windows came back on. Not the whole model, just its window glow, floating at its own spacing and count on top of the Kenney body, which has windows of its own in different places.
The cause is a two-line story. Attaching an asset hid the code model's glow mesh. The night loop then walked every moving glow mesh and set its visibility from the clock. The night loop won, because it ran second and did not know the difference between "hidden because it is daytime" and "hidden because this model no longer exists".
The fix has two halves. The asset loader now flags the code glow as superseded as well as hiding it, and exactly one line in the game loop decides whether a moving glow mesh shows, because it is the only line that reads the flag. The second half mattered as much as the first: the loop used to set visibility again per train and per vehicle straight afterwards, which undid the flag and gave every car two sets of headlights at two different heights.
The general lesson is duller and more useful: a system that sets a property on everything in a list must know why each thing is in the state it is in. "Hidden" is not one condition, and code that treats it as one will eventually un-hide something that was hidden for a different reason.
What dusk actually does
Six things change together, and all but one of them move on a curve rather than a switch, because a hard cut reads as a bug.
The sun lowers, warms and dims, sets at six in the evening by the layout clock, and switches off. The hemisphere light that stands in for the sky's ambient light falls to about a ninth of its daytime level and turns from pale blue to a dark one. The sky through the window passes through an orange dusk on its way from day blue to night blue; a window showing a photograph goes from white to the night colour instead, with only a touch of the orange, because tinting a photograph blue casts the whole picture cold. The room's own lamp comes up as the daylight goes, unless ROOM LIGHT is off, and the cellar's stays lit at every hour, because a cellar has no daylight; the rooms post goes through all four.
The glow meshes are the one that switches. They come on, with up to sixteen real lights, once the daylight has dropped by about an eighth: at 16:41, with the sun still well up. They switch on at a little over a third of their final brightness and keep brightening as the dark deepens, and the real lights scale with the dark the same way. LAMPS on the desk turns all of it off together. In the morning they go out at 07:19.
Coming on before it is dark is right. Street lights run on photocells, and a common dusk-to-dawn photocontrol switches on at about 1.5 foot-candles (the TORK ZB124 is rated 1.3 to 1.7), roughly 16 lux, against about 400 lux at sunset on a clear day and 3.4 at the end of civil twilight (Lux, Wikipedia). Real lamps come on after sunset, but while there is still light in the sky. Traluno's come on earlier still, before its sun has set, and at the default clock the whole evening, from the first fade to full night, takes about half a minute, so they are on for nearly all of it.
The sixth change only happens in the garden.
A night sky that is not painted
The garden's sky is a painted dome, and painting stars onto it does not work. The dome is a 1024 by 512 canvas stretched round a sphere of radius 1500, so one texel is about nine units across, and a star drawn into it is magnified into a blocky square.
So the stars are points. Each one is drawn as a PointsMaterial point with size attenuation off, which keeps it a fixed size in pixels at any distance, and a soft round sprite on it turns the square into a dot. The Milky Way's haze is a second dome just inside the first, added onto it rather than painted over it. Its glow is painted at an eighth of the size and scaled up, because the browser dithers every canvas gradient with a fine ordered pattern, and hundreds of soft blobs stacked and then magnified showed that pattern as a weave across the whole band. Scaled up with smoothing, the dither averages away.

Both are black by day, which in additive blending means invisible, and the clock brings them up. The stars wait for the dusk glow to go, so none is out in an orange sky, and come up squared, so the first of them are the faintest; on the layout clock they are fully out at about a quarter past seven. Both stop at the line of the painted hills, so nothing in the night sky is drawn over a hill.
- engine
- lighting
- night



