Checks reference
Every check in v1 — what it measures, how, and its default severity.
Check IDs are permanent: they are never reused or renumbered. Severities and tolerances live in versioned config, so the numbers below are shipped defaults, not law — any request can override a threshold or pass a fully custom profile.
Severity — error fails the report; warning passes with warnings; info is a measurement with no
judgment. Status per check — pass, warn, fail, skipped (with a reason), or error (the check
itself crashed; never silently omitted).
SPEC — File & spec conformance
| ID | Name | Method | Default severity |
|---|---|---|---|
| SPEC-001 | glTF spec conformance | Run the Khronos gltf-validator; map its errors/warnings into the report | error/warning passthrough |
| SPEC-002 | Required extensions supported | Compare extensionsRequired against the support list |
error if unsupported required ext |
| SPEC-003 | External references resolvable | For .gltf: all buffer/image URIs present in the upload bundle |
error |
| SPEC-004 | File size | Bytes vs profile max_file_bytes |
error over budget |
GEO — Geometry integrity
Operates on the merged, transform-applied triangle soup per mesh primitive unless noted.
| ID | Name | Method | Default severity |
|---|---|---|---|
| GEO-001 | Non-manifold edges | Edge→face incidence; edges with more than two faces | warning |
| GEO-002 | Open boundaries (holes) | Edges with exactly one face; hole count + boundary length | warning; error if hole area > hole_area_pct |
| GEO-003 | Inconsistent winding / flipped normals | Adjacent-face winding agreement per shell | error if > flipped_pct (default 5%) |
| GEO-004 | Degenerate triangles | Area < degen_area_eps or duplicate indices |
warning; error > degen_pct (1%) |
| GEO-005 | Duplicate vertices | Position-space grid hash within weld_tolerance |
info (warning > 10% of verts) |
| GEO-006 | Unreferenced data | Vertices/accessors/images no primitive uses | info |
| GEO-007 | Floating debris | Connected components with bbox diagonal < debris_pct of model diagonal |
warning |
| GEO-008 | Zero/negative scale nodes | Node TRS decomposition; det(basis) ≤ 0 or axis scale < eps | warning |
| GEO-009 | Self-intersection (sampled) | BVH triangle-triangle test, capped/sampled above selfx_tri_cap |
info in v1 |
XFM — Transforms & scale
| ID | Name | Method | Default severity |
|---|---|---|---|
| XFM-001 | Real-world scale sanity | World-space AABB extents vs min_extent / max_extent |
warning |
| XFM-002 | Origin/pivot placement | Distance from origin to AABB bottom-center, normalized by diagonal | info (warning if fully offset) |
| XFM-003 | Non-uniform / unapplied node scale | Any node with non-uniform scale on a mesh-bearing branch | info |
UV — Texture coordinates
Skipped (with a reason) if the model has no textured materials.
| ID | Name | Method | Default severity |
|---|---|---|---|
| UV-001 | Missing UVs on textured mesh | Material references a texture but the primitive has no TEXCOORD_0 |
error |
| UV-002 | UV overlap | Rasterize UV islands at 1024² ; % texels covered twice or more | warning > uv_overlap_pct (5%) |
| UV-003 | UVs outside [0,1] | % of UV verts outside the unit square | info (tiling is legitimate) |
| UV-004 | Texel stretch | Per-tri UV-area to 3D-area ratio, normalized to median; p95 deviation | warning if p95 > stretch_ratio (2.0) |
| UV-005 | Island padding | Min gap between islands, in texels at declared texture res | warning < min_padding_px (4px) |
| UV-006 | Texel density variance | Std-dev of per-tri texel density / median | info |
MAT — Materials & textures
| ID | Name | Method | Default severity |
|---|---|---|---|
| MAT-001 | Texture resolution vs budget | Max texture dimension vs max_texture_dim |
error over budget |
| MAT-002 | Estimated GPU texture memory | Σ (w×h×4 × 1.33 mip factor) vs max_texture_mem |
warning over budget |
| MAT-003 | Non-power-of-two textures | Per-image dimension check | info (warning for mobile) |
| MAT-004 | Material count | Unique materials vs max_materials |
warning over budget |
| MAT-005 | PBR value sanity | Base-color luminance and metallic on large surface share | info |
| MAT-006 | Oversized embedded textures vs usage | Resolution vs texel density needed given UV coverage | info |
PERF — Performance budget
| ID | Name | Method | Default severity |
|---|---|---|---|
| PERF-001 | Triangle count | Post-transform tris vs max_tris |
error over budget |
| PERF-002 | Vertex count | Renderer-effective verts vs max_verts |
warning |
| PERF-003 | Draw call estimate | Σ primitives × material switches vs max_draw_calls |
warning |
| PERF-004 | Node count | Scene-graph node total vs max_nodes |
info |
| PERF-005 | Vertex attribute bloat | Unused attribute sets with byte cost | info |
| PERF-006 | Compression opportunities | Absence of meshopt/Draco/KTX2 with estimated savings | info |
RND — Render checks
Require the renderer; reported skipped in checks_only mode.
| ID | Name | Method | Default severity |
|---|---|---|---|
| RND-001 | Renders without error | Three.js load + render succeeds within timeout | error |
| RND-002 | Visible pixels | Non-background pixels > 0.5% of frame on all standard angles | error |
| RND-003 | Silhouette coverage | % frame coverage per angle; flags thin/empty silhouettes | info |
VIS — Vision checks
/inspect only. Non-deterministic; never part of a /validate report. Every VIS result carries
"deterministic": false and the model version.
| ID | Name | Method |
|---|---|---|
| VIS-001 | Prompt match | Standard angles + prompt → { match, confidence, mismatches[] } |
| VIS-002 | Texture artifact scan | Vision model prompted for seams, smearing, baked lighting, AI artifacts |
| VIS-003 | Freeform Q&A | User question over renders → structured answer |
TOP — Topology & surface structure
Added in phase 5 (report schema 1.1). glTF stores only triangles, but good topology leaves measurable
fingerprints in the triangle soup. All four TOP checks are pure measurements and default to info — an
all-triangle mesh (decimated game asset, scan data) is legitimately low-scoring and is never accused of a
defect. They build adjacency on the position-welded graph (tolerance weld_tolerance, default 0.001) so
UV/normal seams don’t split vertices and skew the readings.
| ID | Name | Method | Default severity |
|---|---|---|---|
| TOP-001 | Quad reconstructibility | Greedily pair triangles across shared manifold edges into planar (≤ quad_planar_deg, 40°), well-shaped (corners within quad_shape_deg, 30°, of 90°), strictly convex quads, scored with Blender’s quad_calc_error; reports quad_pct = paired tris / total tris |
info |
| TOP-002 | Vertex valence regularity | Valence distribution over interior vertices: valence_regular_pct in the 5–7 band, pole density (≤3 or ≥8). Skipped below min_interior_verts (100) interior verts |
info |
| TOP-003 | Triangle regularity & density | p95 aspect ratio (longest edge / min altitude), area coefficient of variation, p95 local density deviation; info-only references | info |
| TOP-004 | Hard-edge share | Share of manifold-interior edge length whose angle between adjacent face normals is ≥ hard_edge_deg (90°, inclusive), on the tolerance-welded edge map; reports hard_edge_count and hard_edge_len_pct |
info |
TOP-001 measures retopology quality — high on authored/retopologized meshes, low on raw generator soup — and a low reading is a legitimate value, not an accusation. TOP-004 uses the same 90° threshold and edge convention as the Khronos glTF Asset Auditor’s hard-edge check; meshcheck additionally reports a length-weighted share so a million tiny edges don’t drown one long hard seam.
Budget profiles
| Param | web | mobile | pc | hero |
|---|---|---|---|---|
| max_tris | 25,000 | 10,000 | 150,000 | 500,000 |
| max_verts | 40,000 | 15,000 | 250,000 | 800,000 |
| max_texture_dim | 2048 | 1024 | 4096 | 8192 |
| max_texture_mem | 32 MB | 12 MB | 256 MB | 1 GB |
| max_materials | 4 | 2 | 16 | 32 |
| max_draw_calls | 8 | 4 | 32 | 64 |
| max_file_bytes | 25 MB | 10 MB | 100 MB | 250 MB |
| min / max extent | 0.01–50 m | 0.01–50 m | 0.01–50 m | 0.01–50 m |
Pass profile: "web" with overrides: { max_tris: 15000 } to adjust a single parameter, or send a fully
custom profile object.