Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit65083fe8f2

readme.md

voxelEngine system

Self-contained voxel engine for Zero. Lives entirely under @builtin::systems.voxelEngine and is the only path through which voxel content is created or edited.

Layout

systems/voxelEngine/
  voxelEngine.module/         -- the API
    init.luau                 -- public surface (Voxel.createWorld, Voxel.createShape, ...)
    grid.module/              -- internal: dense voxel grid + palette + edit ops
    mesher.module/            -- internal: pure-function mesh builder (simple + greedy)
  VoxelWorld.component/       -- internal singleton component (the world entity)
  VoxelShape.component/       -- internal per-entity component (props, characters, ...)
  readme.md                   -- this file

tools/voxelEngine.toolbox/    -- user-facing tools (Voxel.createWorld, Voxel.setBlock, ...)
                              -- Lives here today because toolbox discovery is currently
                              -- baked at build time and only scans `lib/tools/`. See
                              -- issue #1220 — the toolbox should colocate under
                              -- `systems/voxelEngine/voxelEngine.toolbox/` once
                              -- runtime VFS-driven toolbox discovery lands (parity
                              -- with how `.module` and `.component` are loaded).

Flow

                  ┌──────────────┐
   user / agent ──┤ voxelEngine  ├──┐
                  │  .toolbox    │  │
                  └──────────────┘  │
                                    ▼
                            ┌──────────────────┐
              custom code ──┤ voxelEngine      │── add / edit components
              (require)     │  .module (API)   │
                            └──────────────────┘
                                    │
                                    ▼
                       ┌──────────────────────────┐
                       │ VoxelWorld / VoxelShape  │
                       │       components         │
                       └──────────────────────────┘
                                    │
                                    ▼
                      Grid → Mesher → renderer.mesh.create

The components are internal. Don't add them by hand, don't edit their fields by hand. The module API spawns the entity, registers the component, and routes every edit through setBlock / fillBox / setPalette etc.

Two kinds of voxel content

KindComponentLifetimeUse for
WorldVoxelWorld (singleton — only one per scene)Entity at the scene originTerrain, additive build-out where every voxel sits on the same grid
ShapeVoxelShape (one per entity)Per-entity (move it, parent it, give it physics)Props, characters, items — anything not part of the world grid

A shape is independent of the world. It can be parented under any entity, given its own physics (physics = "dynamic"), and removed without affecting the world. The world is the additive surface everything else sits on or in.

Tool calls

-- Create / get the singleton world
local w = Voxel.createWorld({
    size = { x = 64, y = 32, z = 64 },
    blockSize = 1.0,
    palette = {
        grass = { 0.2, 0.7, 0.2 },
        dirt  = { 0.5, 0.3, 0.15 },
        stone = { 0.5, 0.5, 0.5 },
    },
})

Voxel.fillBox("world", { 0, 0, 0 }, { 63, 0, 63 }, "grass")   -- ground plane
Voxel.fillSphere("world", { 32, 6, 32 }, 4, "stone")          -- a pile of stone
Voxel.setBlock("world", 32, 7, 32, "grass")

-- Create a per-entity prop
local hero = Voxel.createShape({
    name = "hero",
    size = { 4, 8, 4 },
    blockSize = 0.25,
    position = { 32, 1, 32 },
    palette = { skin = { 0.95, 0.75, 0.6 }, shirt = { 0.2, 0.4, 0.8 } },
})
Voxel.fillBox(hero, { 0, 0, 0 }, { 3, 4, 3 }, "shirt")
Voxel.fillBox(hero, { 1, 5, 1 }, { 2, 7, 2 }, "skin")

-- Persist
world.debugSaveToDisk()

Custom code

local Voxel = require("@builtin::systems.voxelEngine.voxelEngine")
local w = Voxel.createWorld({ size = { 32, 16, 32 } })
w:fillBox({ 0, 0, 0 }, { 31, 0, 31 }, "grass")

The handle returned by createWorld / createShape exposes the same surface as the tools (setBlock, fillBox, fillSphere, setPalette, clear, flush, bounds, destroy, exists).

Persistence

Both components serialize their state (size, blockSize, palette, grid, physics, greedy) with the entity. world.debugSaveToDisk() writes them to disk; layers.load() rebuilds the Grid + mesh on load. Live edits made via the API land in the component's public.grid so what you save is what you ran.

Internals

  • grid.module — dense flat array (grid[1 + x + y*sx + z*sx*sy]), palette indexed by name, dirty flag, setBlock / fillBox / fillSphere / clear / setPalette / buildMesh ops. Pure data — no entity / mesh knowledge.
  • mesher.module — buildSimple(opts) emits one quad per visible face (favored for small props, easy to debug). buildGreedy(opts) merges adjacent same-color faces in the same slice. Both produce CCW-front winding ready for renderer.mesh.create().
  • The components hold a Grid instance plus the component's public state. All edits flow Voxel.X(...) → handle method → comp.X(...) → Grid mutation → requestRebuild() → coalesced renderer.mesh.create next defer.