> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ploterr.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Stair

> Stair makes a straight, L-shaped or U-shaped stair with equal risers.

It also draws the plan symbol.

## Import

```typescript theme={null}
import { Stair, computeStairLayout } from '@opengeometry/floorkit';
```

## Example

```typescript theme={null}
import { Stair, StairLayout, Floorkit } from '@opengeometry/floorkit';

async function example(wasmURL: string): Promise<void> {
  await new Floorkit().setupOpenGeometry(wasmURL);
  const stair = new Stair({
    layout: StairLayout.L_SHAPE,
    origin: [0, 0],
    elevation: 0,
    width: 1.1,
    totalRise: 3,
    treadDepth: 0.28,
    maxRiserHeight: 0.19,
    landingDepth: 1.2,
    turnDirection: 'left',
  });
  try {
    stair.setOPConfig({ totalRise: 3.1 });
    console.log(stair.riserCount, stair.actualRiserHeight, stair.layoutWarnings);
    console.log(stair.toDrawing('top', { cutElevation: 1.2 }));
  } finally {
    stair.dispose();
  }
}
```

## Notes

* Dimensions are in metres. `origin` is `[x, z]`. `rotation` is in degrees.
* Floorkit calculates the number of risers from the rise. Read `actualRiserHeight` for the result.
* Layout warnings tell you about steps that are not comfortable. They are not a building-code approval.
* `attachRailing` makes a railing follow the stair.
* Start the geometry kernel before you create this object. See [`Floorkit`](/floorkit/api/runtime/floorkit).
* This object is live geometry. To save a building, write it in a [building model](/floorkit/concepts/building-model).

**Inheritance:** `extends OPElement implements IShape, IPlaceable, PlanVectorExportable`

## Constructor

```typescript theme={null}
constructor(config?: Partial<StairOptions>);
```

<ParamField path="config.ogid" type="string" />

<ParamField path="config.labelName" type="string" />

<ParamField path="config.type" type="ElementType.STAIR" />

<ParamField path="config.layout" type="StairLayout" />

<ParamField path="config.origin" type="Point2">
  Plan position of the first flight's walkline start: \[x, z].
</ParamField>

<ParamField path="config.rotation" type="number">
  Plan rotation in degrees about `origin` (CCW viewed from above).
</ParamField>

<ParamField path="config.elevation" type="number">
  World Y of the stair base.
</ParamField>

<ParamField path="config.width" type="number">
  Flight width (m).
</ParamField>

<ParamField path="config.totalRise" type="number">
  Level-to-level rise (m).
</ParamField>

<ParamField path="config.treadDepth" type="number">
  Tread depth / going (m); clamped to ≥ 0.1, warned below 0.25.
</ParamField>

<ParamField path="config.riserHeight" type="number">
  Optional target riser height (m); the solver auto-counts equal risers at or below
  `min(riserHeight, maxRiserHeight)`.
</ParamField>

<ParamField path="config.maxRiserHeight" type="number">
  Hard riser cap (m).
</ParamField>

<ParamField path="config.landingDepth" type="number">
  Landing depth (m), clamped to ≥ width (L/U layouts).
</ParamField>

<ParamField path="config.turnDirection" type="StairTurnDirection">
  L/U turn direction walking up: "left" or "right".
</ParamField>

<ParamField path="config.showBreakLine" type="boolean">
  Draw the conventional break line in plan.
</ParamField>

<ParamField path="config.color" type="number" />

<ParamField path="config.propertySets" type="PropertySets" />

## Properties

<ResponseField name="ogType" type="ElementType" />

<ResponseField name="ogid" type="string" />

<ResponseField name="subElements2D" type="Map<string, OPGeometry>" />

<ResponseField name="subElements3D" type="Map<string, OPGeometry>" />

<ResponseField name="selected" type="boolean" />

<ResponseField name="edit" type="boolean" />

<ResponseField name="locked" type="boolean" />

<ResponseField name="onStairUpdated" type="Event<null>">
  Fires after every geometry rebuild — hosted railings re-derive their paths from it (mirrors
  `onWallGeometryChanged`/`onOpeningUpdated`).
