LOG 008 // 14 OCT 2026
Quaso gets a scene graph
Adding a tree to a Quaso scene used to mean remembering every version of that tree. Its leaves and trunk had to appear in the visible scene. The trunk had to block light. The crown and trunk could cast different height shadows. A glowing part needed to enter the light pass. I drew those pieces by hand in separate passes, and a missed pass made a tree look fine until I moved a lamp near it.
The new world-space light grid made this more awkward. Light blockers and emitters must be drawn beyond the camera view, while the visible color only needs the view. I also had to mark which part of the distance field changed whenever one of those objects moved.
Give each object one home
Quaso now has a scene graph built on my nodio crate. A graph is a set of objects with parent and child relationships. Move a tree's parent node, and its trunk and crown move with it. The game builds those nodes once, changes their values during update, then asks the scene to render. The scene chooses the passes.
A sprite is a node. Light, emission, light blocking and height shadows are attributes attached to it. A tree trunk can have a blocker and a shadow caster. Its crown can have a different shadow caster, with more height and a softer edge. A lamp can carry emission. Water and transparent objects choose their own drawing stages. Siblings keep their order unless a parent asks for sorting by vertical position or layer.
The scene keeps a flat drawing list in that order. Each item knows where its children end, so if a whole forest chunk misses the camera view, rendering skips the chunk in one jump. The visible pass checks the view. The light occupancy pass checks the wider view plus reach. The game no longer has to remember to draw a lantern twice with different bounds.
There is a small but important distinction in the change tracking. A light blocker or emitter remembers its bounds and shape from the previous frame. If either changes, the scene marks both the old and new areas for the distance fields. Changing only a lamp's color or intensity leaves its shape alone. A flickering lamp can change every frame without rebuilding those fields.

The canopy gave the renderer a test
The scene migration made an old visual problem hard to ignore. A canopy sits above its trunk, but its pixels used the light map at the trunk's position. The trunk blocks light there, so its dark outline showed through the leaves. Simply reading a blurred light map everywhere would have washed out ground right beside the trunk too.
I added an overhead material mode. It reads an "open light" map that leaves blocker pixels out of its blurred copies. Near a trunk, the shader begins just beyond the blocker edge and widens the search until it finds enough open space. The canopy gets light from around the trunk. The ground still uses its ordinary local light. A bit of soft trunk shadow under crowns remains, and partly transparent Sakura leaves can still show some of the trunk.
The streamed_world example was my larger check. It loads and unloads 512-unit chunks as the camera travels through rooms, doors, lamps, fires and forest. It exercises the scene graph, off-screen light reach and partial field updates together. I also moved the existing examples and the lantern-forest template to the new scene API. Height shadow order is now handled there as well, so one pier plank need not shadow itself while a taller object can still shade the boat below it.

There are costs I have not measured on a release build. Sorting children by vertical position rebuilds the full drawing list when one moves. Text has no bounds before layout, so the scene cannot cull it. Attribute writes and chunk-load rebuilds still need proper CPU timing. Those are narrower problems than asking every game to hand-route every tree and lamp through the renderer.
Quaso now knows what a tree is made of, and the game can spend more of its code on what the tree does.