# Part IV. Compiler

A compiler derives a model's geometry and quantities from its records, as a compiler derives a program from its source. The records are the only source; what the compiler produces is build output.

## 1. What is derived, and never stored

1. These are derived: bodies and meshes; the layers' bodies; joins between walls and between members found from geometry; openings cut in their hosts; room boundaries, areas and volumes; quantities; members derived from a framing rule or a truss layout; stair runs, landings and treads; railings' balusters; MEP fittings; the elements of placed copies; drawings.
2. Implementations MUST NOT store derived results in records or in record files. A cache of derived results MAY live outside the model (for example in a hidden folder) and MUST be keyed by the records it was derived from.
3. Derived results MUST be a function of the model alone: the same records give the same results, whatever order the elements are in.
4. A compiler derives no body for an element of a category it does not know (Part I, 10, rule 5). Where such an element carries declared geometry of its own in the `world` frame, the compiler MAY place it as section 11.1 says; a type's declaration it cannot place, since a type's frame depends on its category. It says, for each such element, which it did.

Reference: `solids` in `src/core/geometry/geometry.ts` builds every body from the model, and nothing it builds is written by `eikFolder`; the reference tests build a model whole and part by part and require the same bodies (`buildSolids`, "each build is made both ways").

### 1.1 The derived layer

For results that are hard to derive (a wall top attached to a pitched roof, joined members), a writer MAY add an optional derived layer beside the records, in the hidden folder `.eik/derived/`.

1. A derived file MUST name every record it was derived from, by id and by hash (Part III, section 6), and the implementation and rule that produced it.
2. A reader MAY use a derived result only after checking that each named record's current hash equals the one recorded. If any differs or is missing, the reader MUST discard the result and derive it again or do without.
3. A derived file is never a record. A reader MUST NOT read model data from it, a validator MUST NOT require it, and it is not part of a version's tree or of a merge.
4. A model MUST be complete without it: deleting `.eik/derived/` loses nothing.

The file layout inside `.eik/derived/` and the form of each result are not fixed in 0.1; 0.2 fixes them (decided 11 October 2026), in section 1.1.2. A shape that meets the rules is the one 1.1.2 gives: `.eik/derived/elements/<id>.json` holding `{"sources": {"<key>": "<hash>", …}, "producer": "<implementation> <version>", "rule": "<rule name>", "result": {"bodies": […]}}`.

*Note (informative).* The derived layer was decided on 11 October 2026 and is not yet in the reference implementation's folders; until it is, the reference `ek` command derives these results on request (`ek request`, Part VII), and the reference implementation hands its bodies to a bridge as results of 1.1.2's form (`eikBodyResults`).

### 1.1.1 A result's bodies

*Part of 0.2. OpenEik 0.1 had it as an informative section, the proposal `derived`.*

By the steward's decision of 26 October 2026, the reference implementation and a host print IFC with one writer, the bridge of `@openeik/tools` (Part VIII, 1), and an application hands it the bodies this specification does not derive yet, until it derives them all. So that what it hands is the derived layer's own form and not a bridge's, this section gives the first part of the form of a result: a result's bodies, in `schemas/0.2/derived/bodies.schema.json`.

A result has the form section 1.1.2 gives, `{sources, producer, rule, result: {bodies, …}}`: its sources by key and hash (1.1, rule 1), so that a reader uses it only while they hold (1.1, rule 2); its producer as people read it (`Acme Modeller 2.31`); its rule, by the producer's name for it; and its record's bodies, in the producer's order. A result is of one record: an element's bodies, or a type's representation, which its elements place. Handed from one tool to another, results are keyed as sources are: `elements/<id>`, `types/<id>`. Coordinates are in millimetres, z up (Part I, 3): an element's in the model's coordinates, a type's in its own frame.

| Kind | Members | A body |
|---|---|---|
| `extrusion` | `profile`, `holes`, `z0`, `height` | a plan polygon, counter-clockwise seen from above, less its holes, each clockwise, from `z0` up by `height`: a prism with a level underside and top (section 8, N1) |
| `faces` | `vertices`, `faces` (each `{outer, holes}`, indices from 0), `normals` | plane faces, each counter-clockwise seen from outside, its holes the other way, and a normal per vertex where the body is smooth (N2, N6) |
| `rod` | `from`, `to`, `diameter` | a round bar (N5) |
| `cylinder` | `centre`, `radius`, `z0`, `height` | an upright cylinder, such as a round pier (N5) |
| `swept` | `section`, `from`, `to`, `roll` | a section of Part II, 5.2, or a polygon in its own plane, carried straight from one point to the other in a member's frame, the middle of its bounding box on the line, turned by its roll as a beam's is (sections 6.1 and 6.2, rule 5; N4) |
| `mapped` | `type`, `origin`, `xAxis`, `zAxis` | the representation of a type (its element's own where it names none), placed at `origin`, its frame's x along `xAxis` and its z along `zAxis` |

`holes`, `normals`, `roll`, `type`, `xAxis` and `zAxis` may be left out. Each body may carry tags: its `material`, by the name of one of the model's materials or a name of its own; the `layer` of its element's type it is, by the layer's id (Part II, 5.1), which gives its material and colour where it names none; the `part` of its element it is, on the body of any element, by a name of the producer's: a door's or a window's `frame`, `sash`, `glass`, `leaf`, `panel`, `casing` or `handle`, a railing's `post`, `rail` or `baluster`, a truss's `topChord` or `strut`, and the like; the `piece` of its element it is, a part written apart (a stair's `flight:0`, `winders`, `landing:0`, `stringer:0:left`, `beam`, `newel`, `column`, `bearing:0:left`); the framing `member` it is, `{id, class, predefined, objectType, name, section}`, its id unique in the model and all else optional; its `color`; and whether it is `glass`.

An element's parts are the distinct names its bodies give in `part`, and a type's those its representation's bodies give; each part is the bodies that name it, with their material. Where they are two or more, a bridge writes each as a material of its own and the shape of its bodies (Part VIII, 1, its note on given bodies). One part, however many bodies name it, adds nothing: the element keeps the material it has without parts, its type's, or a plain material (open question 91).

*Note (informative).* The kinds and tags are those the reference implementation reads its own bodies in (its work 727, `eikBodies`), with the names it gave them, but for `member`, which it gives as an id alone. `rod`, `cylinder`, `swept` and `mapped` were added so that a round bar, a pier and a profiled member need not come as triangles, and a body that many elements share, a bolt or a bracket, comes once. By the steward's decision of 30 October 2026 (open questions, 98), a result in a folder's derived layer holds its bodies in these kinds alone, as one handed between tools does, and a type's result lies at `.eik/derived/types/<id>.json` (1.1.2).

### 1.1.2 The derived layer's layout and a result's form

*Part of 0.2. OpenEik 0.1 had it as the proposal `derived`: in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), the layout and the form are open (1.1), and what this section says meets their rules; no file of 0.1 is held to it.*

By the steward's decision of 30 October 2026 (open questions, 98), which completes the decision of 11 October 2026 (open questions, 11):

1. **The layout.** A result is of one record, an element or a type. An element's result lies at `.eik/derived/elements/<id>.json` and a type's at `.eik/derived/types/<id>.json`, its id written as a path segment (Part III, 2), so that a result's path says its key, the key its sources and a bridge (1.1.1) name it by: `elements/<id>` or `types/<id>`, the path less `.eik/derived/` and `.json`, its segment read back as an id. A file elsewhere in `.eik/derived/` is no result, and a reader ignores it.
2. **A result's form.** A result is one JSON object `{sources, producer, rule, result}`: its `sources` (rule 3); its `producer`, the implementation that derived it and its version, as people read it; its `rule`, the rule or the set of rules it was derived by, by the producer's name for it; and its `result`, `{bodies, quantities?, line?}`. `bodies` are the record's bodies in the kinds of section 1.1.1 alone, with its tags, in the producer's order, which a reader keeps: an element's in the model's coordinates, a type's in its own frame. `quantities`, an element's, are its quantities by their names, each `{value, unit, basis, rule}`, its unit `m3`, `m2`, `m` or `count`, with `layers`, a quantity by each of its type's layer ids, as section 9 reports them. `line`, a beam's or a column's, is its lines of section 6.5: its `reference` line and its `axis`, each from its start to its end or `null`, a beam's `setOut` line, its `centroidOffset` or `null`, its `section`, `{shape, width, depth, endDepth?, area}`, its area `null` where it is not derived, and its `length`. A result holds nothing else. `schemas/0.2/derived/bodies.schema.json` states the form.
3. **Its sources.** `sources` names, by its key, each record and each set of records whose change may change the result, with its hash (Part III, 6), or `null` where the model has none of that key:
    - `<list>/<id>`, a record of a list (`elements/<id>`, `types/<id>`, `materials/<id>` and the others), `levels`, the levels record, and `project`, the project record;
    - `referrers/<id>`, the elements that name the element by `hostId` or by a join's `to` (Part II, 7): the hash of the list of their ids, in code-unit order, so that a door added to a wall, or a mitre written in another member's record, makes the result stale;
    - `categories/<category>`, every element of a category: the hash of the list of their records, in the order of their ids, where any element of it may change the result wherever it is, as a shaft opens a slab (4.2, rule 8) and a roof of a group buries a gutter (4.7).

    A result names at least its own record.
4. **When it is current.** A reader uses a result only while each of its keys has, in the model, the hash it names, `null` among them: a record named as missing that is there now makes the result stale, as one that changed or went does (1.1, rule 2).
5. **Several producers.** A folder holds one result per record. A writer that derives a record's result writes it in place of the one there, whoever wrote that. A reader that wants its own rules' result compares the result's `producer` and `rule` with its own, and derives it again where they differ.
6. **Never in a version.** Rule 3 of section 1.1 stands: a result is not part of a version's tree, of a merge, or of what a version carries from a host to a tool (Part VI), and no reader takes one from a version. A host or a bridge that prints a version prints what this Part derives from its records; where an application hands it results (1.1.1), they are results of the application's own folder, used only while current against the version's records (rule 4). Every body a print needs gets a rule of this Part in its time, so that each host prints from a version alone what the application printed.

*Note (informative).* Rule 6 is the 0.2 plan's decision D10, which the steward took with question 98. `derivedLayer` of `@openeik/tools` writes each element's result in this layout and form, its bodies the compiler's own (section 8) in 1.1.1's kinds; `derivedCurrent` says whether a result is current; and `readDerived` reads a folder's layer, using what is current and saying why it uses no other file (`derived-path`, `derived-form`, `derived-stale`), none of which makes a model invalid (1.1, rules 3 and 4). The reference implementation hands its bodies in this form (`eikBodyResults`), keyed `elements/<id>`, and writes no `.eik/derived/` yet (open questions, section 2, row 8).

## 2. Rule classes

| Class | What | Status in 0.2 |
|---|---|---|
| A | Closed-form rules: layered extrusions, a slab's sloped plane, outline edges trimmed to a wall's face, roof planes, attached tops, member sweeps, a framing family's parts, rectangular openings and a door's and a window's frame, leaves and glass, shafts' openings, slab edge elements and the thickened edges and fills of their hosts, gutters, the line and the given posts of a railing on an outline, a wall's top or a slab edge element, a generic element's declared bodies, a pipe's or a duct's run swept round its own bends; and, stated from the reference implementation's engines, straight, L and U stairs, a framed wall layer's members, a roof's truss layout and its hip ends, a floor's joists, a room's boundary, ceiling and quantities, and a component's frame and its bodies (sections 7.3 to 7.6) | Normative where this part states them |
| B | Rules that infer from geometry with tolerances: wall corner and T joins, member join extensions, room boundaries (but for those of section 7.5), MEP fittings between runs (branches, reductions, joints) | Reference behaviour (sections 7.1 and 7.2) |
| C | Product and practice engines: timber framing and trusses (but for those of section 7.4), stairs (but for those of section 7.3), precast, steel joints, regional area rules | Reference behaviour (section 7.2) |

A section that is part of 0.2 says what it is in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3): there its rules are reference behaviour, as this table had them in 0.1.

A compiler of the core class MUST implement the class-A rules of sections 3 to 6 (4.6 and 4.7 among them), 7.3 to 7.6, 11.2 and 12, and treat declared geometry and generic elements as sections 11.1 and 11.3 say. Where a class-B or class-C rule changes a body, a compiler MAY differ from the reference implementation; it SHOULD say where it does.

## 3. Conventions

The level semantics, the directed baseline and the layer order of Part I, sections 4 and 5, are part of every rule below. Throughout:

- `elev(l)` is the elevation of level `l`;
- for a wall or beam with profile points `P0`, `P1`: `L = |P1 − P0|` is the plan length, `u = (P1 − P0) / L` the plan direction, and `n = (−u_y, u_x)` its left normal;
- `T` is a type's total layer thickness, the sum of its layers' thicknesses.

## 4. Layered elements

### 4.1 Walls (N1)

Given a wall with base `z0 = elev(levelId) + offset`, height `H` (section 5.3) and a type with layers `t1 … tk` listed exterior first, the compiler MUST produce, before openings, joins, outline and attachment are applied, one body per layer of non-zero thickness:

- Layer `i` is the prism over `[z0, z0 + H]` of the quadrilateral spanned along `P0 → P1` between the offsets `d_i` and `d_(i+1)` along `n`, where `d_1 = T / 2` and `d_(i+1) = d_i − t_i`.
- A wall whose type has no layers is one body of thickness `width`, centred on the profile.

So the first layer lies on the left of the directed baseline, and the layers together fill `[−T/2, +T/2]` across it. The wall's `width` does not set its thickness when its type has layers.

The bodies are then: cut by the wall's hosted doors and windows (4.3); shaped at their ends by joins (7.1); limited to the wall's `wallOutline` when it has one (an elevation outline in wall coordinates: `x` along from `P0`, `y` up from the base); and limited by the wall's top (5.3).

Reference: `strip` and `basicSolids` (`wallWidth = thickness ?? e.width`), `layeredBodies` in `src/core/geometry/geometry.ts`; `layerBands` in `src/core/elements/wallJoins.ts`.

### 4.2 Slabs, foundations, ceilings and flat roofs

Given an element of category `slab`, `foundation`, `ceiling`, or `roof` without a `roof` payload, with top `z1 = elev(levelId) + offset` and outline `profile`, trimmed where its edges are trimmed to a wall's face (4.5):

1. Its thickness is `T` when its type has layers, else its `height`.
2. With layers `t1 … tk` listed top first, layer `i` is the prism of the outline over `[z1 − Σ_(j≤i) t_j, z1 − Σ_(j<i) t_j]`. A layer with an `inset` uses the outline offset inwards by the inset.
3. Without layers, the body is the prism of the outline over `[z1 − height, z1]`.
4. Each outline in `voids` is cut through every layer.
5. A foundation whose type has a round `footing` is a cylinder of the footing's diameter about the profile's single point, over `[z1 − T, z1]` (or `[z1 − height, z1]`).
6. **Thickened edges.** A slab or a foundation is thickened under its edges that carry a slab edge element whose type's `edgeProfile` has a `beam`, and its layers under its structure give way there, as section 4.6, rules 9 and 11 say.
7. **Chamfers' fills.** A slab or a foundation fills the corner a slab edge element's chamfer cuts off, under its structure's top, as section 4.6, rule 10 says.
8. **Shafts.** A shaft (Part II, 6.2), its outline `profile` between its base `elev(levelId) + offset` and its top (5.1), takes the prism of its outline from its base to its top out of every body of every slab, ceiling and roof it overlaps in height by more than 0.5 mm, whatever their levels; and a shaft whose type's `shaft.purpose` is `stair` out of every body of a foundation too. A body is one layer's (rules 2 and 3; a pitched roof's, 4.4, rule 4), or one band of a layer or of a thickened edge (4.6, rule 9), as built before any shaft cuts it, with its own lowest and highest points. Where the shaft's base lies under the body's lowest point or within 0.5 mm of it, the prism reaches through the body's underside; where its top lies over the body's highest point or within 0.5 mm of it, through its top; so no sliver is left. A body that lies wholly over the shaft's top or under its base within the shaft's outline, as a pitched roof can whose lowest points lie elsewhere, loses nothing to it. Walls, beams, slab edge elements, a chamfer's fill and, for any other shaft, foundations stay whole. A shaft that ends inside a body leaves what lies under its base or over its top within its outline: a recess. It takes an **opening** out of a host where it takes all of the host within its outline, and a **recess** where it takes some of it; a host it takes nothing of keeps neither; a bridge writes each (Part VIII, 1.3).

A shaft from 400 under level 0 to level 1 (3000) passes a slab 350 thick whose top is level 0: it takes its outline out of each of the slab's layers whole, an opening. One from 100 under the slab's top to 400 over it takes the top 100 mm of the slab out within its outline and leaves the rest under it: a recess. One whose base is the slab's top, or whose top lies 0.5 mm or less over the slab's underside, takes nothing.

Reference: `basicSolids` (horizontal branch and round footings), `layeredBodies`, `subtractHorizontalVoids`; `thickenedBodies` (`src/core/elements/edgeBeams.ts`) and `withChamferFills` (`src/core/elements/edgeChamfer.ts`) for rules 6 and 7; `shaftRange`, `shaftCutters`, `shaftHosts` and `stairOpeningHosts` in `src/core/elements/shafts.ts`, `subtractShafts` in `src/core/geometry/voidCuts.ts` and `shaftMeetings` in `src/core/elements/shaftOpenings.ts` for rule 8.

*Note (informative).* Rule 8 was decided by the steward on 26 October 2026 (open questions, 77), as the reference implementation cuts. A slab's, a ceiling's or a flat roof's area loses the shafts that pass through its whole thickness and keeps a recess, so that its area and its volume count the same floor; a foundation keeps its area (`floorAreaMm2` in `src/core/elements/shaftOpenings.ts`). The reference implementation's IFC export writes a recess as an OPENING too, and writes none in a foundation; it changes there (Conformance, 3).

### 4.2.1 A slab on a sloped plane

*Part of 0.2. OpenEik 0.1 had it as the proposal `slopedSlab`: in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), a slab's `plane` is a member a schema of 0.1 does not know, and the slab is built level, by section 4.2. The section adds that one member and no file (Part II, 6.3.1).*

By the steward's decision of 30 October 2026 (open questions, 111). Given a slab that carries a `plane` (Part II, 6.3.1), its top at a point p in plan, z(p), as Part II, 6.3.1, rule 2 gives it, a plane of gradient (g_x, g_y), its slope σ, z1 its `elev(levelId) + offset`, and k = √(1 + g_x² + g_y²) = 1/cos σ:

1. **Its layers** are laid square to the plane over its plan outline and cut plumb at its edges. With layers t1 … tn listed top first, layer i lies over the outline, trimmed where its edges are trimmed to a wall's face (4.5), between z(p) − k·Σ_(j<i) t_j and z(p) − k·Σ_(j≤i) t_j: a thickness measured square to the plane lies k times as deep vertically, as a pitched roof's layer does (4.4, rule 4). A layer with an `inset` lies over the outline offset inwards by the inset, as in 4.2, rule 2. Without layers, the body lies between z(p) and z(p) − k·`height`.
2. **Its openings.** Each outline in `voids` is cut plumb through every layer, as through a level slab's (4.2, rule 4) and a pitched roof's. A shaft takes its outline out of each layer's body as 4.2, rule 8 says, by that body's lowest and highest points.
3. **Its edges trimmed to a wall's face** (4.5). Its plane comes from its outline as recorded, as a pitched roof's planes do (4.5, rule 4): a plane given by an `edgeId` starts at the recorded edge, and one given by a `fall` at the recorded first point. Its outline is trimmed by 4.5, rule 2, and its layers fill what is left.
4. **Its quantities** (informative, as section 9) are a pitched roof's: its volume is its layers' bodies'; its `area` is its outline in plan, trimmed, its voids and the shafts through its whole thickness deducted, as a level slab's; and its `slopedArea` is its top face over that area, measured on the slope: the area in plan times k.
5. **Where other rules read its top.** A rule that reads a slab's top at a point reads the plane there: a column's base attached to it (5.2), at the column's centre, the plane, or the plane lowered by the slab's thickness times k for its underside; a wall's top attached to it (5.3), the plane lowered by the face's depth times k, as 5.3, rule 3 lowers a pitched roof's plane; a railing on its outline (11.2, rule 4), each point of the railing's line on the plane there, and each given post rising from the plane at its point; and a room's ceiling under it (7.5, rule 5): its underside, the plane lowered by its thickness times k, there everywhere, where its outline as recorded holds the room's point and none of its voids does, and where it lies more than 100 mm over the floor at the room's point. A rule that reads a slab's top as one height reads z1: which floors a level stands on (7.5, rule 1).
6. **What is not built on it.** A slab whose plane slopes MUST NOT host a slab edge element in 0.2: a validator reports one hosted by it (`slab-plane-edge`), and a compiler derives that element no body, and the slab no thickened edge and no chamfer's fill (4.6, rules 9 and 10), and says so. A slab whose plane slopes has no joists laid out (7.4.15), and is no floor a framed wall bears on (7.4.4, rule 4): a compiler says so.
7. **A level slab**, without a plane or with one of slope 0, is built by section 4.2 alone, as in 0.1, and every rule reads it as in 0.1. A plane a compiler cannot read, as a validator reports it (Part II, 6.3.1, rule 6) or its schema does, gives the slab no body, and the compiler says why (`slab-plane`).

These are class-A rules, held to the tolerances of section 10.

The ramp of Part II, 6.3.1, of a type whose layers are 50 mm of screed over 200 mm of concrete: k = √(1 + (1/20)²) = 1.0012492, so its screed lies from z = x/20 down to x/20 − 50.06, and its concrete on down to x/20 − 250.31. Its volume is 6 m × 2 m × 0.25 m × 1.0012492 = 3.003747 m³, its `area` 12 m² and its `slopedArea` 12.014991 m².

*Note (informative).* `compileModel` of `@openeik/tools` builds a slab with a plane so, each layer a prism of the outline between two planes, as it builds a pitched roof's layers, and reads the plane in an attached base or top, a railing on the outline and a room's ceiling. The reference implementation has no sloped slab (Part II, 6.3.1, its note).

### 4.3 Openings in walls

A door or window hosted by a wall removes, from every layer of its host, the box from `along` to `along + width` along the wall and from `z0 + offset` to `z0 + offset + height` up, where `z0` is the host's base. An opening whose type has an `outline` removes that outline's prism instead, the outline placed at the opening: a point `[x, z]` of it, in mm from the opening's start and its bottom, lies `along + x` along the wall and `z0 + offset + z` up, or `along + width − x` along it where the opening's `handFlipped` is `true`, which mirrors its shape along its wall as it mirrors its hinges (Part II, 6.5). The opening's own body (frame, leaf, glazing) is reference behaviour in 0.1; how its leaves and lights open is Part II, 6.5's.

*Note (informative).* By the steward's decision of 26 October 2026 (open questions, 71), 0.2 adds here a class-A rule for the frame, the leaves or sashes in their grid and the glass, from the sizes of the type's `openingFamily` or `windowFamily`, and draws them closed; the product's details (clearances, a threshold, a handle, glazing bars, casings, flashings, an inner sill, a garage door's panels and tracks) stay reference behaviour. Section 4.3.1 gives it.

Reference: `basicSolids` (wall branch: spans between openings).

### 4.3.1 A door's and a window's own body

*Part of 0.2. OpenEik 0.1 had it as the proposal `frames`: in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), a door's or a window's own body is reference behaviour, as section 4.3 says, and these members are members a schema of 0.1 does not know, kept (Part I, 10): a door family's `leafMaterial` (rule 14), and a family's profiles, an `openingFamily`'s `frameProfile`, `mullionProfile` and `sashProfile` and a `windowFamily`'s `frameProfile` and `mullionProfile` (rule 15). The section adds no file, and those members: the sizes are those of a type's `openingFamily` and `windowFamily` (Part II, 5).*

By the steward's decision of 26 October 2026 (open questions, 71), a door or a window hosted by a wall, whose type has an `openingFamily` or a `windowFamily`, has a body of its own: its frame, its leaves or sashes in their grid, and its glass, each a box or a prism, or, where its family gives a profile, a member's profile carried along it (rule 15), drawn closed. A door or a window whose type has neither family keeps its body reference behaviour. A declared envelope stands in place of these bodies as of any other (11.1, rule 2).

Every size is in the opening's own frame: **x** along its wall from the opening's start, `along`, towards the wall's second profile point, along `u` (section 3); **y** across the wall along its left normal `n`, from the wall's axis, so that the wall's exterior face is at y = T/2 and its interior face at y = −T/2 (4.1); and **z** up from the opening's bottom, the host's base plus the opening's `offset` (4.3). `W` and `H` are the element's `width` and `height`, `T` its wall's thickness. A box x0…x1, y0…y1, z0…z1 is a prism of its plan rectangle from z0 to z1; an outline (x, z) in the wall's plane carried across from y0 to y1 is a prism across the wall. Every body names its part (1.1.1): `frame`, `sash`, `leaf` or `glass`.

For an `openingFamily` f, its sizes `frameWidth` (fw), `frameDepth`, `sashWidth` (sw), `sashDepth`, `mullionWidth` (mw), `glassThickness`, `leafThickness`, `wallOffset` and `gapInsulation` (g):

1. **What is drawn.** Each part below is drawn where each of its extents is more than 0.01 mm, and an outline where its area is more than 1 mm². Where the family's sizes leave no room for its frame, a light's sash or glass, or a leaf's glass, or its glass is thicker than what holds it (a frame's or a sash's depth, a glazed leaf's thickness), the compiler derives no body of its own for the opening and says why (`frames-fit`). A validator SHOULD warn of such a door or window, which it can tell from the records alone.
2. **Across the wall.** The frame runs from y = yExt − d to y = yExt, where yExt = T/2 − `wallOffset` and d = `frameDepth`; where `frameFollowsWall` is true, d = T and `wallOffset` is 0, so that it spans the wall. It is measured from the exterior face whatever the element's `flipped` says.
3. **The frame.** It stands g inside the opening at its sides and its head, and, for a window, at its bottom: fx0 = g, fx1 = W − g, fz0 = g for a window and 0 for a door, fz1 = H − g. Its members are fw wide and as deep as the frame: two jambs, fx0…fx0+fw and fx1−fw…fx1, from fz0 to fz1; a head between them, from fz1−fw to fz1; and, for a window, a sill between them, from fz0 to fz0+fw. A door and a garage door have no sill. The clear opening is ix0 = fx0+fw to ix1 = fx1−fw, and iz0 = fz0+fw for a window, fz0 for a door, to iz1 = fz1−fw.
4. **A window's lights.** Its columns divide ix0…ix1 and its rows iz0…iz1: `lightsX` columns, and `lightsY` rows, each (span − (n − 1)·mw)/n, mw apart; or, where `mullions.x` (`mullions.z`) gives mullions, the fields between them, each mullion centred at fx0 + `at` (fz0 + `at`) and as wide as its `width`, else mw, in the order of `at`. Between two columns a mullion runs the clear opening's height, iz0…iz1; between two rows a transom runs across its column. Mullions and transoms are frame members, as deep as the frame.
5. **A fixed light**, where `operable` is false: its glass fills it, `glassThickness` thick, centred in the frame's depth.
6. **An opening light**, where `operable` is true: a sash fills it, from y = yExt − 12 − `sashDepth` to y = yExt − 12, 12 mm behind the frame's exterior face; its stiles run the light's height and its rails between them, each sw wide. Its glass fills the sash's inside, `glassThickness` thick, centred in the sash's depth.
7. **A door's leaves.** A door of the kind `door` has `lightsX` leaves, and one of the kind `garageSideHinged` its `panels`, side by side, each (ix1 − ix0)/n wide, from fz0 to iz1, `leafThickness` thick and centred in the frame's depth.
8. **A glazed leaf.** Where a door's `glazing` is `full` or `upper`, a leaf x0…x1 from z0 to z1 has stiles sw wide its whole height and a top rail sw deep; its glass runs from gz0 to z1 − sw, where gz0 = z0 + 2·sw for `full` and z0 + (z1 − z0)/2 for `upper`, between the stiles, in `lightsY` rows mw/2 apart, centred in the leaf's thickness, `glassThickness` thick; the rest of the leaf, below gz0 and between the rows, is leaf.
9. **A sliding door** (`operation: slide`, Part II, 6.5, rule 4), closed. A single leaf covers the whole opening, x 0…W and z 0…H, on the face of its wall on the side it opens to (Part II, 6.5, rule 2), its face 10 mm from the wall's: from T/2 + 10 to T/2 + 10 + `leafThickness`, or the mirror of that on the interior. Of several leaves, laid out as rule 7 lays them, counted from the hinge side (Part II, 6.5, rule 1), the first, the third and so on stay and the others slide; with m = yExt − d/2 the frame's middle, the tracks run from m + 3 to m + 3 + `leafThickness` and from m − 3 − `leafThickness` to m − 3, 6 mm apart, and a leaf that slides runs on the track on the side the door opens to, a leaf that stays on the other. A pocket door (`operation: pocket`) is laid out as rule 7 lays it.
10. **A garage door** of the kind `garageSectional`, `garageRoller` or `garageFolding` has the frame of rule 3, and one leaf closing its clear opening, ix0…ix1 from fz0 to iz1, `leafThickness` thick and centred in the frame's depth.
11. **A shaped opening**, whose type has an `outline` (4.3): its frame follows the outline as its wall is cut by it, mirrored where its `handFlipped` is `true`. The outline counter-clockwise, its edges are moved inwards by g (the gap's outline), and those again by fw (the frame's inner outline), each corner where its two edges' lines meet; a door's edges that lie on its bottom, within 0.5 mm of z = 0, are not moved and take no member. Each other edge's member is the quad between the edge on the gap's outline and the same edge on the inner one, mitred at the corners. Where the gap's outline does not exist, the outline is the gap's; where the inner one does not, the whole gap's outline is frame, and nothing else is drawn. The lights of rules 4 to 6 lie in the inner outline's bounding box, measured from the gap's outline's (fx0, fz0 its lowest x and z), each clipped to the inner outline, as are the mullions and transoms; a sash is the ring between its light and the light moved inwards by sw, its glass that inner outline. A door's leaves divide the inner outline's bounding box as rule 7 does, each clipped to the inner outline; a glazed leaf's glass is its outline moved inwards by sw, clipped from gz0 (rule 8, z0 the box's bottom) to the box's top, its stiles and rails the ring between, and the rest below the glass leaf. A garage door's leaf is its inner outline.
12. **What stays the product's** (class C, reference behaviour): clearances round a leaf, a threshold, a handle or a pull, glazing bars, casings, flashings, an inner sill, the insulation in the gap round the frame, an aluminium-clad frame's two materials, a garage door's panels, curtain and tracks, and a pose that opens a leaf (`open`, Part II, 6.5). A compiler MAY draw them; where it does, it SHOULD say so.

