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

# Make objects come alive

> Give objects grips, adjustable physics, exposed properties and agent-written behavior, then share complete editable versions.

A Figment is an interactive object built from an existing Spatial creation. Its definition adds named parts, grips, properties, actions, and local JavaScript behavior. Geometry can come from [Blender](/spatial/blender), a primitive, or an assembly of objects.

A lamp can pulse while you carry it. A machine can expose motor speed and spring stiffness. A crystal can react to impacts. Agents can write the behavior themselves; presets are editable starting points.

## Try a Figment

[Download the working lantern tool calls](/assets/figment-lantern.json). Ask your agent to execute them in order. The example creates a glowing orb, attaches the lantern preset, adds a grip and adjustable physics, and starts its behavior. This is a tool-call recipe, not a package for the Import button.

Open **Objects**, select the lantern, and change its light, brightness, pulse, or tint. **Toggle light** invokes its action. Double-clicking the object or pressing **E** invokes its first action. In XR, squeeze the controller while holding it. A trigger or pinch near a grip aligns the object with the hand; two-hand grips can aim an object or scale it.

The drawer shows whole creations by default. **Show parts** reveals their components. **Duplicate** copies a Figment's complete assembly and remaps its references; **Delete** removes the assembly.

## Agent tools

The Figment bundle extends the existing Spatial tools. These tools work from a connected Spatial conversation or another surface, such as Telegram, belonging to the same Entity.

| Tool                  | Commands                                                   |
| --------------------- | ---------------------------------------------------------- |
| `ar_figment`          | `capabilities`, `inspect`, `attach`, `configure`, `detach` |
| `ar_figment_physics`  | `physics`                                                  |
| `ar_figment_behavior` | `behavior`                                                 |
| `ar_figment_interact` | `properties`, `action`                                     |
| `ar_figment_library`  | `library`, `publish`, `export`, `import`, `place`          |

Start with `ar_figment capabilities` for the current contract and preset source. Direct provider bindings expose the same names without the `ar_` prefix. Every command returns a correlated renderer result; a timeout means execution is unknown, so do not blindly replay placement.

## Attach a definition

Create or load the geometry first, then inspect its real ID. The following call attaches an editable lantern to the `lantern` object created by the downloadable recipe:

```json theme={"theme":"github-light-default"}
{
  "name": "ar_figment",
  "arguments": {
    "command": "attach",
    "payload": {
      "id": "lantern",
      "preset": "lantern",
      "definition": {
        "title": "Pocket lantern",
        "version": "1.0.0",
        "anchors": {
          "handle": { "position": [0, 0.1, 0], "rotation": [0, 0, 0] }
        },
        "grips": {
          "hold": { "anchor": "handle", "hand": "either", "twoHand": "aim" }
        }
      }
    }
  }
}
```

`attach` and `configure` merge top-level definition fields. Named maps replace in full, so include every entry you want to retain. New or changed behavior starts paused unless `start: true` is supplied. Editing a title, grip, or physical property preserves unchanged behavior state.

| Definition field                  | Meaning                                                                        |
| --------------------------------- | ------------------------------------------------------------------------------ |
| `protocol`                        | `ngram.figment/1`; filled automatically when omitted                           |
| `title`, `description`, `version` | Human-readable identity; version uses `major.minor.patch`                      |
| `parts`                           | Names mapped to entity IDs; `self` always refers to the Figment root           |
| `joints`                          | Names mapped to world joint IDs whose bodies are named parts                   |
| `anchors`                         | Named positions and rotations, with optional `part` and unique GLB `node` name |
| `grips`                           | Named grips referencing an anchor; `hand`, grab `radius`, and `twoHand` mode   |
| `properties`                      | Typed values with labels, editability, and optional numeric bounds             |
| `actions`                         | Named actions mapped to `{ "label": "Button label" }`                          |
| `behavior`                        | `{ "source": "JavaScript", "hz": 20 }`                                         |
| `source`                          | Optional `{ "url": "...", "filename": "project.blend" }`                       |

Figment roots are world roots. Parts cannot belong to two Figments. Children of a named group travel with the assembly. Separate physical parts remain world roots and connect through joints.

Anchors use part-local metres and Euler XYZ radians. A `node` selects a uniquely named node inside an imported GLB. Missing or ambiguous nodes are reported rather than silently attaching a grip to another location. Keep Blender node names stable across mesh revisions. In the **Grips** section, you can inspect these errors, reveal markers, adjust offsets, and choose hand or two-hand behavior.

