@bitruvius/gltf
v0.3.1
Published
Bitruvius SDK glTF 2.0 / GLB parser + OGC 3D-Tiles container handlers (b3dm/i3dm/cmpt/pnts): pure TS, no WebGL/DOM/codecs. Normalizes tile content to a GPU-ready struct-of-arrays mesh/point representation; geometry decompression and texture transcode are
Readme
@bitruvius/gltf
glTF 2.0 / GLB and OGC 3D Tiles container parsing in pure TypeScript, with no WebGL, no DOM and no codecs.
Internal building block. This package exists so that
@bitruvius/sdk-maplibreand the Bitruvius codecs can resolve their dependencies on npm. It has no standalone product story. Unless you are deliberately building against it, install the SDK instead.
What it does
Hand it tile bytes. It sniffs the 4-byte magic, unwraps the container (glTF, b3dm, i3dm,
cmpt, pnts), reads glTF accessors into tightly packed typed arrays, flattens the node graph
into world-placed primitives, flattens materials into a default-filled contract, and returns one
indirection-free struct-of-arrays mesh or point cloud that a GPU path can upload as it stands.
Nothing in it touches a GPU, a canvas, or a WASM binary.
Why it is its own package
Three constraints forced the split, and each one is visible in the source.
The codecs must not be a dependency. Draco, meshopt and KTX2 are megabytes of WebAssembly, and
most tiles need none of them. So compression is consumed through seams: DracoGeometryDecoder,
MeshoptDecoder and Ktx2Transcoder. The seam interfaces are declared in @bitruvius/geo-core,
not here, so a codec wrapper depends only on core and never on the parser. @bitruvius/draco,
@bitruvius/meshopt and @bitruvius/ktx2 implement them and are injected at the call site. An
uncompressed tileset therefore decodes without a single WASM download, each codec ships and
versions on its own, and a tile that needs a seam you did not supply throws an error naming the
missing package instead of mis-decoding quietly.
It has to run in a worker. @bitruvius/tiles3d-mesh and @bitruvius/tiles3d-points pool this
parser off the main thread so a streaming city does not spend the map's frame budget. That rules
out WebGL types, document, and anything else the main thread owns. Input is bytes, output is
typed arrays, transferable as they are.
Mesh and point content share the hard parts and must not depend on each other. The container
parsers, the feature/batch table reader, the accessor reader, the magic dispatch and the
octahedral-normal decode are common to textured mesh, BIM and LiDAR. Put them in the mesh package
and the point package inherits a renderer it never uses, and the reverse. A shared base below both,
plus @bitruvius/sdk-maplibre, is the only arrangement in which none of them depends on another.
The output contract lives in core as well (NormalizedMesh, PackedMeshTile, PackedPointTile),
so the renderers consume packed buffers and never see glTF at all.
What is in it
| Area | What it covers |
| --- | --- |
| Containers | parseGlb, parseB3dm, parseI3dm, parsePnts, splitCmpt, sniffMagic. Zero-copy: the parts are views into your buffer. |
| glTF reading | readAccessor, resolveBuffer, decodeDataUri, flattenNodes, normalizeMaterial / normalizeMaterials. |
| Normalization | buildNormalizedMesh for the uncompressed path (synchronous), buildNormalizedMeshAsync for KHR_draco_mesh_compression and EXT_meshopt_compression through the geometry seams. |
| Textures | decodeTextures: a KTX2 transcode seam (KHR_texture_basisu) plus an injected JPEG/PNG image decoder, so the same code runs in a browser worker and in a test. |
| Tile decoders | GltfMeshDecoder, CesiumPntsDecoder, Tiles3DPointDecoder, and their functional forms, taking tile bytes to ENU-rebased packed tiles. |
| Instancing | 1.0 i3dm and 1.1 EXT_mesh_gpu_instancing converge on one per-instance matrix buffer, so the renderer has a single instanced path. |
| Feature metadata | 1.0 batch tables with 3DTILES_batch_table_hierarchy, 1.1 EXT_structural_metadata property tables, and per-point property attributes, all normalized into the shared FeatureProperties so picking, filtering and styling behave the same whatever the tileset version. |
Both generations of 3D Tiles are covered on both content paths: 1.0 b3dm / i3dm / pnts, and
1.1 glTF meshes and glTF POINTS. They produce the same packed output, so nothing downstream
branches on tileset version.
import { parseGlb, buildNormalizedMesh } from '@bitruvius/gltf';
const mesh = buildNormalizedMesh(parseGlb(bytes));
for (const prim of mesh.primitives) {
prim.positions; // Float32Array, 3 per vertex
prim.indices; // Uint16Array | Uint32Array | undefined
prim.nodeMatrix; // composed node world transform, column-major
}Compressed content takes the async form with the seams you supply:
await buildNormalizedMeshAsync(parseGlb(bytes), { draco, meshopt }).
Who should depend on it
Almost nobody, directly. To stream 3D Tiles into a map, install
@bitruvius/sdk-maplibre, which composes
this parser with the codecs and a worker pool for you.
Reach for it directly only when you are building your own pipeline against the Bitruvius contracts and want tile content as typed arrays: a custom renderer, an offline conversion step, a server-side inspector. It is a parser, not a loader. Fetching, tile-tree traversal, level-of-detail and placement all live above it.
Its only runtime dependency is @bitruvius/geo-core.
Trademarks
Cesium and 3D Tiles are trademarks of Cesium GS, Inc. glTF, KTX and WebGL are trademarks of The Khronos Group Inc. OGC is a trademark of the Open Geospatial Consortium. Google and Draco are trademarks of Google LLC. MapLibre is a trademark of the MapLibre organization. All other marks are the property of their respective owners.
These names are used solely to describe the data formats this software interoperates with. Bitruvius is not affiliated with, sponsored by, or endorsed by any of them, and no such relationship is implied. Implementing a published specification is not a claim of certification: Bitruvius has not undergone OGC compliance testing for any standard.
License
Proprietary. The full terms ship as LICENSE inside this package, and are readable
before installing at cdn.bitruvius.com/legal/sdk-license-v1.txt.
© Bitruvius, Inc.