For a `windowFamily` (a window's legacy family; its `family` is a label only):

13. **Its frame** is `frame` wide and `depth` deep, centred on the wall's axis: a head and a sill the whole width, x 0…W, and the jambs between them. Its panes are `panes` across and `transoms` + 1 up, each (W − 2·`frame` − (`panes` − 1)·`mullion`)/`panes` wide and (H − 2·`frame` − `transoms`·`mullion`)/(`transoms` + 1) high, with mullions and transoms `mullion` wide between them, frame members as deep as the frame; and each pane's glass fills it, `glassThickness` thick, centred on the axis.

For an `openingFamily`'s materials:

14. **A door's leaf of its own material.** By the steward's decision of 28 October 2026 (open questions, 89), a family of the kind `door` MAY give `leafMaterial`, the material its leaves are of where it is not its frame's: `wood`, `aluminium` or `steel`, as a wood leaf in a steel frame. A leaf (rules 7 to 9) is of `leafMaterial`, and its frame, its sashes and its mullions of the family's `material`; without `leafMaterial`, the leaf is of `material` too. The material changes no body. A family of another kind has no leaf of its own, its sashes or its panels being of `material`: it SHOULD NOT give `leafMaterial`, and a validator SHOULD warn of one (`leaf-material`).

*Note (informative).* The reference implementation writes `leafMaterial` since its work 749 (`main` `c7d816f2`) as rule 14 says, and refuses it on a family of another kind in a new command. Question 89 also left for 0.2 the profiles of a frame and its mullions, which rule 15 now gives.

For a family's profiles:

15. **The profile of a frame, a mullion and a sash.** By the steward's decision of 30 October 2026 (open questions, 97), a family MAY give its members' section as a profile: an `openingFamily` its `frameProfile`, `mullionProfile` and `sashProfile`, and a `windowFamily` its `frameProfile` and `mullionProfile`. A profile is an outline as a `custom` section's is (Part II, 5.2, rules 8 and 9), `{points, voids?}`, in mm in the section plane of the members it shapes, its x across a member in the wall's plane and its y across the wall. Its bounding box, its arcs included, MUST be the width by the depth of the members it shapes, each within 0.1 mm: a frame profile's `frameWidth` by `frameDepth` (a `windowFamily`'s `frame` by `depth`), a mullion profile's `mullionWidth` by `frameDepth` (`mullion` by `depth`), and a sash profile's `sashWidth` by `sashDepth`. A family whose frame follows its wall (rule 2) MUST NOT give `frameProfile`: its frame is as deep as each wall it stands in. A validator reports a profile that breaks rule 9 of Part II, 5.2 or one of these as an error (`frames-profile`), and a compiler derives no body of its own for a door or a window of such a family, and says why. Where a profile is given, each member it shapes is the profile carried straight along the member, its bounding box lying on the member's section: its lesser y at the interior face of the frame (or of the sash), its greater y at the exterior face, and its x as each member below says. The members' region in the wall's plane, and every other part, stay as rules 2 to 13 lay them out:
    - **The frame.** Its members are the ring round the outline the frame stands on, as rule 11 makes it: the rectangle fx0…fx1 by fz0…fz1 of rule 3, the gap's outline of rule 11, or a `windowFamily`'s opening, 0…W by 0…H, of rule 13, each edge's member between the edge and the same edge of the frame's inner outline, moved inwards by its width. The profile's lesser x lies on the edge and its greater x towards the clear opening. Each member is mitred at each of its corners on the line from the corner of the outline it stands on to the same corner of the inner outline; a door's edge on its bottom has no member (rule 11), so that its jambs end square on it.
    - **A mullion and a transom** (rules 4 and 13) carry the mullion profile from end to end of their box, their ends square, its lesser x at a mullion's side towards the opening's start and at a transom's underside. A mullion or a transom whose own `width` is not `mullionWidth` (rule 4) keeps its box, and so does every mullion and transom of a shaped opening, which rule 11 clips to the frame's inner outline.
    - **A sash** (rule 6) is the ring round its light, as the frame is round the opening: each member between the light's edge and the same edge moved inwards by `sashWidth`, the profile's lesser x on the light's edge and its greater x towards the glass, mitred at the light's corners. A sash of a shaped opening keeps rule 11's ring.

    A profile shapes no leaf, and no stile or rail of a glazed leaf (rule 8); the glass stands where rules 5, 6 and 13 put it.

*Note (informative).* Rule 15 was decided by the steward on 30 October 2026 (open questions, 97), and written ahead of the reference implementation, which draws a frame's members as boxes of `frameWidth` by `frameDepth`, has no profile yet, and names a profile system only as a plan of its work 749; it follows. A profile whose outline is its whole bounding box draws the members' boxes again: the frame's region is the same, mitred or butted, and so is its volume. A supplier who does not share its section declares the envelope instead (section 11.1).

These are class-A rules, held to the tolerances of section 10: each part's bodies within 0.1 mm of the rule's, and its volume within a relative 10⁻⁶. What rule 12 leaves to the product is not compared. A compiler MAY draw a profile's arcs as straight pieces, as a `custom` section's (Part II, 5.2, rule 10).

*Note (informative).* The reference implementation draws a leaf 3 mm short of the frame at each side and of the next leaf, and 8 mm above its threshold or the floor, and a threshold 25 mm high where `threshold` is true; it draws an opening light's or a leaf's open pose in its bodies where the element's `open` is more than 0. On a probe of every kind of family (`packages/openeik/test/fixtures/frames-bodies.json`), `@openeik/tools` agrees with it exactly on every frame and every part of a window, and on a door's leaves and glass to within 8 mm in their boxes and 2 % in their volumes; on the reference implementation's seven examples (its work 727, 28 October 2026), on 265 of the 320 parts of its 141 doors and windows with a family exactly, on 33 to within 2 % and on the other 22, all of doors with a threshold, to within 3 %.

Reference: `openingSolids`, `shapedOpeningSolids` and `familyInWall` in `src/core/elements/openings.ts`; `insetPolygon`, `ringQuads` and `clipBox` in `src/core/elements/openingOutline.ts`; `lightSpans` in `src/core/elements/mullions.ts`; `slidingLeaves` in `src/core/elements/slidingDoors.ts`; `windowSolids` in `src/core/geometry/familyGeometry.ts`. In `@openeik/tools`: `frameParts`, and for rule 15 `familyProfiles`, `profiledRing` and `profiledBar`, in `packages/openeik/src/compile-frames.js`, placed by `compileOpening` in `compile.js`.

### 4.4 Pitched roofs

Given a roof with a `roof` payload, `z0 = elev(levelId) + offset`, and its outline's edges `e_1 … e_m` (edge `i` from profile point `i` to the next):

1. Each edge with `definesSlope: true` and slope `σ_i` (degrees, 0–75) defines the plane `z_i(p) = z0 + tan(σ_i) · (n_i · (p − a_i))`, where `a_i` is the edge's start and `n_i` its unit normal pointing into the outline. So the top face meets `z0` along every slope-defining edge line.
2. The roof's top surface is the lowest of these planes at each point: `z(p) = min_i z_i(p)`. With no slope-defining edge it is the plane `z = z0`.
3. The surface extends past each edge by that edge's `overhang` (mm, in plan).
4. Layers are measured at right angles to the face they lie under: a layer of thickness `t` under a face of gradient `(g_x, g_y)` lies `t · √(1 + g_x² + g_y²)` lower, vertically.
5. Where edges of the roof are trimmed to a wall's face, its extent is trimmed as 4.5 says, and its planes stay those of its recorded edges.
6. Shafts cut its layers' bodies as 4.2, rule 8 says, and a gutter hangs on its edges as 4.7 says.

Reference: `roofFaces` in `src/core/elements/roofs.ts` (one plane per slope-defining edge, faces clipped to the lower envelope, `factor = hypot(1, gx, gy)`); `roofSolids` (each layer's vertical depth is its thickness times the factor).

### 4.5 Outline edges trimmed to a wall's face

Given an element of category `slab`, `foundation`, `ceiling` or `roof` with `edgeAttachments` (Part II, 6.7), and, for each attachment, its wall, with `P0`, `u` and `n` as in section 3 and thickness `T`: its type's total layer thickness, or its `width` where its type has no layers (4.1):

1. The face is a line in plan: the exterior face is `n · (p − P0) = T/2`, the interior face `n · (p − P0) = −T/2`. A point's distance from the face, positive away from the wall, is `δ(p) = n · (p − P0) − T/2` for the exterior face and `δ(p) = −n · (p − P0) − T/2` for the interior face.
2. The trimmed outline is the part of the outline where `δ(p) ≥ 0` for every attachment. Each face cuts along its whole line, not only along the wall, and keeps the side away from the wall; the order of the attachments does not matter.
3. A slab's, foundation's, ceiling's or flat roof's bodies (4.2) are built on the trimmed outline: its layers, each layer's inset measured from the trimmed outline, and its voids cut through them.
4. A pitched roof's planes (4.4, rules 1 and 2) and overhangs (rule 3) come from its outline as recorded: a trimmed edge's plane still starts at the recorded edge, so its slope does not move. The roof's extent, its outline extended by the overhangs, is trimmed as rule 2 says, and its layers (rule 4) fill what is left.
5. Only the element's own bodies and their quantities are trimmed. Other rules read the outline as it is recorded: the footprint that a column's base or a wall's top attaches to (5.2, 5.3), the edges a railing runs along (11.2), the edge a slab edge element runs along and the edges its host is thickened under (4.6), the eave line a gutter hangs on (4.7), and the edge ids. A thickened edge's bands are the host's own bodies, and are trimmed.

So the trim follows the wall: moved, turned, or made thicker or thinner, the wall moves the line its face lies on, and the element's bodies stop there, with neither record changed (Part II, 6.7 shows an example).

*Note (informative).* Section 4.4 does not say where a pitched roof's layer with an `inset` (Part II, 5.1, rule 5) ends. The reference implementation measures the inset from the roof's eaves, its outline extended by the overhangs, and a face its edges are trimmed to then trims the layer as rule 4 trims the extent, so that the layer reaches the face unless its inset from the eaves lies beyond it. A flat element's inset is measured from its trimmed outline (rule 3). `@openeik/tools` measures a pitched roof's so since 28 October 2026; before, it measured it from the face too, and such a layer stopped as far short of the face as its inset.

Reference: `wallFaceLine`, `edgeTrimDistance`, `clipPolygon` and `trimmedFootprint` in `src/core/elements/wallTop.ts`; `basicSolids` (its horizontal branch builds on `trimmedFootprint`) and `layeredBodies` in `src/core/geometry/geometry.ts`; `roofSolids` (`footprintTrims`) in `src/core/elements/roofs.ts`; the area in `quantities` and `floorPerimeterM` (`src/core/elements/elementMeasures.ts`), from `trimmedFootprint`.

*Note (informative).* An analysis model joins a slab to a wall it rests on where it places the wall's plate, along the wall's mid-plane, not at its face, so that the two plates share an edge and the load passes between them. A tool that builds one from a trimmed outline puts each trimmed edge on that line: the wall's baseline, the line rule 1 moves to the face, unless it places the wall's plate at the middle of its core layers. An edge recorded on the centreline is there already. The slab's quantities, its weight among them, stay those of the trimmed outline (decided on 22 October 2026; open questions, 43). A tool that takes the slab's weight from its plate in the analysis model counts the strip between the face and that line twice, once in the wall: a small error on the safe side, which it can accept, or avoid by taking the weight from the trimmed outline (added on 23 October 2026).

*Note (informative).* Until Stomra 612 (live since 21 October 2026) the reference implementation read the thickness of a wall whose type has no layers as the wall's `height`, not its `width`, and so put that wall's face half its height from its baseline (open questions, section 2, row 26). Its thickened slab edges (4.6, rule 9) stop at the same faces (`thickenedBodies` in `src/core/elements/edgeBeams.ts`).

### 4.6 Slab edge elements

By the steward's decision of 26 October 2026 (open questions, 74), as the reference implementation builds them. Given a slab edge element on the edge `hostEdgeId` of its host's outline (Part II, 6.1, rule 6), that edge running from point `a` of the outline as recorded to the next, `b`, with `L = |b − a|`, `u = (b − a)/L` and `n_in` its unit normal into the outline (`(−u_y, u_x)` where the outline runs counter-clockwise, `(u_y, −u_x)` where it runs clockwise):

1. **Its section** is its type's `edgeProfile` (Part II, 5.6). Without one it is a `rectangle` of the element's `width` by its `height`, anchored at `structureBottom`. A type that is a framing family (Part II, 5.4) draws its own section, its family's: these rules are not its rules, but for where its section lies and how its ends are cut, which section 6.6, rule 11, of 0.2, takes from them.
2. **The section's rectangles**, in `x`, across the edge into the host from the edge's line, and `z`, up from the anchor: a `rectangle` from `x = −width/2` to `width/2`; an `L`, its upstand from `x = −web` to 0, and its bottom leg from 0 to `width − web` and from `z = −depth` to `−depth + flange`; a `U`, an `L` whose leg ends at `width − 2·web`, and a second upstand from there to `width − web`. A rectangle and an upstand run from `z = −depth` to 0.
3. **Its facing**, where the section has one, is a rectangle outside it: from `x = x_out − facing.thickness` to `x_out`, where `x_out` is the least `x` of the section's rectangles, and from `z = −facing.depth`, else `−depth`, to 0.
4. **Its anchor.** The section's `z = 0` lies at `z_a + verticalOffset` (0 without it). `z_a` is the host's top, `elev(host.levelId) + host.offset`, for `slabTop`; for `structureBottom` it is the underside of the host's structure, the host's top less the thicknesses of its type's layers, top first, down to and including its first layer whose `function` is `structure`, or less the host's `height` where its type has no such layer.
5. **Where it lies.** The section's `x` lies at the reach `r(x) = horizontalOffset + x` in from the edge's line (`horizontalOffset` 0 without it), or `horizontalOffset − x` where the element is `flipped`. At the edge's start that is the point `a + r n_in + k_a r u`, and at its end `b + r n_in + k_b r u`, where `k_a` and `k_b` are 0 at a square end and the mitre's slide (rule 6) at a mitred one. Each rectangle of rule 2, and the facing, is the prism, in plan, of the four points of its two `x` at the two ends, between the heights of its two `z`: one body each, along the whole edge.
6. **Its ends.** An end is mitred where `miterEnds` is `true`, square where it is `false`, and, without it, mitred where the edge round that corner carries another slab edge element that mitres by itself (Part II, 6.3) and the element's own type is no framing family. The corner at the edge's start is turned by the edge before it, at its end by the edge after it. With `n_c` that edge's unit normal into the outline, a mitred end's slide is `k = (1 − n_in · n_c) / (u · n_c)`: every point of the end lies on the bisector of the host's corner, whatever the element's offsets. A mitred end stays square where `|u · n_c| < 10⁻⁶` (the two edges run straight on) and where `|k| > 4` (the corner is sharper than 2·arctan(1/4), about 28.07°, and the cut would run on more than four times the section's reach). Both ends stay square where, between them, the element would be 1 mm long or less at the least `x` of its section and facing or at its greatest: where `L + (k_b − k_a) r(x) ≤ 1` for either, `k` being 0 at an end that is square by the rules before.
7. **A chamfer** cuts the upstand's top inner corner (an `L`'s, or a `U`'s first upstand's): that upstand is instead the polygon `(−web, −depth)`, `(0, −depth)`, `(0, −chamfer.height)`, `(−chamfer.width, 0)` and, where `chamfer.width < web`, `(−web, 0)`, whose points lie at its two ends as rule 5 places them: a convex body between the two end polygons.
8. These are the element's bodies, and its volume theirs. Its `notches` are rules 12 to 14's, of 0.2.

What it does to its host, rules of the host's own body (4.2, rules 6 and 7):

9. **Thickened edges.** A slab or a foundation is thickened under each edge of its outline that carries a slab edge element whose type's `edgeProfile` has a `beam`; two on one edge thicken it by the wider and the deeper. Its structure is its type's first layer whose `function` is `structure`, or, without layers, its one body; a slab whose type has layers and none of them structure is not thickened. Let `z1` be its top, `s` its structure's underside, `t` its structure layer's `inset` (0 without one), and each edge of its outline as recorded **moved in** by a distance: its line moved into the outline by it, each end where the moved lines of it and its neighbour meet, or, where the two run in line and are moved by different distances, square at their common point.
   - Each beam's depth gives a level `z1 − depth`; those more than 0.5 mm under `s`, from the highest, close bands, the first from `s` down to its level and each other from the level before it down to its own.
   - In a band down to a level `λ`, a beam reaches through where `z1 − depth ≤ λ + 0.5` and its width is more than `t`. With its edge moved in by its width and every other edge by `t`, the four-sided strip between its edge moved in by `t` and moved in by its width is a body of the structure layer, from the band's top down to `λ`.
   - A layer under the structure, one whose top lies 0.5 mm or less over `s`, is cut at the levels within it, and each part takes the outline that its edges moved in leave: the edges of the beams that reach through the part's underside by their widths, where these are more than the layer's own `inset`, and the others by its `inset`.
   - The strips and the layers' outlines are trimmed where the host's edges are trimmed to a wall's face (4.5, rule 3), and the host's `voids` cut through the layers (4.2, rule 4).
10. **A chamfer's fill.** The host fills the corner a chamfer cuts off (rule 7) with its structure, where the corner lies under its structure's top (its top less its layers over its first structure layer; its top without one): the triangle `(0, −chamfer.height)`, `(0, 0)`, `(−chamfer.width, 0)` of the element's section, cut level at that height where it lies within it, placed as rule 7 places the upstand. It is a body of the host's structure layer, else of its first layer.
11. **A fit.** At each depth a beam reaches, the edges moved in by the widths of the beams reaching that depth, and the others by `t`, MUST close a simple outline that turns as the host's does, of 1 mm² or more, and the host's `voids` MUST lie within it. A validator reports a host whose thickened edges do not fit; a compiler builds it without them, and says so.

An `L` 600 wide and 500 deep, its web and its flange 100, at `slabTop`, on the first edge of a slab from `[0, 0]` to `[6000, 0]`, whose outline runs counter-clockwise: its upstand stands from y −100 to 0 and its leg from y 0 to 500, from 500 under the slab's top up. Where another such element runs up the next edge from `[6000, 0]`, both mitre: `k = −1` at the corner, so the upstand's outer face runs on to `[6100, −100]` and the leg's inner face stops at x 5500.

Its notches, rules 12 to 14:

*Part of 0.2. OpenEik 0.1 had them as the proposal `adopted` (Part II, 14): in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), a slab edge element's `notches` is a member a schema does not know (Part I, 10), and no notch is cut.*

