Trees
@voxolith/gen-tree: procedural broadleaf and conifer trees, from one pipeline, with bark, twigs and seasonal foliage.
@voxolith/gen-tree grows broadleaf and conifer trees from one pipeline, tuned for tall, detailed
models (about 192 voxels) where bark texture and single twigs are visible.
import { seededRandom } from "@voxolith/renderer/core";
import { generateTree, PRESETS } from "@voxolith/gen-tree";
const { entity, stats } = generateTree(PRESETS.oak, seededRandom(42));
// entity.model: a dense, Y-up grid of role indices, anchored at the trunk baseHow it works
Skeleton. Branch polylines with radii are grown before any voxel exists. Children start on the parent's axis, so the tree is one connected piece; child radius follows a pipe model, so forks conserve visual mass; direction wobble is coherent noise sampled in space.
Wood. Limbs of at least one voxel radius are rasterised as tapered capsules. Thinner twigs walk their axis with a 3D DDA, which crosses voxel faces and so stays 6-connected.
Bark, surface only. Furrow frequency scales with the local radius, so the wavelength stays constant in voxels as the trunk tapers.
Foliage. Clusters hang off real twigs, not a global envelope, so the crown inherits the irregularity of the branching. A shell hollow throws away buried leaves and a macro carve punches sky holes.
Colour, scored from how far out, how high and how exposed each leaf is, with accents chosen per cluster; then a prune keeps the result a single 6-connected component.
Parameters split into shape and foliage (which voxels exist) and look (which role each voxel
gets), so a UI can re-run the cheap colour pass while caching the geometry. Everything measured in
voxels is tuned for a 192-tall tree and scales with shape.height.
Voxel values are role indices (bark.dark, leaf.edge, snow, ...), so one tree is restyled for a
season or a biome by palette, without regenerating it. Presets: oak, maple and birch for the
broadleaf generator, spruce and pine for the conifer.
Finer scales
At 20, 50 and 100 voxels per metre the leaves, snow and cones refine from the coarse voxels (each leaf voxel becomes a few single leaves, or needles on a conifer, in its own shade), and the wood is redrawn from the skeleton: every segment and root as a thin shell of an exact tapered capsule, flared at the base and thinner above the trunk than the coarse tree could draw it, taking the role of the coarse voxel it falls in (so moss and crevices keep their places) and then fine furrows running up the stem. Leaves, blossom, snow and cones are loose roles. See scales and refinement.
Development
bun run --cwd generators/tree verify # connectivity, budget, determinism
bun run --cwd generators/tree preview species # also: skeleton, foliage, bark, shell, resolution, seasons
bun run --cwd generators/tree gen # bake .vox files into out/
bun generators/tree/tools/debug.ts oak 100 # per-level skeleton report for tuningBroadleaf
- Id
voxolith/tree.broadleaf- Version
- 0.1.0
- Scales
- 10, 20, 50, 100 voxels per metre
Parameters
Shape
| Parameter | Path | Range | Default |
|---|---|---|---|
Height overall height in voxels (10 per metre); the whole tree scales with it | shape.height | 32 to 240 | 192 |
Trunk radius trunk base radius as a fraction of height; higher is a stouter bole | shape.trunk.radiusRatio | 0.012 to 0.05, step 0.001 | 0.034 |
Taper how the trunk narrows: 1 is a straight cone, lower keeps it thick higher up | shape.trunk.taperExp | 0.3 to 1.4, step 0.05 | 0.55 |
Lean most the trunk may lean from vertical, in degrees; the actual lean is random up to this | shape.trunk.leanDeg | 0 to 12, step 0.5 | 3 |
Sweep total sideways bend of the trunk from base to top, in degrees | shape.trunk.sweepDeg | 0 to 20, step 0.5 | 7 |
Root flare extra radius at the foot as a fraction of the base radius; 0 is a straight stem | shape.trunk.flareGain | 0 to 1.6, step 0.05 | 0.85 |
Crown start where the lowest branches leave the trunk, as a fraction of its length; higher is a longer bare bole | shape.crownStartRatio | 0.05 to 0.8, step 0.01 | 0.38 |
Fork mass pipe-model exponent; higher keeps child branches thicker where they fork | shape.pipeExp | 1.8 to 3, step 0.05 | 2.2 |
Foliage
| Parameter | Path | Range | Default |
|---|---|---|---|
Foliage grow leaves or needles; off gives the bare wood skeleton | foliage.enabled | yes / no | yes |
Cluster radius broadleaf leaf clump radius in voxels at height 192; larger clumps give a fuller, lumpier crown | foliage.clusterRadius | 2 to 9, step 0.1 | 6 |
Cluster spacing broadleaf gap between clumps along a twig in voxels at height 192; lower packs them closer | foliage.spacing | 1 to 8, step 0.1 | 2.5 |
Shell depth leaves deeper than this below the canopy surface are dropped, in voxels at height 192; 0 keeps a solid crown | foliage.shellDepth | 0 to 40, step 1 | 14 |
Sky holes size of the sky holes carved through the canopy; 0 carves none | foliage.macroThreshold | 0 to 0.6, step 0.01 | 0.25 |
Look
| Parameter | Path | Range | Default |
|---|---|---|---|
Season leaf colours and density; a winter broadleaf is bare with snow on its upper faces | look.season | spring, summer, autumn, winter | summer |
Age 0 young and slender, 1 old: fatter trunk, more gnarl, a higher crown base, drooping limbs | look.age | 0 to 1, step 0.05 | 0.6 |
Health 1 healthy; lower thins the foliage and turns more of it dead brown | look.health | 0 to 1, step 0.05 | 0.9 |
Bark furrows spacing of bark furrows around the trunk in voxels; higher gives broader plates | look.furrowWavelength | 2 to 10, step 0.5 | 5 |
Moss moss cover on one side of the lower trunk; 0 is none | look.moss | 0 to 1, step 0.05 | 0.25 |
Presets
| Parameter | oak | maple | birch |
|---|---|---|---|
| Height | 192 | 192 | 192 |
| Trunk radius | 0.034 | 0.028 | 0.024 |
| Taper | 0.55 | 0.7 | 0.8 |
| Lean | 3 | 3 | 5 |
| Sweep | 7 | 7 | 10 |
| Root flare | 0.85 | 0.85 | 0.4 |
| Crown start | 0.38 | 0.34 | 0.42 |
| Fork mass | 2.2 | 2.2 | 2.2 |
| Foliage | yes | yes | yes |
| Cluster radius | 6 | 5.6 | 4.4 |
| Cluster spacing | 2.5 | 2.5 | 2.5 |
| Shell depth | 14 | 12 | 9 |
| Sky holes | 0.25 | 0.25 | 0.22 |
| Season | summer | summer | summer |
| Age | 0.6 | 0.6 | 0.6 |
| Health | 0.9 | 0.9 | 0.9 |
| Bark furrows | 5 | 4 | 3 |
| Moss | 0.25 | 0.25 | 0.05 |
Roles
Voxel values are these roles, in this order (value 1 is the first). The colours are the defaults; a host maps each role to a palette slot and can restyle it.
- 1Heartwood
wood.heart - 2Bark dark
bark.dark - 3Bark mid
bark.mid - 4Bark light
bark.light - 5Moss
bark.moss - 6Crevice
bark.crevice - 7Twig
twig - 8Twig dark
twig.dark - 9Leaf light
leaf.hi· may float when refined - 10Leaf mid
leaf.mid· may float when refined - 11Leaf dark
leaf.lo· may float when refined - 12Leaf edge
leaf.edge· may float when refined - 13Leaf accent
leaf.accent· may float when refined - 14Dead leaf
leaf.dead· may float when refined - 15Blossom
blossom· may float when refined - 16Snow
snow· may float when refined - 17Cone
cone· may float when refined
Conifer
- Id
voxolith/tree.conifer- Version
- 0.1.0
- Scales
- 10, 20, 50, 100 voxels per metre
Parameters
Shape
| Parameter | Path | Range | Default |
|---|---|---|---|
Height overall height in voxels (10 per metre); the whole tree scales with it | shape.height | 32 to 240 | 192 |
Trunk radius trunk base radius as a fraction of height; higher is a stouter bole | shape.trunk.radiusRatio | 0.012 to 0.05, step 0.001 | 0.021 |
Taper how the trunk narrows: 1 is a straight cone, lower keeps it thick higher up | shape.trunk.taperExp | 0.3 to 1.4, step 0.05 | 1 |
Lean most the trunk may lean from vertical, in degrees; the actual lean is random up to this | shape.trunk.leanDeg | 0 to 12, step 0.5 | 1.5 |
Sweep total sideways bend of the trunk from base to top, in degrees | shape.trunk.sweepDeg | 0 to 20, step 0.5 | 3 |
Root flare extra radius at the foot as a fraction of the base radius; 0 is a straight stem | shape.trunk.flareGain | 0 to 1.6, step 0.05 | 0.55 |
Crown start where the lowest branches leave the trunk, as a fraction of its length; higher is a longer bare bole | shape.crownStartRatio | 0.05 to 0.8, step 0.01 | 0.09 |
Fork mass pipe-model exponent; higher keeps child branches thicker where they fork | shape.pipeExp | 1.8 to 3, step 0.05 | 2.8 |
Foliage
| Parameter | Path | Range | Default |
|---|---|---|---|
Foliage grow leaves or needles; off gives the bare wood skeleton | foliage.enabled | yes / no | yes |
Cluster radius broadleaf leaf clump radius in voxels at height 192; larger clumps give a fuller, lumpier crown | foliage.clusterRadius | 2 to 9, step 0.1 | 6 |
Cluster spacing broadleaf gap between clumps along a twig in voxels at height 192; lower packs them closer | foliage.spacing | 1 to 8, step 0.1 | 2.5 |
Shell depth leaves deeper than this below the canopy surface are dropped, in voxels at height 192; 0 keeps a solid crown | foliage.shellDepth | 0 to 40, step 1 | 0 |
Sky holes size of the sky holes carved through the canopy; 0 carves none | foliage.macroThreshold | 0 to 0.6, step 0.01 | 0.22 |
Look
| Parameter | Path | Range | Default |
|---|---|---|---|
Season leaf colours and density; a winter broadleaf is bare with snow on its upper faces | look.season | spring, summer, autumn, winter | summer |
Age 0 young and slender, 1 old: fatter trunk, more gnarl, a higher crown base, drooping limbs | look.age | 0 to 1, step 0.05 | 0.6 |
Health 1 healthy; lower thins the foliage and turns more of it dead brown | look.health | 0 to 1, step 0.05 | 0.9 |
Bark furrows spacing of bark furrows around the trunk in voxels; higher gives broader plates | look.furrowWavelength | 2 to 10, step 0.5 | 4 |
Moss moss cover on one side of the lower trunk; 0 is none | look.moss | 0 to 1, step 0.05 | 0.25 |
Presets
| Parameter | spruce | pine |
|---|---|---|
| Height | 192 | 192 |
| Trunk radius | 0.021 | 0.03 |
| Taper | 1 | 0.8 |
| Lean | 1.5 | 4 |
| Sweep | 3 | 8 |
| Root flare | 0.55 | 0.55 |
| Crown start | 0.09 | 0.55 |
| Fork mass | 2.8 | 2.8 |
| Foliage | yes | yes |
| Cluster radius | 6 | 6 |
| Cluster spacing | 2.5 | 2.5 |
| Shell depth | 0 | 0 |
| Sky holes | 0.22 | 0.22 |
| Season | summer | summer |
| Age | 0.6 | 0.6 |
| Health | 0.9 | 0.9 |
| Bark furrows | 4 | 6 |
| Moss | 0.25 | 0.25 |
Roles
Voxel values are these roles, in this order (value 1 is the first). The colours are the defaults; a host maps each role to a palette slot and can restyle it.
- 1Heartwood
wood.heart - 2Bark dark
bark.dark - 3Bark mid
bark.mid - 4Bark light
bark.light - 5Moss
bark.moss - 6Crevice
bark.crevice - 7Twig
twig - 8Twig dark
twig.dark - 9Leaf light
leaf.hi· may float when refined - 10Leaf mid
leaf.mid· may float when refined - 11Leaf dark
leaf.lo· may float when refined - 12Leaf edge
leaf.edge· may float when refined - 13Leaf accent
leaf.accent· may float when refined - 14Dead leaf
leaf.dead· may float when refined - 15Blossom
blossom· may float when refined - 16Snow
snow· may float when refined - 17Cone
cone· may float when refined
See the API reference for generateTree and the parameter types.
Preview renderer
@voxolith/gen-kit/preview: the headless CPU raymarcher, contact sheets, cut-aways and PNG output used to judge generator output without a GPU.
Bushes
@voxolith/gen-bush: multi-stemmed shrubs, thickets, brambles, flowering shrubs and hedges, with thorns, berries, blossom and four seasons.