> ## 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.

# BuildingSession

> BuildingSession holds one building, its 3D geometry and its edit history.

You send it edit commands. It checks each command, builds the geometry again and keeps undo and redo.

## Import

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

## Example

```typescript theme={null}
import {
  BuildingSessionError,
  type BuildingSession,
  type BuildingEditCommand,
} from '@opengeometry/floorkit';

export function captureEdit(session: BuildingSession, command: BuildingEditCommand): () => void {
  const revisionAtGestureStart = session.revision;
  return () => {
    try {
      session.apply(command, revisionAtGestureStart);
    } catch (error) {
      if (error instanceof BuildingSessionError && error.code === 'stale-revision') {
        console.warn('The model changed during this gesture; start again.');
        return;
      }
      throw error;
    }
  };
}
```

## Notes

* Add `session.root` to your scene one time. It stays valid after each edit.
* Read `session.revision` when an edit starts, and pass it to `apply`. If a different edit came first, `apply` throws `stale-revision`.
* An edit that fails changes nothing.
* A new edit clears the redo list. `undo` and `redo` return `null` when there is nothing to do.
* `snapshot()` returns a copy of the building model. Save this copy.
* After an edit, get the elements again from `currentBuild` by their ids. A changed element can be a new object, and Floorkit then disposes the old object. A changed wall, and a door, a window or a hole on a wall, can also stay the same object with new geometry.
* `add-element`, `replace-element` and `remove-element` change one slab, roof, room, stair, column, beam, railing or instance. An `add` rejects an id that the list has. A `replace` or a `remove` rejects an id that the list does not have, and the new element of a `replace` must have the same id.
* `add-asset`, `replace-asset` and `remove-asset` change one asset of the model. `remove-asset` rejects an asset that an instance uses.
* `add-storey`, `remove-storey` and `replace-storey-settings` change the storeys of a building. `add-storey` rejects a storey id that the building has, and `remove-storey` rejects the last storey.
* `replace-mass` sets the mass of a building and the settings of all its storeys in one step. `storeys` is the new storey list, in its order. A storey id that stays keeps its walls and elements, a new id adds an empty storey, and a storey that is left out is removed. It rejects the removal of a storey that holds an element. Without `mass`, the building has no mass. `massSegmentHeightCommand(model, buildingId, segmentId, height)` gives this command for a new height of one segment, snapped to whole storeys.
* `add-building` adds a whole building, last in the list: its storeys, their elements and its optional `mass`. Each id in it must be new in the whole model. The smallest valid building has one storey, and for a massing study a `mass` with one segment whose `storeyIds` names that storey and whose `height` is the height of the storey. `remove-building` removes a building and all it holds; it rejects the last building of the model.
* `replace-site` replaces the site whole: `boundary`, `lotLines`, `elevation`, `geoAnchor`, `trueNorthDeg` and the `zoning` rules. Without `site`, the model has no site any more. The model check refuses a self-intersecting boundary and a `lotLines` list that does not have one class per boundary edge. Run `evaluateZoning` again after the step; the command does not run it. The session builds again only the storeys and the mass of the added or removed building, or only the site.
* A `batch` applies several commands as one step: one revision, one build and one undo step. If one command fails, nothing changes, and the message of the error starts with the place of the command, such as `command 2 of 3:`. After a batch, `lastEditCommand` is the batch.
* A session does not know the saved views of a project. Thus a `remove-storey`, a `replace-mass` or a `remove-building` that removes a storey that a plan view names passes in a session. [`ProjectManager.apply`](/floorkit/api/editor/project-manager) rejects it.
* The history is not saved in the project file.

## Constructor

```typescript theme={null}
constructor(model: BuildingModel, options?: Pick<BuildOptions, 'assetSources' | 'stampMembership' | 'massColors'>);
```

<ParamField path="options.assetSources" type="Record<string, string | OpenElementDefinition>">
  `.op` sources for the document's `external-op` assets, keyed by their `uri`, as either a raw
  buffer or an already-parsed definition. Fetching is the CALLER's pre-step so this function stays
  synchronous — the same split `.opbase` uses (`OPBaseOptions.assetSources`). An `embedded-op` asset
  needs nothing here.
</ParamField>

<ParamField path="options.massColors" type="Readonly<Record<string, string>>">
  The colour of a mass part by its use, `#rrggbb` by use name, used for a part when neither it nor
  its mass has a `color`. Replaces `MASS_COLORS_BY_USE` whole; a use it does not list takes
  `#a0b8c8`. Pass it where the project is opened (`ProjectManager` `build`) so that the live build,
  the plan drawings and the sheets take the same colours.
