Bulk import of the working lanes that were living untracked on the PC. Content: - characters/ Lena/male body lanes, bakes, texture work, run logs - clothing/ garment pipeline, configs, gates, contract docs - garments/ MD-authored garment sources (.zprj/.zpac) - UAL-Lib/ Universal Animation Library 2 source (.blend/.fbx/.glb) - tools/ blender_bridge, iclone_bridge, md_bridge, tailor, glm_agent - docs/, plans/, dev/, .agents/plans/ Repo hygiene: - .gitattributes: LFS now covers .blend, .zprj, .zpac, .obj, .npy and the Reallusion .iAvatar/.ccAvatar/.ccRestore containers. Without this the ~3.8 GB in this commit would land as raw blobs. .png/.jpg are left out on purpose — ~250 are already tracked raw and converting them would rewrite every one without shrinking history. - .gitignore: exclude /accurig/ (~1 GB AccuRig program files, redistributable from Reallusion, nothing authored here) and /dev/null/ (git-lfs hook copies dropped by a `>/dev/null` redirect on Windows). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4.7 KiB
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)
- Marvelous Designer > Plugin tab > Plug-in Manager > + ADD
- Select
tools/md_bridge/TinqsMDBridge.py, name itTinqsMDBridge, 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
# 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)
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_QuatSkinas FBX avatar (Blender-convert the GLB first), drape a rectangle, snapshot. - t-shirt + shorts from
tools/tailor/lena_measurements.jsondrafts. - 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
--stopwhen 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.