How to Export 3D Scenes to glTF/GLB in TypeScript
This guide shows how to export 3D scenes to glTF 2.0 JSON and GLB binary format using Aspose.3D FOSS for TypeScript. Call scene.save() with a GltfFormat.getInstance() descriptor and a GltfSaveOptions object. Set GltfSaveOptions.binaryMode = true to produce a single GLB container, or leave it at the default false for a .gltf file with separate binary buffers.
Step-by-Step Guide
Step 1: Install @aspose/3d
Install the package from the npm registry using the command below:
npm install @aspose/3dConfirm the installed Node.js version meets the minimum requirement of 18 or later:
node --version # must be >= 16.0.0Step 2: Import Scene, GltfSaveOptions, and GltfFormat
Import the classes required to create a scene and configure the glTF export:
import { Scene } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';GltfFormat is the format descriptor passed to scene.save(). GltfSaveOptions carries all export configuration.
If you are also loading a source file (e.g., OBJ), import the matching load options:
import { ObjLoadOptions } from '@aspose/3d/formats/obj';Step 3: Build or load a scene
Option A: Load from an existing file (OBJ → GLB conversion):
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
scene.open('model.obj', new ObjLoadOptions());Option B: Build a minimal scene programmatically:
import { Scene, Node, Mesh } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
const childNode = new Node('cube');
scene.rootNode.addChildNode(childNode);
// Attach geometry to childNode as needed
Step 4: Configure GltfSaveOptions
Create a GltfSaveOptions instance to configure the output format and encoding details for the export:
const saveOpts = new GltfSaveOptions();
// Set to true for a single binary .glb file
// Set to false (default) for JSON .gltf + separate .bin
saveOpts.binaryMode = true;Additional options you may set:
| Property | Type | Default | Effect |
|---|---|---|---|
binaryMode | boolean | false | true → GLB, false → glTF JSON |
flipTexCoordV | boolean | true | Flip UV vertical axis for engine compatibility |
Step 5: Save using scene.save()
Pass the output path, the GltfFormat descriptor, and the configured options:
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
scene.open('model.obj', new ObjLoadOptions());
const saveOpts = new GltfSaveOptions();
saveOpts.binaryMode = true; // produce .glb
scene.save('output.glb', GltfFormat.getInstance(), saveOpts);
console.log('Converted to GLB successfully');To produce a JSON .gltf file with separate binary buffers instead of a single GLB:
saveOpts.binaryMode = false;
scene.save('output.gltf', GltfFormat.getInstance(), saveOpts);
console.log('Exported to glTF JSON successfully');Step 6: Verify the output file
Check that the output file exists and has a non-zero size:
import * as fs from 'fs';
const outputPath = 'output.glb';
const stats = fs.statSync(outputPath);
console.log(`Output file size: ${stats.size} bytes`);
if (stats.size === 0) {
throw new Error('Export produced an empty file: check scene content');
}For a round-trip verification, reload the GLB and inspect the node count:
import { Scene } from '@aspose/3d';
import { GltfLoadOptions } from '@aspose/3d/formats/gltf';
const verify = new Scene();
verify.open('output.glb', new GltfLoadOptions());
let nodeCount = 0;
function countNodes(node: any): void {
nodeCount++;
for (const child of node.childNodes) countNodes(child);
}
countNodes(verify.rootNode);
console.log(`Round-trip verification: ${nodeCount} node(s) in output`);Common Issues and Fixes
OBJ material file not found after export
When saving to OBJ via scene.save('output.obj'), the .mtl material file is written alongside the .obj file automatically. Ensure the output directory is writable and that both files are kept together.
Output .glb is smaller than expected / meshes are missing
If the loaded scene has nodes without entities (e.g., empty groups from an OBJ), those nodes produce no geometry in the GLB output. Confirm your input file has actual polygon data using mesh.controlPoints.length > 0 before saving.
Module resolution error for ‘@aspose/3d/formats/gltf’
Ensure you are on Node.js 18+ and that @aspose/3d is installed in the same node_modules as your entry point. Run npm ls @aspose/3d to confirm the version is 24.12.0 or later.
GltfFormat.getInstance() returns undefined
This indicates a version mismatch between the main @aspose/3d package and a cached older version. Delete node_modules and package-lock.json, then run npm install again.
Textures are missing in the output GLB
Ensure binaryMode = true is set to produce a self-contained GLB. For glTF JSON output, texture image files must be present alongside the output file since they are referenced by relative path.
TypeScript type error on GltfSaveOptions argument
Ensure both Scene and GltfSaveOptions are imported from the same installed package instance. Mixed installs (global + local) can cause interface mismatches.
Frequently Asked Questions (FAQ)
What is the difference between glTF and GLB?
glTF 2.0 JSON (.gltf) stores the scene graph as a human-readable JSON file with separate .bin buffers and image files. GLB (.glb) packages everything into a single binary container. Set binaryMode = true for GLB, false for JSON glTF.
Can I export a scene that was built entirely in code (no source file)?
Yes. Create a Scene, add Node objects, attach Mesh or other entities, then call scene.save(). The scene does not need to originate from a loaded file.
Is glTF export lossless? For geometry and transforms, yes. Materials are mapped to glTF PBR material properties where possible. Proprietary FBX material extensions may lose fidelity during conversion.
Can I export to STL or 3MF instead?
Yes. The pattern is identical; import the corresponding format’s *SaveOptions and *Format.getInstance():
import { StlSaveOptions, StlFormat } from '@aspose/3d/formats/stl';
const opts = new StlSaveOptions();
scene.save('output.stl', StlFormat.getInstance(), opts);Does scene.save() run asynchronously?
No. scene.save() is synchronous. Wrap it in a worker thread if you need to avoid blocking the event loop during large exports.
What Node.js versions are supported? Node.js 18, 20, and 22+. Node.js 16 and earlier are not supported.