</ParamField>

<ParamField path="options.stampMembership" type="boolean">
  Stamp `storeyId`/`buildingId` onto every element's propertySet. Default true.
</ParamField>

## Properties

<ResponseField name="root" type="THREE.Group<THREE.Object3DEventMap>">
  Read-only. Stable scene node. The app may mount it once and retain it across edits.
</ResponseField>

<ResponseField name="revision" type="number">
  Read-only.
</ResponseField>

<ResponseField name="isDisposed" type="boolean">
  Read-only.
</ResponseField>

<ResponseField name="canUndo" type="boolean">
  Read-only.
</ResponseField>

<ResponseField name="canRedo" type="boolean">
  Read-only.
</ResponseField>

<ResponseField name="lastEditCommand" type="BuildingEditCommand | undefined">
  Read-only. Caller-owned identity of the latest successfully published edit or history replay;
  after a batch it is the batch.
</ResponseField>

<ResponseField name="currentBuild" type="BuildResult">
  Read-only.
</ResponseField>

## Methods

### snapshot

```typescript theme={null}
snapshot(): BuildingModel;
```

A caller-owned copy; live preview edits never change this saved model.

### apply

```typescript theme={null}
apply(command: BuildingEditCommand, expectedRevision: number): number;
```

Return the new revision after one complete edit and compilation.

### undo

```typescript theme={null}
undo(expectedRevision: number): number | null;
```

Restore the preceding committed model; an empty history is a no-op.

### redo

```typescript theme={null}
redo(expectedRevision: number): number | null;
```

Reapply the next committed model; an empty redo history is a no-op.

### subscribe

```typescript theme={null}
subscribe(listener: (change: BuildingSessionChange) => void): () => void;
```

Notify after a committed transition; unsubscribe may be called repeatedly.

### dispose

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

## BuildingSessionError

```typescript theme={null}
class BuildingSessionError extends Error {
  readonly code: BuildingSessionErrorCode;
  constructor(code: BuildingSessionErrorCode, message: string);
}
```

## Types

### BuildingEditCommand

A single, serializable edit to an authored building model.

```typescript theme={null}
type BuildingEditCommand =
  | BatchCommand
  | ModelObjectEditCommand
  | ElementListCommand
  | AssetCommand
  | StoreyCommand
  | ReplaceMassCommand
  | BuildingCommand
  | ReplaceSiteCommand
  | SlabTransformCommand
  | SpaceTransformCommand
  | RoofTransformCommand
  | StairTransformCommand
  | ElementReshapeCommand
  | NetworkWallTranslateCommand
  | NetworkWallEndMoveCommand
  | WallCreateCommand
  | WallDeleteCommand
  | HostedOpeningRemoveCommand
  | FreeOpeningRemoveCommand
  | HostedOpeningCreateCommand
  | FreeOpeningCreateCommand
  | HostedOpeningDetachCommand
  | HostedOpeningRehostCommand
  | {
      kind: 'transform-wall';
      buildingId: string;
      storeyId: string;
      wallId: string;
      origin: PointXZ;
      translation: PointXZ;
      yawDeg: number;
    }
  | {
      kind: 'move-wall-point';
      buildingId: string;
      storeyId: string;
      wallId: string;
      pointIndex: number;
      position: PointXZ;
    }
  | {
      kind: 'move-hosted-opening';
      buildingId: string;
      storeyId: string;
      wallId: string;
      openingId: string;
      offset: number;
    }
  | {
      kind: 'move-free-opening';
      buildingId: string;
      storeyId: string;
      openingId: string;
      position: PointXZ;
      yawDeg: number;
    }
  | {
      kind: 'rehost-free-opening';
      buildingId: string;
      storeyId: string;
      openingId: string;
      wallId: string;
      position: PointXZ;
      yawDeg: number;
    };
```

### BuildingSessionChange

```typescript theme={null}
interface BuildingSessionChange {
  readonly kind: 'apply' | 'undo' | 'redo' | 'restore';
  readonly revision: number;
  readonly changed?: readonly string[];
}
```

<ResponseField name="kind" type="'apply' | 'undo' | 'redo' | 'restore'" required>
  What made the step. `restore` is no saved step: a step failed after it changed built objects, and
  the session built them again from the saved model.
</ResponseField>

<ResponseField name="revision" type="number" required>
  The revision of the session after the step. A `restore` leaves the revision as it was.
