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

# Move and reshape

> Change a wall after you draw it. Its doors and windows follow.

export const LiveExample = ({path, title = 'Live example', height = 460}) => {
  return <Frame>
      <iframe src={`https://floorkit-examples.ploterr.com/floorkit/${path}?embed=1`} ref={frame => {
    if (!frame || !['localhost', '127.0.0.1'].includes(window.location.hostname)) return;
    const local = `http://localhost:5555/${path}?embed=1`;
    if (frame.src !== local) frame.src = local;
  }} title={title} loading="lazy" allow="fullscreen" style={{
    width: '100%',
    height: `${height}px`,
    border: 0,
    display: 'block'
  }} />
    </Frame>;
};

You change a wall with a command. Floorkit moves the wall, joins it again to the walls that it touches, and cuts its openings again.

<LiveExample path="guides/move-and-reshape" />

## Before you start

Your building has the room and the garden wall from [Draw a wall](/floorkit/guides/draw-a-wall).

## Move one point of a wall

`pointIndex` is the position of the point in the `points` list of the wall. Index `2` is the third point, the corner at `[6, 4]`.

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

export function stretchRoom(session: BuildingSession): void {
  session.apply(
    {
      kind: 'move-wall-point',
      buildingId: 'building',
      storeyId: 'ground',
      wallId: 'room-walls',
      pointIndex: 2,
      position: [7, 5],
    },
    session.revision,
  );
}
```

The room is now larger at that corner, and the two walls that meet there have a new direction. A door at `offset: 2` is still 2 metres from the first point.

## Take one end off a corner

`move-network-wall-end` moves one end of one segment of a wall. Segment `0` goes from the first point to the second point. `end` is `'start'` or `'end'` of that segment.

```typescript theme={null}
export function freeWallEnd(session: BuildingSession): void {
  session.apply(
    {
      kind: 'move-network-wall-end',
      buildingId: 'building',
      storeyId: 'ground',
      wallId: 'room-walls',
      segmentIndex: 1,
      end: 'end',
      position: [7.5, 3],
    },
    session.revision,
  );
}
```

Only that end moves. The other wall at the corner stays where it is, and the corner is open. If the new position is on a different wall, the end joins that wall.

Floorkit cuts the saved wall at the open corner. A closed wall becomes an open wall with the same `id`. An open wall becomes two walls, and the new wall gets the old `id` with a number, such as `room-walls-2`. Each door and window stays in its segment.

If the new position is less than 1 mm from the corner, the corner stays closed and moves to that position.

## Move or turn a full wall

`transform-wall` turns the wall around `origin` and then moves it by `translation`.

```typescript theme={null}
export function shiftWall(session: BuildingSession): void {
  session.apply(
    {
      kind: 'transform-wall',
      buildingId: 'building',
      storeyId: 'ground',
      wallId: 'garden-wall',
      origin: [0, 7],
      translation: [0, 1],
      yawDeg: 0,
    },
    session.revision,
  );
}
```

## Other elements

Slabs, roofs, stairs and rooms have the same kind of command: `transform-slab`, `transform-roof`, `transform-stair` and `transform-space`. Each one takes an `origin`, a `translation` and a `yawDeg`.

To change the shape of one of them, use a `reshape` command. This example makes the slab from [Add a floor slab](/floorkit/guides/add-a-floor-slab) longer and thicker.

```typescript theme={null}
export function widenSlab(session: BuildingSession): void {
  session.apply(
    {
      kind: 'reshape-slab',
      buildingId: 'building',
      storeyId: 'ground',
      slabId: 'ground-floor',
      profile: {
        outerRing: [
          [-0.1, -0.1],
          [8.1, -0.1],
          [8.1, 4.1],
          [-0.1, 4.1],
        ],
      },
      thickness: 0.25,
    },
    session.revision,
  );
}
```

| Command | What it sets |
| - | - |
| `reshape-slab` | `profile` and `thickness` |
| `reshape-roof` | `profile` and `baseOffset`, the height of the eave |
| `reshape-space` | `profile` and, if you give it, `height` |
| `reshape-stair` | `origin` and `baseOffset` and, if you give them, `width`, `treadDepth` and `landingDepth` |

A `profile` has an `outerRing` and can have `holes`. Each one is a list of `[x, z]` points in metres. All other data of the element stays the same.

## Replace or remove an element

A `reshape` command sets some values of an element. To set all values, send `replace-element` with the full element. The new element must have the same `id`. This example gives the slab a new thickness and puts it lower.

```typescript theme={null}
import type { BmSlab } from '@opengeometry/floorkit';

export function replaceSlab(session: BuildingSession, slab: BmSlab): void {
  session.apply(
    {
      kind: 'replace-element',
      buildingId: 'building',
      storeyId: 'ground',
      list: 'slabs',
      elementId: slab.id,
      element: { ...slab, thickness: 0.3, baseOffset: -0.3 },
    },
    session.revision,
  );
}

export function removeSlab(session: BuildingSession, slabId: string): void {
  session.apply(
    {
      kind: 'remove-element',
      buildingId: 'building',
      storeyId: 'ground',
      list: 'slabs',
      elementId: slabId,
    },
    session.revision,
  );
}
```

| Command | What you give | What it rejects |
| - | - | - |
| `add-element` | The `list` and the new `element` | An id that the list has |
| `replace-element` | The `list`, the `elementId` and the full new `element` | An id that the list does not have, and a new element with a different id |
| `remove-element` | The `list` and the `elementId` | An id that the list does not have |

`list` is `slabs`, `roofs`, `spaces`, `stairs`, `columns`, `beams`, `railings` or `instances`.

Assets and storeys have the same three kinds of command.

| Command | What you give | What it rejects |
| - | - | - |
| `add-asset` | The `assetId` and the `asset` | An id that exists |
| `replace-asset` | The `assetId` and the new `asset` | An id that does not exist |
| `remove-asset` | The `assetId` | An id that does not exist, and an asset that an instance uses |
| `add-storey` | The `buildingId` and the full `storey` | A storey id that the building has |
| `remove-storey` | The `buildingId` and the `storeyId` | The last storey of a building |
| `replace-storey-settings` | The `storeyId` and the `settings`: `name`, `elevation`, `height` and `usage` together | A storey id that the building does not have |

A [`ProjectManager`](/floorkit/api/editor/project-manager) also rejects a `remove-storey` of a storey that a plan view names.

To send several commands as one step, put them in a `batch`. See [A batch of commands](/floorkit/concepts/editing-and-history#a-batch-of-commands).

## Rules

* Positions are `[x, z]` in metres. `yawDeg` is in degrees, and a positive angle turns +X to +Z.
* Doors and windows stay in their wall and keep their `offset`.
* If a wall becomes too short for one of its openings, `apply` throws an error and nothing changes.

## Handle a rejected edit

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

export function tryEdit(run: () => void): string | undefined {
  try {
    run();
    return undefined;
  } catch (error) {
    if (error instanceof BuildingSessionError || error instanceof BmEditError) return error.message;
    throw error;
  }
}
```

Show the message to the user. The building is the same as before the edit.

## Next

<CardGroup cols={2}>
  <Card title="Undo and redo" icon="clock-rotate-left" href="/floorkit/guides/undo-and-redo">
    Go back one edit.
  </Card>

  <Card title="Add a plan editor" icon="pen-ruler" href="/floorkit/guides/add-a-plan-editor">
    Let the user do these edits with the pointer.
  </Card>
</CardGroup>


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