Generation is the commodity. GLBForge is the deterministic layer after it: read a mesh semantically in a tenth of a second while you are still editing it, diff what the last edit broke, then optimize it 90%+ smaller and gate it on a budget that either passes or fails. CLI, in-browser Studio, MCP server, GitHub Action.
Node 20+ · MIT · runs locally, nothing uploaded.
Hand ship a PNG or SVG instead and it forges the artwork; hand it
a photo and it routes to a generator. npx glbforge ui opens the Studio.
glbforge extrude --layers 4 --pillow · drag to orbitGeneration is a commodity. The gap between "generated" and "shipped" is where projects die — GLBForge closes it with deterministic tooling: same input, same settings, same bytes and pixels, every time.
The read after every edit: one connected shell or floating pieces, watertight or holes, size in metres, up axis, origin placement, unapplied or mirrored transforms. Versioned rule ids, measured vs heuristic, a likely cause with its own confidence, a concrete fix. front is never guessed. ~0.1 s on a 150k-triangle asset; under a second on a raw 2M-triangle generation.
Two versions in, a change note out: per-part size deltas, triangle and shell deltas, topology regressions (was watertight, now has three open loops), origin drift, meshes added or removed, optional SSIM with the cameras fixed to the before framing. Regressions first.
Lighthouse-style report card: triangle/file/texture/GPU-memory budgets, welded-space topology, named lint rules with fixes. Exits non-zero over budget — it drops into CI like a linter.
Weld → simplify to budget → smooth normals → WebP or KTX2 textures (4–8× less GPU memory) → meshopt compression → LOD chains. Typically 90%+ smaller, with the visual loss measured rather than claimed.
Logos, wordmarks, SVGs → watertight 3D, no AI and no credits. Exact silhouette, layered colours (--layers auto measures the artwork first), pillow/emboss relief, bevels, enamel/chrome/neon/acrylic/rubber presets. --matte auto lifts a subject off a plain background first, so a photo forges as a sticker. Watertight, so it prints.
For photographic subjects: Meshy 7, plus open weights on fal.ai GPU inference — Hunyuan3D-2, TRELLIS, TripoSR. Bring your own key; every generation lands already analyzed and one step from web-ready.
Web-ready GLB, print-ready STL (mm-scaled, watertightness verdict), and USDZ for iOS AR Quick Look — binary crate written in pure TypeScript, UsdPreviewSurface materials, UsdSkel skeletons and blend shapes, and node animation as xform time samples so a baked clip plays in AR. Plus a React Three Fiber viewer scaffold with LOD switching.
mobile-hero, desktop-hero, product-configurator — opinionated, versioned caps with a published methodology; pin mobile-hero@1 in CI and it never moves under you.
Skinned meshes and morph targets simplify bone-aware: the simplifier sees skin weights and morph deltas as attributes, dominant-joint boundaries are locked, and skins, inverse bind matrices and clips survive — into GLB and into UsdSkel.
A looping idle, bob, spin, sway, breathe or hop baked into any GLB without a rig: a pivot at the base centre carries the motion, your nodes are untouched, and re-running replaces the clip instead of stacking. Deterministic keys, and USDZ bakes them as time samples so AR Quick Look plays it.
The finished asset as a talking character on your desktop: transparent always-on-top window, plays its clips, gazes at the cursor, and answers typed messages — with a Claude agent on your CLI login, or with any MCP client driving it. --hooks wires it to Claude Code, so every session on the machine shows its start, its permission prompts and its finish on the character's face.
A tool you run once per asset never becomes a habit. The inner loop is where the work happens — an agent driving a mesh through bpy.ops is blind after every call. inspect answers what it cannot see, in a fraction of a second; diff says what the last edit broke. Both read GLB, glTF, USDZ, USDA and USDC, and both are MCP tools as well as commands.
$ glbforge inspect model.glb authoring@1 · core-geometry@1, core-scene@1 · 110 ms 1 mesh, 150,000 triangles, 1.43 × 1.90 × 1.28 m, Y-up. One shell, not watertight. Origin at the bounding-box centre, 0.95 m above the base. Front: unknown (declare it with an expectation). WARN topo/non-manifold measured 152 non-manifold edges (0.10% of its triangle count): faces meet three or more to an edge. cause (70%): a simplification artifact rather than an authoring error. → Harmless for display. For printing or booleans, repair the source mesh.
$ glbforge diff before.glb after.glb authoring@1 · diff@1 · 87 ms The asset is 100% deeper along Z (8.0 cm → 16.0 cm). Triangles 4,292 → 20,024 (+367%). Shells 1 → 44: 43 new separate pieces. 3 meshes added, 1 removed. 1 regression at warning or above. WARN diff/shells-changed measured cause (60%): a cut or boolean split geometry off, or new parts were added without joining. → If the pieces should be one solid, boolean-union them.
Add --expect "chair, single-shell, 0.4–1.2m tall, watertight, origin base" and the run becomes a contract: shells, watertightness, size range and origin are measured and fail as errors; a bare category is a plausibility warning with a stated confidence; front is recorded as declared, never measured.
Every optimize and ship renders the asset from four fixed cameras before and after — deterministic software rasterizer, linear-light shading, 2× supersampled — and scores the pairs with SSIM. The weakest view must clear the profile's floor or the report card takes an error and the command exits non-zero, exactly like a budget violation.
visual fidelity ✓ SSIM 96.7% weakest view 95.8% @ verify_135 · floor 94.0% · geometric deviation ≤ 0.1%
Image-to-3D models produce mush from flat graphics. GLBForge traces the silhouette exactly, stacks the colors in layered depth, pillows the surface, and hands you a watertight mesh you can ship — or print. A photo of an object on a plain background is not a dead end either: --matte auto lifts the subject off the ground first — deterministic connectivity, no model download — and the cut is previewable, with a stated confidence, before any geometry exists.
Try it right now in your browser — drag in a GLB or a logo, read the report card, optimize with one click, compare original-vs-optimized with a split slider and the measured SSIM, then export GLB, STL or USDZ. The whole pipeline runs client-side in WASM: your assets never leave the device. Only optional signed-in generation touches a server. The same Studio runs locally, with KTX2 and your own generation keys, via npx glbforge ui.
# the whole studio, no install: npx glbforge ui # or the CLI, piece by piece: npx glbforge inspect model.glb --expect "chair, single-shell, watertight" npx glbforge diff before.glb after.glb --visual npx glbforge analyze model.glb --profile mobile-hero npx glbforge optimize model.glb --ktx2 --lods 40000,10000 npx glbforge extrude logo.png --layers auto --pillow 0.03 --preset enamel npx glbforge animate model.web.glb --preset idle npx glbforge stl model.glb --size 80 npx glbforge usdz model.web.glb npx glbforge init # wire it into a project: scripts, MCP, CLAUDE.md
The same pipeline is an MCP server — 28 tools, published in the official registry as dev.glbforge/glbforge — so Claude Code, Cursor and friends can inspect, diff, fix and ship an asset inside one conversation, looking at rendered previews of their own output. Every tool answers one envelope (ok, summary, duration_ms, errors[], data) where each diagnostic carries a stable code, a severity and the prim path it refers to; every response validates against a published schema; mutating tools take dry_run and return a diff plus a re-validation, so nothing changes silently. And a GitHub Action posts report cards on pull requests and opens a PR with the optimized, perceptually verified files.
# MCP server (Claude Code): claude mcp add glbforge -- npx -y @glbforge/mcp # then just ask: "inspect chair.glb — is it one watertight shell, origin at the base?" "make logo.png into a web-ready 3D asset under the mobile budget"
# .github/workflows/assets.yml - uses: actions/checkout@v7 with: { fetch-depth: 0, lfs: true } - uses: glbforge/glbforge@main with: profile: mobile-hero optimize: true # → report card on every PR, plus a PR # with the web-ready files (SSIM-verified)
An honest scope statement, kept in step with the code — the same one /llms.txt serves to agents.
inspect / diff / --expect contractsanalyze + versioned budget profilesoptimize with SSIM-gated fidelityship: one call, any input, budget-gated--matte auto lifts a subject off its background), STL, USDZanimate: looping motion without a rig, into GLB and USDZusage counterinit, audit