Skip to content

API Worldgen Structure Composition

Piggo41 edited this page Sep 30, 2026 · 1 revision

Structure templates and conditional composition

Lua API / World generation / Structure documents / Composition

Templates remove repeated geometry from a document. Arrays and repeats place repeated instances, while keyed chance and choice groups create deterministic variants without Lua callbacks during generation.

Reusable templates

{
  "palette": {
    "stone": { "block": 4 },
    "mossy": { "block": 48 }
  },
  "templates": {
    "pillar": {
      "elements": [
        { "type": "fill", "from": [0, 0, 0], "to": [0, 3, 0], "state": "material" }
      ]
    }
  },
  "elements": [
    {
      "type": "template",
      "name": "pillar",
      "at": [3, 0, 0],
      "rotation": "clockwise_90",
      "mirror": "none",
      "states": { "material": "mossy" }
    }
  ]
}

Field definitions

Field Behavior
name Required template name for a template element.
at Translation applied after the local transform; defaults to [0,0,0].
rotation none, clockwise_90, clockwise_180, or counterclockwise_90.
mirror none, left_right, or front_back.
states Maps symbolic state names used by the template to palette states visible in the parent instance.

Transforms apply to blocks, markers, loot positions, and directional metadata. Template recursion and expansion deeper than 16 levels are rejected.

Arrays

{
  "type": "array",
  "template": "pillar",
  "at": [-4, 0, -4],
  "count": [3, 1, 3],
  "step": [4, 0, 4],
  "states": { "material": "stone" }
}

Each component of count accepts 1–256, but the product must not exceed 256 instances. step is multiplied by the zero-based X/Y/Z instance index. The example places a 3-by-3 grid, including its first instance exactly at at. Arrays accept the same rotation, mirror, and states fields as a template element.

Repeats

{
  "type": "repeat",
  "count": 5,
  "step": [0, 1, 0],
  "element": {
    "type": "block",
    "pos": [0, 0, 0],
    "state": "stone"
  }
}

repeat accepts any one nested element. It includes the original instance at offset zero, followed by instances at index * step. A count of 5 therefore writes offsets 0 through 4, not 1 through 5.

Chance groups

{
  "type": "chance",
  "key": "side_chest",
  "chance": 0.35,
  "elements": [
    { "type": "block", "pos": [2, 1, 0], "state": "chest", "tags": ["protected"] },
    {
      "type": "loot",
      "key": "side_chest_loot",
      "pos": [2, 1, 0],
      "table": "mymod:side_chest"
    }
  ]
}

A chance group resolves its complete elements list or none of it. Keep a conditional inventory block and its loot element in the same group so they cannot resolve independently. chance accepts 0 through 1.

Choice groups

{
  "type": "choice",
  "key": "roof_variant",
  "choices": [
    {
      "weight": 3,
      "elements": [
        { "type": "fill", "from": [-2, 4, -2], "to": [2, 4, 2], "state": "stone" }
      ]
    },
    {
      "weight": 1,
      "elements": [
        { "type": "ellipsoid", "center": [0, 4, 0], "radius": [3, 1, 3], "state": "mossy" }
      ]
    }
  ]
}

Exactly one choice is selected. Weights are relative: the example selects the first branch with probability 3/4 and the second with probability 1/4. A choice may contain an empty elements list to represent “place nothing.”

Stable keys and conflicts

Every chance and choice requires a lowercase stable key. Keys must be unique within the expanded template instance. A reused template receives an instance-specific random namespace, so its keyed decisions are independent from decisions made by another instance.

The world generator seed, placement identity, element key, and instance identity determine each choice. Adding an unrelated keyed group does not shift existing decisions. Reusing or renaming a key intentionally changes that stream.

Two independent chance groups may both resolve. If they then write different states to the same coordinate, the resolved placement is rejected unless the later write deliberately uses write = "replace". The rejection is atomic; the structure is not partially placed.

Next: structure processors and selectors.

Clone this wiki locally