Modly Deep Dive: A Local, Open-Source "Image-to-3D" Desktop App
> Local AI-powered 3D mesh generation from images — an Electron + Python desktop app that runs open-source AI models on your own GPU.
>
> Subject: lightningpixel/modly (v0.4.1, GitHub created 2026-03-17; ~5,541 stars, 582 forks as of 2026-08-14). Based on four parallel deep-read agents with code-level cross-verification and external checks (GitHub API / Releases / WebSearch).
What It Is (One-Sentence Feynman View)
Many open-source image-to-3D "recipes" exist (Hunyuan3D, TripoSG, TRELLIS...), each requiring painful setup. Modly is the double-click-to-open central kitchen: Electron as the front end, an embedded portable Python as the stove, open models on the menu (extension system), and your own GPU as the fire. Upload a photo, get a 3D model (.glb), all locally — a "distribution" for local AI 3D. Caveats: you bring your own GPU, first-run requires downloading weights from HuggingFace, output quality is capped by local models, and installing extensions from arbitrary GitHub repos currently has no integrity checks.
Fact-Checking Notes
| Claim | Verified conclusion |
| --- | --- |
| "Default model is TripoSR" | False: no TripoSR generator in repo; services/model_manager.py doesn't exist; services/generators/ has zero built-in generators. Source: stale api/README.md. |
| "Code defaults to sf3d (Stable Fast 3D)" | Half-true: generator_registry.py:165 has os.environ.get("SELECTED_MODEL_ID", "sf3d"), but Electron always sets the env to empty; real behavior falls back to the first user-installed extension. sf3d is an HF gated model not listed in the README extension table. |
| "Extensions are signature-verified via public_key.pem" | Disproven (key finding): api/resources/public_key.pem is an orphan file (113 bytes, zero references); cryptography is a dependency but never used for sign/verify; download paths contain no hash/checksum/integrity checks. No supply-chain integrity verification exists. |
| "Runs entirely on your GPU / fully local" | True for inference — 100% local, no cloud APIs. But not fully offline: weights come from HuggingFace, extensions from GitHub, agent routing depends on local Ollama. |
| "Only local × open-source × desktop app" | Holds: no comparable packaged, out-of-the-box, fully local image-to-3D desktop app found; bare model repos and ComfyUI are different categories. |
Conclusion: Modly is a model-agnostic host — the binary hard-codes no model weights or inference code, dynamically discovering extensions by scanning EXTENSIONS_DIR. Documentation lags behind code and the extension ecosystem.
Architecture
- Dual runtimes: Electron main process spawns a bundled python-build-standalone 3.11.9 running uvicorn FastAPI on
127.0.0.1:8765(hardcoded; no multi-instance). Zero system Python required — "green" portable runtime. - Process model: health-polling for ~90s;
python:crashedonly notifies the renderer — no auto-restart supervisor, a structural gap. Unix process-group kill / Windowstaskkill /T /Ffor cleanup. - IPC:
ipc-handlers.tsis a 1,545-line / 63KB monolith with 63 registration points across 16 domains; the channel contract is stringly-typed (no schema/compile-time validation) — accumulating tech debt. - Extension host: each extension needs
manifest.json+generator.py(extendsBaseGenerator). Node IDs areext_id/node_id. Two load modes: subprocess (per-extension venv, NDJSON over stdin/stdout) and legacy directimportlib. Base requirements exclude torch — heavy deps install via extensionsetup.pyat install time (multi-GB downloads). - Workflow engine:
@xyflow/reactnode canvas;preflight.tsstatic validation blocks invalid runs (stricter than README's "warning only"). Execution is front-end driven (workflowRunStore.tstopological sort, wait-node pauses); the backend has no global DAG scheduler. - Inference is 100% local; the only network dependency is one-time weight downloads (HF token supported for gated models).
texture_baker/uv_unwrappership prebuilt only for Windows cp310; Linux/macOS need source builds.- Single-image reconstruction inherently hallucinates backsides/occlusion — the "melted wax" look on close-up humans is a field-wide limitation, not Modly's fault.
- 🔴 H1: Any GitHub repo = RCE at user privilege (no signing, allowlist, or review gate).
- 🔴 H2: No weight integrity checks; PyTorch
pickle.load= code execution;hf_repois attacker-controlled via manifest. - 🔴 H3: Extension subprocesses are unsandboxed and inherit the full host environment including
HF_TOKEN. - 🔴 H4:
POST /extensions/setup/{ext_id}has path traversal (noassertSafeExtensionId), unauthenticated on localhost. - 🟠 M1–M6: no commit pinning (unreproducible installs); FastAPI control plane fully unauthenticated on
127.0.0.1:8765; trusted-registry badge is UI-only and fails open; HF token passed in URL query; JS extensionsnpm installattacker dependencies; tar extraction unaudited. - ✅ Mitigated: path guards, malformed-manifest rejection, atomic install + rollback, conservative pip auto-fix whitelist.
Models & Generation Pipeline
| Model | Method | VRAM | Notes | | --- | --- | --- | --- | | Hunyuan3D 2 / 2 Mini | Rectified-Flow DiT shape + PBR texture baking | ~6GB (shape) / 16–24GB (full) | Apache-2.0 | | TripoSG (VAST) | 1.5B Rectified-Flow Transformer, SDF VAE | ≥8GB (~15s) | Shape only, no texture | | TRELLIS / Trellis2 (Microsoft) | SLAT structured latent diffusion → mesh/3DGS/RF | ≥16GB | GGUF quantization is community work | | TripoSR | Feed-forward LRM | ~6GB | <0.5s, vertex colors, symmetric artifacts | | Stable Fast 3D (sf3d) | Feed-forward + texture pipeline | Medium | HF gated; code default but absent from README |
Trade-off: LRM feed-forward (TripoSR/sf3d) is fast/cheap but weaker; latent diffusion (Hunyuan3D-DiT, TripoSG, TRELLIS) is higher quality but slower and VRAM-hungry.
Pipeline: POST /generate/from-image → ExtensionProcess subprocess → mesh (implicit/voxel → marching cubes) → optional texture stage → optional post-processing (box-projection UV unwrap, texture baking, trimesh+pymeshlab decimation/smoothing, 3DGS .ply → .splat) → export glb / stl / obj / ply → Three.js viewer.
Extension Ecosystem & Security (Key Battleground)
Install flow (extensions:installFromGitHub): parse URL (only hostname==='github.com' + owner/repo shape checked) → download tarball at HEAD (no pinning, no hash) → extract → validate manifest structure → staging + atomic rename → execute third-party code (setup.py or npm install) → reload.
Layered defenses: excellent path-traversal guards for extension IDs and workspace assets, plus manifest structural validation and atomic installs with rollback. But the code-trust layer is fully open — a structurally valid manifest from any repo installs and runs.
Findings
public_key.pem claim was disproven at code level — it's an orphan file. Modly currently has zero supply-chain integrity verification.Agent interfaces: a restrained MCP server (10 tools: list/switch models, generate, status, decimate/smooth/import mesh, unload, settings) and a 65KB stdlib-only CLI (fail-closed, machine-readable JSON). The interfaces themselves are narrow, but the unauthenticated localhost control plane underneath amplifies them.
Competitive Position
| Product | Form | Local/Cloud | Open | Price | Quality | | --- | --- | --- | --- | --- | --- | | Modly | Desktop app | Local | MIT | Free (own GPU) | ★★★ | | Meshy / Tripo | Cloud SaaS | Cloud | Proprietary | Free tier + ~$20–24/mo | ★★★★ (27–28M monthly visits each) | | Rodin (Hyper3D/Deemos) | Cloud SaaS | Cloud | Proprietary | ~$0.5–1.5/download | ★★★★★ | | ComfyUI | Node platform | Local | GPL | Free | High effort, high ceiling | | TRELLIS / Hunyuan3D / TripoSR | Bare models | Local | Open | Free | Require setup expertise |
Modly occupies a nearly unclaimed cell: local × open-source × packaged desktop. It leads on distribution form and agent-readiness but trails cloud leaders on model quality and ecosystem scale.
Maturity scorecard: activity 4, docs 3.5, tests 3, community 2.5, platform coverage 3.5, license 4.5 → ~3.5 overall: an active early Beta, plausibly built by 1–2 core people.
Verdict & Recommendations
> Modly is the sole category-definer for local, open-source, image-to-3D desktop apps — right direction, clever UX, forward-looking agent interfaces. But v0.4.1 prioritizes convenience and openness over code trust and security: a privacy kitchen for casual users, an unguarded castle if you install untrusted extensions.
For users:
1. Fine for personal use — but only install official lightningpixel/* extensions and manually verify repo + commit; never install random GitHub repos (that's running arbitrary code as you).
2. Need a discrete GPU with ≥8GB VRAM; Intel Macs unsupported.
3. Expect object scans to be solid, human subjects to look waxen; production topology still needs Blender cleanup.
4. Inference stays local, but first run needs networked weight downloads; gated models need an HF token.
5. MCP/CLI agent workflows are a real highlight — but avoid running agents on machines with untrusted extensions installed.
Priority fixes for the project:
1. Install gate: maintainer allowlist / signature verification / commit pinning (log install-time SHA); fail closed when offline.
2. Local API token auth (MODLY_API_TOKEN) at minimum for /extensions/*, /process-runs, /hf-download.
3. Fix H4: sanitize ext_id on the setup endpoint.
4. Verify weight expected_sha256 against signed manifests before PyTorch loads.
5. Minimal environment injection — don't leak HF_TOKEN to extension subprocesses; consider OS sandboxing.
6. Whitelist COMFYUI_URL to localhost only.
Key File Traceability
| Topic | Files |
| --- | --- |
| Startup / process lifecycle | electron/main/index.ts, python-bridge.ts |
| IPC monolith | electron/main/ipc-handlers.ts (1,545 lines / 63KB) |
| Path guards | electron/main/extension-path-guard.ts |
| Model registry / default ID | api/services/generator_registry.py:165 |
| Subprocess inference host | api/services/extension_process.py, api/runner.py |
| Generation / workflow APIs | api/routers/generation.py, workflow_runs.py |
| Weight download | api/routers/model.py:125-278 |
| MCP server | api/mcp_server.py (10 tools) |
| CLI | tools/modly-cli/agent.py (65KB) |
| Node canvas / front-end execution | src/areas/workflows/{preflight.ts,workflowRunStore.ts} |
| Orphan signature file | api/resources/public_key.pem (113B, zero references) |