Object placement in 2D/3D always runs the same core loop:
select
→ target
→ preview
→ validate
→ confirm
→ validate again
→ commit
→ record placement/occupancyThe preview is only a suggestion — final validation runs again at commit time, and that second check is what actually decides whether the object appears.
Terminology used below: a placement entry (ScenePlacementEntry) is the resource describing the object; a placeable is the catalog thing being placed; manipulation is what happens to it after commit. See Architecture Overview for the glossary.
Object placement
1. Select
The active PlacementSession selects a ScenePlacementEntry. Profiles/categories on the entry decide which tools and reusable rules apply to it.
2. Target
Where you're aiming depends on the coordinate mode/dimension:
- 2D GRID → a
TileMapLayercell. - 3D GRID → a
GridMapcell/EDGE/FACE/CORNER/TOP mount. - SMOOTH → a free world-space position/footprint.
3. Preview and validate
The preview shows where the object would land, plus current valid/blocked feedback. Validation may check:
- bounds/surface/support;
- occupancy and mounts/sockets;
- collision/environment;
- profile/custom rules;
- your game's own world facts/cost restrictions.
Show the placement result in your UI rather than re-implementing the rules yourself — the plugin already computed them.
4. Commit
Confirming runs the full validation one more time. On success the plugin:
- creates the object;
- updates placement identity and occupancy/mount state;
- emits the lifecycle/result signals;
- keeps save/manipulation state consistent.
On failure, nothing changes — the world stays exactly as it was.
Object LINE placement
Object LINE must be turned on per profile/category — it's off by default.
start line
→ drag to end
→ preview generated placements
→ confirm/release
→ validate generated placements
→ commit according to the supported line policyUse it for repeatable objects such as posts/fence-like props, when each result should still be its own scene object.
2D terrain painting
Terrain painting applies only to TileMapLayer in the 6.0 public contract.
| Brush | Interaction |
|---|---|
SINGLE |
Preview one cell → confirm. |
LINE |
Drag start→end → commit generated line. |
RECTANGLE_FILL |
Drag corners → commit filled region. |
RECTANGLE_OUTLINE |
Drag corners → commit perimeter. |
FLOOD_FILL |
Anchor/preview region → second confirm commits. |
The real TileMapLayer must not mutate during preview.
Large generated brushes are bounded by PlacementSettings.max_terrain_brush_cells; see Surface & Brush Reference.
Cancel and selection changes
Cancel/change-mode/change-selection should clear transient preview/pending state without changing committed placement/terrain.
When your game wants single-shot placement — place one object, then leave that selection — call the host deselection API after the successful commit:
if placement_succeeded:
host.deselect_placeable_for_session(session)Use this instead of calling clear_preview() directly. Preview cleanup is an internal part of deselection; the host API also clears the authoritative selection, synchronizes the UI, restores brush state, and transitions placement mode consistently. Single-session games can use host.deselect_placeable().
This also applies when a session/controller is unregistered or the owning scene exits.
Manipulation
Move/rotate/flip/demolish go through the plugin's manipulation path, never by moving nodes directly from your UI code.
That matters because proper manipulation keeps all of these in sync:
- the object's transform;
- occupancy/mount/socket state;
- validation;
- stable placement identity;
- save data;
- optional refund behavior.
Move a node by hand and some of those quietly drift out of sync — usually noticed much later, when saving or demolishing misbehaves.
See Manipulation: Service vs Parent.
Side effects
A committed placement means the plugin performed the placement operation; it does not mean your game's authoritative entity exists. Game consequences belong to the game.
Hook your game's reactions in at the right lifecycle moment:
- change inventory/costs only after placement actually succeeds;
- configure a new instance through the supported pre-add hook;
- update quests/progression from successful placement/removal results;
- hand out refunds only after demolition succeeds.
Never spend the player's resources or trigger progression because a preview happened to look valid — previews can still be refused at commit.
3D support-specific workflow
GRID structure placement adds mount/support decisions to the same loop:
target CELL/EDGE/FACE/CORNER/TOP
→ resolve support/slope
→ preview + indicators
→ final validation
→ commit canonical mount/occupancy recordSMOOTH adds world-footprint occupancy and optional world sockets instead.
See 3D Object Placement and Grid vs Smooth Placement.
Common failures
- missing/incorrect level context;
- a UI panel consumes the placement input;
- the targeting collision mask can't see the intended surface/object;
- the target cell/object is already occupied;
- a GRID mount/provider is incompatible or occupied;
- the slope/support policy rejects the 3D footprint;
- the SMOOTH footprint is missing;
- your own game rule/world fact rejects the action.
Read the returned failure report first, then fix the thing it names — don't bypass validation to make the error go away.