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

    Interface MeshPreflightResult

    What Stage 1 established.

    The first three fields are the ones Stage 2 reads: the loader destructures { nVertices, nFaces, ndim } and every validateMaterializedLength call derives its expected length from them.

    The last two are deliberately NOT a source of truth, and it matters that this is stated, because the codebase's own rule is that a field no consumer reads is indistinguishable from a field that is wrong (see scene-loader/geometry-descriptors.ts). Both are byproducts of Stage 1 VALIDATION — the checks are the point, the values are how a test can observe that the checks ran. Their real consumers read elsewhere on purpose:

    • colorComponents — the loader calls the shared colorComponentsOf, the same helper the three sibling loaders use, rather than threading this through. The two agree because Stage 1 has already rejected anything but 3 or 4, which is the strictness colorComponentsOf (non-4 ⇒ 3) does not have on its own.
    • normalDims — the winding frame reaches projectMeshTo3D from the node's attrs.normal_dims via the handler, since the projection runs per slice move and does not hold a preflight.

    So: read these two in tests, not in production code.

    accountedBytes is different — unlike the two above, it HAS a production consumer. It is the same peakBytes figure this function's own byte-budget check compares against MESH_DECODE_BUDGET_BYTES (stored bytes, decoded bytes and the largest single chunk buffer, summed), returned so a caller charging several preflights against ONE ceiling — mesh-progressive-loader.ts's MeshProgressiveLoader.assertWithinByteBudget, for a reveal ladder's levels — never has to re-derive the accounting itself. Re-deriving it is exactly how the budget was bypassed four times before (see ENCODING_BUDGET_KIND's docstring); returning the number this function already computed keeps there being exactly one place that does the arithmetic.

    interface MeshPreflightResult {
        nVertices: number;
        nFaces: number;
        ndim: number;
        colorComponents?: 3 | 4;
        normalDims?: number[];
        accountedBytes: number;
        texture?: TextureDeclaration;
    }
    Index
    nVertices: number

    Vertex count, <= MAX_MESH_VERTICES

    nFaces: number

    Triangle count, >= 1

    ndim: number

    Coordinate dimensionality; equals the vertices declared width

    colorComponents?: 3 | 4

    Channels per color entry, when colors is present. Observation only — see above.

    normalDims?: number[]

    The validated normal_dims, when normals is present. Observation only — see above.

    accountedBytes: number

    The node's total accounted bytes (stored + decoded + largest chunk) — the exact quantity this function compares against MESH_DECODE_BUDGET_BYTES. HAS a production consumer, unlike colorComponents/normalDims above: the mesh reveal ladder sums this across every level to charge the ladder once against one budget, IN ADDITION TO each level's own per-level check here against that same budget — not instead of it.

    The validated texture declaration, when the node has a texture.

    A production consumer, like accountedBytes and unlike the two observation-only fields above: the loader decodes and Stage-2-checks against THESE numbers rather than re-reading attrs.texture_*. Re-reading would put a second, unvalidated copy of the load-bearing dimensions in the one place that allocates from them — the same "re-deriving the accounting" mistake that bypassed the byte budget four times.