12. **Notches.** By the steward's decision of 30 October 2026 (open questions, 115), a slab edge element MAY carry `notches`, at most 20 stretches `{from, to, depth}` where its outside upstand is cut down: `from` and `to` in mm along its host's edge from the edge's first point `a`, and `depth` in mm down from the section's top, `z = 0`. Only an `L` or a `U` has an outside upstand, its section's first rectangle (rule 2): an element whose section is a `rectangle`, or whose type is a framing family, MUST NOT carry notches. A notch MUST run from `from` to at least `from + 10`, MUST end on its edge (`to ≤ L`), MUST keep above the flange (`depth ≤ depth − flange`, the section's), and, where the section has a chamfer (rule 7), MUST be at least as deep as the chamfer is high, so that it takes the chamfer whole; and two notches MUST NOT overlap. A validator reports a breach (`notch-invalid`). A compiler builds such an element without its notches, and says so. Only a slab edge element carries `notches` (Part II, 6.3).
13. **Its bodies.** The edge is cut into stretches at the notches' ends: from its start to its first notch, each notch, each stretch between two notches, and from its last notch to its end, a stretch shorter than 10⁻⁶ mm being none. Each stretch lies as rule 5 places the element, between its two ends: an end that is the element's own, at 0 or at `L` along the edge, is that end, square or mitred by rule 6; an end within the edge is cut square, at `s` along it, its points `a + s·u + r(x)·n_in`. The outside upstand is a body for each stretch, from `z = −depth` up to the section's top less the stretch's depth (a whole stretch's being 0), none where that leaves nothing; its chamfer (rule 7) is cut on a whole stretch alone. The facing (rule 3), where the section has one, is a body for each stretch whose depth is less than the facing's, from its foot up to the section's top less that depth. Every other rectangle of the section is one body along the whole edge, as rule 5 says.
14. **The host's fill.** A chamfer's fill (rule 10) is cast along the whole stretches alone: a notch takes the wedge with it.

The `L` of the example above, alone on its edge, with a notch `{from: 1000, to: 3500, depth: 150}`, stands its upstand as three bodies: from `[0, 0]` to `[1000, 0]` along the edge and from `[3500, 0]` to `[6000, 0]` its whole depth, and between them from 500 under the slab's top up to 150 under it. Its leg is one body, as before.

Reference: `profileRects` in `src/core/elements/edges.ts`; `edgePlacement` and `mitresAlone` in `src/core/elements/edgePlacement.ts`; `chamferProblem`, `upstandSection`, `fillSection`, `sweptSection`, `chamferFills` and `withChamferFills` in `src/core/elements/edgeChamfer.ts`; `movedEdges`, `edgeBeamProblem` and `thickenedBodies` in `src/core/elements/edgeBeams.ts`; `basicSolids` (its slab edge branch) in `src/core/geometry/geometry.ts`; for rules 12 to 14, `notchProblem` and `notchedEdgeBodies` in `src/core/elements/edgeNotches.ts`, and `edgeSpans` and `spanPlacement` in `edgePlacement.ts` (Stomra work 487).

*Note (informative).* Part IV, 11.2, rule 9, a railing along a slab edge element, rests on these rules. The reference implementation builds the slab edge elements of `examples/l-house` and of a probe of every rule above with these bodies, to the millimetre, its hosts' thickened edges and fills, and its shafts' cuts in them, to the cubic millimetre (`packages/openeik/test/fixtures/hosted-bodies.json`, Stomra `main` `0c8fcea1`).

### 4.7 Gutters

By the steward's decision of 26 October 2026 (open questions, 75), as the reference implementation builds them, but for rule 6, which it finds at 25 points. Given a gutter on the edge `hostEdgeId` of its roof's outline (Part II, 6.1, rule 13), its type's `gutterProfile` (Part II, 5.6), and its roof's top surface (4.4, rules 1 and 2), the level plane `z = elev(levelId) + offset` for a roof without a `roof`:

1. **Its eave line.** Each edge of the roof's outline, its line moved out of the outline by its `overhang` (4.4, rule 3; 0 for a roof without a `roof`), meets the moved line of the edge before it at a corner, or, where the two run in line, at the start of its own moved line. The gutter's eave line runs from the corner at its edge's start to the corner at its end, whatever trims the roof (4.5, rule 5).
2. **Its height.** At each end of each piece of the gutter (rule 6), its section's `z = 0` lies on the roof's top surface at that point of the eave line; between the two ends, the piece runs straight.
3. **Its section**, in `x` out from the eave line, square to it in plan, and `z` up: a `halfRound` is the half annulus about `(r, 0)`, `r = diameter/2`, between the radii `r` and `r + thickness`, under `z = 0`: its back lip on the eave line and its rim level with the roof's top. A `box` is its bottom, from `x = 0` to `width` and from `z = −depth − thickness` to `−depth`, and its two walls, from `x = 0` to `thickness` and from `width − thickness` to `width`, from `z = −depth` to 0. The half-round's arc is the rule; the straight pieces that stand for it are a compiler's, as a pipe's circle is (12.3, rule 5).
4. **Its offsets.** Its type's `gutterProfile.horizontalOffset` and its own `horizontalOffset` add, and move its section out from the eave line; where it is `flipped`, they move it the other way, in towards the roof. Its type's `gutterProfile.verticalOffset` and its own `verticalOffset` add, and raise it.
5. **Its body** is its section carried straight from one end of each piece to the other: its ends are square to the eave line in plan.
6. **Where it is buried.** Where its roof's `roof.joinGroup` names a group, the gutter is left out wherever its eave line lies, in plan, strictly inside the outline of another roof of the group extended by its overhangs (rule 1), and that roof's top surface there lies more than 20 mm over its own roof's. It is found exactly along the line, from the outlines and the planes. A piece of 10 mm or less in plan that is left is left out too, and a gutter buried along its whole line has no body.
7. **Its quantities** (informative, as section 9): its length is its pieces' length in plan, and its volume its section's area by that length, a half-round's `(π/2)((r + thickness)² − r²)`.

A downpipe's path from its gutter stays reference behaviour (7.2).

A half-round of 150 and 3 on the first edge of a roof from `[0, 0]` to `[8000, 0]` of level 1 (3000), that edge defining a slope of 30° with an overhang of 400, its two neighbours an overhang of 300: its eave line runs at y −400 from x −300 to 8300, at the roof's top there, 3000 − 400 tan 30° = 2769.06; its body reaches from y −397 to −553 and from z 2691.06 to 2769.06, and its volume is `(π/2)(78² − 75²)` mm² by 8.6 m.

Reference: `gutterPath`, `halfRoundCells`, `boxCells`, `gutterProfileCells`, `unburiedSegments` and `gutterSolids` in `src/core/elements/gutters.ts`; `roofDomain` and `roofFaces` in `src/core/elements/roofs.ts`.

*Note (informative).* The reference implementation finds where a gutter is buried at 25 points along its eave line, a twenty-fourth of it apart, and runs a piece on to the first point it finds buried; by the steward's decision, a tolerance of a twenty-fourth of the eave line holds until it finds it exactly (Conformance, 3). On `examples/l-house` it ends the study's north gutter at x 6000, where the rule ends it at 6415.4, and leaves out the 34.6 mm the rule keeps at its west end, under the edge of the wing's eave. It draws a half-round's arc in 10 straight pieces, which hold 1.0 % less than the arc; `@openeik/tools` draws 16. With `flipped` it mirrors the section and its outward direction together, so that only its offsets turn round (rule 4).

## 5. Tops, bases and heights

### 5.1 Heights from the top constraint

For a wall, shaft or stair with `top.constraint = {levelId, offset}`, the height is `elev(levelId) + offset − base`, which MUST be positive. With `"unconnected"` or no `top`, it is the element's `height`.

Reference: `constrainedWall` in `src/core/elements/attachments.ts`; `shaftRange`, `stairRange`.

### 5.2 Attached column bases

For a column with `base.attach = {hostId, face, offset}`:

1. The host MUST be a foundation or a slab whose footprint contains the column's centre (on the boundary counts).
2. The host's face is its top (`face: "top"`) or its underside, `T_host` below its top. For a flat host the face is the plane `elev(host.levelId) + host.offset − depth`.
3. The derived base is the lowest face plane at the column's centre plus `offset` (a negative offset embeds the column below the face).
4. The column's top stays where its record puts it, `elev(levelId) + offset + height`; the derived length is top minus derived base, which MUST be positive.

Reference: `attachedBaseZ` and `resolvedColumn` in `src/core/elements/columnBase.ts`.

### 5.3 Attached wall tops

For a wall with `top.attach = {hostId, face, offset, mode}`:

1. The host MUST be a roof, ceiling, slab or foundation, and its footprint MUST cover the wall's whole centreline in plan, to within 5 mm (section 5.3.1).
2. The face's depth below the host's top is: 0 for `"top"`; the host's thickness for `"underside"`; for `{layerId}`, the sum of the host's layer thicknesses from the top down to and including that layer.
3. The face is, for a flat host, the plane at the host's top minus the depth plus `offset`; for a pitched roof, each of the roof's planes (4.4) lowered by `depth · √(1 + g_x² + g_y²)` and raised by `offset`.
4. `mode: "raking"` (the default): along the centreline the wall's top is the lowest face plane at each point. It is piecewise linear, with breaks where two planes cross over the centreline.
5. `mode: "level"`: the top is flat, at the lowest point of the face over the wall's core band.
6. The face MUST rise above the wall's base somewhere along the centreline, and MUST NOT fall below the base by more than the host's own depth.
7. The wall's `height` and `wallOutline` stay as recorded; they are the unconnected values, used again when the wall is detached.

Reference: `attachedWall`, `derivedTop` and `hostFacePlanes` in `src/core/elements/wallTop.ts` and `src/core/elements/attachments.ts`; `hostCoversBaseline`.

*Note (informative).* Which layers follow the face is reference behaviour in 0.1: by default the layers outside the core keep running up to the unconnected top when the wall also has a cutting roof (`cutRoofId`, `extendExteriorLayers`, the type's `wallAttach`). The body of an attached wall is built up to its highest opening before it is clipped (`wallBodyHeight`). Section 7.4.3 states a wall's cut roof and its extended layers for a framed layer's envelope.

### 5.3.1 A wall's top at its host's edge

*Part of 0.3. OpenEik 0.2 had it as the proposal `wallTopTolerance` (open questions, 123): a model of 0.2, read by 0.2's rules (Part I, 9.6, rule 3), is read by it only where a caller asks for it (decision D12).*

A wall whose top is attached to a host is held to rule 1 of section 5.3 to within 5 mm in plan: a wall drawn to a roof's or a slab's edge stays attached when the edge or the wall's end moves by a few millimetres, as rounding moves them. In a model of 0.2 that does not ask for the proposal, rule 1 holds as written.

1. **Covered to within 5 mm.** The host's footprint, as rule 1 of section 5.3 reads it (a pitched roof's with its overhangs, a round footing's circle), MUST cover the wall's whole centreline in plan to within 5 mm: no point of the centreline lies more than 5 mm outside it, measured in plan. A validator reports a centreline that runs further past it as rule 1 does (`top-host`), and a compiler gives such a wall its unconnected top.
2. **The face past the edge.** Where the centreline runs past the footprint's edge, the face of rule 3 is carried on past it: a flat host's face is the same plane there, and a pitched roof's each of its planes, lowered and raised as rule 3 says. The top of rules 4 and 5 is read from that face along the whole centreline, and rule 6 holds along all of it.
3. **The rest stands.** Rules 2 to 7 of section 5.3 are unchanged.

Reference: `ROOF_EDGE_SLACK`, `baselinePastRoof` and `hostCoversBaseline` in `src/core/elements/wallTop.ts`. In `@openeik/tools`: `WALL_TOP_TOLERANCE` and `wallTopRules` in `packages/openeik/src/rules.js`, and `wallTop` in `packages/openeik/src/compile.js`, for a model of 0.3, and for one of 0.2 asked for with `proposals: ["wallTopTolerance"]`.

*Note (informative).* Rule 1 of section 5.3 was written on 11 October 2026 from the reference implementation as it was then; since 14 October 2026 (its work 508) the reference implementation takes a wall whose centreline ends 5 mm or less past a pitched roof's edge, measured from each edge's line moved out by its overhang, and holds a flat host to rule 1 as written. Ten walls in four of its lines of work lie within it, which 0.2's rule 1 refuses. The steward decided on 31 October 2026 that the tolerance is 5 mm in plan for every host in 0.3 (open questions, 123), and this section was written as a proposal for 0.3, which the cut of 0.3 made a rule until the cut of 0.3 makes it a rule.

## 6. Members: the structural subset

This section fixes what an analysis tool needs to read beams and columns.

### 6.1 Columns

Given a column with centre `c` (its profile's first point), base `z0 = elev(levelId) + offset` (or the attached base, 5.2) and length `H = height` (or the derived length):

1. Without a `section`, the body is the square prism of side `width` centred on `c`, over `[z0, z0 + H]`.
2. With a `section`, the section's `width` runs along x and its `depth` along y, centred on `c`, swept over `[z0, z0 + H]`.
3. Either is then turned by `turn` degrees counter-clockwise in plan about `c`.
4. The column's reference line runs from `(c, z0)` to `(c, z0 + H)` (6.5). Its start is its base.

### 6.2 Beams

Given a beam from `P0` to `P1`, `z0 = elev(levelId) + offset` and `r = endRise` (0 when absent):

1. The beam's **set-out line** runs from `(P0, z0)` to `(P1, z0 + r)`. It is the centreline of the member's underside, where the record places it. Its length is `Ls = √(L² + r²)`; let `sin α = r / Ls`, `cos α = L / Ls`.
2. Without a `section`, the body is the prism over `[z0, z0 + height]` of the rectangle of width `width` centred on the plan axis. A beam with neither a `section` nor a `framing` family MUST NOT have a non-zero `endRise`.
3. With a `section` of width `w` and depth `d`, the section stands at right angles to the set-out line: the point at distance `s` along the line (0 ≤ `s` ≤ `Ls`), `x` across it (−`w`/2 ≤ `x` ≤ `w`/2) and `v` up from the underside (0 ≤ `v` ≤ `d`) is at plan position `P0 + u (L s / Ls) + n x − u v sin α` and elevation `z0 + r s / Ls + v cos α`. The element's own `width` and `height` do not size it.
4. With a `taper` (rectangular sections only), the depth varies linearly from `d` at the start to `taper.endDepth` at the end; the underside follows the set-out line. A `rectangle`'s `radius` does not round a tapered beam: its body is the wedge with square corners.
5. With a `roll`, the body is turned `roll` degrees about the reference line (6.5): the line through the middle of the section, parallel to the set-out line. It turns right-handed about the line's direction from the start to the end, so that a positive roll turns the section's `x` (across, along `n`) towards its `v` (up), as the reference implementation and `@openeik/tools` turn it.
6. A beam whose type has a `framing` family takes its body from the family (Part II, 5.4), with `Length = Ls`. Section 6.6, of 0.2, builds that body.

### 6.3 What sizes a member

| | Section width | Section depth | Length |
|---|---|---|---|
| Beam with a `section` | `section.width` | `section.depth` | from the profile and `endRise` |
| Beam without a `section` | `width` | `height` | from the profile |
| Column with a `section` | `section.width` (along x) | `section.depth` (along y) | `height` |
| Column without a `section` | `width` | `width` | `height` |

Reference: `basicSolids` (column and beam without a section), `memberSolids`, `squareMemberSolids`, `beamMiddleLine` and `turnSolids` in `src/core/geometry/familyGeometry.ts`; `validateElement` ("Sloped members require a beam section").

### 6.4 Member joins

A member's `joins` list says how each of its ends meets another member or plate: `{id, to, at, kind, gap?, extend?}`.

1. `at` is `"start"` or `"end"` of this member; a column's start is its base.
2. `kind: "butt"`: this member's end stops at the face of `to`, held back by `gap` (mm). With `extend: false` the end is only cut, never lengthened to the face.
3. `kind: "mitre"`: both members are cut on the plane that bisects their reference lines, so they meet on one plane; one record does both sides. `to` MUST be a beam or column, and `extend: false` MUST NOT be used.
4. A join does not change either member's record: the set-out line and the stored ends stay as recorded. The cut and the lengthening are derived.
5. Join ids MUST be unique on a member; a member MUST NOT be joined to itself; `to` MUST exist.
6. Joins and trims are computed on the members' reference lines (6.5), not on their axes.

Reference: `memberJoinSchema` and `validateMemberJoins` in `src/core/elements/memberJoins.ts`.

*Note (informative).* How far a joined end is lengthened before it is cut is reference behaviour: the reference implementation lengthens it along the member's reference line (6.5) until the other member's reference line plus a margin of both sections' larger dimensions is passed (`joinExtensions`).

### 6.5 Reference lines and axes

A member has two lines:

- Its **reference line** runs through the middle of its section: the centre of the section's bounding box, `width` by `depth`. The record places the member by it: a column stands on its profile point, and a beam's section is centred across its plan axis and stands on its set-out line (6.2). A roll turns the body about it (6.2), and joins and trims are computed on it (6.4). The rules of 6.1 and 6.2 already place every body this way; no existing body moves.
- Its **axis**, the structural axis, is the centroidal line of its body as built, after the roll: the reference line moved by the section's centroid offset. Analysis tools and analytical exports MUST use the axis. They MAY publish the section's shear centre with it.

For a section that is symmetric about both its own axes the two lines coincide.

1. **A column**: the reference line runs from `(c, z0)` to `(c, z0 + H)`, where `c` is the centre (the profile's first point), `z0` the base (or the attached base, 5.2) and `H` the length.
2. **A beam with a section** of depth `d`: the reference line runs through the middle of the section, `d/2` above the set-out line measured square to the member, along the member's true length `Ls = √(L² + r²)`. It runs from `(P0 − u (d/2) sin α, z0 + (d/2) cos α)` to `(P1 − u (d/2) sin α, z0 + r + (d/2) cos α)`, with `α` and `r` as in 6.2. Across the member it lies on the plan axis.
3. **A tapered beam**: the reference line runs through the middle of the section at each end, using the section's depth at the start and `taper.endDepth` at the end.
4. **A beam without a section**: the reference line runs `height / 2` above the underside, from `(P0, z0 + height/2)` to `(P1, z0 + height/2)` (such a beam has no `endRise`).
5. **The axis.** A section's **centroid offset** is the centroid of the section's area less the middle of its bounding box, in the section's own coordinates: `(e_x, e_v)` for a beam, with `x` across the member (along `n`) and `v` up from the underside, as in 6.2; `(e_x, e_y)` for a column, along its section's `x` and `y` before its `turn`. The offset turns with the body, by a beam's `roll` about its reference line or by a column's `turn` in plan, giving `(e_x', e_v')` or `(e_x', e_y')`. The axis is the reference line moved by the turned offset: for a beam, each point moves by `n e_x' − u e_v' sin α` in plan and by `e_v' cos α` up; for a column, by `(e_x', e_y')` in plan.
6. A `rectangle` (with a `radius` or without), `I`, `RHS`, `CHS` or `round` section, a tapered beam and a beam without a section have a centroid offset of zero: their axis is their reference line, and a roll does not move it. A `T` or `2L` section has a centroid offset of zero across and not zero in `v` (in `y` for a column), set by its sizes, its radii and, for a `2L`, its `gap` (Part II, 5.2). An `L` or `U` section, and a `sheet` section in general, have a centroid offset that is not zero, set by the section's legs or flanges, its corner and its radii. A `custom` section's centroid offset is its region's centroid less the middle of its outline's bounding box (Part II, 5.2, rule 10), zero only where they meet.

A beam built from a framing family (6.2, rule 6) takes its body from the family, a class-C rule (section 2), and 0.1 defines no reference line and no axis for it: rules 2 to 6 are not its rules. The steward deferred its reference line and axis to 0.2 on 15 October 2026, and decided on 21 October 2026 what 0.2 says: its reference line is the middle of its height over its set-out line, and it has no single axis, an analysis taking each of its `member` parts as a member with its own axis (open questions, 10). A reader that cannot place those parts, because it does not evaluate the family's expressions (Part II, 5.4), leaves such a beam out of an analysis and says so, rather than standing a member of its own in its place (decided on 22 October 2026 for 0.2). Section 6.6, of 0.2, places and builds the parts as class-A rules, and section 6.5.1 gives the beam its reference line.

Reference: `beamMiddleLine` in `src/core/geometry/familyGeometry.ts` computes rule 2; `memberStructuralAxis` in `src/core/geometry/memberStructuralAxis.ts`, with `sectionProperties.ts`, computes rule 5.

*Note (informative).* The member axis was decided on 11 October 2026 and refined the same day into these two lines: the axis follows the section's centroid, and joins keep the section's middle. In the reference implementation, Stomra pull request #777 (`sectionedBeamAxis` in `src/core/geometry/sectionedBeamAxis.ts`, called by both `memberAxisEnds` and `beamMiddleLine`; live in Stomra since 11 October 2026, `main` `21cd71c6`) computes the reference line of rules 1 to 4 for sectioned beams, and sets a sectioned beam's `height` to its section's depth on every command and on load, a disagreeing patch refused. Before it, the join code lifted every beam's set-out line by `height / 2` vertically. #777 computes no separate axis: it uses the section's middle, which for an `L` or `U` member is not the centroid that rule 5 asks for. Stomra work 480 (live since 13 October 2026) computes rule 5's axis for beams and columns whose type has a section, `L` and `U` included: `memberStructuralAxis` moves the reference line by the section's centroid offset, worked out from the section's cells as built, fillets included; for a beam across and square to the slope and then turned by the roll, for a column in plan and turned by its `turn` (the reference implementation's columns do not lean). Its tests hold the axis against the body's own centre of volume: an `L` 100 × 100 × 10 has its centroid 28.2 mm from its heel, and level, sloped and rolled `L` and `U` beams pass within 0.5 mm of their bodies' centres. Stomra work 558 (merged, `main` `ff98daa1`) adds the `T`, `2L` and `round` sections with their rules (Part II, 5.2); `memberStructuralAxis` computes their axes as it does the others', and its tests hold a `T`'s and a `2L`'s area and centroid to the parallel-axis formulas, and a `round` section's to its circle. A member without a section and a framing member keep the box's middle, which is the centroid of a rectangle; a body that is not prismatic (a family's own geometry, or ends and notches cut by joins) keeps its prismatic section's centroidal line. A beam built from a framing family (a truss, a purlin) keeps `z0 + height/2` along its profile, with its `endRise`, in #777: its body is the family's own profile, and its reference line and axis are deferred to 0.2 (open questions, 10); meanwhile a tool that needs a line for such a beam chooses one, as for any reference behaviour (section 2).

### 6.5.1 A framing family's beam

*Part of 0.2. OpenEik 0.1 had it as the proposal `framing`, with section 6.6: in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), a beam built from a framing family has neither line, as section 6.5 says. The section adds no file and no member. It was written as a proposal of its own, `framingLines`, and folded into the proposal `framing`; the steward confirmed the fold on 30 October 2026 ("allt ja enligt din rekommendation"; open questions, 10).*

By the steward's decisions of 21 and 22 October 2026 (open questions, 10), the second asked by an analysis application. A beam whose type has a `framing` family (6.2, rule 6) takes its body from the family, whose `member` parts the family's expressions place (Part II, 5.4).

1. **Its reference line** is the middle of its height over its set-out line (6.2, rule 1): from `(P0, z0 + height/2)` to `(P1, z0 + r + height/2)`, where `z0` and `r` are section 6.2's and `height` is the element's, so that it rises by the beam's `endRise` as its set-out line does. Its joins and trims are computed on it (6.4, rule 6), and the beam's record places it, as any beam's does.
2. **It has no single axis.** A family's parts, a truss girder's chords and diagonals or an I-joist's flanges and web, have no one centroid. An analysis takes each of the family's `member` parts as a member of its own, with its own axis through the middle of its section, where the family's expressions place it (Part II, 5.4; section 6.6, rule 4).
3. **A reader that cannot place the parts**, because it does not evaluate the family's expressions, MUST leave such a beam out of an analysis, and SHOULD say so. It MUST NOT stand a member of its own on the reference line in its place: that member would carry loads with a section the beam does not have.

A purlin of a framing family, 220 mm high, from `[0, 0]` to `[6000, 0]` on a level at 3000 with an `endRise` of 600, has the set-out line from `(0, 0, 3000)` to `(6000, 0, 3600)` and the reference line from `(0, 0, 3110)` to `(6000, 0, 3710)`.

*Note (informative).* The reference implementation keeps `z0 + height/2` along a framing family's beam's profile, with its `endRise` (`beamMiddleLine` in `src/core/geometry/familyGeometry.ts`), and joins such beams on it: it meets rule 1. `compileModel` of `@openeik/tools` gives the reference line, and no axis, beside the parts section 6.6 builds; it cuts no join against such a beam (section 6.6, rule 15).

### 6.6 A framing family's parts

*Part of 0.2. OpenEik 0.1 had it as the proposal `framing`: in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), the body of a beam or a slab edge element whose type is a framing family is reference behaviour, as section 6.2, rule 6, section 4.6, rule 1, and section 7.2 say. The section adds no file and no member: the family is its type's `framing`, and its parameters the element's `framingParameters` (Part II, 5.4).*

By the steward's decision of 26 October 2026, amended on 29 October 2026 (open questions, 83), a beam or a slab edge element whose type is a framing family has the bodies of its family's parts: the family's expressions, which Part II, 5.4 specifies, are evaluated with the element's parameters, and each part is built from what they give. Nothing stands in for a family that cannot be.

`f` is the type's `framing`. A point of the family's plane is `(x, z)`, in mm, and `cross(a, b, p) = (b_x − a_x)(p_z − a_z) − (b_z − a_z)(p_x − a_x)`, which is positive where `p` lies to the left of the line from `a` to `b`. To clip a polygon to one side of a line is to walk its edges in order, keeping each point on that side, within 10⁻⁹, and the point where an edge crosses the line.

1. **No stand-in.** A family that cannot be evaluated by rule 2, or whose parts cannot be built by rules 3 to 9 and 11, is a fault of the model. The compiler derives no body for the element, and says why; nothing stands in for its bodies. A validator reports it as an error, which it can tell from the records alone: `framing-expression` where an expression is invalid or a parameter breaks Part II, 5.4's rules, and `framing-part` where its `Length` is out of its range, two of its parts share an id, or a part cannot be built.
2. **The scope.** `Length` is a beam's set-out line's length, `Ls` (section 6.2, rule 1), or a slab edge element's edge's length in plan (section 4.6), and lies from 1 to 100 000 mm. Each parameter of `f` takes the element's `framingParameters[name]` where its scope is `instance` and the element gives it, and its `value` otherwise; `f` keeps Part II, 5.4's rules on parameters, and its parts' ids are unique. Every expression of these rules is evaluated in this scope as Part II, 5.4 states, and is valid.
3. **Which parts exist.** A part whose `when` is given exists while its value is greater than 0. A part that does not exist has no body, and cuts no other part (rule 6).
4. **A part's outline.** A `member` part runs from its point `a` to its point `b`, at least 1 mm apart, and its `depth` d lies from 1 to 10 000 mm. With `t = (b − a)/|b − a|` its axis and `m = (−t_z, t_x)`, its outline is the rectangle `a − (d/2)m`, `b − (d/2)m`, `b + (d/2)m`, `a + (d/2)m`, so that its line from `a` to `b` runs through the middle of its depth, and its centre is the middle of `a` and `b`. A `profile` part's outline is its `outline`'s points, and its centre the centroid of the area they bound. Either outline is simple: of three points or more, each two consecutive points at least 0.1 mm apart, no two of its edges crossing or touching but neighbours at their common point, and of 5 mm² or more. A part's `width` lies from 1 to 10 000 mm on a beam, and from 1 to 100 000 mm on a slab edge element.
5. **Its straight cuts.** Each of a part's `cuts`, the line through its two points, which lie at least 10⁻⁶ mm apart, and for a top chord each of its tail's line cuts (rule 7), keeps the side of the line that holds the part's centre, which does not lie on the line: the outline is clipped to that side, by each line in turn. The result, cleaned (rule 8), is the part's cut outline. A part cuts others by its cut outline, never by what its own joints leave of it (rule 6), so that the order of the parts does not matter.
6. **Its joints.** Each part a part's `cutBy` names is another part of `f`. Where that part exists and its cut outline has three points or more, that outline is convex, its turns all one way within 10⁻⁶, and is taken out of the part: for each of its edges in turn, what lies outside the edge's line is set apart as a piece, where it has three points or more and more than 10⁻⁶ mm², and what lies inside is carried on to the next edge; what lies inside every edge is gone. The parts `cutBy` names are taken out in its order, each from every piece the ones before it left.
7. **A tail.** A family's `tail` cuts each `member` part whose `role` is `topChord` and whose axis rises, `t_z` more than 10⁻⁹ (its left tail), or falls, `t_z` less than −10⁻⁹ (its right tail); a level top chord has none. `f` then has the parameters `Pitch`, `HeelHeight`, `OverhangLeft` and `OverhangRight`. With `o` that side's overhang, `OverhangLeft` or `OverhangRight`, and `TipTop = HeelHeight − o·tan(Pitch)`, a tail's expressions are evaluated in the scope of rule 2 with `Overhang = o` and `TipTop` added (Part II, 5.4). A point `(u, v)` whose `origin` is `tip` lies at `(−o + u, TipTop + v)`, and one whose `origin` is `bearing` at `(u, v)`; on the right tail its `x` is mirrored to `Length − x`. A `line` cut's `origin` is `tip` where it gives none, and a `notch`'s `bearing`. A `line` cut is one more straight cut of the part (rule 5). A `notch`, its outline convex and of 1 mm² or more, is taken out of the part's pieces after its joints, as rule 6 takes a part out.
8. **Its pieces.** A polygon is cleaned by dropping each point within 0.5 mm of the next, and then each point `b` whose neighbours `a` and `c` leave `|cross(a, b, c)|` no more than 10⁻³·|c − a|. Each of a part's pieces is cleaned, and one of fewer than three points, or under 200 mm², is dropped. A part that exists keeps at least one piece, and each of its pieces is simple (rule 4).
9. **Nail plates.** A `plate` part that exists has a `thickness` from 0.5 to 20 mm and an outline that, cleaned, has three points or more and is convex; each part its `on` names is a `member` part of `f`. On each piece of each such member, in turn, the piece clipped to the inside of each edge of the plate's outline, cleaned, where it keeps three points and 100 mm² or more, is a piece of the plate on each face of the member: across the plane from `w/2` to `w/2 + thickness` on either side, `w` the member's width. Its pieces are simple (rule 4).
10. **On a beam.** The plane is Part II, 5.4's, over the beam's set-out line: with `P0`, `u`, `z0` and α as section 6.2 has them, and `n = (−u_y, u_x)`, the point `(x, z)` of the plane at `y` across it lies at plan position `P0 + u (x cos α − z sin α) + n y`, and at elevation `z0 + z cos α + x sin α`. A part's piece lies from `y = −w/2` to `w/2`, `w` its width; a plate's as rule 9 says.
11. **On a slab edge element.** The plane is the element's section along its host's edge: `x` across the edge into the host, where section 4.6, rule 5 places a section's `x` (by its `horizontalOffset`, its `flipped` and its mitred ends), and `z` up from its anchor, `z_a + verticalOffset`, where `z_a` is as section 4.6, rule 4 gives it for `f`'s `edgeAnchor`, and `slabTop` where `f` gives none; its type's `edgeProfile` is not used. Its ends are mitred only where its `miterEnds` is `true` (section 4.6, rule 6), and stay square where that rule keeps them square, the least and the greatest `x` of its section being those of its parts' pieces. A part's piece runs along the edge for `r = min(w, L)`, `w` its width and `L` the edge's length, centred on the edge's middle: each of its points lies at the stations `L/2 − r/2` and `L/2 + r/2` along the line between its places at the edge's two ends. A plate has no faces to lie on there: a slab edge element's family has no `plate` part that exists.
12. **Bodies and quantities.** Each piece is a body, closed: its polygon at each end of its extent across the plane, or along the edge, joined by its sides. Each body names its part by the part's id. The element's volume is the sum of its bodies' volumes: on a beam, each polygon's area by its width; on a slab edge element, each body's own, its polygon's area by its run `r` where its ends are square, and less or more where a mitre slants them.
13. **Members.** Where a `member` part or a plate has a piece, every part that has one is a member of its element, written apart from it (Part VIII, 1.6): keyed `<element id>:<part id>`, which is unique in the model, or the model cannot be printed (Part VIII, 1.6); named by its element's name (its id where it has none), its role in words (Part VIII, 1.6) and its id, as `T1 · top chord topL`, a `profile` part by its id alone, as `T1 · seat`, and a plate as `T1 · nail plate p1`; and with its section, its width by its depth, each to a tenth of a millimetre, as `45 × 220`, where a `member` part's depth is its own and another part's its pieces' height in the plane. Otherwise its parts, all `profile` parts, are the element's own body.
14. **What a family may say.** Rules 2 to 13 build every member Part II, 5.4 gives a family: its parameters and their scopes; its `member`, `profile` and `plate` parts, with `when`, `cuts`, `cutBy` and `on`; its `tail`, with both kinds of cut and both origins; and its `edgeAnchor`. Its `trussStyle` names what kind of family it is, and its `previewLength` is an editor's: neither changes a body. What the language lets a family say that these rules cannot build is a finding of rule 1, never a stand-in: an expression that is invalid or out of its range, a member shorter than 1 mm, an outline that is not simple, a cut through a part's centre, a joint by a part that is not convex or is not there, a tail without the parameters it needs, a part cut away, a plate off its members, and a plate on a slab edge element.
15. **What stays reference behaviour** (class C). The framing an engine lays out from a wall, a floor or a roof, which the model does not hold as a family's parts (studs, plates, noggings, headers, joists, and the trusses along a roof), is not this section's: by the steward's decision of 29 October 2026 (open questions, 83) section 7.4 lays it out, its trusses built as these rules build a family's parts. A family's beam's joins (section 6.4) do not cut or lengthen its parts, nor do its `connection`, its own `holes` or the holes of a bolt group through it: the compiler builds its parts without them, and says so (`not-derived`). Its `roll` and its `taper` turn and taper a section (section 6.2, rules 4 and 5), which it does not have, and are not applied: the compiler says so (`roll-family`, `taper-shape`). Its reference line, and its parts' axes, which open question 10 decided for 0.2, are not these rules'.

These are class-A rules, held to the tolerances of section 10: each part's bodies within 0.1 mm of the rules', and its volume within a relative 10⁻⁶.

An example: a beam from `[0, 0]` to `[4000, 0]`, its family two `member` parts of width 45, `bottom`, a `bottomChord` from `[0, 100]` to `[Length, 100]` of depth 200, and `post`, a `heelPost` from `[Length/2, 0]` to `[Length/2, 1200]` of depth 95, whose `cutBy` names `bottom`. `bottom` is the rectangle from x 0 to 4000 and z 0 to 200, 45 × 200 × 4000 mm. `post` is the rectangle from x 1952.5 to 2047.5 and z 0 to 1200, less `bottom`: its first edge, along `bottom`'s underside, leaves nothing outside, its second, `bottom`'s far end, nothing either, and its third, `bottom`'s top, sets apart the piece from z 200 to 1200, which is kept; what lies inside `bottom` is gone. So the beam's volume is 45 × (200 × 4000 + 95 × 1000) mm³, 0.040275 m³, and its two parts are its members, an IfcMember CHORD and an IfcMember POST (Part VIII, 1.6).

*Note (informative).* The reference implementation builds a family's parts as these rules do. On a probe of every member of the language (`packages/openeik/test/fixtures/framing-bodies.json`: trusses with nail plates, joints, cuts, parts that exist and do not, and tails cut and notched from the tip and from the bearing; a rafter cut to its seat; a purlin, a brace and a rafter on sloped beams; and slab edge elements on both anchors, offset, flipped and mitred: 14 elements of 54 parts), `@openeik/tools` agrees with it exactly on each part's pieces, volume and box. On its examples (its work 727, `main` `f2bc53d2`, 29 October 2026), on the villa's 117 imported rafters, of 129 parts, on the guesthouse's 78 trusses and rafters, of 326 parts, and on the extension's 4 beams of families, it agrees exactly: each element's parts in their count and their ids, and each part's volume, to a relative 10⁻¹³, and its box, to 10⁻⁹ mm; and so do the bodies it gives the bridge (`eikBodyResults`), by the names it gives the parts there, a part's role or its id. They differ in four places, where the text decides. A tail's `notch` that names no `origin`: reading a folder, the reference measures it from the tip; its own schema, and this specification's, give it `bearing`, which rule 7 follows. A mitred slab edge element's fit: the reference tries it at its `width`, or its type's `edgeProfile`'s, either side of its edge, which no record of a family's section gives; rule 11 tries it at its parts' least and greatest `x`, which are its section's. And a plate on a slab edge element: the reference lays it along the edge, `(w + thickness)/2` either side of the edge's middle, which Part II, 5.4's "on the members it lies `on`" does not describe; rule 11 has it a finding. And a mitred slab edge element's volume: the reference gives each piece's area by its run, rule 12 the body's own, which its slanted ends change; the bodies are the same.

Reference: `framingSchema`, `framingExpression` and `framingProfiles` in `src/core/elements/framing.ts`; `framingSolids` in `src/core/geometry/framingGeometry.ts`; `edgeFramingSolids` in `src/core/geometry/edgeFraming.ts`; `edgePlacement` in `src/core/elements/edgePlacement.ts`; `framingIfcClass` in `src/core/elements/framingIfc.ts`. In `@openeik/tools`: `familyParts` and `familyEvaluate` in `packages/openeik/src/compile-framing.js`, placed by `compileBeam` and `compileFramingEdge` in `compile.js`.

### 6.7 A member between two points

*Part of 0.2. OpenEik 0.1 had it as the proposal `member`: in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), a `member` is of a category 0.1 does not have, and a compiler derives it no body (section 1, rule 4). The section adds no file: the member is its element's record (Part II, 6.2.1).*

By the steward's decision of 30 October 2026 (open questions, 110), one rule for linear members in any direction, sharing this section's reference line, axis, roll, taper and joins. Given a member (Part II, 6.2.1) with profile points `P0` and `P1`, its start's height `z0 = elev(levelId) + offset` and its end's `z1 = elev(end.levelId) + end.offset`:

1. **Its line.** `A = (P0, z0)` and `B = (P1, z1)` are the ends of its reference line (6.5), the line through the middle of its section, at least 10 mm apart. Its length is `Ls = |B − A|`, and `t = (B − A) / Ls` its direction. No underside sets it out: its reference line is the line its record gives.
2. **Its frame**, the section's `x` and `v` before a roll. Where the member is not plumb, `x = (−u_y, u_x, 0)`, the left normal of its plan direction `u = (P1 − P0) / |P1 − P0|`, as a beam's `n` (section 3); where it is plumb (Part II, 6.2.1, rule 4), `x = (1, 0, 0)`, the model's x axis. In both, `v = t × x`. So `x`, `v` and `t` turn as the model's x, y and z do: for a member that is not plumb, `v` is square to the line in its vertical plane and points up, as a beam's is (6.2, rule 3); for a plumb member that runs up, `x` and `v` are the model's x and y, as a column's section's `width` and `depth` before its turn (6.1, rule 2), and for one that runs down, `v` is the model's −y.
3. **Its roll.** With a `roll` ρ, in degrees, the section turns about the line, right-handed about `t`, as a beam's does (6.2, rule 5): `x' = x cos ρ + v sin ρ` and `v' = −x sin ρ + v cos ρ`. Without one, `x' = x` and `v' = v`.
4. **Its body.** The point `(x, y)` of the section, `x` across and `y` up from the middle of its bounding box, lies at `A + s t + x x' + y v'` for `s` from 0 to `Ls`: the section stands square to the line, the middle of its bounding box on it (6.5), its `width` along `x'` and its `depth` along `v'`. A `custom` section's point `[px, py]` is `(px − mx, py − my)` there, `(mx, my)` the middle of its outline's bounding box (Part II, 5.2, rule 10). Without a section, the section is a rectangle `width` across by `height` deep (Part II, 6.2.1, rule 5).
5. **A taper**, on a rectangular section only, as a beam's (6.2, rule 4): the depth runs linearly from the section's `depth` d at `A` to `taper.endDepth` e at `B`, centred on the line: at `s` along it, `y` runs from `−d(s)/2` to `d(s)/2`, where `d(s) = d + (e − d) s / Ls`. Its reference line runs through the middle of each section, as 6.5, rule 3 says. A taper on another section is left out, and a compiler says so (`taper-shape`).
6. **Its axis** is its reference line moved by its section's centroid offset, turned with the body (6.5, rule 5): each point moves by `e_x x' + e_v v'`, where `(e_x, e_v)` is the offset in the section's own `x` and `v`. Section 6.5, rule 6 says which sections have none; a tapered member, as a tapered beam, has none.
7. **Its joins** are a beam's (6.4): `at` names its start, `A`, or its end, `B`; they are found on reference lines; and a mitre joins two members of the categories `beam`, `column` and `member`, any two of them.
8. **What it measures** (informative, as section 9): its length, `Ls`, as recorded, whatever its joins do (6.4, rule 4); its volume, its section's area along `Ls`, a tapered one's mean area, its joined ends on their cuts.
9. **A column's and a beam's line as a member's.** A column is the member from its base to its top, `(c, z0)` to `(c, z0 + H)` (6.5, rule 1), of its section, its `turn` its roll: plumb and running up, its frame is the column's before its turn (rule 2), and a roll turns it as `turn` does, counter-clockwise in plan. A beam with a section and no taper is the member along its reference line (6.5, rule 2), of its section and its `roll`: that line runs parallel to its set-out line, the same distance over it at both ends, and the member's frame is the beam's. Each has the same body and the same axis as that member. So an analysis reads beams, columns and members alike, each by its line, its frame and its section. A tapered beam's sections stand square to its set-out line (6.2, rule 4), not to its reference line as a member's do (rule 5), and a beam without a section is level (6.2, rule 2).

These are class-A rules, held to the tolerances of section 10.

The brace of Part II, 6.2.1, a square hollow section 100 × 100 × 5 from `(0, 0, 0)` to `(6000, 0, 3450)`, runs `Ls = √(6000² + 3450²) = 6921.16` mm, `t = (0.86691, 0, 0.49847)`, with `x = (0, 1, 0)` and `v = (−0.49847, 0, 0.86691)`; its section, 1900 mm² with square corners, gives it 0.013150 m³. The plumb hanger from `(2000, 1000, 3600)` down to `(2000, 1000, 2700)` has `t = (0, 0, −1)`, `x = (1, 0, 0)` and `v = (0, −1, 0)`.

*Note (informative).* `compileModel` of `@openeik/tools` builds a member so, as a sweep of its section along its line (section 8, N4), its joins cut as a beam's, its line and axis among its lines. The reference implementation has no member (Part II, 6.2.1, its note); its beams and columns are built as rule 9 says, by `memberSolids` and `memberStructuralAxis`.

## 7. Reference behaviour, and the class-A rules stated from it

Sections 7.1 and 7.2 are informative: what the reference implementation does where this specification fixes no rule, the class-B and class-C rules (section 2). Sections 7.3 to 7.6, part of 0.2, state class-A rules from its engines, which a compiler of the core class implements (section 2).

### 7.1 Wall joins (informative)

The reference implementation joins walls from their geometry; nothing is stored but the switch `joinEnds: [start, end]`, where `false` keeps that end free.

- **Corners (L).** Two wall ends pair when the walls' bases are at the same height (rounded to the millimetre), the ends lie within twice the thickest wall's thickness of each other, and the two axes cross near both ends: within the thicker wall's thickness, and within a quarter of each wall's length. Ends at the same point always pair. When more than one pair is possible, a partner of the same height, outline or attachment host is chosen; when that still leaves more than one, the end stays free. A corner is mitred: each wall ends on the line through its inner and outer corner points.
- **Tees (T).** An end that has no corner partner and meets another wall's side part-way along, within half that wall's thickness plus 50 mm of its axis and at more than 10° to it, butts it. Its layers run through the host's layers on that side up to the host's core face.

In the example, the partition's ends meet the south and north walls as tees at their core faces, `y = 135` and `y = 6865` (the exterior walls' 15 mm linings give way), and the four outer walls meet in mitred corners at the outer corner points.

