Tree feature
minecraft:tree_feature grows a tree at the origin. You reach for it for anything tree-shaped — a forest's oaks, a savanna's leaning acacias, a swamp's vine-hung trunks, a log lying on a forest floor — and for a good deal that is not a tree at all, because a trunk is a column of blocks and a canopy is a blob of blocks around it.
It is a Content feature: it writes blocks itself and never delegates to another feature. The one key that looks like delegation is not — a trunk's branches.branch_canopy nests a canopy shape, not a feature reference. (Two keys genuinely do delegate: log_decoration_feature, on the fallen and poplar trunks.)
What makes it the most configurable type in the system is that it is not one algorithm. A tree body names exactly one trunk key and exactly one canopy key, and which keys are present is what selects the algorithm — there is no "type" field. Eight trunk shapes, twelve canopy shapes, each with its own field set. You do not need to read all twenty: find the trunk you want in the trunk table, the canopy you want in the canopy table, and read those two.
Start here: a complete example
One file, complete. A leaning acacia trunk that grows a side branch, with a big crown on the trunk and a small one on the branch tip.
features/acacia_branching_tree.json{
"format_version": "1.21.110",
"minecraft:tree_feature": {
"description": { "identifier": "wiki:acacia_branching_tree" },
"acacia_trunk": {
"trunk_width": 1,
"trunk_height": { "base": 5, "intervals": [3, 3], "min_height_for_canopy": 3 },
"trunk_block": { "name": "minecraft:log2", "states": { "new_log_type": "acacia" } },
"trunk_lean": {
"allow_diagonal_growth": true,
"lean_height": { "range_min": 1, "range_max": 5 },
"lean_steps": { "range_min": 1, "range_max": 4 }
},
"branches": {
"branch_chance": 100.0,
"branch_length": { "range_min": 4, "range_max": 6 },
"branch_position": { "range_min": 1, "range_max": 3 },
"branch_canopy": {
"acacia_canopy": {
"canopy_size": 1,
"leaf_block": { "name": "minecraft:leaves2", "states": { "new_leaf_type": "acacia" } },
"simplify_canopy": true
}
}
}
},
"acacia_canopy": {
"canopy_size": 2,
"leaf_block": { "name": "minecraft:leaves2", "states": { "new_leaf_type": "acacia" } },
"simplify_canopy": true
},
"base_block": ["minecraft:dirt"],
"may_grow_on": ["minecraft:dirt", "minecraft:grass_block", "minecraft:podzol"],
"may_replace": ["minecraft:air", "minecraft:leaves2"],
"may_grow_through": ["minecraft:air", "minecraft:grass", "minecraft:dirt", "minecraft:grass_block"]
}
}What each choice buys you:
acacia_trunkandacacia_canopyare the two keys that select the algorithm. Swapacacia_trunkfortrunkand this becomes a straight-column tree without touching anything else; swapacacia_canopyforpine_canopyand it keeps its lean and grows tiers instead.trunk_height: { "base": 5, "intervals": [3, 3] }samples 5 to 9: a base of 5 plus one random value per entry inintervals, each from 0 to that entry minus one.min_height_for_canopy: 3means only logs from index 3 upward are offered to the canopy as a place to sit.branch_chance: 100.0is a percent, and 100 always succeeds — which is what makes the two-canopy silhouette reproducible rather than a coin flip.branch_canopyis a whole canopy body nested insidebranches. It is not a feature reference and it is shaped independently of the tree's own canopy: here it is acanopy_size: 1acacia crown against the trunk'scanopy_size: 2.may_replacelistsminecraft:leaves2as well as air, so the branch's crown and the trunk's crown may overlap instead of the second one stopping at the first.

featurelab generate --pack <pack> --feature wiki:acacia_branching_tree --env plains --seed 3Run against plains with feature seed 3, this writes 48 blocks: 13 acacia logs, 34 acacia leaves, and the dirt base_block puts under the trunk in place of the grass. The trunk leans away from its base; the branch steps diagonally out of it and up; the large canopy sits at the trunk's own top and the small one at the branch tip.
The branch is not guaranteed to look like this
The branch's direction is random, and one of the four directions it can pick is the trunk's own lean direction — in which case the branch is abandoned and the tree comes out with one crown. branch_chance: 100 only guarantees the branch is attempted. At other seeds it comes out on the opposite side, or not at all.
Fields
A tree body has three parts: a handful of keys that apply whatever shape you chose, exactly one trunk key, and exactly one canopy key. Writing none of either, or two of either, is reported rather than resolved — there is no default shape. "Default" below is what the game uses when the key is absent. The long-form account of every key, in the editor's own words, is the field reference further down; these tables are the short version.
The eight trunk keys
One picture, eight trees that differ in one key. Every panel grows from the same origin at feature seed 3, in the same 12×19×10 volume with the same camera, with the same minecraft:oak_log and a trunk 15 blocks tall wherever the shape has a height at all. The crown is cut down to a 10-cell marker in every panel, because an ordinary crown hides the thing this figure is about — so what you are looking at is the log skeleton each trunk key builds, and where it hands its canopy over.

