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 a Mesh with a BufferGeometry (specifying custom attributes like position, normal, and uv) and a Material. The GLTFExporter module serializes the mesh into either a JSON glTF object or a binary GLB ArrayBuffer.
  • Babylon.js (GLTF2Export): Babylon.js offers a dedicated serializer that converts its internal mesh structures, materials, and animations directly into glTF/GLB files via GLTF2Export.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:

  1. A 12-byte header: Magic number (0x46546C67), version (2), and total file length.
  2. Chunk 0 (JSON): Contains the structural definition—scenes, nodes, meshes, accessors, and buffer views.
  3. Chunk 1 (BIN): The raw binary data containing vertex positions, indices, normals, colors, and textures.

To build this manually:

  • Use Float32Array to define vertex positions, normals, and texture coordinates.
  • Use Uint16Array or Uint32Array for face indices.
  • Concatenate these arrays into a single contiguous ArrayBuffer.
  • Build the JSON metadata defining how bufferViews slice the buffer and how accessors interpret the data types (e.g., VEC3, SCALAR).
  • Package the chunks together using DataView to 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, append Node, Mesh, Primitive, and Accessor instances, 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 Blob with the MIME type model/gltf-binary (for GLB) or model/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="...">).