A 3D Garment CAD Tool Rebuilt from Python Scripts into a Desktop App
The project demonstrates a practical pattern for productizing research code: isolate unstable native libraries in subprocesses, use file-based progress reporting, and audit data at every cross-language boundary. The OBJ parsing bug alone is a cautionary tale for any pipeline that passes geometry between Blender and a WebGL frontend.
The original Costumy prototype required writing Python scripts and waiting minutes to see a single 3D garment result. Costumy Studio turns that into a point-and-click desktop tool: drag sliders to adjust body measurements and design parameters, get a 2D pattern preview in under 3 seconds, and run a full cloth simulation in about 25 seconds.
The architecture splits responsibilities cleanly. A React frontend handles the parameter panel, SVG pattern display, and a three.js 3D viewport. A Python backend — built on the standard library's HTTP server with zero extra dependencies — runs freesewing for pattern generation, the triangle library for mesh triangulation, and Blender's bpy module for physics baking inside an isolated subprocess. That subprocess isolation is non-negotiable: the triangle C library can crash silently beyond Python's exception handling, and bpy is not thread-safe.
Three debugging stories anchor the piece. An IDE file-sync conflict silently dropped an import and caused a full-page white screen. A polling loop reloaded a 12MB OBJ file every 1.2 seconds, freezing the UI. The hardest bug: two stray edge records in an exported OBJ caused three.js to misinterpret an entire mesh as line segments, turning a garment into white noise — a failure caught only by auditing record-type counts at the format boundary.
The triangle library's silent C-level crash and the 40-retry workaround are a stark reminder that wrapping native code in Python subprocesses is sometimes the only viable error-handling strategy — try/except simply cannot reach that failure mode.
The OBJ stray-edge bug reveals a brittle assumption in three.js's OBJLoader: mixed face and line records in one object group trigger a complete type misclassification with no warning. Any pipeline exporting OBJ from Blender for WebGL consumption should strip `l` records as a defensive post-processing step.
The IDE file-sync conflict is a concrete failure mode for AI-assisted coding workflows: an agent edits a file on disk while the same file sits open in an editor with unsaved state, and the next manual save silently reverts the agent's change. The fix is procedural — always confirm disk contents before debugging — not technical.
The architecture's deliberate avoidance of Flask or FastAPI in favor of the standard library's HTTP server is a pragmatic choice for a venv already loaded with numpy, bpy, and triangle; adding a web framework would risk dependency conflicts with no meaningful benefit for a single-user desktop tool.
The architecture is very clear, and the front-end/back-end separation design is clever. I've run into similar cross-language data interaction problems when building Electron apps before — especially the case you mentioned where stray edges mixed into the OBJ file caused front-end parsing errors. That's way too real: each module looks fine on its own, but when you chain them together, everything blows up. The approach of isolating Blender calls in a Python subprocess is great; it avoids main-process crashes from memory or threading issues. The off-screen window trick for capturing logs and screenshots is also really practical — I've been burned before by the separation of main-process and renderer-process logs in similar apps, and this solution is a solid idea. I'm curious: for the 25-second 3D simulation pipeline, have you considered adding a progress callback? If users could see a percentage while waiting, the experience would be much better.
There is a progress callback — clicking 'generate cloth' shows it in real time.