The pack
voxels3d
function voxels3d(opts: Voxels3dOptions = {}): Pack<{ voxels: Voxels3dApi }>
The voxels-3d pack: a chunked block volume with a procedural texture pack, exposed-face meshing with
baked ambient occlusion, a DDA raycast and a character controller. Requires a 3D world and render-3d.
Helpers
BLOCK
const BLOCK: { readonly air: 0; readonly grass: 1; readonly dirt: 2; readonly stone: 3; readonly cobble: 4; readonly sand: 5; readonly log: 6; readonly planks: 7; readonly leaves: 8; readonly water: 9; readonly snow: 10; readonly glass: 11; readonly brick: 12; readonly coalOre: 13; readonly goldOre: 14; readonly gravel: 15; readonly bedrock: 16; }
Named ids so callers read BLOCK.grass not a magic number.
BLOCKS
const BLOCKS: (BlockDef | null)[]
The block table. BLOCKS[id] — id 0 (air) is intentionally a hole.
Functions
bakeTiles
function bakeTiles(res = 16, seed = 1): { data: Uint8Array; layers: number; res: number }
Bake the whole pack: count layers of res*res RGBA, contiguous. Pure.
faceTile
function faceTile(def: BlockDef, face: number): number
Pick the per-face tile layer for a block + face index (0..5, order = FACES).
halveRGBA
function halveRGBA(px: Uint8Array, w: number, h: number): { px: Uint8Array; w: number; h: number }
Box-filter downsample one RGBA layer by 2× (for mip generation). Pure.
meshChunk
function meshChunk(get: (x: number, y: number, z: number) => number, x0: number, y0: number, z0: number, ch: number): Float32Array
Mesh one chunk into an interleaved Float32Array (VOX_FLOATS per vertex).
Only faces exposed to air / a non-opaque different block are emitted.
get is the WORLD accessor (crosses chunk borders for correct culling+AO).
raycastVoxel
function raycastVoxel( get: (x: number, y: number, z: number) => number, ox: number, oy: number, oz: number, dx: number, dy: number, dz: number, maxDist = 64, ): VoxelHit | null
March a ray through the grid; return the first SOLID block hit (or null).
place = hit cell + face normal is the empty cell to build into.
tileMipChain
function tileMipChain(baked: { data: Uint8Array; layers: number; res: number }, mipmaps = true): TileLevel[]
The baked pack's whole mip chain, level 0 first: each level box-filters every layer of the one above with
halveRGBA, down to 1×1 (floor(log2(res)) + 1 levels). One level when mipmaps is false. Both renderers
upload exactly this, so WebGL2 and WebGPU sample the same texels at every distance. Pure.
vertexAO
function vertexAO(side1: boolean, side2: boolean, corner: boolean): number
Standard 3-sample corner AO: 0 (both sides closed) … 3 (all open).
voxelTerrain
function voxelTerrain(world: VoxelWorld, opts: VoxelTerrainOptions = {}): void
Fill a VoxelWorld with a landscape. Pure + deterministic by seed — the same
(type, seed) is the same world on every machine. Every type is SOLID from the
surface down to bedrock (dig-through), coloured grass/sand/snow by height,
with an ore-flecked stone core. Reseed by calling clear() then this again.
Classes
VoxelAgent
class VoxelAgent
A mob: a VoxelBody plus a tiny brain. wander roams and randomly re-heads;
seek/flee chase or avoid a target; all of them AUTO-JUMP when a wall
blocks them (so they climb terraces like a Minecraft mob). Drive it with
update(dt, target?).
readonly body: VoxelBody— The physics body that the brain drives. Read its position for rendering.mode: VoxelAgentMode— The active steering mode. Change it at any time.speed: number— The move speed, in blocks each second. Default 3.heading: number— Current heading in radians (wander) — also where a mesh should face.constructor(world: VoxelWorld, spawn: { x: number; y: number; z: number }, opts: VoxelAgentOptions = {})update(dt: number, target?: { x: number; z: number }): void— One AI tick.targetis required for seek/flee (a point to chase/avoid).
VoxelBody
class VoxelBody
An axis-aligned body that walks the voxel world: gravity, jumping, per-axis
swept collision resolve against solid blocks, and auto step-up over 1-block
ledges. Feed it a wished horizontal velocity + a jump flag each step; it
resolves the move and reports onGround / blocked.
x: number— The X centre of the footprint, in blocks.y: number— The bottom of the body, in blocks (Y).z: number— The Z centre of the footprint, in blocks.vy: number— The vertical speed, in blocks each second. Negative is falling.onGround: boolean— True when the body stands on a solid block after the last step.blocked: boolean— True when a wall stopped horizontal motion last step (AI: turn/jump).readonly hw: number— Half the footprint width, in blocks. The body spans x - hw .. x + hw.readonly height: number— The body height, in blocks. Default 1.8.constructor(private world: VoxelWorld, spawn: { x: number; y: number; z: number }, opts: VoxelBodyOptions = {})step(dt: number, wishX: number, wishZ: number, jump: boolean): void— Advance one tick.wishX/wishZare desired horizontal velocity (blocks/s);jumplaunches if standing. Substepped so fast motion can't tunnel through a 1-block wall.
VoxelWorld
class VoxelWorld
A bounded grid of block ids, split into fixed-size chunks. Pure/testable.
readonly sx: number— The world width, in blocks (X).readonly sy: number— The world height, in blocks (Y).readonly sz: number— The world depth, in blocks (Z).readonly ch: number— The chunk edge length, in blocks. Default 16.readonly cx: number— The number of chunks along X.readonly cy: number— The number of chunks along Y.readonly cz: number— The number of chunks along Z.readonly dirty: Set<number>— Chunk indices needing a remesh.constructor(opts: VoxelWorldOptions = {})inBounds(x: number, y: number, z: number): boolean— Returns true when the cell (x, y, z) lies inside the world bounds.get(x: number, y: number, z: number): number— Block id at a cell, or 0 (air) outside the world.set(x: number, y: number, z: number, id: number): void— Set a cell. Marks the owning chunk (and a bordering neighbour) dirty.columnTop(x: number, z: number): number— Highest solid block at column (x, z), or -1 if the column is empty.markAllDirty(): void— Mark every non-empty chunk dirty (after a bulk generate, or device loss).clear(): void— Empty the world back to all-air. Marks every previously-filled chunk dirty so its geometry clears on the next remesh (used by reseed).chunkCoords(idx: number): [number, number, number]— Chunk grid coords from a linear chunk index (for the mesher).get chunkCount(): number— The total number of chunk slots in the world, filled or not.hasChunk(idx: number): boolean— Returns true when the chunk at a linear index holds block data.
Constants
AO_LEVELS
const AO_LEVELS: number[]
Ambient-occlusion brightness by occluder count (0 = darkest corner). Deliberately gentle — the block look wants a hint of crease, not deep shadow (Minecraft absorbs very little light per face).
FACES
const FACES: Face[]
The six cube faces in mesher order: +X, -X, +Y, -Y, +Z, -Z. Each holds its normal, axes and UVs.
isOpaque
const isOpaque = (id: number): boolean=> …
Does this block fully hide the faces behind it? Air, leaves, glass and water do not.
isSolid
const isSolid = (id: number): boolean=> …
Does this block stop movement and answer a raycast? Water does not.
TILES
const TILES: readonly ["grassTop", "grassSide", "dirt", "stone", "cobble", "sand", "logTop", "logSide", "planks", "leaves", "water", "snowTop", "snowSide", "glass", "brick", "coalOre", "goldOre", "gravel", "bedrock"]
The tile layer names, in upload order. The index of a name is its array-texture layer.
VOX_FLOATS
const VOX_FLOATS: 8
The number of floats in one voxel vertex: pos(3) + uv(2) + layer(1) + face(1) + ao(1).
Types
BlockDef
interface BlockDef
One face's tile picked by axis.
name: string— The block name, for reading and debugging (BLOCKmaps these names to ids).top: number— Tile layer index for the +Y face.bottom: number— Tile layer index for the -Y face.side: number— Tile layer index for the four side faces (±X, ±Z).opaque?: boolean— Fully hides faces behind it (default true). Leaves/glass/water = false.solid?: boolean— Blocks movement / is pickable by the raycast (default true). Water = false.cutout?: boolean— Alpha-tested in the shader (leaves, glass) — kept in the opaque pass.
TileLevel
interface TileLevel
One level of the texture pack's mip chain: every layer at w×h, one after another, as an array texture's level is laid out.
w: number— Level width in texels.h: number— Level height in texels.data: Uint8Array— RGBA bytes,w * h * 4per layer, every layer in order.
VoxelAgentMode
type VoxelAgentMode = 'wander' | 'seek' | 'flee' | 'idle'
The steering mode of a VoxelAgent: roam, chase a target, avoid a target, or stand still.
VoxelAgentOptions
interface VoxelAgentOptions extends VoxelBodyOptions
Options for a VoxelAgent: the body options plus mode, speed and wander seed.
mode?: VoxelAgentMode— The steering mode to start in. Default 'wander'.speed?: number— Move speed, blocks/s (default 3).seed?: number— Seed for wander randomness (default derived from spawn).
VoxelBodyOptions
interface VoxelBodyOptions
Options for a VoxelBody: its size in blocks and its gravity, jump and fall tuning.
width?: number— Footprint width in blocks (default 0.6).height?: number— Height in blocks (default 1.8).stepHeight?: number— Auto-climb ledges up to this tall without jumping (default 1.05 — walks single-block terraces smoothly; set ~0.6 for jump-required full blocks).gravity?: number— Downward acceleration, blocks/s² (default 28).jumpSpeed?: number— Jump launch speed, blocks/s (default 8.4 ≈ clears ~1.25 blocks).maxFall?: number— Terminal fall speed, blocks/s (default 40).
VoxelHit
interface VoxelHit
The result of a voxel raycast: the block hit, the entry face normal, and the ray distance.
x: number— The X cell of the solid block hit.y: number— The Y cell of the solid block hit.z: number— The Z cell of the solid block hit.nx: number— The X part of the entry face normal (points back toward the ray origin).ny: number— The Y part of the entry face normal.nz: number— The Z part of the entry face normal.dist: number— Ray distance to the hit.
Voxels3dApi
interface Voxels3dApi
game.voxels.
readonly world: VoxelWorld— The CPU grid — the contract everything else reads.get(x: number, y: number, z: number): number— Block id at a cell, 0 outside.set(x: number, y: number, z: number, id: number): void— Set a cell, marking its chunk and any bordering neighbour for a remesh.columnTop(x: number, z: number): number— Highest non-air block in a column, or −1.raycast(ox: number, oy: number, oz: number, dx: number, dy: number, dz: number, maxDist?: number): VoxelHit | null— March a ray and return the first SOLID block, or null. The hit's face normal added to its cell IS the empty cell to build into.landscape(opts?: VoxelTerrainOptions): void— Fill the volume with a generated landscape.clear(): void— Empty it back to air.body(spawn: { x: number; y: number; z: number }, opts?: VoxelBodyOptions): VoxelBody— A body that walks the blocks — the player, or a mob.agent(spawn: { x: number; y: number; z: number }, opts?: VoxelAgentOptions): VoxelAgent— A body with steering on top of it.readonly blockSize: number— World units per block.readonly chunksDrawn: number— Chunks drawn last frame.readonly verticesDrawn: number— Vertices submitted in visible chunks last frame.readonly remeshed: number— Chunks re-meshed last frame.enabled: boolean— Whether it draws.
Voxels3dOptions
interface Voxels3dOptions extends VoxelWorldOptions
Manifest options: the volume, the texture pack and how it draws.
tileRes?: number— Block-texture resolution in texels. Default 16 — the classic.seed?: number— Texture-pack seed. Default 1.blockSize?: number— World units per block. Default 1.mipmaps?: boolean— Build mipmaps, which is what kills the shimmer on distant blocks. Default true.cullDist?: number— Chunks further than this from the camera are skipped. Default 512.
VoxelTerrainOptions
interface VoxelTerrainOptions
Options for voxelTerrain and landscape: the landform, its seed, sea level and trees.
type?: VoxelTerrainType— Landform (default 'island'). All types fill SOLID down to bedrock, so you can dig right through them. 'island' + 'plains' add a sea; the rest are dry.seed?: number— The random seed. The same (type, seed) makes the same world. Default 1.seaLevel?: number— Water fill height. Defaults per type ('island'/'plains' have one; -1 = dry).trees?: boolean— Scatter trees on grass (default true).treeDensity?: number— Tree density multiplier (default 1).
VoxelTerrainType
type VoxelTerrainType = 'island' | 'flat' | 'plains' | 'hills' | 'mountains'
The landform that voxelTerrain builds: an island with a sea, or a dry or wet plain, or hills.
VoxelWorldOptions
interface VoxelWorldOptions
Options for a VoxelWorld: the world size in blocks and the chunk edge length.
sizeX?: number— The world width, in blocks (X). Default 128.sizeY?: number— The world height, in blocks (Y). Default 48.sizeZ?: number— The world depth, in blocks (Z). Default 128.chunk?: number— Chunk edge in blocks (default 16). Bigger = fewer draws, costlier edits.


