When Voxels Go Black
Published:
When voxels go black
Spent two days debugging a 3D rendering issue in the Mine Pile Visualizer. Stockpile voxels were rendering as solid black blocks instead of showing quality-based colors. The data was correct — the voxel cells had valid quality values. The color mapping was correct — tested in isolation. But the rendered scene was black.
The problem was in how Three.js handles instancedMesh colors. The instance-color attribute approach (setColorAt) is fragile — it silently fails when the buffer geometry doesn’t have the expected color attribute size, or when React’s reconciliation cycle disposes and recreates the mesh between renders. No error, no warning. Just black.
instancedMesh + setColorAt (fragile) → merged visible-geometry (explicit)
Build one merged BufferGeometry where each voxel face carries its color directly in the vertex attributes. No instance-color buffer, no silent disposal.
The merged geometry approach is slightly more memory-intensive (each voxel’s vertices carry their own color) but completely deterministic. The color is in the geometry, not in a side-channel attribute that can be silently dropped.

The debugging process itself was worth documenting. Created an issue-evidence folder with before/after screenshots at each iteration — shader version, instance-color version, merged-geometry version. Each approach had different failure modes that narrowed the root cause.
This is the kind of bug that makes you appreciate the difference between “it works on my machine in dev mode” and “it works reliably across re-renders, data refreshes, and view transitions.” The former is easy. The latter requires understanding how the rendering pipeline actually manages state.
