← Back to Documentation Index

Godot Voxel — Native Parity Plan

Status: actively in progress on feature/godot-adapter.

Sponsor

Current checkpoint (2026-05-07)

The current Godot voxel path is now native for the expensive terrain work:

Recent validation:

Next voxel-parity work:

Older terrain checkpoint (2026-05-02, commit 550147e)

Branch: feature/godot-adapter

Completed:

Current smoke-test status: 6/6 PASS — voxel-terrain, minecraft-demo, voxel-creative, wizardry-3d, star-fox-nova-3d, f-zero-nova-3d.

Key files

File Purpose
nova64-godot/gdextension/src/bridge.cpp C++ GDExtension bridge — mesher, fog, light.setSun
nova64-godot/gdextension/src/bridge.h Declarations — _sun_light, _cmd_light_set_sun
nova64-godot/godot_project/shim/nova64-compat.js JS shim — terrain, biomes, APIs
runtime/api-voxel.js Web engine ground truth for noise/biome/cart APIs

Shim constants (nova64-compat.js)

Latest parity checkpoint

Run on 2026-05-07:

pnpm godot:visual -- --cart=minecraft-demo --frames=220 --wait-ms=1000 --report-only --max-diff=100

Result: 84.13% report-mode pixel diff vs browser Three.js.

Improvements this session:

The remaining gap is primarily:

  1. Camera/fog/HUD framing differences in the visual harness.
  2. Lighting model differences: no skylight propagation or torch emission yet.
  3. Remaining compact-column limitations around caves, overhangs, ores, and chunk-border edge cases.
  4. Water material polish: transparency/tint/shoreline blending is functional but still not visually equivalent to the browser.

meta.json is supported in the Godot host path: load_cart() reads sidecar metadata, exposes it as globalThis.cart_meta, and the compatibility shim applies text, sky, fog, lighting, effects, and camera defaults before the cart module evaluates. Voxel-specific defaults should continue to flow through configureVoxelWorld() so carts keep one programming model across hosts.

Remaining gaps vs the web engine

  1. Camera/fog/HUD framing — the Godot frame is visually readable, but the captured view still differs enough to dominate report-mode diff.
  2. Caves / overhangs / ores — compact-column uploads cover the common heightmap path well, but need another audit against browser full-volume generation features.
  3. Lighting — no skylight propagation or torch emission buffer yet.
  4. Water polish — water is native and non-solid now, but fluid material tint, transparency, and shoreline blending remain approximate.

Phased plan

Phase 1 — Native voxel.uploadChunk (face-culled mesher) ✅ DONE (commit 4817332)

Added _cmd_voxel_upload_chunk in C++: builds an ArrayMesh from a packed block array, emitting one quad per visible face. Shim replaced column-bucketing path with a chunk-builder calling voxel.uploadChunk per 16×50×16 chunk. Shutdown double-free fixed (_handles->clear(false)).

Phase 2 — Greedy meshing in C++ ✅ DONE (commit 299b03d)

Same bridge command, smarter mesher: sweeps each axis plane, builds a 2D visibility+color mask, merges same-colored adjacent faces into rectangles. ~5-10× fewer triangles for typical heightmap terrain.

Phase 3 — Simplex noise + per-biome height formula ✅ DONE

Goal: Eliminate the terrain generation divergence that accounted for the old value-noise heightmap mismatch.

Step 1 — Port simplex noise from web engine into shim ✅

runtime/api-voxel.js uses OpenSimplex2 (lines ~100–243). Port or inline an equivalent pure-JS _vxSimplex2D(x, z) into nova64-compat.js, then replace _vxFbm/_vxSmoothNoise with:

function _vxFbm2D(x, z, octaves, persistence, lacunarity, scale) { ... }

Use the same call sites as the web engine:

Step 2 — Per-biome height formula ✅

Replace the single VX_BASE_Y + blend * VX_HEIGHT_AMPLITUDE formula with biome-conditioned heightBase + simplex * heightScale matching the web engine:

Biome heightBase heightScale
Jungle 58 22
Desert 63 4
Plains 64 6
Forest 64 8
(etc — check runtime/api-voxel.js for all values)

Validation:

Phase 4 — Cave / overhang / ore parity ← NEXT

Audit the compact-column shortcut against browser full-volume generation for caves, overhangs, ores, and edge-case chunk boundaries. Decide whether to extend native column expansion with targeted carve/ore metadata or send a selective full-volume payload only when a cart needs those features.

Phase 5 — Skylight / torch-light parity

The native atlas path is already live. The remaining lighting pass should add or approximate an A8 skylight/block-light buffer per chunk, then feed it into vertex color or a secondary attribute so caves, water, and tree interiors better match the browser renderer.

Build and test commands

# Build both platforms (WSL)
wsl bash -lc 'cd /mnt/c/Users/brend/exp/nova64/nova64-godot/gdextension && scons platform=linux target=template_debug -j$(nproc) 2>&1 | tail -15 && scons platform=windows target=template_debug use_mingw=yes -j$(nproc) 2>&1 | tail -15'

# Smoke test (6 carts)
powershell -NoProfile -ExecutionPolicy Bypass -File nova64-godot\scripts\run-cart-smoke.ps1

# Visual parity — minecraft-demo
wsl bash -lc 'cd /mnt/c/Users/brend/exp/nova64 && source ~/.nvm/nvm.sh; nvm use 20 >/dev/null; pnpm godot:visual -- --cart=minecraft-demo --frames=120 --wait-ms=3000 --max-diff=100'

# Commit pattern (never git push)
Set-Content -Encoding utf8 .git/COMMIT_MSG_TMP "your message"
wsl bash -lc "cd /mnt/c/Users/brend/exp/nova64 && git add <files> && git -c core.hooksPath=/dev/null commit -F .git/COMMIT_MSG_TMP && rm .git/COMMIT_MSG_TMP"

Decision log