# Gododin voxel stream

A seeded voxel landscape streamed around a flying camera. Pure Odin generates
and greedy-meshes 32³ chunks on one cancellable worker. The authored
`Voxel_World` node owns scheduling, editable voxel storage, staging and server
RIDs. Godot owns the scene, material, sky, sun, shadows, fog, camera and UI.

The useful language boundary is the whole chunk: generation and meshing stay in
Odin; a handful of calls and whole-buffer copies publish a finished surface.
This example does not contain a GDScript performance baseline, so its timings do
not establish a speedup over GDScript or another native language.

![Recorded Voxel Stream capture; retained from the original evaluation](screenshot.png)

## Try it

Click the landscape to capture the mouse. WASD flies, Space/Shift climb/sink,
Ctrl boosts speed, and Esc or right click releases. Left click while captured
carves a sphere at the first occupied voxel within twelve blocks. A miss is
harmless. Enter a whole-number seed and press Generate to rebuild; the radius
slider takes effect on Generate. Edits are retained only while their chunks
remain loaded; leaving and revisiting regenerates those chunks from the seed.

## Read the code

Start with [the scene, camera and UI](project/main.gd),
[the native world class](declarations/voxel_world.odin),
[the background worker](subsystem/worker.odin), and
[the chunk mesher](subsystem/mesh.odin). A completed chunk is the unit of work
that crosses from Odin to Godot.

## Run