Reference: `joinPartner`, `wallEndPair` and `teeHost` in `src/core/elements/wallJoins.ts`.

*Note (informative).* Section 7.4.2 states these rules exactly, for what a framed wall layer's layout reads of a wall's corners and tees; with it, the core compiler still ends a wall's own body square.

### 7.2 Others (informative)

Room boundaries (but for those of section 7.5, of 0.2), stair runs and landings (but for those of section 7.3, of 0.2), railings (but for the line of a railing on an outline, a wall's top or a slab edge element, and its given posts, section 11.2), a door's and a window's own body (but for how it opens, Part II, 6.5, and its frame, leaves and glass, section 4.3.1, of 0.2), components (but for a component's frame and the bodies of section 7.6, of 0.2), a slab edge element's `notches` (but for section 4.6, rules 12 to 14, of 0.2) and a framing family's section (but for section 6.6, of 0.2), timber framing members and trusses (but for a wall's framed layers', a roof's truss layout and its hip sets, and a floor's joists, section 7.4, of 0.2), MEP fittings between runs (a run's own bends are part of its body, section 12) and the paths of downpipes worked out from their gutters, rebar shapes, precast pieces, steel joints, a column's or a beam's own `holes` and the holes a bolt group drills in the members its `through` names (Part II, 6.2), and regional area rules are reference behaviour. Their results enter the model only when a command materialises them as records.

*Note (informative).* Open questions 71 to 79, raised on 26 October 2026 by the IFC bridge of `@openeik/tools` (Part VIII, 1), asked the steward which bodies that no rule of this part gave become rules. The steward decided all nine on 26 October 2026 as proposed. Into 0.1, and written here the same day: a shaft's openings (4.2, rule 8), a slab edge element's section, anchor, offsets, facing, chamfer and mitres with its host's thickened edges and fills (4.6), and a gutter's body (4.7); and, in Part II and Part VIII, how a door or a window opens (Part II, 6.5; Part VIII, 1.2), where a member's profile sits in IFC (Part VIII, 1.4) and which point of the plan the site's latitude and longitude name (Part II, 2). For 0.2: a door's and a window's frame, leaves and glass (4.3), a room placed by a point, a component's frame and its bodies that are boxes and prisms, a stair's numbers and the layout of straight, L and U stairs, and a site's coordinate reference systems. Until 0.2, those stay reference behaviour here.

### 7.3 Straight, L and U stairs

*Part of 0.2. OpenEik 0.1 had it as the proposal `stairs`: in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), stair runs and landings are reference behaviour, as section 7.2 says. The section adds no file and no member: the members are those of a stair's `stair` and of its type's `stair` (Part II, 5 and 6.1).*

By the steward's decision of 26 October 2026 (open questions, 76), every stair's risers, their height, its going and its location line, the layout of a straight stair and of an L or a U stair with a landing, and the bodies of a cast concrete stair's flights and landings, are these rules.

A stair's **frame**: x up its first run, from its profile's first point, the foot of its first riser, towards its second (Part II, 6.1, rule 7), along `u`; y to the left looking up the stair, along `n` (section 3); z up. Its base is its level's elevation plus its `offset`, and its top its top constraint's level's elevation plus that constraint's offset, else its base plus its `height` (5.1). `W` is its `width`, `s` its `stair`, and `f` its type's `stair`.

1. **Its numbers.** Its rise is its top less its base, and MUST be more than 0. It has `s.risers` risers, else the fewest `f.maxRiser` allows, ⌈rise / `f.maxRiser` − 10⁻⁹⌉, and at least 2; each riser R = rise / risers high; its going g is `s.going`, else `f.going`. Where it has no risers or no going, its top is not above its base, its first run has as many risers as it has or more (rule 5), or an L's landing is shallower than its run is wide (rule 5), the compiler gives it no layout and no body, and says why (`stairs-layout`). A validator SHOULD warn of such a stair, which it can tell from the records alone.
2. **Its location line** is the line its profile gives. Its width lies across it from y0 to y0 + W, where y0 is −W where `s.locationLine` is `left` (the line is its left edge, looking up), 0 where it is `right` (its right edge), and −W/2 otherwise.
3. **A flight** of n treads, its first riser's foot at o, running along a way d, from a to b across it along d's left, on a height z: its tread j, from 1 to n, is the plan rectangle from (j − 1)·g to j·g along d and from a to b across it, its top at z + j·R; its nosing line is its front edge at that height, from its left end to its right, looking up the run. Treads are numbered from 1 up the stair, across its flights. A flight has one riser more than it has treads: its last rises to the landing or the floor it reaches.
4. **A straight stair** (`s.shape` `straight`) is one flight: from its frame's origin along `u`, from y0 to y0 + W, on its base, with risers − 1 treads; its last riser rises to its top, the floor above.
5. **An L or a U stair with a landing** (`L` or `U`, without `s.winders`). Its first run has r1 risers: `s.firstRunRisers`, else half its risers rounded up, at least 1 and at most risers − 1. Its first flight is rule 4's with r1 − 1 treads, so that it ends at L1 = (r1 − 1)·g; its landing's top is at its base plus r1·R, and the landing runs from x = L1 to L1 + D, where D is `s.landingDepth`, else W.
   - An **L**'s landing lies from y0 to y0 + W, and D MUST NOT be less than W. Its second flight turns a quarter to the side `s.turn` gives, `left` where it gives none: along `n`, its first riser's foot at (L1 + D − W, y0 + W), or, to the `right`, along −`n`, its first riser's foot at (L1 + D, y0); either way from −W to 0 across its way's left. It leaves the landing's far end, beside its side.
   - A **U**'s second flight comes back beside the first, `s.gap` from it, 100 mm where it gives none: with yb = y0 + W + gap to the `left` and y0 − W − gap to the `right`, it runs along −`u` from (L1, yb + W), from 0 to W across its way's left, its first riser on the landing's front edge. Its landing lies from min(y0, yb) to max(y0 + W, yb + W).
   - The second flight stands on the landing's top and has risers − r1 − 1 treads; its last riser rises to the stair's top.
6. **A cast concrete stair** (`f.construction` `concreteCast`) has these bodies, closed.
   - **Each flight** with treads, the whole of its width: in its run's vertical plane, x up the run from its first riser and z up, its top is its steps, each tread's top over its going; its ends are square, at its first riser and at its last tread's back; and its underside is the soffit, the line `f.waist` below the line through its risers' roots, z = z0 + (R/g)·x where z0 is the height it stands on, measured square to that line, so at z0 − `f.waist`/cos(atan(R/g)) + (R/g)·x, but never below its floor: the stair's base for a flight on it, and the landing's underside, its top less `f.landingThickness`, for a flight on a landing. The body is that outline carried across the flight's width. Each body names its part `flight` and its piece `flight:<k>`, k from 0.
   - **Each landing**: its outline, from its top less `f.landingThickness` up to its top; its part `landing`, its piece `landing:<k>`.
   - A flight and its landing meet on the plane of the flight's last riser, and do not overlap.
7. **What stays reference behaviour** (class C): the parts of every other construction (stringers, treads and risers of timber, precast pieces, cross-laminated timber), the nosing a type's `nosing` gives a tread, winders and balanced winders, spiral and helical stairs, and a stair that repeats another (`s.repeatOf`). The compiler gives them no layout and no body; a bridge says that it approximates them (Part VIII, 1).

These are class-A rules, held to the tolerances of section 10. With them, a railing on a straight, L or U stair can follow its flights by rule (open questions, 18); until that rule is written, a railing's line on a stair stays reference behaviour (11.2).

*Note (informative).* The reference implementation lays a stair out and builds a cast concrete stair's flights and landings as these rules do, and checks a stair's comfort, `2·R + g`, against its type's `comfortMin` and `comfortMax`, which these rules leave alone. On a probe of eight stairs (`packages/openeik/test/fixtures/stairs.json`: straight, L and U stairs both ways, each location line, a given first run, landing depth and gap, a stair turned 37° and one 120°, one whose top is a level's, and a timber L), `@openeik/tools` agrees with it exactly on every number, tread, nosing line and landing, and on the volume and box of every flight and landing of its concrete stairs; on the reference implementation's seven examples (its work 727, 28 October 2026), on the layout of both their stairs, of cross-laminated timber.

Reference: `stairNumbers`, `stairLayout` and `stairSolids` in `src/core/elements/stairs.ts`; `stairPredefined` in `src/core/io/ifcExport.ts`. In `@openeik/tools`: `stairLayout` and `flightSection` in `packages/openeik/src/compile-stairs.js`, built by `compileStair` in `compile.js`.

### 7.4 The members of a framed wall layer

*Part of 0.2. OpenEik 0.1 had it as the proposal `framingLayout`, which decision D5 of the plan for 0.2 put into the first version it was finished for: in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), timber framing members and trusses are reference behaviour, as section 7.2 says. The section adds two members, a layer rule's `battens` (section 7.4.8, rule 1) and a roof opening's `header` (section 7.4.13, rule 10), and no file: the other members it reads are those of a wall type's layer `framing`, a slab type's layer `joists`, a wall's framing members, a roof's `trussLayout` and a truss family of 0.1 (Part II, 5.1, 5.4 and 6.3), whose meaning these rules give.*

By the steward's decision of 29 October 2026 (open questions, 83, part 2), the reference implementation's timber framing engine becomes these rules, as far as it lays out a wall's layers: its plates, studs, end and corner studs, the backing of a wall that ends against it, each door's and window's jacks, kings, headers, sill and cripples, its noggings and battens, and the heel members over a level top plate. A wall's corners and tees, which section 7.1 leaves to reference behaviour, are stated in section 7.4.2 for what the layout reads of them, and a wall's cut roof, which the note on section 5.3 leaves to reference behaviour, in section 7.4.3. Its other engines become these rules too, by the same decision: a roof's truss layout (section 7.4.13), the walls it bears on (section 7.4.14), a floor's joists (section 7.4.15) and a truss layout's hip ends (section 7.4.16). What the rules cannot state yet is said, with a code, and laid out not at all (section 7.4.12).

In these rules lengths are in mm, and two lengths within 10⁻⁶ mm of each other are equal.

### 7.4.1 A framed layer, its rule and its elevation

1. **A framed layer** is a layer of a wall's type that carries `framing`. A compiler lays out each framed layer of each wall but those of section 7.4.12, each on its own, as if it were its type's only framed layer, into **members**. It changes no body: the layer's own body stays its layer's (section 4.1), and the members are results of their own.
2. **Its rule, with its defaults.** A rule is read with these values for what it leaves out: `material` C24, `direction` vertical, `start` left, `restartAtOpenings` false, `restartFrom` king, `restartMinWidth` 0, `bottomPlates` and `topPlates` none, `plateOverhangAtEnds` 0, `top.mode` auto, `rakingTopPlate` true, `roughOpeningGap` 0, `bottomPlateAtOpenings` with doors `cut`, windows `keep` and `clearance` 0; for each tier `headerPlies`, `kingStuds` and `jackStuds` 1, `cripplesAbove` and `cripplesBelow` true and `studsAtKings` false; no noggings where it gives no `noggings`, and there `rows` 0 and `staggered` false; `junctions.L` butt, `junctions.T` backer, `junctions.end` single and `junctions.endFlat` false; `moveBlockedStuds` false, `minGap` and `middleBay` 0, `studsAtPosts` false, and `battens` service. A plate is a rule's `bottomPlates` or `topPlates` entry, the first two of each. A rule without a member's `width`, a `spacing` or a structural tier is not read: its layer is not laid out (`framing-layout-rule`).
3. **What the rule may hold.** A rule ought to have its member, its plates and its sills no deeper than its layer, a spacing no less than its stud's width, its tiers in order of increasing `maxWidth`, each tier's header plies together no deeper than its layer, and a `relyOn` that names another framed layer of its type; and to be on a wall type's layer of some thickness. A validator warns of one that is not (`framing-layout-rule`). A compiler lays such a rule out as these rules say, each section's depth taken as at most its layer's thickness (rule 5); a layer of no thickness it does not lay out.
4. **The elevation.** A layer is laid out in its wall's elevation: x along the wall's baseline from its first point, along `u` (section 3), and z up from its base, its level's elevation plus its `offset`; and y across the wall from its exterior face, the first layer's outer face, so that a layer lies from y0, the sum of the thicknesses of the layers before it, to y1 = y0 + its thickness. The point at x and y lies in plan at `P0 + u x + n (T/2 − y)`, T the wall's thickness (section 4.1).
5. **Sizes.** w is the rule's member's `width`, a stud's width along the wall. A section's depth across the wall, d, is its `depth`, else its layer's thickness, and at most its layer's thickness; a section is centred in its layer across the wall unless a rule below places it.
6. **The order of its members.** A layer's members are laid in this order, which is the order of its result: its bottom plates and its top plates (7.4.5); its end studs, its corner and end flat studs, the studs that back a T, and the grid's studs (7.4.6); each opening's jacks, kings, headers, sill and cripples (7.4.7); a T's ladder and the noggings, or a batten layer's battens (7.4.8); then cut where a ridge beam bears in it, and its post (7.4.14, rule 6); then cut where a wall runs through (7.4.8, rule 4); then its heel members (7.4.4, rule 6).
7. **Chains.** The bottom and the top of a layer, and its plates' faces, are chains: a function of x, linear between its points, given by points of increasing x; where two points have one x the chain steps there, and has a value left of the step and one right of it. A member at x, w wide, stands from x − w/2 to x + w/2 between two chains, as the polygon between them over that span; it has no body where the polygon has no area, or its top lies under its bottom anywhere by more than 10⁻³ mm.

### 7.4.2 Corners and tees

These rules say which wall ends meet, at a corner or on a wall's side, and the line each joined end's layers stop on (section 7.1, stated). They change no wall's body: a compiler of the core class ends a wall square, as in 0.1 (open questions, 104).

1. **A storey.** Two walls are of one storey where their bases lie within 0.01 mm of each other. A wall's end is kept free, and meets nothing, where its `joinEnds` says `false` for it. A wall's thickness T is its type's layers' together, or its `width` where its type has none.
2. **Ends that pair.** An end of a wall pairs with an end of another where the two points are within 0.01 mm of each other; or where the two walls are not parallel (|u × u′| ≥ 10⁻⁶) and their axes cross within the thicker wall's thickness, and within a quarter of each wall's length, of each end, measured along each axis.
3. **A corner on its storey.** An end's storey partners are the ends of the walls of its storey within 2·max(T_max, T) + 0.01 of it, T_max the thickest wall of the model, that pair with it and are not kept free. Where it has more than one, only those of a wall as high as it within 0.01 mm, or of a wall that has a `wallOutline` where it has one, or attached to the same host (`top.attach.hostId`), count. Where it has storey partners at all, it has a corner only where one counts, and only one, and the corner fits (rule 6): over the end's height, up to its own top or its base plus its partner's `height`, whichever is lower.
4. **A corner across bases.** An end that has no storey partner and meets no wall's side (rule 7) has corners with the ends of walls of other bases within 1 mm of its point that pair with it, are not kept free, have no storey partner and meet no side either, and share more than 1 mm of its height, each over the heights the two share. Between each two of the heights at which a shared height begins or ends, the end has a corner with the one such end there, where there is only one, and that end has only this end there too, and the corner fits; a partner's corners one above the other are one corner.
5. **Its partner** is the one of an end's corners over most of its height, a later one only where it is over more by more than 0.01 mm.
6. **A corner fits** where the two walls do not run the same way from it: the directions from the two ends into their walls' bodies differ, their dot product at most 0.999999. Parallel walls (|u × u′| ≤ 10⁻⁶) fit. Otherwise the mitre reaches along the wall t = |(s n′ − n) × u′| / |u × u′| · T / 2, s −1 where both ends are first points or both last, else +1; the corner fits where t is at most half either wall's length and 4 T. Where it reaches further, it fits only where, for each of the two walls, each face is cut back by the mitre line (rule 8) by at most 4 times its thickness, and keeps more than 1 mm of its length beside what the lines its other end may stop on cut back from it (each at least 0): its corner's mitre and its partner's outer face, or its T's core face.
7. **A T.** An end of a wall at least 1 mm long meets the side of a wall of its storey at least 1 mm long where the two run at more than 10° to each other (|u · u′| ≤ cos 10°), the end lies within T′/2 + 50 of that wall's axis, measured square to it, and part-way along it, at least T/2 + 1 from either of its ends, T′ that wall's thickness and T this one's; and where the wall runs away from it: the direction from the end into its own body has a part along that wall's left normal of at least 10⁻⁶, of the sign of the end's offset from its axis where that offset is more than 1 mm. Where exactly one wall's side is met, the end meets it as a T, where it has no corner partner: on that wall's left (+1) or right (−1), as its body runs, and at its core face on that side, the outer face of its first core layer on the left and the inner face of its last on the right, or its own faces where no layer is core.
8. **The line a joined end stops on.** At a corner, the mitre: the line through the point where the two walls' inner faces meet (the faces towards each other's bodies) and the point where their outer faces meet, or the partner's axis where the two points are one; where the two walls' faces are parallel and never meet, the line square to the wall through its end's point; an end none of whose corners has a mitre has no line, and its frame ends free. At a T, the host's core face on its side. An end's x at an offset c along its left normal is where the wall's line at c meets that line, measured from the wall's first point.

### 7.4.3 A framed layer's envelope

1. **The outline.** A framed layer is laid out within its envelope, an outline in its elevation. Its source is the wall's `wallOutline`, else the rectangle from x = 0 to its length L and from its base up to its height (section 5.1).
2. **The faces that cut it.** A wall attached to a host (section 5.3) is cut by the host's face, by rules 2 and 3 of 5.3 and its `offset`, every plane of it, or, where its `mode` is `level`, the one level plane at the lowest point of that face over the wall's core band at its two ends (from its first core layer's outer face to its last core layer's inner face, or its whole thickness where no layer is core). A wall with a **cut roof** is cut by that roof's face too: its `top.cutRoofId`, else, where its type's `wallAttach.cutToAttachedRoof` is true, the roof it is attached to; the face its `top.cutRoofFace` names (its underside where it names none), by rules 2 and 3 of 5.3, with no offset. A cut roof MUST be a roof. Every framed layer is cut by the cut roof's face; a layer **extended** past the attached face is not cut by the attached face. The layers before a wall's type's first core layer are extended where the wall is attached and its `top.extendExteriorLayers` is true, or where it gives none, the wall has a cut roof, and its type's `wallAttach.extendExteriorLayers` is not false. Legacy members are read as Part II, 6.4 reads them. A wall whose top fails a rule of section 5.1 or 5.3, attached to a barrel vault or cut under one, or whose cut roof is no roof, is not laid out (`framing-layout-top`).
3. **The faces as lines.** Each plane of the faces that cut a layer is taken, for its envelope, as the line along the wall of its height above the base over that face of the layer, y0 or y1, over which it is higher at the middle of the wall's length (y0 where equal), from x = 0 to x = L. The top of a layer cut by an attached face is the lower envelope of these lines; of any other layer, the lower envelope of its source's top and these lines. Its bottom is its source's bottom.
4. **Its ends.** At each end of the wall, the layer ends: at a T (section 7.4.2, rule 7), at the x of the far one of its two faces' ends on the line the end stops on (the less at the wall's first point, the greater at its last); at a corner, at its corner's x (rule 5). Where an end lies outside 0 to L, the layer's top and bottom run on, level, to it; where it lies inside, the outline is cut there.
5. **How a layer ends at a corner.** With its partner (7.4.2, rule 5), where the two walls are square to each other within 5° (|u · u′| ≤ sin 5°): the partner's matching layer is its layer of the same place in its type, counted from the other side where both ends are first points or both last; the layer's middle line meets that layer's two faces at two x, the outer the one further from the wall's body. The **core runs through** on the longer wall (by more than 1 mm; of two within 1 mm, the one whose id is first by code units), unless a `framingCorners` names it: the wall's own `through` or `butt` at that end where it differs from its partner's at its end, else its partner's, `butt` there making this core run through. A core layer runs through where its wall's core does, any other layer where its core does not. A layer that runs through ends at the outer x (`through`), any other at the inner x (`butt`); the inner x is its **partner's inner face**. Where the walls are not square, or the partner's type has no matching layer, the layer is mitred: its end is where its middle line meets the line the end stops on, and its faces' ends where its two faces do (`miter`). At a T, its end is where its middle line meets the T's core face, and its faces' ends where its two faces do (`tee`).
6. **Standing.** The outline is cut to the x where its top lies above its bottom: an attached gable drawn to its eave's corner stands where its roof comes down to its base.
7. **Its lowest top** is the least of: its top at its outline's two ends, its top's points between, and, where faces cut it, each face's least plane over each of its two faces, y0 and y1, at the x of each end's face (its corner's or its T's face end, held within the outline's x; 0 and L where the end is free). **Its drop across** is, where faces cut it, the difference between the least of the faces over y0 and over y1 at the middle of its outline's x.
8. **The walls that end against it.** The walls whose ends meet the layer's wall as a T (7.4.2, rule 7) are taken in order of their first x along it, then of their ids. Where the layer lies between the T's core face and the face of its wall on the ending wall's side, the ending wall **runs through** it (`cut`): over the x where the ending wall's two faces cross the layer's two faces, from the ending wall's base up by its `height`. Where the layer is the core it runs to, or its type has no core layer, it **backs** it (`back`): over the x where the ending wall's two faces meet the core face, and with the x where the ending wall's framed layer (its first that carries `framing`, else its first core layer) meets that face. A T of any other layer is not the layer's.

### 7.4.4 Its top

1. **Its mode** is its wall's `framingTop.mode`, else its rule's `top.mode`. `auto` is `raking` where its top has a segment steeper than 1 in 10 along the wall; else `underFloor` where a floor bears on it (rule 4); else `levelPlate`.
2. **A level plate**: its top plates' top is its wall's `framingTop.wallLiveHeight`, else its rule's `top.height`, else its lowest top (7.4.3, rule 7, or its top's points, the less). A top plate above its lowest top is not laid out (`framing-layout-top`). The plate's top is its **bearing plane**, and over it the **heel zone** is its envelope between the bearing plane and its top, where that holds more than 100 mm².
3. **Under a floor**: its top plates' top is the underside of the bearing floor's structure (rule 4). Without a bearing floor, or with one whose structure's underside lies above its lowest top, it is not laid out (`framing-layout-top`). Its **bearing plane** is the floor's top, held at its lowest top; its heel zone is its envelope between the bearing plane, held under its top, and its top. A wall-live height is not read.
4. **The bearing floor** is the slab its wall's `framingTop.floorId` names, which MUST be a slab (else `framing-layout-floor`); else the floor found. A slab's top is its level's elevation plus its offset, less the wall's base; the underside of its structure lies below its top by its layers down to and including its last core layer, or by all its thickness where no layer is core. A floor is found among the slabs whose structure's underside lies at least 1000 mm over the wall's base and not above the layer's lowest top. Along the layer's x, from its outline's least x + 50 every 100 mm to its greatest, a slab covers a sample where its outline (its stored `profile`) holds the plan point at that x and one of the y y0 − 50, y0, the layer's middle, y1, y1 + 50, and, where no core layer follows the framed layer in its type, the wall's room face plus 50 (T + 50); its coverage is 100 for each sample it covers, at most the layer's length. The candidates are the slabs that cover at least the lesser of 1000 and the layer's length, the highest underside first, then the greatest coverage. Below, "enough" is the lesser of 1000 and the layer's length, in mm of coverage. A candidate **reaches the frame** at a sample where its outline holds one of y0 + i, y1 − i and the layer's middle, i the lesser of 10 and a quarter of the layer's thickness; at a sample where it does not, it **meets a face** at y0 − 50 or at y1 + 50, and **meets the facade** at y0 − 50 or at −50. Where the layer's top is found by itself (its mode `auto`), and among the candidates that reach the frame over less than enough, one meets the face y0 − 50 and one the face y1 + 50, each over enough, only the candidates that reach the frame over enough count: a party wall that floors meet from both sides bears neither. Else, where its mode is `auto`, a candidate covers enough only with the room face (at the first five y it covers less), and a slab of those whose underside lies as these rules ask meets the facade over enough, only the candidates that cover enough at the first five y count: a floor drawn to the room face of a wall that another floor meets at its facade stands beside it. The bearing floor is the first that counts.
5. **Raking**: its top plates follow its top.
6. **Heel members.** Over a level plate or under a floor, where it has a heel zone and its lowest top (7.4.3, rule 7) lies at least its first top plate's width (or its member's) plus w above its bearing plane: on each segment of its top a **heel plate**, the section of its first top plate (or of its member), hanging from its top lowered by its drop across, h √(1 + s²) deep, h that plate's width and s the segment's slope; and a **heel post** at each x of its studs', end studs', kings' and cripples' lines (their first points), in the order they were laid, then of the places of its stud grid (7.4.6, rule 1), in their order, each but where one taken already lies within w of it, from the bearing plane up to the heel plates' underside, where that is at least w. A heel plate's key is its segment's number, from 0; a heel post's the key of its grid place, or the x of the line it stands on, to 10⁻⁶ mm (`1222.5`). Where its lowest top is lower, it has none, which is said. Where trusses bear on the wall, they hold their width of the heel zone, or rest on the heel plate at their seat (7.4.14, rules 3 and 5).

### 7.4.5 Plates and openings

1. **Its openings** are the doors and windows its wall hosts. An opening whose bottom (`offset`) lies at or above the frame's top (rule 7) less 1 mm, the least of it at the opening's two sides and its middle, held within the frame, is not framed: it lies in the roof's zone. Each other opening's **rough opening** runs from `along` − g to `along` + `width` + g and from `offset` − g (0 where its `offset` is 0) to `offset` + `height` + g, g the rule's `roughOpeningGap`. A pocket door (a door whose type's `openingFamily` is of the kind `door` with the operation `pocket`, Part II, 6.5) reaches over its pocket: its rough opening runs on by its `width` + 150 towards its wall's first point where its family's `hinge` is not `right` and its `handFlipped` is not true, or both are so, else towards its last point. An opening with an `offset` above 0 may have a sill and cripples under it (7.4.7, rules 4 and 5); one at 0 has none.
2. **Its tier** is of the rule's `openings.nonStructural` where the wall's `structural` is false and the rule gives them, else of its `structural`: the first whose `maxWidth` is at least its rough width; else the last, which is said.
3. **Its zone** is its rough opening widened on each side by its tier's jacks and kings, (`jackStuds` + `kingStuds`) w. A place x **lies in a zone** where a stud there overlaps it, x + w/2 above its first x and x − w/2 below its last, the first such zone; and **in a hole** where a stud there lies within its rough opening.
4. **Element joints.** Each of its wall's `framingJoints` that lies more than 2w inside the outline's x from both ends is a joint, where prefabricated elements meet, each framed on its own; one that does not is not used, which is said.
5. **Plates.** Its bottom plates are laid up from its bottom, the first (`sole`) on it and the second (`sole2`) on the first; its top plates down from its top (raking), from the level plate's top, or from the floor's structure's underside, the first (`top`) under it and the second (`top2`) under the first. On each segment of the chain they follow, of slope s, a plate h wide (its `width`) is h √(1 + s²) deep, and lies the depth of the plates before it, each √(1 + s²) times its width, from the chain. A plate runs over its segment, on past the outline's ends by `plateOverhangAtEnds`, and is cut at each joint; a top plate is not laid on a sloped segment where `rakingTopPlate` is false, and is cut to above the frame's foot. A plate whose `side` is `exterior` lies against the layer's face y0, one whose side is `interior` against y1, across its depth; any other is centred. A plate's key is its segment's number along its chain, from 0 (a step is no segment, a segment that takes no plate is one), and, for a piece after a gap or a joint, `@` and the gap's opening's id or `j<i>`, i the joint's number from 0: `0`, `1@D1`, `0@j0`.
6. **Bottom plates cut at openings.** Where the bottom plates have a width, an opening's own `bottomPlate` (`cut` or `keep`), else its rule's `bottomPlateAtOpenings` for its category (doors, windows), says whether they are cut under it. They are cut only where the opening's `offset` lies under the bottom plates' top (else, where its own `bottomPlate` asks for a cut, that is said); from its `along` − g − c to its `along` + `width` + g + c, c the `clearance`, held within the outline's x, where that is at least 1 mm; an opening cut above its wall's base leaves the strip under it open, which is said. Cuts that touch or overlap, within 1 mm, are one gap, named for the opening whose cut reaches furthest along it. A bottom plate's pieces between the gaps, each at least 1 mm, are its plates.
7. **The frame's foot** is the bottom raised by the bottom plates' widths together; **its top** is, raking, the top lowered on each segment by the top plates' widths together times √(1 + s²) (by nothing on a sloped segment where `rakingTopPlate` is false), else the level plate's or the floor's underside lowered by the top plates' widths. Over a level plate or under a floor, a frame whose top lies less than w above its foot's highest point is not laid out (`framing-layout-top`).

