@needle-tools/editor-sync
v3.0.0
Published
Package providing hooks to connect and apply changes from external editors to the Needle Engine runtime scene
Downloads
270
Readme
@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
npm install @needle-tools/editor-syncUsage
Import the package in your Needle Engine project to enable editor sync at runtime:
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:
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:
{
"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:
{
"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:
{
"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":
{ "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:
{
"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:
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 |
