Generating glTF Files Dynamically in the Browser
Dynamic programmatic generation of glTF (GL Transmission Format) files directly in the browser allows web applications to create, manipulate, and export 3D models on the client side without relying on server-side rendering pipelines. By leveraging modern browser APIs such as TypedArrays, ArrayBuffers, and the Blob API alongside specialized JavaScript libraries or native WebAssembly modules, developers can procedurally synthesize 3D geometry, assemble valid glTF or GLB structures, and deliver them instantly to users for preview or download.
1. High-Level Engine Exporters
The most straightforward way to generate glTF files is by using established 3D WebGL/WebGPU engines like Three.js or Babylon.js. These frameworks provide built-in abstraction layers that convert live scene graphs into valid glTF or binary GLB formats.
- Three.js (
GLTFExporter): You can programmatically define aMeshwith aBufferGeometry(specifying custom attributes likeposition,normal, anduv) and aMaterial. TheGLTFExportermodule serializes the mesh into either a JSON glTF object or a binary GLBArrayBuffer. - Babylon.js (
GLTF2Export): Babylon.js offers a dedicated serializer that converts its internal mesh structures, materials, and animations directly into glTF/GLB files viaGLTF2Export.GLBAsync().
This method is ideal when the application already uses a 3D engine for rendering and interaction, as it requires minimal low-level binary manipulation.
2. Low-Level Manual GLB Construction
For lightweight applications that want to avoid the overhead of a
full 3D rendering engine, glTF files—specifically binary
.glb files—can be constructed from scratch using native
JavaScript binary manipulation tools.
A standard GLB container consists of:
- A 12-byte header: Magic number
(
0x46546C67), version (2), and total file length. - Chunk 0 (JSON): Contains the structural definition—scenes, nodes, meshes, accessors, and buffer views.
- Chunk 1 (BIN): The raw binary data containing vertex positions, indices, normals, colors, and textures.
To build this manually:
- Use
Float32Arrayto define vertex positions, normals, and texture coordinates. - Use
Uint16ArrayorUint32Arrayfor face indices. - Concatenate these arrays into a single contiguous
ArrayBuffer. - Build the JSON metadata defining how
bufferViewsslice the buffer and howaccessorsinterpret the data types (e.g.,VEC3,SCALAR). - Package the chunks together using
DataViewto write the appropriate binary chunk headers and byte-alignment padding (4-byte alignment).
3. Specialized Headless glTF Libraries
When manual byte manipulation is too complex but a full rendering engine is too heavy, developers turn to specialized headless libraries designed strictly for glTF generation and mutation:
- glTF-Transform: A modular TypeScript/JavaScript
library that runs in the browser. It allows you to create a
Document, appendNode,Mesh,Primitive, andAccessorinstances, and export the document directly to a binary GLB array without needing WebGL context. - Minimal GLB Packagers: Small utility packages or custom micro-scripts that simply wrap raw geometry data into the formal GLB structure, keeping bundle sizes under a few kilobytes.
4. WebAssembly (Wasm) Pipelines
For computationally heavy procedural generation—such as Marching Cubes, CAD-style boolean operations (CSG), or procedural terrain synthesis—JavaScript can become a performance bottleneck.
Developers can compile languages like Rust, C++, or Go into
WebAssembly to handle geometric calculations. Libraries such as
gltf-rs (Rust) or tinygltf (C++) can run
inside the browser thread or a Web Worker, compute the mesh, serialize
it directly into a glTF/GLB byte array, and return the pointer or buffer
to JavaScript.
5. In-Browser Output and Persistence
Once the glTF/GLB data is produced as an ArrayBuffer or
a JSON string:
- Blob Creation: Wrap the binary data in a
Blobwith the MIME typemodel/gltf-binary(for GLB) ormodel/gltf+json(for glTF). - Object URLs: Generate an ephemeral URL using
URL.createObjectURL(blob)to feed the generated file into a standard<model-viewer>component or trigger an immediate user download via an anchor tag (<a download="...">).