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
- 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.
- 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.
- Derived results MUST be a function of the model alone: the same records give the same results, whatever order the elements are in.
- 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
worldframe, 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/.
- 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.
- 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.
- 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.
- 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; fixing them is planned for 0.2 (decided 11 October 2026), and section 1.1.2 proposes them. A shape that meets the rules is the one 1.1.2 proposes: .eik/derived/elements/<id>.json holding {"sources": {"<key>": "<hash>", …}, "producer": "<implementation> <version>", "rule": "<rule name>", "result": {"bodies": […]}}.
1.1.1 A result's bodies (proposed for 0.2)
Proposed for 0.2, and informative in 0.1: it adds no rule to 0.1, and no file of 0.1 is held to it.
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, the first part of the form of a result planned for 0.2 is proposed here: a result's bodies, in schemas/proposed/derived/bodies.schema.json (the proposal derived).
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).
1.1.2 The derived layer's layout and a result's form (proposed for 0.2)
Proposed for 0.2, with the proposal derived, and informative in 0.1: 0.1 leaves the layout and the form open (1.1), and what this section proposes meets its 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):
The layout. A result is of one record, an element or a type. An element's result lies at
.eik/derived/elements/<id>.jsonand 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>ortypes/<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.A result's form. A result is one JSON object
{sources, producer, rule, result}: itssources(rule 3); itsproducer, the implementation that derived it and its version, as people read it; itsrule, the rule or the set of rules it was derived by, by the producer's name for it; and itsresult,{bodies, quantities?, line?}.bodiesare 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 unitm3,m2,morcount, withlayers, 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: itsreferenceline and itsaxis, each from its start to its end ornull, a beam'ssetOutline, itscentroidOffsetornull, itssection,{shape, width, depth, endDepth?, area}, its areanullwhere it is not derived, and itslength. A result holds nothing else.schemas/proposed/derived/bodies.schema.jsonstates the form.Its sources.
sourcesnames, by its key, each record and each set of records whose change may change the result, with its hash (Part III, 6), ornullwhere 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, andproject, the project record;referrers/<id>, the elements that name the element byhostIdor by a join'sto(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.
When it is current. A reader uses a result only while each of its keys has, in the model, the hash it names,
nullamong 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).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
producerandrulewith its own, and derives it again where they differ.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.
2. Rule classes
| Class | What | Status in 0.1 |
|---|---|---|
| A | Closed-form rules: layered extrusions, outline edges trimmed to a wall's face, roof planes, attached tops, member sweeps, rectangular openings, 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 | Normative where this part states them |
| B | Rules that infer from geometry with tolerances: wall corner and T joins, member join extensions, room boundaries, MEP fittings between runs (branches, reductions, joints) | Reference behaviour (section 7) |
| C | Product and practice engines: timber framing, trusses, stairs, precast, steel joints, regional area rules | Reference behaviour |
A compiler of the core class MUST implement the class-A rules of sections 3 to 6 (4.6 and 4.7 among them), 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 levell;- for a wall or beam with profile points
P0,P1:L = |P1 − P0|is the plan length,u = (P1 − P0) / Lthe plan direction, andn = (−u_y, u_x)its left normal; Tis 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
iis the prism over[z0, z0 + H]of the quadrilateral spanned alongP0 → P1between the offsetsd_iandd_(i+1)alongn, whered_1 = T / 2andd_(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):
- Its thickness is
Twhen its type has layers, else itsheight. - With layers
t1 … tklisted top first, layeriis the prism of the outline over[z1 − Σ_(j≤i) t_j, z1 − Σ_(j<i) t_j]. A layer with aninsetuses the outline offset inwards by the inset. - Without layers, the body is the prism of the outline over
[z1 − height, z1]. - Each outline in
voidsis cut through every layer. - A foundation whose type has a round
footingis a cylinder of the footing's diameter about the profile's single point, over[z1 − T, z1](or[z1 − height, z1]). - Thickened edges. A slab or a foundation is thickened under its edges that carry a slab edge element whose type's
edgeProfilehas abeam, and its layers under its structure give way there, as section 4.6, rules 9 and 11 say. - 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.
- Shafts. A shaft (Part II, 6.2), its outline
profilebetween its baseelev(levelId) + offsetand 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'sshaft.purposeisstairout 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.
4.2.1 A slab on a sloped plane (proposed for 0.2)
Proposed for 0.2, and informative in 0.1: it adds no rule to 0.1, and no file of 0.1 is held to it. A compiler builds these only when it is asked for the proposal slopedSlab; without it, 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 proposal 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 σ:
- 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
insetlies 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. - Its openings. Each outline in
voidsis 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. - 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
edgeIdstarts at the recorded edge, and one given by afallat the recorded first point. Its outline is trimmed by 4.5, rule 2, and its layers fill what is left. - Its quantities (informative, as section 9) are a pitched roof's: its volume is its layers' bodies'; its
areais its outline in plan, trimmed, its voids and the shafts through its whole thickness deducted, as a level slab's; and itsslopedAreais its top face over that area, measured on the slope: the area in plan times k. - 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, with the proposal
rooms, 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). - 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. With the proposalframingLayout, 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. - 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².
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.
Reference: basicSolids (wall branch: spans between openings).
4.3.1 A door's and a window's own body (proposed for 0.2)
Proposed for 0.2, and informative in 0.1: it adds no rule to 0.1, and no file of 0.1 is held to it. A compiler derives these bodies only when it is asked for the proposal frames; without it, a door's or a window's own body is reference behaviour, as section 4.3 says. The proposal adds no file, and these members, each of which without it is a member 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 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):
- 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 asked for the proposal SHOULD warn of such a door or window, which it can tell from the records alone. - Across the wall. The frame runs from y = yExt − d to y = yExt, where yExt = T/2 −
wallOffsetand d =frameDepth; whereframeFollowsWallis true, d = T andwallOffsetis 0, so that it spans the wall. It is measured from the exterior face whatever the element'sflippedsays. - 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.
- A window's lights. Its columns divide ix0…ix1 and its rows iz0…iz1:
lightsXcolumns, andlightsYrows, each (span − (n − 1)·mw)/n, mw apart; or, wheremullions.x(mullions.z) gives mullions, the fields between them, each mullion centred at fx0 +at(fz0 +at) and as wide as itswidth, else mw, in the order ofat. 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. - A fixed light, where
operableis false: its glass fills it,glassThicknessthick, centred in the frame's depth. - An opening light, where
operableis true: a sash fills it, from y = yExt − 12 −sashDepthto 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,glassThicknessthick, centred in the sash's depth. - A door's leaves. A door of the kind
doorhaslightsXleaves, and one of the kindgarageSideHingeditspanels, side by side, each (ix1 − ix0)/n wide, from fz0 to iz1,leafThicknessthick and centred in the frame's depth. - A glazed leaf. Where a door's
glazingisfullorupper, 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 forfulland z0 + (z1 − z0)/2 forupper, between the stiles, inlightsYrows mw/2 apart, centred in the leaf's thickness,glassThicknessthick; the rest of the leaf, below gz0 and between the rows, is leaf. - 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 +leafThicknessand from m − 3 −leafThicknessto 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. - A garage door of the kind
garageSectional,garageRollerorgarageFoldinghas the frame of rule 3, and one leaf closing its clear opening, ix0…ix1 from fz0 to iz1,leafThicknessthick and centred in the frame's depth. - A shaped opening, whose type has an
outline(4.3): its frame follows the outline as its wall is cut by it, mirrored where itshandFlippedistrue. 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. - 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):
- Its frame is
framewide anddepthdeep, centred on the wall's axis: a head and a sill the whole width, x 0…W, and the jambs between them. Its panes arepanesacross andtransoms+ 1 up, each (W − 2·frame− (panes− 1)·mullion)/paneswide and (H − 2·frame−transoms·mullion)/(transoms+ 1) high, with mullions and transomsmullionwide between them, frame members as deep as the frame; and each pane's glass fills it,glassThicknessthick, centred on the axis.
For an openingFamily's materials:
- 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
doorMAY giveleafMaterial, the material its leaves are of where it is not its frame's:wood,aluminiumorsteel, as a wood leaf in a steel frame. A leaf (rules 7 to 9) is ofleafMaterial, and its frame, its sashes and its mullions of the family'smaterial; withoutleafMaterial, the leaf is ofmaterialtoo. The material changes no body. A family of another kind has no leaf of its own, its sashes or its panels being ofmaterial: it SHOULD NOT giveleafMaterial, and a validator asked for the proposal SHOULD warn of one (leaf-material).
For a family's profiles:
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
openingFamilyitsframeProfile,mullionProfileandsashProfile, and awindowFamilyitsframeProfileandmullionProfile. A profile is an outline as acustomsection'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'sframeWidthbyframeDepth(awindowFamily'sframebydepth), a mullion profile'smullionWidthbyframeDepth(mullionbydepth), and a sash profile'ssashWidthbysashDepth. A family whose frame follows its wall (rule 2) MUST NOT giveframeProfile: its frame is as deep as each wall it stands in. A validator asked for the proposal 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
widthis notmullionWidth(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.
- 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
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).
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):
- Each edge with
definesSlope: trueand slopeσ_i(degrees, 0–75) defines the planez_i(p) = z0 + tan(σ_i) · (n_i · (p − a_i)), wherea_iis the edge's start andn_iits unit normal pointing into the outline. So the top face meetsz0along every slope-defining edge line. - 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 planez = z0. - The surface extends past each edge by that edge's
overhang(mm, in plan). - Layers are measured at right angles to the face they lie under: a layer of thickness
tunder a face of gradient(g_x, g_y)liest · √(1 + g_x² + g_y²)lower, vertically. - 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.
- 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):
- The face is a line in plan: the exterior face is
n · (p − P0) = T/2, the interior facen · (p − P0) = −T/2. A point's distance from the face, positive away from the wall, isδ(p) = n · (p − P0) − T/2for the exterior face andδ(p) = −n · (p − P0) − T/2for the interior face. - The trimmed outline is the part of the outline where
δ(p) ≥ 0for 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. - 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.
- 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.
- 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).
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.
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):
- Its section is its type's
edgeProfile(Part II, 5.6). Without one it is arectangleof the element'swidthby itsheight, anchored atstructureBottom. 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, proposed for 0.2, takes from them. - The section's rectangles, in
x, across the edge into the host from the edge's line, andz, up from the anchor: arectanglefromx = −width/2towidth/2; anL, its upstand fromx = −webto 0, and its bottom leg from 0 towidth − weband fromz = −depthto−depth + flange; aU, anLwhose leg ends atwidth − 2·web, and a second upstand from there towidth − web. A rectangle and an upstand run fromz = −depthto 0. - Its facing, where the section has one, is a rectangle outside it: from
x = x_out − facing.thicknesstox_out, wherex_outis the leastxof the section's rectangles, and fromz = −facing.depth, else−depth, to 0. - Its anchor. The section's
z = 0lies atz_a + verticalOffset(0 without it).z_ais the host's top,elev(host.levelId) + host.offset, forslabTop; forstructureBottomit 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 whosefunctionisstructure, or less the host'sheightwhere its type has no such layer. - Where it lies. The section's
xlies at the reachr(x) = horizontalOffset + xin from the edge's line (horizontalOffset0 without it), orhorizontalOffset − xwhere the element isflipped. At the edge's start that is the pointa + r n_in + k_a r u, and at its endb + r n_in + k_b r u, wherek_aandk_bare 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 twoxat the two ends, between the heights of its twoz: one body each, along the whole edge. - Its ends. An end is mitred where
miterEndsistrue, square where it isfalse, 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. Withn_cthat edge's unit normal into the outline, a mitred end's slide isk = (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 leastxof its section and facing or at its greatest: whereL + (k_b − k_a) r(x) ≤ 1for either,kbeing 0 at an end that is square by the rules before. - A chamfer cuts the upstand's top inner corner (an
L's, or aU's first upstand's): that upstand is instead the polygon(−web, −depth),(0, −depth),(0, −chamfer.height),(−chamfer.width, 0)and, wherechamfer.width < web,(−web, 0), whose points lie at its two ends as rule 5 places them: a convex body between the two end polygons. - These are the element's bodies, and its volume theirs. Its
notchesare rules 12 to 14's, proposed for 0.2.
What it does to its host, rules of the host's own body (4.2, rules 6 and 7):
- Thickened edges. A slab or a foundation is thickened under each edge of its outline that carries a slab edge element whose type's
edgeProfilehas abeam; two on one edge thicken it by the wider and the deeper. Its structure is its type's first layer whosefunctionisstructure, or, without layers, its one body; a slab whose type has layers and none of them structure is not thickened. Letz1be its top,sits structure's underside,tits structure layer'sinset(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 unders, from the highest, close bands, the first fromsdown 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 wherez1 − depth ≤ λ + 0.5and its width is more thant. With its edge moved in by its width and every other edge byt, the four-sided strip between its edge moved in bytand 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 owninset, and the others by itsinset. - 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
voidscut through the layers (4.2, rule 4).
- Each beam's depth gives a level
- 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. - 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'svoidsMUST 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 (proposed for 0.2):
Proposed for 0.2, with the proposal adopted (Part II, 14), and informative in 0.1: these rules add no rule to 0.1, where a slab edge element's notches is a member a schema does not know (Part I, 10). A compiler cuts notches, and a validator checks them, only when it is asked for the proposal.
- 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:fromandtoin mm along its host's edge from the edge's first pointa, anddepthin mm down from the section's top,z = 0. Only anLor aUhas an outside upstand, its section's first rectangle (rule 2): an element whose section is arectangle, or whose type is a framing family, MUST NOT carry notches. A notch MUST run fromfromto at leastfrom + 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 carriesnotches(Part II, 6.3). - 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
Lalong the edge, is that end, square or mitred by rule 6; an end within the edge is cut square, atsalong it, its pointsa + s·u + r(x)·n_in. The outside upstand is a body for each stretch, fromz = −depthup 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. - 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).
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:
- 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 aroof), 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). - Its height. At each end of each piece of the gutter (rule 6), its section's
z = 0lies on the roof's top surface at that point of the eave line; between the two ends, the piece runs straight. - Its section, in
xout from the eave line, square to it in plan, andzup: ahalfRoundis the half annulus about(r, 0),r = diameter/2, between the radiirandr + thickness, underz = 0: its back lip on the eave line and its rim level with the roof's top. Aboxis its bottom, fromx = 0towidthand fromz = −depth − thicknessto−depth, and its two walls, fromx = 0tothicknessand fromwidth − thicknesstowidth, fromz = −depthto 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). - Its offsets. Its type's
gutterProfile.horizontalOffsetand its ownhorizontalOffsetadd, and move its section out from the eave line; where it isflipped, they move it the other way, in towards the roof. Its type'sgutterProfile.verticalOffsetand its ownverticalOffsetadd, and raise it. - 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.
- Where it is buried. Where its roof's
roof.joinGroupnames 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. - 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.
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}:
- The host MUST be a foundation or a slab whose footprint contains the column's centre (on the boundary counts).
- The host's face is its top (
face: "top") or its underside,T_hostbelow its top. For a flat host the face is the planeelev(host.levelId) + host.offset − depth. - The derived base is the lowest face plane at the column's centre plus
offset(a negative offset embeds the column below the face). - 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}:
- The host MUST be a roof, ceiling, slab or foundation, and its footprint MUST cover the wall's whole centreline in plan.
- 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. - 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 bydepth · √(1 + g_x² + g_y²)and raised byoffset. 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.mode: "level": the top is flat, at the lowest point of the face over the wall's core band.- 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.
- The wall's
heightandwallOutlinestay 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.
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):
- Without a
section, the body is the square prism of sidewidthcentred onc, over[z0, z0 + H]. - With a
section, the section'swidthruns along x and itsdepthalong y, centred onc, swept over[z0, z0 + H]. - Either is then turned by
turndegrees counter-clockwise in plan aboutc. - 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):
- 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 isLs = √(L² + r²); letsin α = r / Ls,cos α = L / Ls. - Without a
section, the body is the prism over[z0, z0 + height]of the rectangle of widthwidthcentred on the plan axis. A beam with neither asectionnor aframingfamily MUST NOT have a non-zeroendRise. - With a
sectionof widthwand depthd, the section stands at right angles to the set-out line: the point at distancesalong the line (0 ≤s≤Ls),xacross it (−w/2 ≤x≤w/2) andvup from the underside (0 ≤v≤d) is at plan positionP0 + u (L s / Ls) + n x − u v sin αand elevationz0 + r s / Ls + v cos α. The element's ownwidthandheightdo not size it. - With a
taper(rectangular sections only), the depth varies linearly fromdat the start totaper.endDepthat the end; the underside follows the set-out line. Arectangle'sradiusdoes not round a tapered beam: its body is the wedge with square corners. - With a
roll, the body is turnedrolldegrees 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'sx(across, alongn) towards itsv(up), as the reference implementation and@openeik/toolsturn it. - A beam whose type has a
framingfamily takes its body from the family (Part II, 5.4), withLength = Ls. Section 6.6, proposed for 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?}.
atis"start"or"end"of this member; a column's start is its base.kind: "butt": this member's end stops at the face ofto, held back bygap(mm). Withextend: falsethe end is only cut, never lengthened to the face.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.toMUST be a beam or column, andextend: falseMUST NOT be used.- 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.
- Join ids MUST be unique on a member; a member MUST NOT be joined to itself;
toMUST exist. - 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.
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,
widthbydepth. 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.
- A column: the reference line runs from
(c, z0)to(c, z0 + H), wherecis the centre (the profile's first point),z0the base (or the attached base, 5.2) andHthe length. - A beam with a section of depth
d: the reference line runs through the middle of the section,d/2above the set-out line measured square to the member, along the member's true lengthLs = √(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αandras in 6.2. Across the member it lies on the plan axis. - 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.endDepthat the end. - A beam without a section: the reference line runs
height / 2above the underside, from(P0, z0 + height/2)to(P1, z0 + height/2)(such a beam has noendRise). - 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, withxacross the member (alongn) andvup from the underside, as in 6.2;(e_x, e_y)for a column, along its section'sxandybefore itsturn. The offset turns with the body, by a beam'srollabout its reference line or by a column'sturnin 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 byn e_x' − u e_v' sin αin plan and bye_v' cos αup; for a column, by(e_x', e_y')in plan. - A
rectangle(with aradiusor without),I,RHS,CHSorroundsection, 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. ATor2Lsection has a centroid offset of zero across and not zero inv(inyfor a column), set by its sizes, its radii and, for a2L, itsgap(Part II, 5.2). AnLorUsection, and asheetsection in general, have a centroid offset that is not zero, set by the section's legs or flanges, its corner and its radii. Acustomsection'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, proposed for 0.2, places and builds the parts as class-A rules, and section 6.5.1 gives the beam its reference line, with the same proposal.
Reference: beamMiddleLine in src/core/geometry/familyGeometry.ts computes rule 2; memberStructuralAxis in src/core/geometry/memberStructuralAxis.ts, with sectionProperties.ts, computes rule 5.
6.5.1 A framing family's beam (proposed for 0.2)
Proposed for 0.2, and informative in 0.1: it adds no rule to 0.1, and no file of 0.1 is held to it. A compiler gives such a beam its reference line only when it is asked for the proposal framing, which builds its parts by section 6.6; without it, a beam built from a framing family has neither line, as section 6.5 says. The proposal adds no file and no member. This section 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).
- 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), wherez0andrare section 6.2's andheightis the element's, so that it rises by the beam'sendRiseas 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. - 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
memberparts 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). - 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).
6.6 A framing family's parts (proposed for 0.2)
Proposed for 0.2, and informative in 0.1: it adds no rule to 0.1, and no file of 0.1 is held to it. A compiler derives these bodies only when it is asked for the proposal framing; without it, 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 proposal 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.
- 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 asked for the proposal reports it as an error, which it can tell from the records alone:
framing-expressionwhere an expression is invalid or a parameter breaks Part II, 5.4's rules, andframing-partwhere itsLengthis out of its range, two of its parts share an id, or a part cannot be built. - The scope.
Lengthis 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 offtakes the element'sframingParameters[name]where its scope isinstanceand the element gives it, and itsvalueotherwise;fkeeps 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. - Which parts exist. A part whose
whenis 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). - A part's outline. A
memberpart runs from its pointato its pointb, at least 1 mm apart, and itsdepthd lies from 1 to 10 000 mm. Witht = (b − a)/|b − a|its axis andm = (−t_z, t_x), its outline is the rectanglea − (d/2)m,b − (d/2)m,b + (d/2)m,a + (d/2)m, so that its line fromatobruns through the middle of its depth, and its centre is the middle ofaandb. Aprofilepart's outline is itsoutline'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'swidthlies from 1 to 10 000 mm on a beam, and from 1 to 100 000 mm on a slab edge element. - 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. - Its joints. Each part a part's
cutBynames is another part off. 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 partscutBynames are taken out in its order, each from every piece the ones before it left. - A tail. A family's
tailcuts eachmemberpart whoseroleistopChordand whose axis rises,t_zmore than 10⁻⁹ (its left tail), or falls,t_zless than −10⁻⁹ (its right tail); a level top chord has none.fthen has the parametersPitch,HeelHeight,OverhangLeftandOverhangRight. Withothat side's overhang,OverhangLeftorOverhangRight, andTipTop = HeelHeight − o·tan(Pitch), a tail's expressions are evaluated in the scope of rule 2 withOverhang = oandTipTopadded (Part II, 5.4). A point(u, v)whoseoriginistiplies at(−o + u, TipTop + v), and one whoseoriginisbearingat(u, v); on the right tail itsxis mirrored toLength − x. Alinecut'soriginistipwhere it gives none, and anotch'sbearing. Alinecut is one more straight cut of the part (rule 5). Anotch, 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. - Its pieces. A polygon is cleaned by dropping each point within 0.5 mm of the next, and then each point
bwhose neighboursaandcleave|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). - Nail plates. A
platepart that exists has athicknessfrom 0.5 to 20 mm and an outline that, cleaned, has three points or more and is convex; each part itsonnames is amemberpart off. 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 fromw/2tow/2 + thicknesson either side,wthe member's width. Its pieces are simple (rule 4). - On a beam. The plane is Part II, 5.4's, over the beam's set-out line: with
P0,u,z0and α as section 6.2 has them, andn = (−u_y, u_x), the point(x, z)of the plane atyacross it lies at plan positionP0 + u (x cos α − z sin α) + n y, and at elevationz0 + z cos α + x sin α. A part's piece lies fromy = −w/2tow/2,wits width; a plate's as rule 9 says. - On a slab edge element. The plane is the element's section along its host's edge:
xacross the edge into the host, where section 4.6, rule 5 places a section'sx(by itshorizontalOffset, itsflippedand its mitred ends), andzup from its anchor,z_a + verticalOffset, wherez_ais as section 4.6, rule 4 gives it forf'sedgeAnchor, andslabTopwherefgives none; its type'sedgeProfileis not used. Its ends are mitred only where itsmiterEndsistrue(section 4.6, rule 6), and stay square where that rule keeps them square, the least and the greatestxof its section being those of its parts' pieces. A part's piece runs along the edge forr = min(w, L),wits width andLthe edge's length, centred on the edge's middle: each of its points lies at the stationsL/2 − r/2andL/2 + r/2along 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 noplatepart that exists. - 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
rwhere its ends are square, and less or more where a mitre slants them. - Members. Where a
memberpart 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, asT1 · top chord topL, aprofilepart by its id alone, asT1 · seat, and a plate asT1 · nail plate p1; and with its section, its width by its depth, each to a tenth of a millimetre, as45 × 220, where amemberpart's depth is its own and another part's its pieces' height in the plane. Otherwise its parts, allprofileparts, are the element's own body. - 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,profileandplateparts, withwhen,cuts,cutByandon; itstail, with both kinds of cut and both origins; and itsedgeAnchor. ItstrussStylenames what kind of family it is, and itspreviewLengthis 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. - 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. The steward decided on 29 October 2026 that it becomes rules too (open questions, 83); it is proposed apart from this section, in section 7.4 (the proposal
framingLayout), whose trusses are 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 itsconnection, its ownholesor the holes of a bolt group through it: the compiler builds its parts without them, and says so (not-derived). Itsrolland itstaperturn 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).
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 (proposed for 0.2)
Proposed for 0.2, and informative in 0.1: it adds no rule to 0.1, and no file of 0.1 is held to it. A compiler builds a member only when it is asked for the proposal member; without it, a member is of a category 0.1 does not have, and a compiler derives it no body (section 1, rule 4). The proposal 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:
- Its line.
A = (P0, z0)andB = (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 isLs = |B − A|, andt = (B − A) / Lsits direction. No underside sets it out: its reference line is the line its record gives. - Its frame, the section's
xandvbefore a roll. Where the member is not plumb,x = (−u_y, u_x, 0), the left normal of its plan directionu = (P1 − P0) / |P1 − P0|, as a beam'sn(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. Sox,vandtturn as the model's x, y and z do: for a member that is not plumb,vis 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,xandvare the model's x and y, as a column's section'swidthanddepthbefore its turn (6.1, rule 2), and for one that runs down,vis the model's −y. - Its roll. With a
rollρ, in degrees, the section turns about the line, right-handed aboutt, as a beam's does (6.2, rule 5):x' = x cos ρ + v sin ρandv' = −x sin ρ + v cos ρ. Without one,x' = xandv' = v. - Its body. The point
(x, y)of the section,xacross andyup from the middle of its bounding box, lies atA + s t + x x' + y v'forsfrom 0 toLs: the section stands square to the line, the middle of its bounding box on it (6.5), itswidthalongx'and itsdepthalongv'. Acustomsection'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 rectanglewidthacross byheightdeep (Part II, 6.2.1, rule 5). - A taper, on a rectangular section only, as a beam's (6.2, rule 4): the depth runs linearly from the section's
depthd atAtotaper.endDepthe atB, centred on the line: atsalong it,yruns from−d(s)/2tod(s)/2, whered(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). - 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 ownxandv. Section 6.5, rule 6 says which sections have none; a tapered member, as a tapered beam, has none. - Its joins are a beam's (6.4):
atnames its start,A, or its end,B; they are found on reference lines; and a mitre joins two members of the categoriesbeam,columnandmember, any two of them. - 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 alongLs, a tapered one's mean area, its joined ends on their cuts. - 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, itsturnits roll: plumb and running up, its frame is the column's before its turn (rule 2), and a roll turns it asturndoes, 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 itsroll: 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).
7. Reference behaviour (informative)
7.1 Wall joins
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.
7.2 Others
Room boundaries (but for those of section 7.5, proposed for 0.2), stair runs and landings (but for those of section 7.3, proposed for 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), components (but for a component's frame and the bodies of section 7.6, proposed for 0.2), a slab edge element's notches (but for section 4.6, rules 12 to 14, proposed for 0.2) and a framing family's section (but for section 6.6, proposed for 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, proposed for 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 in 0.1. Their results enter the model only when a command materialises them as records.
7.3 Straight, L and U stairs (proposed for 0.2)
Proposed for 0.2, and informative in 0.1: it adds no rule to 0.1, and no file of 0.1 is held to it. A compiler lays a stair out and builds a concrete stair's bodies only when it is asked for the proposal stairs; without it, stair runs and landings are reference behaviour, as section 7.2 says. The proposal 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.
- Its numbers. Its rise is its top less its base, and MUST be more than 0. It has
s.risersrisers, else the fewestf.maxRiserallows, ⌈rise /f.maxRiser− 10⁻⁹⌉, and at least 2; each riser R = rise / risers high; its going g iss.going, elsef.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 asked for the proposal SHOULD warn of such a stair, which it can tell from the records alone. - 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.locationLineisleft(the line is its left edge, looking up), 0 where it isright(its right edge), and −W/2 otherwise. - 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.
- A straight stair (
s.shapestraight) is one flight: from its frame's origin alongu, from y0 to y0 + W, on its base, with risers − 1 treads; its last riser rises to its top, the floor above. - An L or a U stair with a landing (
LorU, withouts.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 iss.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.turngives,leftwhere it gives none: alongn, its first riser's foot at (L1 + D − W, y0 + W), or, to theright, 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.gapfrom it, 100 mm where it gives none: with yb = y0 + W + gap to theleftand y0 − W − gap to theright, it runs along −ufrom (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.
- 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
- A cast concrete stair (
f.constructionconcreteCast) 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.waistbelow 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 lessf.landingThickness, for a flight on a landing. The body is that outline carried across the flight's width. Each body names its partflightand its pieceflight:<k>, k from 0. - Each landing: its outline, from its top less
f.landingThicknessup to its top; its partlanding, its piecelanding:<k>. - A flight and its landing meet on the plane of the flight's last riser, and do not overlap.
- 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
- 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
nosinggives 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).
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 (proposed for 0.2)
Proposed for 0.2, and informative in 0.1: it adds no rule to 0.1, and no file of 0.1 is held to it. A compiler lays a framed wall layer, a roof's truss layout and a floor's joists out only when it is asked for the proposal framingLayout; without it, timber framing members and trusses are reference behaviour, as section 7.2 says. The proposal 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
- A framed layer is a layer of a wall's type that carries
framing. With the proposal, 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. - Its rule, with its defaults. A rule is read with these values for what it leaves out:
materialC24,directionvertical,startleft,restartAtOpeningsfalse,restartFromking,restartMinWidth0,bottomPlatesandtopPlatesnone,plateOverhangAtEnds0,top.modeauto,rakingTopPlatetrue,roughOpeningGap0,bottomPlateAtOpeningswith doorscut, windowskeepandclearance0; for each tierheaderPlies,kingStudsandjackStuds1,cripplesAboveandcripplesBelowtrue andstudsAtKingsfalse; no noggings where it gives nonoggings, and thererows0 andstaggeredfalse;junctions.Lbutt,junctions.Tbacker,junctions.endsingle andjunctions.endFlatfalse;moveBlockedStudsfalse,minGapandmiddleBay0,studsAtPostsfalse, andbattensservice. A plate is a rule'sbottomPlatesortopPlatesentry, the first two of each. A rule without a member'swidth, aspacingor a structural tier is not read: its layer is not laid out (framing-layout-rule). - 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 arelyOnthat names another framed layer of its type; and to be on a wall type's layer of some thickness. A validator asked for the proposal 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. - 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 itsoffset; 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 atP0 + u x + n (T/2 − y), T the wall's thickness (section 4.1). - 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 itsdepth, 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. - 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).
- 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: the core compiler of 0.1 ends a wall square.
- 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
joinEndssaysfalsefor it. A wall's thickness T is its type's layers' together, or itswidthwhere its type has none. - 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.
- 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
wallOutlinewhere 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'sheight, whichever is lower. - 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.
- 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.
- 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.
- 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.
- 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
- 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). - 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 itsmodeislevel, 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: itstop.cutRoofId, else, where its type'swallAttach.cutToAttachedRoofis true, the roof it is attached to; the face itstop.cutRoofFacenames (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 itstop.extendExteriorLayersis true, or where it gives none, the wall has a cut roof, and its type'swallAttach.extendExteriorLayersis 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). - 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.
- 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.
- 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
framingCornersnames it: the wall's ownthroughorbuttat that end where it differs from its partner's at its end, else its partner's,buttthere 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). - 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.
- 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.
- 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 itsheight. 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 carriesframing, else its first core layer) meets that face. A T of any other layer is not the layer's.
7.4.4 Its top
- Its mode is its wall's
framingTop.mode, else its rule'stop.mode.autoisrakingwhere its top has a segment steeper than 1 in 10 along the wall; elseunderFloorwhere a floor bears on it (rule 4); elselevelPlate. - A level plate: its top plates' top is its wall's
framingTop.wallLiveHeight, else its rule'stop.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². - 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. - The bearing floor is the slab its wall's
framingTop.floorIdnames, which MUST be a slab (elseframing-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 storedprofile) 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 modeauto), 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 isauto, 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. - Raking: its top plates follow its top.
- 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
- 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 fromalong− g toalong+width+ g and fromoffset− g (0 where itsoffsetis 0) tooffset+height+ g, g the rule'sroughOpeningGap. A pocket door (a door whose type'sopeningFamilyis of the kinddoorwith the operationpocket, Part II, 6.5) reaches over its pocket: its rough opening runs on by itswidth+ 150 towards its wall's first point where its family'shingeis notrightand itshandFlippedis not true, or both are so, else towards its last point. An opening with anoffsetabove 0 may have a sill and cripples under it (7.4.7, rules 4 and 5); one at 0 has none. - Its tier is of the rule's
openings.nonStructuralwhere the wall'sstructuralis false and the rule gives them, else of itsstructural: the first whosemaxWidthis at least its rough width; else the last, which is said. - 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. - Element joints. Each of its wall's
framingJointsthat 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. - 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 (itswidth) 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 byplateOverhangAtEnds, and is cut at each joint; a top plate is not laid on a sloped segment whererakingTopPlateis false, and is cut to above the frame's foot. A plate whosesideisexteriorlies against the layer's face y0, one whose side isinterioragainst 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 orj<i>, i the joint's number from 0:0,1@D1,0@j0. - Bottom plates cut at openings. Where the bottom plates have a width, an opening's own
bottomPlate(cutorkeep), else its rule'sbottomPlateAtOpeningsfor its category (doors, windows), says whether they are cut under it. They are cut only where the opening'soffsetlies under the bottom plates' top (else, where its ownbottomPlateasks for a cut, that is said); from itsalong− g − c to itsalong+width+ g + c, c theclearance, 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. - 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
rakingTopPlateis 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
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>, ee<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'sframingStart, else its rule'sstart, and the wall'sframingOffset(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, prefixr;centre: a place at the middle (c0), and from it towards both ends, prefixescandcl;bothEnds: from the second end to the middle (r), then from the first towards the middle, or, with amiddleBay, 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
restartAtOpeningsis true, the start isleftorright, and a place falls in an opening's zone whose rough width is at leastrestartMinWidth, the grid sets its places a spacing apart from there across the zone, and walks on from the far king's middle (restartFromking) or the opening's far side (opening).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). WithstudsAtPosts, the grid sets a place against each side of each post (p-<post>-a,p-<post>-b).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.End studs (
endStud) stand full height at each end of the frame and on each side of each joint, flush:end0at the first end,joint<i>aandjoint<i>bat the i-th joint,end1at the second. Wherejunctions.endisdouble, each has a second inwards beside it, keyed with abafter its key.A corner's flat stud. Where
junctions.Liswrapand the layer runs through at a corner (7.4.3, rule 5), a stud laid flat (cornerStud,corner0at the first end,corner1at 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 acornerStudWidth, 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. Wherejunctions.endFlatis 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).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⁻⁶.
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
framingTeessays at its end, else asjunctions.Tsays, elsebacker:backer, a stud (endStud) on each of the ending wall's face lines,tee-<wall>-aand-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,teeFlatWidthwide, 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.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; withmoveBlockedStuds, 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 aminGap, 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 astud, its key its place's, full height.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):
- Jacks (
jack):jackStudson 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. - Kings (
king):kingStudson 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. - 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'swidth, 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. - A sill (
sill): under a rough opening that has anoffsetabove 0 and whose bottom plates are not cut, where its tier has asilland the rough opening's bottom lies at least the sill'swidthabove the frame's foot at its sides, from there down by the sill's width, over the rough opening;<opening>. - 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, wherecripplesAboveis 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), wherecripplesBelowis true, the opening has anoffsetabove 0, its bottom plates are not cut, and that is more than 1 mm (<opening>:b:<key>). WithstudsAtKings, 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 aminGap, a cripple of the grid less than the minimum gap clear of one against a king or a post is left out. - Where two openings' zones overlap, their members overlap, which is said.
7.4.8 Noggings and battens
- Battens. A rule whose
directionishorizontallays battens, of itsbattens:service(the default,serviceBatten),nailing(nailingBatten) orcounter(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,.0and.1after 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. - 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. - Noggings (
nogging), where the rule'snoggingsgives aspacingorrows: 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: everyspacingfrom its foot while they fit, orrowsrows evenly, each centred at its foot plus the bay's height times r / (rows + 1); in every second bay a nogging's height higher wherestaggeredis true, where it still fits;<bay>:<row>, bays and rows counted from 0. - 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
- 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'smaterial. - 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
- 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).
- 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.
- 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
- 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 whosehips.frameis false, frames no hip end, and says its hip ends. - Materialised members (
framing-layout-materialised). A wall whose members are materialised as elements, which name it in theirframeHost.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 theirframeHost.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. - What a later rule may read. A rule's
relyOn, which names the layer whose studs its battens follow, is not read.
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.
A truss layout, its rule and its family. A roof with a
roofpayload, no barrel vault, and atrussLayoutis laid out. Its rule is read with these values for what it leaves out:layoutRulefixedDistance,spacing1200,count2,justificationbeginning,bearingReferencecoreFace,endsinsideGables,endOffset0,openingFramingwithtrimmerPliesandheaderPlies2,hipsas section 7.4.16, rule 1 reads it, and aridgeBeam'stopOffset0 and noposts. Its family is theframingof the type itsfamilyTypeIdnames, which MUST be a beam type, and is a truss family: one that declares the parametersPitch,HeelHeight,OverhangLeftandOverhangRightof the scopeinstance. The family's parameters' values (value) give w, itsWidth(45 where it has none), and itsChordDepth(170),BottomDepth(0),RidgeGap(0),BottomPitch(0) andNotch(0); a family with aFurringMinis 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 asked for the proposal 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).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.edgesgives 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).Its bearings. Where
bearingWallIdsgives 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.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 wholewidth, 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. WithbearingReferencefinishFace 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 nomemberpart of the rolebottomChordbears 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.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). WithendsinsideGables 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 plusendOffset+ w/2, the last its end lessendOffset+ w/2; a last more than 10⁻⁶ before the first is a finding. WithlayoutRulepositions, each ofpositions, sorted byat, is a truss at the range's start plus itsat, of the mark itsmarkgives; 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; elsemaximumSpacing: n = max(1, ⌈t / c − 10⁻⁹⌉), and n + 1 places evenly from the first to the last;fixedNumber:countplaces 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 thebeginning, 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 theend, 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 thecenter, 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.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.
Its heel and its parameters. The chords' top is the face of the roof's chord layer: the layer of its type that
chordLayernames, which MUST be one, else the first layer as thick asChordDepthwithin 0.5 where the family is no furring family, else none;chordLayerunderside 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 isheelHeight, 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 lessBottomDepththat is more than 0.5 under itsFurringMin. It gives its family the parametersPitch, the left eave's edge's slope;HeelHeight, its heel; andOverhangLeftandOverhangRight,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.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
memberpart of the roletopChordis 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 (cosPitch, sinPitch), mirrored on the right, what lies down the slope of the line square to it through A(from) is kept, where the band givesfrom, and what lies up the slope of the line through A(to), where it givesto, 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.
Lengthis 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).- a one-sided truss keeps only the top chords of its side: a
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.
Its roof openings. A roof opening (
roof.windows) lies on the face of its edgeedgeId: on an eave face, else it is not framed, which is said. Its outline is the rectanglewidthacross the slope andlengthalong it, its plan lengthlength/√(1 + tan² σ), σ its edge's slope, about itscenter, 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'strussStyleis rafters; in any other, they are said. For each opening, in order:- its trimmers,
trimmerPliesk 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, itsfromonly 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 cosPitch, 0 where it has none; - its header:
headerPliesplies of w byChordDepth, else one ply of the section its opening'sheadergives,{width, depth}, or none where it givesnone. 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 sinPitch(τ_R − d − k sinPitchon the right) on its line, at E + heel + tan(Pitch)·d − k cosPitch, each to 0.001; keyed<roof>:opening:<opening>:header:ridgeand…: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,dormerRafterDepthdeep (elseChordDepth) 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>.
- its trimmers,
A ridge beam. A layout whose family's
trussStyleis rafters lays itsridgeBeam; another says it does not. Its width is itswidth, elseRidgeGap, and one less than 45 is said, and none laid; a width more than 1 mm fromRidgeGapis said. At a place along the ridge, its top is E + heel + tan(Pitch)·((τ_R − τ_L)/2 − width/2) lesstopOffset, its underside itsdepthlower, 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 carriesframing, 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 ofposts, 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.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 nofrom(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.Each member: its name, its section and its class. A truss is keyed
<roof>:truss:<key>and namedTrussand its mark, asTruss 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, asTruss T1 · top chord topL(aprofilepart 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, namedheader,rafter,ridge beamandridge postand their key after its first:, asheader opening:W1:header:ridgeandridge 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, as45 × 220.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.
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 fromtruss:<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, keyedframing:<member id>and typed by class, predefined type and section, its materialTimberand 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 fromfastener:<key>, its nameTruss clip pair, its object typeTRUSSCLIPand its predefined type USERDEFINED, with no body: the rules give its place, not its shape. An IfcRelConnectsWithRealizingElements of the typeTRUSS_TO_PLATE, keyedconnects:<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.
- 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 postandTruss 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 aprofilepart 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.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.
- 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'sBottomDepthover 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. - Studs under trusses. Where the rule's
alignToTrussesis 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, keyedt-<truss id>. - 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. - 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.
- 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).
- 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. - A rafter's notch. A wall attached
levelto a layer of a roof (top.attach.facenames a layer) that has a truss layout reads the face raised by its family'sNotch, at least 0, as well as by itsoffset: 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.
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.
- A joist layer and its rule. A slab whose type is a slab type with a layer that carries
joistsis laid out, by its first such layer. Its rule is read with these values for what it leaves out:materialC24,spacing600,directionauto,rim45 wide (null: none),trimmerPliesandheaderPlies2, andblockingwithendBaystrue andspacing600. A rule without a member'swidthis not read (framing-layout-joists). A joist is w, the member'swidth, wide, and d, itsdepthelse the layer's thickness and at most that, deep; the layer's top lies under the slab's top, its level's elevation plus itsoffset, by the layers before it, and its underside d under that: z0 and z1, each to 0.001. A validator asked for the proposal 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). - The posts through it. A column whose base and top (its level's elevation plus its
offset, and that plus itsheight) 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 itswidthabout 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 (itsprofile). Columns are taken in the order of their ids, then the ridge posts, the roofs in the order of their ids. - 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.
- The joists' direction. With
directionauto, 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. - 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 keyedh<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. - 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. - 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. - 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), elsetrimmerPliestrimmers (trimmer), (k + ½)·w inward of it, keyede<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,headerPliesheaders w wide, the first against the edge, inward, keyed<edge>.<k>. Whereblocking.endBaysis 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. - 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. - 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'smaterial. 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 |
- 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.
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.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).
Its hip ends and its rule. A layout of two sides frames its hip ends; one whose
hips.frameis false frames none, and says them (7.4.13, rule 2). Itshipsis read with these values for what it leaves out:systemauto,girderPlies2,hipPlies2,minJack400, andjackSpacingthe layout'sspacing. 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.Its families. The jack family is the
framingof the model's type whose id is the layout's family type's id followed by-jack, where the model has one with aframing, and the flat-top family that of the type whose id is followed by-flat: the layout uses such a type, and a validator asked for the proposal 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 declareFlatLengthof the scopeinstanceas well; a validator asked for the proposal 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 whosetrussStyleisraftersorcollar.- Its parameters are f's but
Pitch,HeelHeight,OverhangLeftandOverhangRight, in their order; then, where f has none of the name,Width(45, from 20 to 200) andChordDepth(170, from 45 to 600), and, but in the jack family of a rafter family,BottomDepth(170, from 45 to 500) andWebDepth(95, from 45 to 300), each of the scopetype; thenPitch(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 scopeinstance; each with itsvalueand then itsminandmax. - It has f's
tail. The jack family'strussStyleisrafterswhere f is a rafter family, elsemono; the flat-top family has none. - Its parts are the
memberparts of the tables below, eachWidthwide, 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 expressionBottomDepth/2, C(x) forHeelHeight-ChordDepth/(2*cos(Pitch))+tan(Pitch)*(x), D(x) forHeelHeight-ChordDepth/(2*cos(Pitch))+tan(Pitch)*(Length-(x)), K(x) forHeelHeight-ChordDepth/cos(Pitch)+tan(Pitch)*(x)-BottomDepth, X1 for(Length-FlatLength)/2, X2 for(Length+FlatLength)/2, F forHeelHeight+tan(Pitch)*(Length-FlatLength)/2-ChordDepth/2and W forFlatLength-WebDepth-20, each written out with the text of x, X1 or X2 in its place: C(Length/2) isHeelHeight-ChordDepth/(2*cos(Pitch))+tan(Pitch)*(Length/2), X1/2is(Length-FlatLength)/2/2, and K(0)-45is K(0) followed by-45.
The jack family of a rafter family has the part
topalone, with nocutBy; any other jack family has these nine:- Its parameters are f's but
| 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 |
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
trussStyleis neitherraftersnorcollar, and itships.systemisridgeGirder, orautoand 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 togirderPlies·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 plusendOffset+ w/2, and the last its end less w/2, or lessendOffset+ 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:girderPliestrusses 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).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 aframeHostand 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'swidth) 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 itsbearingReference, 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.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 leastminJack. The half width κ kept clear of the ridge line isgirderPlies·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 tohipPlies− 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 markH<2j+1>on the left andH<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.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
minJackis not laid. Each other takes the markJ<i>, i counting the layout's jacks from 1 in the order they are taken, and is a truss of rule 7. With J thejackSpacing, 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 ander<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>andsr<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.
- its centre jack (rule 5), from P(a_τ, R) along s·along, keyed
A hip truss or a jack as a truss. Its parameters are its
PitchandHeelHeight, itsOverhangLeft, 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), andOverhangRight0; each to 0.001. Its parts are the jack family's, built by section 6.6, rules 2 to 9, with its length L asLength; 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.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 familyPitch, its pitch;HeelHeight, z(P(τ_g, r_0)) − E;OverhangLeft, how far its line runs on before r_0 inside the domain, andOverhangRight, after r_1 (rule 7); andFlatLength, the lesser of its flat top and ℓ; each to 0.001. Where the family cannot be built with ℓ asLength, the girder is said, and neither it nor its half trusses are laid. Else itsgirderPliesplies, the k-th from 0 on the line at τ_g + (k − (girderPlies− 1)/2)·w from r_0 to r_1, each keyedridge:<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) alongacross, τ_g −girderPlies·w/2 − τ_L(r) long, keyedridge:jack:l<k>, and from P(τ_R(r), r) along −across, τ_R(r) − τ_g −girderPlies·w/2 long, keyedridge:jack:r<k>, each bearing on its side's bearing that stands at r.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>:hangerand namedHanger, hip truss to girderfor a hip truss,Hanger, jack to girderfor a centre jack and a half truss, andHanger, jackfor 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.Names, members and IFC. A hip truss is named
Hip trussand its mark, and(ply <k + 1>)after it for a ply after the first; a jackJack trussand its mark; a girder's plyTrussand its mark with(girder),(girder, ply <k + 1>)after the first, and a girder along the ridge's withalong the ridgeaftergirder: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 fromfastener:<key>, its name its name, its object typeHANGERand 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.
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 (proposed for 0.2)
Proposed for 0.2, and informative in 0.1: it adds no rule to 0.1, and no file of 0.1 is held to it. A compiler finds a room's boundary, ceiling and quantities only when it is asked for the proposal rooms; without it, room boundaries are reference behaviour, as section 7.2 says. The proposal 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.
What bounds rooms. On a room's level, each wall and each column whose
statusis notdemolished, and whoseroomBoundingistrue, or which gives none and is no wall whoseoffsetis 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 awallOutlineruns 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 itsturn. 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 itsheight). 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 theirvoids; a demolished one, and a round footing, is no floor.- 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 (
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).
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 asked for the proposal SHOULD warn of it (
rooms-enclosed).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 asked for the proposal 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.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.heightis 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
voidsdoes, 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 aroofwhose 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
heightover 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
statusisdemolishedis none. A thickness is its type's layers' total, else the element'sheight(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.- where its
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'srooms.doorsFromSkirtingisfalse, 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:GrossWallArealess, for each door and each window in its walls whose area is at least the project'srooms.openingMinArea(m²; 0 where it gives none), that area times its width along them over itswidth, 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 itsoffset,heighthigh) begins under the ceiling's highest point over the room and ends over its floor, and its span along its host, fromalongtoalong + 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'soutline's, else itswidthtimes itsheight.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:NetVolumeoverNetFloorArea, the room's mean height.
National area rules stay the application's (Part II, 8).
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.
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 (proposed for 0.2)
Proposed for 0.2, and informative in 0.1: it adds no rule to 0.1, and no file of 0.1 is held to it. A compiler derives these bodies, and a validator checks a component's frame, only when it is asked for the proposal components (Part II, 5); without it, 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 proposal 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.
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'sweld), a bolt group's (bolt, with the element'sboltsand its type'scomponent.bolt), and a cast-in item's block or bar (its type'sinsert.shape,blockorbar). 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 asked for the proposal SHOULD warn of it (component-frame).Its frame. Its origin is its insertion point, its profile's first point, at its level's elevation plus its
offset. Where it givesaxes, they are its frame, whatever its family: its x isaxes.xmade a unit vector, its y isaxes.ymade square to x and a unit vector, and its z is x × y, or y × x where it isflipped(Part II, 6.3);axeswhose x is zero, or whose y runs along x, give no frame. Withoutaxes, 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 isflipped, and its z is up; a profile whose two points are one gives no frame (Part II, 6.1, rule 8).A plate on a column. A plate whose
hostIdnames 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 ownoffset. Its axes are rule 2's, from its own profile or itsaxes. A column without a level, a centre or a height gives it no frame.Hung down and stood up. A component without
axeswhosecomponentInvertedistruehangs its box (rule 6) or its plate (rule 7) down from its origin, from w = −heightto w = 0, where it otherwise stands from w = 0 to w =height. A plate withoutaxeswhoseuprightistruestands 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 toheight/2, whatever itscomponentInvertedsays. Neither member changes a weld, a bolt group, a cast-in item or a component withaxes, anduprightchanges a component of no other family.A cast-in item's frame. A cast-in item, a component whose type has an
insert, placed byinsertAtstands in the wall itshostIdnames, 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 itsheight, and its base at its level's elevation plus itsoffset.- Its point lies
alongfrom P0 along u,upfrom the wall's base andacrossin from its exterior face: P0 + u·along + n·(T/2 − across), at the base plusup.alongis 0 where it gives none, L on the faceend;up0, H on the facetop; andacross0 on the faceexterior, T oninteriorand T/2 on the others. - Its ways. The way into the wall from its face, d, is −n from
exterior, n frominterior, down fromtop, up frombottom, u fromstartand −u fromend. Its length's way, x, is u onexterior,interior,topandbottom, and up onstartandend; where itsturnis 90, x is up onexteriorandinterior, and n on the others. Its third way is y = d × x. - Its body runs in along a = d·cos(tilt) + x·sin(tilt),
tiltin 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
countitems, 1 where it gives none, the k-th, from 0,k·spacingfurther along the wall, or up it where itsdirectionisup,spacing0 where it gives none.
Its
profile,levelIdandoffsetare its writer's copy, which a reader ignores whereinsertAtis given (open questions, 73). A cast-in item whosehostIdnames no wall whose profile is two distinct points has no frame, and one thatinsertAtdoes not place has no body.- Its point lies
A timber section is a box in its frame: u from −
width/2 towidth/2, v from −depth/2 todepth/2, and w from 0 toheight(rule 4), itswidthandheightthe element's and itsdepthits type'scomponent.depth.A plate, a weld, a bolt group, and a cast-in item's block and bar.
- A plate is its outline less its holes,
heightthick. Its outline is its ownplate.outline, points (u, v) in its frame, else its type'swidthby itscomponent.depth, centred on its origin; its holes are its type'scomponent.holesand its ownplate.holes, each a circle of itsdiametercentred at (x, y), or, where itslengthis more than its diameter, a slot that long overall alongangledegrees 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 itswidth(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'sdiameteralong 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 towidth/2 and v′ = −height/2 toheight/2, its type's, run in from δ = 0 to δ =insert.depth(rule 5); its bar, the round bar from δ = 0 toinsert.depthalong a, itsinsert.diameterround, else its type'swidth.
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.
- A plate is its outline less its holes,
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
throughnames, 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 familiestoiletandbasin, 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.
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. 0.1 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:
- 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.
- 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).
- 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.
- 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. - 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.
- 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).
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.
- The run. The edges
railing.edgesnames 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. - The walking side is the inside of a slab's outline, and the outside of a shaft's (the floor round an opening).
- The offset. Each edge's line is moved towards the walking side by its inset:
railing.insets[<edge id>], elserailing.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). - The base. The line stands on the host's top:
elev(levelId) + offsetof a slab, or the top of a shaft (section 5.1). - Given posts. With
railing.posts.at, a post stands at each listed distancesalong the line from its first point, measured in plan, and nowhere else. A post ispostWidthalong the line bypostDepthacross it (postbypostwithout 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 frombelowBasebelow it whenmountisside, to the underside of the top rail, which carries the railing to itsheightabove the base. - 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; withpostEndDistanceit stands the first and last posts that far from the ends, and it leaves out the end postsposts.omitnames. - 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):
- On a wall's top. Let
a,bbe the wall's baseline,Lits length,u = (b − a)/L,nits left normal andTits thickness (4.1), anddthe railing'sinset, elseT/2. A pointxalong the wall, from 0 toL, is ata + 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 onexwhere the top steps; else the wall's height over its base. The line runs from one end of the baseline to the other. - 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 reachr0tor1. The line runs at the reachr_out + dfrom the edge's line,dthe railing'sinset, 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. - Walking side (rule 2): a wall's interior, the right of its baseline; the slab's side of a slab edge element.
- 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.
- A compiler derives nothing for it beyond placing its declared bodies: its own declaration's, in the
worldframe, 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). - 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. - It cuts nothing, and no rule joins it to another element.
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:
- The points. Point
iof the run isP_i = (p_i, elev(levelId) + mep.z[i]): the heights are measured from the level, and the element'soffsetis not added. A run MUST carrymepwith 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. - A run MUST have two points or more, not all at one place; else it has no body.
- The outer size. Let
insbe the run's insulation thickness (Part II, 6.9): its ownmep.insulation.thickness, else its type'spipe.insulationorduct.insulation, 0 when it has none and 0 where its ownmep.insulationgivesnone; where a pipe or its type gives a deprecatedbti, itsthickness(Part II, 6.9, rule 4). The run's outer width isW = mep.size + 2 ins. A duct whose type'sduct.shapeisrectangularhas a rectangular sectionWwide andH = h + 2 inshigh, wherehismep.height, ormep.sizewithout it. Every other run, a pipe or a round duct, is round,Wacross; itsmep.heightis not used.WandHMUST be positive. - 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.
- Where
θ < 10⁻⁴(the run goes straight on) orθ > π − 10⁻³(it turns back),P_istays a corner. - Otherwise the corner becomes an arc of radius
r = W, the outer width, tangent to both pieces. The arc starts atA = P_i − t d0and ends atP_i + t d1, wheret = r tan(θ/2). - Where
tis 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 tor = 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. - The arc is sampled at
k + 1points,k = max(2, ⌈θ / (π/12)⌉): withn = unit(d1 − d0 (d0 · d1))and the centrec = A + r n, pointjisc − r cos φ_j n + r sin φ_j d0, whereφ_j = θ j / k, forj = 0 … k. - The rounded path is
P_0; then, for each inner point in order, its arc'sk + 1points, or the point itself; thenP_(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.
- The tangent at
q_0is the direction ofq_0 q_1, atq_(N−1)that ofq_(N−2) q_(N−1); at an inner point it isunit(unit(q_j − q_(j−1)) + unit(q_(j+1) − q_j)), or the direction ofq_j q_(j+1)where that sum vanishes. Each ring lies square to its tangent, with a side vectorssquare to the tangent andu = unit(t × s). - A round run. Its ring is a circle of radius
W/2aboutq_j, in the plane ofsandu. Its side vector is carried along the path without twisting: atq_0,s = unit(t × Z), or the x axis where the tangent is vertical; at each later point, the laststurned aboutunit(t_(j−1) × t_j)by the angle between the two tangents (not at all where they are parallel), then made square tot_jagain. - A rectangular duct. Its section stays upright: the rectangle
WalongsbyHalongu, centred onq_j, with its width level. At each points = unit(t × Z), except that: where the tangent is vertical (|t × Z| ≤ 10⁻⁶),sis 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 whereswould 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). - The mesh. The rings, each of
npoints 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. - 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 = 20points for a duct andn = 14for a pipe, pointjatq_j + (W/2)(s cos(2πj/n) + u sin(2πj/n)), and a rectangle's corners atq_j ∓ (W/2) s ∓ (H/2) uin 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
- The volume is the section's area,
π W² / 4for a round run orW Hfor 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. - 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.
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).
- 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 storedprofileandoffset; a component in a duct is sized from its duct and its type, not from its storedwidthandheight(Part II, 6.9, rule 8). - 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.
- A component whose
hostIdnames 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
Pin W and its design differenceΔTin K:q = 3.6 P / (c ΔT), withcthe 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'scode, 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.