### 7.4.6 The studs

1. **The stud grid** is a list of places, each a stud's middle, with a key. A place is set only within the frame, from its least x + w/2 to its greatest − w/2, and set again where its key is set. Between each two of the frame's ends and joints, the grid is walked: from a point moved by the offset, a spacing at a time, each step a place, while the step does not pass the walk's limit; each place keyed `<e><walk><k>`, e `e<s>-` for the s-th element after a joint and nothing for the first, walk the walk's prefix below, and k counting the walk's places from 1. Its start is the wall's `framingStart`, else its rule's `start`, and the wall's `framingOffset` (0 where it gives none) moves the point a walk starts from, in its direction:
   - `left`: from the first end, towards the second;
   - `right`: from the second end, towards the first, prefix `r`;
   - `centre`: a place at the middle (`c0`), and from it towards both ends, prefixes `c` and `cl`;
   - `bothEnds`: from the second end to the middle (`r`), then from the first towards the middle, or, with a `middleBay`, towards the least of the middle and the first place from the second end less the middle bay, so that no short bay is left between them.

   Where `restartAtOpenings` is true, the start is `left` or `right`, and a place falls in an opening's zone whose rough width is at least `restartMinWidth`, the grid sets its places a spacing apart from there across the zone, and walks on from the far king's middle (`restartFrom` `king`) or the opening's far side (`opening`).
2. **Posts.** A post stands in a framed layer where a column whose type's section is more than w both ways, which is no materialised member (Part II, 10), has its point in the layer's band (y0 to y1) and within its wall's length (x from 0 to L), and spans some of its wall's height (its top not under the wall's base, its base not over the wall's base plus its `height`); it stands along the wall over its section's side that lies along it (|u_x| `width` + |u_y| `depth`). With `studsAtPosts`, the grid sets a place against each side of each post (`p-<post>-a`, `p-<post>-b`).
3. **Studs set by hand.** Each of its wall's `framingStuds`, in order, is a place (`m-<i>`): a grid place less than w − 10⁻⁶ from it is dropped, or, where it lies within 2 mm of touching, the stud by hand stands against it, moved w from it on its side.
4. **End studs** (`endStud`) stand full height at each end of the frame and on each side of each joint, flush: `end0` at the first end, `joint<i>a` and `joint<i>b` at the i-th joint, `end1` at the second. Where `junctions.end` is `double`, each has a second inwards beside it, keyed with a `b` after its key.
5. **A corner's flat stud.** Where `junctions.L` is `wrap` and the layer runs through at a corner (7.4.3, rule 5), a stud laid flat (`cornerStud`, `corner0` at the first end, `corner1` at the second) stands full height against its inner face (y1 − w to y1), from the end stud's inner side to w past the partner's inner face, stopping at the first opening zone that begins (or ends) between the partner's inner face and it; with a `cornerStudWidth`, at most that wide, from where it stops; none where it is narrower than w or reaches outside the frame. Its section is its width along the wall by w. Where `junctions.endFlat` is true, at each end with no corner and no T, a stud laid flat at the inner face, as wide as the layer's thickness, beside the end stud (`end<i>f`).
6. **The places taken** are, as they are laid, the end studs, the corner and end flat studs, the posts, the studs that back a T, the grid's studs, and each opening's jacks and kings; a place is **occupied** where a stud there would overlap one taken, by more than 10⁻⁶.
7. **A wall that ends against this one.** Each T the layer backs (7.4.3, rule 8), in their order, is backed as the ending wall's `framingTees` says at its end, else as `junctions.T` says, else `backer`: `backer`, a stud (`endStud`) on each of the ending wall's face lines, `tee-<wall>-a` and `-b`, or one at its middle, `tee-<wall>`, where it is less than 2w + 10⁻⁶ wide; `ladder`, noggings between the two verticals that flank it (7.4.8, rule 2); `flat`, a stud against one face of the ending wall's framed layer, or the vertical already standing in it, and a stud laid flat at the inner face across the wall's end from it, `teeFlatWidth` wide, else the stock width (45, 70, …, 245, every 25 mm) nearest the ending wall's thickness, the first of equals (`tee-<wall>-s`, `tee-<wall>-f`); `none`, nothing. A backing stud is set only within the frame, on a place not occupied and in no zone; a flat stud only where it overlaps no zone and no vertical but the one it stands against.
8. **The grid's studs**, in order along the wall: a stud set by hand stands against what it overlaps within 2 mm of touching, and is left out where it overlaps more. A stud on an occupied place is left out; with `moveBlockedStuds`, it moves beside what blocks it, on its side, where that place is free, in no zone and within the frame. A stud in an opening's zone is a cripple where it lies in the hole (7.4.7, rule 5), else it is left out; with `moveBlockedStuds`, it moves out beside the zone as a stud, where it lies in the outer half of the jamb and that place is free, or in as a cripple, beside the hole's side, where it lies in the inner half. A stud where the frame has no height is left out. With a `minGap`, a stud on its own place (not moved, not by hand, not against a post) whose clear gap to a vertical (but one set by hand that it touches) or to a zone is less than the minimum gap is left out. Each other is a `stud`, its key its place's, full height.
9. **The verticals** are the end, corner and flat studs, the posts, the backing studs, the studs, the jacks and the kings (7.4.7), each with its half width.

### 7.4.7 Each opening's framing

For each opening, in order of its rough opening's first x, with its tier (7.4.5):

1. **Jacks** (`jack`): `jackStuds` on each side, against the rough opening and each against the last, from the frame's foot up to the rough opening's top, or to the frame's top where the rough opening reaches it (within 1 mm, rule 3); `<opening>:l<j>` on the first side and `<opening>:r<j>` on the second, j from 0.
2. **Kings** (`king`): `kingStuds` on each side, beyond the jacks, full height, each within the frame but where its place is occupied; `<opening>:l<k>`, `<opening>:r<k>`. Jacks are laid within the frame too, whatever stands there.
3. **Headers** (`header`): over the rough opening and the jacks, held within the frame, from the rough opening's top up by the tier's header's `width`, cut at the frame's top, where that is lower (which is said); its plies side by side across the layer, centred together, each its header's depth; `<opening>:<ply>`, ply from 0. A tier without a header has one ply of the stud's section. An opening whose rough opening reaches the frame's top within 1 mm has no header and no cripples above it, which is said.
4. **A sill** (`sill`): under a rough opening that has an `offset` above 0 and whose bottom plates are not cut, where its tier has a `sill` and the rough opening's bottom lies at least the sill's `width` above the frame's foot at its sides, from there down by the sill's width, over the rough opening; `<opening>`.
5. **Cripples** (`cripple`), at the grid's places that fall in its hole (7.4.6, rule 8), in order: above, from the header's top to the frame's top, where `cripplesAbove` is true, there is a header, and that is more than 1 mm (`<opening>:a:<key>`); under, from the frame's foot to the sill's underside (or the rough opening's bottom), where `cripplesBelow` is true, the opening has an `offset` above 0, its bottom plates are not cut, and that is more than 1 mm (`<opening>:b:<key>`). With `studsAtKings`, a place against each side of the hole (`kl`, `kr`) where its nearest cripple lies more than half a spacing from that side, after those of the grid. With a `minGap`, a cripple of the grid less than the minimum gap clear of one against a king or a post is left out.
6. Where two openings' zones overlap, their members overlap, which is said.

### 7.4.8 Noggings and battens

1. **Battens.** A rule whose `direction` is `horizontal` lays battens, of its `battens`: `service` (the default, `serviceBatten`), `nailing` (`nailingBatten`) or `counter` (`ventBatten`). Where the layer is more than 3w long, a batten stands at each end, w wide, from the layer's bottom to its top at its middle, held within the bottom and the top at its sides, or, where a floor bears on the layer (7.4.4, rule 4), up to the floor's structure's underside and again from the floor's top, each starting over each hole that overlaps the batten and starts at or under its foot, at the hole's top, a hole being a door's or a window's box (Part IV, 4.3) or a truss's bottom chord (7.4.14, rule 4); one less than w high is not laid (`end0`, `end1`, `.0` and `.1` after them where there are two). Rows of battens w high are laid from the layer's lowest point a spacing apart while they fit under its highest, each but where it crosses a floor, cut at the end battens' inner sides, or at the layer's ends without them, and at the sides of each hole it crosses; of the pieces between the cuts, each is laid where its middle lies in none of those holes, up to the layer's top at its ends and middle, where that leaves at least 1 mm (`<row>:<piece>`, from 0). A batten layer has no plates, studs or openings' framing.
2. **A T's ladder.** For a T that a layer backs with `ladder`, in the bay of the two verticals that flank its middle, where the bay is at least 1 mm and its middle lies in no zone, noggings w high, of the stud's section, from 600 above the frame's foot every 600 while they fit under its top (`tee-<wall>:<r>`, from 0). That bay takes no other noggings.
3. **Noggings** (`nogging`), where the rule's `noggings` gives a `spacing` or `rows`: in each bay between two neighbouring verticals at least w wide, but a ladder's and one whose middle lies in a zone, between the frame's foot and its top at the bay's sides: every `spacing` from its foot while they fit, or `rows` rows evenly, each centred at its foot plus the bay's height times r / (rows + 1); in every second bay a nogging's height higher where `staggered` is true, where it still fits; `<bay>:<row>`, bays and rows counted from 0.
4. **Where a wall runs through.** Once its noggings or battens are laid, each member of a layer that reaches into the rectangle a wall runs through it over (7.4.3, rule 8) is cut to its parts outside it, each at least 100 mm², keyed `<key>.<k>`, k from 0, where there is more than one; its line is cut with it. A member wholly inside is left out.

### 7.4.9 Each member: its name, its number and its class

