Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...

    Module data/mesh/validate

    Stage 2 of the mesh loader's admission gate: post-decode value checks.

    These are the checks that genuinely need the materialized arrays, so they run after fetch + decode — but only ever on data Stage 1 (preflight.ts) already admitted, so the fetch they gate is bounded before it happens.

    Two things are checked, and each closes a hole the other cannot see.

    Stage 1 vets the declared .zarray shape. A store that declares correctly but materializes short — a raw or mis-sized chunk, a non-compliant decoder — would otherwise resurrect exactly the undersized-attribute drawElements over-read that Stage 1's shape cross-checks exist to close.

    Every index must land in [0, V), and the check must be two-sided and run before the integer→u32 coercion, because each side of that cast hides its own wrap-around:

    • an externally produced signed store's -1 passes a one-sided < V pre-cast check and then wraps to 0xffffffff;
    • a 64-bit store's 2^32 + 1 survives a check run only after the cast — it wraps to 1, lands inside [0, V), and silently rewrites topology instead of trapping.

    The two-sided source-value check rejects both. And because Stage 1 admits only V <= 2^27, every index it passes is preserved bit-for-bit by the u32 cast — so the values checked here are exactly the values the kernels receive.

    Getting this wrong is not a cosmetic bug. An out-of-range index panics the Rust kernel — the crate is panic = "abort", so the trap escapes as an opaque, uncatchable RuntimeError: unreachable that takes down the whole WASM module rather than one node — and silently corrupts the TypeScript backend, whose out-of-bounds reads yield undefined.

    Stage 2 does not finite-scan the float arrays (vertices, normals, colors, scalars). A non-finite value can neither trap a kernel nor over-read a buffer, and its blast radius is already per-node without a gate: a NaN/±Inf coordinate on a hidden dimension hides the vertex (the #806 rule the cull kernels enforce), a non-finite displayed coordinate corrupts at most that node's rasterization and bounding sphere (which the depth-sort coordinator already refuses to sort by), non-finite colours are clamped by the shared shader sanitizers, and a non-finite stored normal degrades only that node's shading. No sibling loader finite-scans its decoded positions either; mesh matches that policy rather than inventing a stricter one.

    FaceIndexSource
    validateMaterializedLength
    validateFaceIndices