A Remote class has been added to compas_threejs.viewer that enables connecting to a running App instance via websocket and sending geometry updates to it. This allows multiple Remote instances to update a single App from different terminals or processes.
-
src/compas_threejs/viewer/remote.py(NEW)- Main
Remoteclass implementation - ~460 lines of code
- Full API matching the App for geometry operations
- Main
-
src/compas_threejs/viewer/__init__.py(MODIFIED)- Added
Remoteto exports - Updated
__all__list
- Added
docs/remote.md(NEW)- Comprehensive documentation for the Remote class
- Usage examples
- API reference
- Use cases and best practices
-
examples/remote_viewer.py(NEW)- Simple App server setup
- Entry point for testing Remote functionality
-
examples/remote_client.py(NEW)- Basic Remote client example
- Adds random boxes and spheres
-
examples/remote_animated.py(NEW)- Advanced example with real-time animation
- Demonstrates continuous updates
-
examples/remote.py(UPDATED)- Simple standalone example
- Good starting point for new users
-
examples/test_remote.py(NEW)- Import and instantiation test
- Verifies basic functionality
-
examples/REMOTE_EXAMPLES.md(NEW)- Guide for all Remote examples
- Quick start instructions
- Troubleshooting tips
- Connect to App via websocket (
ws://host:port/ws) - Automatic message queueing before connection
- Clean disconnect handling
- Context manager support
All main App methods are supported:
add_geometry()- Add geometry with optional material and metadataadd_geometries()- Add multiple geometries at onceupdate_geometry()- Update existing geometryremove_object()- Remove geometry from viewerupdate_metadata()- Update object metadataadd_text()- Add text labelsadd_light()/update_light()- Lighting controlupdate_material()- Material updatesadd_ui_element()- UI elements
Properties that can be set:
camera_position- Camera position in 3D spacecamera_target- Camera target pointcamera_fov- Field of viewcamera_zoom- Zoom levelcamera_damping- Damping enabled/disabledbackground_color- Background colordark_mode- Dark mode toggleshow_edges- Edge visibility
┌─────────────────┐
│ App Server │ (Terminal 1)
│ Port: 9001 │
└────────┬────────┘
│ WebSocket
│
┌────┴────┬────────┬────────┐
│ │ │ │
┌───┴───┐ ┌───┴───┐ ┌──┴──┐ ┌──┴──┐
│Remote1│ │Remote2│ │ ... │ │ ... │
│(Term2)│ │(Term3)│ │ │ │ │
└───────┘ └───────┘ └─────┘ └─────┘
from compas_threejs.viewer import App
viz = App()
viz.start(show=True)from compas.geometry import Box
from compas_threejs.viewer import Remote
remote = Remote()
remote.connect()
box = Box(1, 1, 1)
remote.add_geometry(box)
remote.disconnect()websockets- Already in project dependenciesasyncio- Standard librarythreading- Standard library- All other dependencies same as App
- Uses same binary protocol as App (compas_pb)
- Messages queued if not connected
- Automatic retry on connection
- Uses asyncio event loop in separate thread
- Thread-safe message sending via
asyncio.run_coroutine_threadsafe() - Message queueing for pre-connection calls
Run the test to verify installation:
python examples/test_remote.pyFull integration test:
# Terminal 1
python examples/remote_viewer.py
# Terminal 2
python examples/remote_client.py- One-way communication: Remote sends to App but doesn't receive UI callbacks
- No scene state sync: Remote doesn't receive existing scene state on connect
- Connection required: Must connect before geometry appears (though messages are queued)
- Add callback support for UI elements
- Sync scene state on connection
- Automatic reconnection on disconnect
- Connection status callbacks
- Batch message sending for efficiency
The Remote class follows these design principles:
- API Parity: Same interface as App for easy switching
- Minimal Dependencies: No new dependencies required
- Clean Architecture: Separation of connection and messaging logic
- User-Friendly: Context managers, automatic queueing, clear error messages
- Thread-Safe: Safe to use from multiple threads