</ResponseField>

<ResponseField name="propertySet" type="StairOptions" />

<ResponseField name="labelName" type="string" />

<ResponseField name="stairLayout" type="StairLayout" />

<ResponseField name="turnDirection" type="StairTurnDirection" />

<ResponseField name="stairWidth" type="number" />

<ResponseField name="totalRise" type="number" />

<ResponseField name="treadDepth" type="number" />

<ResponseField name="maxRiserHeight" type="number" />

<ResponseField name="landingDepth" type="number" />

<ResponseField name="elevation" type="number" />

<ResponseField name="showBreakLine" type="boolean" />

<ResponseField name="stairColor" type="number" />

<ResponseField name="riserCount" type="number">
  Read-only. Solved riser count. Computed, read-only.
</ResponseField>

<ResponseField name="actualRiserHeight" type="number">
  Read-only. Solved equal riser height (m). Computed, read-only.
</ResponseField>

<ResponseField name="runLength" type="number">
  Read-only. Total walkline length in plan (m). Computed, read-only.
</ResponseField>

<ResponseField name="layoutWarnings" type="string[]">
  Read-only. Industry-rule warnings from the last layout solve (riser cap, tread minimum, 2R+T
  comfort). Empty when the stair is code-friendly.
</ResponseField>

<ResponseField name="layoutResult" type="StairLayoutResult">
  Read-only. The solved flight/landing layout in stair-local coordinates.
</ResponseField>

<ResponseField name="outline" type="boolean" />

<ResponseField name="profileView" type="boolean" />

<ResponseField name="modelView" type="boolean" />

## Methods

### editableSchema

```typescript theme={null}
static editableSchema(): OPEditableSchema;
```

Self-describing editable surface; a host inspector renders this generically.

### getPhysicalParts

```typescript theme={null}
getPhysicalParts(): readonly PhysicalElementPart[];
```

Borrow actual material parts; descriptors contain no seeds, cutters or symbols.

### move

```typescript theme={null}
move(delta: Vec3): void;
```

Translate this element by `delta` (world-space, meters).

### rotate

```typescript theme={null}
rotate(angleDeg: number, axis?: Vec3, anchor?: Vec3): void;
```

