# Placement, faces and frames

[Start here](https://pegmatite.dev/guide/start.md). Fetch this topic when a solid must land at an exact position, on a side face, in a turned frame, or against a volume built earlier.

## Reference and default direction

A solid is placed against its **reference**: the previous volume of the current context, a face selected with `on`, or a labelled volume. The first solid starts at the context's origin. Placement uses a volume's **slot**, usually its bounding box; `set` and `!color` create none. Slots, cuts and what a cut leaves as reference are in [booleans](https://pegmatite.dev/guide/booleans.md).

Without an anchor an ordinary solid follows local `@top`; after `-`, `&` or `^` it follows `@bottom`.

## Anchors

| Axis | Towards the reference's | and its  |
| ---- | ----------------------- | -------- |
| x    | `@left`                 | `@right` |
| y    | `@front`                | `@back`  |
| z    | `@bottom`               | `@top`   |

`@right 5` leaves a 5 mm gap. An anchor sets the alignment and gap of its one axis; the other axes keep their own settings. `@center` names no axis and centers the solid inside its reference on all three. An anchor is a setter: it precedes its solid and takes `!`.

```pegm
!@right
block 10 10 10
block 10 10 20   // a row along X
```

A persistent anchor also applies at the origin. It is ignored for the first solid built against a selected face and applies again to the solids after it.

## Alignment

**Syntax:** **`x`** [_align_] [_offset_]

**Syntax:** **`y`** [_align_] [_offset_]

**Syntax:** **`z`** [_align_] [_offset_]

Each axis holds two separate settings, an alignment and an offset, resolved in order: the anchor supplies its axis's alignment and its gap the offset; `x`, `y`, `z` override whichever of the two they name; the rest defaults to centered on x and y, base on z. `unset` clears both. Several setters share a line, `@top x right z top cube 10`; unnamed axes keep what is in force.

An alignment pairs a point on the reference with a point on the volume, `reference:volume`. A point is a percentage of its box:

| Setter | `0%`     | `50%`    | `100%`  |
| ------ | -------- | -------- | ------- |
| `x`    | `left`   | `center` | `right` |
| `y`    | `front`  | `center` | `back`  |
| `z`    | `bottom` | `center` | `top`   |

One point applies to both boxes: `x right` is `x right:right`, `x 25%` is `x 25%:25%`. Names and percentages mix, `x right:center` equals `x 100%:50%`.

```pegm
cube 20
@right x right:left cube 10    // beside it, touching
@right x right:center cube 10  // straddling the previous cube's right face
@right x 100%:25% cube 10      // a quarter of it inside that face
```

The offset is signed and runs along the positive axis whatever the alignment, so `x right 4` is 4 mm outward and `x left 4` 4 mm inward. An offset alone keeps the alignment, and settings from different places combine:

```pegm
cube 10
!@right 5
cube 10       // gap 5 from the anchor
x 10 cube 10  // gap 10: x overrides the offset, the anchor still aligns
@top 5 z top cube 4  // alignment from z, offset from the anchor
```

The axes are those of the placement frame, not the world: after `on #front` of an unrotated block, `x right` points to world +X and `y back` to world +Z.

## Faces

**Syntax:** **`on`** _reference_

| Reference          | Builds the next solid against                            |
| ------------------ | -------------------------------------------------------- |
| `on #front`        | that face of the previous volume                         |
| `on #bounds.front` | that face of its axis-aligned bounding box               |
| `on base`          | the volume labelled `base`, in the current frame         |
| `on base #front`   | that face of the labelled volume                         |
| `on root`          | the origin of the current context, compound or macro     |
| `on root #front`   | that [build plane](https://pegmatite.dev/guide/placement.md#build-planes) of the current context |

A bare `on` is invalid. Faces are `#top #bottom #left #right #front #back`, the faces of the bounding box. `on` builds against any of the six, even where the box only touches the solid, so spheres stack on `on #top`. Everywhere else, in a [face shape](https://pegmatite.dev/guide/shapes.md), an edge selector or `rotate about`, a direction names a flat side the solid has in that plane, so a sphere has none and a dodecahedron only `#top` and `#bottom`; `#bounds.front` names the box's face. An unknown name is reported with the names the solid offers. Prisms and polyhedra add [numbered faces](https://pegmatite.dev/guide/solids.md) `#f1` ….

A face is a frame: local X and Y run across it as seen from outside, local +Z points outward. The solid stands on it with its base and is centered unless aligned. For an unrotated parent:

| Face      | Local +X | Local +Y | Local +Z (outward) |
| --------- | -------- | -------- | ------------------ |
| `#top`    | world +X | world +Y | world +Z           |
| `#bottom` | world +X | world −Y | world −Z           |
| `#front`  | world +X | world +Z | world −Y           |
| `#back`   | world −X | world +Z | world +Y           |
| `#left`   | world −Y | world +Z | world −X           |
| `#right`  | world +Y | world +Z | world +X           |

A turned parent turns its face frames. Following a face orients, an anchor does not: `@bottom cone 12 8` hangs an upright cone under a block, `on #bottom cone 12 8` points its tip down. A macro written upright therefore works on any face, and a solid after it follows its local +Z.

### On a face

The first solid on a face takes no side anchor; align it with `x` and `y`. `@top` and `@bottom` are allowed, and a gap lifts it off the face, `on #top @top 5 cube 10`. Solids after the first follow each other, so an anchor there makes a row.

```pegm
block 50 50 10
/* Expected error: an anchor cannot move the first solid across a selected face. */
on #top @right cube 10
```

```pegm
block 50 50 10
on #top
x left y front cube 10
@right 2 cube 10
```

`@top` continues in the current frame; `on #top` takes the face's rotation. They agree on an unrotated box.

### Build planes

Before any volume exists, `on #face` selects the plane the context grows from. `on #top` is the default ground plane; `on #front` stands a block up, its depth running upward and its height toward the viewer; `#back`, `#left`, `#right` and `#bottom` turn the other ways. The model still rests on the ground, and every solid of the context follows that plane. Once a volume exists, `on #top` names its face:

```pegm
on #front
cube 10
on #top cube 4   // grows toward world front, not world up
```

Inside a compound or macro body write `on root #front`; a bare face before the body's first solid is an error, since it would name the volume outside. `on root #front` also works at top level.

### Face identity

A face name is an identity: it follows the solid through `rotate`, `scale` and `flip` and is never renamed. After `rotate 90 about z`, `#left` is the same facet, now facing −y; after `flip x`, `#left` is on the right. Numbered faces behave the same. An initial `on #front` makes a solid's `#front` face world down, `#back` up, `#top` front and `#bottom` back. `#bounds.` names a face of the axis-aligned box instead, for the six standard faces only:

```pegm
cube 20 | rotate 30 about x
[
  on #top cube 10         // flat on the tilted face
  on #bounds.top cube 10  // level, on the box's roof
]
```

Selectors that measure, `parallel z` or `(x > 0)`, read coordinates after the pipeline.

## Labels

`name:` labels the volume its statement builds. It stands among the solid's qualifiers or before the `on` leading into it: `base: @left cube 10`, `@left base: cube 10` and `base: on #front cube 10` are all valid, at most one per statement, and never before a face list.

| Form             | Meaning                                                    |
| ---------------- | ---------------------------------------------------------- |
| `on name`        | build against the volume; an anchor works across it        |
| `on name #front` | build against that face of it                              |
| `name.width`     | [measure](https://pegmatite.dev/guide/expressions.md) its slot, also `depth`, `height` |

`on name` retargets placement only; persistent settings stay. A label is visible after its solid, in its script or list and nested lists, and on compounds and macro calls as on any solid. `on` never reaches a label across compound or macro braces; a measure reads one from outside a compound, not into a macro body.

```pegm
base: cube 20 [ on #top cube 4 ]
on base @left cube 6
```

## Lists

Each item of `[ … ]` starts from the reference in force at `[`, and `]` restores it with the settings and labels of that point. A list opens from what the statement before it left: a volume, a pattern's box, or a face named by `on`. With nothing before it, it opens from the context's plane, so a bare list's items share the origin.

Items branch, sequences follow: a second `on #front` in a list names the parent's face, and two items with the same face and settings overlap. Persistent setters inside a list reach later items until `]`; one-shot setters do not cross items. A pattern's iterations are not items, so `repeat 4 cube 10` in a list still makes a row. A build plane chosen in an item reaches that item only. To continue from an item, open a nested list right after it:

```pegm
block 40 40 10 [
  on #top block 20 20 10 [
    on #top cube 6
  ]
]
@right cube 10   // against the base block
```

`on` [_label_] **`[`**_face_ …**`]`** _statement_ writes one item per face. It is that list: each item starts from the reference at the `on`, and without a label the faces belong to the previous volume. The statement may carry its own `on` or be a list; `on box [ cube 2 ]` is `on box` followed by a list.

```pegm
box: prism 6 edge 50 50
on box [#f2 #f3 #f4 #f5 #f6 #f7] -cylinder 10 3
```

## Compounds

`{ … }` fuses its statements into one solid that takes setters and anchors like any solid and is the previous volume after `}`. Its faces come from the box over the slots that add material, including an empty [`slot`](https://pegmatite.dev/guide/booleans.md); the material keeps its place in the box. A `-` or `&` cutter adds nothing to the box, so a through hole leaves the compound the size of its solid. Macro calls follow the same rules. A color before the braces applies to the body; colors inside do not escape.

```pegm
{
  cube 20
  @center -cylinder 8 30
}
@right cube 4   // beside a 20 mm compound
```

A compound has its own root context. A list closes inside the body, `on root` returns to the body's ground plane and `on` reaches no label outside; a measure does, `base: cube 20 { cylinder 4 base.height }`. `on root #front` first in the body builds the compound in its own orientation; to place the whole compound against a face write `on #front { … }`.

```pegm
block 30 20 5
{
  on root #front
  block 30 20 5   // an upright panel on the block
}
```
