How ninsent/plasticity-c4d-plugin works
Purpose and Plugin Entry
This is a Cinema 4D 2023+ Python plugin that bridges Plasticity CAD and C4D over WebSocket, supporting live inbound mesh sync and capability-gated outbound uploads. The plugin entry module registers the command/dialog and Auto-Refacet tag integration: plasticity_c4d.pyp. UI orchestration begins in dialogs/main_dialog.py.
Runtime and External Boundary
Cinema 4D is the host runtime and its scene API must run on its main thread. Plasticity is an external CAD process exposing a binary WebSocket server, normally localhost:8980. WebSocket transport is vendored, so deployment requires no package install: libs/websockets/client.py, libs/websockets/connection.py, and libs/websockets/legacy/protocol.py.
Connection, Protocol, and Feature Negotiation
core/client.py owns the background WebSocket client lifecycle: connect/disconnect, receive binary messages, and send commands. core/protocol.py defines the Plasticity-compatible little-endian, aligned binary message encoding/decoding and message layouts. Connection begins with HANDSHAKE_1; server-advertised capabilities determine whether features such as PUT_SOME_1 uploads are enabled.
Threading Boundary and Event Dispatch
The client thread never modifies the C4D document. Parsed network events cross through a thread-safe queue/callback bridge in core/threading_bridge.py. The dialog timer drains that bridge at roughly 60 FPS and dispatches work on the C4D main thread, linking dialogs/main_dialog.py to the scene layer. This is the repository’s principal concurrency and API-safety boundary.
Scene Synchronization and Geometry Lifecycle
core/handler.py is the main-thread scene controller. It maps Plasticity file/group/solid data into the C4D root hierarchy: root null, protected Outbox, and inbound Inbox. Incoming geometry updates replace mesh data in place so existing user materials, animation, constraints, and non-managed tags survive. It also handles coordinate conversion (Z-up to Y-up), meter-to-centimeter scaling, reversed winding, managed normals, CAD face/edge selections, topology modes, and refresh/live-link updates.
Refacet and Persistent Per-Object Settings
Refaceting is coordinated by scene handling and the custom tag implementation in core/refacet_tag.py. The tag persists tessellation/topology parameters on individual C4D objects; subsequent refreshes or live updates can reapply them automatically. C4D resource definitions expose that tag and its Attribute Manager fields: res/description/tplasticityrefacet.res, res/description/tplasticityrefacet.h, and res/strings_us/description/tplasticityrefacet.str.
Bidirectional Content Boundary
Inbound Plasticity objects are managed beneath Inbox; they are eligible for synchronization. User-authored content belongs in Outbox and is protected from incoming replacement. On refresh, supported polygon/SDS and evaluated parametric-generator content can be resolved and serialized into PUT_SOME_1 requests through core/handler.py, core/client.py, and core/protocol.py. Server handshake support is required before this upload path is used.
Main entry points: client.py WebSocket client · handler.py Scene handler · refacet_tag.py Auto-Refacet tag · threading_bridge.py Threading bridge
Components 15
Cinema 4D Host
Main-thread UI, scene API, and plugin resources.
- Plugin entry · Registers the command, dialog, and Auto-Refacet tag integration.
plasticity_c4d.pyp - Main dialog · Drains network events on the C4D main thread.
dialogs/main_dialog.py - Refacet resources · Defines the tag and Attribute Manager fields.
res/description/tplasticityrefacet.res - Inbox hierarchy · Inbound Plasticity objects eligible for synchronization.
- Outbox hierarchy · User-authored content eligible for outbound upload.
Sync Core
Connection, protocol, dispatch, and scene synchronization.
- Scene handler · Maps CAD data into C4D and preserves user-authored scene state.
core/handler.py - Auto-Refacet tag · Persists per-object tessellation and topology settings.
core/refacet_tag.py - Threading bridge · Thread-safe boundary between client and C4D main thread.
core/threading_bridge.py - WebSocket client · Owns connection lifecycle, binary receive, and command send.
core/client.py - Binary protocol · Encodes and decodes Plasticity-compatible binary messages.
core/protocol.py - Capability handshake · Server capabilities gate outbound uploads.
- Geometry lifecycle · Performs conversion, in-place replacement, selections, normals, and topology handling.
core/handler.py - PUT_SOME_1 upload · Serializes supported polygon, SDS, and evaluated generator content.
core/handler.py
External Boundary
Plasticity CAD and vendored WebSocket transport.
- Vendored WebSocket · Bundled client transport requiring no package installation.
libs/websockets/client.py - Plasticity CAD · Binary WebSocket server, normally localhost:8980.
Connections 19
- Plugin entry → Main dialog: opens
- Plugin entry → Auto-Refacet tag: registers
- Refacet resources → Auto-Refacet tag: defines UI
- Main dialog → Threading bridge: drains at ~60 FPS
- Threading bridge → Scene handler: main-thread events
- WebSocket client → Threading bridge: parsed network events
- WebSocket client → Binary protocol: encodes and decodes
- WebSocket client → Vendored WebSocket: uses
- Vendored WebSocket → Plasticity CAD: binary WebSocket
- WebSocket client → Capability handshake: starts with HANDSHAKE_1
- Plasticity CAD → Capability handshake: advertises capabilities
- Scene handler → Inbox hierarchy: synchronizes inbound objects
- Scene handler → Geometry lifecycle: updates in place
- Auto-Refacet tag → Geometry lifecycle: reapplies saved settings
- Scene handler → Outbox hierarchy: refreshes upload candidates
- Outbox hierarchy → PUT_SOME_1 upload: supported content
- PUT_SOME_1 upload → Binary protocol: PUT_SOME_1 encoding
- Capability handshake → PUT_SOME_1 upload: enables when supported
- Binary protocol → WebSocket client: outbound command