</ResponseField>

<ResponseField name="changed" type="readonly string[]">
  The live ids (keys of `currentBuild.elementsById` and `modelObjectsById`) that the step built
  again, added or removed, where a removed id is in the list and not in the build; absent when the
  whole building was built again. An element that was built again is a new object, or the same
  object with new geometry.
</ResponseField>

### BuildingSessionErrorCode

```typescript theme={null}
type BuildingSessionErrorCode = 'stale-revision' | 'disposed' | 'reentrant-transition';
```

### BatchCommand

Several edits as one step, in order: all of them or none.

```typescript theme={null}
interface BatchCommand {
  kind: 'batch';
  commands: readonly Exclude<BuildingEditCommand, BatchCommand>[];
}
```

### ModelObjectEditCommand

One complete saved object edit; replacement preserves authored identity and kind.

```typescript theme={null}
type ModelObjectEditCommand =
  | {
      kind: 'add-model-object';
      buildingId: string;
      storeyId: string;
      object: BmModelObject;
    }
  | {
      kind: 'replace-model-object';
      buildingId: string;
      storeyId: string;
      objectId: string;
      object: BmModelObject;
    }
  | {
      kind: 'remove-model-object';
      buildingId: string;
      storeyId: string;
      objectId: string;
    };
```

### ElementListCommand

One saved edit of a storey list; a replacement keeps the element id and its list.

```typescript theme={null}
type ElementListCommand = {
  [List in keyof ElementLists]:
    | {
        kind: 'add-element';
        buildingId: string;
        storeyId: string;
        list: List;
        element: ElementLists[List];
      }
    | {
        kind: 'replace-element';
        buildingId: string;
        storeyId: string;
        list: List;
        elementId: string;
        element: ElementLists[List];
      }
    | {
        kind: 'remove-element';
        buildingId: string;
        storeyId: string;
        list: List;
        elementId: string;
      };
}[keyof ElementLists];
```

### AssetCommand

One saved edit of the block definitions of a model; an instance names its definition by id.

```typescript theme={null}
type AssetCommand =
  | {
      kind: 'add-asset';
      assetId: string;
      asset: BmAssetRef;
    }
  | {
      kind: 'replace-asset';
      assetId: string;
      asset: BmAssetRef;
    }
  | {
      kind: 'remove-asset';
      assetId: string;
    };
```

### StoreyCommand

One saved edit of the storeys of a building; the settings of a storey are replaced whole.

```typescript theme={null}
type StoreyCommand =
  | {
      kind: 'add-storey';
      buildingId: string;
      storey: BmStorey;
    }
  | {
      kind: 'remove-storey';
      buildingId: string;
      storeyId: string;
    }
  | {
      kind: 'replace-storey-settings';
      buildingId: string;
      storeyId: string;
      settings: Pick<BmStorey, 'name' | 'elevation' | 'height' | 'usage' | 'areaKind'>;
    };
```

### SlabTransformCommand

One saved slab transform in world XZ coordinates, retaining its vertical placement.

```typescript theme={null}
interface SlabTransformCommand extends ProfileTransform {
  kind: 'transform-slab';
  buildingId: string;
  storeyId: string;
  slabId: string;
}
```

### SpaceTransformCommand

One saved space transform in world XZ coordinates, retaining its vertical placement.

```typescript theme={null}
interface SpaceTransformCommand extends ProfileTransform {
  kind: 'transform-space';
  buildingId: string;
  storeyId: string;
  spaceId: string;
}
```

### RoofTransformCommand

One saved roof transform in world XZ coordinates, retaining its vertical placement.

```typescript theme={null}
interface RoofTransformCommand extends ProfileTransform {
  kind: 'transform-roof';
  buildingId: string;
  storeyId: string;
  roofId: string;
}
```

### StairTransformCommand

One saved stair transform in world XZ coordinates, retaining its vertical placement.

```typescript theme={null}
interface StairTransformCommand extends ProfileTransform {
  kind: 'transform-stair';
  buildingId: string;
  storeyId: string;
  stairId: string;
}
```

### ElementReshapeCommand

```typescript theme={null}
type ElementReshapeCommand =
  | SlabReshapeCommand
  | RoofReshapeCommand
  | SpaceReshapeCommand
  | StairReshapeCommand;
```

### NetworkWallTranslateCommand

Translate one compiled segment by a world XZ delta through its storey's WallNetwork.

