{
  "markdown": "# GLBForge — the web-readiness layer for AI-generated 3D\n\n**glbforge.dev** · raw AI mesh in, shipped asset out\n\nMakes AI-generated 3D assets (Meshy, etc.) actually shippable on the web:\n**analyze → optimize → scaffold a viewer**, with performance budgets as a\nCI-able contract.\n\n## Status\n\n- ✅ `glbforge analyze` — budget report card + named lint rules\n- ✅ `glbforge optimize` — weld/simplify/LOD/compress to hit the budget\n- ✅ `glbforge scaffold` — emit a React Three Fiber viewer for the optimized asset\n- ✅ `glbforge meshy` — generate/download via Meshy REST API (image/text → 3D, `--optimize` glue)\n- ✅ MCP server wrapping all of the above (`@glbforge/mcp`, 8 tools)\n- ✅ **GLBForge Studio** (`glbforge ui`) — local web UI: drag-drop analyze,\n  one-click optimize with a before/after compare slider in the viewport,\n  logo forging, Meshy generation with live progress, STL export. Zero\n  hosting; runs entirely on your machine.\n- ✅ `glbforge extrude` — deterministic logo/graphic → 3D (no AI, no credits): traces\n  the silhouette (marching squares → Douglas-Peucker → earcut), extrudes it\n  watertight, and projects the source image back on as the texture. For 2D\n  artwork (logos, wordmarks) this beats image-to-3D generation outright:\n  ~1.5k tris vs ~2M, exact silhouette, original colors. `--bevel` adds a\n  signage-style rounded rim (miter-limited, clamp-probed insets + a crack\n  stitching pass keep it watertight even on thin graffiti strokes; verified\n  0 boundary / 0 non-manifold edges on real logo fixtures). Photographic\n  inputs are detected and routed to Meshy instead. Also exposed as the\n  `extrude_image` MCP tool.\n\n## Usage\n\n```bash\npnpm install && pnpm build\nnode packages/cli/dist/index.js analyze fixtures/veiled-guardian.glb --profile mobile-hero\nnode packages/cli/dist/index.js optimize fixtures/veiled-guardian-tex4k.glb -o out.web.glb --lods 40000,10000\nnode packages/cli/dist/index.js scaffold out.web.glb -o viewer && cd viewer && pnpm install --ignore-workspace && pnpm dev\nnode packages/cli/dist/index.js ui model.glb   # GLBForge Studio on localhost:5177\n```\n\n`analyze` flags: `--profile mobile-hero|desktop-hero|product-configurator`,\n`--json`, `--no-topology`. Exits non-zero when the asset is over budget — wire\nit into CI like a linter. `optimize` flags: `--target <tris>`, `--lods a,b`,\n`--no-textures`, `--no-compress`, `--no-verify`.\n\nMeasured on the included Meshy 7 fixture (4K textures, 1.99M tris):\n**89.4MB → 5.5MB (93.8% smaller), score 25 → 100, ~7s.** Pipeline:\ndedup → weld → meshopt-simplify to budget (error ladder) → fill missing\nnormals → texture resize + WebP (normal maps near-lossless) → prune →\nEXT_meshopt_compression → **perceptual verification**.\n\n### \"No visible loss\" is measured, not claimed\n\nEvery `optimize`/`ship` renders the asset from four fixed cameras before and\nafter (deterministic software rasterizer, 2x supersampled, smooth shading,\nbase-color textures) and scores the pairs with SSIM. The weakest view must\nclear the profile's `minSsim` floor (mobile-hero 0.94, product-configurator\n0.95, desktop-hero 0.96) or the report card gets an error-severity\n`fidelity/perceptual` finding and the command exits non-zero, exactly like a\nbudget violation. A passing run records the number as an info finding, so\nthe score ships with the report everywhere (CLI, `--json`, MCP, Studio).\n\n```\n  visual fidelity ✓ SSIM 96.7%  weakest view 95.8% @ verify_135 · floor 94.0% · geometric deviation ≤ 0.1%\n```\n\nOn the fixture: the budget pass (1.99M → 150k tris) measures 0.958; forcing\n40k tris drops to 0.896 (fails, and it should — hair strands merge); 10k\nmeasures 0.73. `glbforge verify <candidate> <reference>` scores any two\nfiles the same way. The cameras are fixed to the reference's bounds so a\nshifted or shrunken result cannot re-frame itself into a good score.\n\n## Packages\n\n| package     | purpose                                              |\n|-------------|------------------------------------------------------|\n| `@glbforge/core`  | pure analysis library: stats, topology, rules, budgets |\n| `glbforge` (CLI)   | `glbforge` command-line interface                          |\n| `@glbforge/meshy` | typed Meshy REST client: tasks, polling w/ backoff, downloads |\n| `@glbforge/mcp`   | MCP server: compact report cards + `inspect_report` drill-down, rendered previews from every tool, optimize/ship/forge/STL, generation |\n\n## MCP server\n\n`.mcp.json` registers the server for Claude Code automatically (build first:\n`pnpm build`). For other clients:\n\n```bash\nclaude mcp add glbforge -- node /path/to/XUI/packages/mcp/dist/index.js\n```\n\nBuilt for agents: results are compact cards (verdict, key numbers, every\nerror plus top findings, `nextActions`, a `drillDown` pointer) with\n`inspect_report` for the full findings/textures/topology on demand; every\ntool that touches a GLB returns a rendered thumbnail or 2x2 turntable, and a\nfailing optimization returns a reference | result | change-heatmap sheet so\nthe agent sees where the loss is (`compare_glb` for any two files).\n`capabilities` says which providers have keys and whether KTX2 is available\nbefore a plan is made; every written file reports its `sha256`; read-only\ntools carry `readOnlyHint` so clients can auto-approve them. Generation tools are deliberately split into\ncreate/status/download — tasks take minutes, and agents poll at their own\npace instead of holding a tool call open.\n\n## Animated assets\n\nSkinned meshes and morph targets go through a bone-aware path: meshoptimizer's\nattribute-aware simplifier sees the skin weights (and per-target morph\ndeltas) as vertex attributes, vertices on dominant-joint boundaries are\nlocked, and every attribute — `JOINTS_n`, `WEIGHTS_n`, each target — is\ncompacted with the same remap. Skins, inverse bind matrices, and animation\nclips survive untouched; `analyze` reports `scene/animated-asset`. Tested on\na rigged cylinder with a rotation clip and a morph target (blend band\npreserved, weights normalized, deterministic).\n\n## USDZ for iOS AR\n\n```bash\nnpx glbforge usdz model.web.glb          # → model.usdz (PNG textures; --jpeg for smaller)\n```\n\nWrites an ASCII USD layer with `UsdPreviewSurface` materials (base color,\nmetallic/roughness via channel outputs, normal, occlusion, emissive, alpha\nmask/blend), transcodes WebP textures to PNG/JPEG, and packs a store-only\nzip with 64-byte-aligned payloads as the spec requires. Static export: skins\nand clips are baked to the bind pose; KTX2 inputs are rejected with guidance.\nAlso `export_usdz` on the MCP server. Reference it from\n`<model-viewer ios-src=\"model.usdz\">` for the AR button on iOS.\n\n## `glbforge init` — make a project agent-ready\n\n```bash\nnpx glbforge init            # in your project; idempotent\n```\n\nWrites a marker-delimited section into `CLAUDE.md` (what the budget is,\nwhich scripts and MCP tools to use, the forge-vs-generate routing rule, and\nthat \"no visible loss\" is measured), adds `glb:check` / `glb:analyze` /\n`glb:optimize` / `glb:ship` / `glb:verify` / `glb:studio` npm scripts (plus\n`glbforge` as a devDependency), and registers the MCP server in `.mcp.json`\n(`--client cursor|both` for `.cursor/mcp.json`). Existing content, other MCP\nservers, and your own scripts are preserved; a second run reports everything\nunchanged. Flags: `--profile`, `--assets <dir>`, `--local`, `--dry-run`,\n`--force`, `--no-claude-md`, `--no-scripts`, `--no-mcp`. From then on any\nagent session in that project picks GLBForge up automatically.\n\n`glb:check` runs `glbforge audit <dir>`: every GLB in the folder against the\nbudget, non-zero exit if any fails — the pre-commit / CI gate.\n\n## GitHub Action\n\n```yaml\n# .github/workflows/assets.yml\non: pull_request\npermissions: { contents: write, pull-requests: write }\njobs:\n  assets:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with: { fetch-depth: 0, lfs: true }\n      - uses: glbforge/glbforge@main\n        with:\n          profile: mobile-hero\n          optimize: true      # open a PR with the web-ready files\n```\n\nRuns only on GLB/glTF files changed in the pull request. Every run posts a\nsticky report-card comment and gates the check on the budget. With\n`optimize: true` it also optimizes each failing asset (`<name>.web.glb`\nbeside the original, or in place with `replace: true`), verifies it\nperceptually, and opens or updates a pull request against the PR branch with\nthe results — before/after table, visual SSIM, and the pipeline steps. Same\ninput, profile, and CLI version always produce identical bytes, so outputs\nare cached by content hash (`cache: true`) and re-runs are no-ops. Fork PRs\ncannot receive a bot branch; their outputs are uploaded as a workflow\nartifact instead. Opening the PR needs the repository (and, for\norganizations, the org) setting **Allow GitHub Actions to create and approve\npull requests**; when it is off, the run still posts the report card and\nuploads the optimized files as the `glbforge-optimized` artifact. In optimize mode the gate passes when the optimized output\npasses, so the fix is always one merge away. Inputs: `profile`,\n`fail-on-budget`, `optimize`, `optimize-all`, `replace`, `verify`, `cache`,\n`open-pr`, `pr-branch`, `version`, `token`.\n\n## Meshy API key\n\nCopy `.env.example` to `.env` and set `MESHY_API_KEY` (gitignored, loaded\nautomatically, never overrides real env vars). Or keep it out of files\nentirely via macOS Keychain:\n\n```bash\nsecurity add-generic-password -a \"$USER\" -s meshy-api-key -w\n# ~/.zshrc: export MESHY_API_KEY=$(security find-generic-password -s meshy-api-key -w)\n```\n\nFull loop, one command:\n\n```bash\nnode packages/cli/dist/index.js meshy image art.png --pbr --optimize -p mobile-hero -o hero.glb\n```\n\n## Open-model generation (fal.ai)\n\nTrue image→3D via open weights on GPU inference — often 5-25x cheaper\nthan commercial generation. Set `FAL_KEY` (https://fal.ai/dashboard/keys):\n\n```bash\nnode packages/cli/dist/index.js gen photo.png --model hunyuan --optimize   # Hunyuan3D-2\nnode packages/cli/dist/index.js gen photo.png --model trellis             # TRELLIS\nnode packages/cli/dist/index.js gen photo.png --model triposr             # fastest\n```\n\nThe studio's generate panel picks up every configured provider\nautomatically (Meshy + the open trio side by side, with per-model\ncredit costs in hosted mode).\n\n## Rules\n\n`perf/*` budget violations fail the build; `geo/*`, `topo/*`, `mat/*`,\n`tex/*`, `scene/*` describe defects typical of AI-generated assets, each with\na concrete fix. See `packages/core/src/rules.ts`.\n\n## Design decisions\n\n- **Pure Node/TS, no Blender dependency.** Analysis and (upcoming)\n  optimization run on `@gltf-transform` + `meshoptimizer` — native to glTF, no\n  lossy DCC round-trip, installable via `npx`, CI-friendly. Ops are designed\n  as pluggable backends so Blender-only capabilities (retopo, UV unwrap,\n  baking) can be added later without changing the CLI surface.\n- **Topology in welded space.** Boundary/non-manifold counts are computed\n  after unifying position-duplicate vertices, so unwelded exports don't\n  produce garbage numbers.\n- **Budgets are profiles, not advice.** An asset passes or fails a named,\n  versioned target (`mobile-hero@1` pins; bare `mobile-hero` = latest; a cap\n  never changes in place). The methodology behind every cap and the version\n  changelog are in [docs/BUDGETS.md](docs/BUDGETS.md) / glbforge.dev/budgets.\n  Determinism makes it automatable.\n\n## Fixtures\n\n- `fixtures/veiled-guardian.glb` — Meshy 7 High-Detail geometry-stage export\n  (1.99M tris, POSITION-only, 34MB). Welded + manifold; tests assert we don't\n  cry wolf.\n- `fixtures/veiled-guardian-tex4k.glb` — same asset after the 4K texture stage\n  (89MB). Its 77k position-duplicate vertices are UV-seam splits, not waste;\n  the `topo/unwelded` rule distinguishes these (regression-tested).\n",
  "bytes": 11825,
  "sha": "099adb58d52bffe3ce94d890e63ff348bda02db6dbaf4654b1d19b1bb3a1a082",
  "repo_slug": "glbforge/glbforge",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_dev_glbforge_glbforge_c017a229/readme"
}