## Write behavior

Agent-authored JavaScript uses the same sandbox as [creation programs](/spatial/programs). It returns `tick`, `event`, or both. This example changes the lantern when its action fires:

```javascript theme={"theme":"github-light-default"}
return {
  event(e) {
    if (e.type === "action" && e.data.action === "toggle") {
      api.setProperty("on", !api.property("on"));
    }
  },
  tick() {
    api.patch("self", {
      material: {
        emissive: api.property("tint"),
        glow: api.property("on") ? api.property("brightness") : 0
      }
    });
  }
};
```

Install it through `ar_figment_behavior` with `command: "behavior"` and `payload: {id, source, hz, start}`. Without source, use `payload: {id, action: "pause"}`, `"resume"`, or `"reset"`. Reset clears behavior state and leaves it paused. Resuming a behavior also resumes world physics; other paused programs stay paused.

| API                                    | Purpose                                                                            |
| -------------------------------------- | ---------------------------------------------------------------------------------- |
| `api.self`, `api.part(name)`           | Live root or named-part snapshot, including `heldBy`                               |
| `api.anchor(name)`                     | Resolved world position and quaternion, readiness or error                         |
| `api.property(name)`                   | Current typed property value                                                       |
| `api.setProperty(name, value)`         | Change a property through validation                                               |
| `api.patch(part, patch)`               | Patch a named part's transform, geometry, material, control, visibility or physics |
| `api.impulse(part, xyz, torque?)`      | Apply a physical impulse to a dynamic part                                         |
| `api.motor(name, velocity, strength?)` | Drive a named hinge or slider                                                      |
| `api.signal(name, data)`               | Emit a local signal event for this Figment                                         |
| `api.state`, `api.time`, `api.dt`      | Persistent JSON state and local simulation timing                                  |

Use named bindings instead of hard-coded instance IDs so imported copies run the same source. Programs cannot create/delete objects, install code, use the DOM, import modules, or access the network. Humans retain physical control while holding an object; its properties, glow and other nonphysical responses can continue to work.

Events include `action` (`data.action`), `property` (`data.name`, `data.value`), `grab`, `grip`, `release`, `collision`, `collision.end`, `sensor.enter`, `sensor.exit`, and `signal`. See [Physics](/spatial/physics) for contact data. Events and animation never trigger model inference.

`ar_figment inspect` accepts `payload: {id, includeSource: true}` when you need the source. Routine observations omit source text. Figment behaviors share the world's 12-program budget, run at 1–30 Hz, and have a 60,000-character authoring limit. Keep each tick small.

## Publish and share

**Objects → Publish & share → Publish version** freezes a version in this browser's Figment library. A published title/version cannot be replaced with different content; increase its version to publish a revision.

The package contains the assembly, its physical settings and joints, grips, typed properties, and editable JavaScript. Model assets are included by content hash. Linked Blender projects also include their matching `.blend` revision; custom sources can be supplied explicitly. Source files remain available through **Download Blender source**.

**Export to share** downloads a `.figment.json` file. Send that file through your preferred channel. Another person can choose **Figment library → Import Figment**, then **Place**. Imported assets are checked against SHA-256 hashes and package boundaries. The placed copy receives new IDs and remains paused until resumed.

Agent equivalents:

| Command   | Payload                                                           |
| --------- | ----------------------------------------------------------------- |
| `publish` | `{ "id": "lantern" }`                                             |
| `library` | `{}`                                                              |
| `export`  | `{ "packageId": "published SHA-256 ID" }`                         |
| `import`  | `{ "url": "package URL", "place": false }`, or a `package` object |
| `place`   | `{ "packageId": "published SHA-256 ID", "position": [0, 1, -1] }` |

Export starts a download on the human's device and returns a small receipt; it does not stream model binaries into the conversation. Publishing is a local library operation. There is no hosted public gallery or cloud synchronization in this version.

Packages allow 128 MB of combined binary content and 192 MB of serialized JSON. Rendered GLBs retain the 32 MB and 100,000-source-vertex limits. Binary assets and published versions live in IndexedDB; active worlds and program checkpoints use the existing creation storage. Export packages for backups: clearing site data removes the local library, and a world JSON alone does not carry packaged binary assets.