[Project setup](../../docs/setup.md) covers the tools and SDK connection.
The machine-local compiler, SDK and engine paths in `test.sh` must agree with
`.gododin/local.toml` and `.gododin/authority.toml`. Use the exact target in the
attached SDK/example lock; the [active-target record](../../docs/versioning.md#active-target-and-historical-evidence)
owns its identity. Historical dev5 measurements below retain their actual engine.

```sh
./test.sh          # pure tests, doctor, generate, check, accepted debug build
./test.sh eval     # pure subsystem measurements and hard replay assertions
./test.sh run      # windowed flight, edit, replay, saturation and teardown
./test.sh probe    # settled visual capture and actual surface-byte checks
./test.sh play     # interactive use of the same accepted publication
```

Set `GODODIN_PROFILE=release` for both the build and subsequent run to measure
optimized native code. Debug/release acceptance caches are separate and the
runner checks the publication profile. Eval and probe launches disable VSync
and the engine FPS cap; ordinary play keeps the project's presentation settings.

Engine modes refuse stale source/build combinations and refuse to launch while
another Godot process is running. Keep the window frontmost. The runtime is
prepared under `.gododin/run/runtime`; logs and accepted source hashes are in
`.gododin/test/<profile>/`, and each launch retains its own isolated HOME. The `run` and `probe` modes
save a screenshot there.
Engine exit status, error diagnostics and ownership receipts are checked.

**Keep `--rendering-driver opengl3` for this recorded path.** Upstream dev5 had
[GH-123394](https://github.com/godotengine/godot/issues/123394), windowed
Forward+/Metal heap corruption in texture freeing. The runner pins Compatibility
for all windowed modes, including interactive play. The project also defaults to Compatibility. Do not override it to Forward+
to reproduce these receipts. The [dev6 migration](../../docs/versioning.md#active-target-and-historical-evidence)
records the engine fix, but it does not requalify this example on Metal.
Changing the runner's renderer requires a separate inspected run.

## Generation, meshing and ownership

The subsystem imports neither Godot, Gododin nor Raylib. Explicit voxel arrays,
a four-plane neighbor apron, a per-axis greedy mask and retained byte buffers
make its working set visible. Generation uses seeded gradient noise, a terraced
heightmap and cave carving. Repeatability is measured for the pinned compiler
and machine; floating-point noise is not a promise of identical output on every
architecture or compiler setting.

Only an opaque voxel adjoining air emits a face. Different opaque material IDs
inside solid terrain do not emit hidden faces. A chunk never emits its neighbor's
geometry; below-layer bedrock only occludes. All six face directions use Godot's
clockwise outward winding. The fixed uint16 layout admits at most 65,532 vertices;
pathologically fragmented chunks are refused before an out-of-bounds write.
This is an explicit example limit, not support for arbitrary voxel data.

`Mesh_Workspace` owns the producer buffers. `mesh_chunk_into` borrows them and
allocates nothing; the convenience `mesh_chunk` API allocates owned output and
is not the streaming path. Four worker result slots each retain a workspace and
voxel storage. A full result queue applies backpressure instead of dropping
required completions. A consumer leases a slot until `worker_release_result`.
The pending queue is bounded at 128 jobs; the native scheduler retries admission
while stationary, so a radius-six world can settle to all 169 chunks.
Cancellation invalidates obsolete queued/published work and wakes a blocked
producer. Shutdown joins the worker and checks its allocation accounting.

The native owner retains chunk storage and three `Packed_Byte_Staging` owners.
A staging owner is reused when its byte extent matches and replaced when it
changes. These resize allocations and the engine's packed-array copies, mesh
storage and rendering allocations are outside the **zero warm Odin producer
allocation** claim. There is no per-voxel allocation in generation/meshing and
no per-element foreign call in the chunk upload. The input-event dig samples a
short voxel ray through scalar queries; that is not the streaming bulk path.

The scene creates each mesh RID and transfers ownership immediately through
`stage_front`. Native commit binds a replacement instance before retiring the
previous visible mesh. Normal retirement, reconfiguration, error rollback and
shutdown free adopted mesh and instance RIDs symmetrically. A material Resource
is retained as long as its RID is referenced by a surface.

## LOD

Chebyshev distance from the anchor chunk selects three rings: distance ≤2 uses
stride 1, distance ≤4 uses stride 2, and the remaining configured radius uses
stride 4. Radius 4 contains the first two rings; radius 6 also exercises the third.
LOD 0→1 transitions can be roughly 64 blocks from the camera, depending on its
position within the anchor chunk. Fog is not a correctness mechanism.

Each coarse chunk samples its interior at its stride and keeps an exact
one-voxel shell on its four horizontal sides. The same unit-cell greedy sweep
meshes the resulting occupancy. Neighbors therefore agree on their shared wall
at every pair of LODs, and the shell closes transitions to the coarse interior.
Coarse interiors still change shape at ring transitions; there is no geomorph.
This rule reduces geometry but does not retain the old proportional reduction
in mask-sweep CPU cost. The offline eval measures each LOD independently.

A desired-ring change arms a real 0.5-second dwell deadline; movement within the
same desired ring does not restart it. `begin_frame` performs bounded scheduling
bookkeeping, including periodic hysteresis checks. Meshing itself runs only for
new chunks, matured ring changes or edits, through the same worker and upload
budget (two chunks per frame). “Nothing LOD-related runs per frame” would be
incorrect: scheduling and apron preparation run on the main thread. Missing
neighbor aprons can require a bounded synchronous generation; the measured
driver cost includes that work. Greedy meshing runs on the worker.

## Material, sky, shadows and fog

`project/chunk_material.gdshader` is a lit spatial shader using RGBA8 vertex
palette colors, a muted material tint, roughness 1 and restrained world-space
value noise. The noise
is continuous across chunk borders and sampled per fragment; its cost follows
screen coverage, not the number of LOD quads. Godot supplies sunlight, ambient
sky illumination, shadows and fog. The material uses normal backface culling.

`main.tscn` authors a procedural sky and one warm `DirectionalLight3D` at about
32° elevation, with shadows enabled. The 250-block shadow distance is a rendering
budget, not a promise to cover every corner of the maximum stream radius.
A chunk is one server instance and one surface; shadow and other passes can draw
that surface more than once. No extra post-processing stack is required.

Environment fog combines distance density 0.0045 with a height of 10 and height
density 0.04. Positive height density fills valleys exponentially below the
height plane. This uses dev5's real property names, not a fabricated
`fog_height_enabled`/min/max trio. `GODODIN_VOXEL_NOFOG=1` and
`GODODIN_VOXEL_NOSHADOW=1` are visual comparison switches. The optional
`GODODIN_VOXEL_STD_MATERIAL=1` selects a retained StandardMaterial3D reference.

## Culling and scope

Each surface has a world-space AABB inside its chunk footprint; Godot uses it
for instance frustum culling. Native verification checks the stored AABB against
a fresh mesh and rejects out-of-footprint bounds with error -7. The mesh digest
includes its AABB. Representative engine readback also compares the uploaded
AABB and all three byte arrays.

There are no baked occluders. A static bake is a poor fit for mutable streamed
chunks; a dynamic occlusion solution could be added with its own costs and
verification. Empty chunks emit nothing, and the worker skips their meshing.

There is one 32-block vertical layer, no physics bodies, no saved edits, no
texture assets or texture streaming, and no GPU mesher. Dev5's opt-in streamed
texture import would concern texels if large textures were added; today's
vertex palette and procedural detail do not exercise that feature. GPU meshing
would be a different Godot rendering workload, not an automatic improvement.

## What the eval proves

`eval/main.odin` retains the original 64-coordinate workload and default seed.
It measures generation and warm meshing at strides 1/2/4, counts actual visible
unit faces for the greedy ratio, repeats every coordinate and LOD, and compares
worker results to the synchronous reference. Submission errors, missing or
duplicate results, timeouts, digest mismatches, warm allocation and nonzero
worker teardown accounting fail the run. Timings are machine-local information;
digest equality and the correctness/allocation assertions are hard gates.

`project/stream_eval.gd` preserves the original flight: four warm seconds then
eight measured seconds at 10 blocks/s, seed 20260911, radius 4. `frame_avg_usec`
and `frame_p95_usec` now measure wall-clock intervals between frames, including
renderer/wait/presentation pacing. `driver_avg_usec` separately measures the
synchronous upload callback. Phase durations, settlement deadlines and upload
throughput use a monotonic wall clock. Camera motion and the original periodic
carve follow Godot frame delta, which can be capped under heavy load; the named
flight speeds are simulation speeds. None is an isolated GPU timestamp.

Outside that measured interval, the driver stops and requires full coverage,
verifies every resident chunk, makes a multi-voxel border carve and verifies it,
then retires the edited outer chunk and verifies the surviving neighbor before it
reconfigures twice at radius 6 and compares seed replay/storage/RID counts, then
flies at 80 blocks/s and again requires 169 settled chunks. Settlement is bounded
by a 30-second timeout. Surface readback at all three LODs compares actual engine
bytes to the native upload; six real mesher face directions are independently
encoded by ArrayMesh and compared to Odin's octahedral normal bytes. These
expensive checks do not run in interactive mode or the measured flight window.
The final shutdown asserts zero native RID/storage/staging owners, followed by
the Host's zero-instance and zero-foreign-value receipt.

The old [receipt](eval/voxel-stream-evidence.json) and
[original review](eval/reviews/2026-09-12-original.md) remain historical evidence.
The [fix batch](eval/batches/20260912-voxel-stream-fixes.md) records the corrections,
actual follow-up commands, commits, receipts and evidence limits. Old timings
are not presented as measurements of the corrected algorithm.

## The consume decision

The pinned server exposes `RenderingServer.mesh_add_surface(RID, Dictionary)`.
Its two-argument binding is in `servers/rendering/rendering_server.cpp:2371`;
`_dict_to_surf` at 1934 decodes the primitive, format, vertex and attribute bytes,
counts, AABB, indices and material. The example's bound native kits do not expose
the Variant construction needed to assemble that Dictionary. GDScript therefore
makes the single surface-add call per nonempty upload. An empty chunk has no
surface-add. This remains a documented deviation from an entirely native consume.

The mesher writes the engine layout directly: sequential positions (3×f32), then
octahedral normals (2×u16), separate RGBA8 attributes and uint16 indices. Dev5
`core/math/vector3.cpp:90` owns the octahedral algorithm;
`servers/rendering/rendering_server.cpp:621–627` packs its u16 values; RD mesh
storage at `servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp:1507`
describes the position/normal sections. These facts were checked against the
exact dev5 archive, not inferred from successful buffer-size validation.
The scene pulls staged byte views through the admitted `[]u8` return form,
which adds whole-buffer Host copies. The code does not claim zero-copy upload.