1. A member's **id** is `<wall>:<layer>:<role>:<key>`, unique in the model; its **name** is its role's name and its key, `stud 3`, `header D1:0`; its **section** its width in the elevation (a stud's along the wall, a plate's height) by its depth across the wall, each to 0.1 mm, `45 × 170`; its **line** the line along its middle, in the elevation and, at the middle of its y, in the model; its **length** that line's; its **material** its rule's `material`.
2. Each role's name, and the IFC4 class and predefined type it is written as, as the reference implementation writes a wall's members (a heel post a STUD and a header a LINTEL here, where section 6.6 writes a truss's a POST and a USERDEFINED HEADER):

| Role | Name | IFC class | Predefined type |
|---|---|---|---|
| `sole`, `sole2` | sole plate, second sole plate | IfcMember | PLATE |
| `top`, `top2` | top plate, double top plate | IfcMember | PLATE |
| `sill` | rough sill | IfcMember | PLATE |
| `stud`, `endStud`, `cornerStud` | stud, end stud, flat corner stud | IfcMember | STUD |
| `king`, `jack`, `cripple` | king stud, jack stud, cripple stud | IfcMember | STUD |
| `header` | header | IfcBeam | LINTEL |
| `nogging` | nogging | IfcMember | USERDEFINED, NOGGING |
| `serviceBatten`, `nailingBatten`, `ventBatten` | service batten, nailing batten, counter batten | IfcMember | USERDEFINED, BATTEN |
| `heelPlate`, `heelPost` | heel plate, heel post | IfcMember | PLATE, STUD |
| `post` | post under a beam | IfcMember | POST |

### 7.4.10 Each member's body

1. A member's body is its outline in the elevation carried across the wall from its y to its other y, in the model (7.4.1, rule 4).
2. It is cut by the faces its layer is cut by (7.4.3, rule 2), every plane of each a half-space under which the body is kept: the attached face, unless the layer is extended, and the cut roof's. Where a layer ends mitred, or at a T whose face ends lie more than 0.5 mm apart along the wall, it is cut by the vertical plane through those face ends, at y0 and at y1, the side away from the end kept.
3. Its volume is its body's.

These are class-A rules, held to the tolerances of section 10: each member's body within 0.1 mm of the rule's, and its volume within a relative 10⁻⁶; members, their ids, names, sections and classes exactly.

### 7.4.11 In IFC

A bridge writes each member as its class (7.4.9, rule 2), aggregated under its wall by an IfcRelAggregates, its GlobalId from `framing:<id>`, its name its name and its tag its id, its object type its user type, or its predefined type and its section (`PLATE 45 × 170`), and of an IFC type of its class, predefined type and section (`type:<class>:framing:<predefined type>:<user type>:<section>`), as Part VIII, 1 keys a framing member given to it; its material `Timber` and its rule's material, `Timber C24`.

### 7.4.12 What is not laid out yet

1. **A face no set frames.** A truss layout frames its roof's eaves (section 7.4.13) and its hip ends (section 7.4.16). A sloped face that is neither, such as a valley's or a second hip end at one end of the ridge, is framed by no truss, which is said (`framing-layout-note`): the reference implementation lays no set out under it either. A layout of one fall, or one whose `hips.frame` is false, frames no hip end, and says its hip ends.
2. **Materialised members** (`framing-layout-materialised`). A wall whose members are materialised as elements, which name it in their `frameHost.wallId` (Part II, 10), is not laid out: its members are those elements. Nor are the members of a roof whose trusses are materialised, which name it in their `frameHost.roofId`: the layout is still laid out, and the walls and floors that read it (7.4.14, 7.4.15) read it as it is.
3. **What a later rule may read.** A rule's `relyOn`, which names the layer whose studs its battens follow, is not read.

*Note (informative).* On the reference implementation's garage, guesthouse and villa (its `main` `f2bc53d2`, 29 October 2026), `@openeik/tools` lays out every member the reference does, 299, 75 and 482, each with its id, name, section, class, outline and line, its box within 10⁻⁶ mm and its volume within a relative 10⁻⁸, and its print writes each with the GlobalId, class, name and tag of the reference's own print. On a probe of 22 walls and 715 members that takes each rule a way it can go (`packages/openeik/test/fixtures/framing-layout.json`), it agrees with it exactly, but for one top plate of a gable under its roof whose top lies on the roof's face: the reference's clip counts a cap on that face and gives the plate 1.6 % more volume than its outline carried across its layer holds; the rule's volume is the body's. The reference also reads a rule's `top` where it gives none as no object, and fails; these rules take it as `auto`. Two orders are the reference's own and may differ from these rules' where two things tie: walls that end against a wall at one x (the reference, in the order of its walls by base), and floors found of one underside and coverage (the reference, in the order of its elements).

Reference: `deriveWallFraming`, `resolveFrameTop`, `bottomPlateCutsFor`, `splitByGaps`, `framingRuleSchema` and `validateFramingRule` in `src/core/elements/wallFraming.ts`; `frameEnvelope`, `frameCorners`, `frameTees`, `wallFramingFor` and `framingSolids` in `src/core/elements/wallFramingGeometry.ts`; `bearingFloor` in `src/core/elements/bearingFloor.ts`; `joinPartner`, `teeHost`, `teeBranches` and `wallJoinCoordinate` in `src/core/elements/wallJoins.ts`; `wallTopClips` and `extendsExteriorLayers` in `src/core/elements/wallTop.ts`; `pocketSide` in `src/core/elements/openings.ts`; `framingIfcClass` in `src/core/elements/framingIfc.ts`; `derivedFraming` in `src/core/io/ifcFraming.ts`. In `@openeik/tools`: `framingLayouts` and `layoutLayer` in `packages/openeik/src/compile-framing-layout.js`, `wallJoins` in `packages/openeik/src/compile-framing-joins.js`, called by `compileModel` in `compile.js`.

### 7.4.13 A roof's truss layout

These rules lay out the trusses of a roof's `trussLayout` (Part II, 6.3): each truss its family's parts, built as section 6.6 builds a beam's, on a line across the roof's span between the walls or beams it bears on; and a roof opening's trimmers, headers and dormer rafters, a ridge beam and its posts, and an anchor pair where each truss rests. Its hip ends are framed by section 7.4.16. In these rules lengths are in mm, and points in plan.

1. **A truss layout, its rule and its family.** A roof with a `roof` payload, no barrel vault, and a `trussLayout` is laid out. Its rule is read with these values for what it leaves out: `layoutRule` fixedDistance, `spacing` 1200, `count` 2, `justification` beginning, `bearingReference` coreFace, `ends` insideGables, `endOffset` 0, `openingFraming` with `trimmerPlies` and `headerPlies` 2, `hips` as section 7.4.16, rule 1 reads it, and a `ridgeBeam`'s `topOffset` 0 and no `posts`. Its family is the `framing` of the type its `familyTypeId` names, which MUST be a beam type, and is a **truss family**: one that declares the parameters `Pitch`, `HeelHeight`, `OverhangLeft` and `OverhangRight` of the scope `instance`. The family's parameters' values (`value`) give w, its `Width` (45 where it has none), and its `ChordDepth` (170), `BottomDepth` (0), `RidgeGap` (0), `BottomPitch` (0) and `Notch` (0); a family with a `FurringMin` is a **furring family**. A layout that a rule of this section cannot lay out is a finding (`framing-layout-roof`): the roof has no layout, and the walls it would bear on are laid out without its trusses. A validator warns of a layout whose family type is no beam type with a truss family, which it can tell from the records alone (`framing-layout-roof`).
2. **Its faces, its eaves and its frame.** The roof's faces are those of section 4.4: a plane for each slope-defining edge, of two within 10⁻⁷ the first; each face the roof's domain, its outline pushed out by each edge's overhang (4.4, rule 3), where its plane is the lowest; a face of 0.01 mm² or less is none. An edge that `roof.edges` gives no rule defines no slope and has no overhang. A face is sloped where its gradient is more than 10⁻⁹; a roof with no sloped face is not laid out. Two sloped faces face each other where their edges run at least 179° apart (their directions' product less than −cos 1°); of such pairs, the eaves are the pair whose edges are together the longest, the first in the order of the outline where two are as long, and the left eave is the face of the pair's edge that comes first. Without such a pair the layout falls one way, its left eave the sloped face of the longest edge, the first of equals. The layout's frame: **across**, the left eave's edge's normal into the outline; **along**, square to it, the one of the two that points along +x, or along +y where across is square to x within 10⁻⁹; its origin the outline's first point; τ(p) = (p − origin)·across and r(p) = (p − origin)·along. Of the other sloped faces, those whose edges run across the span, within 5° of across (|u × across| ≤ sin 5°), are **hip ends**, framed by section 7.4.16, and the others are not framed, which is said (7.4.12, rule 1).
3. **Its bearings.** Where `bearingWallIds` gives them, each side is the walls or beams it names in order, one or a list, each with two points or more and running along the eaves, its first two points' direction within 5° of along; the middles of the two sides' first bearings lie at least 500 apart in τ, and the side of the lesser τ is the left. Else each side is found: of the walls at least 1 mm long that run along the eaves and **come up to the roof** (attached to it, `top.attach.hostId`, or whose top, at its base plus its height, the highest of its top by sections 5.1 and 5.3, lies at most 1500 under the least of the roof's faces lowered by its thickness at the wall's middle), whose middle's τ lies less than 500 outside the eaves' τ, and whose run in r overlaps the domain's by at least the lesser of 1000 and 0.3 of the domain's run: those whose middle lies on the side's half of the span (under or over the middle of the eaves' τ), and of them those that overlap at least half the domain's run where there are any; the nearest to the side's eave, by |τ − τ_eave| / 50 rounded to a whole number, then the higher base, then the greater overlap, then the first by id in code units. The eaves' τ: the left eave's edge's first point's, and the right's, or the domain's greatest where the layout falls one way. A side with no bearing is a finding.
4. **A bearing's plane and its faces.** A wall bears on the one of its framed layers that has a bearing plane (7.4.4, rules 2 and 3) when it is laid out with no truss on it: a core layer, else any, the thickest, the first of equals. Its **bearing elevation** is its base plus that plane's height, its faces that layer's two faces (y0 and y1), and its extent along the wall that plane's (its envelope's least and greatest x). A beam bears on its top, its base plus its `height`, across its whole `width`, and along its whole length. A wall with no such layer bears on its lowest top (sections 5.1 and 5.3), across its core band (from its first core layer's outer face to its last core layer's inner face, else its whole thickness), along its whole length, which is said. With `bearingReference` finishFace a wall's faces are its outer faces, 0 and its thickness T. A bearing's **reference face** is the one of its two faces, taken at the middle of its extent, nearer the outside: on the left the lesser τ, on the right the greater; and its **run** the least and greatest r of its extent's two ends at the middle of its faces. A side of several bearings bears at the highest of their elevations, its reference face the first's, and its run from the least of theirs to the greatest; a truss at a place bears on the first of them whose run holds the place within 1 mm, else on the one whose run's nearer end is the nearest. The layout's **bearing plane** E is the higher of its two sides'; but a layout that falls one way and whose family has no `member` part of the role `bottomChord` bears at its left side's. Sides more than 1 mm apart in elevation, and a bearing more than 5 mm out of line with its side's first, are said.
5. **Its range and its trusses' places.** The bearings' run is where both sides' runs overlap, at least 1 mm (else a finding); the roof's run the least and greatest r of its domain. The range is the bearings' run held within the roof's run, closed at its gables; where that leaves less room than w + 2·`endOffset` (within 10⁻⁶), the bearings' run closed at its gables, which is said. **The gables** of a run are the walls that are no bearings, at least 1 mm long, running across the span within 5°, whose τ overlaps the span between the two reference faces by at least half of it, whose first point's r lies within half their thickness plus 150 of the run's start (a gable at the start) or else of its end (at the end), and that stand on the trusses' storey: base at most E + 500 and top, their base plus their height, at least E − 1500 (a wall whose top cannot be resolved stands). With `ends` insideGables the range starts no sooner than a start gable's inner face, r + T/2, and ends no later than an end gable's, r − T/2. The first place is the range's start plus `endOffset` + w/2, the last its end less `endOffset` + w/2; a last more than 10⁻⁶ before the first is a finding. With `layoutRule` positions, each of `positions`, sorted by `at`, is a truss at the range's start plus its `at`, of the mark its `mark` gives; a layout that lists none is a finding, and one that stands more than 1 mm outside the range less w/2 is said. Otherwise, with t = last − first and c the spacing: no truss where t is less than −10⁻⁶; one at the middle where t is less than w; else
   - `maximumSpacing`: n = max(1, ⌈t / c − 10⁻⁹⌉), and n + 1 places evenly from the first to the last;
   - `fixedNumber`: `count` places evenly from the first to the last, which is a finding where they are less than w apart;
   - `fixedDistance`, with n = ⌊t / c + 10⁻⁹⌋: from the `beginning`, the places first + k·c for k from 0 to n, the last of them moved to the last place where it lies within w of it, else the last place added after it (and added where n is 0); from the `end`, the same mirrored, last − k·c in order, the first of them moved to the first place where it lies within w of it, else the first place added before it; from the `center`, with r = t − n·c, the places first + r/2 + k·c, and the first and the last places added at the ends where r/2 is more than w, else the first and the last of them moved there (where n is 0, the first and the last places).

   The trusses so placed are numbered T1, T2 … in order, but where a position gives a `mark`; each is keyed by its index from 0. At a hip end, the range, its places and its girder are as section 7.4.16, rule 3 says.
6. **Each truss's line.** A truss at a place lies on the line from the point origin + along·place across the roof, along across. Its left and right ends, at τ_L and τ_R, are where that line meets its two bearings' reference faces, each the line through the face along its bearing's direction; its **span** is τ_R − τ_L, at least 1000 (else a finding), and its points a and b, at τ_L and τ_R, run from its left bearing to its right one, each to 0.001.
7. **Its heel and its parameters.** The chords' top is the face of the roof's **chord layer**: the layer of its type that `chordLayer` names, which MUST be one, else the first layer as thick as `ChordDepth` within 0.5 where the family is no furring family, else none; `chordLayer` underside names none. Its face is the underside of the layer over it, or the roof's top for its first layer, and without a chord layer the roof's underside; each of the roof's faces lowered by that depth, square to it (4.4, rule 4), the least of them. A truss's heel is `heelHeight`, else that face's height at its a less E; a heel under 0 is a finding, and so, in a furring family, is a heel less `BottomDepth` that is more than 0.5 under its `FurringMin`. It gives its family the parameters `Pitch`, the left eave's edge's slope; `HeelHeight`, its heel; and `OverhangLeft` and `OverhangRight`, `overhang`, else τ_L less the least τ and the greatest τ less τ_R where its line lies in the roof's domain, each at least 0; each to 0.001. Pitches more than 0.05° apart are said; with a heel given, a top that stands more than 1 mm into or under the face, and a face that lies more than 1 mm off the heel at the right bearing, are said.
8. **Its parts.** A truss's parts are its family's, built by section 6.6, rules 2 to 9, with the parameters of rule 7 as the element's, with two changes for roof openings (rule 10):
   - a one-sided truss keeps only the top chords of its side: a `member` part of the role `topChord` is the left's where its axis rises (t_z more than 10⁻⁹) and the right's where it falls;
   - a **band** taken out of a side's top chords, from and to horizontal distances from that side's bearing line, is taken out of each of their pieces after its notches: with A(d) the point d along and `HeelHeight` + tan(`Pitch`)·d up (on the right, `Length` − d along) and the direction up the slope (cos `Pitch`, sin `Pitch`), mirrored on the right, what lies down the slope of the line square to it through A(`from`) is kept, where the band gives `from`, and what lies up the slope of the line through A(`to`), where it gives `to`, each a piece where it has three points or more and more than 10⁻⁶ mm². A top chord that its bands take all of has no piece, which is no fault.

   A family that cannot be built is a finding. `Length` is the span τ_R − τ_L for its seats (rule 9), the span to 0.001 for its members' sections and lengths (rule 13), and the length of its line from a to b for its bodies (rule 14).
9. **Its seats.** On each side, where it bears on a framed wall or a beam, its seat is the least height over the bearing plane of its pieces, its plates' too, where each is clipped to between that bearing's two faces (each τ less τ_L, x0 and x1, in the plane), counting a clipped piece of 1 mm² or more, plus E less its side's elevation (rule 4), to 0.001. It has none where no piece spans the faces, or the bearing is no framed wall nor beam.
10. **Its roof openings.** A roof opening (`roof.windows`) lies on the face of its edge `edgeId`: on an eave face, else it is not framed, which is said. Its outline is the rectangle `width` across the slope and `length` along it, its plan length `length`/√(1 + tan² σ), σ its edge's slope, about its `center`, along its edge's direction and normal; its run, from a0 to a1, and its τ are its corners' least and greatest. Openings are framed in a layout whose family's `trussStyle` is rafters; in any other, they are said. For each opening, in order:
    - **its trimmers**, `trimmerPlies` k from 0 on each side, a truss of its side only (rule 8) at a0 − w/2 − k·w (keyed `<opening>:a<k>`) and at a1 + w/2 + k·w (`<opening>:b<k>`), in that order, after the layout's trusses, numbered V1, V2 … across the openings, with their own indices on from the layout's;
    - **the trusses it cuts**: each of the layout's trusses (not a trimmer) whose width overlaps, by more than 10⁻⁶, a trimmers' band, a0 − `trimmerPlies`·w to a0 or a1 to a1 + `trimmerPlies`·w, loses its top chords on the opening's side whole (a band with neither end); one that overlaps a0 to a1 loses a band from d_eave − h to d_ridge + h, its `from` only where d_eave is more than 0, each to 0.001, where d_eave and d_ridge are the opening's τ on its eave side and on its ridge side measured inward from that side's bearing line at the truss (τ − τ_L on the left, τ_R − τ on the right), and h is its header's plies by their width by cos `Pitch`, 0 where it has none;
    - **its header**: `headerPlies` plies of w by `ChordDepth`, else one ply of the section its opening's `header` gives, `{width, depth}`, or none where it gives `none`. A header runs from a0 to a1 along the ridge, on the chords' top face, its plies' width up the slope and its depth square to it: across the ridge side from d_ridge to d_ridge + h, d_ridge measured at a0, but where its far top edge, 1 mm short, lies outside the opening's face at a0 or a1, which is said; and across the eave side from d_eave − h to d_eave, where the opening does not reach its bearing line (d_eave at a0 more than 0). Its corners: at each end, at d along from the bearing line and k into the chord, the point τ_L + d + k sin `Pitch` (τ_R − d − k sin `Pitch` on the right) on its line, at E + heel + tan(`Pitch`)·d − k cos `Pitch`, each to 0.001; keyed `<roof>:opening:<opening>:header:ridge` and `…:header:eave`;
    - **its dormer rafters**: under the roof whose face over the opening's middle (the middle of its first and third corners) is sloped, of a pitch at least 1° from `Pitch`, its underside the highest there (the first by id of equals), where its gradient lies within 5° of across (else said): for each truss it cuts, in order, a rafter at the truss's place (to 0.001), from its ridge-side d_ridge to where its line leaves that roof's domain on the opening's side, where that is 100 or more, `dormerRafterDepth` deep (else `ChordDepth`) and w wide, its top on that roof's underside and its plumb depth that depth over the cosine of its pitch, its length along its slope; keyed `<roof>:opening:<opening>:dormerRafter:<truss key>`.
11. **A ridge beam.** A layout whose family's `trussStyle` is rafters lays its `ridgeBeam`; another says it does not. Its width is its `width`, else `RidgeGap`, and one less than 45 is said, and none laid; a width more than 1 mm from `RidgeGap` is said. At a place along the ridge, its top is E + heel + tan(`Pitch`)·((τ_R − τ_L)/2 − width/2) less `topOffset`, its underside its `depth` lower, and its middle at (τ_L + τ_R)/2. It runs from the range's start to its end, but where a gable stands there (rule 5): from that gable's framed layer's outer face, its core layer that carries `framing`, else its first that does, where that face is the outer one (else from between its faces, said), in which it then bears; or from the gable's line where it has no framed layer (said). Its corners at each end are its top and underside at its middle ± width/2. Each of `posts`, a distance from the range's start, is a post width by width at its middle, from the base of the left side's first bearing up to the beam's underside there, where it lies within the beam's run (else said); keyed `<roof>:ridge:post:<i>`. Where it bears in a gable, its **bearing** there is its middle's x along the gable at the gable's first point's place, its width, its underside and top over the gable's base, and the y of the framed layer's outer face (7.4.14, rule 6). The beam is keyed `<roof>:ridge`.
12. **Its connections.** Each truss, on each side where it rests, has an anchor pair on that side's bearing at its point a or b, at E, of two brackets, keyed `<truss id>:anchor:<side>`. A truss **rests** on a side unless it is one-sided to the other side, or a band that gives no `from` (one that takes its tail) is taken out of that side; a hip truss and a jack as section 7.4.16, rule 9 says, which gives them hangers too.
13. **Each member: its name, its section and its class.** A truss is keyed `<roof>:truss:<key>` and named `Truss` and its mark, as `Truss T3`; a hip set's trusses and a girder's plies as section 7.4.16, rule 10 names them. Each of its parts that has a piece is a **member**, keyed `<truss id>:<part id>`, named by the truss's name, its role in words and the part's id, as `Truss T1 · top chord topL` (a `profile` part by its id alone, a plate as a nail plate), of the IFC class and predefined type section 6.6 and Part VIII, 1.6 give a family's part by its role, its material its family type's timber, and a nail plate's steel. Its section is its width by the greatest depth of its pieces: a part's pieces, ordered by their least extent along its axis, are grouped where each starts within 1 mm of the reach of those before it, and each group's depth is its extent square to the axis; a plate's is its pieces' height in the plane. Its length is the sum of its groups' extents along the axis. The headers, dormer rafters, ridge beam and posts are members too, named `header`, `rafter`, `ridge beam` and `ridge post` and their key after its first `:`, as `header opening:W1:header:ridge` and `ridge post ridge:post:0`, of the classes of section 6.6's table: a header an IfcMember USERDEFINED HEADER, a dormer rafter an IfcMember RAFTER, a ridge beam an IfcBeam BEAM RIDGEBEAM and a post an IfcColumn COLUMN; their sections a ply's width by its depth, the beam's width by its depth and a post's width by width. Sections are each to 0.1, as `45 × 220`.
14. **Each member's body.** A truss's pieces are placed as a beam's (section 6.6, rule 10) on its line from a to b, level, its set-out line at E: each piece is its polygon carried across its width, a plate's on its member's faces (6.6, rule 9). A header, a dormer rafter, the ridge beam and a post is the closed body of its eight corners, its start's four and then its far end's in the same order: its six faces the end faces and the four sides between them, its volume by the divergence theorem over each face's triangles from its first corner.
15. **In IFC.** A bridge writes each truss as an IfcElementAssembly of the predefined type TRUSS, its object type `Truss`, under its roof by an IfcRelAggregates, its GlobalId from `truss:<truss id>`, its name its name and its tag its key, with no body of its own, and its members under it, each as section 7.4.11 writes a wall's, keyed `framing:<member id>` and typed by class, predefined type and section, its material `Timber` and its family type's material, a nail plate's steel. It writes the headers, dormer rafters, ridge beam and posts under the roof the same way. Each anchor pair is an IfcMechanicalFastener in its roof's storey, its GlobalId from `fastener:<key>`, its name `Truss clip pair`, its object type `TRUSSCLIP` and its predefined type USERDEFINED, with no body: the rules give its place, not its shape. An IfcRelConnectsWithRealizingElements of the type `TRUSS_TO_PLATE`, keyed `connects:<key>`, connects its truss's assembly to its wall or beam, where both are written.

These are class-A rules, held to the tolerances of section 10: each member's body within 0.1 mm of the rules', and its volume within a relative 10⁻⁶; trusses, members, their ids, names, sections and classes exactly.

*Note (informative).* On the reference implementation's examples with truss layouts (its `main` `f2bc53d2`, 29 October 2026): its garage, second version, whose 11 collar trusses with nail plates bear on a wall and a beam in line on each side; and its villa's frame, whose three roofs carry 24 rafter pairs and trimmers round a roof window and a dormer's opening under a ridge beam on two posts, 8 rafter pairs on a ridge beam, and 6 fink trusses. `@openeik/tools` lays out every truss the reference does, 11 and 38, with its mark, line, span, parameters, bearings and seats; every member, 66 and 108, with its id, name, section, class, box and volume exactly; and every anchor pair, 22 and 65. On a probe of five roofs that takes each rule a way it can go (`packages/openeik/test/fixtures/framing-roofs.json`: fink, collar, rafter, one-fall and king post trusses, each layout rule, bearings named and found, a wall and a beam in line, finish faces, a heel and an overhang given, the bearings' ends, a chord layer, a ridge beam with a post, a roof window and a dormer's opening under a dormer roof, and seats), it agrees with it exactly: 43 trusses, 209 members and 82 anchor pairs. Its print writes each truss, member and anchor pair with the GlobalId, class and tag of the reference's own print, and its name as the reference's with its Swedish words put into the rules' English (below). They differ where the text decides:
- **Names.** The reference names a truss, a ridge beam, a ridge post and an anchor pair with its trade's Swedish words (`Takstol T3`, `nockbalk`, `nockstolpe`, `Takstolsvinkel, par (truss clip pair)`), while it names every member's role in English. By the steward's decision of 30 October 2026 these rules name them in English, `Truss T3`, `ridge beam`, `ridge post` and `Truss clip pair`, and the reference changes (open questions, section 2). Until it does, `@openeik/tools`' tests compare each name with the reference's, its Swedish words put into these English words one for one (`packages/openeik/test/support/reference-names.mjs`), so that the comparison stays exact. It names a `profile` part of a truss by its id twice (`Takstol T1 · seat seat`); rule 13 names it by its id once, as section 6.6 does.
- **An anchor pair's body.** The reference gives each a box 60 × 60 × 40 mm at its point, which stands for no part's shape; rule 15 writes it with none.
- **A nail plate's material.** The reference writes a truss's nail plates of its family type's timber; rule 15 writes them of steel, as Part VIII, 1.6 does a family's.
- **Ties.** Where two walls are found alike for a side, or two gables or two dormer roofs stand alike, the reference takes the first in the order of its elements, which section 9 of Part III gives no meaning; these rules take the first by id.

Reference: `deriveTrussLayout`, `trussPositions`, `trussChordLayer`, `wallBearing`, `trussElement`, `trussSolids` and `bearsOn` in `src/core/elements/trussLayout.ts`; `trussLayoutSchema` in `src/core/elements/trussLayoutRule.ts`; `layoutRange` in `src/core/elements/trussLayoutRange.ts`; `bearingFrame` in `src/core/elements/bearingFrame.ts`; `lineInside` and `seatOver` in `src/core/elements/trussHips.ts`; `framingProfiles` (its `interruptions` and `side`) in `src/core/elements/framing.ts`; `roofFaces` and `roofWindowPolygon` in `src/core/elements/roofs.ts`; `openingHeaderSection` in `src/core/elements/roofOpeningHeader.ts`; `trussMembers` in `src/core/elements/trussReport.ts`; `boxSolid` in `src/core/geometry/memberBox.ts`; `derivedFraming` in `src/core/io/ifcFraming.ts`. In `@openeik/tools`: `trussLayoutOf` and `trussMembers` in `packages/openeik/src/compile-framing-roofs.js`, with `familyParts` in `packages/openeik/src/compile-framing.js`, called by `framingLayouts` in `packages/openeik/src/compile-framing-layout.js`.

### 7.4.13.1 What a truss layout's members bear on

*Part of 0.4. OpenEik 0.3 had it as the proposal `bearsOn` (open questions, 130): a model of 0.3, read by 0.3's rules (Part I, 9.6, rule 3), is read by it only where a caller asks for it (decision D12).*

Each member these rules derive names what it bears on, as the rule that laid it out found it, so that a reader follows a load to its support with no rule of its own. A compiler of a model of 0.3 that does not ask for the proposal gives a derived member no `bearsOn`.

1. **Its form.** `bearsOn` is `{start, end}`, each a list of the ids of the elements, or of the members a layout derives, that the member bears on at that end: its start the end its line begins at, its end the other. An end that bears on nothing the rule finds has an empty list. A member that bears between its ends too names those as `along`.
2. **A truss.** A truss bears at its start on the wall or beam of its left side, and at its end on that of its right side, as rule 3 finds them (`bearings`). Its parts bear on each other, within the truss, and carry no `bearsOn`: the truss names its bearings.
3. **A roof opening's members.** A header (rule 10) bears at each end on the trimmer beside the opening there, the trimmer truss whose place lies nearest the header's end. A dormer rafter (rule 10) names no bearings that the rule finds: both lists are empty.
4. **A ridge beam and its posts.** A ridge beam (rule 11) bears at each end on the gable wall it is seated in, an end without one on nothing, and between its ends on its posts (rule 12), named in `along`. A ridge post bears on nothing the rule finds: it stands on its storey, which no element names.

Reference: none in the reference implementation, whose truss layout finds the same bearings (`wallBearing`, `bearsOn` in `src/core/elements/trussLayout.ts`) and does not give them to its members. In `@openeik/tools`: `trussLayoutOf`, `trussMembers` and `framingLayouts`, asked for with `compileModel(model, {proposals: ["bearsOn"]})` on a model of 0.3.

### 7.4.14 The walls a truss layout bears on

A framed wall that a truss layout bears on is laid out by sections 7.4.1 to 7.4.11, with these rules besides.

1. **The trusses on a wall.** Each truss of each roof's layout (7.4.13), the roofs in the order of their ids and each roof's trusses in their order, whose bearing on a side is the wall, the first side that is, and that rests on that side (7.4.13, rule 12, and 7.4.16, rule 9), stands on the wall as a **truss line**: at x = (its a, or its b on the right, less the wall's first point)·u along it, as wide as its family's `Width`, its bottom its family's `BottomDepth` over the bearing plane, and with its seat on that side (7.4.13, rule 9). Each ridge beam that bears in the wall (7.4.13, rule 11) bears on it too. A layout that is a finding bears on none.
2. **Studs under trusses.** Where the rule's `alignToTrusses` is true, after the studs set by hand (7.4.6, rule 3), each truss line within the frame (from its least x + w/2 to its greatest − w/2, within 10⁻⁶) takes the grid's places within w + 50 of it out of the grid, and sets a place at its x, keyed `t-<truss id>`.
3. **The heel zone the trusses hold.** Over a level plate or under a floor (7.4.4, rule 6), a truss line that has no seat over the bearing plane (rule 5) holds the heel zone over its width: each heel plate is cut at it, into its pieces more than w long, keyed `<segment>.<k>`, k from 0, wherever the layer has a truss line; and no heel post stands where it would overlap one.
4. **Bottom chords across battens.** In a batten layer on which a floor bears (7.4.8, rule 1), each truss line with a bottom crosses the layer: a hole over its width about its x, from the floor's top up by its bottom, which cuts the rows and which the end battens start over.
5. **A seat.** The truss lines whose seats are more than 1 mm over the bearing plane rest on the heel plate. Where the least of their seats is at least the heel plate's width plus w, the heel plate lies level, its top at the bearing plane plus that seat and with no drop across, continuous under them, whatever the heel zone's height; its heel members are cut by the layer's mitres alone (7.4.10, rule 2). Seats more than 1 mm apart are said. Where the least seat is less, it is said, and the trusses are taken to stand on the plane (rule 3).
6. **A ridge beam in a gable.** For each ridge beam bearing in the wall, x0 to x1 its width about its x, held within the frame (none where that is under 10⁻⁶), in each framed layer whose inner face lies past the beam's end, y1 more than its y plus 10⁻⁶: where the layer holds its end (its outer face y0 at or before it), its **post** stands from the layer's bottom at x0 and x1, the higher, raised to the top of each sole plate, second sole plate and header over x0 to x1 whose top lies at or under the beam's underside, up to the beam's underside: x1 − x0 wide and as deep as the layer, across all of it, keyed `beam-<beam id>`, where that is at least w high (else said); and its members lose what lies in the rectangle from x0 to x1 and from the post's foot up to the beam's top, as section 7.4.8, rule 4 cuts them. Where the layer does not hold its end, its members lose what lies from x0 to x1 and from the beam's underside up to its top.
7. **A rafter's notch.** A wall attached `level` to a layer of a roof (`top.attach.face` names a layer) that has a truss layout reads the face raised by its family's `Notch`, at least 0, as well as by its `offset`: for its envelope (7.4.3, rule 2), its members' bodies (7.4.10) and its top as rule 3 of 7.4.13 reads it.

These are class-A rules, held to the tolerances of section 10.

*Note (informative).* On the reference implementation's garage, second version, and its villa's frame, `@openeik/tools` lays out every member of every wall the reference does, 294 and 660, with its id, name, section and class; all agree exactly in box and volume but for nine top plates of the villa frame's gables, under their roof's face. The reference's clip gives five of them more volume than their outlines carried across their layer hold, by up to 1.4 %, as section 7.4's note says of one plate of its probe; three agree within a relative 3·10⁻⁶, and a sliver of 0.13 mm³ within 2·10⁻⁵ mm³; and four of their boxes differ by up to 9·10⁻⁶ mm, where a plate's top lies on that face and the line where the two meet is ill-conditioned. On the probe of 7.4.13's note, its 465 wall members agree exactly, and on the probe of 7.4.16's note, whose walls carry hip trusses and jacks, its 826. An end batten starts over a hole across its foot (7.4.8, rule 1), as the reference's does: a door's or a window's box there too, which no wall of 7.4's examples or probe had.

Reference: `deriveWallFraming` (its `trusses`, `beams`, `applyBeamBearings` and `deriveHeelMembers`) in `src/core/elements/wallFraming.ts`; `trussLinesOnWall` and `beamBearingsOnWall` in `src/core/elements/trussLayout.ts`; `rafterNotch` and `wallTopClips` in `src/core/elements/wallTop.ts`. In `@openeik/tools`: `layoutLayer` in `packages/openeik/src/compile-framing-layout.js`, given its trusses by `trussLinesOnWall` and `beamBearingsOnWall` in `packages/openeik/src/compile-framing-roofs.js`.

### 7.4.15 A floor's joists

These rules lay out a floor's joists from the joist rule of its type's layer (Part II, 5.1, a layer's `joists`): joists across the span between its bearing walls, trimmers beside its holes, headers across the edges the joists end at, rim joists on its bearing walls, and blocking in its end bays, each a rectangle in plan carried through the joist layer. In these rules lengths are in mm.

1. **A joist layer and its rule.** A slab whose type is a slab type with a layer that carries `joists` is laid out, by its first such layer. Its rule is read with these values for what it leaves out: `material` C24, `spacing` 600, `direction` auto, `rim` 45 wide (`null`: none), `trimmerPlies` and `headerPlies` 2, and `blocking` with `endBays` true and `spacing` 600. A rule without a member's `width` is not read (`framing-layout-joists`). A joist is w, the member's `width`, wide, and d, its `depth` else the layer's thickness and at most that, deep; the layer's top lies under the slab's top, its level's elevation plus its `offset`, by the layers before it, and its underside d under that: z0 and z1, each to 0.001. A validator warns of a rule on a layer of a type that is not a slab type, or whose member is deeper than its layer (`framing-layout-joists`).
2. **The posts through it.** A column whose base and top (its level's elevation plus its `offset`, and that plus its `height`) reach more than 1 mm into the layer from below and above (top more than z0 + 1, base less than z1 − 1) is a post: a square of its `width` about its first point. So is a ridge post of a truss layout (7.4.13, rule 11) that does: the box of its corners in plan. A post is kept where its box overlaps the box of the floor's outline (its `profile`). Columns are taken in the order of their ids, then the ridge posts, the roofs in the order of their ids.
3. **Its bearing walls.** The framed walls, in the order of their ids, a point of whose baseline lies within 1000 of the outline's box, each with a framed layer that, laid out with no truss on it, ends under this floor (its bearing floor, 7.4.4, rule 4): the first such layer. A bearing wall gives its layer's faces, y0 and y1, and its own faces, 0 and T, as lines in plan.
4. **The joists' direction.** With `direction` auto, the normal (−u_y, u_x) of a bearing wall across which the outline is least wide (the greatest less the least of its points' products with it), of equals the one that points the most along +x, then along +y. Without a bearing wall, x where the outline's box is no wider in x than in y, else y, which is said. With a number θ, (cos θ, sin θ). The joists run along d, the direction; across them runs û = (−d_y, d_x), and a point p of the plan lies at u = p·û, v = p·d.
5. **Its holes.** Each of the slab's `voids`, and each shaft whose base lies under z1 − 1 and whose top over z0 + 1 (4.2, rule 8), is a hole: its box in (u, v), held within the outline's box, where it is at least 1 mm each way. Holes whose boxes touch or overlap, within 1 mm, are one, until none do. A hole whose corners, 1 mm in, do not all lie in the outline is not framed, which is said. Holes are ordered by their least u, then v, and keyed `h<u0>_<v0>`, each rounded to the millimetre. A hole wider in u than the spacing less w is framed; another that a joist overlaps is said.
6. **Its edges.** The outline, and each framed hole's box, its corners wound as the outline's, are rings. Each edge of a ring at least 1 mm long runs along the joists (less than 1 mm in u), at u its middle's, over its v; or across them (less than 1 mm in v), at v its middle's, over its u; or neither, and is not framed, which is said. An edge's inward side is the one the floor lies on, as the ring is wound; an outline's edge is a **hull** edge where no point of the outline lies more than 1/ℓ outside its line, ℓ its length. An edge is numbered by its place in the outline, from 0, or keyed `<hole key>.<i>` in a hole's ring.
7. **Where a joist ends.** An edge across the joists lies **on a bearing wall** where, of the bearing walls in order, the first has its layer's two faces and its own two faces so that, with v_in the layer's face nearer the floor's inside and v_out the other, and v_w the wall's own face nearer the inside: the edge lies no more than 60 inward past v_w, and no more than |v_out − v_in| + 60 outward of v_in; and the wall's baseline, widened by 300 at each end, overlaps the edge by at least 1 mm in u. A joist's end at an across edge (its v within 1 mm of it, the edge facing it, and its u within the edge's u, within 10⁻⁶) on a bearing wall is v_out less the rim's width, towards the joist; at another across edge it ends short of it by `headerPlies`·w; elsewhere at the floor's edge.
8. **Its members.** Its **joists' places** are: on each edge along the joists, a joist w/2 inward of a hull edge (keyed `e<edge>.0`), else `trimmerPlies` trimmers (`trimmer`), (k + ½)·w inward of it, keyed `e<edge>.<k>`; and the grid, from the least u of the outline plus w/2 + spacing, every spacing, while it lies more than 10⁻⁶ under its greatest u less w/2, each keyed by its count from 1, but where it lies within w of a place on an edge; in order of u, each within 1 mm of the one before it dropped. Each place is a joist over each interval of the floor along its line (where the line lies inside the outline and outside the framed holes), from where it ends at the interval's one end to where it ends at the other (rule 7), where that is at least w; keyed `<key>.<k>` where its line has more than one interval. On each across edge on a bearing wall, where the rule has a rim, a **rim joist** of the rim's width on the outer face's inner side, along the edge, keyed by the edge; on each other across edge, `headerPlies` **headers** w wide, the first against the edge, inward, keyed `<edge>.<k>`. Where `blocking.endBays` is true and the floor has two joists' places or more, **blocking** in its first bay and its last (the first two places and the last two; one bay where there are two): for each interval of one joist and each of the other, from where they overlap plus the blocking's spacing, every spacing, while less than where they end less w, a row w wide about it, from one joist's side to the other's, keyed `<start or end>.<the first interval's start, to 0.001>.<k>`. A member is a rectangle in (u, v) at least 1 mm each way.
9. **Posts cut its members.** Each post, in order, as its box in (u, v), cuts each member it overlaps by more than 10⁻⁶ into its parts before it and after it along the member's length (v where the member is at least as long in v as it is wide in u, else u), each kept where it is at least 1 mm each way; a member cut in more than one part is keyed `<key>.<k>`, k from 0.
10. **Each member: its name, its section and its class.** A member's id is `<floor>:<layer>:<role>:<key>`; its name its role's name and its key, `joist 3`, `rim joist 1`; its section its width across its length by d, each to 0.001 and then to 0.1, `45 × 220`; its length along it; its material its rule's `material`. Each role's name and its IFC4 class, predefined type and user type:

| Role | Name | IFC class | Predefined type |
|---|---|---|---|
| `joist` | joist | IfcBeam | JOIST |
| `trimmer` | trimmer joist | IfcBeam | JOIST |
| `rimJoist` | rim joist | IfcBeam | USERDEFINED, RIMBOARD |
| `header` | header | IfcBeam | USERDEFINED, HEADER |
| `blocking` | blocking | IfcMember | USERDEFINED, BLOCKING |

11. **Its body, and in IFC.** A member's body is the closed body of its eight corners (7.4.13, rule 14): its start's four, at its least along its length, and then its far end's, each at its two sides across, at z1 and then at z0, each plan point to 0.001. A bridge writes each member under its floor by an IfcRelAggregates, as section 7.4.11 writes a wall's.

These are class-A rules, held to the tolerances of section 10.

*Note (informative).* On the reference implementation's villa frame (its `main` `f2bc53d2`), whose upper floor's 53 joists, trimmers, rim joists, headers and blocking frame a stair's opening in its outline and are cut by the two ridge posts through it, and on the two floors of 7.4.13's probe, 71 members (a column through one, a hole, joists turned 90° without rims or blocking, single plies and a slanted edge), `@openeik/tools` lays out every member the reference does, each with its id, name, section, class, box and volume exactly, and the print writes each with the GlobalId, class, name and tag of the reference's own print. Where two bearing walls span the floor alike, as two opposite walls always do, the reference takes the first in the order of its elements, which section 9 of Part III gives no meaning; rule 4 turns the direction to +x, then +y, which is the reference's on its villa frame.

Reference: `joistLayer`, `postsThroughFloor`, `floorFramingFor` and `floorFramingSolids` in `src/core/elements/floorFraming.ts`; `floorFramingRuleSchema` in `src/core/elements/floorFramingRule.ts`; `floorHoles` in `src/core/elements/floorOpenings.ts`; `framingIfcClass` in `src/core/elements/framingIfc.ts`. In `@openeik/tools`: `floorLayoutOf` in `packages/openeik/src/compile-framing-floors.js`, called by `framingLayouts` in `packages/openeik/src/compile-framing-layout.js`.

### 7.4.15.1 What a floor's members bear on

*Part of 0.4. OpenEik 0.3 had it as the proposal `bearsOn` (open questions, 130): a model of 0.3, read by 0.3's rules (Part I, 9.6, rule 3), is read by it only where a caller asks for it (decision D12).*

Each member of a floor's joists names what it bears on, in the form of 7.4.13.1, rule 1.

1. **A joist and a trimmer.** Each end bears on the bearing wall it runs onto (rule 7), or on the header it ends at, every ply of it; an end at an outline edge that is neither bears on nothing the rule finds.
2. **A rim joist** bears along its bearing wall, which it names at both ends.
3. **A header** bears at each end on the trimmers beside the hole there, every ply of them.
4. **Blocking** bears at each end on the joist beside it.
5. **A member a post cuts** (rule 9) bears on the post at each end the post cut, and keeps at its other end what the member it was cut from bore on.

Reference: none in the reference implementation. In `@openeik/tools`: `floorLayoutOf` in `packages/openeik/src/compile-framing-floors.js`, asked for with `compileModel(model, {proposals: ["bearsOn"]})` on a model of 0.3.

### 7.4.16 A truss layout's hip ends

These rules frame each hip end of a truss layout (7.4.13, rule 2) as the reference implementation lays out a hipped roof's trusses: a **girder** of plies where the ridge ends, a **hip truss** of plies up each hip line to it, and **jacks** square to the end and to the sides up to them; or, where hips at both ends leave a short ridge, one **girder along the ridge**, which half trusses from both eaves hang on. Hip trusses and jacks are trusses of the layout's **jack family**, a girder along the ridge of its **flat-top family**: families written in the language of Part II, 5.4, which the rules make of the layout's own family where the model holds none (rule 2). In these rules lengths are in mm and points in plan. τ, r, `across`, `along`, the origin, the bearing plane E and w are those of 7.4.13 (rules 1, 2 and 4); P(t, r) is the point origin + along·r + across·t; τ_L(r) and τ_R(r) are where the line across the roof at the place r meets the two sides' reference faces (7.4.13, rule 6); and z(p) is the height over p of the face the chords' top lies on (7.4.13, rule 7).

1. **Its hip ends and its rule.** A layout of two sides frames its hip ends; one whose `hips.frame` is false frames none, and says them (7.4.13, rule 2). Its `hips` is read with these values for what it leaves out: `system` auto, `girderPlies` 2, `hipPlies` 2, `minJack` 400, and `jackSpacing` the layout's `spacing`. Of a hip end's face, g its gradient (the plan direction it rises in, |g| the tangent of its pitch): its **pitch** is atan |g| in degrees, to 0.001; it lies at the **start** of the ridge where g·along is more than 0, else at its **end**; its **apex** a_r is the greatest r of its polygon's points at the start and the least at the end, and a_τ the mean τ of its points whose r lies within 1 of a_r: where its hip lines meet the ridge. Where two hip ends or more lie at one end of the ridge, the one of the longest edge is framed, of equals the first in the order of the faces, which is said.
2. **Its families.** The jack family is the `framing` of the model's type whose id is the layout's family type's id followed by `-jack`, where the model has one with a `framing`, and the flat-top family that of the type whose id is followed by `-flat`: the layout uses such a type, and a validator does not warn of it as of a library record the model does not use (Part III, 13, rule 2). A family the model holds ought to be a truss family (7.4.13, rule 1), and a flat-top family to declare `FlatLength` of the scope `instance` as well; a validator warns of one that is not, which it can tell from the records alone (`framing-layout-roof`), since a compiler leaves out each hip truss and jack, or each girder along the ridge, it cannot build (rules 7 and 8). Where the model holds none, each is made of the layout's family f, as follows. A **rafter family** is one whose `trussStyle` is `rafters` or `collar`.
   - Its parameters are f's but `Pitch`, `HeelHeight`, `OverhangLeft` and `OverhangRight`, in their order; then, where f has none of the name, `Width` (45, from 20 to 200) and `ChordDepth` (170, from 45 to 600), and, but in the jack family of a rafter family, `BottomDepth` (170, from 45 to 500) and `WebDepth` (95, from 45 to 300), each of the scope `type`; then `Pitch` (20, from 1 to 75), `HeelHeight` (200, from 0 to 5000), `OverhangLeft` (500, from 0 to 3000), `OverhangRight` (0 in the jack family, 500 in the flat-top family, from 0 to 3000) and, in the flat-top family, `FlatLength` (0, from 0 to 50 000), each of the scope `instance`; each with its `value` and then its `min` and `max`.
   - It has f's `tail`. The jack family's `trussStyle` is `rafters` where f is a rafter family, else `mono`; the flat-top family has none.
   - Its parts are the `member` parts of the tables below, each `Width` wide, in their order. A point is its x and its z; a plumb cut at x is the cut from (x, `0`) to (x, `1`); and in the tables B stands for the expression `BottomDepth/2`, C(x) for `HeelHeight-ChordDepth/(2*cos(Pitch))+tan(Pitch)*(x)`, D(x) for `HeelHeight-ChordDepth/(2*cos(Pitch))+tan(Pitch)*(Length-(x))`, K(x) for `HeelHeight-ChordDepth/cos(Pitch)+tan(Pitch)*(x)-BottomDepth`, X1 for `(Length-FlatLength)/2`, X2 for `(Length+FlatLength)/2`, F for `HeelHeight+tan(Pitch)*(Length-FlatLength)/2-ChordDepth/2` and W for `FlatLength-WebDepth-20`, each written out with the text of x, X1 or X2 in its place: C(`Length/2`) is `HeelHeight-ChordDepth/(2*cos(Pitch))+tan(Pitch)*(Length/2)`, X1`/2` is `(Length-FlatLength)/2/2`, and K(`0`)`-45` is K(`0`) followed by `-45`.

   The jack family of a rafter family has the part `top` alone, with no `cutBy`; any other jack family has these nine:

| Part | Role | `a` | `b` | `depth` | `when` | Plumb cuts at | `cutBy` |
|---|---|---|---|---|---|---|---|
| `bottom` | bottomChord | `0`, B | `Length`, B | `BottomDepth` | | | |
| `top` | topChord | `-OverhangLeft-ChordDepth`, C(`-OverhangLeft-ChordDepth`) | `Length+OverhangRight+ChordDepth`, C(`Length+OverhangRight+ChordDepth`) | `ChordDepth` | | `-OverhangLeft`, `Length+OverhangRight` | `bottom` |
| `heelL` | heelPost | `WebDepth/2`, B | `WebDepth/2`, C(`WebDepth/2`) | `WebDepth` | K(`0`)`-45` | | `bottom`, `top` |
| `post` | web | `Length-WebDepth/2`, B | `Length-WebDepth/2`, C(`Length-WebDepth/2`) | `WebDepth` | K(`Length-WebDepth`)`-45` | | `bottom`, `top` |
| `diag` | web | `Length/2`, C(`Length/2`) | `Length-WebDepth`, B | `WebDepth` | `min(Length-1200,3000-Length)` | | `bottom`, `top`, `post` |
| `post1` | web | `Length/3`, B | `Length/3`, C(`Length/3`) | `WebDepth` | `Length-3000` | | `bottom`, `top` |
| `post2` | web | `2*Length/3`, B | `2*Length/3`, C(`2*Length/3`) | `WebDepth` | `Length-3000` | | `bottom`, `top` |
| `diag1` | web | `Length/3`, C(`Length/3`) | `2*Length/3`, B | `WebDepth` | `Length-3000` | | `bottom`, `top`, `post1`, `post2` |
| `diag2` | web | `2*Length/3`, C(`2*Length/3`) | `Length-WebDepth`, B | `WebDepth` | `Length-3000` | | `bottom`, `top`, `post2`, `post` |

   The flat-top family has these fourteen:

| Part | Role | `a` | `b` | `depth` | `when` | Plumb cuts at | `cutBy` |
|---|---|---|---|---|---|---|---|
| `bottom` | bottomChord | `0`, B | `Length`, B | `BottomDepth` | | | |
| `topL` | topChord | `-OverhangLeft-ChordDepth`, C(`-OverhangLeft-ChordDepth`) | X1`+ChordDepth`, C(X1`+ChordDepth`) | `ChordDepth` | | `-OverhangLeft`, X1 | `bottom` |
| `topR` | topChord | X2`-ChordDepth`, D(X2`-ChordDepth`) | `Length+OverhangRight+ChordDepth`, D(`Length+OverhangRight+ChordDepth`) | `ChordDepth` | | X2, `Length+OverhangRight` | `bottom` |
| `topFlat` | topChord | X1, F | X2, F | `ChordDepth` | W | | |
| `heelL` | heelPost | `WebDepth/2`, B | `WebDepth/2`, C(`WebDepth/2`) | `WebDepth` | K(`0`)`-45` | | `bottom`, `topL` |
| `heelR` | heelPost | `Length-WebDepth/2`, B | `Length-WebDepth/2`, D(`Length-WebDepth/2`) | `WebDepth` | K(`0`)`-45` | | `bottom`, `topR` |
| `postL` | web | X1, B | X1, F | `WebDepth` | `min(`W`,`K(X1)`-45)` | | `bottom`, `topFlat`, `topL` |
| `postR` | web | X2, B | X2, F | `WebDepth` | `min(`W`,`K(X1)`-45)` | | `bottom`, `topFlat`, `topR` |
| `king` | web | `Length/2`, B | `Length/2`, `HeelHeight+tan(Pitch)*`X1 | `WebDepth` | `min(WebDepth+20-FlatLength,`K(X1)`-45)` | | `bottom`, `topL`, `topR` |
| `diagL` | web | X1`/2`, C(X1`/2`) | X1`-WebDepth`, B | `WebDepth` | X1`-1500` | | `bottom`, `topL`, `postL`, `king`, `vertL` |
| `diagR` | web | `Length-`X1`/2`, D(`Length-`X1`/2`) | X2`+WebDepth`, B | `WebDepth` | X1`-1500` | | `bottom`, `topR`, `postR`, `king`, `vertR` |
| `vertL` | web | X1`/2`, B | X1`/2`, C(X1`/2`) | `WebDepth` | X1`-3000` | | `bottom`, `topL` |
| `vertR` | web | `Length-`X1`/2`, B | `Length-`X1`/2`, D(`Length-`X1`/2`) | `WebDepth` | X1`-3000` | | `bottom`, `topR` |
| `diagFlat` | web | X1`+WebDepth`, B | X2`-WebDepth`, F | `WebDepth` | `FlatLength-800` | | `bottom`, `topFlat`, `postL`, `postR` |

3. **The ridge's range and its girders.** At a hip end, rule 5 of 7.4.13 is changed so. The range starts at the start's hip end's apex a_r, and ends at the end's. Where the layout has hip ends at both ends, its family's `trussStyle` is neither `rafters` nor `collar`, and its `hips.system` is `ridgeGirder`, or `auto` and the range is shorter than 2·`spacing`, it has a **girder along the ridge** (rule 8), and no truss is placed by 7.4.13, rule 5. Else, where it has hip ends at both ends and the range is shorter than 2·`girderPlies`·w + 1, the two **share** one girder: the range is narrowed to `girderPlies`·w about its middle, and its one truss stands at its first place. The first place is the range's start plus w/2 where a hip end lies at the start, else plus `endOffset` + w/2, and the last its end less w/2, or less `endOffset` + w/2; with no girder along the ridge, a last place more than 10⁻⁶ before the first is a finding. Where a hip end lies at the start and its girder is not shared, each place but the first that lies less than w − 10⁻⁶ past the first place plus (`girderPlies` − 1)·w is dropped; where one lies at the end and its girder is not shared, each place but the last that lies less than w − 10⁻⁶ before the last place less (`girderPlies` − 1)·w. The truss at the first place, where a hip end lies at the start, and the one at the last, where one lies at the end and the girder is not shared, is a **girder**: `girderPlies` trusses of the layout's family by 7.4.13's rules, its plies, the k-th, from 0, at its place plus k·w where it is the first truss, else less k·w; all of its mark, keyed by its index and, after the first ply, `:ply<k>` (`0`, `0:ply1`).
4. **A hip set's end bearing.** Each hip end gets a **hip set**, laid after the layout's other trusses: with no girder along the ridge, the start's and then the end's; with one, as rule 8 says. With s 1 at the start and −1 at the end, its **girder face** G is the range's start or end (rule 3), or, under a girder along the ridge, its apex a_r; and its **heel** h is the heel of 7.4.13, rule 7 at the first place (at the start) or the last (at the end): the layout's `heelHeight`, else z at the left point of the line across the roof there, less E; under a girder along the ridge, at the middle of the two apexes. Its **bearing line** is a place R along the ridge: with Z(r) = z(P(a_τ, r)), r1 = G − 100s, r2 = G − 1100s and m = (Z(r1) − Z(r2))/1000, R = r1 − s(Z(r1) − (E + h))/m where m is more than 10⁻⁶, else G − 1000s. Then its **end wall**: of the walls and the beams of two points or more, none with a `frameHost` and none a bearing of the layout, each running across the span within 5° (its first two points' direction, at least 1 mm apart) and overlapping the span between the two sides' reference faces (7.4.13, rule 5) in τ by at least half of it, whose first point's r lies within half its thickness (a beam's `width`) plus 1000 of R; each one's bearing found as rule 4 of 7.4.13 finds a side's, with r and τ exchanged (its reference face, by its `bearingReference`, the one of the lesser r at the start and of the greater at the end; its run in τ), where that bearing lies within 300 of E and its reference face, at its first point, within 300 of R in r; the one whose first point's r lies nearest R, the first by id of equals. Where it has one, R is that face's r. A set whose R is not finite, or that leaves less than 500 from R to G (s(G − R) < 500), frames nothing, which is said.
5. **Its hip trusses.** The hip face's edge's two points in the roof's outline (its stored `profile`) are its left corner p_L, of the lesser τ (the edge's first of equals), and its right p_R; its apex point A = P(a_τ, a_r). For each side, its **hip line** runs from its corner p towards A: d = (A − p)/|A − p|, d_τ = d·across and d_r = d·along; it crosses the bearing line at τ = t_0 = τ(p) + (R − r(p))·d_τ/d_r, or τ(p) where |d_r| is 10⁻⁹ or less; and it starts at S, the point of it nearest the corner of the bearing lines, P(τ_L(R), R) on the left and P(τ_R(R), R) on the right. With ν the greater over the two sides of (w/2)|d_r|/|d_τ| (0 where |d_τ| is 10⁻⁹ or less), the **centre jack** is s(G − R) − ν long, and stands where the set has no girder along the ridge and it is at least `minJack`. The half width κ kept clear of the ridge line is `girderPlies`·w/2 under a girder along the ridge, else w/2 where the centre jack stands, else 0. Then, the left side's first: with n = (−d_y, d_x) and b = `hipPlies`·w/2, its **drop** is b·max(|g_s·n|, |g·n|), g_s the gradient of the side's eave face and g the hip face's; its **pitch** atan((z(A) − z(S))/|A − S|) in degrees; and its **heel** z(S) − E less the drop. Each ply, k from 0 to `hipPlies` − 1, runs from a = S + n·(k − (`hipPlies` − 1)/2)·w along d for its **reach**, the least, over its corners a ± n·w/2, of (G − r(corner))/d_r, where the set has no girder along the ridge and |d_r| is more than 10⁻⁹, and of (λ − τ(corner))/d_τ, where κ is more than 0 and |d_τ| more than 10⁻⁹, λ = a_τ − κ on the left and a_τ + κ on the right. A ply whose reach is not more than 300 is not laid. Each other is a **hip truss** (rule 7), keyed `<end>:hip:<side>:<k>` (`start:hip:left:0`), of the mark `H<2j+1>` on the left and `H<2j+2>` on the right, j the number of hip sets framed before this one; it bears on the side's bearing that stands at R (the first whose run holds R within 1 mm, 7.4.13, rule 4), else on the end wall, else on nothing.
6. **Its jacks.** A **jack** runs from a point a along a direction d for a length L: its heel z(a) − E, and its pitch atan((z(a + dL/2) − z(a))/(L/2)) in degrees. One shorter than `minJack` is not laid. Each other takes the mark `J<i>`, i counting the layout's jacks from 1 in the order they are taken, and is a truss of rule 7. With J the `jackSpacing`, a set's jacks are, in this order:
   - its centre jack (rule 5), from P(a_τ, R) along s·along, keyed `<end>:jack:c`;
   - its **end jacks**, the left side's and then the right's, of each side where t_0, d_τ, d_r, τ_L(R) and τ_R(R) are finite and |d_τ| is at least 10⁻⁹: for k from 1 to 500, at t = a_τ − kJ on the left and a_τ + kJ on the right, each but where |t − a_τ| − w/2 is less than κ, and none more from where its near side, t_n = t − w/2 on the left and t + w/2 on the right, reaches the hip line or the side's corner (t_n at most max(t_0, τ_L(R)) on the left, at least min(t_0, τ_R(R)) on the right): a jack from P(t, R) along s·along, s(r_e − R) long, where r_e = R + (t_n − t_0)·d_r/d_τ − s·b/|d_τ|; keyed `<end>:jack:el<k>` on the left and `er<k>` on the right;
   - its **side jacks**, at places r along the ridge: without a girder along the ridge, G − s(k + 1)J for k from 0 to 499, in that order, those where s(r − sw/2 − R) is more than 0; under one, its grid's places (rule 8), from the least, where s(r − sw/2 − R) is more than 0 and s(a_r − (r + sw/2)) is at least 0. The left side's and then the right's, of each side where t_0, d_τ and d_r are finite and |d_r| is at least 10⁻⁹, at the k-th place, from 1: with r_n = r − sw/2 and t_h = t_0 + (r_n − R)·d_τ/d_r, a jack from P(τ_L(r), r) along `across`, t_h − b/|d_r| − τ_L(r) long, on the left, and from P(τ_R(r), r) along −`across`, τ_R(r) − t_h − b/|d_r| long, on the right; keyed `<end>:jack:sl<k>` and `sr<k>`.

   The centre jack and an end jack bear on the end wall where their τ lies within its run, within 1 mm; a side jack on the side's bearing that stands at its place. Jack or hip truss ends with no bearing are said.
7. **A hip truss or a jack as a truss.** Its parameters are its `Pitch` and `HeelHeight`, its `OverhangLeft`, how far its line runs on behind a inside the roof's domain (−t for the least t at which a + d·t lies in it, where that is finite and less than 0, else 0), and `OverhangRight` 0; each to 0.001. Its parts are the jack family's, built by section 6.6, rules 2 to 9, with its length L as `Length`; where they cannot be, it is left out, which is said, and its mark is given to no other. Its id is `<roof>:truss:<key>`; its place, the r of the middle of a and b = a + dL, its points a and b and its span L are each to 0.001, at E. It bears on its left side only, on its bearing. Its **seat** there, where its bearing has the two faces of a frame (7.4.13, rule 4), is the least height of its pieces between the two distances along d from a at which its line crosses the faces' lines (7.4.13, rule 9), to 0.001, as its family's plane has it, with no change for the bearing's own elevation; it has none where d·k lies within 10⁻⁹ of 0 for a face, k the face's normal.
8. **A girder along the ridge.** Its two hip sets are laid out first, the start's and then the end's (rules 4 to 7), each with its side jacks at its grid's places. Its **grid** is the middle of the two apexes, M, and M ± kJ for k from 1 to 500, while either lies within 20 000 of the range, from least to greatest. With R_s and R_e the two sets' bearing lines, its line lies at τ_g, the mean of the two hip ends' a_τ, from r_0 = M − ℓ/2 to r_1 = M + ℓ/2, where ℓ = 2ρ + φ, φ = max(0, a_r(end) − a_r(start)) its **flat** and ρ = (a_r(start) − R_s + R_e − a_r(end))/2 its **rise**. Its pitch is the mean of the two hip ends' pitches; where they differ by more than 0.5°, that is said. Its drop δ is `girderPlies`·w/2 times the greatest |g·across| of the two eaves' gradients g, and its flat top φ + 2δ/tan(pitch) (φ where the tangent is 10⁻⁹ or less). It gives the flat-top family `Pitch`, its pitch; `HeelHeight`, z(P(τ_g, r_0)) − E; `OverhangLeft`, how far its line runs on before r_0 inside the domain, and `OverhangRight`, after r_1 (rule 7); and `FlatLength`, the lesser of its flat top and ℓ; each to 0.001. Where the family cannot be built with ℓ as `Length`, the girder is said, and neither it nor its half trusses are laid. Else its `girderPlies` plies, the k-th from 0 on the line at τ_g + (k − (`girderPlies` − 1)/2)·w from r_0 to r_1, each keyed `ridge:<k>`, of the mark of the layout's first listed position, else T1, at the place M, of the span ℓ, bearing on the two sets' end walls, the start's on the left, with no seat. Then its **half trusses**: at each place r of its grid that lies between the two apexes, more than 10 from each (r − w/2 > a_r(start) + 10 and r + w/2 < a_r(end) − 10), the k-th from 1, a jack (rule 6) on the left and one on the right, from the side's reference face to the girder's side face: from P(τ_L(r), r) along `across`, τ_g − `girderPlies`·w/2 − τ_L(r) long, keyed `ridge:jack:l<k>`, and from P(τ_R(r), r) along −`across`, τ_R(r) − τ_g − `girderPlies`·w/2 long, keyed `ridge:jack:r<k>`, each bearing on its side's bearing that stands at r.
9. **Where they rest and hang.** A hip truss and a jack rest on their first side only, where they have a bearing (7.4.13, rule 12): an anchor pair at a. Each also hangs at its far end: a **hanger** of one bracket at b, at E, keyed `<truss id>:hanger` and named `Hanger, hip truss to girder` for a hip truss, `Hanger, jack to girder` for a centre jack and a half truss, and `Hanger, jack` for any other jack. The layout's connections are its anchor pairs, in the order of its trusses, and then its hangers, in the same order.
10. **Names, members and IFC.** A hip truss is named `Hip truss` and its mark, and `(ply <k + 1>)` after it for a ply after the first; a jack `Jack truss` and its mark; a girder's ply `Truss` and its mark with `(girder)`, `(girder, ply <k + 1>)` after the first, and a girder along the ridge's with `along the ridge` after `girder`: `Truss T1 (girder, along the ridge, ply 2)` (7.4.13, rule 13). Each one's members are its family's parts, by 7.4.13, rules 13 and 14, its jack or flat-top family's for a hip truss, a jack and a girder along the ridge; their material is the layout's family type's. In IFC each is a truss of 7.4.13, rule 15. A hanger is an IfcMechanicalFastener in its roof's storey, its GlobalId from `fastener:<key>`, its name its name, its object type `HANGER` and its predefined type USERDEFINED, with no body; it connects no element, since what it hangs on, a girder's or a hip truss's plies, is no one element.

These are class-A rules, held to the tolerances of section 10: each member's body within 0.1 mm of the rules', and its volume within a relative 10⁻⁶; trusses, members, connections, their ids, names, sections and classes exactly.

*Note (informative).* None of the reference implementation's examples has a hipped roof with a truss layout (its `main` `f2bc53d2`, 29 October 2026). On a probe of nine hipped roofs over houses of framed walls whose studs stand under the trusses (`packages/openeik/test/fixtures/framing-hips.json`: fink, king post, Howe, collar and rafter families; hips at one end and at both; girders across the ridge, a girder shared by two hip sets on a ridge 100 mm long, and girders along a short ridge and through a pyramid's apex; hip ends of 20° to 75° over eaves of 20° to 35°; one, two and three plies; a jack spacing and a least jack given; the model's own jack family; end walls framed, unframed and a beam, and a hip end with none, its jacks unborne; a heel given and the finish faces; places given, one standing in a girder's plies; a hip end too short to frame; and hip trusses and jacks with no heel, left out), `@openeik/tools` lays out every truss the reference does, 272 (29 common trusses, 23 plies of girders across the ridge and 4 along it, 56 plies of hip trusses and 160 jacks), with its mark, family, line, span, parameters, bearings and seat; every member, 1223 of the roofs and 826 of the walls under them, with its id, name, section, class, box and volume exactly; and every connection, 317 anchor pairs and 216 hangers. Its print writes each truss, member and connection with the GlobalId, class, tag and object type of the reference's own print, and its name as the reference's with its Swedish words put into these rules' English (`Valmstol`, `Kortstol`, `bärande`, `längs nocken` and `lager` as `Hip truss`, `Jack truss`, `girder`, `along the ridge` and `ply`; 7.4.13's note), 2854 objects, and passes IfcOpenShell's validation and buildingSMART's rules with no issue. Where two end walls lie alike, the reference takes the first in the order of its elements, which section 9 of Part III gives no meaning; these rules take the first by id.

Reference: `hipEndsOf`, `hipSet`, `ridgeGirder`, `lineInside` and `seatOver` in `src/core/elements/trussHips.ts`; `jackFamily`, `flatTopFamily`, `jackType` and `flatTopType` in `src/core/elements/trussFamilies.ts`; `deriveTrussLayout` (its hip ends, its range at a hip, its girders and its `endWall`), `bearsOn` and `trussName` in `src/core/elements/trussLayout.ts`; `derivedFraming` in `src/core/io/ifcFraming.ts`; `exportIfc` (its fasteners) in `src/core/io/ifcExport.ts`. In `@openeik/tools`: `hipEndsOf`, `hipSet`, `ridgeGirder`, `jackFamily`, `flatTopFamily`, `hipFamilies` and `trussName` in `packages/openeik/src/compile-framing-hips.js`, called by `trussLayoutOf` in `packages/openeik/src/compile-framing-roofs.js`.

### 7.5 A room's boundary, ceiling and quantities

*Part of 0.2. OpenEik 0.1 had it as the proposal `rooms`: in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), room boundaries are reference behaviour, as section 7.2 says. The section adds no file and no member: the members are those of a room's `room`, a wall's and a column's `roomBounding`, a room separator's profile and the project's `rooms` (Part II, 2, 6.1 and 6.3).*

