# MeshIR Buffer Layout This document is the versioned boundary between the Blender reader and the Three.js renderer. The compatibility C ABI returns a JSON snapshot. The preferred ABI separates JSON metadata from a native WBG1 geometry stream, and the Worker transfers each typed mesh buffer without reconstructing large JSON arrays. JSON arrays remain a fallback for older engine binaries. ## Coordinate and topology contract - Blender source coordinates are right-handed, Z-up, with forward `-Y`. - Positions and normals use packed little-endian IEEE-754 `float32` values. - `indices` are packed little-endian unsigned 32-bit integers and reference `positions` vertices. - `topology` is `triangles`; every three indices form one triangle. - `triangleCornerIndices` maps every index entry to the original Blender mesh corner. It is required when UV or color attributes are present because a single position can have multiple corner values. - `triangleMaterialIndices` has one non-negative integer per triangle and indexes `materialSlotIds`. ## SceneIR fields | Field | Element count | Type | Domain | | --- | ---: | --- | --- | | `positions` | `vertexCount * 3` | `float32` | Point | | `normals` | `vertexCount * 3` | `float32` | Point, normalized | | `indices` | `triangleCount * 3` | `uint32` | Triangle corners | | `triangleCornerIndices` | `triangleCount * 3` | `uint32` | Blender Corner | | `uvs` | `cornerCount * 2` | `float32` | Corner, optional | | `colors` | `cornerCount * 4` | `float32` RGBA | Corner, optional | | `triangleMaterialIndices` | `triangleCount` | `uint32` | Face expanded to triangles | | `triangleFaceIndices` | `triangleCount` | `uint32` | Source face for edit selection | | `edgeVertexIndices` | `edgeCount * 2` | `uint32` | Edge endpoints | | `tangents` | `cornerCount * 4` | `float32` | Corner tangent/sign, optional | | `splitNormals` | `cornerCount * 3` | `float32` | Corner normal, optional | `bounds.min` and `bounds.max` are three finite JSON numbers in source object space. `materialSlotIds` are stable SceneIR IDs and never contain embedded material data. ## Native WBG1 stream The stream starts with `WBG1`, a little-endian schema version and mesh count. Each mesh contains an ID length, eleven element counts, UTF-8 ID bytes, then the following arrays in order: ```text positions:f32, indices:u32, normals:f32, triangleCornerIndices:u32, uvs:f32, colors:f32, triangleMaterialIndices:u32, triangleFaceIndices:u32, edgeVertexIndices:u32, tangents:f32, splitNormals:f32 ``` Every count is element-based and every scalar is 4 bytes, so array starts stay 4-byte aligned. The decoder rejects truncation/trailing bytes, unknown mesh IDs, count/summary mismatches and indices outside `vertexCount`. Topology changes must regenerate triangle-face and edge mappings; stale source arrays are never accepted. `geometryStatus: "binary"` means metadata references a transferred per-mesh buffer through `geometryBufferId`. `geometryStatus: "available"` is the JSON fallback. After the initial WBG1 generation, `MeshGeometryDelta` carries `meshId`, field, byte offset and transferable replacement bytes for stable-size changes; topology or attribute-layout changes replace only that mesh envelope. Network-style progressive sub-mesh streaming is not implied by WBG1.