Skip to content

Building an open world in the browser, part 11: Policy mode, not hardcoded mode

By Oleg Sidorkin, CTO and Co-Founder of Cinevva

New here? Use the series guide. It explains what a spike is and links all parts.

After the seam chaos chapter, we needed to stop reacting and start governing.

Spike 23 replaced ad-hoc behavior with explicit policy rules. Instead of chunks doing whatever their local state suggested, a central policy system now made the decisions. Which LOD level does this chunk get? Is it rendered as heightmap or marching cubes? Does it need transition cells, and on which faces? The answers came from a policy function that evaluated distance to camera, edit history, and neighbor resolution states.

Open Spike 23 in a new tab ↗ · View source

The distance-based LOD assignment used concentric rings around the camera, similar to the clipmap concept but applied to the chunk grid. Ring 0 chunks get full-resolution MC. Ring 1 gets half-resolution MC. Ring 2 and beyond get heightmap mode. The adjacency constraint was critical: if two neighboring chunks differ by more than one LOD level, the policy forces the lower-detail chunk to upgrade. This prevents seam cases that the Transvoxel tables can't handle, since transition cells are defined for a 2:1 resolution ratio only.

The HM/MC switching logic checked each chunk's edit bitmap. If a chunk had any volumetric edits (caves, tunnels, terrain sculpts), it stayed in MC mode regardless of distance. Unedited chunks could drop to heightmap mode when they moved far enough away. This hybrid approach gave us volumetric freedom where it mattered and efficiency where it didn't.

This spike looked smaller from the outside than some earlier ones. In practice it was a major quality-of-life improvement for development.

When your system can explain why a chunk switched mode, you spend less time guessing. We added color-coded overlays: green for heightmap chunks, blue for MC chunks, orange for transition-active faces. When seam visibility has dedicated render controls, visual debugging ambiguity drops. When draw ranges are explicitly tied to active vertex counts from the policy system, stale geometry ghosts stop wasting your afternoon.

We also overhauled camera behavior in this spike. Earlier spikes had simple orbit controls fine for screenshots but useless for reproducing bugs. Spike 23 added WASD fly camera with configurable speed, altitude lock toggle, and position readout. That sounds minor. It meant the difference between "I saw a bug somewhere near that ridge" and "the bug appears at position (142, 12, -67) facing northwest."

The key insight from this chapter is that policy didn't reduce complexity. It organized complexity. The same number of edge cases existed. But now each edge case had a name, a trigger condition, and a place in the code where you could set a breakpoint. That's a different kind of win, and it's what determines whether a system can keep evolving or collapses under its own weight.

By the end of Spike 23, we had a near-field behavior layer that was predictable enough to connect to a far-field clipmap ring strategy without constant fear of interaction bugs.

In part 12 we cover Spike 24, where ring transitions, skybox fog, and Three.js version-level shader integration close out this chapter of the project.

Technology referenced in this chapter

Distance-based LOD policy. A central function that assigns LOD level and rendering mode to each chunk based on distance to camera, edit history, and neighbor states. Concentric distance rings determine the base LOD: ring 0 = full-res MC, ring 1 = half-res MC, ring 2+ = heightmap mode. The policy function runs per frame as the camera moves and triggers chunk transitions. This replaces ad-hoc per-chunk decisions with a predictable, debuggable rule system. See GPU-driven LOD selection for the compute shader equivalent.

Adjacency constraints. The Transvoxel algorithm handles 2:1 resolution ratios only. If two neighboring chunks differ by more than one LOD level (e.g., LOD 0 next to LOD 2), the transition tables can't produce valid seam geometry. The policy system enforces this by upgrading the lower-detail chunk when the LOD difference exceeds 1. This constraint propagation can cascade: upgrading one chunk may force its neighbors to upgrade as well. The implementation is a simple iterative pass that converges in 2-3 iterations for typical grid configurations.

Edit bitmap for mode selection. Each chunk maintains a bitmap recording whether it contains volumetric SDF edits (caves, tunnels, sculpts). Chunks with any edits stay in marching cubes mode regardless of distance, preserving the creator's modifications. Unedited chunks drop to heightmap mode when far enough from the camera, saving compute and memory. The bitmap is a single flag per chunk but can be extended to track edit density for more granular mode decisions.

Debug visualization overlays. Color-coded chunk rendering where green = heightmap mode, blue = MC mode, orange = transition-active faces. Per-chunk overlays with LOD level numbers, mode labels, and wireframe toggles. These are development tools, not shipped features, but they pay for themselves repeatedly when debugging LOD transitions and seam artifacts. Combined with a WASD fly camera that reports exact world position, they turn "I saw a bug somewhere" into "the bug appears at (142, 12, -67) with this LOD configuration."


Part 11 of 12.
Previous: Part 10 - Seam chaos and the corner boss fight
Next: Part 12 - Rings, sky fog, and what we would do again
Series guide: /blog/2026-02-25-open-world-browser-series-guide