Content as text
Materials, voxel types, microvoxel models and prop models in TOML; parametric parts, ranges sampled per instance, branches, scatters and ASCII voxel art; the asset library; and model grids for bodies, hair and gear.
Everything a Ragnavoxel world is made of can be read and edited as text. Materials, voxel types and models are TOML files a project lists in its project file, loaded by voxel::AssetLibrary (voxel/AssetLibrary.hpp). Units in model files are voxels unless stated; colours are linear RGB unless written as sRGB hex.
Materials
[[material]]
name = "granite_dartmoor" # unique id
albedo = [0.37, 0.30, 0.26] # linear reflectance
roughness = 0.62 # 0 mirror .. 1 matte
subsurface = 0.0 # translucency (leaves, petals)
emissive = [0, 0, 0]
seam_color = [1.0, 0.62, 0.22] # the emissive seam round merged tiles
seam_strength = 0.55
flags = ["opaque", "collidable"] # opaque water foliage emissive collidable dressed glass
face = { pattern = "granite", amplitude = 70, frequency = 150 } # default face parameters
# Optional: up-facing faces grow blades in the grass pass.
grass = { height = [0.28, 0.78], density = 680, width = 0.034, stiffness = 1.0,
base = [0.03, 0.075, 0.018], tip = [0.15, 0.27, 0.055], flowers = 0.025, flower = [0.85, 0.8, 0.55] }
Material files load in the order listed, and later files may use the materials of earlier ones. Air is material 0 and is registered for you. See Voxels and units for the flags and the face parameters.
Voxel types
A named voxel type is a material with face parameters for each side, and tint-jittered variants:
[voxels.bark]
material = "bark_oak"
variants = 4 # tint-jittered copies
jitter = 10 # +/- tint jitter per channel
faces.side = { pattern = "bark_oak", amplitude = 110, frequency = 150 }
faces.top = { pattern = "cells", amplitude = 30 }
# keys: all, side, top, bottom, px, nx, pz, nz (applied in that order)
Voxel types can be global (standalone terrain files, loadVoxelTypes) or local to a model file.
Microvoxel models
One model a file: trees, shrubs, herbs, fungi, rocks and fauna, built from parametric parts and stamped into the world.
[model]
name = "english_oak"
kind = "tree" # tree | shrub | herb | fungus | rock | fauna
description = "Quercus robur ..."
[variation]
scale = [0.85, 1.2] # uniform scale per instance
yaw = "free" # free | quarter | none
[[part]]
id = "trunk"
type = "capsule" # capsule | ellipsoid | box | layers | branches | scatter
from = [0, -38, 0] # any number may be a [lo, hi] range, sampled per instance
to = [[-12, 12], [340, 520], [-12, 12]]
radius = [[22, 32], [14, 20]] # start, end
segments = 3 # polyline segments
bend = [0, 14] # lateral jitter of interior points
shell = "bark" # voxel names (model-local or global)
core = "heartwood"
core_inset = 3
alt = "lenticel" # optional alternate shell voxel
alt_ratio = 0.1
grain = "micro" # micro: per voxel | clump: per cell of bricks
priority = "wood" # foliage | wood | rock | embed | overlay
Ranges are first-class. Any number may be [lo, hi], sampled for each instance from its seed, so one file grows a whole wood of different oaks.
Part types
- capsule: a tapered cylinder along a polyline (
from,to,radius,segments,bend). - ellipsoid:
center,radii,fillorshell, an optionaltopvoxel for upward faces,noise(surface wobble),holes(see-through gaps, 0 to 1),dome = truekeeps the upper half, andgrain = "clump"withcell = 2fills quarter-block leaf clumps. - box:
min,max,fill, optionaltop. - branches: grown from a
parent(a capsule or another branches part):count,along(0 to 1 along the parent),pitch(degrees above horizontal),length,relative_radius = [start, end](fractions of the parent’s radius),droop, and atiptemplate placed at each end. - scatter:
count,scatter_radius, and achildtemplate placed at each point. - layers: ASCII voxel art.
legendmaps single characters to voxel names (.or anything unmapped is air);layersgo bottom to top, each a list of rows along +z, each row a string along +x;originis the art’s minimum corner relative to the anchor. Layers turn by quarter turns and are never scaled.
A part with template = true is placed only through tip or child, its coordinates relative to that anchor (plus offset).
Using models
rv::voxel::AssetLibrary assets(materials, &palette);
assets.loadMaterials("assets/materials/geology.toml"); // before the palette is created
assets.loadVoxelTypes("assets/terrain/rocks.toml");
assets.loadModels("assets/models"); // a folder, searched recursively
rv::voxel::PrimitiveSet prims;
if (const auto* oak = assets.model("english_oak")) assets.instantiate(*oak, base, seed, prims);
scene.stamp(prims);
instantiate expands a model into world-space primitives at a base position, drawing yaw and variation from the seed; another overload grows it to a given shape. parseModel(text, file) parses a model without registering it (editors use it for live previews of unsaved edits) and throws with the file and the reason on any error; putModel and removeModel change the library at run time.
Prop models
model/PropModel.hpp. Furniture, tools, fittings and any hard-surface piece, built from a handful of shapes and rasterised into a fine voxel grid (typically 1/128 m to 1/32 m), then greedy-meshed into actor vertices, so props keep the world’s voxel look at any size. A file holds any number of [[model]] tables:
[[model]]
id = "stool"
cell = 0.0156 # voxel size in metres
[[model.part]]
shape = "cylinder" # box ellipsoid cylinder capsule cone torus
a = [0.0, 0.42, 0.0] # ends (cylinder, capsule); box/ellipsoid/torus use `at`
b = [0.0, 0.46, 0.0] # cone uses `base` and `tip`
r = 0.17 # cylinder, cone radius; capsule `ra`/`rb`; torus `R` ring, `r` tube
colour = "#a2723e" # sRGB hex; `colour2` the pattern's second colour
pattern = "rings"
period = 0.06 # metres per repeat of the pattern
rough = 0.8 # roughness; also emissive, metal, unlit, translucent, foliage
carve = false # true removes the shape from what came before
Box parts also take half (half extents) and yaw, pitch, roll; ellipsoids radii; tori axis. The patterns are wood grain (along x, y or z), rings, staves, stripes, checks, knotwork, weave, mail, mottle, a drawn map and masonry. Parts stamp in file order, and a carving part removes what came before it. Games add their own keys beside these (lights, seats, work spots) and read them themselves; the parser ignores what it does not know, and the editor still edits them.
Model grids: bodies, hair and gear
model/VoxelGrid.hpp. Actors (bodies, hair, clothes, armour, held gear) are built from signed distance functions rasterised into a voxel grid of any cell size, then greedy-meshed into flat-shaded faces. Each cell carries the joint it rides on, so one grid holds a whole articulated body, and skinned meshing keeps such bodies closed under any pose. LostVale grows its heroes at 1/64 m, their heads at 1/128 m and each eye at 1/1024 m in grids of their own this way.
Content checks
The editor’s --validate loads every model with the engine’s own loader, and --selftest checks that every content file round-trips byte for byte through the editor’s TOML handling (see The editor).
Written from the engine's headers and source as of commit 02e81b2 (2026-11-01).