A 3D model optimization CLI: simplification, part splitting, texturing, format conversion, LOD, and web-delivery compression through a single
meshifycommand. Every run writes ameshify.report/v1structured report and a semantic exit code for agents to consume.
English | 简体中文
Meshify prepares 3D models for delivery on the web, AR, and mobile. It is designed first for AI agents (Claude Code, Cursor, Codex, and others): every command emits a structured manifest, and degradations such as generated UVs or stripped textures are always disclosed as warning codes in the report. It is also a CLI that developers can use directly.
glb / gltf / obj / stl / ply work out of the box; step / stp (CAD) goes through the
Tier1 kernel.
- Eight commands:
inspect/simplify/segment/texture/convert/lod/optimize/doctor - Failed runs still write a structured error report (
errors[]+failed_early), not just an exit code - The Tier0 kernel is pure Node + WASM (gltf-transform / meshoptimizer / earcut) and runs on Node ≥ 18.17; STEP/STP goes to the Tier1 Python kernel (uv-managed, gmsh / OpenCASCADE), with install guidance returned on exit 5
- Source files are read-only; artifacts go to
<input-name>.meshify/; overwriting requires an explicit--overwrite - Quality assertions are kernel-independent (custom Hausdorff sampling / boundary-edge watertightness counting), with dedicated cross-kernel consistency tests
--preview-htmlgenerates a single-file before/after comparison page
From GitHub into an agent host (recommended, no clone needed; skills CLI):
# auto-detect installed hosts, choose interactively
npx skills add lxie-leo/meshify --skill meshify
# or target a host explicitly (-g installs to the user-level global directory)
npx skills add lxie-leo/meshify --skill meshify -a claude-code # Claude Code
npx skills add lxie-leo/meshify --skill meshify -a cursor # Cursor
npx skills add lxie-leo/meshify --skill meshify -a codex # Codex
npx skills add lxie-leo/meshify --skill meshify -a qoder-cn # Qoder (international: -a qoder)
npx skills add lxie-leo/meshify --skill meshify -a codebuddy # CodeBuddy
npx skills add lxie-leo/meshify --skill meshify -a universal # Comate etc. (installs to .agents/skills/, auto-loaded by Comate)
npx skills update # update installed skillsOn Windows, symlinks require Developer Mode; without it, add --copy to install by copying.
Cursor also works through its UI: Customize → Rules → Add Rule → Remote Rule (GitHub) → point it
at this repository.
Claude Code native plugin marketplace (the same path works in the VSCode extension's
/plugins → Marketplaces):
claude plugin marketplace add lxie-leo/meshify
claude plugin install meshify@meshify-skillsNote: the
npx skillsinstalls deliver the skill documentation (SKILL.md+references/) only; build the CLI from a clone (below), or usenpx meshifyonce published to npm. The Claude Code plugin additionally puts the repository'sbin/on the session PATH:meshifyworks right away, auto-building on first run (one-time per install/update, needs pnpm).
From a clone (the installer builds the CLI and copies the skill into detected host directories):
# PowerShell
powershell -ExecutionPolicy Bypass -File skills/meshify/scripts/install.ps1
# POSIX sh (Git Bash / macOS / Linux)
sh skills/meshify/scripts/install.shThe installer copies SKILL.md + references/ into host skills directories, builds the CLI if
missing, and runs meshify doctor as a self-check. See skills/meshify/SKILL.md
for skill usage.
From the repository (no AI host required — usable as a standalone CLI):
pnpm install && pnpm build
pnpm meshify --help # or: ./bin/meshify --help (the launcher the plugin puts on PATH)
# Windows CMD/PowerShell: bin\meshify.cmd --help
# dist is auto-built on first run if missing (needs pnpm); zero overhead afterwardsThe decision tree and exit-code table in SKILL.md double as quick-reference sheets.
# Structure first: faces / submeshes / materials / textures / bounding box
$ meshify inspect fixtures/glb/multimat.glb --json
{
"schema": "meshify.report/v1",
"tool": { "name": "meshify", "version": "0.1.0", "tier": "ts-wasm" },
"command": "inspect",
"input": { "format": "glb", "vertices": 72, "faces": 36, "meshes": [...], "bbox": [...] },
"warnings": [],
"exit_code": 0
}
# Simplify to 30% (ratio = fraction kept; per-submesh with materials preserved,
# submeshes <200 faces skipped with a warning)
meshify simplify model.glb --ratio 0.3
# Or an exact target face count (mutually exclusive with --ratio)
meshify simplify model.glb --target-faces 50000
# Split an assembly / cut with a plane (capped watertight by default)
meshify segment model.glb --mode connected
meshify segment model.glb --mode plane --axis x --position 0
# Web delivery: simplify + texture downscaling + meshopt/Draco compression
meshify optimize model.glb --ratio 0.5 --texture-size 2048
# STEP → GLB: routed to Tier1 automatically, with install guidance when missing
meshify convert part.step --to glbGlobal options: -o <path>, --json, --overwrite, --tier auto|ts|py, --preview-html,
--force. Full examples and the decision tree live in SKILL.md.
| Command | Purpose | Key semantics |
|---|---|---|
inspect |
Read-only analysis (vertices/faces/submeshes/materials/textures/bbox) | manifest is the output; no artifact file |
simplify |
QEM decimation (--ratio fraction kept | --target-faces target; one of the two) |
Submeshes <200 faces skipped + SMALL_MESH_SKIPPED |
segment |
Split: --mode plane|connected|semantic |
Plane cuts capped watertight by default |
texture |
Texturing / UV reprojection (planar/cylindrical/spherical/box/uv) | Submeshes missing UVs get box projection automatically + disclosure |
convert |
Format interconversion (glb/gltf/obj/stl/ply; STEP input via Tier1) | Materials/textures preserved across formats where possible, losses disclosed; empty scenes produce a valid empty file + warning |
lod |
Multi-level detail chain (--levels --ratio) |
level0 kept as-is, strictly decreasing afterwards |
optimize |
One-command lightweighting (simplify + meshopt/draco + texture compression/downscaling) | Degrades and discloses when dependencies are missing, never fails on them |
doctor |
Environment check (Tier0/Tier1 readiness, uv install guidance) | --json for machine-readable output |
Exit codes (agents decide by code):
| Code | Meaning |
|---|---|
| 0 | Success (may carry non-fatal warnings; read warnings[]) |
| 2 | Input unreadable (path/permissions/parse failure — truncated, corrupt, and garbage content all land here) |
| 3 | Format unsupported (export FBX etc. through a DCC first) |
| 4 | Parameter conflict / overwrite refused (overwrites need an explicit --overwrite; output == input is always refused) |
| 5 | Tier1 executor unavailable (stderr carries install guidance) |
| 6 | Algorithm failed on this input |
| 7 | Resource limit exceeded (>5M faces / >500 MB; --force for a one-shot pass) |
| 8 | Internal error |
Usage errors count as 4. Every non-zero exit (including pre-load failures 2/3/4/5) writes a
minimal failure manifest: errors[] with the reason, params.failed_early: true, input stats
zeroed as a fallback; --json sends it to stdout.
Each command writes <input-name>.<op>.report.json under <input-name>.meshify/, identical to
the --json stdout. Effects show up in metrics.face_reduction / byte_reduction; degradations in
warnings[].code — field-level documentation and the full table of 23 warning codes live in
report-schema.md; troubleshooting in
troubleshooting.md.
| Tier | Stack | Covers | Requirements |
|---|---|---|---|
Tier0 ts-wasm |
TypeScript + WASM (gltf-transform / meshoptimizer / earcut) | every command on glb / gltf / obj / stl / ply | Node ≥ 18.17, zero Python |
Tier1 python-uv |
Python (uv-managed; trimesh / gmsh / OpenCASCADE) | STEP/STP CAD meshing, cross-kernel cross-validation | uv sync (meshify doctor guides the install) |
Routing rules: STEP input is forced onto Tier1 (exit 5 when not installed); animated / skinned
input is forced onto Tier0 (animation preserved); everything else defaults to Tier0. --tier auto|ts|py overrides, and --tier py runs the Python implementation with a manifest identical to
Tier0's. Details in tiering.md.
model.glb
model.meshify/
├─ model.inspect.report.json # per-command reports (tool logs, auto-overwritable)
├─ model.simplified.glb # single-file artifact (needs --overwrite to replace)
├─ model.segment-plane.glb # merged segmentation artifact (part-level scene)
├─ model.lod0.glb / lod1.glb ... # LOD chain
└─ model.optimized.preview.html # --preview-html self-contained comparison page
pnpm build # build core / kernel-ts / cli
pnpm test # full suite (Tier1 cases auto-skip without uv)
pnpm test -- tests/ts/quality.test.ts
node fixtures/generate.mjs # regenerate golden samples (STEP part needs uv)
node fixtures/generate.mjs --big # append a >5M-face mesh (with MESHIFY_TEST_BIG=1)
MESHIFY_TEST_BIG=1 pnpm test # include resource-guard (exit 7) casesQuality assertions are kernel-independent (custom Hausdorff sampling / boundary-edge watertightness counting). Cross-kernel consistency tests require the same input to yield identical vertices, faces, materials, textures, per-submesh statistics, and bbox on Tier0 and Tier1.
CI (ci.yml): a Tier0 matrix of win/mac/linux × Node 18/20/22, a three-platform uv full-chain Tier1 job, and a manually triggered big-mesh guard job.
Note:
pnpm.overridesin the rootpackage.jsonpins sharp for ndarray-pixels at 0.33.5 — the prebuilt linux/macOS libvips of the sharp 0.35 line lacks OpenJPEG and crashes at module load (sharp#4475). Confirm the upstream fix before upgrading.
Repository layout
packages/core contract layer: zod schema / warning codes / exit codes / tier routing / Python bridge
packages/kernel-ts Tier0 kernel: io/inspect/simplify/segment/texture/convert/lod/optimize
packages/cli commander CLI: 8 commands + output management + before/after preview HTML
packages-py/kernel-py Tier1 kernel: trimesh/gmsh service layer (uv run python -m meshify_kernel payload.json)
skills/meshify the agent skill: SKILL.md + references/ + installers
tests/ts contract (zod×ajv) / quality (Hausdorff, watertightness) / per-command / exit codes / cross-kernel consistency / e2e
fixtures golden sample generator + committed artifacts (multi-material / open shells / STL / STEP / skinned animation / empty geometry)
- SKILL.md — skill overview and decision tree
- references/ — per-command detail, report schema, tier routing, troubleshooting
- report-schema.md —
meshify.report/v1field-level docs and the 23 warning codes - Chinese translations: README.zh-CN.md / SKILL.zh-CN.md / references/zh-CN/
Issues and PRs are welcome. Keep pnpm build && pnpm test green; changes touching contracts
(exit codes / warning codes / manifest schema) should update references/
and the tests together.
MIT © 2026 Leo Xie