Rotate this element by `angleDeg` around `axis` (default Y-up), pivoted at `anchor` (default the element's own centroid).

### getRailingPath

```typescript theme={null}
getRailingPath(side: "left" | "right", inset?: number): Vec3[];
```

Rail base path along one side of the stair: flight start → flight top at the step-walking-surface heights, then level AROUND the landing — never diagonally across it.

### attachRailing

```typescript theme={null}
attachRailing(railing: Railing, opts?: {
    side?: "left" | "right";
    inset?: number;
}): void;
```

Host a railing on this stair: derives its base path from the flight nosings on the chosen side and re-derives it on every stair rebuild (subscribes `onStairUpdated` — the wall `attachDoor` re-bind pattern).

### detachRailing

```typescript theme={null}
detachRailing(railing: Railing): void;
```

Unhost a railing: stops syncing its path (the path itself is kept).

### getHostedRailings

```typescript theme={null}
getHostedRailings(): Railing[];
```

Railings currently hosted on this stair.

### setOPGeometry

```typescript theme={null}
setOPGeometry(): void;
```

### getExportRoots

```typescript theme={null}
getExportRoots(view: PlanExportView): THREE.Object3D[];
```

Vector-export roots (RFC §7).

### toDrawing

```typescript theme={null}
toDrawing(view: PlanExportView, options?: StairPlanDrawingOptions): DrawingPrimitive[];
```

Plan symbol as standardized primitives, emitted parametrically from the solved layout: flight/landing regions, nosing lines, the walkline with its arrowhead, and the break line.

### setOPMaterial

```typescript theme={null}
setOPMaterial(): void;
```

### getEditAnchors

```typescript theme={null}
getEditAnchors(): EditAnchor[];
```

Draggable handles for a parametric stair: the plan `origin` (free on the floor plane), an `elevation` grip (vertical), and `width`, `going` and `landing` grips that slide across or along the first flight.

### applyEditAnchor

```typescript theme={null}
applyEditAnchor(id: string, position: [
    number,
    number,
    number
]): void;
```

### getOPConfig

```typescript theme={null}
getOPConfig(): StairOptions;
```

### setOPConfig

```typescript theme={null}
setOPConfig(config: Partial<StairOptions>): void;
```

### beginEdit

```typescript theme={null}
beginEdit(): void;
```

Start one live edit; a second `beginEdit` before `endEdit` keeps the first start.

### endEdit

```typescript theme={null}
endEdit(): {
    undo: () => void;
    redo: () => void;
} | undefined;
```

End the live edit; its exact undo and redo, or undefined when no option changed.

### dispose

```typescript theme={null}
dispose(): void;
```

## computeStairLayout

Solve the riser count and lay out flights/landings for the requested configuration.

```typescript theme={null}
function computeStairLayout(input: StairLayoutInput): StairLayoutResult;
```

## Types

### StairOptions

```typescript theme={null}
interface StairOptions extends HasPropertySets {
  ogid?: string;
  labelName: string;
  type: ElementType.STAIR;
  layout: StairLayout;
  origin: PointXZ;
  rotation: number;
  elevation: number;
  width: number;
  totalRise: number;
  treadDepth: number;
  riserHeight?: number;
  maxRiserHeight: number;
  landingDepth: number;
  turnDirection: StairTurnDirection;
  showBreakLine: boolean;
  color: number;
}
```

### StairLayout

Pure stair layout solver — riser math and flight/landing plan rectangles in stair-local coordinates, separated from the element class so the industry rules are unit-testable without the WASM kernel.

```typescript theme={null}
enum StairLayout {
  STRAIGHT = 'STRAIGHT',
  L_SHAPE = 'L_SHAPE',
  U_SHAPE = 'U_SHAPE',
}
```

### StairTurnDirection

```typescript theme={null}
type StairTurnDirection = 'left' | 'right';
```

### StairLayoutResult

```typescript theme={null}
interface StairLayoutResult {
  riserCount: number;
  actualRiserHeight: number;
  treadCount: number;
  runLength: number;
  landingSide: number;
  flights: StairFlight[];
  landings: StairLanding[];
  warnings: string[];
}
```

<ResponseField name="riserCount" type="number" required />

<ResponseField name="actualRiserHeight" type="number" required />

<ResponseField name="treadCount" type="number" required>
  Total tread rectangles across all flights.
</ResponseField>

<ResponseField name="runLength" type="number" required>
  Total walkline length in plan (flights + landings).
</ResponseField>

<ResponseField name="landingSide" type="number" required>
  Clamped landing square side, `max(landingDepth, width)`. 0 for STRAIGHT.
</ResponseField>

<ResponseField name="flights" type="StairFlight[]" required />

<ResponseField name="landings" type="StairLanding[]" required />

<ResponseField name="warnings" type="string[]" required />

### StairPlanDrawingOptions

View-only options; never change the saved stair dimensions or solids.

```typescript theme={null}
interface StairPlanDrawingOptions {
  cutElevation?: number;
}
```

<ResponseField name="cutElevation" type="number">
  Finite world Y of the plan cut.
</ResponseField>

### StairLayoutInput

```typescript theme={null}
interface StairLayoutInput {
  layout: StairLayout;
  width: number;
  totalRise: number;
  treadDepth: number;
  riserHeight?: number;
  maxRiserHeight?: number;
  landingDepth?: number;
  turnDirection?: StairTurnDirection;
}
```

<ResponseField name="layout" type="StairLayout" required />

<ResponseField name="width" type="number" required>
  Flight width (m).
</ResponseField>

<ResponseField name="totalRise" type="number" required>
  Level-to-level rise (m).
</ResponseField>

<ResponseField name="treadDepth" type="number" required>
  Tread depth / going (m).
</ResponseField>

<ResponseField name="riserHeight" type="number">
  Target riser height (m); the solver picks the count whose equal risers come closest below this.
  Defaults to 0.178.
</ResponseField>

<ResponseField name="maxRiserHeight" type="number">
  Hard riser cap (m). Defaults to 0.19.
</ResponseField>

<ResponseField name="landingDepth" type="number">
  Landing depth (m), clamped to ≥ width (L/U layouts).
</ResponseField>

<ResponseField name="turnDirection" type="StairTurnDirection">
  L/U turn direction, viewed from above walking up: "left" turns toward −Z, "right" toward +Z.
</ResponseField>

### StairFlight

```typescript theme={null}
interface StairFlight {
  riserCount: number;
  baseElevation: number;
  direction: PointXZ;
  steps: StairStep[];
  walkline: {
    start: PointXZ;
    end: PointXZ;
  };
}
```

<ResponseField name="riserCount" type="number" required>
  Risers this flight climbs (its tread count is `risers − 1` when it ends at a landing — the landing
  is the arrival surface — and `risers` for the final flight, whose top tread represents the arrival
  level).
</ResponseField>

<ResponseField name="baseElevation" type="number" required>
  Elevation of the flight's first tread's base above the stair base.
</ResponseField>

<ResponseField name="direction" type="PointXZ" required>
  Unit run direction in local XZ.
</ResponseField>

<ResponseField name="steps" type="StairStep[]" required />

<ResponseField
  name="walkline"
  type="{
start: PointXZ;
end: PointXZ;
}"
  required
