# 17 - Trees, Fungi, Coral, Crystals, Formations, Ruins Procedural objects are baked from JSON settings into deterministic block blobs and scattered like `.iob` placements. They live under biome or region `proceduralObjects` and do not require object files. Separate systems: sapling tree overrides (`IrisTree` on object placements) and dimension `treeSettings` for growth replacement mode. Related: `13 - Biomes.md`, `12 - Regions.md`, `15 - Caves & Carving.md`, `16 - Surfaces, Decorators & Deposits.md`, `18 - Structures Overview.md`, `19 - Objects.md`, `20 - Object Placement.md`. ## Container (`IrisProceduralObjects`) | Field | Type | Contents | |-------|------|----------| | `trees` | `IrisProceduralTree[]` | Procedural trees | | `fungi` | `IrisFungus[]` | Mushrooms / shelf fungi | | `coral` | `IrisCoral[]` | Underwater coral forms | | `crystals` | `IrisCrystal[]` | Cave crystal clusters | | `formations` | `IrisFormation[]` | Rock landmarks | | `ruins` | `IrisRuin[]` | Crumbling man-made shapes | Attach on biomes and regions: ```json { "proceduralObjects": { "trees": [ { "...": "..." } ], "crystals": [ { "...": "..." } ] } } ``` Shipping overworld content currently relies on `.iob` tree objects more than procedural trees; the fields and generators are fully available for pack authors. ## Shared placement fields All procedural types implement placement via `asPlacement()` → `IrisObjectPlacement`-compatible settings: | Field | Typical default | Notes | |-------|-----------------|-------| | `name` | type-specific | Log key / variant key prefix | | `chance` | 0.02–0.4 | Per-chunk attempt probability | | `density` | `1` | Attempts if chance passes | | `variants` | 6–8 | Pre-baked shape count (1..64) | | `seed` | `1337` | Deterministic bake seed | | `mode` | `CENTER_HEIGHT` (ruins: `MIN_HEIGHT`) | Terrain anchor mode | | `rotation` | object rotation | Placement rotation | | `clamp` | height limits | Min/max place height | | `carvingSupport` | `SURFACE_ONLY` (crystals: `CARVING_ONLY`) | Surface vs cave | | `underwater` | type-specific | Coral default true | | `translate` | zero | XYZ offset | | `stiltSettings` / `vacuumSettings` | optional | For stilt/vacuum modes | Variant objects load as keys like `procedural/#` (trees: `procedural/tree/#`). Same seed + settings always bake the same variants. `CarvingMode`: `SURFACE_ONLY`, `CARVING_ONLY`, `ANYWHERE`. Common `ObjectPlaceMode` values: `CENTER_HEIGHT`, `MAX_HEIGHT`, `MIN_HEIGHT`, `FAST_*` variants, `STILT`, `MIN_STILT`, `FAST_STILT`, `CENTER_STILT`, `ERODE_STILT`, `ORGANIC_STILT`, vacuum modes. Cave defaults often use organic/fast stilt to prevent floating. ## Procedural trees (`IrisProceduralTree`) Baked by `ProceduralTreeGenerator`. ### Core materials and size | Field | Default | Notes | |-------|---------|-------| | `trunk` / `trunkPalette` | oak log | Palette wins | | `leaves` / `leavesPalette` | oak leaves | Palette wins; real leaves get decay distances when `plausible` | | `plausible` | `true` | Vanilla leaf distance / non-persistent | | `heightMin` / `heightMax` | 8 / 12 | Trunk height range across variants | | `trunkWidth` | `1` | Base trunk thickness | | `profile` | `OAK` | Named canopy silhouette | ### Profiles (`IrisTreeProfile`) `OAK`, `BIRCH`, `SPRUCE`, `JUNGLE`, `ACACIA`, `DARK_OAK`, `DARK_OAK_FLAT`, `DARK_OAK_FLAT_WIDE`, `CHERRY`, `PALM`, `WILLOW`, `COLUMNAR`, `BUSH`, `MEGA_SPRUCE`. ### Trunk shaping | Field | Default | Notes | |-------|---------|-------| | `trunkShape` | `CONSTANT` | `IrisTreeFunction` over trunk width by height | | `shapeStart` / `shapeEnd` | `1` / `1` | Linear width multipliers | | `shapeSteepness` | `5` | Sigmoid steepness | | `shapeBase` | `2.718281828` | Logarithmic base | | `shapePeriod` / `shapeAmplitude` | `1` / `0.2` | Sine width controls | | `shapePeakOffset` / `shapeFloor` | `0.5` / `0.5` | Parabolic waist position and minimum fraction | | `leanAzimuth` / `leanAngle` | `0` / `0` | Compass direction and degrees from vertical | | `trunkCurve` / `curveSteepness` | `LINEAR` / `8` | Lean accumulation and sigmoid steepness | | `leanAzimuthMode` | `CONSTANT` | How lean direction changes over height | | `azimuthStart` / `azimuthEnd` | `0` / `0` | Linear azimuth endpoints | | `azimuthTurns` | `1` | Full turns for `SPIRAL` | | `azimuthAmplitude` / `azimuthPeriod` / `azimuthOffset` | `90` / `1` / `0` | Sine azimuth controls | | `azimuthScale` | `1` | Noise azimuth scale | | `azimuthWhorlCount` | `5` | Branches per ring for `WHORL` | | `trunkForks` / `forkHeight` / `forkAngle` | `1` / `0.5` / `25` | Fork count, normalized split height, and outward angle | | `secondaryTrunk` / `secondaryTrunkPalette` | null | Optional band material; palette wins | | `secondaryTrunkStart` / `secondaryTrunkEnd` | `0.5` / `1` | Normalized secondary band bounds | | `roots` / `rootStyle` | `true` / `BUTTRESS` | Enable roots and select `TAPROOT`, `BUTTRESS`, or `STILT` | | `rootDepth` / `rootFlare` | `0` / `0` | Explicit values; zero uses automatic scaling | `IrisTreeFunction`: `CONSTANT`, `LINEAR`, `SIGMOID`, `LOG`, `SINE`, `PARABOLIC`, `EXPONENTIAL`, `SQRT`, `STEP`, `BELL`, `EASE_IN_OUT`. `IrisTreeAzimuthMode`: `CONSTANT`, `LINEAR`, `SPIRAL`, `SINE`, `NOISE`, `RANDOM`, `GOLDEN_ANGLE`, `ALTERNATING`, `WHORL`, `ZIGZAG`. ### Canopy (`IrisTreeCanopy`) | Field | Default | Notes | |-------|---------|-------| | `startAngle` | `90` | Disc elevation (90 flat, lower = dome, higher = umbrella) | | `squish` | `1` | Vertical scale | | `mode` | `TRIMMED` | Leaf fill mode | | `leafDensity` | `0.85` | For density/noise modes | | `crownStretchX` / `crownStretchZ` | `1` | Ellipse crown | | `layers` | `[]` | Explicit discs override profile | | `branches` | null | Branch system drives canopy when set | `IrisTreeLayer`: `yOffset`, `radius`. `IrisTreeLeafMode`: `TRIMMED`, `FILLED`, `DENSITY`, `NOISE`, `HOLLOW`, `GRADIENT`, `CLUMPED`, `TATTERED`, `SPARSE`. ### Branches (`IrisTreeBranches`) Probability functions (`IrisTreeBranchProbability`): `CONSTANT`, `LINEAR`, `SIGMOID`, `TOP_HEAVY`, `GAUSSIAN`, `NOISE`, `BOTTOM_HEAVY`, `PERIODIC`, `BAND`, `INVERSE_GAUSSIAN`, `EXPONENTIAL_DECAY`. | Field | Default | Role | |-------|---------|------| | `probabilityFunction` | `TOP_HEAVY` | Branch chance curve over normalized trunk height | | `probabilityConstant` | `0.5` | `CONSTANT` chance | | `probabilityBase` / `probabilityCrown` | `0` / `1` | `LINEAR` endpoints | | `probabilitySteepness` / `probabilityMidpoint` | `10` / `0.7` | `SIGMOID` controls | | `probabilityExponent` | `2` | `TOP_HEAVY` exponent | | `probabilityMean` / `probabilityStd` | `0.7` / `0.15` | Gaussian center and deviation | | `probabilityScale` | `1` | Noise scale | | `probabilityPeriods` | `5` | Periodic whorl count | | `lengthFunction` | `LINEAR` | Branch-length curve over trunk height | | `lengthBase` / `lengthCrown` | `1` / `4` | Linear endpoints | | `lengthConstant` / `lengthMax` | `3` / `4` | Constant value and nonlinear maximum | | `lengthSteepness` | `5` | Sigmoid length steepness | | `azimuthMode` / `azimuth` | `RANDOM` / `0` | Direction selection and fixed direction for `CONSTANT` | | `elevation` / `sag` | `0` / `0` | Initial elevation and catenary droop | | `branchDepth` | `1` | Recursive branch levels, 0–6 | | `leafStartUp` | `false` | Clamp primary branches so they do not droop below horizontal | | `clusterRadius` / `clusterMode` / `clusterDensity` | `2` / `TRIMMED` / `0.85` | Primary tip leaf cluster | | `subBranches` | `null` | Optional `IrisTreeSubBranches` configuration | `subBranches` fields: `count` (`1`), `pitchDelta` (`0`), `yawDelta` (`45`), `lengthScale` (`0.5`), `sag` (`0`), `clusterRadius` (`1`), `clusterMode` (`TRIMMED`), and `clusterDensity` (`0.85`). ### Secondary leaves and accents | Field | Notes | |-------|-------| | `secondaryLeaves` | Single accent block | | `weightedSecondaryLeaves` | Weighted list (`block`, `weight`) | | `secondaryLeavesPalette` | Wins over both | | `secondaryLeafFraction` | Fraction replaced | | `decorators` | `IrisTreeDecorator[]` post accents | ### Tree decorator (`IrisTreeDecorator`) | Field | Default | Notes | |-------|---------|-------| | `target` | `BRANCH_TIP` | Placement locus | | `block` / `palette` | required block | Palette wins | | `chance` | `0.5` | Per candidate | | `length` | `1` | Max hang for `CANOPY_HANG` | | `axisAware` | `false` | Orient facing away from trunk | Targets: `BRANCH_TIP`, `TRUNK_SURFACE`, `CANOPY_TOP`, `CANOPY_BOTTOM`, `TRUNK_BASE`, `LEAF_SURFACE`, `CANOPY_HANG`, `BRANCH_SURFACE`, `TRUNK_TOP`, `GROUND_SCATTER`. ### Minimal tree example ```json { "name": "oak-plains", "chance": 0.35, "density": 2, "variants": 8, "seed": 9001, "trunk": "minecraft:oak_log", "leaves": "minecraft:oak_leaves", "profile": "OAK", "heightMin": 7, "heightMax": 11, "plausible": true, "roots": true, "rootStyle": "BUTTRESS", "canopy": { "mode": "TRIMMED", "startAngle": 88, "squish": 0.9 } } ``` ## Sapling overrides (`IrisTree` + `IrisTreeSettings`) — not procedural trees `IrisTree` on **object placements** (`IrisObjectPlacement.trees`) maps grown sapling types/sizes to that object: | Field | Notes | |-------|-------| | `treeTypes` | Bukkit `TreeType` names | | `anyTree` | Match any type | | `sizes` | `IrisTreeSize` width×depth sapling footprints | | `anySize` | Match any size | Dimension `treeSettings`: `enabled`, `mode` (`FIRST` biome→region→dimension, or `ALL` pool). This is growth replacement, not worldgen scatter. ## Fungi (`IrisFungus`) | Field | Default | Notes | |-------|---------|-------| | `stem` / `stemPalette` | mushroom_stem | Palette wins | | `cap` / `capPalette` | red_mushroom_block | Palette wins | | `stemHeightMin` / `Max` | 5 / 9 | Stem height | | `stemWidth` | `1` | 1–3 column | | `stemCurve` / `stemLeanAzimuth` / `stemWaveAmplitude` / `stemWavePeriods` | lean/wave | Organic stem | | `capShape` | `DOME` | `DOME`, `FLAT`, `FUNNEL`, `CONICAL`, `FLAT_WIDE` | | `capRadiusMin` / `Max` | 3 / 5 | Cap size | | `capThickness` / `capSquish` / `capDroop` / `capOverhang` | shape controls | | | `gillBlock` / `gillPalette` / `gillChance` | underside | | | `spotBlock` / `spotPalette` / `spotChance` | top speckles | | | `shelf` / `shelfRadius` | false / 3 | Sideways polypore mode | ## Coral (`IrisCoral`) Defaults: `underwater: true`, `waterlogged: true`, `mode: CENTER_HEIGHT`. | Field | Notes | |-------|-------| | `form` | `BRANCHING`, `FAN`, `BRAIN`, `PILLAR`, `TENDRIL` | | `block` / `blockPalette` | Structure body | | `tipBlock` / `tipPalette` / `tipChance` | Fans/pickles | | `heightMin` / `heightMax` | Overall height | | `spread` / `sway` | Horizontal reach / wobble | | Branching-only | `branchCount`, `branchLength`, `branchElevation`, `branchAzimuth` (`GOLDEN_ANGLE`/`EVEN`/`RANDOM`), `subBranches`, `subBranchCount`, `subBranchScale`, `tipClusterRadius` | | Brain-only | `brainRadius`, `brainRoughness` | | Pillar-only | `pillarRadius` | | Fan-only | `fanWidth` | | Tendril-only | `tendrilCount` | ## Crystals (`IrisCrystal`) Defaults: `carvingSupport: CARVING_ONLY` (cave-first). | Field | Notes | |-------|-------| | `growthSurface` | `FLOOR`, `CEILING`, `WALL` (orients bake only) | | `block` / `blockPalette` | Shard body | | `tipBlock` / `tipPalette` / `tipChance` | Tip accents | | `glow` / `glowBlock` | Auto glow tips if no tip block | | `baseBlock` / `basePalette` / `baseRadius` / `baseNoise` | Budding base blob | | `shardCountMin` / `Max` | Shard count | | `shardLengthMin` / `Max` | Shard length | | `shardBaseRadius` / `shardTaper` | Taper geometry | | `spreadAngle` | Cone half-angle degrees | | `distribution` | `RANDOM` or `GOLDEN_ANGLE` | | `jitter` | Angular noise | ## Formations (`IrisFormation`) Natural landmarks. Extra field `surfaceSupportBuffer` (default 3) for foundation solidity. | Field | Notes | |-------|-------| | `form` | `SPIRE`, `HOODOO`, `ARCH`, `SEA_STACK`, `BOULDER`, `BASALT_COLUMN` | | `block` / `blockPalette` | Body | | `capBlock` / `capPalette` | Caprock | | `strataPalette` / `strataThickness` | Horizontal bands | | `heightMin` / `heightMax` | Height | | `baseWidthMin` / `baseWidthMax` / `topWidth` | Radii | | `profile` | `CONSTANT`, `LINEAR`, `TAPER`, `PARABOLIC`, `BULGE` | | `profileWaist` / `profileWaistFloor` | Parabolic waist | | `lean` / `leanAzimuth` | Tilt | | `roughness` / `jitter` | Surface erosion | | Hoodoo | `hoodooCapRadius`, `hoodooCapHeight` | | Arch | `archSpan`, `archThickness` | | Basalt | `basaltColumns`, `basaltColumnRadius`, `basaltHeightVariance` | ## Ruins (`IrisRuin`) | Field | Default | Notes | |-------|---------|-------| | `form` | `PILLAR` | `PILLAR`, `WALL`, `ARCH`, `FLOOR_SLAB`, `RUBBLE` | | `block` / `blockPalette` | cobblestone | Structure body | | `heightMin` / `Max` | 4 / 9 | Height band | | `widthMin` / `Max` | 1 / 3 | Footprint X | | `lengthMin` / `Max` | 3 / 7 | Footprint Z | | `weatheredBlock` / `weatheringPalette` | mossy_cobblestone | Weather remap | | `mossiness` / `weatheringScale` | 0.45 / 1 | Weather intensity/scale | | `erosion` / `erosionScale` | 0.25 / 1.5 | Missing-block noise | | `buriedFraction` | 0.2 | Fraction sunk below surface | | `accents` | `[]` | `IrisRuinDecorator` list | ### Ruin decorator (`IrisRuinDecorator`) | Field | Default | Notes | |-------|---------|-------| | `target` | `TOP` | `TOP`, `SURFACE`, `BASE_SCATTER` | | `block` / `palette` | required | Palette wins | | `chance` | `0.4` | Per candidate | | `scatterRadius` | `2` | BASE_SCATTER extent | ## Authoring workflow 1. Choose system: trees for forests, fungi for mushroom biomes, coral for warm oceans, crystals for cave biomes, formations for deserts/coasts, ruins for sparse land. 2. Set `chance`/`density` low first; raise after silhouette looks correct. 3. Keep `variants` 4–12; each variant is baked at first use/cache warm. 4. Use palettes for material mix; single `block` strings for simple packs. 5. Match `carvingSupport` to environment; crystals and cave props use `CARVING_ONLY`. 6. For cave props, prefer stilt place modes and profile `defaultObjectPlaceMode`. 7. Prefer procedural systems for infinite variety; use `.iob` objects when you need hand-authored geometry (overworld trees mostly use objects today). ## Practical notes - Procedural content is separate from `objects` placements and from structure jigsaws. - `plausible: true` on trees enables natural leaf decay; false forces persistent leaves. - Formation `surfaceSupportBuffer` interacts with dimension `objectSurfaceSupportBuffer` (max of requirements). - Do not confuse `IrisTree` (sapling→object) with `IrisProceduralTree` (worldgen bake). - Empty variant bake (invalid sizes) skips that entry; check logs if nothing places.