Built in the open

The devlog

145 posts of what shipped, what broke, and what got deleted on the way to 1.0. Numbered in order; start anywhere.

083

Carving the Core

A rewrite the size of the bindless mesh path leaves the codebase a little god-shaped, and a god-shaped codebase is how a tool that demos beautifully starts hitching in your hands. This is the cleanup that keeps that from happening: the Render3D framegraph collapsed into one graph (so your shadows actually render and the async-compute overlap actually fires), thirty-plus per-frame allocations routed through the bind-group cache, and a 3,466-line bridge file carved into eight, with a workspace-wide sweep behind it.

Read the story
082

Deleting the Legacy Renderer

Lux had two mesh renderers: a fast bindless one that drew static geometry, and a 1,466-line legacy function that did everything else (shadows, skinned characters, instances). Two renderers is a slow fork in every frame and two ways for your scene to drift. This post teaches the fast path everything the slow one knew, deletes the slow one, and then solves the harder problem the deletion forces: with no old renderer to compare against, correctness stops meaning 'matches last quarter' and starts meaning 'matches physics', which is the ruler that actually protects what you see.

Read the story
081

The Bindless Arm Goes Live

For most of Lux's life the renderer announced every object to the GPU one at a time, which is fine until a scene has a few thousand of them and the CPU falls over. The bindless arm draws the entire scene in a single GPU-driven indirect call and lets the GPU decide what is visible, which is the road to dense scenes at framerate. This post loads the real 778-line shader, stands up the orchestrator that feeds it the whole scene, caches its seven bind groups, and flips the live arm on capable hardware, keeping the old renderer beside it on purpose so the new one can be proven correct before anything is deleted.

Read the story
076

Shadow Orchestrator + 1024-Slot Lights

The live shadow path was a hardcoded ±10 ortho, an 0.005 magic-number bias, an atlas the size of someone's first attempt, and an 8-slot light uniform that silently dropped lights past slot 7. Worse: every area light and IES light was packing as LIGHT_TYPE_NONE = 0 and getting dropped by the shader's guard before it ever reached the loop. Now there's an orchestrator with cascade-snap stability, a 4-cascade PSSM, a 1024-slot LightStore, and a cluster-bin compute pass that puts the lights in tiles instead of a fixed-size uniform.

Read the story