```typescript theme={null}
interface NetworkWallTranslateCommand {
  kind: 'translate-network-wall';
  buildingId: string;
  storeyId: string;
  wallId: string;
  segmentIndex: number;
  translation: PointXZ;
}
```

### NetworkWallEndMoveCommand

Move one end of a compiled segment through its storey's WallNetwork.

```typescript theme={null}
interface NetworkWallEndMoveCommand {
  kind: 'move-network-wall-end';
  buildingId: string;
  storeyId: string;
  wallId: string;
  segmentIndex: number;
  end: WallEnd;
  position: PointXZ;
}
```

### WallCreateCommand

Append one complete authored wall run; openings require their own saved edit.

```typescript theme={null}
interface WallCreateCommand {
  kind: 'create-wall';
  buildingId: string;
  storeyId: string;
  wall: Omit<BmWall, 'openings'> & {
    openings?: never;
  };
}
```

### WallDeleteCommand

Remove the complete authored run, including every segment of a closed wall.

```typescript theme={null}
interface WallDeleteCommand {
  kind: 'delete-wall';
  buildingId: string;
  storeyId: string;
  wallId: string;
}
```

### HostedOpeningRemoveCommand

Remove one authored opening from its exact wall without changing its wall axis.

```typescript theme={null}
interface HostedOpeningRemoveCommand {
  kind: 'remove-hosted-opening';
  buildingId: string;
  storeyId: string;
  wallId: string;
  openingId: string;
}
```

### FreeOpeningRemoveCommand

Remove one exact storey-owned free door or window without changing any wall.

```typescript theme={null}
interface FreeOpeningRemoveCommand {
  kind: 'remove-free-opening';
  buildingId: string;
  storeyId: string;
  openingId: string;
}
```

### HostedOpeningCreateCommand

Add one complete authored door or window to its explicitly chosen wall.

```typescript theme={null}
interface HostedOpeningCreateCommand {
  kind: 'add-hosted-opening';
  buildingId: string;
  storeyId: string;
  wallId: string;
  opening: BmDoor | BmWindow;
}
```

### FreeOpeningCreateCommand

Add one complete physical door or window at an explicit free pose in a storey.

```typescript theme={null}
interface FreeOpeningCreateCommand {
  kind: 'add-free-opening';
  buildingId: string;
  storeyId: string;
  opening: BmUnhostedOpening;
}
```

### HostedOpeningDetachCommand

Explicitly remove a door/window from its host and place it in world XZ metres.

The package does not export this type by name.

```typescript theme={null}
interface HostedOpeningDetachCommand {
  kind: 'detach-hosted-opening';
  buildingId: string;
  storeyId: string;
  wallId: string;
  openingId: string;
  position: PointXZ;
}
```

### HostedOpeningRehostCommand

Move one door, window or void from its wall to a place on another wall of the same storey.

```typescript theme={null}
interface HostedOpeningRehostCommand {
  kind: 'rehost-hosted-opening';
  buildingId: string;
  storeyId: string;
  wallId: string;
  openingId: string;
  toWallId: string;
  offset: number;
}
```

<ResponseField name="kind" type="'rehost-hosted-opening'" required />

<ResponseField name="buildingId" type="string" required />

<ResponseField name="storeyId" type="string" required />

<ResponseField name="wallId" type="string" required />

<ResponseField name="openingId" type="string" required />

<ResponseField name="toWallId" type="string" required />

<ResponseField name="offset" type="number" required>
  Distance in metres along the saved centreline of the new wall.
</ResponseField>

### ElementLists

The storey lists that the element commands edit, with the element type of each list.

```typescript theme={null}
interface ElementLists {
  slabs: BmSlab;
  roofs: BmRoof;
  spaces: BmSpace;
  stairs: BmStair;
  columns: BmColumn;
  beams: BmBeam;
  railings: BmRailing;
  instances: BmAssetInstance;
}
```

### ProfileTransform

A rigid world XZ transform shared by authored polygon families.

The package does not export this type by name.

```typescript theme={null}
interface ProfileTransform {
  origin: PointXZ;
  translation: PointXZ;
  yawDeg: number;
}
```

<ResponseField name="origin" type="PointXZ" required>
  World XZ pivot in metres.
</ResponseField>

<ResponseField name="translation" type="PointXZ" required>
  World XZ translation in metres, applied after rotation.
</ResponseField>

<ResponseField name="yawDeg" type="number" required>
  Relative degrees; positive yaw turns +X toward +Z.
</ResponseField>

### SlabReshapeCommand

Replace one slab's outline and thickness.