| Trunk key | What it builds | Reach for it when |
|---|---|---|
trunk | A plain vertical column, and nothing else: no lean, no branch, no random direction anywhere in it. It is the only trunk that can start below its origin — can_be_submerged lets it descend through may_grow_through cells and grow from the deepest one it reaches. Hands the canopy a single anchor and an empty anchor list. | You want an ordinary tree. Vanilla's oak, birch, jungle, spruce, pine and swamp trees are all this key; what makes them look different is the canopy, not the column. |
acacia_trunk | A column that can lean diagonally and grow a side branch that carries its own crown. Despite the name, nothing about it is tied to acacia wood. | You want a tree that is not vertical, or a second crown off to one side. Vanilla's savanna and roofed trees. |
cherry_trunk | A column with long horizontal branches, and a crown at every branch tip rather than on the trunk. tree_type_weights picks between one branch, two branches, and two branches plus a crowned trunk top. | You want a wide, low, several-lobed crown carried on visible limbs. |
fallen_trunk | A horizontal log lying on the ground with a short stump at one end. It grows no canopy at all. Since 1.26.50.24 the log also drops through and replaces ground cover such as leaf litter instead of failing on it. | You want forest-floor debris. Pair it with log_decoration_feature to grow something on each log. |
fancy_trunk | A scaled column that scatters foliage coordinates around itself, grows a canopy at every one of them, and draws a limb out to each. The lumpy multi-lobed big-oak silhouette falls out of those crowns overlapping. | You want a big irregular tree rather than a tidy one. Vanilla's fancy oak. |
mangrove_trunk | A column with branches that step outward and upward, aerial roots (through the separate mangrove_roots key) and hanging decoration. | You want stilted, branching, swamp-shaped growth. |
mega_trunk | A wide (trunk_width 2 or more) column with branches radiating at random angles, trunk decoration, and an optional base_cluster ground patch — the only shape that reads that key. | You want a giant: vanilla's mega jungle and mega spruce. |
poplar_trunk | A perfectly straight column that never leans, crowned by a ring of short sideways branch stubs — and its canopy sits a fixed number of cells below the top, so the upper trunk spears through the crown. New in 1.26.50.24. | You want a tall narrow tree whose trunk is visible above its leaves. |
The twelve canopy keys
The trunk decides where the canopy goes; the canopy decides what shape it is. Most canopies use only the last anchor the trunk collected — the top of the trunk, or the last branch tip.
| Canopy key | Shape | Reach for it when |
|---|---|---|
canopy | A step pyramid: a stack of filled square layers narrowing with height, with the corners optionally rolled away. | You want the ordinary crown. Most of vanilla's trees use this. |
acacia_canopy | Flat, wide octagonal layers — the umbrella silhouette. One size knob, canopy_size. | You want a flat, wide top. |
pine_canopy | Tiered rings that shrink and regrow with height. | You want the stepped conifer look. |
spruce_canopy | The same kind of tiering on a different layer schedule, driven by two offsets rather than a height. | You want a conifer whose taper you control from both ends. |
fancy_canopy | A stack of tapered discs. The crown fancy_trunk grows at every one of its foliage coordinates. | You are writing a fancy_trunk, or you want a small round blob. |
roofed_canopy | A thick slab with a randomized peak, sized from an inner and an outer radius. | You want a dark-forest roof. |
mega_canopy | A wide crown sized from the trunk's own width. | You are writing a mega_trunk (or an acacia_trunk at width 1). |
mega_pine_canopy | The same, with a radius that steps as it climbs. | You want the mega spruce taper. |
mangrove_canopy | A scattered crown with hanging blocks, built by repeated random placement rather than in layers. Reads the whole anchor list. | You want an irregular crown and hanging growth. |
cherry_canopy | A crown placed per branch tip, with holes and hanging leaves. | You are writing a cherry_trunk. |
random_spread_canopy | Leaves scattered randomly around several trunk positions rather than in layers. Reads the whole anchor list. | You want leaves through the trunk rather than above it. |
poplar_canopy | A tall rounded crown of stacked diamonds with a log cross buried inside it. New in 1.26.50.24. | You are writing a poplar_trunk. |
Three pairings grow a bare pole, and one grows a bare log
The anchor list is not filled by every trunk. trunk and cherry_trunk hand the canopy an empty one, and random_spread_canopy and mangrove_canopy are the only two canopies that read it — they return immediately when it is empty, without placing a leaf. So trunk or cherry_trunk paired with either of those two grows a bare pole. That is engine behaviour, not a bench limit. Pair those two canopies with acacia_trunk, mega_trunk or mangrove_trunk, which push every placed log onto the list.
Two more pairings that surprise people, for different reasons. A cherry_trunk grows the canopy key on the feature body, once at every branch tip. It also accepts a branches.branch_canopy and never grows it: a cherry tree whose only canopy sits there loads without complaint and places its logs and not one leaf. And a fallen_trunk grows no canopy under any circumstances — the key is accepted and never used.
On the feature body
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
| one trunk key | yes | trunk acacia_trunk cherry_trunk fallen_trunk fancy_trunk mangrove_trunk mega_trunk poplar_trunk | — | The table above. Exactly one. |
| one canopy key | yes, except on fallen_trunk and cherry_trunk | one of the twelve above | — | The table above. Exactly one. A cherry tree grows it at every branch tip, and without one it is logs only. |
base_block | no | block descriptor, or an array of them | absent — no fixup | The ground under the trunk is converted to this list's first entry wherever it does not already match: one cell for most trunks, every cell of the trunk_width × trunk_width footprint for acacia_trunk and mega_trunk. fancy_trunk and mangrove_trunk never do it. It is also the block base_cluster lays. An absent or empty list means no fixup at all. |
may_grow_on | no | array of block descriptors | absent — no restriction | The ground the trunk will accept. If the cell below does not match, the tree fails outright. |
may_replace | no | array of block descriptors | absent — no restriction | The cells a log or a leaf may overwrite. This is the gate on every trunk cell at or above the origin, and on the cells of most canopies. A trunk cell that holds air, leaves, water or a vine takes its log whatever the list says, so a trunk grows through its own trunk_decoration vines and through a neighbour's crown. canopy and spruce_canopy do not read it: they write into air, leaves and vines only, whatever the list says. roofed_canopy writes into air only. |
may_grow_through | no | array of block descriptors | absent — no restriction | The cells the trunk may pass through below its own origin. Only the plain trunk ever has cells below its origin, and only when can_be_submerged is set — everywhere else this key is read, accepted and never consulted. See what the bench does differently. |
base_cluster | no | object — the next table | absent — no patch | Ground-level patches of base_block around the trunk — the podzol around a giant spruce. Read by mega_trunk and nothing else, and it lays nothing without a base_block. |
mangrove_roots | no | object — the table below | absent — no roots | The aerial-root pass. It is a sibling of the trunk key, not part of mangrove_trunk, and it runs for every trunk shape — see mangrove_roots decides where the trunk starts. |
base_cluster
The whole object is optional; all three keys are required once it is there. What a patch lays is the tree's own base_block (its first entry), not anything named here.
| Key | Required | Value | What it does |
|---|---|---|---|
may_replace | yes | array of block descriptors | Which ground cells the patch may overwrite. Its own list, not the tree's. Each cell of a patch is searched from two blocks above the ground down to three below, and the first block on this list takes the patch block — so an empty list, which passes everything, puts the patch in the air two blocks up. |
num_clusters | yes | integer ≥ 0 | How many patches to lay. |
cluster_radius | yes | integer ≥ 0 | How wide each one is. |
mangrove_roots
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
max_root_width | yes | integer ≥ 0 | — | How far the root spread may reach horizontally. |
max_root_length | yes | integer ≥ 0 | — | How far a single root may run. |
y_offset | yes | range | — | How far above or below the origin the root pass starts. |
root_block | yes | block descriptor | — | The root block in ordinary ground. |
muddy_root_block | yes | block descriptor | — | The root block where it runs through mud_block. |
mud_block | yes | block descriptor | — | The block that counts as mud for the rule above. It names one exact block state: states the descriptor leaves out take their defaults, and a cell in any other state is not mud. |
roots_may_grow_through | yes | array of block descriptors | — | The roots' own pass-through list. Unlike may_grow_through, this one is consulted on every trunk shape. |
above_root | no | object | absent — nothing on top | What to put on top of a root. |
above_root.above_root_chance | no | percent, or {numerator, denominator} | absent — never placed | How often to place it. |
above_root.above_root_block | no | block descriptor | absent | What to place. |
root_decoration | no | a decoration object | absent — roots left bare | Attached to the sides of roots, the same shape as trunk_decoration. |
trunk
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
trunk_block | yes | block descriptor | — | The log. |
trunk_height | yes | range | — | How tall the column is. A range, and its maximum is exclusive: {7, 9} gives 7 or 8, never 9. |
height_modifier | no | range | {0, 0} — no effect | Added to the sampled height. A combined height below 1 fails the tree. |
can_be_submerged | no | true, false, or { "max_depth": n } | absent — depth 0, no descent | How deep the column may descend below its origin before growing. true means 255; { "max_depth": n } means n; absent or false means no descent at all. |
can_be_submerged.max_depth | yes, inside the object | integer | — | The depth, when the object spelling is used. |
trunk_decoration | no | object — the shared table | absent | Blocks attached to the sides of logs. On this key all four horizontal sides of every log are eligible. |
acacia_trunk
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
trunk_block | yes | block descriptor | — | The log. |
trunk_width | yes | integer ≥ 1 | — | The footprint is trunk_width × trunk_width. |
trunk_height | yes | object | — | Not a range on this key — an object with the three sub-keys below. |
trunk_height.base | yes | integer | — | The floor of the height. |
trunk_height.intervals | no | array of integers | [] — the height is exactly base | One random addition per entry, each from 0 to that entry minus one. [3, 3] on a base of 5 samples 5 to 9. |
trunk_height.min_height_for_canopy | no | integer | 3 | Only logs at or above this index are offered to the canopy as an anchor. It never changes which logs are placed — see min_height_for_canopy. |
trunk_lean | yes | object | — | Required, even for a tree you do not want to lean. |
trunk_lean.allow_diagonal_growth | yes | boolean | — | Picks which of the two branch routines runs. It has a default of true behind it, but the default only applies to a tree with no trunk_lean at all, and trunk_lean is itself required — so leaving it out is a load error, not a silent fallback. |
trunk_lean.lean_height | yes | range | — | Where the lean starts, measured down from the crown — see lean_height is measured from the top. |
trunk_lean.lean_steps | yes | range | — | The most cells the column may shift sideways. |
trunk_lean.lean_length | no | range | {0, 0} — no effect | Extra loop iterations past the top of the trunk. They march sideways at the top log's level: a horizontal run at the crown, not a taller tree. |
branches | no | object — the next rows | absent — no branch is grown | Optional as a whole; all three of its own range keys are required once it is present. |
branches.branch_length | yes | range | — | Diagonal steps (allow_diagonal_growth: true) or column cells (false). |
branches.branch_position | yes | range | — | Offset from the lean start (diagonal) or below the canopy anchor (sweep). |
branches.branch_chance | yes | percent, or {numerator, denominator} | — | Whether a branch is grown. A number is a percentage; 100 or more always succeeds, 0 or less always fails. |
branches.branch_canopy | no | object with exactly one canopy key | absent — bare branch tips | A whole canopy body, grown at the branch tip, always sized as a 1×1 branch whatever trunk_width says. |
trunk_decoration | no | object — the shared table | absent | On this key only the sides facing out of the footprint are eligible. |
cherry_trunk
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
trunk_block | yes | block descriptor | — | The log. Branch logs are laid on their side. |
trunk_height | yes | object | — | Spelled as acacia_trunk's — base and intervals, no min_height_for_canopy — but sampled one wider; see the next row. |
trunk_height.base | yes | integer ≥ 2 | — | The floor of the height. |
trunk_height.intervals | no | array of integers | [] — the height is exactly base | One random addition per entry, each from 0 to that entry inclusive — not to one below it, as acacia_trunk's is. [2] on a base of 5 samples 5, 6 or 7. |
branches | yes | object | — | Required on this key: a cherry tree is its branches. |
branches.tree_type_weights | no | object | absent — always the single-branch shape | A weighted pick between the three shapes below. |
branches.tree_type_weights.one_branch | yes, inside the object | integer ≥ 0 | — | Weight for one branch. |
branches.tree_type_weights.two_branches | yes, inside the object | integer ≥ 0 | — | Weight for two branches in opposite directions. |
branches.tree_type_weights.two_branches_and_trunk | yes, inside the object | integer ≥ 0 | — | Weight for two branches and a crown on the trunk top. |
branches.branch_horizontal_length | yes | range, minimum 2 — maximum inclusive | — | How far out a branch reaches. |
branches.branch_start_offset_from_top | yes | range, maximum 0 — maximum inclusive | — | Where on the trunk a branch starts, counted down from the top. |
branches.branch_end_offset_from_top | yes | range — maximum inclusive | — | What height the branch tip ends at, counted from the top. |
branches.branch_canopy | no | object with exactly one canopy key | — | Accepted and checked like any canopy body, and never grown. The tips grow the canopy key on the feature body instead. |
fallen_trunk
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
trunk_block | yes | block descriptor | — | The log, laid on its side along the direction it fell. |
log_length | yes | range | — | The nominal length. The log itself comes out log_length minus two blocks long. |
height_modifier | no | range | {0, 0} — no effect | Added to the length. |
stump_height | no | range | {1, 1} — a single block | How tall the upright stump at the near end is. |
log_decoration_feature | no | feature identifier | absent | Another feature, run once at every log of the fallen log — never at the stump. Drawn as a connection in the node editor rather than as a form field. |
trunk_decoration | no | object — the shared table | absent | Applied to the stump column. |
fancy_trunk
Every key here is required, including branches and all three of its own — the opposite of acacia_trunk, where the whole object is optional.
| Key | Required | Value | What it does |
|---|---|---|---|
trunk_block | yes | block descriptor | Used for the trunk columns and the limbs alike. |
trunk_width | yes | integer ≥ 1 | The trunk is drawn as trunk_width² vertical columns. |
trunk_height.base | yes | integer | The floor of the height. |
trunk_height.variance | yes | integer ≥ 1 | The height is base plus a random value from 0 to variance minus one. Vanilla's oak samples 5 to 16, so the same file yields anything from a shrub to a full canopy tree. |
trunk_height.scale | yes | number | The fraction of the sampled height the trunk actually reaches, capped at height - 1. This is why foliage routinely sits above the highest log. |
width_scale | yes | number | Multiplies each level's radius: how far the foliage coordinates spread horizontally. |
foliage_altitude_factor | yes | number | Levels below height × this get no coordinates at all. |
branches.slope | yes | number | Drops each limb's attachment point down the trunk in proportion to how far out its coordinate sits. |
branches.density | yes | number | Scales how many coordinates are attempted per level. |
branches.min_altitude_factor | yes | number | A coordinate whose attachment height is below height × this keeps its canopy but grows no limb. |
mangrove_trunk
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
trunk_block | yes | block descriptor | — | The log. |
trunk_width | no | integer | absent | Accepted and never read on this shape. The mangrove column is always one block across whatever this says. |
trunk_height | yes | object | — | An object, not a range. |
trunk_height.base | yes | integer | — | The floor of the height. |
trunk_height.height_rand_a | yes | integer ≥ 0 | — | One random addition, 0 to height_rand_a minus one. |
trunk_height.height_rand_b | yes | integer ≥ 0 | — | A second one. |
branches | no | object | absent — branch_length and branch_steps both {0, 0} | The branch pass runs either way; with the defaults it grows nothing. |
branches.branch_length | no | range — maximum inclusive | {0, 0} | How far a branch reaches. Drawn twice per branch; see the draw table. |
branches.branch_steps | no | range — maximum inclusive | {0, 0} | How many steps it climbs on the way. |
branches.branch_chance | no | percent, or {numerator, denominator} | absent | Whether each branch is grown. |
trunk_decoration | no | object — the shared table | absent | All four sides eligible. |
mega_trunk
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
trunk_block | yes | block descriptor | — | The log. |
trunk_width | yes | integer ≥ 1 | — | 2 for vanilla's mega trees. The footprint is trunk_width × trunk_width. |
trunk_height | yes | object | — | base and intervals, as acacia_trunk's. |
trunk_height.base | yes | integer | — | The floor of the height. |
trunk_height.intervals | no | array of integers | [] — exactly base | One random addition per entry. |
branches | no | object | absent — a bare column | Optional as a whole; every key below is required once it is present. |
branches.branch_length | yes | integer | — | How many logs long each branch is. Not a range — a plain integer. |
branches.branch_slope | yes | number | — | Vertical change per step. May be negative, and a negative value moves where the branch begins — see the warning. |
branches.branch_interval | yes | range | — | The vertical gap between successive branch levels. |
branches.branch_altitude_factor | yes | object with min and max | — | The band of the trunk's height branches may start in, as fractions. min/max only — not a range, the same trap canopy_offset has. |
branches.branch_altitude_factor.min | yes | number | — | The bottom of the band. |
branches.branch_altitude_factor.max | yes | number | — | The top of the band. |
branches.branch_canopy | no | object with exactly one canopy key | absent — bare tips | A whole canopy body, grown at each branch's tip. |
trunk_decoration | no | object — the shared table | absent | Vines and moss on the column. |
poplar_trunk
New in 1.26.50.24; earlier builds reject the key.
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
trunk_block | yes | block descriptor | — | The log. The branch stubs use the same block on its side. |
trunk_height | yes | range | {7, 9} — maximum exclusive, so 7 or 8 | How tall the column is. |
remaining_trunk_height_above_branches | no | range | {4, 4} — maximum inclusive | How many trunk cells continue up through the canopy. The branch ring sits at height - remaining - 1 and the canopy one cell above it. |
amount_of_foliage_support_branches | no | range | {1, 4} — maximum inclusive | How many of the four cardinal directions get a stub. There are only four directions, so a value above 4 adds nothing. |
log_decoration_feature | no | feature identifier | absent | Another feature, run at every cell of the column — including a cell whose own log was refused. Drawn as a connection in the node editor. |
trunk_decoration | no | object — the shared table | absent | All four sides eligible, on the stubs as well as the column. |
trunk_decoration
A per-trunk key rather than a shared one, but it behaves the same wherever it appears. trunk, acacia_trunk, mega_trunk, mangrove_trunk, fallen_trunk and poplar_trunk accept it; fancy_trunk and cherry_trunk do not. It is how vanilla's vine-covered oak, spruce, jungle and roofed trees get their vines.
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
decoration_block | no | block descriptor | absent | The single block to attach. Write this or decoration_blocks_sequence, not both — a sequence wins and this is ignored. |
decoration_blocks_sequence | no | array of { "block": …, "count": range } | absent | Ordered runs placed one after another from the same running position, which is what lets a sequence spell "two of A, then B". Each run stops at the first cell that is not air. |
decoration_blocks_sequence.block | yes, per entry | block descriptor | — | That run's block. |
decoration_blocks_sequence.count | no, per entry | range — maximum inclusive | {1, 1} | How many of it. {1, 3} really does reach 3. |
decoration_chance | no | percent, or {numerator, denominator} | 0 — decorates nothing | Rolled once per eligible side of every placed log. |
decoration_chance.numerator | yes, inside the object | integer | — | The fraction's top. |
decoration_chance.denominator | yes, inside the object | integer | — | The fraction's bottom. |
num_steps | no | integer | 0 | With decoration_block, the run is num_steps + 1 blocks: 4 hangs five, and leaving it out hangs one. A decoration_blocks_sequence ignores it; each entry's own count sets that entry's run. |
step_direction | no | down up out away | down | Which way a run longer than one block stacks. out and away are the same value spelled two ways: away from the log, in the direction that chose the cell. Mind the default — it is down, not outward. Only visible on a run longer than one block. |
Which sides are eligible differs by shape. trunk, mangrove_trunk and poplar_trunk enable all four horizontal sides on every log. acacia_trunk enables only the sides facing outward from its own footprint, and it evaluates the −X and −Z edges first: at trunk_width 1, where a cell is simultaneously on every edge, only the −X and −Z sides are decorated.
canopy
| Key | Required | Value | Default | What it does |
|---|---|---|---|---|
leaf_block | yes | block descriptor | — | The leaf. |
canopy_offset | yes | object with min and max | — | Which layers to build, relative to the anchor. A negative min puts layers below it. Not a range — see the warning. |
canopy_offset.min | yes | integer | — | The lowest layer. |
canopy_offset.max | yes | integer | — | The highest layer. |
min_width | no | integer | 1 | Widens every layer at once. At least 0. |
canopy_slope | no | object with rise and run | { "rise": 2, "run": 1 } | How fast the layers taper. The names read backwards — see the formula. A member left out keeps its own default. |
canopy_slope.rise | no | integer | 2 | The divisor. At least 1. |
canopy_slope.run | no | integer | 1 | The multiplier. At least 1. |
variation_chance | always write it | an array with one entry per layer; a single percent or {numerator, denominator} counts as one entry | — | The chance to leave out each of a layer's four corners, which is what rounds the square off. Ordered from canopy_offset.min upward. Optional in the schema, but the game crashes without it and misbehaves with too few entries — see the warning. |
canopy_decoration | no | object — the next rows | absent — nothing hangs | Hangs a run of blocks off the crown. |
canopy_decoration.decoration_block | yes | block descriptor | — | What hangs. |
canopy_decoration.decoration_chance | yes | percent, or {numerator, denominator} | — | Rolled once per horizontal neighbour of every leaf in the finished crown. |
canopy_decoration.num_steps | yes | integer | — | One less than how many cells a run is: 4 hangs five. The run stops at the first cell that is not air. The bench also accepts a range here, drawn inclusive of its maximum; the game takes an integer. |
canopy_decoration.step_direction | yes | down | — | Which way the run grows. Only down is accepted — see what the bench does differently. |
The other eleven canopies
| Canopy | Key | Required | Value | Default | What it does |
|---|---|---|---|---|---|
acacia_canopy | leaf_block | yes | block descriptor | — | The block both layers of the crown are built from. |
canopy_size | yes | integer | — | The half-width of the lower ring: the one size knob this crown has. | |
simplify_canopy | no | boolean | false | Replaces the upper layer's four protruding arms with a plain square. | |
pine_canopy | leaf_block | yes | block descriptor | — | The leaf. |
canopy_height | yes | range | — | How tall the cone is, sampled per tree. | |
base_radius | yes | integer | — | The half-width the cone is allowed to reach at its widest. | |
spruce_canopy | leaf_block | yes | block descriptor | — | The leaf. |
lower_offset | yes | range | — | Where the crown stops, sampled per tree: the lowest layer sits this many cells above the ground the trunk stands on — the first cell below the crown that is in may_grow_on — so that many logs at the foot of the trunk stay bare. | |
upper_offset | yes | range | — | How far above the trunk top it starts. The crown is built downward from there. | |
max_radius | yes | range | — | The widest a band may get before it snaps back. | |
fancy_canopy | leaf_block | yes | block descriptor | — | The leaf. |
height | yes | integer ≥ 0 | — | How many discs are stacked. | |
radius | yes | integer ≥ 1 | — | The half-width of the middle discs; the top and bottom ones are a cell narrower. | |
roofed_canopy | leaf_block | yes | block descriptor | — | The floor, the filling and the roof are all this block. |
canopy_height | yes | integer ≥ 3 | — | Three more than the number of layers between the floor and the roof: the game subtracts 3 first. Vanilla's dark oak writes 4 — one layer of filling, the roof one block above the anchor. 3 builds the floor and the roof with nothing between them. | |
core_width | yes | integer | — | The trunk width this crown is built around. Must match it — the feature is refused when it does not. | |
outer_radius | yes | integer ≥ -1 | — | The half-width of the floor and the roof. | |
inner_radius | yes | integer ≥ 0 | — | The half-width of the solid block of leaves stacked between them. | |
mega_canopy | leaf_block | yes | block descriptor | — | Every layer of the cone. |
canopy_height | yes | range | — | How many layers the cone has, sampled per tree. | |
base_radius | no | integer ≥ 0 | 2 | The half-width of the narrowest layer, at the very top. Every layer below widens by one from here, so this sets the whole cone. | |
core_width | yes | integer | — | Must match the trunk's width. At a branch tip the trunk is always one block wide, so a crown grown there needs 1. | |
simplify_canopy | no | boolean | false | Uses a strict circle for each layer instead of a relaxed one. | |
mega_pine_canopy | leaf_block | yes | block descriptor | — | Every layer of the cone. |
canopy_height | yes | range | — | How many layers, sampled per tree. | |
base_radius | no | integer ≥ 0 | 2 | The half-width of the topmost layer. | |
radius_step_modifier | no | number | 3.5 | How fast the cone widens going down. Larger means a wider, blunter cone. | |
core_width | yes | integer | — | Must match the trunk's width. | |
mangrove_canopy | canopy_height | yes | range | — | How far up and down a scattered leaf may land, sampled once for the whole crown. |
canopy_radius | yes | range | — | How far sideways it may land. | |
leaf_placement_attempts | yes | integer ≥ 0 | — | How many leaves are attempted around each trunk log. Attempts, not leaves — which is why this canopy needs a trunk that fills the anchor list. | |
leaf_blocks | yes | weighted block list | — | The blocks the scattered leaves are picked from, with weights. | |
hanging_block | yes | block descriptor | — | Hung beneath the crown — propagules, in vanilla. | |
hanging_block_placement_chance | yes | percent, or {numerator, denominator} | — | The chance any one candidate position below the crown gets one. | |
canopy_decoration | no | object | absent | Attaches a block to the sides of the hanging positions. The same shape as canopy's, except that decoration_block is optional when decoration_blocks_sequence supplies one, and its num_steps is accepted and ignored. | |
cherry_canopy | leaf_block | yes | block descriptor | — | The crown and its hanging fringe. |
height | yes | range, minimum 4 — maximum inclusive | — | How tall the crown is, sampled per crown. | |
radius | yes | range, minimum 3 — maximum inclusive | — | How wide it is. | |
trunk_width | no | integer, exactly 1 | 1 | The footprint the crown is built around. Must be 1: every trunk that can carry this crown hands it a one-block footprint, and any other value is refused. | |
wide_bottom_layer_hole_chance | yes | percent, or {numerator, denominator} | — | The chance of a hole in the outer edge of the widest bottom layer. | |
corner_hole_chance | yes | percent, or {numerator, denominator} | — | The chance of leaving out a layer's corner cell. | |
hanging_leaves_chance | yes | percent, or {numerator, denominator} | — | The chance of trailing a leaf one cell below the crown's bottom edge. | |
hanging_leaves_extension_chance | yes | percent, or {numerator, denominator} | — | The chance of extending that trail by a second cell. | |
random_spread_canopy | canopy_height | yes | range | — | How far up and down a scattered leaf may land, sampled once for the whole crown. |
canopy_radius | yes | range | — | How far sideways. | |
leaf_placement_attempts | yes | integer ≥ 0 | — | How many leaves are attempted around each trunk log. | |
leaf_blocks | yes | weighted block list | — | The blocks the scattered leaves are picked from, with weights. | |
poplar_canopy | leaf_block | yes | block descriptor | — | The leaf. |
branch_block | yes | block descriptor | — | The log the buried cross is made of. Unused below a radius value of 5. | |
radius | yes | non-empty array of {value, weight} entries, spelled { "value": n, "weight": m } | — | The crown widths to choose between. The working radius is the picked value - 1. | |
radius.value | yes, per entry | integer | — | The width. | |
radius.weight | no, per entry | integer | 1 | Its share of the pick. | |
height | yes | range | {5, 6} — maximum inclusive | How tall the crown is. | |
side_hole_chance | no | number 0 to 1 | 0.0 | Rolled on every crown cell; a success shrinks that one cell's effective radius by 1, pitting the surface. | |
trunk_width | no | integer | 1 | A consistency check only. It does not change the crown's geometry for any trunk this canopy can currently be paired with. |
How a range is written
Wherever a key above says range — the kind the editor's own catalogue calls range, and which older notes call an IntRange — four spellings are accepted: { "range_min": a, "range_max": b }, { "min": a, "max": b }, [a, b], or a bare number. The sampled value is uniform over [min, max) — the maximum is exclusive — on most keys. Seventeen keys are the exception and sample inclusive of their maximum, and they are not all new ones:
trunk_decoration.decoration_blocks_sequence[].count, andcanopy_decoration.num_stepswhen it is written as a range (the bench's own allowance; add one to the result), wherever either appears.- Every range a cherry tree has:
cherry_trunk.trunk_height.intervals(each entry adds 0 to that entry, not 0 to one below it, which is where it parts company withacacia_trunk's identically-spelled key),branches.branch_start_offset_from_top,branches.branch_end_offset_from_top,branches.branch_horizontal_length, and both ofcherry_canopy's,heightandradius. mangrove_trunk.branches.branch_lengthandbranches.branch_steps.poplar_trunk'sremaining_trunk_height_above_branchesandamount_of_foliage_support_branches, andpoplar_canopy'sheight.canopy_heightandcanopy_radiuson the two scattering canopies,mangrove_canopyandrandom_spread_canopy.
Everything else is exclusive: trunk_height on the other seven trunks, height_modifier, log_length, stump_height, the three trunk_lean ranges, acacia_trunk's and mega_trunk's branch ranges, mangrove_roots.y_offset, and every other canopy's own ranges. Mixing the two conventions in one file is easy to get wrong: { "range_min": 4, "range_max": 6 } is 4 or 5 on an exclusive key and 4, 5 or 6 on an inclusive one.
Two object keys look like ranges and are not: canopy_offset and mega_trunk's branch_altitude_factor take min/max and only min/max.
Common mistakes
| You wrote | What happens | Do instead |
|---|---|---|
A cherry_trunk tree with its canopy inside branches.branch_canopy | The file loads, the logs and branches grow, and not one leaf appears. The cherry trunk never grows its branch_canopy. | Move the canopy body out to the feature body, next to cherry_trunk. |
A canopy key on a fallen_trunk tree | Accepted, and never grown. A fallen trunk has no crown. | Nothing to fix — reach for log_decoration_feature if you want something on the logs. |
trunk or cherry_trunk paired with random_spread_canopy or mangrove_canopy | A bare pole: those two canopies read the anchor list, and those two trunks hand them an empty one. | Pair them with acacia_trunk, mega_trunk or mangrove_trunk. |
"trunk_height": { "range_min": 7, "range_max": 9 } expecting 9 to be possible | The maximum is exclusive: 7 or 8. | { "range_min": 7, "range_max": 10 }. |
"canopy_offset": { "range_min": -3, "range_max": 0 } | canopy_offset is not a range. The min/max spelling is the only one it takes. | { "min": -3, "max": 0 }. |
"branch_altitude_factor": [0.6, 0.8] | The same trap on mega_trunk. | { "min": 0.6, "max": 0.8 }. |
"lean_height": { "range_min": 1, "range_max": 2 } meaning "lean only near the ground" | lean_height is measured down from the crown, so 1 leans almost the whole trunk. | A value near the sampled height leans almost none of it. |
"branch_slope": -1.0 meaning "tilt the branch down" | The branch still ends at its own level; a negative slope moves its start upward, three blocks for every step of length. | Use a positive slope for a branch that rises to its level, and read the table before choosing a negative one. |
acacia_trunk.trunk_lean without allow_diagonal_growth | A load error. The field's default only applies to a tree with no trunk_lean at all, and trunk_lean is required. | Write it out. It changes the branch geometry completely, so it is worth stating anyway. |
"branches": { "branch_chance": 50 } on an acacia_trunk | A load error: once branches is present, branch_length, branch_position and branch_chance are all required. | Write all three, or leave branches out entirely. |
"min_height_for_canopy": 6 on a trunk that can sample a height of 5 | Some trees come out as bare trunks: no log qualifies as an anchor, so the canopy is handed an unset one and does not appear. | Keep it below the smallest height trunk_height can sample. |
"radius": [{ "value": 3 }] on a poplar_canopy expecting radius-3 layers | The working radius is value minus one, so that is a radius-2 crown — and below a value of 5 the buried log cross disappears and branch_block goes unused. | Write { "value": 4 } for radius 3. |
A plain canopy with no variation_chance | The file loads, and the game crashes the first time it places the tree. featurelab check reports it as an error and places nothing. | One entry per layer; 0 keeps a layer's corners. |
"variation_chance": [a, b, c] on a four-layer canopy, or a single chance on a canopy of two layers or more | Loads, and the game reads past the end of the list for the missing layers: random corners or a crash. A warning. | Count the layers — canopy_offset.max - canopy_offset.min + 1 — and write that many entries. |
mangrove_roots written inside mangrove_trunk | Not a key there. It is a sibling of the trunk key. | Write it on the feature body — and know that it then runs for whatever trunk you chose. |
"num_steps": 3 inside a trunk_decoration, expecting three blocks | Four: the run is num_steps + 1. With a decoration_blocks_sequence it is not read at all. | "num_steps": 2 for three, or a sequence entry with "count": 3. |
may_grow_through on any trunk but the plain one, expecting a trunk to push through undergrowth | Above the origin, every trunk is gated on may_replace alone; may_grow_through only ever applies below the origin, which only the plain trunk with can_be_submerged has. | Add the blocks to may_replace instead. |
| Two trunk keys, or two canopy keys, in one body | Reported, not resolved. There is no precedence between them. | Exactly one of each. |
How it runs
Every trunk shape has its own order, and the three that are worth walking through are below. What they share is this skeleton:
- The height is settled first, before anything is checked. That matters because a tree that fails its ground check has already committed to a height.
- If
mangrove_rootsis configured, the root pass runs — for any trunk shape. The position it returns replaces the origin, so the roots decide where the trunk starts. If the root pass fails, the whole feature fails: no trunk, no canopy, nothing placed. - The ground is checked at that position, against
may_grow_on, and the trunk is checked against the build height. Either failing ends the tree. - The trunk places its logs, one shape's worth. Every cell at or above the origin is gated on
may_replace; a cell below the origin — only the plaintrunkwithcan_be_submergedever has one — is gated onmay_grow_through. Each placed log offers its sides totrunk_decoration, and qualifies as a canopy anchor if it is at or abovemin_height_for_canopy. - The canopy grows, once per anchor. Most trunks collect one anchor;
cherry_trunkcollects one per branch tip, and the two anchor-reading canopies use the whole list. - The ground under the trunk is converted to
base_block, if it does not already match — and this happens after the canopy, not before.
The plain column (trunk)
trunk is the simplest shape and the one most of vanilla's own trees are built from — oak, birch, jungle, spruce, pine and swamp trees all use this key. It grows a straight vertical column and nothing else. What makes those trees look different from one another is the canopy paired with the column, not the column.
It is also the only trunk that can start below the origin it was handed. In order:
- The height is sampled from
trunk_height, with the usual exclusive maximum. - The descent (
can_be_submerged). The cell below the origin is tested againstmay_grow_through. While it passes and the depth budget allows, the trunk steps one cell further down, and the deepest passing cell becomes the position it grows from. If the very first probe fails, nothing moves. - The ground check, at the descended position rather than the original one. The tree fails here if the trunk would not fit under the build height, or if the cell below does not match
may_grow_on. height_modifieris added to the sampled height. A combined height below 1 fails the tree.- The column loop. One log per cell, straight up from the descended position. Cells below the original origin — the ones the descent walked past — are gated on
may_grow_through; cells at or above it are gated onmay_replace.trunk_decorationis offered all four horizontal sides of every placed log. - The canopy, placed once, one cell above the topmost log that was actually placed — not on it — with an empty anchor list.
- The ground fixup. Only now, after the canopy, is the cell under the descended position compared against
base_block.
The descent is what gives `may_grow_through` teeth
It is the only thing that does. Without can_be_submerged, every cell of the column is at or above the origin and gated on may_replace alone, so the field is read, accepted, and never consulted. Vanilla's own oak, birch and spruce all write may_grow_through in exactly that inert position.
The dependency does not run the other way. Vanilla's swamp tree sets can_be_submerged and writes no may_grow_through at all — and an absent or empty list means "no restriction", so its descent steps down through whatever happens to be under it.
Here is the shape at its plainest, committed as fixtures/features/tree_plain_trunk.json:

featurelab generate --pack <pack> --feature wiki:plain_trunk_tree --env plains --seed 3Twelve logs, dead straight, and 78 blocks in total: 12 logs, 55 leaves, 11 vines. The crown's bottom layer sits two cells below the topmost log, so the top three logs run up inside it. The vines are trunk_decoration at a 1-in-3 chance rolled against all four sides of every log, before the crown is built — and the crown then covers the ones beside those top three logs, so every vine left hangs below the leaves.
The definition sets can_be_submerged to { "max_depth": 1 } and lists minecraft:grass_block under may_grow_through, so the descent takes one step: the bottom log is at world Y 62, one below the requested origin of 63, and it replaced the grass block that was there rather than standing on it. Drop minecraft:grass_block from may_grow_through and the whole trunk moves back up a cell — the probe fails, the descent never happens, and Y 62 gets a base_block conversion instead of a log.
The step pyramid (canopy)
canopy is the matching default crown, and the one most of vanilla's trees use: a stack of filled square layers, widest at the bottom, narrowing with height. Each layer's half-width comes from one formula:
radius = slope(canopy_offset.max) + min_width - slope(dy)
slope(d) = truncate(canopy_slope.run * d / canopy_slope.rise)dy runs from canopy_offset.min to canopy_offset.max and is measured from the anchor the trunk handed over, so a negative min puts layers below it. With the defaults — min_width 1, canopy_slope { "rise": 2, "run": 1 } — and canopy_offset { "min": -3, "max": 0 }, that is radii 2, 2, 1 and 1 from the bottom up: the familiar oak crown, five blocks across. min_width widens every layer at once; canopy_slope changes how fast they taper.
rise and run are the other way round
Read as a fraction, canopy_slope is run over rise, not rise over run: run is multiplied by the layer's distance and rise divides it. So { "rise": 1, "run": 2 } does not make a gentler slope — it adds two blocks of half-width per layer. Over canopy_offset { "min": -3, "max": 0 } with min_width 1 that is radii 7, 5, 3 and 1 from the bottom up, a flat stepped pyramid 15 blocks across at its base. { "rise": 2, "run": 1 } is the gentle one: radii 2, 2, 1 and 1, the size of a vanilla oak crown. Both values must be at least 1, and min_width at least 0; the game refuses a file that goes below.
variation_chance is the only part of this canopy that is random at all, and it applies to corners only — a cell where |dx| and |dz| both equal that layer's radius. There are four such cells per layer, each rolled once, and a successful roll leaves that corner out, which is what rounds the square off. Write it as an array with one entry per layer, ordered from canopy_offset.min upward; a 0 entry keeps all of that layer's corners.
See the warning below before leaving it out or writing fewer entries than layers.
A one-cell layer is four corners at once
The corner test is not guarded against a radius of 0. On a one-cell layer, |dx| and |dz| are both zero and both equal the radius, so that single cell is a corner and gets rolled — and a chance that always succeeds deletes the layer outright. Vanilla's own oaks end their variation_chance array with { "numerator": 1, "denominator": 1 } on the top layer; at the default radius of 1 there, that takes all four corners every time and caps the crown with a plus shape. The plain-trunk example above does the same.
The leaves go into air, into other leaves and into vines, and nowhere else. may_replace is not asked at all, so listing water or stone there does not let this crown overwrite them. Vines are the case that shows: trunk_decoration hangs its vines on the logs before the crown is built, and the crown then covers the ones beside the logs inside it, so a vine-hung trunk only shows vines below its leaves.
canopy_decoration hangs a block off the crown once the whole crown is built. Every leaf block in the canopy's layers, including a matching leaf that was there before the tree, rolls decoration_chance once per horizontal neighbour; a successful roll on a neighbour that is air writes num_steps + 1 cells straight down from it, stopping at the first cell that is not air. It is how vanilla's swamp oak gets its hanging vines.
variation_chance is not optional
The game crashes on a canopy without it
The schema lets you leave variation_chance out, but the game reads one entry for every layer it places, and it never checks how many entries there are:
- No
variation_chanceat all: the game crashes the first time it places the canopy — on world generation and on/place featurealike.featurelab checkreports this as an error (canopy has no variation_chance: the game crashes when it places this canopy), and the bench places nothing for the feature rather than a crown the game would never grow. - Fewer entries than layers: the game reads past the end of the list for the rest, which gives random corners or a crash. A single chance — a bare number or one
{numerator, denominator}object — is stored as one entry, not copied to every layer, so it is short on any canopy of two layers or more.featurelab checkwarns; the bench reuses the last entry for the missing layers, which is its guess, not the game's answer.
The layer count is canopy_offset.max - canopy_offset.min + 1. Entries past it are never read. Vanilla's own jungle_bush_feature writes a single chance over three layers, so the game's own bush relies on reading past the end — do not copy that.
canopy_offset is not a range
It looks like a range and it is not
It is a plain object with min and max members, spelled that way and only that way — the range_min/range_max and [a, b] spellings the range keys accept do not apply to it. mega_trunk's branch_altitude_factor is the same kind of field. Both spellings turn up in the same vanilla definition, each on the field that wants it: vanilla's mega jungle tree writes branch_interval as range_min/range_max and branch_altitude_factor as min/max, four lines apart.
The leaning trunk (acacia_trunk)
This is the most involved trunk shape, and the one behind vanilla's savanna and roofed trees. Given an origin, in order:
- The height is sampled:
trunk_height.baseplus one random value per entry intrunk_height.intervals, each from 0 to that entry minus one — so{ "base": 5, "intervals": [3, 3] }samples 5 to 9. - The ground is prepared. The cell below each footprint column is checked against
may_grow_on; if one does not match, placement fails here, before anything is written. Then every footprint cell below the trunk that does not already matchbase_blockis converted to its first entry. - The lean direction is picked: one of the four cardinal directions.
- The lean start.
lean_heightis sampled and subtracted from the sampled height — see below. - The lean steps.
lean_stepsis sampled: the maximum number of cells the trunk may shift horizontally. - The lean length.
lean_lengthis sampled and added to the number of loop iterations, not to the height. - The column loop, for each index from 0 to
height + lean_length - 1:- If the index has reached the lean start and steps remain, the column shifts one cell in the lean direction and one step is consumed.
- The cell's Y is
origin.Y + indexonly while the index is below the sampled height. Past that point Y is frozen, so the remaining iterations march sideways at the top log's level. That is the whole effect oflean_length: a horizontal run at the crown, not a taller tree. - Every cell in the
trunk_width×trunk_widthfootprint is tested againstmay_replace/may_grow_throughand placed if it passes. - A placed cell becomes a canopy anchor if its index is at or above
min_height_for_canopy.
- The canopy runs once, at the last anchor collected.
- The branches. One of two routines runs, chosen by
trunk_lean.allow_diagonal_growth. Both run on every tree, whether or notbrancheswas configured.
lean_height is measured from the top
This is the field most likely to be set to the wrong end of the range by someone reasoning from the name. lean_height is the distance from the crown at which leaning starts, so a lean_height of 1 leans almost the whole trunk and a value equal to the height leans none of it:
lean_height: 1 lean_height: 5 (== height)
#
# #
# #
# #
# #The two branch routines
branches describes one branch concept but is consumed by two routines with genuinely different geometry. Which one runs depends on allow_diagonal_growth:
allow_diagonal_growth: true | allow_diagonal_growth: false | |
|---|---|---|
| Branches grown | At most one | Up to one per perimeter cell |
| Direction | One random cardinal direction; if it matches the trunk's own lean direction the branch is abandoned | No direction is picked — the sweep covers all sides |
| Shape | Steps diagonally outward and upward, one cell per step | A downward column below the crown |
| Starting point | lean_start - branch_position cells up the trunk | branch_position cells below the canopy anchor |
| Length meaning | Steps taken, bounded by the trunk height | Cells in the column |
| Decoration | trunk_decoration applies | Does not apply |
The non-diagonal sweep walks every offset from −1 through trunk_width on both horizontal axes and considers only cells outside the trunk footprint — the ring around it. Interior cells are skipped without a roll.
A branch that never manages to place a single log grows no branch_canopy. One that does places its canopy at the branch's final horizontal position and the last log's height — so if the branch's last step or two landed in blocked cells, the canopy ends up offset from the last log rather than on top of it.
min_height_for_canopy
Only trunk cells at or above this index become canopy anchors. It never affects which logs are placed. If the trunk is short enough that no cell qualifies, the canopy is handed an unset anchor rather than the trunk top, and effectively does not appear on the tree. A min_height_for_canopy larger than the smallest height trunk_height can sample is therefore a way to accidentally grow bare trunks some fraction of the time.
The scattered-foliage trunk (fancy_trunk)
fancy_trunk is the one trunk shape that does not work by "grow a column, put a crown on top". It builds a set of foliage coordinates scattered around the trunk, grows a canopy at every one of them, and then draws a limb from the trunk out to each. The familiar big-oak silhouette — a lumpy, multi-lobed crown rather than a tidy pyramid — falls out of those canopies overlapping.
Its phases, in order:
- Ground, then the trunk line. The cell below the origin is checked against
may_grow_on, then the straight line from the origin toorigin.y + height - 1is walked. A blocked line does not fail the tree — it shortens it, the blocked index becoming the new height. Only an obstruction at or belowtrunk_height.baseaborts placement. - Foliage coordinates. One coordinate is always seeded directly above the trunk. Then, for each level from
height - (variance+1)/3down to 0, a radius is computed from a semicircular profile anddensitydecides how many clusters that level attempts. A level belowheight * foliage_altitude_factorgets no radius and is skipped entirely. Each cluster is accepted only if the space above it is clear and the limb path back to the trunk is clear. - Placement. Canopies first, at every accepted coordinate; then the trunk itself, drawn as
trunk_width²vertical columns up totrunk_height.scaleof the sampled height; then a limb to each coordinate whose attachment height clearsheight * min_altitude_factor. Canopies going first is why logs sit on top of leaves where the two overlap, and not the other way round.
Two things that look like bugs and are not
The trunk stops at trunk_height.scale of the sampled height, so foliage routinely sits above the highest log; the limbs are what connect them. And because the height is base + variance sampled per tree, a low sample produces a genuinely stunted tree whose foliage overlaps its own trunk — vanilla's oak samples 5 to 16, so the same definition yields anything from a shrub to a full canopy tree.
Vanilla's own fancy_oak_tree_feature body, run at seed 3:

featurelab generate --pack <pack> --feature wiki:fancy_oak_tree --env plains --seed 3405 blocks: 31 logs and 374 leaves. The crown is not one canopy but many, each grown at its own foliage coordinate, with limbs reaching out to them from the trunk. Compare the shape with the acacia at the top of this page: no lean, no single branch, and a trunk that deliberately stops short of the foliage.
slope tilts each limb's attachment point down the trunk in proportion to how far out its cluster sits; density scales the cluster count with height; min_altitude_factor sets the height below which a coordinate keeps its canopy but grows no limb.
The fallen log (fallen_trunk)
A horizontal log on the ground with a short upright stump at one end, and no canopy — whatever canopy key the file writes, none is grown. Its length is log_length minus two blocks, plus height_modifier; stump_height is the upright part.
Two things are specific to this shape. The logs themselves are placed unconditionally — no allowlist gate — while the stump is gated on may_replace. And log_decoration_feature names another feature, run once at every log of the horizontal run and never at the stump, at that log's own position and after the log is written. That reference is weak: if nothing defines it, nothing is run and the log is laid bare, rather than the tree failing.
Since 1.26.50.24 a fallen log also drops through and replaces ground cover such as leaf litter instead of failing on it.
The branch-crowned trunk (poplar_trunk)
New in 1.26.50.24. poplar_trunk is the newest and simplest of the branching trunks: a perfectly straight column that never leans, topped by a ring of short sideways branch stubs just below the crown. Its whole character comes from where it puts the canopy — not on the trunk top, but a fixed number of cells below it, so the upper trunk spears through the crown. In order:
- The height is sampled from
trunk_height, with the usual exclusive maximum — the engine's own default of{7, 9}yields 7 or 8, never 9. - The ground is prepared. The tree fails if the cell below the origin does not match
may_grow_on, or the trunk would not fit under the build height. If the cell below does not matchbase_block, it is overwritten with the firstbase_blockentry. - The branch level.
remaining_trunk_height_above_branchesis sampled — this one includes its maximum — and subtracted from the height. The result is where the crown sits: the branches grow atheight - remaining - 1, the canopy one cell above them, andremainingtrunk cells continue up through the canopy. - The column loop. One log per cell from the origin up, each gated by
may_replace.trunk_decorationapplies to each placed log with all four sides eligible. Iflog_decoration_featurenames a feature, it runs at every column cell — including cells whose own log was blocked. - The branch stubs. The four cardinal directions are shuffled, then
amount_of_foliage_support_branches(inclusive) picks how many of them — in shuffled order — get a single sideways log at the branch level. The stubs use the trunk's own block lying on its side (pillar_axisfollows the branch direction), andtrunk_decorationapplies to them too. There are only four distinct directions, so values above 4 add nothing. - The canopy, placed once, at the cell directly above the branch stubs.
In the trunk-kinds figure, the poplar panel is the one whose crown sits a third of the way down the trunk. It is also the one whose marker crown is smallest: four of its ten cells, because the column itself and the four stubs already occupy the layer the crown starts on.
The poplar crown (poplar_canopy)
poplar_canopy builds a tall, rounded crown out of stacked diamond-shaped layers, then buries a small cross of horizontal logs inside it. Three decisions are made up front:
- The radius.
radiusis a weighted list of{ "value": n, "weight": m }entries (weightdefaults to 1). One entry is picked in proportion to its weight, and the working radius is itsvalueminus one (value - 1) — an entry of{ "value": 3 }produces radius-2 layers. - The height, from the canopy's own
heightrange, inclusive of its maximum. - A coin flip that picks one diagonal pair of quadrants to bulge outward by one cell — either north-west/south-east or north-east/south-west. The whole crown shares one flip, which is what gives a poplar its slightly lopsided, natural silhouette.
The layers then go down from the top: the topmost layer at radius − 2, two layers at radius − 1, the middle of the crown at the full radius, one more radius − 1 layer level with the anchor, and a small cap below the anchor. On the top two layers the outermost row and column are trimmed, so the crown rounds off rather than ending in a slab. Every remaining cell rolls once against side_hole_chance; a successful roll shrinks that one cell's effective radius by 1, pitting the crown's surface. Cells are only written where may_replace allows.
Finally, three layers below the crown's topmost layer, the leaves along the two horizontal axes are replaced with branch_block logs — a cross reaching out to radius - 4 cells from the centre, each log's pillar_axis following its arm. At a working radius of exactly 4 (a value of 5) the "cross" is the single centre cell; below that it vanishes entirely and branch_block goes unused, which is the case for small poplars.
`trunk_width` on this canopy is an assertion, not a shape knob
It exists only as a consistency check against the trunk's width; it does not change the crown's geometry for any trunk this feature can currently pair it with — every trunk hands its canopy a 1×1 crown footprint.
mangrove_roots decides where the trunk starts
mangrove_roots is worth calling out because it is easy to read as belonging to mangrove_trunk. It does not. It is a sibling of the trunk key, and the engine runs it for the feature: the tree's height is settled first, then the root pass runs, and the position it returns becomes the trunk's origin. So the roots do not just decorate the base — they decide where the trunk starts.
Three consequences:
- If the root pass fails, the whole feature fails. No trunk, no canopy, nothing placed.
- It runs for every trunk shape. Pair it with
mega_trunkorfallen_trunkand it still runs, and still moves the origin. roots_may_grow_throughis the roots' own pass-through list, consulted on every trunk shape — unlike the tree-levelmay_grow_through, which only ever applies below a plaintrunk's origin.
A negative branch_slope anchors the end of the branch, not the start
This is a mega_trunk.branches field, and nothing rejects a negative value. A negative value does not merely tilt the branch downward — it moves where the branch begins.
The engine places a branch by first computing a start height from the level it is attached to and then walking outward: startY = level - 1 - slope × (length - 1), then each step sits at startY + slope × step. The subtraction means the branch always ends at level - 1, whatever the slope is. A positive slope therefore starts the branch below its level and rises to it; a negative slope starts it above and descends to it, and the steeper the negative value, the higher the start.
For a branch of length 6 attached at level 20:
branch_slope | start | heights along the branch |
|---|---|---|
0.5 | 16 | 16 16 17 17 18 18 |
0.0 | 19 | 19 19 19 19 19 19 |
-0.5 | 21 | 21 20 20 19 19 18 |
-1.0 | 24 | 24 23 22 21 20 19 |
-2.0 | 29 | 29 27 25 23 21 19 |
At -2.0 the branch starts nine blocks above the level it belongs to — which can be above the trunk entirely, leaving branches hanging in the air over the tree. Because branches radiate at random angles and each one can carry its own branch_canopy at its tip, a negative slope turns the crown into a downward cone of branches with the apex at the top. That is a real shape you can build on purpose; it is only a surprise if you expected the value to change the angle without moving the origin.
Field reference
The long-form account of every key, generated from the editor's own catalogue — the same text the Feature Lab node editor shows in its ? pane and on hover, with the schema facts (required, kind, absent-key default, format_version gates) the editor's forms are built from. The tables above are the summary; where the two differ in precision, the tables are the measured version. Each trunk and canopy variant is folded, because a flat list of 235 keys is not a reference.
Exactly-one group: trunk
Exactly one trunk variant. The type does not load without one, and two is an error.
Exactly-one group: canopy
At most one canopy variant. canopy (bare) is the generic/default shape.
fallen_trunk.log_decoration_feature
optional · feature identifier · absent: nothing is run over the logs · edited on the connection, not in the form
A feature run once at every log of the fallen log itself.
Placed at the log's own position, immediately after the log is written, and never at the stump. Unlike the delegation every Proxy feature does, this one is not subject to the internal-feature permission check -- a fallen trunk runs it whenever the reference resolves. An unresolved reference is not an error: nothing is run and the log is laid bare.
poplar_trunk.log_decoration_feature
optional · feature identifier · absent: nothing is run over the column · edited on the connection, not in the form
A feature run once at every cell of the poplar's own column.
Every cell the column walks, including a cell whose own log was refused by may_replace -- so the count of runs follows the sampled height, not the number of logs that actually went down. An unresolved reference is not an error: nothing is run.
trunk — 16 keys
trunk
optional · group
The plain trunk: one straight column of logs, and nothing else.
The bare key is the SIMPLE shape, not a default that becomes something else once you fill it in. It takes five keys -- trunk_height and trunk_block are required, height_modifier, can_be_submerged and trunk_decoration are optional -- and has no trunk_width, no trunk_lean and no branches. It also hands its canopy an empty list of trunk positions, so pairing it with a canopy that scatters leaves over those positions grows a bare pole.
trunk.trunk_height
required · range
How many logs tall the column is, drawn once per tree.
A range, so write a number for a fixed height or {range_min, range_max} for a varying one. A range object spelled {min, max} is not read: the engine reports the two members as missing and uses a height of 0, which loads and grows nothing.
trunk.height_modifier
optional · range · absent: {0, 0} -- adds nothing, and costs no draw
A second draw added to the trunk height.
Drawn separately from trunk_height and added to it, so the two ranges compose. Leaving it out adds nothing and costs no draw at all, which keeps everything placed after this tree in the same spot.
trunk.can_be_submerged
optional · group · absent: no descent: the column starts at the origin
Lets the trunk start below the surface instead of at the origin.
Before building, the column walks downward through blocks listed in may_grow_through and starts from where it stops. This is an option ON the plain trunk and never a choice of trunk shape -- the bare key is the plain trunk with or without it.
Also accepts a bare true, which means a maximum depth of 255, and a bare false, which means the same as leaving the key out.
trunk.can_be_submerged.max_depth
required · integer
The furthest down the trunk may start, in blocks.
Required inside the object form. Writing the whole key as true instead means a maximum depth of 255, and writing false, or leaving it out, means no descent at all.
trunk.trunk_block
required · block
The log the trunk column is built out of.
Required on every trunk shape. Several shapes place sideways logs too -- branches, and a fallen log -- and those are this same block turned to lie along the direction they run in, so there is no second key for them.
trunk.trunk_decoration
optional · group · absent: no decoration -- logs are placed bare
Blocks hung off the sides of the logs, such as vines.
On this shape it is offered on all four sides of every log the column places. Each enabled side rolls decoration_chance independently, and only a side that wins its roll and finds a free cell gets anything. Up and down are never offered, on any trunk shape.
trunk.trunk_decoration.decoration_chance
optional · chance · absent: 0, which decorates nothing at all
How often one side of one log gets decorated.
Either a percent -- 100 always, 0 never -- or a {numerator, denominator} fraction. Mind the default: a trunk_decoration written without this key rolls 0 and therefore places nothing, so the decoration looks silently ignored rather than sparse.
trunk.trunk_decoration.decoration_chance.numerator
required · integer
The top half of a fractional decoration chance.
Used only when decoration_chance is written as an object. A numerator equal to the denominator always succeeds; anything else is compared against a draw below the denominator.
trunk.trunk_decoration.decoration_chance.denominator
required · integer
The bottom half of a fractional decoration chance.
A denominator of 0 never succeeds, and costs no draw. Otherwise the chance is numerator in denominator, drawn fresh for each side of each log.
trunk.trunk_decoration.decoration_blocks_sequence
optional · groupList
A stack of decoration blocks placed outward from the log, in order.
The entries share one running position: the first entry's run starts at the cell next to the log and each later entry continues from where the previous one stopped, rather than restarting. That is what lets a sequence spell "two of block A, then block B". Write this OR decoration_block, not both -- a sequence wins and the single block is ignored.
trunk.trunk_decoration.decoration_blocks_sequence.block
required · block
The block this run of the sequence places.
Accepted as a bare name string, as {name, states}, or as {tags: "<Molang query>"}. It is turned to face the log before it is written, so a vine-like block attaches the right way.
trunk.trunk_decoration.decoration_blocks_sequence.count
optional · range · absent: {1, 1} -- a single block, placed at the cell next to the log
How many blocks this entry of the sequence places.
A range, so it can differ per log. The run stops early at the first cell that is not free, and the next entry carries on from wherever it stopped.
trunk.trunk_decoration.decoration_block
optional · block
One block hung on the log, the short form.
Exactly the same as a decoration_blocks_sequence of one entry with a count of 1, and this is the spelling most trees use. Ignored when decoration_blocks_sequence is also present.
trunk.trunk_decoration.num_steps
optional · integer
With decoration_block, one less than the run length.
A single decoration_block becomes a run of num_steps + 1 blocks, so 4 hangs five vines and the default 0 hangs one. A decoration_blocks_sequence ignores it: there, each entry's own count sets its run.
trunk.trunk_decoration.step_direction
optional · enum · absent: down
Which way a run of decoration blocks stacks from the log.
Only visible on a run longer than one block: the first block of every entry lands in the same cell whatever this says. Mind the default -- it is down, not outward.
Values, in the order the engine lists them:
down— Each run hangs downward from the log. The default, and what a vine-like decoration wants: the run grows toward the ground one cell at a time.up— Each run climbs upward from the log. The run grows toward the sky one cell at a time, alongside the trunk rather than away from it.out— Each run grows away from the log, horizontally. It follows the same direction that chose the cell -- so a run on the north side keeps going north.away— The same asout, spelled differently. Both spellings are accepted and behave identically; there is no reason to prefer one over the other.
acacia_trunk — 23 keys
acacia_trunk
optional · group
A column that leans off to one side near the top, then branches.
A different key set from the plain trunk: trunk_width, an object-shaped trunk_height and trunk_lean are all required, and there is no can_be_submerged. The lean begins a drawn number of blocks BELOW the top of the trunk, not above the ground.
acacia_trunk.trunk_height
required · group
The height of the column, as a base plus optional random steps.
An object, not a range: base is the fixed part and intervals adds the variation. Writing a plain number here is refused, which is the quickest way to tell this shape apart from the plain trunk.
acacia_trunk.trunk_height.base
required · integer
The fixed part of the trunk height, in blocks.
Everything intervals draws is added on top of this, so it is the shortest the tree can be.
acacia_trunk.trunk_height.intervals
optional · groupList · absent: no intervals -- the height is exactly `base`, with no draw at all
Extra random height added on top of base, one draw per entry.
Each entry adds a draw between 0 and that entry's own value, so [3, 3] adds nought to four and [5] adds nought to four in one lumpier step. Leaving the list out makes the height exactly base every time, with no variation at all.
acacia_trunk.trunk_height.min_height_for_canopy
optional · integer · absent: 3
How far up the trunk must reach before a canopy may sit on it.
It gates where the canopy may ANCHOR, never where logs are placed: a trunk that never gets this high still builds its column, but hands the canopy nowhere to grow and comes out bare. It lives inside trunk_height rather than trunk_lean, which is easy to get wrong.
acacia_trunk.trunk_width
required · integer · range [1, −]
How many blocks across the trunk column is.
The column is a square of this many logs on each side, so 2 is a four-log column. It also decides which logs count as being on an edge, and only edge logs can carry a decoration.
acacia_trunk.trunk_lean
required · group
The sideways step the top of the trunk takes.
Required. A single horizontal direction is picked at random, and from lean_height blocks below the top the column starts stepping that way once per block for lean_steps blocks.
acacia_trunk.trunk_lean.allow_diagonal_growth
required · boolean
Picks which of two completely different branch routines runs.
Required, and getting it wrong does not shift the shape slightly, it swaps it: true grows at most ONE branch off a random side, false sweeps the trunk perimeter and can grow one per cell. The two even draw branch_length and branch_position in opposite orders, and only the true path decorates its branch logs.
acacia_trunk.trunk_lean.lean_height
required · range
How far below the top of the trunk the lean starts.
Counted DOWN from the top, not up from the ground: a draw of 1 leans over the last block, and a draw as large as the height leans from the very bottom.
acacia_trunk.trunk_lean.lean_steps
required · range
How many blocks the trunk steps sideways once it starts leaning.
One step per block of height, all in the same direction, so this is also how far the top of the tree ends up from its base.
acacia_trunk.trunk_lean.lean_length
optional · range · absent: {0, 0} -- no sideways run past the top of the trunk
Extra logs laid sideways at the very top of the lean.
It extends the column past trunk_height while the height stops rising, so it grows a horizontal run at the top rather than a taller tree. Left out it adds nothing and costs no draw.
acacia_trunk.branches
optional · group · absent: no branch is grown -- but see the note: the branch pass still runs
The branch grown off the side of the trunk.
Optional, but leaving it out is not the same as switching branches off: the branch pass runs on every acacia trunk and still spends its direction draw, it simply rolls a chance of 0 and places nothing. All three of branch_length, branch_position and branch_chance are required once the object is present.
acacia_trunk.branches.branch_length
required · range
How far the branch reaches out from the trunk.
Counted in steps, not in logs placed: a step into a blocked cell still moves the branch along and still uses up one of its length, it just leaves no log there.
acacia_trunk.branches.branch_position
required · range
How far below the start of the lean the branch leaves the trunk.
Subtracted from where the lean begins. A value that puts the branch above the top of the trunk grows no branch at all, and the draws are still spent.
acacia_trunk.branches.branch_chance
required · chance
How often a branch is grown at all.
Required inside branches. Either a percent or a {numerator, denominator} fraction. The random direction is drawn BEFORE this is rolled, and a branch pointing the same way the trunk leans is dropped, so even 100 does not mean every tree gets one.
Sub-keys: the same as trunk.trunk_decoration.decoration_chance — numerator, denominator.
acacia_trunk.branches.branch_canopy
optional · json · absent: no canopy is grown at the branch tips
A canopy grown at the tip of each branch this trunk makes.
Separate from the tree's own canopy key and shaped independently of it -- the branch tips always ask for a canopy one block wide, whatever trunk_width says. Write exactly one canopy variant key inside it; none and two are both reported.
Free-text field
A whole canopy body: exactly one canopy variant key, from the same set the tree's own canopy offers, and every one of those variants is described elsewhere in this panel. What is missing here is the control, not the knowledge -- a choice of one nested inside another field is not something this editor can draw yet, so it is edited as JSON. Writing two canopy keys here, or none, is reported rather than ignored.
acacia_trunk.trunk_block
required · block
The log the trunk column is built out of.
Required on every trunk shape. Several shapes place sideways logs too -- branches, and a fallen log -- and those are this same block turned to lie along the direction they run in, so there is no second key for them.
acacia_trunk.trunk_decoration
optional · group · absent: no decoration -- logs are placed bare
Blocks hung off the sides of the logs, such as vines.
On this shape it is offered on the outward sides of every edge log of the column, and on all four sides of each branch log. Each enabled side rolls decoration_chance independently, and only a side that wins its roll and finds a free cell gets anything. Up and down are never offered, on any trunk shape.
acacia_trunk.trunk_decoration.decoration_chance
optional · chance · absent: 0, which decorates nothing at all
How often one side of one log gets decorated.
Either a percent -- 100 always, 0 never -- or a {numerator, denominator} fraction. Mind the default: a trunk_decoration written without this key rolls 0 and therefore places nothing, so the decoration looks silently ignored rather than sparse.
Sub-keys: the same as trunk.trunk_decoration.decoration_chance — numerator, denominator.
acacia_trunk.trunk_decoration.decoration_blocks_sequence
optional · groupList
A stack of decoration blocks placed outward from the log, in order.
The entries share one running position: the first entry's run starts at the cell next to the log and each later entry continues from where the previous one stopped, rather than restarting. That is what lets a sequence spell "two of block A, then block B". Write this OR decoration_block, not both -- a sequence wins and the single block is ignored.
Sub-keys: the same as trunk.trunk_decoration.decoration_blocks_sequence — block, count.
acacia_trunk.trunk_decoration.decoration_block
optional · block
One block hung on the log, the short form.
Exactly the same as a decoration_blocks_sequence of one entry with a count of 1, and this is the spelling most trees use. Ignored when decoration_blocks_sequence is also present.
acacia_trunk.trunk_decoration.num_steps
optional · integer
With decoration_block, one less than the run length.
A single decoration_block becomes a run of num_steps + 1 blocks, so 4 hangs five vines and the default 0 hangs one. A decoration_blocks_sequence ignores it: there, each entry's own count sets its run.
acacia_trunk.trunk_decoration.step_direction
optional · enum · absent: down
Which way a run of decoration blocks stacks from the log.
Only visible on a run longer than one block: the first block of every entry lands in the same cell whatever this says. Mind the default -- it is down, not outward.
Values, in the order the engine lists them:
down— Each run hangs downward from the log. The default, and what a vine-like decoration wants: the run grows toward the ground one cell at a time.up— Each run climbs upward from the log. The run grows toward the sky one cell at a time, alongside the trunk rather than away from it.out— Each run grows away from the log, horizontally. It follows the same direction that chose the cell -- so a run on the north side keeps going north.away— The same asout, spelled differently. Both spellings are accepted and behave identically; there is no reason to prefer one over the other.
cherry_trunk — 14 keys
cherry_trunk
optional · group
A trunk that forks into one, two, or two branches plus a stem.
The shape is drawn from tree_type_weights, and each resulting tip grows a copy of the tree's own canopy -- the canopy key written next to cherry_trunk, not one inside branches. Leave that key out and the tree is logs only.
cherry_trunk.trunk_height
required · group
The height of the stem, as a base plus optional random steps.
An object of base and intervals, like the acacia and mega trunks, not a range. The base must be at least 2, because a fork needs a stem under it to leave from.
cherry_trunk.trunk_height.base
required · integer · range [2, −]
The fixed part of the stem height, at least 2 blocks.
Anything intervals draws is added on top. Below 2 there is no stem for the branches to fork from.
cherry_trunk.trunk_height.intervals
optional · groupList · absent: no intervals -- the height is exactly `base`, with no draw at all
Extra random height added on top of base, one draw per entry.
Each entry adds a draw between 0 and that entry's own value INCLUDED, one wider than the acacia and mega trunks get from the same list: with base 5 and [2] this trunk is 5 to 7 where theirs is 5 to 6. Leaving the list out makes the height exactly base every time.
cherry_trunk.branches
required · group
The fork: how many branches, how long, and where they leave the stem.
Required -- unlike the acacia and mega trunks, a cherry trunk without this object does not load. branch_horizontal_length, branch_start_offset_from_top and branch_end_offset_from_top are each required inside it.
cherry_trunk.branches.tree_type_weights
optional · group · absent: all three weights 0, which always grows the single-branch shape
The weighted choice between the three fork shapes.
All three weights are required once the object is written, and they are relative rather than percentages. Leaving the whole object out leaves every weight at 0, which always produces the single-branch shape.
cherry_trunk.branches.tree_type_weights.one_branch
required · integer · range [0, −]
Weight of the shape with a single branch off the stem.
One tip, so one canopy. The stem stops where the branch leaves it.
cherry_trunk.branches.tree_type_weights.two_branches
required · integer · range [0, −]
Weight of the shape with two branches on opposite sides.
Two tips and two canopies. The second branch always leaves in the direction opposite the first.
cherry_trunk.branches.tree_type_weights.two_branches_and_trunk
required · integer · range [0, −]
Weight of the shape with two branches and a stem that keeps going.
Three canopies: one at each branch tip and one on top of the stem, which runs the full height.
cherry_trunk.branches.branch_horizontal_length
required · range · range [2, −]
How far out from the stem each branch reaches.
Both ends of the range must be at least 2 -- a branch shorter than that has nowhere to put its bend, and the file is refused rather than silently straightened.
cherry_trunk.branches.branch_start_offset_from_top
required · range · range [−, 0]
How far below the top of the stem a branch leaves it.
Counted downward, so both ends of the range must be 0 or negative; -4 leaves the stem four blocks below its top. The two branches draw this separately and can start at different heights.
cherry_trunk.branches.branch_end_offset_from_top
required · range
How high the branch tip finishes, relative to the top of the stem.
Together with the start offset this is what makes a branch rise or fall along its length, and it is where the canopy for that branch is anchored.
cherry_trunk.branches.branch_canopy
optional · json · absent: nothing changes -- the tips grow the tree-level canopy either way
Accepted, and never grown.
The file loads with a canopy here, but the cherry trunk never places it: every branch tip grows the tree's own canopy key instead. A cherry tree whose only canopy is in this object grows logs and no leaves. Move the canopy next to cherry_trunk.
Free-text field
A whole canopy body: exactly one canopy variant key, from the same set the tree's own canopy offers, and every one of those variants is described elsewhere in this panel. What is missing here is the control, not the knowledge -- a choice of one nested inside another field is not something this editor can draw yet, so it is edited as JSON. Writing two canopy keys here, or none, is reported rather than ignored.
cherry_trunk.trunk_block
required · block
The log the trunk column is built out of.
Required on every trunk shape. Several shapes place sideways logs too -- branches, and a fallen log -- and those are this same block turned to lie along the direction they run in, so there is no second key for them.
fallen_trunk — 11 keys
fallen_trunk
optional · group
A log lying on the ground, with a short stump beside it.
It is the one trunk shape that needs no canopy at all. The log drops to the ground first, then the whole run is checked before anything is written: if any cell is blocked, or three cells in a row have nothing under them, no log is placed -- though the stump is still built.
fallen_trunk.log_length
required · range
How long the fallen log is before modifiers.
The log actually written is log_length plus height_modifier minus 2 blocks long, so a log_length of 5 lays 3 blocks unless height_modifier adds more.
fallen_trunk.height_modifier
optional · range · absent: {0, 0} -- the log is log_length minus 2 blocks long
A second draw added to the fallen log's length.
Drawn separately and added to log_length. Left out it adds nothing and costs no draw.
fallen_trunk.stump_height
optional · range · absent: {1, 1} -- a single stump block
How many blocks of upright stump stand next to the log.
Mind the default: it is a single block, not none. The stump is also what decides success -- a fallen tree whose stump placed nothing counts as failed even when the log itself went down.
fallen_trunk.trunk_block
required · block
The log the trunk column is built out of.
Required on every trunk shape. Several shapes place sideways logs too -- branches, and a fallen log -- and those are this same block turned to lie along the direction they run in, so there is no second key for them.
fallen_trunk.trunk_decoration
optional · group · absent: no decoration -- logs are placed bare
Blocks hung off the sides of the logs, such as vines.
On this shape it is offered on all four sides of each block of the upright stump, and not on the fallen log. Each enabled side rolls decoration_chance independently, and only a side that wins its roll and finds a free cell gets anything. Up and down are never offered, on any trunk shape.
fallen_trunk.trunk_decoration.decoration_chance
optional · chance · absent: 0, which decorates nothing at all
How often one side of one log gets decorated.
Either a percent -- 100 always, 0 never -- or a {numerator, denominator} fraction. Mind the default: a trunk_decoration written without this key rolls 0 and therefore places nothing, so the decoration looks silently ignored rather than sparse.
Sub-keys: the same as trunk.trunk_decoration.decoration_chance — numerator, denominator.
fallen_trunk.trunk_decoration.decoration_blocks_sequence
optional · groupList
A stack of decoration blocks placed outward from the log, in order.
The entries share one running position: the first entry's run starts at the cell next to the log and each later entry continues from where the previous one stopped, rather than restarting. That is what lets a sequence spell "two of block A, then block B". Write this OR decoration_block, not both -- a sequence wins and the single block is ignored.
Sub-keys: the same as trunk.trunk_decoration.decoration_blocks_sequence — block, count.
fallen_trunk.trunk_decoration.decoration_block
optional · block
One block hung on the log, the short form.
Exactly the same as a decoration_blocks_sequence of one entry with a count of 1, and this is the spelling most trees use. Ignored when decoration_blocks_sequence is also present.
fallen_trunk.trunk_decoration.num_steps
optional · integer
With decoration_block, one less than the run length.
A single decoration_block becomes a run of num_steps + 1 blocks, so 4 hangs five vines and the default 0 hangs one. A decoration_blocks_sequence ignores it: there, each entry's own count sets its run.
fallen_trunk.trunk_decoration.step_direction
optional · enum · absent: down
Which way a run of decoration blocks stacks from the log.
Only visible on a run longer than one block: the first block of every entry lands in the same cell whatever this says. Mind the default -- it is down, not outward.
Values, in the order the engine lists them:
down— Each run hangs downward from the log. The default, and what a vine-like decoration wants: the run grows toward the ground one cell at a time.up— Each run climbs upward from the log. The run grows toward the sky one cell at a time, alongside the trunk rather than away from it.out— Each run grows away from the log, horizontally. It follows the same direction that chose the cell -- so a run on the north side keeps going north.away— The same asout, spelled differently. Both spellings are accepted and behave identically; there is no reason to prefer one over the other.
fancy_trunk — 13 keys
fancy_trunk
optional · group
The big branching oak: scattered foliage clusters with limbs drawn out to them.
Not a leaning trunk with a crown on top. It picks foliage positions around the tree, grows a canopy at each, and draws a limb from the trunk out to every one high enough to qualify. All of trunk_height, trunk_width, width_scale, foliage_altitude_factor, branches and trunk_block are required.
fancy_trunk.trunk_height
required · group
The height of the tree, as a base, a variance and a trunk scale.
An object with all three members required. Note that the tree height and the COLUMN height are different numbers here -- see scale.
fancy_trunk.trunk_height.base
required · integer
The fixed part of the overall tree height.
Also the floor under which a blocked trunk is not shortened: a trunk blocked above this height simply comes out shorter, and one blocked below it fails to grow at all.
fancy_trunk.trunk_height.variance
required · integer · range [1, −]
How much the tree height varies from tree to tree.
Must be at least 1. One draw between 0 and this value is added to base for each tree.
fancy_trunk.trunk_height.scale
required · number
The fraction of the tree height the log column actually reaches.
Below 1 the column stops short of the top of the tree, which is normal here and not a defect: foliage routinely sits above the last log. A short height draw can leave the foliage overlapping the trunk, which is also what the game does.
fancy_trunk.trunk_width
required · integer · range [1, −]
How many blocks across the log column is.
A square of this many logs per side, the same as on the acacia and mega trunks.
fancy_trunk.width_scale
required · number
How far out from the trunk the foliage clusters sit.
It scales the radius of the ring of foliage positions, so a larger value spreads the crown wider and makes the limbs reaching out to it longer.
fancy_trunk.foliage_altitude_factor
required · number
How the foliage spread changes with height up the tree.
The crown is shaped along a curved profile rather than a cylinder, and this is what bends it: it decides how wide the ring of foliage positions is at each height.
fancy_trunk.branches
required · group
The limbs drawn from the trunk out to the foliage clusters.
Required on this shape, unlike the acacia and mega trunks where the branches object is optional. All three of slope, density and min_altitude_factor are required inside it.
fancy_trunk.branches.slope
required · number
How steeply a limb climbs as it reaches outward.
It sets where on the trunk a limb starts, so a steeper slope attaches it lower down.
fancy_trunk.branches.density
required · number
How many foliage clusters, and so how many limbs, the tree gets.
Scaled by the height of the tree, so a taller tree with the same density carries more clusters.
fancy_trunk.branches.min_altitude_factor
required · number
How high up a cluster must be before a limb is drawn to it.
Clusters below it still grow their canopy -- they simply float, with no limb connecting them to the trunk. Limbs are also written without checking may_replace, so they overwrite whatever they cross.
fancy_trunk.trunk_block
required · block
The log the trunk column is built out of.
Required on every trunk shape. Several shapes place sideways logs too -- branches, and a fallen log -- and those are this same block turned to lie along the direction they run in, so there is no second key for them.
mangrove_trunk — 17 keys
mangrove_trunk
optional · group
The mangrove trunk: a thin column that sprouts short angled branches.
The shape that pairs with the top-level mangrove_roots key, though the roots run for every trunk shape. Its trunk_height is an object of base plus two random terms, which is unlike every other trunk shape.
mangrove_trunk.trunk_width
optional · integer
Accepted here, but it changes nothing on this shape.
The mangrove column is always one block across whatever this says. It is accepted rather than refused so a pack that already writes it still loads.
mangrove_trunk.trunk_height
required · group
The height, as a fixed base plus two independent random terms.
An object, and all three members are required. Two separate draws are added to base, which piles the result toward the middle instead of spreading it evenly like a range would.
mangrove_trunk.trunk_height.base
required · integer
The fixed part of the mangrove trunk height.
Both random terms are added on top of it, so it is the shortest the column can be.
mangrove_trunk.trunk_height.height_rand_a
required · integer · range [0, −]
The first random term added to the mangrove height.
One draw from 0 up to and including this value. A 0 here contributes nothing.
mangrove_trunk.trunk_height.height_rand_b
required · integer · range [0, −]
The second random term added to the mangrove height.
Drawn separately from the first and added as well, so the two together bunch the height around the middle of their combined span rather than spreading it evenly.
mangrove_trunk.trunk_block
required · block
The log the trunk column is built out of.
Required on every trunk shape. Several shapes place sideways logs too -- branches, and a fallen log -- and those are this same block turned to lie along the direction they run in, so there is no second key for them.
mangrove_trunk.branches
optional · group · absent: branch_length and branch_steps both {0, 0} -- see the note, the branch pass still runs
The short angled branches that come off the mangrove column.
Optional, and leaving it out is not the same as switching branches off: every non-final log flips a coin either way, and on a win a branch is grown using lengths of 0, which places nothing. Writing the object simply gives those draws something to work with.
mangrove_trunk.branches.branch_length
optional · range · absent: {0, 0}
How far a mangrove branch reaches out.
Drawn TWICE per branch, and both draws are used: the difference between them decides where along the branch the logs actually start, so a wide range makes a ragged tree rather than just a longer branch.
mangrove_trunk.branches.branch_steps
optional · range · absent: {0, 0}
How many times a mangrove branch steps upward as it goes out.
Drawn once per branch. It is what tilts the branch up rather than leaving it flat.
mangrove_trunk.branches.branch_chance
optional · chance
Accepted here, but it changes nothing on this shape.
Whether a mangrove branch is grown is decided by a plain coin flip that this key does not feed. A malformed value is still reported, so it has to be written correctly even though nothing reads it.
Sub-keys: the same as trunk.trunk_decoration.decoration_chance — numerator, denominator.
mangrove_trunk.trunk_decoration
optional · group · absent: no decoration -- logs are placed bare
Blocks hung off the sides of the logs, such as vines.
On this shape it is offered on all four sides of every log, the topmost one included, and of every branch log. Each enabled side rolls decoration_chance independently, and only a side that wins its roll and finds a free cell gets anything. Up and down are never offered, on any trunk shape.
mangrove_trunk.trunk_decoration.decoration_chance
optional · chance · absent: 0, which decorates nothing at all
How often one side of one log gets decorated.
Either a percent -- 100 always, 0 never -- or a {numerator, denominator} fraction. Mind the default: a trunk_decoration written without this key rolls 0 and therefore places nothing, so the decoration looks silently ignored rather than sparse.
Sub-keys: the same as trunk.trunk_decoration.decoration_chance — numerator, denominator.
mangrove_trunk.trunk_decoration.decoration_blocks_sequence
optional · groupList
A stack of decoration blocks placed outward from the log, in order.
The entries share one running position: the first entry's run starts at the cell next to the log and each later entry continues from where the previous one stopped, rather than restarting. That is what lets a sequence spell "two of block A, then block B". Write this OR decoration_block, not both -- a sequence wins and the single block is ignored.
Sub-keys: the same as trunk.trunk_decoration.decoration_blocks_sequence — block, count.
mangrove_trunk.trunk_decoration.decoration_block
optional · block
One block hung on the log, the short form.
Exactly the same as a decoration_blocks_sequence of one entry with a count of 1, and this is the spelling most trees use. Ignored when decoration_blocks_sequence is also present.
mangrove_trunk.trunk_decoration.num_steps
optional · integer
With decoration_block, one less than the run length.
A single decoration_block becomes a run of num_steps + 1 blocks, so 4 hangs five vines and the default 0 hangs one. A decoration_blocks_sequence ignores it: there, each entry's own count sets its run.
mangrove_trunk.trunk_decoration.step_direction
optional · enum · absent: down
Which way a run of decoration blocks stacks from the log.
Only visible on a run longer than one block: the first block of every entry lands in the same cell whatever this says. Mind the default -- it is down, not outward.
Values, in the order the engine lists them:
down— Each run hangs downward from the log. The default, and what a vine-like decoration wants: the run grows toward the ground one cell at a time.up— Each run climbs upward from the log. The run grows toward the sky one cell at a time, alongside the trunk rather than away from it.out— Each run grows away from the log, horizontally. It follows the same direction that chose the cell -- so a run on the north side keeps going north.away— The same asout, spelled differently. Both spellings are accepted and behave identically; there is no reason to prefer one over the other.
mega_trunk — 20 keys
mega_trunk
optional · group
The wide trunk of a giant tree, with long sweeping branches.
trunk_width is required and is usually 2 or more, which is what makes it "mega". It is the only trunk shape that builds the tree's top-level base_cluster -- written next to any other shape, that key is read and then never used.
mega_trunk.trunk_height
required · group
The height of the column, as a base plus optional random steps.
An object of base and intervals, the same shape the acacia and cherry trunks use, not a range.
mega_trunk.trunk_height.base
required · integer
The fixed part of the mega trunk height.
Everything intervals draws is added on top of this. Giant trees need a tall preview volume to fit.
mega_trunk.trunk_height.intervals
optional · groupList · absent: no intervals -- the height is exactly `base`, with no draw at all
Extra random height added on top of base, one draw per entry.
Each entry adds a draw between 0 and that entry's own value, so [3, 3] adds nought to four and [5] adds nought to four in one lumpier step. Leaving the list out makes the height exactly base every time, with no variation at all.
mega_trunk.trunk_width
required · integer · range [1, −]
How many blocks across the wide column is.
A square of this many logs per side. It also decides which logs are on an edge, and only edge logs carry a decoration -- and the topmost layer never does, whatever its width.
mega_trunk.trunk_block
required · block
The log the trunk column is built out of.
Required on every trunk shape. Several shapes place sideways logs too -- branches, and a fallen log -- and those are this same block turned to lie along the direction they run in, so there is no second key for them.
mega_trunk.branches
optional · group · absent: no branches at all -- the trunk is a bare column
The long branches that sweep out from the column.
Optional, and here absence really does mean no branches at all. The branches are built BEFORE the column, so a log of the trunk placed afterwards can overwrite a branch log that crossed it. branch_length, branch_slope, branch_interval and branch_altitude_factor are all required once the object is present.
mega_trunk.branches.branch_length
required · integer
How many logs long each branch is.
A plain whole number, not a range, so every branch on the tree is the same length. The logs are written without checking may_replace, so a branch goes straight through whatever is there.
mega_trunk.branches.branch_slope
required · number
How steeply each branch climbs as it reaches out.
Applied per log, so it also decides how far below the branch's anchor height the branch starts.
mega_trunk.branches.branch_interval
required · range
The vertical gap between one branch and the next.
Drawn fresh for each gap, so the branches are unevenly spaced up the trunk. Branches keep being added downward until the next gap would take them below where branches are allowed.
mega_trunk.branches.branch_altitude_factor
required · group
The band of the trunk, top and bottom, that carries branches.
Both members are fractions of the tree height: max is where the topmost branch may sit and min is the lowest. This object is the one place in a trunk body that really is spelled min and max -- everywhere else those two names are the wrong spelling of a range.
A plain two-member object, NOT a range: this one really is spelled min and max.
mega_trunk.branches.branch_altitude_factor.min
required · number
The lowest point on the trunk that may carry a branch.
A fraction of the tree height, so 0.4 means branches stop about two fifths of the way up.
mega_trunk.branches.branch_altitude_factor.max
required · number
The highest point on the trunk that may carry a branch.
A fraction of the tree height, and where the first branch is placed before the gaps walk downward.
mega_trunk.branches.branch_canopy
optional · json · absent: no canopy is grown at the branch tips
A canopy grown at the tip of each branch this trunk makes.
Separate from the tree's own canopy key and shaped independently of it -- the branch tips always ask for a canopy one block wide, whatever trunk_width says. Write exactly one canopy variant key inside it; none and two are both reported.
Free-text field
A whole canopy body: exactly one canopy variant key, from the same set the tree's own canopy offers, and every one of those variants is described elsewhere in this panel. What is missing here is the control, not the knowledge -- a choice of one nested inside another field is not something this editor can draw yet, so it is edited as JSON. Writing two canopy keys here, or none, is reported rather than ignored.
mega_trunk.trunk_decoration
optional · group · absent: no decoration -- logs are placed bare
Blocks hung off the sides of the logs, such as vines.
On this shape it is offered on the outward sides of every edge log below the top layer -- the topmost layer of logs is never decorated. Each enabled side rolls decoration_chance independently, and only a side that wins its roll and finds a free cell gets anything. Up and down are never offered, on any trunk shape.
mega_trunk.trunk_decoration.decoration_chance
optional · chance · absent: 0, which decorates nothing at all
How often one side of one log gets decorated.
Either a percent -- 100 always, 0 never -- or a {numerator, denominator} fraction. Mind the default: a trunk_decoration written without this key rolls 0 and therefore places nothing, so the decoration looks silently ignored rather than sparse.
Sub-keys: the same as trunk.trunk_decoration.decoration_chance — numerator, denominator.
mega_trunk.trunk_decoration.decoration_blocks_sequence
optional · groupList
A stack of decoration blocks placed outward from the log, in order.
The entries share one running position: the first entry's run starts at the cell next to the log and each later entry continues from where the previous one stopped, rather than restarting. That is what lets a sequence spell "two of block A, then block B". Write this OR decoration_block, not both -- a sequence wins and the single block is ignored.
Sub-keys: the same as trunk.trunk_decoration.decoration_blocks_sequence — block, count.
mega_trunk.trunk_decoration.decoration_block
optional · block
One block hung on the log, the short form.
Exactly the same as a decoration_blocks_sequence of one entry with a count of 1, and this is the spelling most trees use. Ignored when decoration_blocks_sequence is also present.
mega_trunk.trunk_decoration.num_steps
optional · integer
With decoration_block, one less than the run length.
A single decoration_block becomes a run of num_steps + 1 blocks, so 4 hangs five vines and the default 0 hangs one. A decoration_blocks_sequence ignores it: there, each entry's own count sets its run.
mega_trunk.trunk_decoration.step_direction
optional · enum · absent: down
Which way a run of decoration blocks stacks from the log.
Only visible on a run longer than one block: the first block of every entry lands in the same cell whatever this says. Mind the default -- it is down, not outward.
Values, in the order the engine lists them:
down— Each run hangs downward from the log. The default, and what a vine-like decoration wants: the run grows toward the ground one cell at a time.up— Each run climbs upward from the log. The run grows toward the sky one cell at a time, alongside the trunk rather than away from it.out— Each run grows away from the log, horizontally. It follows the same direction that chose the cell -- so a run on the north side keeps going north.away— The same asout, spelled differently. Both spellings are accepted and behave identically; there is no reason to prefer one over the other.
poplar_trunk — 11 keys
poplar_trunk
optional · group · 1.26.50.24
A tall narrow column with a small ring of branches near the top.
Added in game version 1.26.50. The branches are short stubs that support the crown rather than limbs of their own, and the canopy is anchored just above them rather than on top of the column.
poplar_trunk.trunk_height
required · range
How many logs tall the poplar column is.
A range, like the plain trunk and unlike the acacia, mega, cherry, fancy and mangrove trunks, all of which want an object here. Required, even though the shape has a height of its own it would otherwise fall back on.
poplar_trunk.remaining_trunk_height_above_branches
optional · range · absent: {4, 4} -- four blocks of bare trunk above the branch ring, with no draw
How much bare trunk is left standing above the branch ring.
Measured down from the top, so a larger value pushes the branches and the canopy lower without making the tree shorter. The default of four blocks is a fixed number and costs no draw.
poplar_trunk.amount_of_foliage_support_branches
optional · range · absent: {1, 4} -- one to four branches
How many short branches ring the trunk under the crown.
The directions are shuffled first, so a count of 2 picks two different sides at random. There are only four sides, so anything above 4 behaves exactly like 4.
poplar_trunk.trunk_block
required · block
The log the trunk column is built out of.
Required on every trunk shape. Several shapes place sideways logs too -- branches, and a fallen log -- and those are this same block turned to lie along the direction they run in, so there is no second key for them.
poplar_trunk.trunk_decoration
optional · group · absent: no decoration -- logs are placed bare
Blocks hung off the sides of the logs, such as vines.
On this shape it is offered on all four sides of every log of the column and of every branch stub. Each enabled side rolls decoration_chance independently, and only a side that wins its roll and finds a free cell gets anything. Up and down are never offered, on any trunk shape.
poplar_trunk.trunk_decoration.decoration_chance
optional · chance · absent: 0, which decorates nothing at all
How often one side of one log gets decorated.
Either a percent -- 100 always, 0 never -- or a {numerator, denominator} fraction. Mind the default: a trunk_decoration written without this key rolls 0 and therefore places nothing, so the decoration looks silently ignored rather than sparse.
Sub-keys: the same as trunk.trunk_decoration.decoration_chance — numerator, denominator.
poplar_trunk.trunk_decoration.decoration_blocks_sequence
optional · groupList
A stack of decoration blocks placed outward from the log, in order.
The entries share one running position: the first entry's run starts at the cell next to the log and each later entry continues from where the previous one stopped, rather than restarting. That is what lets a sequence spell "two of block A, then block B". Write this OR decoration_block, not both -- a sequence wins and the single block is ignored.
Sub-keys: the same as trunk.trunk_decoration.decoration_blocks_sequence — block, count.
poplar_trunk.trunk_decoration.decoration_block
optional · block
One block hung on the log, the short form.
Exactly the same as a decoration_blocks_sequence of one entry with a count of 1, and this is the spelling most trees use. Ignored when decoration_blocks_sequence is also present.
poplar_trunk.trunk_decoration.num_steps
optional · integer
With decoration_block, one less than the run length.
A single decoration_block becomes a run of num_steps + 1 blocks, so 4 hangs five vines and the default 0 hangs one. A decoration_blocks_sequence ignores it: there, each entry's own count sets its run.
poplar_trunk.trunk_decoration.step_direction
optional · enum · absent: down
Which way a run of decoration blocks stacks from the log.
Only visible on a run longer than one block: the first block of every entry lands in the same cell whatever this says. Mind the default -- it is down, not outward.
Values, in the order the engine lists them:
down— Each run hangs downward from the log. The default, and what a vine-like decoration wants: the run grows toward the ground one cell at a time.up— Each run climbs upward from the log. The run grows toward the sky one cell at a time, alongside the trunk rather than away from it.out— Each run grows away from the log, horizontally. It follows the same direction that chose the cell -- so a run on the north side keeps going north.away— The same asout, spelled differently. Both spellings are accepted and behave identically; there is no reason to prefer one over the other.
canopy — 15 keys
canopy
optional · group
The generic canopy: a stack of filled squares over the trunk, widest at the bottom.
The bare word is a real shape with its own key set, not a default that turns into one of the others. Each layer's half-width is min_width plus the drop from the top layer's slope to this one's, so with the defaults (min_width 1, rise 2, run 1) and canopy_offset {min: -3, max: 0} the radii run 2, 2, 1, 1 from the bottom up -- the familiar 5-wide oak crown.
canopy.leaf_block
required · block
The block every layer of the crown is built from.
One block for the whole shape; this canopy has no second block and no weighting.
canopy.canopy_offset
required · group
Which heights the layers occupy, measured from the top of the trunk.
Mind the spelling: this is a plain object with members named min and max, NOT a range, so range_min and range_max do not work here and neither does the two-element array form. A negative min puts layers BELOW the point the trunk handed over.
canopy.canopy_offset.min
required · integer
The lowest layer, as an offset from the trunk top.
Usually negative, because the crown normally starts below the trunk top and builds upward.
canopy.canopy_offset.max
required · integer
The highest layer, as an offset from the trunk top.
Also the layer the whole taper is measured from: every other layer's width is worked out as its distance below this one, so moving max changes the width of every layer at once, not just the top.
canopy.min_width
optional · integer · absent: 1
A half-width added to every layer, including the topmost.
It widens the crown uniformly rather than changing its taper; canopy_slope is what changes the taper. Absent means 1, so write 0 for a crown that narrows to a single block. Must be 0 or more.
canopy.canopy_slope
optional · group · absent: rise 2, run 1 -- one step of radius every other layer
How fast the layers widen going down: run steps of width for every rise layers.
The names read backwards: run is the one multiplied by the layer's distance and rise is the one divided by, so each layer below the top is run / rise wider (rounded toward zero). {rise: 1, run: 2} adds two blocks of half-width per layer -- a wide, flat stepped pyramid -- while {rise: 2, run: 1} adds one every other layer. {rise: 2, run: 1} is also what you get with the key absent, and each member left out keeps its own default. Both must be at least 1; the game refuses the file otherwise.
canopy.canopy_slope.rise
optional · integer · absent: 2
The divisor of the taper: how many layers one step of width is spread over.
Raising it makes a narrower, more column-like crown. Must be at least 1.
canopy.canopy_slope.run
optional · integer · absent: 1
The multiplier of the taper: how much half-width each step adds.
Raising it makes a wider, flatter crown. Must be at least 1.
canopy.variation_chance
optional · json · absent: none -- and the game crashes when it places a canopy without it, so always write it
Chance to leave out each of the four corners of a layer, which is what rounds the square off.
Four cells per layer -- where the horizontal and vertical distances from the centre both equal that layer's half-width -- are each rolled once. This is the only part of this canopy that draws random numbers at all. There is no guard for a one-cell layer: on a layer of half-width 0 that single centre cell IS all four corners, so a chance that always succeeds deletes the layer outright -- which is how a crown gets capped flat instead of ending in one leaf poking out of the top. Always write it, with one entry per layer (canopy_offset.max - canopy_offset.min + 1): the key is optional in the schema, but the game reads one entry for every layer it places and never checks the length. Without the key the game crashes when it places the canopy; with fewer entries than layers (a single chance is one entry) it reads past the end for the rest -- random results or a crash. A chance of 0 keeps that layer's corners and draws nothing.
Free-text field
This key accepts three spellings and a single control cannot offer all three: a percent number, a {numerator, denominator} object, or an array of either with one entry per canopy layer, ordered from canopy_offset.min upward. A single chance counts as ONE entry, not one for every layer. Write it as JSON.
canopy.canopy_decoration
optional · group · absent: nothing hangs off the canopy, and no random number is drawn for it
Hangs a block off the sides of the crown -- vines, typically.
Once every layer is built, each leaf in the crown rolls once per horizontal neighbour; a success on a neighbour that is air writes a run of cells straight down from it, stopping at the first cell that is not air. Note that this object is NOT the same shape as the object of the same name on mangrove_canopy.
canopy.canopy_decoration.decoration_block
required · block
The block written down the side of the crown.
The whole run is this one block; there is no sequence form here.
canopy.canopy_decoration.decoration_chance
required · chance
Chance that any one horizontal neighbour of a leaf starts a run.
Rolled per leaf per neighbour, so a dense crown spends a great many rolls.
canopy.canopy_decoration.num_steps
required · range
One less than how many cells long a run is.
A run is num_steps + 1 cells: 4 hangs a five-block vine, 0 a single block. It stops early at the first cell that is not air, so a long run is not guaranteed.
canopy.canopy_decoration.step_direction
required · enum
Which way the run grows. Only downward is accepted here.
That is the direction vanilla's own definitions use and the only one whose behaviour has been established for this object, so any other spelling is refused rather than guessed at.
Values, in the order the engine lists them:
down— Grows the run straight down from the leaf it started at. The only value accepted for this object, and the one vanilla's own hanging vines use.
acacia_canopy — 4 keys
acacia_canopy
optional · group
The flat, spreading acacia crown: one wide octagonal ring with a smaller layer on top.
Entirely fixed -- this shape draws no random numbers at all, so two acacias with the same settings get identical crowns.
acacia_canopy.leaf_block
required · block
The block both layers of the crown are built from.
One block for the whole crown -- this shape takes no second block and no weighted list, so the two layers always match.
acacia_canopy.canopy_size
required · integer
The half-width of the lower ring.
The lower layer is a square of this half-width minus its four exact corners. That corner cut has no guard for a size of 0: at 0 the single centre cell is itself a corner, so the lower layer comes out completely empty and only the upper layer is placed.
acacia_canopy.simplify_canopy
optional · boolean · absent: false
Replaces the upper layer's four protruding arms with a plain square.
With it off, the upper layer is a narrower square with four single cells poking out along the axes. With it on, it is one filled square and nothing sticks out -- a cleaner, slightly smaller silhouette.
cherry_canopy — 9 keys
cherry_canopy
optional · group
The cherry crown: a rounded block of leaves with a fringe hanging below it.
Built as a stack of square layers that widen toward the bottom, then two more layers below the anchor that also trail leaves downward. Under a cherry trunk, written next to cherry_trunk, it is grown once at each branch tip rather than once for the whole tree.
cherry_canopy.leaf_block
required · block
The block the crown and its hanging fringe are built from.
The fringe is the same block as the body; there is no separate hanging block on this shape.
cherry_canopy.height
required · range · range [4, −]
How tall the crown is, drawn per crown. At least 4.
A range, so it wants range_min and range_max. The bottom four layers are fixed in shape and the remainder stack above them at full width, so raising this makes the crown taller without making it wider. Values below 4 leave the shape with no layers to build and are refused.
cherry_canopy.radius
required · range · range [3, −]
How wide the crown is, drawn per crown. At least 3.
A range, so it wants range_min and range_max. The widest layers sit at this half-width; the top two step in by one and two cells. Values below 3 make the topmost layer inside-out and are refused.
cherry_canopy.trunk_width
optional · integer · absent: 1 · range [1, 1]
The trunk footprint the crown is built around. Must be 1.
Every trunk that can carry this crown hands it a one-block footprint, so any other value is refused rather than silently building a crown around a trunk that is not there.
cherry_canopy.wide_bottom_layer_hole_chance
required · chance
Chance to punch a hole in the outer edge of the widest bottom layer.
Rolled per edge cell of that one layer. It is what stops the underside reading as a solid slab.
cherry_canopy.corner_hole_chance
required · chance
Chance to leave out a corner cell of a layer.
Which cells count as corners changes with the layer's width: a narrow layer rolls its four square corners, a wide one has its corners cut outright and instead rolls a ring just inside the edge.
cherry_canopy.hanging_leaves_chance
required · chance
Chance to trail a leaf one cell below the crown's bottom edge.
Rolled along the four straight edges of the two lowest layers -- the fringe that gives a cherry its drooping look.
cherry_canopy.hanging_leaves_extension_chance
required · chance
Chance to extend a trailing leaf by a second cell.
Rolled only where the first leaf was actually placed, so this is a chance on a chance and a small value thins the fringe quickly.
fancy_canopy — 4 keys
fancy_canopy
optional · group
A stack of round discs, full width in the middle and pulled in at the top and bottom.
Each layer is a disc rather than a square, which is what makes this the roundest of the twelve. It draws no random numbers, so its shape is entirely fixed by its two numbers.
fancy_canopy.leaf_block
required · block
The block every disc is built from.
One block for the whole crown -- this shape takes no second block and no weighted list, so the discs come out a single solid colour.
fancy_canopy.height
required · integer · range [0, −]
How many discs are stacked.
A height of 0 is legal and places nothing at all. A height of 1 gives a single pulled-in disc, since that one layer is both the top cap and the bottom.
fancy_canopy.radius
required · integer · absent: the game treats this key as optional, but what it falls back to has not been established, so a value is asked for here rather than guessed · range [1, −]
The half-width of the middle discs.
The top and bottom discs are one cell narrower than this. A radius below 1 would make those caps inside-out, so it is refused.
mangrove_canopy — 15 keys
mangrove_canopy
optional · group
A scattered crown of leaves with blocks hanging beneath it.
Unlike the layered shapes, this scatters individual leaves around EVERY log the trunk placed, not just the top one. Pair it with a trunk that collects its logs -- with the plain trunk or the cherry trunk it is handed an empty list, places nothing and draws nothing, leaving a bare pole.
mangrove_canopy.canopy_height
required · range
How far up and down a scattered leaf may land, drawn once for the whole crown.
A range, so it wants range_min and range_max, and its maximum is included. One value is drawn per tree and then reused for every attempt.
mangrove_canopy.canopy_radius
required · range
How far sideways a scattered leaf may land, drawn once for the whole crown.
A range, so it wants range_min and range_max, and its maximum is included. Like the height, drawn once and shared by every attempt.
mangrove_canopy.leaf_placement_attempts
required · integer · range [0, −]
How many leaves are attempted around each trunk log.
Multiplied by the number of logs the trunk collected, so this number and the trunk height together decide how dense the crown is. An attempt that lands somewhere it may not build is simply lost.
mangrove_canopy.leaf_blocks
required · weightedBlockList
The blocks the scattered leaves are picked from, with weights.
Write each entry as a two-element pair: the block first, then its weight. The list may not be empty. One pick is made per leaf, so the weights decide the mix within a single crown rather than between trees.
mangrove_canopy.hanging_block
required · block
The block hung beneath the crown -- propagules, in vanilla.
Placed in a separate pass after every leaf is down, so it hangs from the finished shape rather than from a partial one.
mangrove_canopy.hanging_block_placement_chance
required · chance
Chance that any one candidate position below the crown gets a hanging block.
This is the only gate on that pass: at zero the crown is leaves alone, and the hanging block never appears.
mangrove_canopy.canopy_decoration
optional · group · absent: nothing is attached to the scattered leaves, and no random number is drawn for it
Attaches a block to the sides of the hanging positions.
Runs before the hanging blocks themselves, once per candidate, with all four horizontal sides eligible. Note that this object is a DIFFERENT shape from the object of the same name on the generic canopy: it takes a block sequence and a four-way step direction, where that one takes a single block and only accepts downward.
mangrove_canopy.canopy_decoration.decoration_block
optional · block · absent: no block, unless decoration_blocks_sequence supplies one
A single block to attach.
An alternative to decoration_blocks_sequence, not an addition to it -- when the sequence is present this is not read.
mangrove_canopy.canopy_decoration.decoration_blocks_sequence
optional · groupList · absent: the single decoration_block is used instead
An ordered list of block runs to attach, one after another from the same starting cell.
Each run stops early the moment its next cell is not air, so a later run can be cut short by what an earlier one built.
mangrove_canopy.canopy_decoration.decoration_blocks_sequence.block
required · block
The block this run is made of.
Required on every entry; an entry without one has nothing to place.
mangrove_canopy.canopy_decoration.decoration_blocks_sequence.count
optional · range · absent: one block
How many cells long this run is, drawn per run.
A range, so it wants range_min and range_max. Leaving it out gives a run of exactly one block.
mangrove_canopy.canopy_decoration.decoration_chance
required · chance
Chance that any one eligible side is decorated.
Rolled per side per candidate position. At zero nothing is attached and the whole object has no effect.
mangrove_canopy.canopy_decoration.num_steps
optional · integer · absent: 0 -- decoration_block hangs one block
With decoration_block, one less than the run length.
A single decoration_block becomes a run of num_steps + 1 blocks (the default 0 gives one). A decoration_blocks_sequence ignores it: there, each entry's own count sets its run.
mangrove_canopy.canopy_decoration.step_direction
optional · enum · absent: down
Which way a run of more than one block grows.
Only runs longer than one cell can tell the difference, so on a single-block decoration this changes nothing.
Values, in the order the engine lists them:
down— Grows each run downward from its starting cell. The default, and what a hanging decoration wants.up— Grows each run upward from its starting cell. The mirror of down; a run still stops at the first cell that is not air.out— Grows each run outward, away from the block it is attached to. The run reaches sideways into open space rather than along the crown.away— The same as out -- a second spelling of the outward direction. Written either way it behaves identically, so pick whichever reads better in your file.
mega_canopy — 6 keys
mega_canopy
optional · group
A broad cone for a wide trunk, flaring outward toward the bottom.
Each layer is one cell wider than the one above it, so the crown reads as a solid downward-flaring cone rather than a ball.
mega_canopy.leaf_block
required · block
The block every layer of the cone is built from.
One block for the whole cone. Unlike the two scattering canopies there is no weighted list here, so a mega crown cannot be mixed from several leaf types.
mega_canopy.canopy_height
required · range
How many layers the cone has, drawn per tree.
A range, so it wants range_min and range_max. A drawn value of 0 places nothing. This is the shape's only random draw.
mega_canopy.base_radius
optional · integer · absent: 2 · range [0, −]
The half-width of the narrowest layer, at the very top.
Every layer below widens by one from here, so this sets the whole cone's width, not just the tip's.
mega_canopy.core_width
required · integer
The width of the trunk this crown is built around. Must match it.
Not a free setting: the feature is refused when it disagrees with the trunk's own width. At a branch tip the trunk is always one block wide, so a crown grown there needs 1.
mega_canopy.simplify_canopy
optional · boolean · absent: false
Uses a strict circle for each layer instead of a relaxed one.
With it off -- the default -- the corners of each layer are allowed through and the crown is fuller. With it on, every cell must fall inside the circle, which visibly shrinks each layer.
mega_pine_canopy — 6 keys
mega_pine_canopy
optional · group
A tall conical crown for a wide trunk, widening in steps rather than one cell per layer.
The same cone idea as mega_canopy but with the rate of widening under its own control, which is what makes it read as a pine rather than a jungle crown.
mega_pine_canopy.leaf_block
required · block
The block every layer of the cone is built from.
One block for the whole cone, tiers included -- the widening is a change of shape, never a change of block.
mega_pine_canopy.canopy_height
required · range
How many layers the cone has, drawn per tree.
A range, so it wants range_min and range_max. This is the shape's only random draw.
mega_pine_canopy.base_radius
optional · integer · absent: 2 · range [0, −]
The half-width of the topmost layer.
Every layer below is this plus whatever radius_step_modifier has added by then.
mega_pine_canopy.radius_step_modifier
optional · number · absent: 3.5
How fast the cone widens going down. Larger means a wider, blunter cone.
It scales the distance below the top before that distance is rounded down to whole cells, so a value below 1 makes several layers share a width and gives the crown visible tiers rather than a smooth flare.
mega_pine_canopy.core_width
required · integer
The width of the trunk this crown is built around. Must match it.
The feature is refused when it disagrees with the trunk's own width.
pine_canopy — 4 keys
pine_canopy
optional · group
The narrow conical pine crown: diamond rings that shrink going up.
One random draw jitters how far up the widest part sits, so two pines with identical settings still differ.
pine_canopy.leaf_block
required · block
The block every ring of the cone is built from.
One block for the whole crown; this shape takes no second block, so the rings differ from each other only in width.
pine_canopy.canopy_height
required · range
How tall the cone is, drawn per tree.
A range, so it wants range_min and range_max. It also sets the size of the second draw that jitters the cone vertically, so a taller cone is also a more variable one.
pine_canopy.base_radius
required · integer
The half-width the cone is allowed to reach at its widest.
Where along the cone that width lands is what the jitter draw decides.
poplar_canopy — 9 keys
poplar_canopy
optional · group · game build 1.26.50.24 -- whether the schema gates this key on format_version was NOT established, so it is offered at every version rather than hidden below one
A tall rounded crown of stacked diamonds with a cross of logs buried inside it.
One coin flip per tree bulges a diagonal pair of quadrants outward by a cell, which is what gives a poplar its slightly lopsided silhouette. The top two layers have their outermost row and column trimmed so the crown rounds off instead of ending in a slab.
poplar_canopy.leaf_block
required · block
The block the diamond layers are built from.
The buried cross is branch_block instead; everything else is this.
poplar_canopy.branch_block
required · block
The log used for the cross buried inside the crown.
Placed four cells below the crown's top layer, reaching out along both horizontal axes with each arm's log turned to follow it. On a small crown the cross has no room and this block is never placed at all.
poplar_canopy.radius
required · groupList
The crown widths to choose between, with weights.
One entry is picked per tree in proportion to its weight, and the crown it builds is one cell narrower than the entry says -- a value of 3 gives half-width-2 layers. Below a value of 5 the buried cross disappears entirely.
poplar_canopy.radius.value
required · integer
One candidate width. The crown built is one cell narrower than this.
That offset by one is easy to lose: writing 5 here is what a crown of half-width 4 needs.
poplar_canopy.radius.weight
optional · integer · absent: 1
How often this width is picked, relative to the other entries.
Weights are relative, not percentages, so doubling every entry changes nothing.
poplar_canopy.height
required · range
How tall the crown is, drawn per tree.
A range, so it wants range_min and range_max. Unlike most ranges in this feature it includes its maximum.
poplar_canopy.side_hole_chance
optional · number · absent: 0 -- no cell is pitted, though the roll is still spent on every cell
Chance to pull any one surface cell in by a block, pitting the crown.
Mind the default, which is 0: no cell is ever pitted, and the crown comes out smooth. Worth knowing either way is that the roll happens for every candidate cell whether or not this key is written, so raising it changes the crown's look without changing how many random numbers the tree spends.
poplar_canopy.trunk_width
optional · integer · absent: 1
Checked against the trunk's own width. It does not change the crown's shape.
Every trunk that can carry a poplar crown hands it a one-block footprint, so the geometry is the same whatever is written here. Listed so that finding it in an existing file is not mistaken for a width setting that stopped working.
roofed_canopy — 6 keys
roofed_canopy
optional · group
The thick flat-topped crown of a dark forest: a solid floor, a hipped roof above it, and a peak.
The floor below the anchor is a full solid square; the roof at the top is that same square with its corners chamfered off. One coin flip decides whether a single cell is placed on top as a peak, and that flip is spent on every tree whatever the other settings say.
roofed_canopy.leaf_block
required · block
The block the floor, the filling and the roof are all built from.
One block for all three parts -- there is no way to give the roof a different block from the floor on this shape.
roofed_canopy.canopy_height
required · integer · range [3, −]
Three more than the number of leaf layers between the floor and the roof.
The game subtracts 3 before using it: vanilla's dark oak writes 4, which is ONE layer of filling, with the roof one block above the anchor. At least 3. A height of 3 is legal and is not the same as placing nothing: the floor, the roof and the coin-flipped peak are all still placed, and only the filling between them is skipped.
roofed_canopy.core_width
required · integer
The width of the trunk this crown is built around. Must match it.
The feature is refused when it disagrees with the trunk's own width.
roofed_canopy.outer_radius
required · integer · absent: the game treats this key as optional, but what it falls back to has not been established, so a value is asked for here rather than guessed · range [-1, −]
The half-width of the floor and the roof.
A value of -1 is legal and means exactly one thing: skip the floor and the roof entirely. The coin flip and its peak still happen. Anything below -1 is refused.
roofed_canopy.inner_radius
required · integer · absent: the game treats this key as optional, but what it falls back to has not been established, so a value is asked for here rather than guessed · range [0, −]
The half-width of the solid block of leaves stacked between the floor and the roof.
Filled, not hollow, with its four corners cut. Set it below the outer radius and the floor and roof overhang it like a brim; set it to 0 and the two slabs are joined by a single column.
spruce_canopy — 5 keys
spruce_canopy
optional · group
The layered spruce crown: bands that grow wide, snap back to nothing and grow again.
That grow-and-reset is the whole shape -- it is what gives a spruce its alternating full and skinny bands instead of the single smooth taper every other conical shape here has.
spruce_canopy.leaf_block
required · block
The block every band of the crown is built from.
One block for the whole crown; the alternating bands are a change of width, not of block, so they read as one material throughout.
spruce_canopy.lower_offset
required · range
How far above the ground the crown stops, drawn per tree.
A range, so it wants range_min and range_max. The canopy looks straight down from the trunk top for the first block in may_grow_on -- the ground the trunk stands on -- and its lowest layer sits this many cells above that, so that many logs at the foot of the trunk stay bare. Together with the upper offset it sets how many bands there is room for.
spruce_canopy.upper_offset
required · range · absent: the game treats this key as optional, but what it falls back to has not been established, so a value is asked for here rather than guessed
How far above the trunk top the crown starts, drawn per tree.
A range, so it wants range_min and range_max. The crown is built downward from here.
spruce_canopy.max_radius
required · range
The widest a band may get before it snaps back, drawn per tree.
It is doing two jobs at once: the drawn value caps each band, and the SPAN between the two ends of the range decides how wide the first band is allowed to get before the first reset. So widening the range changes the banding pattern, not just the maximum width.
random_spread_canopy — 5 keys
random_spread_canopy
optional · group
Leaves scattered at random around the trunk rather than arranged in layers.
Like mangrove_canopy it works from every log the trunk placed, not just the top one. Paired with the plain trunk or the cherry trunk it is handed an empty list, places nothing and draws nothing, leaving a bare pole -- pair it with the acacia, mega or mangrove trunk instead.
random_spread_canopy.canopy_height
required · range
How far up and down a scattered leaf may land, drawn once for the whole crown.
A range, so it wants range_min and range_max, and its maximum is included. Drawn once per tree and then reused for every attempt.
random_spread_canopy.canopy_radius
required · range
How far sideways a scattered leaf may land, drawn once for the whole crown.
A range, so it wants range_min and range_max, and its maximum is included. Drawn once per tree, like the height.
random_spread_canopy.leaf_placement_attempts
required · integer · range [0, −]
How many leaves are attempted around each trunk log.
Multiplied by the number of logs the trunk collected, so a tall trunk makes a much denser crown for the same number here. An attempt that lands somewhere it may not build is lost rather than retried.
random_spread_canopy.leaf_blocks
required · weightedBlockList
The blocks the scattered leaves are picked from, with weights.
Write each entry as a two-element pair: the block first, then its weight. The list may not be empty. A fresh pick is made for every leaf, so a mixed list gives one tree a mixed crown.
base_block
optional · blockList · a single descriptor is accepted as a one-element list
The block the ground under the trunk is turned into, where it does not already match.
A finishing touch: it overwrites whatever the ground turned out to be rather than deciding where the tree may grow -- that is may_grow_on. The first entry is what gets written. The acacia and mega trunks convert their whole trunk_width footprint, the fancy and mangrove trunks never do it, and base_cluster lays this same block.
A single descriptor or a list; both are accepted.
may_grow_on
optional · blockList
Blocks the tree is willing to root on.
Tested at the ground under the trunk. If the ground does not pass, the tree is not placed at all; what the ground is turned into afterwards is base_block's business.
may_grow_through
optional · blockList
Blocks the trunk may push through on its way up.
Applies BELOW the tree's own origin. At and above the origin the trunk is governed by may_replace instead, which is the distinction that catches people out when a trunk stops short in undergrowth.
may_replace
optional · blockList
Blocks the tree may overwrite at and above its origin.
Below the origin it is may_grow_through that decides instead. A trunk log also goes into air, leaves, water or a vine whatever this list says, so a trunk grows through its own trunk_decoration vines. The canopy and spruce_canopy crowns do not read it: they write into air, leaves and vines only.
base_cluster — 4 keys
base_cluster
optional · group · absent: no ground patch is laid
Patches of base_block laid around a wide trunk -- the podzol around a giant spruce.
Only the wide-trunk shape reads it; on any other trunk it is accepted and does nothing. What it lays is the tree's own base_block (its first entry), and without a base_block it lays nothing. The whole object is optional, but all three of its keys are required once it is there -- half of it is refused, not defaulted.
base_cluster.may_replace
required · blockList
The blocks a patch may overwrite.
Each patch cell is searched from two blocks above the ground down to three below, and the first block on this list takes the patch block. An empty list passes every block, so the patch lands in the air two blocks up.
base_cluster.num_clusters
required · integer
How many patches to lay.
A whole number, not a range -- unlike most sizes on this type. Writing {range_min, range_max} here is refused rather than read as a range. Nothing enforces a minimum: 0 or less loads clean and lays no patch at all.
base_cluster.cluster_radius
required · integer
How far a patch reaches from its own centre.
A whole number, not a range, for the same reason as the count beside it. Nothing enforces a minimum here either: at 0 or less every patch comes out empty, so no ground is replaced.
mangrove_roots — 12 keys
mangrove_roots
optional · group · absent: the tree stands on no roots
The stilt roots a mangrove stands on.
Leaving it out means no roots at all, not roots of some default shape.
mangrove_roots.max_root_width
required · integer
How far the roots may spread from the trunk.
Nothing enforces a minimum: 0 or less loads clean and behaves the same either way -- the roots never step sideways, they only drop straight down under the trunk.
mangrove_roots.max_root_length
required · integer
How long one root may grow before it stops.
Nothing enforces a minimum, but 0 or less is fatal rather than inert: the root pass fails on the first direction and the whole tree is abandoned -- no roots, no trunk, no canopy.
mangrove_roots.y_offset
required · range
How far above or below the trunk base the roots start.
Drawn once per tree, so two trees from the same settings can start their roots at different heights.
mangrove_roots.root_block
required · block
The block a root is built from in open air.
mangrove_roots.muddy_root_block
required · block
The block a root is built from where it passes through mud.
mangrove_roots.mud_block
required · block
The block laid as mud around the roots.
mangrove_roots.roots_may_grow_through
required · blockList
The blocks a root may pass through.
A root that meets a block not listed here stops there; the rest of the roots carry on.
mangrove_roots.above_root
optional · group · absent: nothing is placed on top of a root
An optional block placed on top of a finished root.
Both of its keys are optional; with neither set, nothing is placed.
mangrove_roots.above_root.above_root_chance
optional · chance · absent: never placed
How often a finished root gets a block on top of it.
mangrove_roots.above_root.above_root_block
optional · block
The block placed on top of a root.
mangrove_roots.root_decoration
optional · json · absent: roots are left undecorated
A decoration attached to the finished roots.
The same shape a trunk decoration takes. Its own keys are not described at this path yet, so it is edited as JSON.
Free-text field
A decoration attached to the finished roots, in the same shape a trunk decoration takes. This editor does not describe its keys at this path yet, so it is edited as JSON.
What changed in 1.26.50.24
Two additions and one behaviour change, none of which a file written for an older build has to care about:
poplar_trunkandpoplar_canopyare new. Earlier builds reject both keys, so a file using them does not load on 1.26.40.26.- A
fallen_trunkdrops through ground cover. A log that would previously have failed on leaf litter now drops through and replaces it.
Everything else on this page holds for 1.26.40.26 as well: the other seven trunk shapes, the eleven other canopies, every default and every range convention.
What the bench does differently
featurelab implements minecraft:tree_feature in full — every trunk shape and every canopy shape, including all of cherry_trunk — so no part of the JSON surface refuses. Four approximations are worth knowing when you read a preview of a tree:
may_grow_throughis applied on the plaintrunkkey only. The engine hands bothmay_replaceandmay_grow_throughto the routine that clears a trunk's column; the bench approximates that routine for the seven<shape>_trunkkeys and gates their columns onmay_replacealone, so a cell this field would have let the trunk pass through blocks it instead. The plaintrunkkey reads the field for real, on itscan_be_submergeddescent probe and on every column cell below the original origin. Writingmay_grow_throughon any of the other seven produces a diagnostic saying it will not be applied.canopy_decorationis read only withstep_direction: "down". That is the value vanilla's own definitions use and the only one whose behaviour has been established here; the bench refuses a file spelling it any other way rather than guessing at the difference.- Sideways logs — branch stubs, fallen trunks, cherry and poplar branches — are modeled through the
pillar_axisblock state. Block families that express orientation through some other state are not rewritten per family. - A few block predicates are approximated. The bench has no per-block material registry, so "can this ground cover be built over" runs against a fixed list of the vanilla blocks that qualify — leaf litter, the small replaceable plants, snow — and a custom block that the game would let a fallen log drop through may block one here. A few solidity tests use the bench's own block classification.
Where a field is unimplemented, the bench says so in its diagnostics instead of silently ignoring it: a file that loads without warnings is one whose fields were all applied.
Advanced: how the random values are spent
You do not need this section to grow a tree. It is for reading a preview draw for draw against the game, or for reproducing the engine's behaviour exactly — the facts that decide whether a change "that should not matter" moves everything placed after it. RNG and determinism is the model these numbers fit into; this section is the tree's row in it.
Ranges, and the degeneracy that skips a draw
The ordinary range sample is uniform over [min, max) — the maximum is exclusive — and a range whose min is at or above max - 1 returns min without consuming a random number at all. That is the single most useful fact in this section: making a range degenerate does not merely fix its value, it shortens the stream, and everything drawn after it in the same feature moves. { "base": 5, "intervals": [3, 3] } is 5 + nextIntBound(3) + nextIntBound(3); trunk_height.variance on a fancy trunk is base + nextIntBound(variance).
The seventeen inclusive-maximum keys follow the same rule: a range with min == max costs nothing here. For mangrove_canopy and random_spread_canopy's canopy_height and canopy_radius the game still spends one draw on a range with min == max; the bench does not, so a scattering canopy with a fixed height or radius shifts everything drawn after it by one value.
Where the draws sit, by shape
| Shape | What is drawn, in order |
|---|---|
trunk | The height, then height_modifier. The descent itself costs nothing at all. Then trunk_decoration's per-side rolls, then the canopy's. |
acacia_trunk | The height (one draw per intervals entry), then nextInt(4) for the lean direction, lean_height, lean_steps, lean_length, then per-log decoration rolls, then the canopy, then the branch routine. |
cherry_trunk | The height, the weighted pick over tree_type_weights, two inclusive range draws for the branch start offsets, one nextInt(4) for the direction, then per branch: an end offset, a horizontal length, and one float per step of the walk. No draw is spent between branch tips. |
fancy_trunk | The height, then two draws per cluster — one for its distance from the trunk, one for its angle — both spent before the clearance checks, so a rejected cluster still costs them. |
mega_trunk | The height, then per branch level: one branch_interval, one float for the angle, then the branch canopy's own draws, then the next branch_interval. |
poplar_trunk | The height, then remaining_trunk_height_above_branches, then the direction shuffle and amount_of_foliage_support_branches, then the canopy: the weighted radius pick, the height, one boolean for the quadrant bulge, then one float per crown cell for side_hole_chance — spent whether or not side_hole_chance is greater than zero. |
canopy | variation_chance only, four rolls per layer. A fraction whose numerator equals its denominator succeeds without drawing, and one with a zero denominator fails without drawing — the same "no draw at the extremes" rule the percentage form follows, which is why vanilla's { "numerator": 1, "denominator": 1 } cap is free. |
The two acacia branch routines draw in opposite orders
The diagonal routine draws branch_position first; the sweep draws branch_length first. This is invisible unless both ranges are non-degenerate, but it does mean the same JSON and the same seed produce different trees depending only on allow_diagonal_growth.
And the branch pass runs on every tree, whether or not branches was configured: on the diagonal path it still spends its direction draw. Two trees that differ only by having an empty versus an absent branches object therefore consume the same random numbers.
mangrove_roots moves the stream as well as the trunk
The order is height, then roots, then the trunk — so a tree that skips the root pass does not merely grow at a different height, it spends none of the draws that pass costs, and every value after it in the same feature shifts.
The fixtures
Every measured claim on this page is reproducible from committed fixtures. tree_acacia_branching.json (the worked example), tree_plain_trunk.json, tree_fancy_oak.json and tree_poplar.json, behind the single images, are under docs/wiki/tools/fixtures/features/; the eight tree_panel_*.json files behind the trunk-kinds figure are in the documentation's own pack, docs/wiki/tools/figure-fixtures/features/.
See also
- Scatter feature — how a tree gets placed many times across a chunk, rather than once at an origin.
- Feature rules — what invokes the scatter. A tree needs both to reach a world.
- Single block feature — the simplest Content feature, and what most other features end up delegating to.
- Vegetation patch feature — ground and ceiling patches that commonly delegate to trees.
- Weighted random feature — picking between several tree variants, which is how a forest gets more than one shape.
- RNG and determinism — the model the Advanced section above fits into, and why making one range degenerate moves everything after it.
How this page was checked
Everything above is a statement about Bedrock 1.26.60.22, and holds for 1.26.50.24 too. Everything except poplar_trunk and poplar_canopy also holds for 1.26.40.26, which is why this page carries no "also holds" badge for that build: those two keys do not exist in that build and a file using them does not load there.
Five findings can be reproduced directly from the committed fixture pack. The worked example's 48 blocks (13 logs, 34 leaves, 1 dirt) and the plain trunk's 78 (12 logs, 55 leaves, 11 vines, bottom log at world Y 62 against a requested origin of 63) were read back out of featurelab generate's own result, as was the fancy oak's 405 (31 logs, 374 leaves). The may_grow_through claim on the plain trunk was checked both ways: dropping minecraft:grass_block from that list moves the whole column up one cell and turns Y 62 from a log into a base_block conversion. The three pairings that grow a bare pole, and the two that grow no crown at all, were each run: a cherry_trunk whose only canopy is in branches.branch_canopy places its logs and not one leaf, and moving the same canopy body out to the feature body grows it at every branch tip. The poplar_canopy cross was read off a run with a working radius of 8: the log arms land three layers below the crown's topmost leaf layer and reach four cells from the centre, and at a working radius of 4 the cross is a single centre cell.
The branch_slope table is arithmetic from the formula stated beside it rather than a run, because a negative-slope branch is a shape nobody has shipped.
All four images were rendered from those exact results by the documentation's own image pipeline, which runs the real engine against the fixtures and the documentation's own pack with a fixed seed and a deterministic camera, so re-running it reproduces each picture byte for byte. The trunk-kinds figure is additionally refused by that pipeline if any two of its panels come out nearly identical, and it was refused three times before the parameters separated them; the closest pair now is trunk against poplar_trunk, at 2.9% of pixels differing. Every panel's cells were checked against a four-times-larger volume first, so the figure's tight framing is framing and not a boundary artifact.
What is not established: what the game does with an inverted canopy_offset (max below min), and what fancy_canopy's radius, roofed_canopy's two radii and spruce_canopy's upper_offset fall back to when omitted — the editor's catalogue asks for a value rather than guessing, and so does this page.