By the steward's decision of 26 October 2026, and of 30 October 2026 for a roof that comes down through the floor (open questions, 72), the boundary of a room placed by a point, found from the walls, columns, room separators and roofs round it, the ceiling of every room and its quantities are these rules, as the reference implementation finds them. A room drawn by hand (Part II, 6.1, rule 4) keeps its outline, and takes its ceiling and its quantities from them.

A room's **level** is its `levelId`, and its **floor** that level's elevation plus its `offset`. Its **point** is its profile's one point; for a room drawn by hand, its outline's centroid where that lies in the outline, else the middle of the first of its diagonals, from a point to the next but one, that does, else its first point.

1. **What bounds rooms.** On a room's level, each wall and each column whose `status` is not `demolished`, and whose `roomBounding` is `true`, or which gives none and is no wall whose `offset` is 1900 mm or more, bounds rooms with its **plan**:
   - a wall's: the convex hull, in plan, of its layers' bodies (section 4.1) as its joins end them, its points at each end within 1 mm of the furthest along it moved 15 mm further out along it, so that a joint up to 30 mm wide between two walls in line closes. Each layer's band is taken from the wall's base to its top (section 5.1), between the heights at which the line its ends stop on changes. Each point at an end moves along the wall to the line section 7.4.2 joins that end on at its height: at a corner, its mitre (7.4.2, rule 8) over the heights its corner covers (rules 3 and 4), and its partner's outer face above and below them; at a T, the host's core face on its side (rule 7). It moves only where that takes it no further than half the wall's length, or all of it where the corner fits only with room for its mitre (rule 6), and no further than four times the wall's thickness and 1 mm; the band is then cut on the line, keeping the side of the wall's middle, or of its other end where the corner fits only so. An end with no corner and no T, and an end section 7.4.2 keeps free (`joinEnds`), stays square. A wall with a `wallOutline` runs from its outline's least x to its greatest, an end that reaches the wall's end stopping on its main join's line (7.4.2, rule 5), and every end kept within it;
   - a column's: the convex hull of its body in plan (section 6.1), its section's outline, or a square of its `width`, centred on its point and turned by its `turn`. An arc of the outline is the rule; a compiler MAY draw it in chords that come within 0.01 mm of it.

   Each room separator on the level bounds rooms with a **line** from each of its points to the next, where they are at least 1 mm apart, lengthened by 1 mm at each end.

   **A roof that comes down through the floor**, a loft's, bounds rooms too. A roof with a `roof`, but for a barrel vault, has a face for each of its planes that is the lowest of them over some of its extent (its outline, each edge moved out by its overhang, each corner where the moved edges' lines meet; section 4.4, rules 2 and 3): the part of its extent where that plane is the lowest, of more than 0.01 mm². Its underside over a face is that plane lowered by the roof's thickness measured square to it (4.4, rule 4; a thickness is its type's layers' total, else its `height`). Where that underside lies under the level's elevation plus 10 mm at a corner of a face and over it at another, of any of its faces, the part of each face where it lies at that height or under, of more than 1 mm², is a plan. And then the edges of the floors the level stands on bound rooms as lines, each at least 1 mm long and lengthened by 1 mm at each end: the edges of the union of the outlines of the slabs and foundations of the level whose top lies less than 1000 mm under its elevation and less than 300 mm over it, and of those of other levels whose top lies within 50 mm of it, and the edges of their `voids`; a demolished one, and a round footing, is no floor.
2. **The faces.** The plans and the lines cut the plane into faces: the parts of the plane outside every plan and off every line, each in one piece. A face that is bounded, and whose outer ring encloses more than 100 mm², is a room's face. Its **boundary** is its outer ring and its holes, the outer rings of the groups of plans and lines that touch one another, lie inside it and touch none of those round it. A line that ends inside a face is part of its boundary, which runs along it on each side; a line that touches no plan and no other line divides nothing and is part of no boundary. The boundary's points are where the plans' edges and the lines meet, found to the model resolution of 0.01 mm (section 10).
3. **A room placed by a point** has the boundary of the face that holds its point inside it, off every ring of the face's boundary. Where none does, as where the point lies on a ring or in a plan, it has the boundary of the first face that so holds the point moved 1 mm along +x, along −x, along +y or along −y, in that order. Where no face holds it, it has no boundary, and a validator SHOULD warn of it (`rooms-enclosed`).
4. **One room to a face.** Where the points of two rooms or more lie in one face, the room whose id comes first in code-unit order (Part III, 9) keeps it, and each of the others has no boundary; a validator SHOULD warn of each of them (`rooms-shared`). A room drawn by hand has its outline as its boundary, without holes, whatever faces it lies in.
5. **The ceiling** is a surface over the room's boundary, from which its height, its walls' areas and its volume are measured:
   - where its `room.height` is given, the level plane that far over its floor;
   - else, at each point, the lowest of the planes over the room that are there: the underside of each slab and each ceiling whose outline, as recorded, holds the room's point, and none of whose `voids` does, level at its top less its thickness (section 4.2, rule 1), where that is more than 100 mm over the floor, there everywhere; and, of each roof with a `roof` whose extent (rule 1) holds the room's point, or leaves three points or more of the room's boundary's outer ring cut on the inner side of each of the extent's edges' lines in turn (the part of the room under it, where the extent is convex), the underside, there over its extent alone: of a pitched roof, its face's planes lowered as rule 1 lowers them, and of a roof none of whose edges defines a slope, its top less its thickness. A roof's underside is taken where it is more than 100 mm over the floor at the room's point, if the extent holds the point, or at a corner or at the centroid of that cut part of the room;
   - where neither is, the level plane of the lowest level 1800 mm or more over the floor, else the room's element's `height` over its floor (the room height, Part II, 6.2);
   - where only roofs' undersides are, that same plane is the ceiling over the part of the room that no roof's extent holds.

   A slab, a ceiling or a roof whose `status` is `demolished` is none. A thickness is its type's layers' total, else the element's `height` (4.2, rule 1). A barrel vault (`roof.vault`), whose faces are reference behaviour, is no ceiling by rule: a room whose point its extent holds, or whose boundary it cuts as above, has no ceiling by these rules, and a compiler says so.
6. **The quantities**, under the names of IFC4's `Qto_SpaceBaseQuantities`. Each stretch of a room's boundary lies against the plan that holds the point 0.05 mm out of the stretch's middle, square to it and away from the room, else the point 1 mm out, else 3 mm out; of the plans that hold the point, a wall's before a column's before a roof's, and of two walls' the one whose id comes first in code-unit order. A stretch along a line lies against that line, a room separator's before a floor's edge. Any other stretch lies against nothing. The room's **walls** are its stretches that lie against walls and columns.
   - `NetFloorArea`: the area of its boundary's outer ring less its holes'.
   - `GrossPerimeter`: the length of its boundary, its outer ring and its holes.
   - `NetPerimeter`: the length of its walls, less, unless the project's `rooms.doorsFromSkirting` is `false`, the width along them of each door in them.
   - `GrossWallArea`: the area of its walls up to its ceiling: along each stretch, the ceiling's height over the floor, where the ceiling is above it.
   - `NetWallArea`: `GrossWallArea` less, for each door and each window in its walls whose area is at least the project's `rooms.openingMinArea` (m²; 0 where it gives none), that area times its width along them over its `width`, at most its whole area; and never less than 0. A door or a window is in the room's walls where its host is a wall one of the room's walls lies against, its opening (section 4.3, from its host's base plus its `offset`, `height` high) begins under the ceiling's highest point over the room and ends over its floor, and its span along its host, from `along` to `along + width`, overlaps by 1 mm or more the stretches against its host, each measured along its host's baseline: that overlap is its width along them. Its area is its type's `outline`'s, else its `width` times its `height`.
   - `NetCeilingArea`: the area of the ceiling's surface over the room's boundary, a sloped plane's measured on its slope.
   - `NetVolume`: the volume from the room's floor up to its ceiling over its boundary, where the ceiling is above the floor.
   - `Height`: `NetVolume` over `NetFloorArea`, the room's mean height.

   National area rules stay the application's (Part II, 8).
7. **The volume.** A room's body, for a bridge or a view, is its volume: over its boundary, from its floor up to its ceiling where the ceiling is above it, as a prism for each part of the boundary that lies under one set of the ceiling's planes. It is no body of the model's (Part II, 6.2: a room has none): it cuts nothing, and a clash check does not read it.

These are class-A rules, held to the tolerances of section 10.

