A comprehensive operational transformation (OT) system for real-time collaborative 3D model editing, similar to Google Docs but for 3D models.
- Operational Transformation Engine: Conflict resolution for concurrent edits
- Generic 3D Format: Based on glTF 2.0 as interchange format
- Multi-Platform Support: Live editing adapters for:
- Blender - Popular open-source 3D creation suite
- SceneKit/ARKit - Apple's 3D graphics framework
- RealityKit/ModelEntities - Apple's AR framework
- SketchUp - 3D modeling for design
- ARCore - Google's AR platform
┌─────────────────────────────────────────────────────────────┐
│ EditSpace System │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ OT Engine │◄────►│ Operations │ │
│ └──────────────┘ └──────────────┘ │
│ ▲ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ glTF Model (Interchange) │ │
│ └──────────────────────────────────────────┘ │
│ ▲ │
│ │ │
│ ┌──────┴───────┬─────────┬──────────┬──────────┐ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ Blender SceneKit RealityKit SketchUp ARCore │
│ Adapter Adapter Adapter Adapter Adapter │
└─────────────────────────────────────────────────────────────┘
npm install optransform3dimport {
CollaborativeSession,
BlenderAdapter,
Operation,
OperationType
} from 'optransform3d';
// Initialize session with Blender adapter
const adapter = new BlenderAdapter();
const session = new CollaborativeSession(adapter);
// Load initial model
const blenderModel = {
objects: [{
name: 'Cube',
type: 'MESH',
location: [0, 0, 0],
scale: [1, 1, 1]
}]
};
await session.initialize(blenderModel);
// Create and apply operations
const translateOp = new Operation(OperationType.TRANSLATE, {
targetId: 'Cube',
x: 5, y: 0, z: 0
});
session.applyLocalOperations([translateOp]);
// Sync with remote users
const remoteOps = getRemoteOperations(); // From network
session.applyRemoteOperations(remoteOps);import {
BlenderAdapter,
SceneKitAdapter,
RealityKitAdapter
} from 'optransform3d';
// User 1 with Blender
const blenderAdapter = new BlenderAdapter();
const gltfModel = await blenderAdapter.importModel(blenderData);
// User 2 with SceneKit
const sceneKitAdapter = new SceneKitAdapter();
const sceneKitModel = await sceneKitAdapter.exportModel(gltfModel);
// User 3 with RealityKit
const realityKitAdapter = new RealityKitAdapter();
const realityKitModel = await realityKitAdapter.exportModel(gltfModel);
// All users work on the same model in their preferred tool!The system supports various 3D operations:
TRANSLATE- Move objects in 3D spaceROTATE- Rotate objectsSCALE- Scale objects
ADD_MESH- Add new mesh to sceneDELETE_MESH- Remove mesh from sceneUPDATE_MESH- Modify mesh geometry
ADD_VERTEX- Add vertex to meshDELETE_VERTEX- Remove vertex from meshMOVE_VERTEX- Move vertex position
ADD_MATERIAL- Add new materialDELETE_MATERIAL- Remove materialUPDATE_MATERIAL- Modify material properties
ADD_NODE- Add scene nodeDELETE_NODE- Remove scene nodeUPDATE_NODE- Update node properties
ADD_LIGHT,DELETE_LIGHT,UPDATE_LIGHTADD_CAMERA,DELETE_CAMERA,UPDATE_CAMERA
import { BlenderAdapter } from 'optransform3d';
const adapter = new BlenderAdapter();
// Import from Blender Python API format
const blenderData = {
objects: [{
name: 'Cube',
type: 'MESH',
location: [0, 0, 0],
rotation_euler: [0, 0, 0],
scale: [1, 1, 1],
data: { /* mesh data */ }
}]
};
const gltfModel = await adapter.importModel(blenderData);
const exportedBlender = await adapter.exportModel(gltfModel);import { SceneKitAdapter } from 'optransform3d';
const adapter = new SceneKitAdapter();
// Import from SceneKit format
const sceneKitData = {
rootNode: {
name: 'Root',
position: { x: 0, y: 0, z: 0 },
childNodes: [/* ... */]
}
};
const gltfModel = await adapter.importModel(sceneKitData);import { RealityKitAdapter } from 'optransform3d';
const adapter = new RealityKitAdapter();
// Import from RealityKit Entity format
const realityKitData = {
entities: [{
name: 'Box',
transform: {
translation: { x: 0, y: 0, z: 0 },
rotation: { x: 0, y: 0, z: 0, w: 1 },
scale: { x: 1, y: 1, z: 1 }
}
}]
};
const gltfModel = await adapter.importModel(realityKitData);import { SketchUpAdapter } from 'optransform3d';
const adapter = new SketchUpAdapter();
// Import from SketchUp format
const sketchUpData = {
entities: [{
type: 'ComponentInstance',
transformation: { origin: [0, 0, 0] }
}]
};
const gltfModel = await adapter.importModel(sketchUpData);import { ARCoreAdapter } from 'optransform3d';
const adapter = new ARCoreAdapter();
// Import from ARCore Sceneform format
const arCoreData = {
nodes: [{
name: 'Box',
localPosition: { x: 0, y: 0, z: 0 },
localRotation: { x: 0, y: 0, z: 0, w: 1 },
localScale: { x: 1, y: 1, z: 1 }
}]
};
const gltfModel = await adapter.importModel(arCoreData);- Concurrent Edits: Multiple users edit the same 3D model simultaneously
- Operation Generation: Each edit generates an Operation object
- Transformation: When operations conflict, the OT engine transforms them
- Convergence: All clients converge to the same final state
// User A moves cube right: (0,0,0) → (5,0,0)
const opA = new Operation(OperationType.TRANSLATE, {
targetId: 'Cube',
x: 5, y: 0, z: 0
});
// User B moves cube up: (0,0,0) → (0,3,0)
const opB = new Operation(OperationType.TRANSLATE, {
targetId: 'Cube',
x: 0, y: 3, z: 0
});
// OT Engine transforms operations
const { op1Prime, op2Prime } = engine.transform(opA, opB);
// Final position converges to (5,3,0) for both usersnpm testRun the included examples:
# Basic collaborative editing
npm run example
# Or run directly
node examples/basic-usage.js
node examples/multi-adapter.jstransform(op1, op2)- Transform two concurrent operationsapply(operation)- Apply operation to historygetOperationsSince(version)- Get operations since versionconflictsWith(op1, op2)- Check if operations conflict
initialize(nativeModel)- Initialize session with modelapplyLocalOperations(ops)- Apply local user operationsapplyRemoteOperations(ops)- Apply and transform remote operationsgetModel()- Get current glTF modelgetNativeModel()- Get model in native formatgetPendingOperations(since)- Get operations to sync
All adapters inherit from BaseAdapter:
importModel(nativeModel)- Import to glTFexportModel(gltfModel)- Export from glTFapplyOperations(model, ops)- Apply operationsextractOperations(oldModel, newModel)- Extract operations
- Real-time collaborative 3D modeling across different platforms
- Multi-user AR experiences with live model updates
- Remote design collaboration between different tools
- Educational environments with synchronized 3D scenes
- Game development with collaborative level editing
- Architecture visualization with team collaboration
The system uses glTF 2.0 as the universal interchange format because:
- Industry-standard 3D format
- Efficient transmission over networks
- Supports all major 3D features (meshes, materials, animations, etc.)
- Wide platform support
The OT engine handles conflicts using transformation functions:
- Transform composition for geometric operations
- Priority-based resolution for conflicting edits
- Maintains causality and convergence properties
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE file for details
- Based on Operational Transformation theory from collaborative text editing
- Inspired by Google Docs' real-time collaboration
- Uses glTF 2.0 specification from the Khronos Group