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

# Add a 3D editor

> Let your users select and move elements in your Three.js view.

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>;
};

The 3D editor draws handles on top of your Three.js view. When you connect it to a project manager, each drag becomes one step in the history of the manager. The plan editors and the 3D editor of one manager always show the same building.

<LiveExample path="guides/add-a-3d-editor" />

## Before you start

* You have a project. See [Create a plan view](/floorkit/guides/create-a-plan-view).
* You have a scene, a camera and camera controls, such as `OrbitControls`.

## Open the project

Open the project in a `ProjectManager` and add `manager.root` to your scene one time.

```typescript theme={null}
import type * as THREE from 'three';
import {
  GUIEditor,
  ProjectManager,
  type CameraControlsLike,
  type ProjectFile,
} from '@opengeometry/floorkit';

export function openSceneProject(scene: THREE.Scene, project: ProjectFile): ProjectManager {
  const manager = new ProjectManager(project, {
    onError: (error) => console.error('Floorkit rejected the edit', error),
  });
  scene.add(manager.root);
  return manager;
}
```

## Mount the editor

`GUIEditor` needs the element that holds your canvas, your camera and your controls. It stops the controls while the user drags a handle. `bindSceneEditor` connects it to the project.

```typescript theme={null}
export function mountSceneEditor(
  container: HTMLElement,
  camera: THREE.Camera,
  controls: CameraControlsLike,
  manager: ProjectManager,
): GUIEditor {
  const editor = new GUIEditor(container, camera, controls);
  manager.bindSceneEditor(editor);
  return editor;
}
```

## Update it in each frame

Call `update()` before you render. The handles then follow the camera.

```typescript theme={null}
export function renderFrame(
  editor: GUIEditor,
  renderer: THREE.WebGLRenderer,
  scene: THREE.Scene,
  camera: THREE.Camera,
): void {
  editor.update();
  renderer.render(scene, camera);
}
```

## Edit a wall

When the user selects a wall, the editor shows a line along the wall and these handles:

| The user drags | Result |
| - | - |
| A dot at an end | Only that end moves. The other wall at the corner stays where it is. |
| The dot at the middle | The wall moves sideways. The walls at its ends become longer or shorter. |
| The dot at the centre | All segments of the wall move, with their doors and windows. |
| The dot beside the centre dot | All segments of the wall turn about their centre. |

An end that leaves a corner is free. An end released near the end of another wall joins that end, and the two walls make a corner. An end released near the body of another wall joins that wall. When an end leaves a corner inside one saved wall, Floorkit cuts the saved wall there and gives the new part its own id.

The walls, their doors and their windows move while the user drags. When the user releases the pointer, Floorkit saves one edit command. Thus one drag is one step for undo.

## Edit a door or a window

When the user selects a door or a window, the editor shows one dot on it.

| The user drags the dot | Result |
| - | - |
| Along its wall | The door moves along the wall. |
| Near a different wall | The door moves into that wall. |
| More than 0.35 m from every wall | The door leaves its wall and becomes a loose door. |
| On a loose door | The loose door moves. It does not go into a wall. |

The door moves while the user drags, and the cut in the wall moves when the user releases the pointer. One drag is one edit command.

## Edit a slab, a roof, a room or a stair

When the user selects one of these, the editor shows its handles.

| Element | Handles |
| - | - |
| Slab | A dot at each corner moves that corner. A dot at the middle of an edge adds a corner. |
| Roof | A dot at each corner moves that corner. |
| Room | A dot at each corner moves that corner. |
| Stair | A dot at the start point moves the stair. Three smaller dots set its width, the depth of its treads and the depth of its landing. |

The 3D editor also has a handle for the height: the thickness of a slab, the eave of a roof, the height of a room and the base of a stair.

The element changes while the user drags. One drag is one `reshape` command.

## Add undo and redo

The manager has one history for the building, the views and the sheets. The undo key in the editor uses the same history.

```typescript theme={null}
export function sceneActions(manager: ProjectManager) {
  return {
    undo: () => manager.undo(),
    redo: () => manager.redo(),
  };
}
```

`undo()` and `redo()` return the new revision, or `null` when there is no step.

## Remove the editor

You made the editor, so you dispose it. Then remove the project.

```typescript theme={null}
export function closeSceneEditor(
  scene: THREE.Scene,
  manager: ProjectManager,
  editor: GUIEditor,
): void {
  editor.dispose();
  scene.remove(manager.root);
  manager.dispose();
}
```

## Rules

* The container must be the element that the canvas fills. The editor uses its size to place the handles.
* An object with an `enabled` property is sufficient for `controls`. `OrbitControls` has one.
* The plan editors and the 3D editor of one manager use the same `hostedOpeningDetachTolerance`. Set it in the options of the manager.
* The manager does not dispose the `GUIEditor`. Dispose the editor before you dispose the manager.

## Without the manager

If your app makes the `BuildingSession` itself, connect the editor with `bindManagedSceneEditor`. See the [bindManagedSceneEditor API](/floorkit/api/editor/bind-managed-scene-editor).

## Next

<CardGroup cols={2}>
  <Card title="GUIEditor API" icon="code" href="/floorkit/api/editor/gui-editor">
    See each member of the 3D editor.
  </Card>

  <Card title="ProjectManager API" icon="code" href="/floorkit/api/editor/project-manager">
    See each member of the manager and the project commands.
  </Card>
</CardGroup>


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