3dqa — free local CLI
Validate and auto-heal 3D assets from the command line. Same deterministic, stateless core as the dashboard and API — but it runs entirely on your machine: $0, offline, no account, no upload, no API key.
Supports .glb .gltf .obj .ply .stl.
Install
pip install 3dqa # core (linter + repair, numpy + trimesh)
pip install "3dqa[all]" # + scipy fast path, decimation, UV unwrap/bake
Prefer a single file? The 3dqa.pyz bundle packs the whole engine into one
executable zipapp — python 3dqa.pyz lint model.glb (needs numpy + trimesh
in the environment; add scipy/xatlas/fast-simplification for the fast path
and full heal).
Use
# Audit one asset. Exit code is a CI gate: 0 = PASS, 1 = FAIL, 2 = error.
3dqa lint model.glb --pretty
# Audit a whole export folder (recursed), one line per asset.
3dqa lint ./exports --quiet
# Gate against target engines from a single scan.
3dqa lint ./exports --targets unreal_5,unity_mobile,three_js_web
3dqa lint ./exports --config 3dqa.config.json
# Non-destructively auto-heal — writes <name>_repaired.glb, never touches input.
3dqa heal model.glb
3dqa heal ./exports --out-dir ./healed --targets unity_mobile
# See exactly what WOULD be repaired, writing nothing.
3dqa heal ./exports --dry-run --pretty
# The closed loop: heal, RE-RENDER the healed artifact, RE-RUN the vision pass
# on it, and emit ONE certificate proving it is geometrically AND visually clean.
3dqa verify model.glb --pretty
3dqa verify ./exports --targets unity_mobile --out-dir ./healed --quiet
# Same loop, keyless and free — the mock visual backend proves the wiring at $0.
3dqa verify model.glb --vision mock --dry-run --pretty
# Compact integration schema for a pipeline hook to branch on.
3dqa verify model.glb --compact
# Half the model spend: skip the pre-heal pass when you only need the
# after-verdict and not the before/after attribution.
3dqa verify ./exports --no-baseline
What you get
lint emits a JSON Quality Certificate — a machine-readable pass/fail verdict
with a finding per check (poly budget, non-manifold edges, watertightness,
normals, UVs, floating debris, appearance) plus optional per-target compatibility.
heal runs the repair loop lint → fix → re-lint and emits a before/after report
with fixed / unfixable / introduced lists and a healing efficacy. A fix is
only reported as fixed after an independent re-lint of the exported .glb
confirms it. Nothing that can’t be safely repaired is hidden.
verify closes the loop. It heals, re-renders the healed artifact headless,
re-runs the vision pass on that render, and returns ONE certificate:
verdict PASS | FAIL | UNVERIFIED
claims geometrically_clean · visually_clean · target_compatible · closed_loop
attestation one sentence stating exactly what was proven
visual.delta resolved / persisted / introduced defect classes, before vs after
It is honest about the case that matters: if healing fixes the math but
introduces a visual defect — decimation smearing a texture, an unwrap
opening a seam — visual.delta.introduced names it and the verdict is FAIL even
though the geometry certificate passes. And if the visual pass could not
actually run (no headless GL, --vision none), the verdict is UNVERIFIED, never
a silent PASS: a certificate only claims "visually clean" when a render was
really audited.
Rendering needs nothing installed
The visual pass renders through three tiers and stops at the first that produces
frames: pyrender (offscreen GL), trimesh (pyglet), then a pure-numpy
software rasterizer. The last tier needs no GL, no display and no driver, so
verify works on a stock laptop or CI runner. The tier that ran is recorded in
visual.render.backend — a software render is a real render, but you always know
which one you got. It is roughly an order of magnitude slower than GL (measured:
7 views at 1024² in 0.76 s for 1.3k faces, 4.8 s for 82k); lower --resolution
if that matters.
--compact emits the integration schema instead of the full certificate:
{"asset_id": "...", "status": "PASSED",
"repartition_delta": {"initial_defects": ["NORMALS_INVERTED"],
"repaired_defects": ["NORMALS_INVERTED"],
"residual_visual_delta": 0.0},
"execution_time_ms": 91.4}
residual_visual_delta is the fraction of visual defect classes still present
after healing (0.0 = visually clean). It is null — never 0.00 — when the
visual pass could not run, because 0.00 there would assert a cleanliness nobody
measured.
Cost
verify runs the vision backend twice — once on the arriving asset, once on
the healed one — because the before pass is what lets the certificate say a
defect was introduced by healing rather than merely present. Two levers:
| Setting | Model calls | Pixels sent |
|---|---|---|
--resolution 1024 + baseline |
2 | 14.7 MPx |
| default (512, baseline) | 2 | 3.7 MPx |
--no-baseline at 512 |
1 | 1.8 MPx |
--no-baseline buys that saving with attribution, and says so: delta.baseline
becomes "skipped" and every comparative field (resolved, persisted,
introduced, regression) is null, not false. The healed asset is
still fully audited — you just can no longer tell whether a defect it shows was
caused by the heal.
Guarantees
- Non-destructive: your input file is never modified.
- Deterministic: same input → same certificate and same repaired bytes.
- Permissive-licensed: MIT/BSD/Apache-2.0 dependencies only (CI-gated).
- Stateless & offline: no network, no telemetry, nothing leaves your box.
Exit codes
| Code | Meaning |
|---|---|
| 0 | every asset PASSes (and passes all targets) |
| 1 | at least one asset FAILs |
| 2 | a load/engine error |
For verify, an UNVERIFIED certificate gates like a FAIL (exit 1). Pass
--allow-unverified to accept a geometry-only pass on a box with no headless GL.
Metadata
Release files for 3dqa 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| 3dqa-1.0.0.tar.gz | 50.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 3dqa-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 105.4 kB
Release files / 3dqa-1.0.0.tar.gz
| Download URL | 3dqa-1.0.0.tar.gz |
|---|---|
| Size | 50.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a7905ac7512f86896b3e8a31a6be9c2514e9d3c2698df505e711ddbdd2de3a6d
|
|
BLAKE2b-256 checksum How to use checksums |
a78a59b1414b8d145d1a16f3cc4114d47f1251c2419ba3092da6e5e9804c5d5c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / 3dqa-1.0.0-py3-none-any.whl
| Download URL | 3dqa-1.0.0-py3-none-any.whl |
|---|---|
| Size | 54.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e6db905e9a7b9dfb8dcaabeb2001467f09201e76c21a41ad23ea3511f86df40c
|
|
BLAKE2b-256 checksum How to use checksums |
d3398cd20bd227f1af1cbc0e63bc909fe9207d04d9f6bb580882068abc0894d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|