>
  Walkline along the flight centerline, base → top.
</ResponseField>

### StairLanding

```typescript theme={null}
interface StairLanding {
  rect: StairRect;
  topElevation: number;
  walkline: {
    start: PointXZ;
    end: PointXZ;
  };
}
```

<ResponseField name="rect" type="StairRect" required />

<ResponseField name="topElevation" type="number" required />

<ResponseField
  name="walkline"
  type="{
start: PointXZ;
end: PointXZ;
}"
  required
>
  Walkline across the landing connecting the adjoining flights.
</ResponseField>

### StairStep

```typescript theme={null}
interface StairStep {
  rect: StairRect;
  topElevation: number;
}
```

<ResponseField name="rect" type="StairRect" required>
  Plan rectangle of the tread.
</ResponseField>

<ResponseField name="topElevation" type="number" required>
  Elevation of the tread's walking surface above the stair base.
</ResponseField>

### StairRect

Axis-aligned-in-local-space plan rectangle, CCW \[corner, +run, +run+across, +across].

```typescript theme={null}
type StairRect = [PointXZ, PointXZ, PointXZ, PointXZ];
```

## Related

* [`OPElement`](/floorkit/api/architecture/op-element)
* [`Railing`](/floorkit/api/architecture/railing)
* [`DrawingPrimitive`](/floorkit/api/drawings/draw-project-view#drawingprimitive)
* [`EditAnchor`](/floorkit/api/architecture/op-element#editanchor)
* [`ElementType`](/floorkit/api/architecture/op-element#elementtype)
* [`Event`](/floorkit/api/architecture/wall-network#event)
* [`HasPropertySets`](/floorkit/api/architecture/op-element#haspropertysets)
* [`IPlaceable`](/floorkit/api/architecture/op-element#iplaceable)
* [`IShape`](/floorkit/api/shapes/cuboid-shape#ishape)
* [`OPEditableSchema`](/floorkit/api/architecture/op-element#opeditableschema)
* [`OPGeometry`](/floorkit/api/architecture/opening#opgeometry)
* [`PhysicalElementPart`](/floorkit/api/architecture/door#physicalelementpart)
* [`PlanExportView`](/floorkit/api/shapes/cylinder-shape#planexportview)
* [`PlanVectorExportable`](/floorkit/api/shapes/cylinder-shape#planvectorexportable)
* [`PointXZ`](/floorkit/api/primitives/polygon-maths#pointxz)
* [`Vec3`](/floorkit/api/architecture/wall#vec3)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.