npm package: @needle-tools/editor-sync
Description: Package providing hooks to connect and apply changes from external editors to the Needle Engine runtime scene
Author: Needle
Latest version: 3.0.0

# @needle-tools/editor-sync

Package providing hooks to connect and apply changes from external editors (like Unity or Blender) to the Needle Engine runtime three.js scene in real-time.

## Installation

```bash
npm install @needle-tools/editor-sync
```

## Usage

Import the package in your Needle Engine project to enable editor sync at runtime:

```ts
import "@needle-tools/editor-sync";
```

This registers the necessary hooks automatically. The package listens for editor connections and applies incoming property changes to the three.js scene.

To send property changes back to the editor from your components, use `notifyPropertyChanged`:

```ts
import { notifyPropertyChanged } from "@needle-tools/editor-sync";

// Notify the editor that a property was changed at runtime
notifyPropertyChanged(myObject, "position", myObject.position);
```

## How It Works

Editor sync enables real-time property modifications between an external editor and a running Needle Engine web app. Communication happens over **Vite HMR** (Hot Module Replacement) WebSocket channels.

### Architecture Overview

```
┌──────────────┐    WebSocket (Vite HMR)    ┌──────────────────┐
│  Editor Tool  │ ◄────────────────────────► │  Needle Engine   │
│  (Unity, etc) │    needle:editor:* msgs    │  (Web Runtime)   │
└──────────────┘                             └──────────────────┘
       │                                              │
       │  Exports glTF with                           │  Loads glTF and
       │  NEEDLE_editor extension                     │  registers objects
       │  containing object GUIDs                     │  by GUID in Registry
       ▼                                              ▼
  ┌──────────┐                                ┌──────────────┐
  │ .glb/.gltf│ ──────────────────────────── │ Three.js Scene│
  └──────────┘                                └──────────────┘
```

## Integrating a New Editor Tool

To add editor sync support for a new editor (e.g. Godot, custom tool), you need to implement the following:

### 1. Connect via Vite HMR

The web runtime communicates through Vite's HMR WebSocket. Your editor needs to connect to the Vite dev server's WebSocket and exchange messages using the HMR protocol.

### 2. Embed GUIDs in glTF Exports

When exporting scenes to glTF/GLB, add the `NEEDLE_editor` extension to nodes and materials:

```json
{
  "nodes": [{
    "name": "MyCube",
    "extensions": {
      "NEEDLE_editor": { "id": "unique-guid-for-this-object" }
    }
  }],
  "materials": [{
    "name": "MyMaterial",
    "extensions": {
      "NEEDLE_editor": { "id": "unique-guid-for-this-material" }
    }
  }]
}
```

The web runtime uses these GUIDs to map editor objects to three.js objects in the scene.

### 3. Send Property Modifications

Send property changes as HMR messages on the `needle:editor:modified-property` channel:

```json
{
  "type": "needle:editor:modified-property",
  "data": {
    "guid": "object-guid",
    "propertyName": "position",
    "value": { "x": 0, "y": 1, "z": 0 }
  }
}
```

### 4. Property Name Mapping

Properties use **glTF conventions** for materials and standard names for transforms:

| Editor Property | Sync Property Name | Value Format |
|---|---|---|
| Position | `position` | `{ x, y, z }` |
| Rotation | `rotation` | `{ x, y, z, w }` (quaternion) |
| Scale | `scale` | `{ x, y, z }` |
| Base Color | `baseColorFactor` | `{ r, g, b, a }` (linear) |
| Base Color Texture | `baseColorTexture` | data URI (see below) |
| Metallic | `metallicFactor` | number |
| Roughness | `roughnessFactor` | number |
| Normal Map | `normalTexture` | data URI |
| Normal Scale | `normalTextureScale` | `{ x, y }` |
| Emission Color | `emissiveFactor` | `{ r, g, b }` (linear) |
| Emission Map | `emissiveTexture` | data URI |
| Occlusion Map | `occlusionTexture` | data URI |
| Occlusion Strength | `occlusionStrength` | number |

### 5. Texture Encoding

Textures are sent as base64 data URIs with metadata:

```json
{
  "type": "texture",
  "data": "data:image/png;base64,iVBOR...",
  "filter": 1,
  "anisotropy": 1,
  "wrap": 0,
  "name": "my-texture"
}
```

| Filter | Value | Wrap | Value |
|---|---|---|---|
| Point | 0 | Repeat | 0 |
| Bilinear | 1 | Clamp | 1 |
| Trilinear | 2 | Mirror | 2 |

Supported formats: PNG, JPEG, EXR, HDR.

### 6. Scene Camera Sync

Sync the editor's scene camera using the special guid `"scene-camera"`:

```json
{ "guid": "scene-camera", "propertyName": "enabled",  "value": true }
{ "guid": "scene-camera", "propertyName": "position", "value": { "x": 0, "y": 1, "z": 5 } }
{ "guid": "scene-camera", "propertyName": "rotation", "value": { "x": 0, "y": 0, "z": 0, "w": 1 } }
{ "guid": "scene-camera", "propertyName": "fov",      "value": 60 }
{ "guid": "scene-camera", "propertyName": "near",     "value": 0.1 }
{ "guid": "scene-camera", "propertyName": "far",      "value": 1000 }
```

### 7. Listen for Changes from the Web Runtime

The web runtime can send property changes back to the editor on the `needle:editor` channel:

```json
{
  "type": "needle:editor:propertyChanged",
  "data": {
    "id": "object-guid",
    "property": "position",
    "value": { "x": 1, "y": 2, "z": 3 }
  }
}
```

### 8. Custom Component Handling

Components can implement `IEditorModificationListener` for custom modification logic:

```typescript
import type { EditorModification, IEditorModificationListener } from "@needle-tools/editor-sync";

class MyComponent implements IEditorModificationListener {
    onEditorModification(mod: EditorModification): boolean {
        // Return false to use default behavior
        // Return true to handle it yourself
        return false;
    }
    onAfterEditorModification(mod: EditorModification): void {
        // Called after modification is applied
    }
}
```

## Debug Parameters

| URL Parameter | Description |
|---|---|
| `?debugeditor` | Enable debug logging |
| `?noeditor` | Disable editor sync |
| `?editorid=<id>` | Set editor instance ID |

## Links

- [Needle Engine](https://needle.tools)
- [Documentation](https://engine.needle.tools/docs)
- [Discord](http://discord.needle.tools)
- [GitHub Issues](https://github.com/needle-tools/needle-engine-support/issues)

## Contact

[Needle](https://needle.tools) | [@NeedleTools](https://twitter.com/NeedleTools) | [@marcel_wiessler](https://twitter.com/marcel_wiessler) | [@hybridherbst](https://twitter.com/hybridherbst)