*Note (informative).* These rules are the reference implementation's room finder, stated on class-A bodies and the joins of section 7.4.2, but where this specification decided otherwise. Its body kernel takes each wall and each column as the convex hull of its bodies as built, joins included, and each room separator and each floor's edge as a strip 0.2 mm wide. From the records, `@openeik/tools` agrees with it exactly on 32 of the 39 rooms of `packages/openeik/test/fixtures/rooms.json`, on each boundary, area, perimeter, ceiling, height, wall, skirting, opening, ceiling area and volume: 12 of a probe of 14 (a free-standing column, a room on a separator's line, two rooms in one face, a room open on one side, a 20 mm joint, a wall that bounds no room and a high one, a room round the outer corner of two joined walls, a corner whose wall stops 125 mm short, a gable wall drawn by its outline, a gable roof over a room, a room drawn by hand beyond its eaves and a loft under a roof that comes down through its floor), and 20 of the 25 rooms of its one example with rooms (its work 727, 29 October 2026). Each of the other seven lies beside a room separator or a floor's edge, which these rules draw as a line, as open question 72 decided: its area is larger by 0.1 mm along each such stretch, its perimeter by 0.2 mm at each end of one, and what rests on its walls by as little. With the reference's strips in place of the lines, the faces of rule 2 give every room of the example to 10⁻⁹ m².

These rules leave the reference implementation to change where this specification decided otherwise, and where the reference contradicts itself: a room separator, and a floor's edge, as a line; two rooms in one face given to the one whose id comes first, where it gives the face to the one first in its list of elements; the element's `height` as the last ceiling, where it takes 2500 mm (open question 72); a room's ceiling area and volume under a roof whose extent is not convex measured over the extent as it is, where it cuts the room by the extent's edges as if it were convex, as it does not when it measures the room's walls; a door's or a window's opening from its host's base, as section 4.3 places it, where it measures from its host's level; a room's floor at its level plus its `offset`, as Part I, 4 places an element, where it takes its level alone; and a barrel vault no ceiling and no bound of a room, where it takes the facets of its own vault. None of these made a difference on the rooms compared.

Reference: `roomsOf`, `roomBodies`, `roofBodies`, `levelFloors`, `pastEnds`, `traceUnion` and `enclosedRegions` in `src/core/elements/rooms.ts`; `joinedWallSolids` in `src/core/elements/wallJoinSolids.ts` and `profileSolids` in `src/core/geometry/profileGeometry.ts`, on the joins of `src/core/elements/wallJoins.ts`; `ceilingPlanes`, `roomEdges`, `roomQuantities` and `roomVolume` in `src/core/elements/roomQuantities.ts`; `spaceTriangles` in `src/core/io/ifcSpaces.ts`. In `@openeik/tools`: `roomContext`, `wallPlan`, `roofShape`, `levelBounds`, `planFaces`, `faceAt`, `roomsOf`, `ceilingOf` and `measureRoom` in `packages/openeik/src/compile-rooms.js`, on `wallJoins` in `compile-framing-joins.js`, built by `compileRooms` in `compile.js`.

### 7.6 A component's frame and its bodies

*Part of 0.2. OpenEik 0.1 had it as the proposal `components` (Part II, 5): in a model of 0.1, read by 0.1's rules (Part I, 9.6, rule 3), what `componentInverted`, `axes`, `upright`, `plate`, `bolts`, `weld` and `insertAt` do to a component's body is reference behaviour, as Part II, 6.3 says. The section adds no file and no member.*

By the steward's decisions of 26 October 2026 (open questions, 73), which completes his decision of 17 October 2026, and of 30 October 2026 (open questions, 99), a component's frame, and its bodies that are boxes and prisms, are class-A rules, as the reference implementation places and builds them but where question 99 decided otherwise.

1. **Its frame and its bodies.** A component (Part II, 6.2) stands in a frame: rules 2 to 4 give it, or, for a cast-in item placed by `insertAt`, rule 5 gives each of its items one. A point (u, v, w) of a frame is its origin moved u along its x, v along its y and w along its z. Its bodies are rule 6's and rule 7's, by its type's family (Part II, 5): a timber section's (`timberSection`), a plate's (`plate`), a weld's (`weld`, with the element's `weld`), a bolt group's (`bolt`, with the element's `bolts` and its type's `component.bolt`), and a cast-in item's block or bar (its type's `insert.shape`, `block` or `bar`). Rule 8 says what stays reference behaviour. A component that has no frame, as rules 2 to 5 say, has no body, and a validator SHOULD warn of it (`component-frame`).
2. **Its frame.** Its origin is its insertion point, its profile's first point, at its level's elevation plus its `offset`. Where it gives `axes`, they are its frame, whatever its family: its x is `axes.x` made a unit vector, its y is `axes.y` made square to x and a unit vector, and its z is x × y, or y × x where it is `flipped` (Part II, 6.3); `axes` whose x is zero, or whose y runs along x, give no frame. Without `axes`, its x runs in plan from its profile's first point towards its second, its y is the left normal of x in plan, or its right normal where it is `flipped`, and its z is up; a profile whose two points are one gives no frame (Part II, 6.1, rule 8).
3. **A plate on a column.** A plate whose `hostId` names a column stands on it: its origin is the column's centre, the column's profile's first point, at the column's top (5.2, rule 4) plus the plate's own `offset`. Its axes are rule 2's, from its own profile or its `axes`. A column without a level, a centre or a height gives it no frame.
4. **Hung down and stood up.** A component without `axes` whose `componentInverted` is `true` hangs its box (rule 6) or its plate (rule 7) down from its origin, from w = −`height` to w = 0, where it otherwise stands from w = 0 to w = `height`. A plate without `axes` whose `upright` is `true` stands on its edge: a point (u, v) of its outline lies u along its frame's x and v up, and its thickness runs along its frame's y, centred on its origin, from −`height`/2 to `height`/2, whatever its `componentInverted` says. Neither member changes a weld, a bolt group, a cast-in item or a component with `axes`, and `upright` changes a component of no other family.
5. **A cast-in item's frame.** A cast-in item, a component whose type has an `insert`, placed by `insertAt` stands in the wall its `hostId` names, whose profile is two points, P0 and P1: u = (P1 − P0)/L along the wall, L = |P1 − P0|, n the left normal of u, T the wall's thickness (4.1), H its `height`, and its base at its level's elevation plus its `offset`.
    - **Its point** lies `along` from P0 along u, `up` from the wall's base and `across` in from its exterior face: P0 + u·along + n·(T/2 − across), at the base plus `up`. `along` is 0 where it gives none, L on the face `end`; `up` 0, H on the face `top`; and `across` 0 on the face `exterior`, T on `interior` and T/2 on the others.
    - **Its ways.** The way into the wall from its face, d, is −n from `exterior`, n from `interior`, down from `top`, up from `bottom`, u from `start` and −u from `end`. Its length's way, x, is u on `exterior`, `interior`, `top` and `bottom`, and up on `start` and `end`; where its `turn` is 90, x is up on `exterior` and `interior`, and n on the others. Its third way is y = d × x.
    - **Its body** runs in along a = d·cos(tilt) + x·sin(tilt), `tilt` in degrees, 0 where it gives none: a point (u′, v′) at a depth δ lies at its point + u′·x + v′·y + δ·a, so that a body that leans keeps its end in its face.
    - **Its items.** It has `count` items, 1 where it gives none, the k-th, from 0, `k`·`spacing` further along the wall, or up it where its `direction` is `up`, `spacing` 0 where it gives none.

    Its `profile`, `levelId` and `offset` are its writer's copy, which a reader ignores where `insertAt` is given (open questions, 73). A cast-in item whose `hostId` names no wall whose profile is two distinct points has no frame, and one that `insertAt` does not place has no body.
6. **A timber section** is a box in its frame: u from −`width`/2 to `width`/2, v from −`depth`/2 to `depth`/2, and w from 0 to `height` (rule 4), its `width` and `height` the element's and its `depth` its type's `component.depth`.
7. **A plate, a weld, a bolt group, and a cast-in item's block and bar.**
    - **A plate** is its outline less its holes, `height` thick. Its outline is its own `plate.outline`, points (u, v) in its frame, else its type's `width` by its `component.depth`, centred on its origin; its holes are its type's `component.holes` and its own `plate.holes`, each a circle of its `diameter` centred at (x, y), or, where its `length` is more than its diameter, a slot that long overall along `angle` degrees from u, its ends half circles (Part II, 5); its thickness runs from w = 0 to w = `height` (rule 4).
    - **A weld** is a fillet: the triangle (v, w) = (0, 0), (leg, 0), (0, leg), leg = `weld.throat`·√2, carried along u from 0 to its `width` (Part II, 6.3).
    - **A bolt group** is each bolt's shank within its grip: at each of its `positions` (u, v), a cylinder of its bolt's `diameter` along w, from w = 0, the face its head, or an anchor's nut, bears on, to w = `grip` (open questions, 99).
    - **A cast-in item's block** is, at each item, the box from u′ = −`width`/2 to `width`/2 and v′ = −`height`/2 to `height`/2, its type's, run in from δ = 0 to δ = `insert.depth` (rule 5); **its bar**, the round bar from δ = 0 to `insert.depth` along a, its `insert.diameter` round, else its type's `width`.

    A compiler MAY draw a hole's circle and a slot's ends in straight pieces, as it draws a pipe's circle (12.3, rule 5): the circle is the rule, and a component's volume is its bodies', its holes' circles exact.
8. **What stays reference behaviour** (class C): a bolt's head, washers and nut, an anchor's plate and the nut at its foot, and a shank past its grip, sized from a table of ISO bolts no record holds; the holes a bolt group drills in what its `through` names, a plate among them (7.2); an angle bracket's and a joist hanger's legs and nail holes; a cast-in item's lattice tie, its conduit and its bends, the cut its recess former makes in its wall, and the bar and the edge detail its product asks for at each item; a void form's and an edge detail's bodies; and the shapes of the families `toilet` and `basin`, deprecated in 0.2 (Part II, 5). A compiler says which of them a component has, and a supplier who needs one of them exact declares it (Part II, 12.1).

These are class-A rules, held to the tolerances of section 10. A component's IFC class is its type's (Part VIII, 1, its note on components): a plate an IfcPlate, a bolt group an IfcMechanicalFastener, a weld an IfcFastener WELD, and any other an IfcBuildingElementProxy.

*Note (informative).* Question 99 decided the two places where the reference implementation does what the records do not say. (a) It runs a hex bolt's shank from under its head's washer for the group's `length`, else for a length its table of ISO bolts picks, and an anchor's and a rod's between ends the same table gives (`assemblyPieces` and `rodSpan` in `src/core/elements/bolts.ts`); rule 7 takes the shank within the grip, which every bolt has whatever a table says, and which is what the parts it passes through are drilled for. (b) It places a box, a timber section, by its profile and does not read its `axes`, and its validator says "Axes belong to a plate, a bolt group or a weld"; rule 2 gives every component its `axes`, as Part II, 6.3 says, and the reference implementation changes for a box. Question 73 left a cast-in item's lattice tie and conduit to reference behaviour and made its frame a rule; its block, a box, and its bar, a round bar, are rule 7's, built from its records alone.

Reference: `partFrame` in `src/core/elements/partFrames.ts`; `componentSolids`, `plateFrame` and `plateOutline` in `src/core/elements/components.ts`; `holeLoop` in `src/core/geometry/holedCells.ts`; `placedPlate` and `plateBaseZ` in `src/core/elements/plates.ts`; `weldSolids` in `src/core/elements/welds.ts`; `boltFrame` and `boltGroupSolids` in `src/core/elements/bolts.ts`; `insertPoint` in `src/core/elements/inserts.ts`; `insertPlacements` and `insertSolids` in `src/core/geometry/insertSolids.ts`. In `@openeik/tools`: `componentFrame`, `castInItems` and `componentBodies` in `packages/openeik/src/compile-components.js`, called by `compileComponentBody` in `compile.js`.

## 8. Body kinds (informative)

The reference compiler produces six kinds of body. The plan proposes them as the normative kinds N1–N6 of a later version.

| Kind | Reference representation |
|---|---|
| N1. A vertical prism of a plan polygon | `profile`, `bottom`, `top` |
| N2. A convex polyhedron, or a set of convex cells | `vertices`, `faces`, `cells` |
| N3. A layer between two planes (pitched roofs) | prisms clipped by half-spaces |
| N4. A member swept along a line, square to it | `vertices`, `faces`, with an `axis` |
| N5. An exact cylinder or a rod | `round` (centre, radius); `rod` (two points, diameter) |
| N6. An opaque mesh with a stand-in box | `shape` (indexed mesh), with a `proxy` body for sections and quantities |

A pipe's or a duct's body (section 12) is a closed mesh of `vertices` and `faces`; the reference implementation also cuts it into convex cells between its rings (N2), so that a section shows a bend as a bend.

Reference: the `Solid` type in `src/core/geometry/geometry.ts`.

## 9. Quantities (informative)

The reference implementation reports, per element, a volume in m³ with its basis ("per-element solids; openings deducted; matching endpoint wall mitres included; other inter-element overlaps not deducted"), the volume of each layer, a wall's gross, opening and net area per side on its centreline, and a roof's sloped area, perimeter, eaves, verges and ridge. 0.1 does not standardise quantities; the plan proposes typed values `{value, unit, basis, rule, version}`.

For `examples/one-storey-house` the reference compiler gives:

| Element | Quantity | Value | By hand |
|---|---|---|---|
| `slab-ground` | volume | 33.8355 m³ | 10.3 m × 7.3 m × 0.45 m |
| `slab-ground` | layer `concrete` | 7.519 m³ | 75.19 m² × 0.1 m |
| `wall-south` | gross area, one side | 27.0359 m² | 10 m × 2.70359 m: the roof's underside over the centreline lies at 2700 + 350 − 300/cos 30° = 2703.59 mm |
| `wall-south` | openings | 3.9 m² | 1.0 × 2.1 + 1.5 × 1.2 |
| `wall-west` (gable) | gross area, one side | 25.9977 m² | 7 m × 2.70359 m + ½ × 7 m × 3.5 m × tan 30° |
| `roof-main` | sloped area | 95.4706 m² | (10 + 2 × 0.3) m × (7 + 2 × 0.4) m / cos 30° |
| `roof-main` | ridge | 10.6 m | 10 m plus two 0.3 m gable overhangs |

These values are informative; they are what a conformance vector for this folder would check.

## 10. Tolerances and conformance (proposed)

The plan proposes that a compiler conforms when, on published vectors, each element's bodies lie within a Hausdorff distance of 0.1 mm of the reference, volumes and areas within a relative error of 10⁻⁶, and counts are exact, with a model resolution of 0.01 mm. This specification publishes no vectors yet; until it does, the class-A rules above are the requirement and the table in section 9 is an example. Pipes and ducts, whose faceting is the reference implementation's and not the rule's, have a tolerance of their own (12.5).

## 11. A supplier's parts

This section says what a supplier's parts (Part II, 12) ask of a compiler: declared geometry (Part II, 12.1) and railings for product systems (Part II, 12.2).

### 11.1 Declared geometry

A type or an element may carry a supplier's declared geometry at a declared level of detail, with the aspects it is authoritative for (Part II, 12.1). A compiler treats it so:

1. **It derives nothing beyond what a record declares itself authoritative for.** From an envelope it MAY derive the space the part takes (its bounds, its volume as space taken, sections and plans through it), and nothing about what is inside: not its materials, its parts, a count of parts or a cut list.
2. **For a declared aspect, the declaration wins** over the compiler's own rule: a declared envelope replaces the body derived from the type's payload where a body stands for the space taken (clashes, sections, exports); declared positions replace a reference layout (the posts of a railing).
3. **For an aspect that is not declared**, the compiler derives as it does for any record of the category, and says which results come from the declaration and which from its own rules.
4. **It MUST NOT derive fabrication data from declared geometry.** When a declaration is authoritative for `fabrication`, a compiler or a bridge passes that data on as the supplier gave it, and does not work it out again.
5. **Nothing it derives is stored** (section 1): the declaration is a record's own content, and the results a compiler works out from it are derived like any others.
6. A bridge that exports a declared envelope as a product's body SHOULD say so in its fidelity report (Part VIII, 1), with the declaration's level.

Reference: `declaredSolids` in `src/core/geometry/declaredBodies.ts` (rules 2 and 3: a declared envelope, or declared parts, drawn in place of the derived body for 3D, sections, quantities and IFC).

*Note (informative).* Whether the sizes a type sets (Part II, 5.3) must agree with its declared envelope was deferred to 0.2 by the steward on 15 October 2026 (open questions, 17). In 0.1 nothing requires it: the sizes size the record and the body this part derives from it, and rule 2 puts the envelope in that body's place where a body stands for the space taken. A declaration on a type of a category that Part II, 12.1 gives no frame for is placed nowhere, and a compiler derives nothing from it. Part II, 12.1.1 gives in 0.2 what the steward decided on 21 October 2026: the sizes stay nominal, and a stair's type and a wall's type get a frame, in which a compiler places their declarations.

### 11.2 Railing lines and posts

The line of a railing on the outline of a slab or a shaft, and its given posts, are class-A rules. The line of a railing on a stair stays reference behaviour (class C): it follows the stair's derived flights.

1. **The run.** The edges `railing.edges` names are taken in their order round the host's outline, as one run (Part II, 12.2). The run's points are the outline's points from the start of its first edge to the end of its last; when it names every edge, the line is closed.
2. **The walking side** is the inside of a slab's outline, and the outside of a shaft's (the floor round an opening).
3. **The offset.** Each edge's line is moved towards the walking side by its inset: `railing.insets[<edge id>]`, else `railing.inset`, else 50 mm (the reference default). A negative inset moves it off the edge, as side mounting needs. When every edge of the run has the same inset, each corner moves along its bisector by the inset divided by the cosine of half the turn at the corner, but never by more than 4 times the inset. When the edges' insets are not all the same, every corner of the run is where the moved lines of its two edges cross, or halfway between their ends where those lines are parallel or cross farther than four times the larger inset from the corner (Part II, 12.2).
4. **The base.** The line stands on the host's top: `elev(levelId) + offset` of a slab, or the top of a shaft (section 5.1).
5. **Given posts.** With `railing.posts.at`, a post stands at each listed distance `s` along the line from its first point, measured in plan, and nowhere else. A post is `postWidth` along the line by `postDepth` across it (`post` by `post` without them), centred on the line and square to its segment (at a corner, square to the corner's bisector). It rises from the base, or from `belowBase` below it when `mount` is `side`, to the underside of the top rail, which carries the railing to its `height` above the base.
6. **Without given posts** the layout is reference behaviour. The reference implementation places a post at both ends, at every corner, and evenly between them, no farther apart than `postSpacing`; with `postEndDistance` it stands the first and last posts that far from the ends, and it leaves out the end posts `posts.omit` names.
7. Rails, infill and handrails stay reference behaviour.

By the steward's decisions of 21 and 24 October 2026 (Part II, 12.2; open questions, 18), in 0.1 since 24 October 2026, the lines of railings on a wall's top and along a slab edge element are derived so; both are class-A rules, a slab edge element's since its section became one on 26 October 2026 (section 4.6):

8. **On a wall's top.** Let `a`, `b` be the wall's baseline, `L` its length, `u = (b − a)/L`, `n` its left normal and `T` its thickness (4.1), and `d` the railing's `inset`, else `T/2`. A point `x` along the wall, from 0 to `L`, is at `a + u·x + n·(T/2 − d)` in plan. Its height is the wall's top there: where the wall has an elevation outline (an attached top, a profile of its own; section 5.3), the upper edge of that outline, with a point at each of its corners and two at one `x` where the top steps; else the wall's height over its base. The line runs from one end of the baseline to the other.
9. **Along a slab edge element.** With the element's section across its edge, its rectangles and its facing, as section 4.6 places them (its chamfer not counted), its outer face is the least reach of the section from the edge's line, `r_out`, and its top face the part of the section within 0.5 mm of its highest point, from reach `r0` to `r1`. The line runs at the reach `r_out + d` from the edge's line, `d` the railing's `inset`, else `(r0 + r1)/2 − r_out`, along the element between its own ends, square, or on a corner's bisector where the element is mitred (4.6, rule 6), at the height of the element's top, and never below its slab's top.
10. **Walking side** (rule 2): a wall's interior, the right of its baseline; the slab's side of a slab edge element.
11. **Posts** stand by rules 5 and 6; on a wall's top, its corners include every point where the top steps or its slope changes.

Reference: `railingLine` and `offsetLine` in `src/core/elements/railings.ts`; `offsetEdges` in `src/core/elements/railingEdges.ts` (different insets); `railingPosts` in `src/core/elements/railingPostLayout.ts`.

### 11.3 Generic elements

A generic element (Part II, 6.6) has no shape but its declared geometry.

1. A compiler derives nothing for it beyond placing its declared bodies: its own declaration's, in the `world` frame, and its type's, in the frame of a category placed at a point (Part II, 12.1), at its insertion point, turned to its orientation, on its base. Where both declare an aspect, the element's wins (Part II, 12.1).
2. Its quantities are those of its declared bodies: a volume from its closed bodies, as space taken (11.1, rule 1), with the basis `declared`.
3. It cuts nothing, and no rule joins it to another element.

*Note (informative).* The reference implementation has no `generic` category (Open questions, 2).

## 12. Pipes and ducts

A pipe or a duct is a run (Part II, 6.2): its points in plan, a height for each, a size and a system. Its body is its outer section swept along the run with each corner rounded into a bend. The body and its quantities are class-A rules; the fittings found between runs (a branch where one run's end lies on another, a reduction or a joint where two runs meet end to end) stay reference behaviour (section 7.2).

### 12.1 The run

Given a pipe or a duct with profile points `p_0 … p_(m−1)`, its `mep` payload and its type:

1. **The points.** Point `i` of the run is `P_i = (p_i, elev(levelId) + mep.z[i])`: the heights are measured from the level, and the element's `offset` is not added. A run MUST carry `mep` with one height per profile point; one that does not has no body. Two points on one spot in plan, at two heights, make a vertical piece: the run climbs or drops there.
2. A run MUST have two points or more, not all at one place; else it has no body.
3. **The outer size.** Let `ins` be the run's insulation thickness (Part II, 6.9): its own `mep.insulation.thickness`, else its type's `pipe.insulation` or `duct.insulation`, 0 when it has none and 0 where its own `mep.insulation` gives `none`; where a pipe or its type gives a deprecated `bti`, its `thickness` (Part II, 6.9, rule 4). The run's outer width is `W = mep.size + 2 ins`. A duct whose type's `duct.shape` is `rectangular` has a rectangular section `W` wide and `H = h + 2 ins` high, where `h` is `mep.height`, or `mep.size` without it. Every other run, a pipe or a round duct, is round, `W` across; its `mep.height` is not used. `W` and `H` MUST be positive.
4. Two points in a row less than 1 mm apart, and a turn of more than 179° at a point, are not runs the reference implementation writes (its validator refuses them). A compiler builds them by the rules below and SHOULD say so.

### 12.2 Bends

The **rounded path** replaces each corner of the run by a circular arc. For each inner point `P_i`, let `d0` and `d1` be the unit directions of the pieces `P_(i−1) P_i` and `P_i P_(i+1)`, and `θ = arccos(d0 · d1)` the turn there.

1. Where `θ < 10⁻⁴` (the run goes straight on) or `θ > π − 10⁻³` (it turns back), `P_i` stays a corner.
2. Otherwise the corner becomes an arc of radius `r = W`, the outer width, tangent to both pieces. The arc starts at `A = P_i − t d0` and ends at `P_i + t d1`, where `t = r tan(θ/2)`.
3. Where `t` is more than half the shorter of the two pieces, `|P_i − P_(i−1)|` and `|P_(i+1) − P_i|`, it is that half, and the radius shrinks to `r = t / tan(θ/2)`. So two arcs never overlap on one piece. Each corner is measured on the run's own points, not on its neighbours' arcs.
4. The arc is sampled at `k + 1` points, `k = max(2, ⌈θ / (π/12)⌉)`: with `n = unit(d1 − d0 (d0 · d1))` and the centre `c = A + r n`, point `j` is `c − r cos φ_j n + r sin φ_j d0`, where `φ_j = θ j / k`, for `j = 0 … k`.
5. The rounded path is `P_0`; then, for each inner point in order, its arc's `k + 1` points, or the point itself; then `P_(m−1)`. A point within 10⁻⁶ mm of the one before it is dropped (where two arcs each take half of one piece, the second starts where the first ends).

A rectangular duct's bend has the radius of its width `W` whether it turns in plan or climbs.

### 12.3 The body

The section is carried along the rounded path, one ring at each of its points `q_0 … q_(N−1)`, and the rings are joined into one closed mesh.

1. **The tangent** at `q_0` is the direction of `q_0 q_1`, at `q_(N−1)` that of `q_(N−2) q_(N−1)`; at an inner point it is `unit(unit(q_j − q_(j−1)) + unit(q_(j+1) − q_j))`, or the direction of `q_j q_(j+1)` where that sum vanishes. Each ring lies square to its tangent, with a side vector `s` square to the tangent and `u = unit(t × s)`.
2. **A round run.** Its ring is a circle of radius `W/2` about `q_j`, in the plane of `s` and `u`. Its side vector is carried along the path without twisting: at `q_0`, `s = unit(t × Z)`, or the x axis where the tangent is vertical; at each later point, the last `s` turned about `unit(t_(j−1) × t_j)` by the angle between the two tangents (not at all where they are parallel), then made square to `t_j` again.
3. **A rectangular duct.** Its section stays upright: the rectangle `W` along `s` by `H` along `u`, centred on `q_j`, with its width level. At each point `s = unit(t × Z)`, except that: where the tangent is vertical (`|t × Z| ≤ 10⁻⁶`), `s` is the previous point's (at a run that starts vertical, that of the first point that is not; on a run that is vertical throughout, the x axis); and where `s` would point away from the previous point's (`s · s_prev < −10⁻⁹`), it is reversed. So the section never turns end over end, and turns about the vertical only along a vertical piece that the run leaves in another plan direction than it came in (by 90° from −x to +y, say).
4. **The mesh.** The rings, each of `n` points in order counter-clockwise about the tangent, are joined by a four-sided face between each two rings at each side; the first ring, reversed, and the last close its ends. Every face turns counter-clockwise seen from outside.
5. The body is the section swept along the rounded path. Which points stand on each ring, and how many, is the reference implementation's faceting, not the rule: it draws a circle with `n = 20` points for a duct and `n = 14` for a pipe, point `j` at `q_j + (W/2)(s cos(2πj/n) + u sin(2πj/n))`, and a rectangle's corners at `q_j ∓ (W/2) s ∓ (H/2) u` in the order `(−, −)`, `(+, −)`, `(+, +)`, `(−, +)`. A compiler MAY facet the body otherwise, within section 12.5. The orientation of a rectangle (rule 3) is the rule.

### 12.4 Quantities

1. **The volume** is the section's area, `π W² / 4` for a round run or `W H` for a rectangular one, times the length of the rounded path as sampled (12.2.5): the sum of the distances between its consecutive points. It is the space the run takes, its insulation included; the fittings between runs are not in it. The volume a faceted body holds is less (by about 1.6 % for a circle of 20 points, 3.3 % for one of 14) and is not the quantity.
2. **The length** is measured along the run's own points in 3D, `Σ |P_(i+1) − P_i|`, each bend taken as its corner, as pipe and duct schedules measure it.

### 12.5 Conformance

A compiler's body for a run conforms when its volume (12.4.1) is within 0.5 % of the rule's, its length (12.4.2) is the rule's, and each side of its bounding box lies within 2 % of the outer width `W` (and at least 1 mm) of the bounding box of the reference faceting of 12.3.5. Vertex counts need not match.

`packages/openeik/test/fixtures/run-bodies.json` holds eighteen runs (straight, bent in plan, climbing, sloped, with short pieces and with insulation, a ventilation main with several bends and a climb) with the volume, length, bounding box and vertex count the rule gives, and the reference implementation's own results; `tools/run-bodies-reference.mjs` writes it from a checkout of the reference implementation.

Reference: `runPoints`, `runOuter` (with `runInsulation` in `src/core/elements/mepInsulation.ts`), `bendRadius` (the outer width), `runLength` and `runSolids` in `src/core/elements/mep.ts`; `roundedPath`, `tangents`, `frames`, `tubeRings`, `boxRings`, `ringsToMesh`, `ringCells` and `pathLength` in `src/core/geometry/sweep.ts`. The volume is `runSolids`' `volumeMm3`.

*Note (informative).* The reference implementation reads a run with no `mep`, which its validator refuses, with its type's `width` (else 100 mm) for its size and the element's `offset` for every height; and a point with no height of its own at the element's `offset`. These are the application's fallbacks, not the rule (12.1.1). It also gives the body its type's colour and material, hides it in plans, where a run is drawn by its symbol, and cuts it into convex cells between its rings for sections. It works out `θ` in floating point, so at a turn that is a whole multiple of 15° it can take one chord more than `⌈θ / (π/12)⌉` (four for a 45° bend between the directions (1, 0) and (1, 1)), within 12.5. Before `d0774a48` it differed from rule 3 of 12.3: where the tangent was vertical it took the x axis for `s`, and it did not keep `s`'s sense, so a rectangular duct that started or ended climbing, or climbed and came back the way it came, turned its section along the vertical piece. Since then it gives the rule's volume, length, vertex count and bounding box in all eighteen fixtures.

*Note (informative).* The reference implementation takes a duct's insulation thickness from its code's entry in a table, its project's (`project.standards.mep.ductInsulation`) or its own, where the entry has one, before the type's `duct.insulation`: a duct whose code is `K25` is drawn 50 mm larger all round by it, and not by rule 3 (open questions, section 2, row 28). It gives no run its own thickness.

### 12.6 Terminals and components in a pipe or a duct

A terminal (Part II, 6.9) is its declared geometry, where it or its type has one (Part II, 12.1), placed in the frame of a category placed at a point (section 11.1). Otherwise its body is a box of its type's `terminal.width` across the way it faces, `terminal.depth` along it and `terminal.height` high: centred on its point in plan, turned to the way it faces, from its base, `elev(levelId) + offset`, up. A terminal whose type gives no width, depth or height has no body. A component in a pipe or a duct stands where its run puts it, by the rules below; a duct part that names no duct (Part II, 6.9) is a terminal as this paragraph says.

The washbasin of a type 600 mm wide, 450 deep and 200 high, at `[2000, 1000]` facing `[2000, 0]`, its offset 750 on level 0: its box runs from x 1700 to 2300, y 775 to 1225, and z 750 to 950.

A component in a pipe or a duct (Part II, 6.9) is its declared geometry, where it or its type has one (Part II, 12.1), placed in the frame of a category placed at a point: its origin at its point, x along its way, z up. Otherwise its body is a box `w` across its way, its type's `terminal.depth` along it and `h` high, centred on its point in plan, from `z − h/2` to `z + h/2`, where `z` is its point's height. In a pipe, `w` and `h` are its type's `terminal.width` and `terminal.height`. In a duct they are its size across (Part II, 6.9): `w = max(terminal.width, W + 20)` and `h = max(terminal.height, H + 20)`, where `W` and `H` are its duct's outer width and height (12.1, rule 3).

1. A component's body is placed from its run and `along`, where Part II, 6.9 puts its point and its way, not from its stored `profile` and `offset`; a component in a duct is sized from its duct and its type, not from its stored `width` and `height` (Part II, 6.9, rule 8).
2. Its run's body runs through it: a component cuts nothing, and the run's length and volume (12.4) are the run's whole. Its volume is the box's.
3. A component whose `hostId` names no element of its run's category, a pipe for a type that mounts on a pipe and a duct for one that mounts on a duct, or whose run has no line or no outer size (12.1, rules 1 to 3), has no body.

The valve of Part II, 6.9, 60 mm across, 80 mm along and 70 mm high, 2000 mm along its pipe on a piece that runs +x at 2400 mm: its box runs from x 2960 to 3040, y 970 to 1030 and z 2365 to 2435.

The damper of Part II, 6.9, of a type 145 mm across, 200 mm along and 145 mm high, in a duct 400 mm wide and 200 mm high without insulation: `w = max(145, 420) = 420` and `h = max(145, 220) = 220`. 1500 mm along its duct, on a piece that runs +x at 2700 mm, its box runs from x 2400 to 2600, y 4790 to 5210 and z 2590 to 2810.

These are closed-form rules, of class A (section 2). The reference implementation draws some terminals in a shape of their own (a WC, a basin, a round ceiling outlet), and keeps the box as the shape's proxy for sections, elevations and collision: the shape is reference behaviour (class C), and the box is the body this section derives (decided on 24 October 2026).

Reference: `terminalSolids` in `src/core/elements/mep.ts`, which boxes a terminal of its type's size from its base, turned to its facing, a component centred on its point, and a component in a duct as large across as its stored `width` and `height`; `terminalAt` in `src/core/elements/terminalPlacement.ts`, which places a terminal's point, facing and base; and `placedOnRun` and `componentBody` in `src/core/elements/runComponents.ts` (Stomra 633 and 676).

### 12.7 What is derived (informative)

These are derived from pipes, ducts and terminals, and never stored (section 1):

- **A heating terminal's water flow**, in l/h, from its power `P` in W and its design difference `ΔT` in K: `q = 3.6 P / (c ΔT)`, with `c` the heat of a litre of water per kelvin, 4.18 kJ/(kg·K) × 0.988 kg/l. 500 W at 10 K is 44 l/h.
- **The heat of a system**: its terminals counted, their power and their flow summed.
- **The metres of insulation** by code, from the runs' lengths (12.4, rule 2).
- **A tag's text**: a template filled in, a room tag's rows (Part II, 13.3 and 13.4), a component's tag (its `mark`, else its type's `code`, and its run's size).
- **A schedule of components**, by mark, type, system and size.

How each is worked out and shown is the application's. An application that keeps derived results keeps them in its own folder with a result manifest (Part VI, 8), never in a record.

Reference: `terminalHeat`, `heatTagText` and `heatList` in `src/core/elements/mepHeat.ts`; `mepLists` and `terminalTag` in `src/core/elements/mep.ts`; `componentList` in `src/core/elements/runComponents.ts`.
