World
Data model for the voxel world: layers, chunks, and per-voxel entries.
Under the hood world use:
Types
/**
* World-space integer position.
* Any `THREE.Vector3Like` is accepted wherever `VoxelCoord` is expected.
**/
interface VoxelCoord {
x: number;
y: number;
z: number;
}
interface VoxelEntry {
// references BlockDefinition.id;
// 0 = air (never stored), capped at MAX_BLOCK_ID (2^23 - 1)
blockId: number;
// packed rotation + flip flags
transform: number;
}IMPORTANT
VoxelEntry is a value type, not a handle. Chunks store voxels as packed integers (see Chunk), so every read rebuilds the object: compare results with a deep equality check, never ===. Use the Packed accessors on hot paths to skip the allocation entirely.
Coordinate helpers
Conversions from continuous world space to the whole cells the world stores. A cell owns the half-open span from its own corner up to the next, so both floor rather than round.
voxelCellOf(point: VoxelCoord): VoxelCoord
Cell containing point. { x: 3.5, y: 0.5, z: 4.5 } is in cell { x: 3, y: 0, z: 4 }, and { x: -0.2 } is in cell { x: -1 }.
voxelPositionOf(point: VoxelCoord, normal: VoxelCoord, side?: "front" | "back"): VoxelCoord
Cell on either side of a surface, for picking against a raycast hit. Offsets point half a cell along normal, then takes the containing cell.
"front"(default) is the empty cell the surface faces, where a voxel is placed."back"is the cell the surface belongs to, the voxel that gets removed.
Neither argument is modified.
VoxelWorld
Top-level container for a layered voxel scene. Layers are composited from highest order to lowest — the first visible layer with opacity > 0 that has a voxel at a given position wins. This allows decorative layers to override base terrain non-destructively. A layer with opacity === 0 is skipped during compositing exactly like an invisible one.
Constructor
new VoxelWorld(chunkSize?: number) // default: 16chunkSize must be a power of two. Every world-to-chunk conversion — on the write path, in the mesher, and in the neighbour lookups — is a shift and a mask, so a size that is not a power of two throws a RangeError rather than falling back to division.
Properties
readonly chunkSize: number;Methods
addLayer(name: string): VoxelLayer
Creates and appends a new layer with the next available order.
removeLayer(name: string): boolean
Removes a layer by name. Returns false if not found.
moveLayer(name: string, direction: "up" | "down"): void
Swaps order with the neighbouring layer in the given direction.
setLayerVisible(name: string, visible: boolean): void
Hidden layers are skipped during compositing and mesh rebuild.
setLayerOpacity(name: string, opacity: number): void
Sets a layer's rendered translucency (clamped to [0, 1]). A layer with opacity < 1 stops occluding neighbouring faces during mesh building (like glass); opacity === 0 is treated exactly like visible = false. Marks only the layer's own chunks dirty for a same-bucket change (e.g. 0.4 → 0.6), or every layer's chunks when the change crosses the opacity === 1 occlusion boundary. No-op if the layer is not found.
setLayerOffset(name: string, offset: VoxelCoord): void
Sets the world-space translation of a layer. All voxels in that layer are shifted by offset — a voxel stored at local {0,0,0} will appear at {offset.x, offset.y, offset.z} in world space. Marks all chunks in every layer dirty so cross-layer face culling is re-evaluated on the next frame. No-op if the layer is not found.
translateLayer(name: string, delta: VoxelCoord): void
Adds delta to the layer's current offset. Equivalent to calling setLayerOffset with layer.offset + delta. Marks all chunks dirty. No-op if the layer is not found.
getLayer(name: string): VoxelLayer | undefined
getLayers(): readonly VoxelLayer[]
All layers, sorted highest order first.
getVoxelAt(position: VoxelCoord): VoxelEntry | undefined
Composited read — returns the voxel from the highest-priority visible layer (opacity > 0) at that position. Returns undefined for air.
getPackedVoxelAt(position: VoxelCoord): PackedVoxel
Allocation-free getVoxelAt, returning VOXEL_ABSENT (-1) for air.
getVoxelWithLayerAt(position: VoxelCoord): { entry: VoxelEntry; layer: VoxelLayer } | undefined
Same compositing rules as getVoxelAt, but also returns the owning VoxelLayer so callers can inspect layer-level properties (e.g. opacity) of the resolved voxel.
getVoxelNeighbour(position: VoxelCoord, face: Face): VoxelEntry | undefined
Composited read of the voxel immediately adjacent to position in the given face direction.
setVoxelAt(layerName: string, position: VoxelCoord, entry: VoxelEntry): void
setPackedVoxelAt(layerName: string, position: VoxelCoord, packed: PackedVoxel): void
Writes a voxel directly and marks neighbouring chunks dirty for boundary face re-evaluation. Throws if the layer is not found. Prefer VoxelEngine.setVoxel to handle rotation packing.
removeVoxelAt(layerName: string, position: VoxelCoord): void
Removes a voxel. No-op if the layer is not found.
getAllChunks(): Generator<[VoxelLayer, VoxelChunk]>
Iterates over every chunk across all layers.
getAllDirtyChunks(): Generator<[VoxelLayer, VoxelChunk]>
Iterates over chunks whose dirty flag is set.
clear(): void
Removes all voxel layers and object layers.
Object Layer Management
Object layers hold placed objects (spawn points, trigger zones, etc.) rather than voxel data. They are stored by name and serialised as part of VoxelWorldJSON.
addObjectLayer(name: string, options?: { visible?: boolean; order?: number }): VoxelObjectLayerJSON
Creates a new object layer. order defaults to the current layer count (appended last). Returns the new layer descriptor.
removeObjectLayer(name: string): boolean
Deletes an object layer by name. Returns false if not found.
getObjectLayer(name: string): VoxelObjectLayerJSON | undefined
Returns the layer descriptor for name, or undefined if it does not exist.
getObjectLayers(): readonly VoxelObjectLayerJSON[]
Returns a snapshot array of all object layers in insertion order.
updateObjectLayer(name: string, patch: { visible?: boolean }): boolean
Applies a partial patch to a named object layer. Returns false if not found.
addObjectToLayer(layerName: string, object: VoxelObjectJSON): boolean
Appends an object to the named layer's objects array. Returns false if the layer does not exist.
removeObjectFromLayer(layerName: string, objectId: string): boolean
Removes the object with the given id from the layer. Returns false if the layer or object is not found.
updateObjectInLayer(layerName: string, objectId: string, patch: Partial<VoxelObjectJSON>): boolean
Merges patch into the matching object. Returns false if the layer or object is not found.