Skip to main content
glTF

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.

GitHub

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:

PropertyContents
scenesOne @luma.gl/engine GroupNode root per source scene.
materialsShared engine materials in source glTF material order.
variantsSource-aware runtime controller for authored material variants.
camerasRuntime camera projections updated by supported animation pointers.
animatorA GLTFAnimator backed by the shared engine animation mixer.
animationsDecoded source clips, including supported animation-pointer channels.
skinsAutomatically updated source skin bindings and reusable joint palettes.
lightsWorld-space directional, point, and spot lights from KHR_lights_punctual.
extensionSupportA map describing support for extensions reported by the asset.
sceneBoundsWorld-space bounds and camera-framing recommendations for each scene.
modelBoundsCombined world-space bounds for the complete asset.
gltfNodeIdToNodeMap, gltfNodeIndexToNodeMapSource-node lookup tables for application integration.
gltfMeshIdToNodeMapSource-mesh lookup table.
gltfThe 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;
};
  • modelOptions supplies additional props to generated primitive models.
  • pbrDebug enables shader-level material debugging.
  • imageBasedLightingEnvironment supplies existing diffuse, specular, and BRDF lookup textures.
  • lights controls the generated material's punctual-light shader configuration. The returned lights array is still parsed from the source asset.
  • useTangents enables existing authored TANGENT attributes; it does not generate missing tangent data.
  • useByteColors: false keeps 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/gltf loads and decompresses .gltf and .glb assets.
  • @luma.gl/gltf interprets glTF-specific scene, material, sampler, light, and animation data.
  • @luma.gl/engine owns generic scenegraph, animation, and morph-target primitives.
  • @luma.gl/shadertools owns 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.