# Marvelous Designer Bridge (TinqsMDBridge) Live control of Marvelous Designer's Python scripting API from the terminal, sibling of the iClone bridge (`docs/iclone-bridge.md`): a socket server plug-in inside the app + a thin JSON-over-TCP client. **Key architectural difference from the iClone bridge, found the hard way (2026-07-30, MD 2026 Personal):** MD's embedded Python (3.11.8) does NOT schedule background threads while MD idles, and ships no Python Qt binding — so both the daemon-thread server and the QTimer executor patterns are dead on arrival (a threaded server binds, the OS accepts connections, and every request times out). Instead the bridge is a **blocking main-thread serve loop**: clicking the plugin starts a *bridge session* during which **MD's UI is frozen** ("Not Responding" is normal) and all api calls run on the main thread. The session ends via `--stop` or an idle timeout (default 14400 s / 4 h — the escape hatch, since a frozen UI can't be clicked). | | iClone bridge | MD bridge | |---|---|---| | Plug-in source | `tools/iclone_bridge/TinqsBridge/main.py` | `tools/md_bridge/TinqsMDBridge.py` | | Client | `tools/iclone_bridge.py` | `tools/md_bridge.py` | | Port | 18800 | **18900** (`TINQS_MD_BRIDGE_PORT` overrides) | | Install | ps1 copies to OpenPlugin, auto-loads | **manual register**, click = start session | | Executor | QTimer on Qt main thread, app stays live | main-thread serve loop, **UI frozen during session** | | Session end | app exit | `--stop`, or idle `TINQS_MD_BRIDGE_IDLE` (4 h default) | | Embedded Python | 3.8 | 3.11.8 | | Log | `%TEMP%\tinqs_iclone_bridge.log` | `%TEMP%\tinqs_md_bridge.log` | ## Install (one-time) 1. Marvelous Designer > **Plugin** tab > **Plug-in Manager** > **+ ADD** 2. Select `tools/md_bridge/TinqsMDBridge.py`, name it `TinqsMDBridge`, OK. ⚠ Unverified: whether the Plug-in Manager references the .py in place or copies it. `--ping` returns a `source` field — if it isn't the repo path, MD copied it and **every edit to the plug-in needs remove + re-ADD**. If a click appears to run stale code (old prints, old behavior), re-register. ## Session workflow ```bash # 1. In MD: click Plugin > TinqsMDBridge (UI freezes -- session active) python tools/md_bridge.py --ping # 2. verify python tools/md_bridge.py --exec "result = dir(pattern_api)" python tools/md_bridge.py --file draft_tshirt.py python tools/md_bridge.py --timeout 300 --exec "utility_api.Simulate(200)" python tools/md_bridge.py --stop # 3. unfreeze MD ``` Wire protocol and `result` convention are identical to the iClone bridge: newline-delimited JSON, one request per connection; set `result` in submitted code to get a JSON value back; stdout/stderr captured; exceptions return `ok:false` + traceback without ending the session. The exec namespace persists across requests within a session (NOT across sessions) and is pre-seeded with: - MD api modules that imported successfully: `import_api`, `export_api`, `pattern_api`, `fabric_api`, `utility_api`, `ApiTypes` (all 6 confirmed importable in MD 2026 Personal) - `BRIDGE` — info dict: `version`, `mode` ("mainloop"), `port`, `idle_timeout_s`, `source`, `api_modules`, `api_missing`, `python` ## Day-1 checklist (next session) ```bash python tools/md_bridge.py --ping # mode=mainloop, source path? python tools/md_bridge.py --exec "result = {m: [f for f in dir(globals()[m]) if not f.startswith('_')] for m in BRIDGE['api_modules']}" # dump the REAL api surface (docs are incomplete) python tools/md_bridge.py --file tools/md_bridge/smoke_test.py --timeout 180 # signatures + square-of-fabric + Simulate + snapshot python tools/md_bridge.py --stop ``` Open question the smoke test answers: do viewport snapshots (`ExportSnapshot3D`) render while the Qt event loop is blocked? If not, plan B is pumping events from inside the loop or snapshotting after --stop. Then the real milestones: - import `Ariki_Female_QuatSkin` as FBX avatar (Blender-convert the GLB first), drape a rectangle, snapshot. - t-shirt + shorts from `tools/tailor/lena_measurements.json` drafts. - EveryWear rig + GLB export, check bone names == Quaternius. ## Gotchas - **A session must be started by a human click** in MD — plan work in batches, and always `--stop` when done so Jeremy gets his UI back. - Long `Simulate()` calls: raise client `--timeout`; the idle timer only resets when a request *completes*, so a 4-minute drape is safe but two 6-minute gaps in a row end the session. - Windows may dim the MD window and offer to kill it — decline; the process is healthy. - Port clash: 18900 chosen to coexist with iClone's 18800.