IFClite TypeScript API
    Preparing search index...

    Interface MeshData

    Mesh data for a single geometric representation of an IFC element.

    An element may produce MULTIPLE MeshData entries (one per material, CSG part, or representation item). Group by expressId for per-element operations such as DOM grouping, picking, or depth sorting. The number of meshes per element depends on the IFC file's geometric complexity.

    interface MeshData {
        appearanceSource?: {
            cornerIndices?: Uint32Array<ArrayBufferLike>;
            indices: Uint32Array;
            kind: "canonical-item";
            sourceIndices: Uint32Array;
        };
        color: [number, number, number, number];
        entityIds?: Uint32Array<ArrayBufferLike>;
        expressId: number;
        geometryAabb?: EntityWorldAabb;
        geometryClass?: number;
        geometryHash?: bigint;
        geometryItemId?: number;
        geometryVolume?: number;
        ifcType?: string;
        indices: Uint32Array;
        localBounds?: {
            max: [number, number, number];
            min: [number, number, number];
        };
        localToWorld?: number[];
        material?: { metallic?: number; roughness?: number };
        materialId?: number;
        modelIndex?: number;
        normals: Float32Array;
        occurrenceKey?: string;
        origin?: [number, number, number];
        positions: Float32Array;
        shadingColor?: [number, number, number, number];
        texture?: MeshTexture;
        textureBitmap?: ImageBitmap;
        textureRef?: MeshTextureRef;
        uvs?: Float32Array<ArrayBufferLike>;
    }
    Index
    appearanceSource?: {
        cornerIndices?: Uint32Array<ArrayBufferLike>;
        indices: Uint32Array;
        kind: "canonical-item";
        sourceIndices: Uint32Array;
    }

    Canonical item triangle order, stamped at WASM extraction before streaming. Rebuilt topology must discard this metadata. The repeated indices reference survives structured clone and detects replacement without hashing geometry.

    Type Declaration

    • OptionalcornerIndices?: Uint32Array<ArrayBufferLike>

      Current triangle corner -> canonical triangle corner. Absent means identity.

    • indices: Uint32Array

      Identity fence for the current geometry topology.

    • kind: "canonical-item"
    • sourceIndices: Uint32Array

      Original canonical final geometry, before streaming fragments.

    color: [number, number, number, number]

    Apparent rendering colour: IfcSurfaceStyleRendering.DiffuseColour when authored, otherwise the SurfaceColour. Matches what most IFC viewers display and what the GLB exporter uses by default.

    entityIds?: Uint32Array<ArrayBufferLike>

    Per-vertex entity IDs for color-merged batches (desktop fast path). When present the renderer writes these instead of repeating expressId for every vertex, so picking/selection resolves to the correct individual entity even though many entities share a single GPU batch.

    expressId: number
    geometryAabb?: EntityWorldAabb

    Whole-entity world bounding box from the SAME hashing pass as MeshData.geometryHash (MeshCollection.geometryAabbValues), populated only when geometry hashing is enabled (GeometryProcessor.enableGeometryHashes()). Like the hash, all submeshes of one entity carry the same box — it spans the entity, not this submesh.

    ABSOLUTE world, unlike positions: the RTC offset and the per-element MeshData.origin are already folded in, so two revisions that chose different RTC offsets report the same box. Do NOT add origin to it.

    Absent when the pass produced no box for the entity (the wasm side writes six NaNs there; the extractor drops them rather than passing a NaN-bearing object on), when hashing is off, or on a wasm build predating the getter. Consumed by the model-diff / compare feature to tell a move from a reshape (#1891); renderers ignore it.

    geometryClass?: number

    Geometry provenance for rendering and the viewer's Model/Types view switch:

    • 0 = occurrence (placed IfcProduct). RENDER THIS in normal/Model views.
    • 1 = orphan type geometry (an IfcTypeProduct RepresentationMap with no occurrence). RENDER THIS in both Model and Types views.
    • 2 = instanced type template. DO NOT RENDER in normal/Model view. Instances of this type appear as class 0 occurrences with the same shape. Rendering class 2 produces duplicate overlapping geometry. Shown only in the viewer's Types mode.

    Absent/undefined is treated as 0 (occurrence). Downstream filter: if ((mesh.geometryClass ?? 0) === 2) continue;

    geometryHash?: bigint

    RTC-invariant per-entity geometry fingerprint from the WASM mesh pass, populated only when geometry hashing is enabled (GeometryProcessor.enableGeometryHashes()). All submeshes of one entity share the same value (it is the whole-entity hash). Consumed by the model-diff / compare feature (issue #924); renderers ignore it.

    geometryItemId?: number

    The IfcRepresentationItem this mesh came from, so a host can drill from a rendered piece to its entity (#2985). ALWAYS a representation item; materialId carries the other case and the two are NEVER both set. Absent where identity is merged away (single-mesh fallback, cached IfcMappedItem, GPU instancing) (#3199).

    geometryVolume?: number

    Whole-entity enclosed volume in CUBIC METRES, from the SAME hashing pass as MeshData.geometryHash (MeshCollection.geometryVolumeValues, #1993). Like the hash and the box, all submeshes of one entity carry the identical value — it is the volume of the entity, not of this submesh, so summing it across submeshes would multiply it.

    Present only when the meshed geometry was PROVABLY a single closed, orientable, single-component solid (measured coverage on a real corpus: 71.4%, 24,073 of 33,701 elements). Absent means the kernel could not prove a volume — an open shell, a material-layered wall, a multi-item assembly — and NEVER that the volume is zero or that it differs. The wasm side writes NaN there; the extractor drops it rather than passing a NaN-bearing number on.

    It is the volume of what was actually meshed, AFTER opening cuts, so it is not an IFC BaseQuantities GrossVolume and must not be compared with one. Consumed by the model-diff split/merge detector (#1891); renderers ignore it.

    ifcType?: string
    indices: Uint32Array

    Triangle indices (3 per face). NOTE: Winding order is UNRELIABLE (meshes are double-sided by design). Do not use winding for front/back-face determination or normal-based culling. Use depth testing or abs(dot(normal, viewDir)) for shading.

    localBounds?: { max: [number, number, number]; min: [number, number, number] }

    Local (pre-placement, object-space) AABB — positions bounds as they were BEFORE the element's IfcLocalPlacement was baked in (issue #1474). Absent when not captured (e.g. an instancing template, or a mesh built outside the standard element pipeline). Unrelated to origin, which is a world-space translation captured AFTER placement, purely for f32 precision — don't conflate the two.

    localToWorld?: number[]

    The resolved IfcLocalPlacement chain applied to this mesh (issue #1474): row-major 4x4, 16 numbers, WebGL Y-up axis convention — but its translation is the placement's PRE-RTC absolute origin, not the frame positions render in (mesh_world.rs assigns this before subtracting the model's RTC offset). Do NOT shift it when RTC changes. Absent when not captured. All of one entity's MeshData pieces share the same value (one placement per element).

    material?: { metallic?: number; roughness?: number }

    IFC-authored metallic/roughness (#5582): IfcSurfaceStyleRendering's SpecularColour / SpecularHighlight / ReflectanceMethod, mapped in Rust (ifc_lite_processing::style::extract_surface_style_specular). Either field, or the whole object, is absent when the file authored no evidence for it — the renderer's packMeshMaterial then keeps its own default (a matte dielectric, or glass roughness when the authored colour is translucent).

    materialId?: number

    The IfcMaterial layer this mesh slices. DISJOINT from geometryItemId, which used to carry it — so following that field for a layered wall landed on the wrong entity. geometryClass === 3 cannot substitute (#3199). Same id space as expressId: a federated viewer session re-homes it alongside expressId and geometryItemId (applyFederationOffsetToMesh in apps/viewer/src/hooks/useIfcLoader.ts), so a value read off this field is always safe to resolve the same way as expressId (#3525).

    modelIndex?: number
    normals: Float32Array
    occurrenceKey?: string

    Stable key for CPU caches that must distinguish occurrences sharing one expressId. GPU-instanced occurrences are materialized on demand as one MeshData per occurrence, all stamped with the same expressId but holding different world-space positions (issue #1405). Caches keyed on expressId alone (e.g. the measure-snap geometry cache) would collide across them and serve the first occurrence's geometry for every later one. When present, such caches must key on this instead. Absent for flat meshes (one MeshData per expressId), where expressId is already a sufficient key.

    origin?: [number, number, number]

    Per-element local-frame origin (WebGL Y-up, metres): world position of vertex i = origin + positions[3i..3i+3]. Present when the wasm pipeline emits a per-element frame (building-scale f32 precision); absent/[0,0,0] means positions are already absolute world coords (legacy / native / caches predating local frame). The renderer reconstructs world via a per-batch model-matrix translate.

    positions: Float32Array
    shadingColor?: [number, number, number, number]

    SurfaceColour, populated by the WASM extractor only when the file authored a distinct DiffuseColour (so shadingColor !== color). Consumed by the GLB exporter's "Shading" colour-source option. For basic rendering, use color (matches most IFC viewers). For physically-accurate rendering, prefer shadingColor ?? color.

    texture?: MeshTexture

    Decoded surface texture (IfcBlobTexture / IfcPixelTexture), present only for textured meshes (#961). Decoded to RGBA8 entirely in Rust; the renderer uploads rgba verbatim to a GPU texture.

    textureBitmap?: ImageBitmap

    The decoded image for textureRef, attached on the MAIN thread by the viewer after resolving textureRef.url against the .ifcZIP sibling images (#1781). One ImageBitmap instance is shared by every mesh with the same textureRef.textureId; the renderer uploads it to ONE GPU texture per id. Never set by the worker.

    textureRef?: MeshTextureRef

    External image texture reference (IfcImageTexture, #1781): the image ships OUTSIDE the model (a sibling file inside the .ifcZIP), so the pipeline carries the reference and the viewer resolves + decodes it once per textureId, sharing the GPU texture across every mesh that samples it. Mutually exclusive with texture. uvs are present alongside.

    uvs?: Float32Array<ArrayBufferLike>

    Per-vertex texture coordinates (u, v pairs, 1:1 with positions), present only for textured meshes (issue #961).