Overview
@luma.gl/gltf is a standards-first asset runtime for physically based materials, animated
characters, morph deformation, native animation pointers, and source-faithful .gltf / .glb
interchange across WebGPU and WebGL. It turns postprocessed glTF assets into ordinary luma.gl
scenegraphs and exports generic scene descriptors without depending on a particular renderer.
File loading, decompression, and glTF postprocessing belong to @loaders.gl/gltf; animation
primitives, geometry, and shader modules remain in their existing luma.gl packages.
Installation
npm install @luma.gl/gltf @loaders.gl/core @loaders.gl/gltf
A rendering application also needs a configured Device from @luma.gl/core, backed by
@luma.gl/webgl or @luma.gl/webgpu.
Load and animate an asset
import {load} from '@loaders.gl/core';
import {GLTFLoader, postProcessGLTF} from '@loaders.gl/gltf';
import {createScenegraphsFromGLTF} from '@luma.gl/gltf';
const asset = await load('/models/model.glb', GLTFLoader);
const gltf = postProcessGLTF(asset);
const scenegraphs = createScenegraphsFromGLTF(device, gltf, {
useTangents: true,
useByteColors: false
});
for (const scene of scenegraphs.scenes) {
root.add(scene);
}
function renderFrame(timeMilliseconds: number): void {
scenegraphs.animator.setTime(timeMilliseconds);
requestAnimationFrame(renderFrame);
}
requestAnimationFrame(renderFrame);
GLTFAnimator.setTime() takes an absolute clock value in milliseconds. The shared
AnimationMixer exposed as scenegraphs.animator.mixer uses seconds. See
glTF animation and deformation before mixing the
legacy wall-clock API with direct mixer controls.
createScenegraphsFromGLTF()
const scenegraphs = createScenegraphsFromGLTF(device, gltf, options);
gltf is the object returned by calling postProcessGLTF() on the loaded asset. loaders.gl v4
does not postprocess automatically. The returned GLTFScenegraphs
bundle contains:
| Property | Contents |
|---|---|
scenes | One @luma.gl/engine GroupNode root per source scene. |
materials | Shared engine materials in source glTF material order. |
variants | Source-aware runtime controller for authored material variants. |
cameras | Runtime camera projections updated by supported animation pointers. |
animator | A GLTFAnimator backed by the shared engine animation mixer. |
animations | Decoded source clips, including supported animation-pointer channels. |
skins | Automatically updated source skin bindings and reusable joint palettes. |
lights | World-space directional, point, and spot lights from KHR_lights_punctual. |
extensionSupport | A map describing support for extensions reported by the asset. |
sceneBounds | World-space bounds and camera-framing recommendations for each scene. |
modelBounds | Combined world-space bounds for the complete asset. |
gltfNodeIdToNodeMap, gltfNodeIndexToNodeMap | Source-node lookup tables for application integration. |
gltfMeshIdToNodeMap | Source-mesh lookup table. |
gltf | The original postprocessed glTF document. |
destroy() | Idempotently releases scene-owned models, materials, buffers, and textures. |
Each bounds object contains bounds, center, size, radius, and
recommendedOrbitDistance.
Asset lifetime
Release the returned scenegraphs when replacing or unloading an asset:
scenegraphs.destroy();
This includes hidden nodes, detached mesh templates, instancing buffers, and generated source-image textures. The application-owned device and borrowed image-based-lighting textures are not destroyed.
Options
type ParseGLTFOptions = {
modelOptions?: Partial<ModelProps>;
pbrDebug?: boolean;
imageBasedLightingEnvironment?: PBREnvironment;
lights?: boolean;
useTangents?: boolean;
useByteColors?: boolean;
};
modelOptionssupplies additional props to generated primitive models.pbrDebugenables shader-level material debugging.imageBasedLightingEnvironmentsupplies existing diffuse, specular, and BRDF lookup textures.lightscontrols the generated material's punctual-light shader configuration. The returnedlightsarray is still parsed from the source asset.useTangentsenables existing authoredTANGENTattributes; it does not generate missing tangent data.useByteColors: falsekeeps authored punctual-light colors in the linear[0, 1]range. The default preserves luma.gl's legacy byte-style light-color convention.
Parsed CPU geometry retains source semantics such as POSITION, NORMAL, TANGENT, COLOR_0,
TEXCOORD_0, TEXCOORD_1, JOINTS_0, and WEIGHTS_0. Shader-facing attribute names are
resolved only at model boundaries.
Materials, textures, and lights
The canonical PBR path preserves all 17 supported core and extension texture slots, authored sampler addressing/filtering, generated or supplied mipmaps, per-slot UV transforms, secondary UV coordinates, advanced material factors, alpha modes, and punctual lights.
Useful low-level exports include parsePBRMaterial, createGLTFTexture, convertGLTFSampler,
convertSamplerToGLTF, getTextureTransformSlotDefinitions, resolveTextureTransform,
resolveTextureCoordinateSet, parseGLTFLights, and loadPBREnvironment. See the
glTF materials, textures, and lighting reference
for examples, color-space rules, and current transmission limitations.
Animation and deformation
parseGLTFAnimations() decodes translation, rotation, scale, morph weights, selected material
factors, and supported KHR_texture_transform pointers. GLTFAnimator applies STEP, LINEAR,
and CUBICSPLINE tracks through the format-independent engine mixer. Existing shared skinning
and morph-target helpers preserve authored joint attributes, target deltas, and per-node weights.
See glTF animation and deformation, the GPU-animated crowd reference, the engine animation guide, and glTF extension support for details and limitations.
Independently animated GPU crowds
createGLTFAnimatedCrowd() shares one parsed asset and one GPU model per reachable source
primitive across actors with independently selected clips, phases, playback speeds, and poses.
WebGPU stores joint palettes in read-only storage buffers; WebGL 2 reads equivalent floating-point
palette textures. Distinct actions and crossfades do not split an instanced draw: 100 Robot
Expressive actors still use its 19 source-primitive draws instead of 1,900 separate draws.
See GPU-animated glTF crowds for the complete render loop, actor lifecycle, batching, backend requirements, current morph and LOD limitations, and Animation Studio controls.
Source-faithful asset interchange
exportGLTF() serializes renderer-independent glTF scene descriptors as embedded JSON or binary
GLB. Existing hierarchy, skins, inverse bind matrices, morph targets, animation clips, material
pointers, variants, GPU instancing, cameras, punctual lights, sampler settings, and authored
physical materials remain available to the output asset.
import {exportGLTF, type GLTFExportScene} from '@luma.gl/gltf';
const scene: GLTFExportScene = {name: 'Exported scene', nodes: [{name: 'Root'}]};
const document: string = exportGLTF(scene);
const binary: ArrayBuffer = exportGLTF(scene, {binary: true});
See glTF asset interchange for typed descriptors, RGBA vertex colors, normalized joint weights, animation pointers, and resource ownership.
Package ownership
@loaders.gl/gltfloads and decompresses.gltfand.glbassets.@luma.gl/gltfinterprets glTF-specific scene, material, sampler, light, and animation data.@luma.gl/engineowns generic scenegraph, animation, and morph-target primitives.@luma.gl/shadertoolsowns the shared PBR, lighting, and skinning shader modules.@luma.gl/anari/gltf, when explicitly imported, adapts decoded glTF data to retained ANARI objects without making the core ANARI entry point a glTF loader.