```typescript theme={null}
interface SlabReshapeCommand {
  kind: 'reshape-slab';
  buildingId: string;
  storeyId: string;
  slabId: string;
  profile: PolygonProfile;
  thickness: number;
}
```

<ResponseField name="kind" type="'reshape-slab'" required />

<ResponseField name="buildingId" type="string" required />

<ResponseField name="storeyId" type="string" required />

<ResponseField name="slabId" type="string" required />

<ResponseField name="profile" type="PolygonProfile" required>
  Outline and holes in world XZ metres.
</ResponseField>

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

### RoofReshapeCommand

Replace one roof's outline and its eave height above the storey.

```typescript theme={null}
interface RoofReshapeCommand {
  kind: 'reshape-roof';
  buildingId: string;
  storeyId: string;
  roofId: string;
  profile: PolygonProfile;
  baseOffset: number;
}
```

<ResponseField name="kind" type="'reshape-roof'" required />

<ResponseField name="buildingId" type="string" required />

<ResponseField name="storeyId" type="string" required />

<ResponseField name="roofId" type="string" required />

<ResponseField name="profile" type="PolygonProfile" required>
  Outline and holes in world XZ metres.
</ResponseField>

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

### SpaceReshapeCommand

Replace one room's outline and, when given, its height.

```typescript theme={null}
interface SpaceReshapeCommand {
  kind: 'reshape-space';
  buildingId: string;
  storeyId: string;
  spaceId: string;
  profile: PolygonProfile;
  height?: number;
}
```

<ResponseField name="kind" type="'reshape-space'" required />

<ResponseField name="buildingId" type="string" required />

<ResponseField name="storeyId" type="string" required />

<ResponseField name="spaceId" type="string" required />

<ResponseField name="profile" type="PolygonProfile" required>
  Outline and holes in world XZ metres.
</ResponseField>

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

### StairReshapeCommand

Put one stair's start point at a new place and height above the storey; a given size replaces its own.

```typescript theme={null}
interface StairReshapeCommand {
  kind: 'reshape-stair';
  buildingId: string;
  storeyId: string;
  stairId: string;
  origin: PointXZ;
  baseOffset: number;
  width?: number;
  treadDepth?: number;
  landingDepth?: number;
}
```

## Related

* [`BmAssetInstance`](/floorkit/api/architecture/validate-building-model#bmassetinstance)
* [`BmAssetRef`](/floorkit/api/architecture/validate-building-model#bmassetref)
* [`BmBeam`](/floorkit/api/architecture/validate-building-model#bmbeam)
* [`BmColumn`](/floorkit/api/architecture/validate-building-model#bmcolumn)
* [`BmDoor`](/floorkit/api/architecture/validate-building-model#bmdoor)
* [`BmModelObject`](/floorkit/api/architecture/validate-building-model#bmmodelobject)
* [`BmRailing`](/floorkit/api/architecture/validate-building-model#bmrailing)
* [`BmRoof`](/floorkit/api/architecture/validate-building-model#bmroof)
* [`BmSlab`](/floorkit/api/architecture/validate-building-model#bmslab)
* [`BmSpace`](/floorkit/api/architecture/validate-building-model#bmspace)
* [`BmStair`](/floorkit/api/architecture/validate-building-model#bmstair)
* [`BmStorey`](/floorkit/api/architecture/validate-building-model#bmstorey)
* [`BmUnhostedOpening`](/floorkit/api/architecture/validate-building-model#bmunhostedopening)
* [`BmWall`](/floorkit/api/architecture/validate-building-model#bmwall)
* [`BmWindow`](/floorkit/api/architecture/validate-building-model#bmwindow)
* [`BuildingCommand`](/floorkit/api/editor/pure-edits#buildingcommand)
* [`BuildingModel`](/floorkit/api/architecture/validate-building-model#buildingmodel)
* [`BuildOptions`](/floorkit/api/architecture/build-from-building-model#buildoptions)
* [`BuildResult`](/floorkit/api/architecture/build-from-building-model#buildresult)
* [`PointXZ`](/floorkit/api/primitives/polygon-maths#pointxz)
* [`PolygonProfile`](/floorkit/api/primitives/polygon-maths#polygonprofile)
* [`ReplaceMassCommand`](/floorkit/api/editor/pure-edits#replacemasscommand)
* [`ReplaceSiteCommand`](/floorkit/api/editor/pure-edits#replacesitecommand)
* [`WallEnd`](/floorkit/api/architecture/wall-network#wallend)


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