> For the complete documentation index, see [llms.txt](https://multiset.gitbook.io/multiset/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://multiset.gitbook.io/multiset/webxr-sdk/api-reference/mapspace.md).

# MapSpace

```typescript
import { MapSpace } from '@multisetai/vps/three';
```

`MapSpace` marks one object as the origin of the scanned map. Nest your map-anchored content underneath it, and on every successful localization the frame is moved so its origin coincides with the map's origin. Every descendant follows by ordinary parenting.

**A child's local position is therefore its map coordinate.** You can paste a value straight from the portal's Map Viewer into a child's Transform.

This is what makes relocalization cheap. Only one transform changes, so anything computed relative to the frame stays valid: no re-anchoring, no recompute, and no visible jump when localization runs again in the background.

### Two forms

| Form             | Import                                             | Use in                                                           |
| ---------------- | -------------------------------------------------- | ---------------------------------------------------------------- |
| Package class    | `import { MapSpace } from '@multisetai/vps/three'` | Plain Three.js, or from code in a Needle project                 |
| Needle component | `import { MapSpace } from './MapSpace.js'`         | Unity, as a template file copied into your `src/scripts/` folder |

The Needle component is a thin `Behaviour` that owns a package `MapSpace` bound to its GameObject and forwards to it, so behaviour is identical. The Unity to Three.js handedness correction lives in the package class, which keeps one verified implementation rather than a copy in every project.

Copy the template into your project with:

```bash
cp node_modules/@multisetai/vps/templates/MapSpace.ts <your-web-folder>/src/scripts/
```

### Constructor

```typescript
const mapSpace = new MapSpace(new THREE.Object3D(), { hideUntilLocalized: true });
scene.add(mapSpace.object);
mapSpace.connect(adapter);
```

| Parameter | Type               | Description                                                        |
| --------- | ------------------ | ------------------------------------------------------------------ |
| `object`  | `THREE.Object3D`   | The object to use as the map frame. Add it to your scene yourself. |
| `options` | `IMapSpaceOptions` | Optional. See below.                                               |

### Options and fields

| Name                 | Type      | Default | Description                                                                                                                                                                                                      |
| -------------------- | --------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hideUntilLocalized` | `boolean` | `true`  | Hide the object until the first localization, and re-hide it when the session ends. This is a public mutable field, read live, so you can set it to `false` at runtime to keep content visible between sessions. |

### Properties

| Property      | Type             | Description                                                               |
| ------------- | ---------------- | ------------------------------------------------------------------------- |
| `object`      | `THREE.Object3D` | The wrapped object. Add this to your scene, and parent map content to it. |
| `isLocalized` | `boolean`        | `true` once a localization has been applied in the current session.       |

### Methods

| Method                                                       | Description                                                                                                                                                                                                                                                                                                                                                    |
| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `connect(adapter: IVpsAdapter)`                              | Subscribe to an adapter so the frame is positioned on every localization. Accepts `ThreeAdapter` or `NeedleAdapter`. Safe to call more than once, since previous subscriptions are removed first. If the adapter has already localized in the current session, that result is replayed immediately, so a `MapSpace` created mid-session is positioned at once. |
| `disconnect()`                                               | Remove every subscription made by `connect()`.                                                                                                                                                                                                                                                                                                                 |
| `applyLocalization(result, worldFromMap)`                    | Position the frame directly, bypassing events. Useful in tests, or from a component that receives the result by another route.                                                                                                                                                                                                                                 |
| `add(object: THREE.Object3D, mapCoordinate?: THREE.Vector3)` | Parent an object to the frame, optionally at a map coordinate.                                                                                                                                                                                                                                                                                                 |
| `mapToWorld(v: THREE.Vector3, target?)`                      | Convert map space to world space.                                                                                                                                                                                                                                                                                                                              |
| `worldToMap(v: THREE.Vector3, target?)`                      | Convert world space to map space. Use this to convert the camera pose before any map-space calculation.                                                                                                                                                                                                                                                        |
| `dispose()`                                                  | Same as `disconnect()`.                                                                                                                                                                                                                                                                                                                                        |

### Static methods

| Method                                                 | Description                                                                                  |
| ------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
| `MapSpace.toLocal(unityCoord: THREE.Vector3, target?)` | Convert a Unity (left-handed) coordinate copied from the portal's Map Viewer into map space. |

Content authored in the Unity editor gets this conversion from Needle's exporter and must **not** use `toLocal`. Content created in code does need it:

```typescript
const marker = new THREE.Mesh(geometry, material);
mapSpace.add(marker, MapSpace.toLocal(new THREE.Vector3(1.5, 0, -2.0)));
```

### Hiding behavior

{% hint style="warning" %}
`hideUntilLocalized` hides the entire subtree. Needle Engine treats an invisible GameObject as inactive, and an inactive component never runs `start()` or `update()`. Keep always-running logic (session listeners, UI, network polling, navigation) on a GameObject **outside** the `MapSpace` hierarchy, or it will never start.
{% endhint %}

### In Unity

`MultisetVPS` discovers and wires all `MapSpace` components at startup. A scene should contain exactly one. `MultisetVPS` logs a warning if it finds more, because they would all be moved to the same origin.

The Needle component exposes `connectAdapter(adapter)` and `applyLocalization(result, worldFromMap)`, matching [MapAnchor](/multiset/webxr-sdk/api-reference/mapanchor.md), so it can also be registered at runtime with `NeedleAdapter.registerAnchor(mapSpace)`.

Reach the underlying package object through `.space`:

```typescript
const camMap = mapSpace.space.worldToMap(camera.getWorldPosition(new THREE.Vector3()));
```

### MapSpace or MapAnchor

| Use                                                     | Component                                                                                  |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| A layout of several objects, authored in the editor     | `MapSpace`                                                                                 |
| Navigation                                              | `MapSpace`, which is required                                                              |
| One object that must **not** inherit the map's rotation | [MapAnchor](/multiset/webxr-sdk/api-reference/mapanchor.md) with `matchOrientation: false` |
| One object in a scene that has no `MapSpace`            | [MapAnchor](/multiset/webxr-sdk/api-reference/mapanchor.md)                                |

`MapSpace` is the preferred model for anything with more than one anchored object, because the layout you build in the editor is the layout you get in AR, with no per-object component and no offset fields to keep in sync.

{% hint style="warning" %}
Do not nest a `MapAnchor` inside a `MapSpace`. Both would apply the map transform, so the offset is applied twice.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://multiset.gitbook.io/multiset/webxr-sdk/api-reference/mapspace.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
