Tree Configuration
Register breakable static objects that spawn naturally during world generation.
Trees are breakable static objects that spawn naturally during world generation. This is the catalog file that registers them.
When several trees share the same spacing, footprint, hitbox, or breaking tool, you can factor that shape into a preset and give each entry a preset: key instead of repeating it — see Config Presets.
File Location
Register the file in your mod’s manifest (mods/<YourMod>/<YourMod>.yaml):
tree-config: tree-config.yaml
Then create the file it points to, relative to your mod’s folder:
mods/<YourMod>/tree-config.yaml
The file is a single list of tree entries. Each entry represents one tree type (a natural-spawn group) and contains one or more named variations — the actual placeable objects. Mechanical fields (hitbox, tool-break-types, power-required, time-to-break-ms, drop-table) can be declared once at the tree level and every variation inherits them, so variations that differ only in appearance need nothing but a name:
trees:
- name: my_oak
spacing:
x: 20
y: 20
max-size:
width: 10
height: 15
spawn-chance: 1.0
hitbox:
width: 10.0
height: 10.0
tool-break-types: axe
drop-table:
drops:
- item: oak_log
min-amount: 4
max-amount: 25
chance: 1.0
variations:
- name: my_oak
- name: my_oak_2
Both variations here share the tree-level hitbox, tool and drop-table; they differ only in which texture the world picks for them. A variation can still override any inherited field by declaring its own (see Field Inheritance).
Names — the tree entry’s name, each variation’s name, and item references like the item: in a drop — are automatically prefixed with your mod name unless you write a colon yourself. Write bare names (oak_log) for your own content; only add a prefix (OtherMod:their_item) to reference another mod.
Minimal Example
trees:
- name: my_oak
spacing:
x: 20
y: 20
max-size:
width: 10
height: 15
spawn-chance: 1.0
hitbox:
width: 10.0
height: 10.0
variations:
- name: my_oak
Fields
| Field | Default | Description |
|---|---|---|
name | (required) | The tree entry’s identifier. |
type | name | Groups trees for natural-spawn purposes (multiple tree entries can share a type). Omit it and the tree forms its own singleton group. |
biomes | (none) | Biomes this tree can spawn in, named from the tree’s side — see Choosing where a tree spawns. |
spacing (x, y) | (required) | World-gen spacing, in blocks — how much horizontal/vertical room each natural-spawn slot “claims”. |
max-size (width, height) | (required) | Upper bound on this tree’s footprint, used by world generation to reserve space. |
spawn-chance | (required) | Probability (0.0–1.0) that a given eligible placement cell spawns this tree. Resolved once per cell from the world seed at chunk generation, not re-rolled — see Chance vs. weight. The cell size is set by spacing. |
spawn-chance-inverse | false | Selects the opposite end of the per-cell random range, so the tree lands on a different set of cells at the same density — spawn-chance: 0.3 still fills 30% of eligible cells either way. Use it to shift a layout without changing how much spawns; it does not make the tree rarer or commoner. |
attach | floor | Which solid↔air boundary a natural spawn anchors to. floor (default) sits on solid ground with air above, anchored at its base and growing upward — the historical behavior. ceiling hangs from a solid ceiling (solid above, air below), anchored at its top and growing downward; the renderer flips the texture vertically, so author a ceiling object’s texture the same way as a floor object’s (rooted at the image bottom). wall attaches beside a vertical solid face, with facing pointing away from the wall into the open air. Only the underground-feature spawn path honors this — a surface or sky-island spawn always uses floor. See Ceiling & wall attachment. |
submerged | false | When true, a surface natural spawn roots on a seabed that lies below its biome’s water line (kelp, sea plants) instead of on dry land, anchored at its base and growing up into the water column. The object only spawns where the biome has a water fill (fill-surface-blocks) and the terrain top sits under that fill altitude. Ignored by the underground-feature and sky-island paths. See Submerged (underwater) spawns. |
submerged-max-depth | (none) | Optional cap, in blocks, on how far below the water line a submerged object may root — keeps it on the shallow shelf rather than in the deep. Omit it and any submerged depth is eligible. No effect unless submerged: true. |
hitbox | (none) | Tree-level default { width, height } in blocks, inherited by variations that don’t declare their own — see Field Inheritance. |
tool-break-types | (none) | Tree-level default tool categories, inherited by variations that don’t declare their own. |
power-required | 1 | Tree-level default tool power, inherited by variations that don’t declare their own. |
time-to-break-ms | 1000 | Tree-level default break time, inherited by variations that don’t declare their own. |
drop-table | (none) | Tree-level default drop table, inherited by variations that don’t declare their own. |
variations | (required — at least one) | The actual placeable tree objects — see Variations below. |
particles | (none) | Client-only. Tree-level ambient particle emission (e.g. falling leaves) — a list of emitter groups, the same shape every emitter uses (reference); see Per-Variation Particles for an example. Each variation may override this. |
shader | (none) | Client-only. Overrides the render shader for this tree. |
A tree entry with no valid variations is skipped entirely (logged as an error) — at least one variation must parse successfully.
Choosing where a tree spawns
A tree spawns in a biome when the two are linked, and either side can declare the link:
# From the tree's side, in tree-config.yaml — works across mods.
trees:
- name: glow_tree
biomes:
- Creation:forest # another mod's biome
- my_own_biome # bare name = your own mod
# From the biome's side, in your biome file — only for biomes you own.
static-object-spawns:
- glow_tree
The two are additive, not alternatives: a biome’s static-object-spawns and every tree naming that biome all feed one pool, so adding your tree to Creation:forest never displaces the trees Creation already spawns there. Declare the link once, from whichever side you own — writing it on both is harmless but redundant.
Ceiling & wall attachment
By default a static object roots on the ground. The attach field lets an object spawned by an
underground feature anchor to a cave ceiling or wall
instead — the way hanging vines, dangling roots, ceiling moss, and stalactites grow:
trees:
- name: hanging_vine
attach: ceiling # floor (default) | ceiling | wall
spacing: { x: 3, y: 3 }
max-size: { width: 1, height: 4 }
spawn-chance: 0.4
variations:
- name: hanging_vine
hitbox: { width: 1, height: 4 }
Notes:
- Feature-only.
attachis honored solely by the underground-feature spawn path (a feature that lists the object in itsstatic-object-spawns, see underground-feature-config.md). Objects placed on the surface or on sky islands always spawn on the floor. The feature must carve open space (acave-generator) for a ceiling/wall to exist to attach to. - Textures aren’t pre-flipped. A
ceilingobject is rendered upside-down from its authored texture, so draw it rooted at the bottom of the image exactly like a floor object; the engine flips it and hangs it from the ceiling. - Clearance. A ceiling object only spawns where there is at least
max-size.heightof open air below the ceiling for it to hang into. Awallobject only spawns in an open cell with solid rock on exactly one side.
Submerged (underwater) spawns
By default a surface object needs open air above the ground it spawns on. The submerged field lets an
object instead root on the seabed — the terrain surface of an ocean or lake biome, which sits below
the water the biome layers on top with fill-surface-blocks. This is how kelp
and other underwater foliage grow on the shallow shelf:
trees:
- name: kelp
submerged: true # root on a below-water-line seabed
submerged-max-depth: 12 # only within 12 blocks of the water line (the shallows)
spacing: { x: 4, y: 4 }
max-size: { width: 1, height: 6 }
spawn-chance: 0.5
biomes: [ Creation:tropical_ocean ]
variations:
- name: kelp
hitbox: { width: 1, height: 6 }
Notes:
- Surface path only.
submergedis honored by the surface natural-spawn scan (the same one that places land trees). An ocean biome’s terrain surface is its seabed, so the object anchors there and grows up into the water. It has no effect on underground-feature or sky-island spawns. - Needs a water line. The object spawns only where the biome declares
fill-surface-blocksand the terrain top is below thatfill-to-altitude. A biome with no water fill never spawns submerged objects, and a column whose surface is above the water line (a beach, an offshore islet) is skipped. - Stay in the shallows. Set
submerged-max-depthto keep the object near the surface — a good match for a kelp forest. Author the object no taller than the local water depth so it doesn’t spike out of the surface; the depth cap is your control for that. Omitting the cap allows any depth. - Anchor is still
floor. A submerged object roots at its base and grows upward like a normal floor object — author its texture rooted at the image bottom.attachandsubmergedare independent; a submerged object ignoresattach. - Sits on the seabed, not in it. A submerged object is placed one cell higher than a land object would be, so it rests on top of the seafloor surface rather than embedding its base row into the seabed block (which reads as “rooted” for a wide tree but “buried” for thin foliage).
biomes is the only way to put a tree in a biome another mod owns, since the biome-side list would mean editing that mod’s files. It works the same way an ore’s biomes always has. Names follow the usual rule: bare means your own mod, OtherMod:name reaches across. If your mod adds to another mod’s biome, declare that mod as a dependency — that’s what guarantees its biomes load before your trees register.
Not for sky islands. An island’s static objects come from the sky island feature, not from its biome, so a tree naming a sky-island biome can’t be placed. The server logs a warning at load telling you to move it to the feature’s
static-object-spawnsinstead.
A tree with no biomes and named by no biome never spawns naturally — it can still be placed by a structure or from Lua.
Worldgen placement, not runtime spawning. A tree’s
spacingandspawn-chanceare worldgen placement fields — decided deterministically when a chunk generates, and shared verbatim with structures and sky-island features. This is a different system from a mob’s runtimespawn-rulesblock (see Natural Spawning); the two look nothing alike because they answer different questions. Use this spacing-plus-spawn-chancevocabulary for anything placed at worldgen.
Variations
Each entry in variations is a distinct placeable object (e.g. a tree with two trunk styles both counted as the same “type” for spawning purposes):
| Field | Default | Description |
|---|---|---|
name | (required) | The variation’s identifier — this is the name actually used for placement/breaking, not the parent tree entry’s name. |
hitbox | (inherited) | { width, height } in blocks. Falls back to the tree-level hitbox; required if the tree defines no tree-level default. |
tool-break-types | (inherited) | Which tool categories can break it — a single string or a list. Falls back to the tree-level value; if neither is set there is no tool requirement, so any tool or a bare hand breaks it, subject to power-required (same rule as interactables). |
power-required | (inherited → 1) | Minimum tool power level needed to break it. Falls back to the tree-level value, then 1. |
time-to-break-ms | (inherited → 1000) | How long it takes to break with a valid tool. Falls back to the tree-level value, then 1000. |
drop-table | (inherited) | Items dropped when broken — see Shared Blocks → drop-table (same shared block). Falls back to the tree-level drop-table. |
weight | 1.0 | Relative likelihood this variation is chosen at natural-spawn time, compared to its siblings. weight: 3 on one of two variations makes it appear ~3× as often as a weight: 1 sibling; weight: 0 disables natural spawning of the variation. Not inheritable — it only makes sense per-variation. |
particles | (none) | Client-only. Per-variation override of the tree-level particles — see below. |
A variation with an invalid name or hitbox — or with no hitbox when the tree defines no tree-level default — is skipped on its own; the rest of the tree’s variations still load.
Variations are otherwise chosen uniformly (each equally likely) unless you set weight. Setting equal weights on every variation is identical to leaving them all unset.
Typos fail the entry. Any field name on a tree entry or a variation that the engine doesn’t recognize is a load-time error naming the bad key (
Unknown field '…' — entry skipped (check for a typo)); an unknown key on the tree skips the whole tree, one on a variation skips just that variation. This is the same rule every catalog file follows — see Unknown Fields.
Field Inheritance
hitbox, tool-break-types, power-required, time-to-break-ms and drop-table may be set on the tree entry itself as defaults. Each variation inherits the tree-level value unless it declares its own, which fully replaces the inherited one (drop-tables are not merged). This keeps variations that differ only in appearance down to a single name line while still letting an individual variation carry, say, a rarer drop-table or a tougher break time:
trees:
- name: my_oak
spacing:
x: 20
y: 20
max-size:
width: 10
height: 15
spawn-chance: 1.0
hitbox: { width: 10.0, height: 10.0 }
tool-break-types: axe
drop-table:
drops:
- item: oak_log
min-amount: 4
max-amount: 25
variations:
- name: my_oak # inherits hitbox, tool-break-types and drop-table
- name: ancient_oak # same hitbox/tool, but its own richer drop-table
drop-table:
drops:
- item: oak_log
min-amount: 20
max-amount: 40
- item: golden_acorn
chance: 0.05
particles follows the same tree-level-default / per-variation-override rule (see below); the only field that is never inheritable is name.
Per-Variation Particles
A variation’s own particles block fully replaces the tree-level one for that variation — it isn’t merged. This lets, e.g., a wind-blown variation of a tree emit leaves on a different cadence than its sibling variations while still counting as the same tree type:
trees:
- name: cherry_tree
spacing:
x: 20
y: 20
max-size:
width: 10
height: 15
spawn-chance: 1.0
hitbox: { width: 10.0, height: 10.0 }
tool-break-types: axe
drop-table:
drops:
- item: cherry_log
min-amount: 4
max-amount: 25
particles:
- emit-random:
- name: cherry_leaf
chance: 0.1
cooldown-ms: 5000
lifetime-ms: 10000
x-offset-min: -8.0
x-offset-max: 8.0
y-offset-min: 8.0
y-offset-max: 9.0
variations:
- name: cherry_tree # inherits everything, including the tree-level leaf particles
- name: cherry_tree_2 # same hitbox/tool/drop-table, but its own faster particle cadence
particles:
- emit-random:
- name: cherry_leaf
chance: 0.2
cooldown-ms: 3000
lifetime-ms: 10000
x-offset-min: -9.0
x-offset-max: 9.0
y-offset-min: 10.0
y-offset-max: 11.0
Here cherry_tree_2 inherits the tree-level hitbox, tool and drop-table but overrides the particle block, shedding leaves twice as often (chance: 0.2 vs 0.1) and faster (cooldown-ms: 3000 vs 5000) than plain cherry_tree, even though both are variations of the same tree type. This mirrors the shipped Creation cherry tree.
Last updated