GLB (Binary glTF) format: web 3D and AR — single-file OSM export to .glb

2026-04-0911 min read
3dweb3dgltfkhronosar-vr

GLB is the binary container variant of glTF 2.0 from Khronos Group, ratified in June 2017 as part of the core glTF 2.0 spec. Unlike "plain" glTF (a .gltf JSON manifest + companion .bin buffers + separate .png/.jpg textures — three to five files total), GLB packs everything into a single self-contained .glb file: the JSON section, geometry buffers, and embedded textures all live inside one chunked layout under the glTF magic header. That's enough to open a model via drag-and-drop in Microsoft Windows 3D Viewer, load it in three.js with new GLTFLoader().load('city.glb', ...), or display it in the browser through <model-viewer src="x.glb"> with zero preprocessing. On osm2cdr.ru gltf_exporter.py uses the same Building3DExporter pipeline as glTF, but the final step is pack-as-GLB through trimesh.Mesh.export(file_type='glb'), giving you a single-file deliverable for web/AR/Sketchfab.

Map generation of Novosibirsk city center

History: why Khronos shipped a binary variant

By the time glTF 2.0 launched in June 2017, Khronos had been through COLLADA (XML, 2004) and glTF 1.0 (JSON + .bin + GLSL shaders, 2015). Both had the same practical pain point: a model is not one file but a bundle of manifest + binary buffers + textures. That's a poor fit for:

  • Web upload. Drop one model into Sketchfab or Facebook 3D Posts via drag-and-drop one file — that's user expectation, not three files in a ZIP folder.
  • AR sharing. Send a 3D model to a friend via AirDrop / iMessage — single-file scenario. Multi-file only works inside archives.
  • Drag-and-drop in desktop viewers. Windows 3D Viewer, Reality Composer, Sketchfab — all expect one file.
  • Caching and CDN. One HTTP request for one file beats three parallel coordinated requests.

So glTF 2.0 defines two valid variants from day one: 1. glTF JSON + .bin + textures — for development, version control, hand-editing. 2. GLB — single-file binary for production / sharing / web upload.

Both variants are content-equivalent — literally the same glTF, packed differently. The Khronos gltf-pipeline converter switches between them with one command: gltf-pipeline -i model.gltf -o model.glb or the inverse.

