Squared centroid magnitude cx² + cy² + cz² from the AABB. Cheap.
Per-vertex-slot remap: canonical[v] === v iff v is the
first occurrence of its byte signature; otherwise points at
the canonical slot to coalesce onto. Returns null for
geometries without positionsCompressed. Used by
geometryQuality's duplicate-vertex check and the
mergeDuplicateVertices fix.
Sorted-vertex-triple keys for triangle-dedup, plus the count
of duplicate (already-seen) triangles encountered during the
walk and a per-triangle "kept" bitmap. Each key is a_b_c
with a ≤ b ≤ c, so all rotations / reflections of the same
triangle collapse to one key. Degenerate triangles
(i0 === i1 || i1 === i2 || i0 === i2) are kept (they're a
separate concern). Returns null for non-triangle geometries.
keys — set of every distinct canonical key seen.duplicateCount — count of triangles whose canonical key
was already in keys at walk time. Read by
geometryQuality's duplicate-triangles check.kept — Uint8Array(triCount) with kept[t] === 1 iff
t was the first occurrence of its canonical key (or is
degenerate). Read by the dropDuplicateTriangles fix to
know which triangles to keep.FNV-1a fingerprint over typed-array bytes, primitive constant,
and AABB. Includes render-significant optional attributes such
as colors, edges, and gaussian splat payloads. Two geometries
with the same contentHash have identical content (modulo
birthday-paradox collisions, which are negligible for ≪ 10⁶
geometries). Used by
duplicateGeometries.
Dequantized vertex positions (3 floats per vertex), produced
by decompressPositions3WithAABB3. The heaviest column —
roughly 3 × vertCount × 4 bytes per geometry — gated behind
lazy access so callers that don't need it don't pay. Used by
similarGeometries, geometryQuality's degenerate
triangle check, and the recenter / similar-merge fixes.
Directed edge → incidence count. Key is a_b. Manifold
meshes have each shared edge traversed in opposite
directions by its two adjacent triangles, so any directed
edge with count > 1 indicates inconsistent winding. Returns
null for non-triangle geometries. Used by
geometryQuality's winding check.
64-bin log₂ histogram of every triangle edge's length. Pose-
invariant shape fingerprint (translation / rotation /
reflection independent; NOT scale-invariant). Returns null
for non-triangle geometries. Used by
similarGeometries.
Undirected edge → list of triangle ids that include it,
plus a per-triangle degeneracy bitmap. Same key shape as
undirectedEdgeIncidence, but the heavier triangle-id
list is only paid when a consumer actually needs adjacency
(the unifyTriangleWinding fix's flood-fill walk). The
degenerate bitmap has degenerate[t] === 1 iff triangle
t has repeated indices (its edges are NOT registered in
edges). Returns null for non-triangle geometries.
geometryId → ids of every non-destroyed mesh referencing it.
Unlike the other reverse tables this one is mutation-aware: it
builds once, then stays current by tracking
onSceneMeshCreated / onSceneMeshDestroyed on the owning Scene.
That lets a fix which repoints meshes across many issues (e.g.
mergeSimilarGeometries) read O(1) per geometry for the whole fix
pass instead of rescanning every mesh per fix. The event
subscription is released by invalidateAll — a caller
driving fixes outside the framework should call it when done.
geometryId → de-duplicated ids of non-destroyed SceneObjects that
own a non-destroyed mesh referencing the geometry (object order
follows sceneModel.meshes iteration). Built once by a single
mesh walk and shared across every geometry-tied inspection, so a
check populating Issue.highlight pays O(1) per geometry
instead of re-scanning all meshes. Empty array when unreferenced.
Backs findSceneObjectsForGeometry.
Clear every cached row in the index.
Drop one geometry's cached rows.
Drop one object's cached rows.
Drop the per-scene reverse-reference tables.
materialId → mesh ids that reference it.
World-space AABB (union of mesh world AABBs). Used by objectPlacement's far-from-origin and duplicate-AABB checks.
Free the heaviest cached rows (decompressed positions,
directed/undirected edge maps, canonical-triangle key sets)
but keep the cheap ones (content hash, topology key,
canonical slots, AABB centroid). Called by the orchestrator
after inspectSceneModel returns, unless the caller pinned
them.
textureId → material ids that reference it.
${primitive}|${vertCount}|${triCount} topology key. Two
geometries with the same key have the same primitive type
and the same vertex / triangle counts — a fast pre-bucket
for shape-similarity matchers. Used by
similarGeometries.
Undirected edge → incidence count. Key is lo_hi with
lo = min(a, b), hi = max(a, b). Watertight closed
manifolds have every edge incident to exactly 2 triangles.
Returns null for non-triangle geometries. Used by
geometryQuality's non-watertight check.
Bit per vertex slot — 1 = referenced by some entry of
geom.indices or geom.edgeIndices, 0 = unused. Used by
geometryQuality's unused-vertex check and the
compactUnusedVertices fix.
Lazy per-column cache of derived data the inspect / fix pipeline reads from a SceneModel. Single source of truth for "expensive precomputable rows" — content hashes, vertex dedup maps, edge incidence counts, decompressed positions, reverse-reference tables — so the same work isn't repeated by every inspection that needs it (and again by every fix that touches the same geometry).
Per-column lazy. Each accessor builds and caches on first call, returns the cached value thereafter. A consumer that only needs
contentHashdoesn't pay fordecompressedPositionsoredgeToTriangles.Where it lives. Held in a process-local WeakMap keyed by SceneModel via getInspectionIndex — no SceneModel API change, auto-GC'd, transparent to consumers. Each
inspectSceneModel/applyFixesrun reuses the same index across inspections + fixes.Invalidation. Coarse, orchestrator-driven. After a fix mutates a geometry the orchestrator calls invalidateGeometry; after a fix touches references it calls invalidateReferences. Clients that mutate the SceneModel outside the framework should call invalidateAll when they're done.