---
title: "Object Placement"
description: "Iris documentation: Object Placement"
published: true
date: 2026-10-24T00:00:00.000Z
tags: "iris"
editor: markdown
dateCreated: 2026-08-09T00:00:00.000Z
---
A biome or region `objects[]` entry distributes objects over terrain. If publishing an object into a chunk fails, earlier completed placements in that chunk remain intact. A dimension `staticObjects[]` entry places one saved object at an exact world position with fixed rotation, scale, and block edits. Building the objects themselves is [19 - Objects](/iris/19-objects). Multi-piece assemblies are [21 - Jigsaw Structures](/iris/21-jigsaw-structures).
## Static objects at fixed coordinates
Use dimension `staticObjects` for a landmark, spawn building, or other object that must generate at a particular position. Prerequisites: the saved `.iob` file and a Studio or disposable world whose target chunks have not generated.
1. Save the object as, for example, `objects/landmarks/tower.iob`.
2. Add this entry to `dimensions/.json`:
```json
{
"staticObjects": [
{
"object": "landmarks/tower",
"position": { "x": 100, "y": 100, "z": -100 },
"rotation": { "y": 90 },
"scale": 1,
"edit": [
{
"find": [{ "block": "minecraft:oak_planks" }],
"replace": { "palette": [{ "block": "minecraft:stone_bricks" }] }
}
]
}
]
}
```
3. Validate with `/iris pack validate pack=` on Bukkit or `/iris pack validate ` on modded, then open Studio or create a test world.
4. Visit world coordinates `100 100 -100`. That coordinate is the object's saved origin, usually its center, rather than its bottom or a terrain sample. Check the footprint on both sides of any chunk boundary.
Static objects generate after terrain and decoration, regardless of biome, slope, water, caves, density, or chance, and later native structures cannot overwrite them. Entries apply in array order and the later entry wins where they overlap. Saved air writes air; unsaved space stays unchanged unless `bore` or `smartBore` fills it. **This can replace terrain, including the bedrock layer.**
Rotation uses fixed degrees on `x`, `y`, and `z`, all zero by default. Negative and fractional angles work, but angles other than multiples of 90 round onto the block grid and can create holes or merge voxels. When rotated voxels merge or a later placement replaces a block, the surviving block keeps only its own block-entity data. Saved block-entity data accompanies its transformed blocks; edits apply before rotation, leave the source `.iob` unchanged, and changing a block's material discards incompatible block-entity data. A non-solid directional block that cannot represent its rotated orientation is skipped along with its tile data; the rest of the object still places.
| Field | Default | Meaning |
|-------|---------|---------|
| `object` | required | One load key under `objects/`, without `.iob` |
| `position` | required | Absolute integer world coordinates; Y is not measured from the dimension floor |
| `rotation` | `{ "x": 0, "y": 0, "z": 0 }` | Fixed degrees per axis, from -360 to 360 |
| `scale` | Dimension factor | Fixed size multiplier, 0.01 to 50; an explicit value overrides `allObjectScaleFactor` |
| `scaleInterpolation` | `NONE` | Enlargement interpolation: `NONE`, `TRILINEAR`, `TRICUBIC`, or `TRIHERMITE` |
| `edit` | `[]` | The same material/state replacement rules described in section 6 below |
| `bore` | `false` | Clear the complete transformed bounding box before writing the object |
| `smartBore` | `false` | Fill enclosed rooms and pockets with air on a copy of the object |
| `seed` | `0` | Fixed seed for probabilistic edits and replacement palettes, independent of chunk order and world seed |
Missing objects and invalid settings are errors. The origin and the full transformed object must fit inside the dimension's build height; an overflowing object is rejected outright rather than placed as a clipped fragment.
These settings affect newly generated chunks only. They do not repair objects players break, paste into existing chunks, or rewrite existing buildings after a reload test in fresh chunks or a disposable world. See [05 - Concepts & Pack Layout](/iris/05-concepts-pack-layout).
## Tutorial: get one object into the world
Prerequisites: a saved object such as `objects/tutorial/lookout.iob`, a biome or region the target dimension actually uses, and a Studio or disposable test world. Placements only affect chunks generated after the JSON existed. Every check below needs fresh terrain.
Merge this into one focused biome, keeping the biome other fields:
```json
{
"objects": [
{
"place": ["tutorial/lookout"],
"chance": 1,
"density": 1,
"mode": "CENTER_HEIGHT",
"rotation": { "enabled": false }
}
]
}
```
1. Paste the object by hand first: `/iris object paste tutorial/lookout`. If the geometry or the origin is wrong, fix the object before you touch placement JSON.
2. Validate the pack: `/iris pack validate pack=` on Bukkit, `/iris pack validate ` on a modded loader.
3. Open or hotload Studio and fly into fresh chunks whose center column uses the edited biome. At `chance: 1` you get one in nearly every such chunk.
4. Confirm ownership: run `/iris find object tutorial/lookout`, or get `/iris object dust` and right-click a placed block. Iris names the placement that owns that block.
5. Pick the terrain mode that fixes what you see. Use `PAINT` for ground-hugging clutter. Use a stilt mode for support over uneven ground. Use `CEILING_HANG` for cave roofs. Use a `VACUUM` mode to pull the terrain up to a flat base.
6. Adjust `chance` and `density` to set how often the object appears.
## 1. Which files carry placements
`objects[]` exists on exactly two resource types:
- **Biome** (`biomes/**.json`): wherever that biome generates.
- **Region** (`regions/**.json`): every biome in the region.
Dimensions use `staticObjects[]` for fixed-coordinate placements, as described above. Random `objects[]` entries belong only to biomes and regions. Dimensions also carry two knobs that tighten every random placement underneath them (`requireObjectSurfaceSupport`, `objectSurfaceSupportBuffer`, section 4) and two that gate the inverted upper dimension (`upperDimensionObjects`, `upperObjectsForcePlace`).
Per chunk, Iris samples the biome and region once at the chunk center (block 8,8). It then walks four lists in this fixed order: biome surface, biome cave, region surface, region cave. Every entry rolls independently. A biome entry and a region entry can both fire in the same chunk. A biome that only clips the corner of a chunk contributes nothing there. The center biome objects can spill a few blocks into its neighbors.
A whole placement can be replaced by a snippet reference. `"objects": ["snippet/object-placer/my-camp"]` loads `snippet/object-placer/my-camp.json`.
Minimal entry:
```json
{
"objects": [
{
"place": ["clutter/boulder1"],
"chance": 0.05
}
]
}
```
`place` entries are object keys: the path under `objects/` without `.iob`.
## 2. How often does it spawn?
Two numbers do the work. `chance` decides whether the entry runs at all in this chunk. `density` decides how many stamps it then attempts.
```json
{
"place": ["clutter/boulder1", "clutter/boulder2"],
"chance": 0.05,
"density": 3
}
```
Roughly `chance x density` objects per chunk, before rejections. `chance: 0.002` is about one chunk in five hundred.
Each of the `density` attempts independently picks a random object out of `place` and a random column inside the chunk. It then runs every gate in sections 3 to 5. Density is a budget of tries, not a guarantee of placements.
`place` is an unweighted, uniform pick. To bias one object, list its key more than once or split the entry in two. A key that does not resolve costs the attempt and logs `Couldn't find Object: ` once per lookup.
Surface entries add uniform `+/- 0.005` jitter to `chance` before rolling. Cave entries roll the raw value. Two consequences, each worth about one chunk in eight hundred: `chance: 1` occasionally fails, and `chance: 0` occasionally succeeds. Omit an entry to disable it. Do not set it to zero.
`densityStyle` replaces `density` with a noise-driven count, so density varies across the world instead of being flat:
```json
{
"densityStyle": { "min": 1, "max": 4, "style": { "style": "IRIS_THICK", "zoom": 8 } }
}
```
Always set `min` and `max`. The class defaults are 16 and 32. A bare `"densityStyle": {}` would ask for 16 to 32 attempts in every chunk that passes the chance roll. `/iris pack validate` rejects a densityStyle that omits both. It warns when only one is set.
## 3. Where is it allowed to land?
By default a placement is surface-only, unlimited in height, unlimited in slope, and refuses to sit over a cave mouth. Each field below narrows one of those.
**Surface or cave.** `carvingSupport` sorts the entry into the surface list, the cave list, or both.
```json
{ "carvingSupport": "CARVING_ONLY", "caveAnchorMode": "FLOOR" }
```
`SURFACE_ONLY` (the default) rejects any anchor in carved space. `CARVING_ONLY` requires carved space at the anchor or within three blocks below it, and hunts for an anchor Y inside the cave column instead of using the terrain surface. A biome-owned cave placement accepts only cells owned by that exact cave biome; a region-owned one spans every cave biome in the region. Unless `underwater: true` opts into fluid anchors, the anchor must be dry carved air above the dimension cave-lava height. `ANYWHERE` sits in both lists, so it rolls `chance` **twice** per chunk, once for each pass. A cave pass resolves its biome by sampling 48, 80, and 112 blocks down and taking the deepest sample that differs from the surface biome.
`caveAnchorMode` picks which carved cells count. `FLOOR` needs solid support below. `CEILING` needs solid above. `CENTER` needs neither. `ANY` takes anything carved. `PROFILE_DEFAULT` defers to the cave profile ([15 - Caves & Carving](/iris/15-caves-carving)). `CEILING_HANG` overrides this to `CEILING` regardless of what you wrote. Later placement retains the underlying cave-fluid boundaries used to select anchors. Authored subterrain floors, shelves, rims, seals and pillars are protected, as are reserved passage cells. A placement touching those protected cells is rejected even when another cave crosses the room.
**Height band.** `clamp` rejects placements whose resolved top or bottom leaves the band.
```json
{ "clamp": { "minimumHeight": 40, "maximumHeight": 225 } }
```
These are engine-internal Y values: 0 to (dimension height), not world Y. In a `-64..320` dimension, world Y 0 is internal Y 64.
**Slope.** `slopeCondition` gates on the terrain slope sampled around the anchor column.
```json
{ "slopeCondition": { "minimumSlope": 0, "maximumSlope": 2 } }
```
The default (`0` to `10`) is treated as "no condition" and skips the check entirely. `maximumSlope: 2` keeps buildings off hillsides. Going below about 1 excludes nearly all natural terrain. `rotateTowardsSlope: true` finds whichever of the four footprint edges sits lowest. It rotates the object to face that way in 90 degree steps. It adds the `yAxis` `min`. It discards `yAxis` `max` and `interval`.
**Neighbors.** `forbiddenCollisions` lists object keys this object refuses to intersect. If any block of an already-placed object with that key falls inside this object transformed bounding box, the attempt is dropped. Rotation, rotated translation, warp reach, ceiling inversion, and random Y translation are included. `allowedCollisions` names exceptions that win over the forbidden list. Both are empty by default. The check only runs when at least one of them is non-empty.
Overlapping surface and cave objects on the main terrain use a repeatable placement order for the same pack and seed, including parallel chunk generation. Empty collision lists permit overlaps without making their result depend on which chunk generates first.
**Overrides.** `forcePlace: true` (JSON also accepts `"force"`) skips the usual placement gates. Those gates are the slope check, the carving-anchor check, surface support, underwater rejection, fluid-height and cave-height checks, `clamp`, the bedrock guard, and the collision lists. It does **not** skip the native-structure veto or the automatic water veto. An object whose blocks would land inside a vanilla or datapack structure piece is always rejected, forced or not.
## 4. Surface support
Iris refuses surface objects that roof over, bridge, or overhang a carved opening. It takes the object lowest solid non-foliage layer and rasterizes those columns. It dilates the stencil by `surfaceSupportBuffer`. Every column in the result must have `surfaceSupportDepth` blocks of un-carved, surface-solid ground. A failure drops the placement with **no log line at all**. That makes it the usual cause of "my object never appears" near caves, canyon rims, and ravines.
Natural scatter also rejects a surface placement whose support columns intersect the water, shore or dam columns of a river, pond, lake or sea inlet mouth; banks stay open. `forcePlace`, `underwater`, `onwater`, and `requireSurfaceSupport: false` **do not** bypass that water exclusion; only an explicit-Y call such as `/iris object paste` can build in the water.
Native structures reserve their piece bounds and the surface cut area of `FLATTEN` terrain adjustments. An object intersecting that reserved area is skipped as a whole, including forced placements. This keeps trees from relying on ground that a village or other native structure removes. Objects beneath the cut area remain eligible.
Procedural trees check the trunk base and root footprint. Their roots fill short gaps to solid terrain within the configured reach, and unsupported cliff placements are skipped. See [Procedural Trees](/iris/17b-procedural-trees#ground-contact) for root settings.
```json
{ "requireSurfaceSupport": true, "surfaceSupportBuffer": 2, "surfaceSupportDepth": 2 }
```
The dimension acts as a floor, not a ceiling. The effective buffer is `max(placement, dimension)` and the guard is on only if both the placement and the dimension ask for it. A dimension can therefore widen the ring or force the guard on pack-wide. It can never loosen it. `surfaceSupportDepth` is not merged. The placement value is used as written.
The check is skipped entirely for `forcePlace`, `fromBottom`, `mode: FLOATING`, `mode: STRUCTURE_PIECE`, `underwater`, `onwater`, cave-anchored placements, and `requireSurfaceSupport: false`.
Loosen in this order, stopping as soon as the object appears: `surfaceSupportBuffer: 0`, then `surfaceSupportDepth: 1`, then `requireSurfaceSupport: false`, then `force: true`, and only then the dimension-wide switch.
A second guard rejects surface-anchored placements that resolve to y