After 2018 GLB became the de-facto preferred distribution variant. Microsoft built native support into Windows 10/11 (Paint 3D, 3D Viewer, Mixed Reality). Apple Reality Composer imports GLB for iOS AR apps (though iOS AR Quick Look's native format is USDZ; see USD/USDZ). Google <model-viewer> takes GLB drag-and-drop. Sketchfab made GLB the primary upload format. Facebook 3D Stories — GLB only.

What's inside the file: chunked layout

GLB is not a "wrapped archive" — it's a specifically defined binary layout. File structure:

Header (12 bytes): - magic (uint32) = 0x46546C67 — ASCII "glTF". These first 4 bytes let viewers recognize GLB. - version (uint32) = 2 — container version (for glTF 2.0). - length (uint32) — total file size in bytes.

Chunk 0 — JSON chunk (mandatory): - chunkLength (uint32) — chunk data size. - chunkType (uint32) = 0x4E4F534A — ASCII "JSON". - chunkData — the same glTF JSON manifest as in the standalone .gltf variant. Describes scene, nodes, meshes, materials, accessors, bufferViews. Padded to 4-byte alignment with spaces (0x20).

Chunk 1 — BIN chunk (optional, but usually present): - chunkLength (uint32) — binary data size. - chunkType (uint32) = 0x004E4942 — ASCII "BIN " with a trailing space. - chunkData — raw binary buffers: vertex positions, normals, UVs, indices, embedded PNG/JPEG textures. Padded to 4-byte alignment with zeros (0x00).

The JSON section inside GLB references the BIN chunk via the standard glTF buffers/bufferViews mechanism: the first buffer has no uri (which in standalone glTF would mean embedded base64), and the runtime treats it as the inline BIN chunk.

Hex dump of the first 64 bytes of a typical GLB:

67 6C 54 46  02 00 00 00  E8 27 00 00     // header: "glTF" version=2 length=10216
44 09 00 00  4A 53 4F 4E                   // chunk 0: length=2372 type="JSON"
7B 22 61 73 73 65 74 22 3A 7B 22 76 65 ...  // chunk data: {"asset":{"ve...

Map generation of Vladivostok city center

GLB vs glTF JSON: when to pick which

GLB and glTF are two variants of the same spec. Content is semantically identical. The differences are operational:

Pick GLB when: - Production deployment — single file is easier to CDN-cache, version, hash-compare. - Web upload to Sketchfab, Facebook, Microsoft 3D Viewer, Google Poly — all expect single file. - AR sharing via AirDrop / iMessage / Telegram — one file in the attachment. - Drag-and-drop UX — the user drops one .glb into the viewer window. - Mobile-friendly delivery — one HTTP request on a cell connection vs three parallel. - E-commerce product viewers — one CDN URL per item.

Pick glTF JSON + .bin when: - Development and debugging — the JSON section is human-readable, openable in an editor. - Version control — git diffs on JSON show semantic changes, not binary diff. - Hand-editing — fix material properties or node transforms by hand. - Texture pipeline — textures sit separately, swappable without re-packing the whole file. - Build tooling — separate .bin and .png are easier to process in a build pipeline (Gulp, Webpack, esbuild).

Conversion between variants is lossless and trivial: gltf-pipeline -i model.gltf -o model.glb or the reverse. File size after GLB conversion is usually 1-2% smaller because base64 overhead on embedded textures and a few layers of JSON whitespace go away.

Strengths and weaknesses

Strengths. Self-contained single file — drag-and-drop into any viewer without losing assets. Embedded PBR materials and textures — render natively in Windows 3D Viewer, Sketchfab, three.js, Cesium. Full compatibility with glTF 2.0 — every glTF loader reads GLB (Khronos requirement). Efficient storage — no base64 overhead, raw binary buffers. CDN-friendly — one URL, one HTTP request. Draco compression supported via KHR_draco_mesh_compression (minus 90% geometry size). KTX2 GPU-native texture compression via KHR_texture_basisu. Microsoft built-in Windows 10/11 drag-and-drop support. AR-ready on Android (<model-viewer ar> loads GLB directly).

Weaknesses. Hand-editing impossible — you have to unpack to JSON+BIN via gltf-pipeline first. Version control less efficient than for the JSON variant — git stores the full binary diff. Not for legacy CAD tools — old SolidWorks / AutoCAD <2020 don't understand glTF/GLB (use FBX or OBJ). Not for 3D printing — slicers (Cura, PrusaSlicer) don't understand materials or textures; export STL instead. For iOS AR Quick Look you need USDZ, not GLB (Apple-specific; see USD deep-dive).

GLB vs USDZ vs FBX

Three single-file 3D container formats competing in web / AR / games:

  • GLB (Khronos, 2017) — universal web + Android AR + games. Royalty-free, open spec. Default choice for a new web/AR project.
  • USDZ (Apple, 2018) — iOS AR Quick Look. It's a USD-based ZIP container, specific to the Apple ecosystem. For iOS-only apps there's no alternative. See USD/USDZ deep-dive.
  • FBX (Autodesk, 1996/proprietary) — Maya / Unity / Unreal animation pipelines. Closed binary format, but a de-facto standard for game dev animation. For a new web project, avoid; for integration into a legacy Unity pipeline, mandatory.

For cross-platform web 3D — pick GLB. For iOS AR Quick Look — USDZ. For integration with an existing Maya/Unreal pipeline — FBX.

Use cases

Web 3D delivery. An e-commerce store (furniture, shoes, jewelry) embeds <model-viewer src="chair.glb" auto-rotate camera-controls ar> on the product page. Visitors rotate the model with their mouse; on mobile, AR Quick Look / Scene Viewer launches. No plugins.

Sketchfab upload. A 3D artist authors a model in Blender, exports via File → Export → glTF 2.0 → Format: glTF Binary (.glb), drag-drops into Sketchfab — model lands in the public gallery with a WebGL viewer.

OSM building viewer. An OSM cartographer exports a district via osm2cdr (format=glb), uploads to CloudFlare R2, drops <model-viewer src="https://r2.example.com/moscow-center.glb"> onto their blog — visitors see the 3D district in-browser with no backend, no plugins.

3D Tiles content payload. Cesium 3D Tiles (OGC standard 1.1, 2023) is a streaming format for city-scale 3D. Tile content inside is GLB (b3dm payload) or JSON+bin glTF. Microsoft Cities, NTT Tokyo Digital Twin, Singapore Smart Nation use GLB-based 3D Tiles to stream cities into the browser.

AR on Android. <model-viewer src="building.glb" ar> on Chrome Android launches Scene Viewer (built-in Google ARCore client), placing the model in the user's room through the camera. No app store, no download.

Drag-and-drop Windows preview. An analyst downloads a GLB building export, double-clicks — Windows 10/11 native 3D Viewer shows the model with PBR materials, mouse rotation, basic measure tools.

Software for GLB

Microsoft Windows 3D Viewer. Free, built-in to Windows 10/11. Double-click on .glb → model opens with PBR rendering, mouse controls, basic measure tools.

Google <model-viewer>. Free HTML web component. One tag in HTML: <model-viewer src="model.glb" auto-rotate camera-controls ar></model-viewer>. three.js + WebXR under the hood. Works on Chrome / Safari / Firefox / Edge, desktop and mobile.

three.js (GLTFLoader). Free JavaScript library, de-facto standard for web 3D. new GLTFLoader().load('model.glb', gltf => scene.add(gltf.scene)) — full 3D scene in one line.

Babylon.js. Microsoft's free JavaScript engine. Alternative to three.js with a batteries-included API. Full GLB support through SceneLoader.Append.

Sketchfab. Freemium 3D-sharing platform. Upload GLB, get an embeddable WebGL viewer with annotations, VR mode, AR mode.

Blender. Free, cross-platform. File → Export → glTF 2.0 → Format: glTF Binary (.glb) — native export with PBR materials, Draco compression checkbox, KTX2 textures.

Cesium ion / CesiumJS. Cesium ion (paid hosting) takes GLB uploads, converts to 3D Tiles. CesiumJS (free) renders GLB via Cesium.Model.fromGltf({url: 'building.glb'}).

Reality Composer (Apple). Free for macOS/iOS. Imports GLB for AR scene composition (though preferred iOS AR format is USDZ).

Unity / Unreal Engine. UnityGLTF (free, Khronos GitHub) and glTFRuntime (Unreal Marketplace) — official plugins to import GLB as runtime assets.

Pipeline in OSM2CDR

Our GLB comes from the same gltf_exporter.py as glTF, in binary=True mode (see glTF deep-dive):

  1. Building3DExporter base — load buildings from PostGIS via the WKB fast-path.
  2. Height calculationheight > building:levels × 3 m > category fallback.
  3. Polygon extrusiontrimesh.creation.extrude_polygon turns a 2D polygon into a 3D prism.
  4. PBR materials — by building type: residential = [0.8, 0.8, 0.8] matte, commercial = [0.6, 0.7, 0.9] semi-gloss, industrial = [0.5, 0.5, 0.5] rough, retail = [0.9, 0.7, 0.4] warm tone.
  5. Pack as GLBtrimesh.Mesh.export(file_type='glb') writes the 12-byte header + JSON chunk + BIN chunk into one .glb file.

Coordinates are Y-up, as the glTF spec requires, same as the glTF exporter: the rotation is written into the scene-graph nodes. No 90° X rotation on import into three.js / model-viewer (it was needed until 2026-08-30, when we still emitted Z-up — that was a bug). If you want Z-up, take OBJ or STL.

Draco compression is off by default in the pipeline — it could land via a compression=draco query parameter (tradeoff: minus 80-90% geometry size, plus CPU decompression cost on the client).

KTX2 textures are unused — OSM data has no building texture maps. If we eventually plug UV mapping based on 3D Tiles photogrammetric textures, KTX2 becomes relevant.

Map generation of Samara city center

FAQ

GLB or glTF — which for production? GLB. Single file is easier to CDN-cache, version, share. glTF JSON + .bin — for development, hand-editing, version control.

Can I unpack GLB back to glTF? Yes, via Khronos gltf-pipeline: gltf-pipeline -i model.glb -o model.gltf. You get a JSON manifest + companion .bin file, ready for editing. The reverse conversion is just as simple: gltf-pipeline -i model.gltf -o model.glb.

Does GLB support animation? Yes. GLB fully supports the glTF 2.0 animation spec: keyframe animations, skeletal animation (skins + joints), morph targets (blendshapes). We don't use animation for OSM buildings — they are static. But if you export a model from Blender with a rigged character, the animation lands in the GLB.

What's the GLB max size? The spec sets no hard limit, but practical constraints exist: mobile WebGL browsers can OOM on files >100 MB. For city-scale exports use the 3D Tiles streaming format, where data is split across many tile-GLBs. Single-GLB sweet spot — 1-50 MB for web delivery.

Will GLB work on iOS AR Quick Look? No. iOS AR Quick Look (a Safari rel=ar link) requires USDZ. For cross-platform AR, use <model-viewer> with two sources: src="model.glb" ios-src="model.usdz" — Android gets GLB through Scene Viewer, iOS gets USDZ through AR Quick Look.

Sources

← All articles