Click a named node to read it as a separate part. Open or drop your own .glb to inspect it in this browser without uploading it.
gltf.read converts a .glb to CPU arrays and materials. It flattens nodes and unpacks accessors. The mesh pool uploads the result with one write per array. The reader needs neither WebAssembly nor TextDecoder and runs in browsers, Node and Hermes. Only Draco meshes need a decoder you add.
Reads a binary glTF 2.0 file into meshes, selected parts, a skin and animations. It applies
default-scene node transforms and groups meshes by material. Morph targets are omitted.
Skinned meshes use their bind pose with four joints and weights per vertex. An unskinned mesh
attached to a joint, such as a helmet, binds to that joint. An unskinned mesh without a joint
ancestor must be read as a part or this throws. A part holding a skinned mesh binds to the skin
as meshes do; other parts have no skin bindings.
It checks every index, count and range before reading. Invalid glTF, unsupported file versions
and unsupported required features throw with details. Use load for a model whose buffers or
images are separate files. For extensions that need conversion,
errors name the gltf-transform command.
@param ― source the file's bytes, from anywhere
@param ― options.parts names of nodes to keep apart from the rest, each posed about its own origin
or, holding a skinned mesh, by the skin
@param ― options.rotation a turn of the whole model, for one that doesn't face +z
@returns ― plain arrays and images, for meshPool.add
Uploads each mesh into the next free ranges and decodes images in the background. Each image
decodes once per pool and format. The first skinned mesh allocates a joint-and-weight buffer
for the full vertex capacity. Throws if the pool is full, the model has no meshes, its
arrays disagree or encoded images have no decoder.
add(
constmodel:gltf.ModelData<never>
model);
await
constwindmill:meshPool.Model
windmill.
Model.ready: Promise<void>
Resolves when all textures have decoded and uploaded, at once for a model whose materials
name none. Until then, meshes draw without textures. Rejects if image decoding fails or the
pool is destroyed before upload. A destroyed pool uploads nothing.
Adds an instance of a mesh, model or group of meshes from the pool. Each mesh uses a row,
and all rows move and change together under one id. values may be a function of each mesh,
to give a model's meshes values of their own. Throws if a mesh belongs to another pool, the
group is empty, a posed kind receives a mesh without joints or the set is full.
Load the bytes with fetch on the web, readFileSync in Node or expo-file-system on React Native. Pass an ArrayBuffer or any view of one to read, including a Node Buffer.
gltf.load fetches a .glb or .gltf with the buffers and images it keeps in separate files, such as a shared Textures/colormap.png, and reads it as read does:
Fetches a .glb or .gltf with the buffers and images it keeps in separate files, then reads
it as read does. It resolves each file's URI against url and fetches them all at once.
Base64 data: URIs are decoded without fetching.
@param ― url the model's address; files it names are fetched from beside it
@param ― options.fetch a fetch of your own, for headers or app assets
@returns ― the model read returns, for meshPool.add
Uploads each mesh into the next free ranges and decodes images in the background. Each image
decodes once per pool and format. The first skinned mesh allocates a joint-and-weight buffer
for the full vertex capacity. Throws if the pool is full, the model has no meshes, its
arrays disagree or encoded images have no decoder.
add(
constcrate:gltf.ModelData<never>
crate);
load resolves each file’s URI against the model’s URL and fetches the files at once. It decodes base64 data: URIs without fetching.
It takes the options of read, and fetch for a fetch of your own, such as one that adds headers.
A file that fails to load throws an error naming its URL.
Exporters often shrink meshes with Draco compression, KHR_draco_mesh_compression, which needs a decoder. The kit bundles none. Create a decoder module with the draco3d package, wrap it with gltf.draco and pass it to read or load:
Makes a Draco decoder for the draco option of read and load from a decoder module you
create, such as await createDecoderModule({ wasmBinary }) from the draco3d package. The kit
bundles no decoder, so a program without Draco models pays nothing for one.
@param ― module a Draco decoder module, made once and shared by every read
Reads a binary glTF 2.0 file into meshes, selected parts, a skin and animations. It applies
default-scene node transforms and groups meshes by material. Morph targets are omitted.
Skinned meshes use their bind pose with four joints and weights per vertex. An unskinned mesh
attached to a joint, such as a helmet, binds to that joint. An unskinned mesh without a joint
ancestor must be read as a part or this throws. A part holding a skinned mesh binds to the skin
as meshes do; other parts have no skin bindings.
It checks every index, count and range before reading. Invalid glTF, unsupported file versions
and unsupported required features throw with details. Use load for a model whose buffers or
images are separate files. For extensions that need conversion,
errors name the gltf-transform command.
@param ― source the file's bytes, from anywhere
@param ― options.parts names of nodes to keep apart from the rest, each posed about its own origin
or, holding a skinned mesh, by the skin
@param ― options.rotation a turn of the whole model, for one that doesn't face +z
@returns ― plain arrays and images, for meshPool.add
Decodes primitives compressed with KHR_draco_mesh_compression. Make one with draco from a
Draco decoder module. Default none, which throws for a model that needs Draco.
draco});
Serve draco_decoder.wasm from the draco3d package beside your files, or import its URL through your bundler. In Node, leave out wasmBinary and the module finds the file itself.
The draco3d entry also loads Draco’s encoder. To bundle only the decoder, import createDecoderModule as the default export of draco3d/draco_decoder_nodejs.js.
Create the decoder once and pass it to every read. Reading stays synchronous. The night market loads its market this way, on the web with draco3d and on React Native with the JavaScript build below.
read decodes each compressed primitive once, also with placements, and checks the decoded arrays against their accessors’ counts and types.
Hermes has no WebAssembly. On React Native, bundle Google’s JavaScript build of the decoder, draco_decoder_gltf.js, and pass gltf.draco the module its DracoDecoderModule() resolves to. It decodes slower than WebAssembly. A gltf.Draco of your own, a function that decodes one primitive’s bytes into indices and attributes, works too.
read returns a gltf.ModelData that you can pass to pool.add:
Field
meshes
One meshPool.MeshData per material, with node transforms applied.
images
Encoded images referenced by index from material textures.
parts
Requested parts, keyed by node name. Empty if none were requested.
clips
Animations as poses.ClipData. Empty if the file has none.
skin
Joint data as poses.SkinData, present only for skinned meshes.
placements
Mesh transforms from nodes, present only with placements.
Each mesh holds:
Field
positions
Three floats a vertex.
normals
Three floats a vertex, unit length.
uvs
Two floats a vertex, from TEXCOORD_0, or zero.
uvs1
Two floats a vertex, from TEXCOORD_1, when a texture of its material reads it or with uvs1: true.
indices
u32, three a triangle, counter-clockwise seen from its front.
material
glTF’s metallic-roughness material, below.
joints
Four a vertex, indices in the model’s skin.joints, with a skin.
weights
Four floats a vertex beside joints, adding up to 1.
extra
color, four floats a vertex, linear RGBA, from COLOR_0, when present.
For the default scene, read transforms positions by node matrices and normals by their inverse transposes. Mirrored nodes reverse triangle winding so fronts remain counter-clockwise.
Strips and fans become triangle lists.
A mesh without normals gets flat normals. Each triangle needs separate vertices, increasing the vertex count by up to three times.
If any primitive has COLOR_0, its mesh gets extra.color. Vertices from other primitives are white. Create the mesh pool with extra: { color: d.vec4f } to keep these colours. Otherwise the pool drops them and warns once.
Each meshPool.MaterialData holds every field, with glTF defaults for omitted ones:
Field
Default
name
''
color
[1, 1, 1, 1]
Base colour factor, linear, with alpha.
roughness
1
metallic
1
emission
[0, 0, 0]
Linear, times KHR_materials_emissive_strength.
textures
none
color, metallicRoughness, normal, emission and occlusion. Each has an image index into images, a sampler with WebGPU address modes and filters, and a uvSet and transform when it reads other coordinates.
normalScale
1
How far the normal texture bends the normal.
occlusionStrength
1
How far the occlusion texture darkens, from 0 for none to 1 for all of it.
alpha, alphaCutoff
'opaque', 0.5
'opaque', 'mask' or 'blend', and where a mask cuts. A renderer draws 'blend' as opaque.
doubleSided
false
Whether its back faces show too.
Without an explicit metallic factor or texture, a material renders as rough white metal. The rogue’s Glow material in the figure has this default. Set its instance to metallic: 0, or set the factor in the file.
Meshes merge by material, so a turret barrel and base with the same material become one mesh. Request independently moving nodes by name to keep them separate, each with its own pivot:
Reads a binary glTF 2.0 file into meshes, selected parts, a skin and animations. It applies
default-scene node transforms and groups meshes by material. Morph targets are omitted.
Skinned meshes use their bind pose with four joints and weights per vertex. An unskinned mesh
attached to a joint, such as a helmet, binds to that joint. An unskinned mesh without a joint
ancestor must be read as a part or this throws. A part holding a skinned mesh binds to the skin
as meshes do; other parts have no skin bindings.
It checks every index, count and range before reading. Invalid glTF, unsupported file versions
and unsupported required features throw with details. Use load for a model whose buffers or
images are separate files. For extensions that need conversion,
errors name the gltf-transform command.
@param ― source the file's bytes, from anywhere
@param ― options.parts names of nodes to keep apart from the rest, each posed about its own origin
or, holding a skinned mesh, by the skin
@param ― options.rotation a turn of the whole model, for one that doesn't face +z
@returns ― plain arrays and images, for meshPool.add
Selects named nodes and their descendants as separate parts instead of entries in
meshes. A selected node nested in another selected node becomes a separate part too. A part
holding a skinned mesh stays bound to the skin. Default none.
Uploads each mesh into the next free ranges and decodes images in the background. Each image
decodes once per pool and format. The first skinned mesh allocates a joint-and-weight buffer
for the full vertex capacity. Throws if the pool is full, the model has no meshes, its
arrays disagree or encoded images have no decoder.
Uploads each mesh into the next free ranges and decodes images in the background. Each image
decodes once per pool and format. The first skinned mesh allocates a joint-and-weight buffer
for the full vertex capacity. Throws if the pool is full, the model has no meshes, its
arrays disagree or encoded images have no decoder.
add(
constturret:gltf.ModelData<"barrel">
turret.
ModelData<"barrel">.parts: {
readonly barrel:gltf.PartData;
}
Contains the requested named nodes and their descendants.
parts.
barrel:gltf.PartData
barrel);// the barrel uses its node pivot
const[
constx:number
x,
consty:number
y,
constz:number
z]=
constturret:gltf.ModelData<"barrel">
turret.
ModelData<"barrel">.parts: {
readonly barrel:gltf.PartData;
}
Contains the requested named nodes and their descendants.
Adds an instance of a mesh, model or group of meshes from the pool. Each mesh uses a row,
and all rows move and change together under one id. values may be a function of each mesh,
to give a model's meshes values of their own. Throws if a mesh belongs to another pool, the
group is empty, a posed kind receives a mesh without joints or the set is full.
Adds an instance of a mesh, model or group of meshes from the pool. Each mesh uses a row,
and all rows move and change together under one id. values may be a function of each mesh,
to give a model's meshes values of their own. Throws if a mesh belongs to another pool, the
group is empty, a posed kind receives a mesh without joints or the set is full.
Contains the requested named nodes and their descendants.
parts.
barrel:gltf.PartData
barrel.
PartData.rotation: Vec4
Gives node rotation in model space as a unit quaternion [x, y, z, w].
rotation]});
A name selects one node in the default scene and all its descendants. Missing names throw with a list of the first 20 available names. Duplicate names also throw.
A part uses its node’s local space, so rotations use the exported pivot, unless it holds a skinned mesh (skinned parts). Node scale and mirroring stay in the vertices. Use position and rotation to place the part within the model.
A named descendant of another named node becomes a separate part, excluded from its parent.
Pass a part to pool.add as a model. It shares the parent model’s images, which the pool decodes once.
By default, a house mesh placed a thousand times becomes a thousand copies merged by material. Set placements: true to read each glTF mesh once in local space and return its node transforms as placements. The pool then stores the house once, and instances draw each placement:
Reads a binary glTF 2.0 file into meshes, selected parts, a skin and animations. It applies
default-scene node transforms and groups meshes by material. Morph targets are omitted.
Skinned meshes use their bind pose with four joints and weights per vertex. An unskinned mesh
attached to a joint, such as a helmet, binds to that joint. An unskinned mesh without a joint
ancestor must be read as a part or this throws. A part holding a skinned mesh binds to the skin
as meshes do; other parts have no skin bindings.
It checks every index, count and range before reading. Invalid glTF, unsupported file versions
and unsupported required features throw with details. Use load for a model whose buffers or
images are separate files. For extensions that need conversion,
errors name the gltf-transform command.
@param ― source the file's bytes, from anywhere
@param ― options.parts names of nodes to keep apart from the rest, each posed about its own origin
or, holding a skinned mesh, by the skin
@param ― options.rotation a turn of the whole model, for one that doesn't face +z
@returns ― plain arrays and images, for meshPool.add
read(
constbytes:ArrayBuffer
bytes,{
placements:true
Reads each glTF mesh once in mesh space when true, with one entry per material. Node
transforms are returned in placements for instancing. Throws for a skinned model. Default
false, which copies placements and merges them by material.
Uploads each mesh into the next free ranges and decodes images in the background. Each image
decodes once per pool and format. The first skinned mesh allocates a joint-and-weight buffer
for the full vertex capacity. Throws if the pool is full, the model has no meshes, its
arrays disagree or encoded images have no decoder.
add(
consttown:gltf.PlacedModelData<never>
town);// stores each glTF mesh once, split by material
Adds an instance of a mesh, model or group of meshes from the pool. Each mesh uses a row,
and all rows move and change together under one id. values may be a function of each mesh,
to give a model's meshes values of their own. Throws if a mesh belongs to another pool, the
group is empty, a posed kind receives a mesh without joints or the set is full.
For poses, read returns skinned meshes in their bind pose with skin data. It returns animations as clips whether or not the file has meshes:
Field
skin.joints
Joints and their ancestor nodes, with parents before children. Each has a name, parent index, rest transform and inverse bind matrix.
clips
Animation names, durations and channels. Each channel names a node, its position, rotation or scale, and its keyframes.
An unskinned mesh attached to a joint, such as a helmet, binds to that joint alone. An unattached mesh throws; read it as a part instead.
A part holding a skinned mesh stays bound to the skin, so one figure can split into pieces you highlight or hide apart. Its meshes keep joints and weights in model space, and its position and rotation are the model’s origin. Add each piece to the pool and draw it with the same pose as the rest. A rigid mesh in such a part follows its joint, as in meshes. Other parts do not bind to joints.
A file containing only clips is valid. Its clips play on skins with matching joint names.
Unnamed nodes and animations get names such as node 12 and animation 3.
All meshes in a model must use one skin. Multiple skins or vertices with more than four joints through JOINTS_1 throw.
glTF and instances.facing use +z as forward. Rotate differently oriented models in the exporter or when reading them. Kernels and deform then use that orientation:
Reads a binary glTF 2.0 file into meshes, selected parts, a skin and animations. It applies
default-scene node transforms and groups meshes by material. Morph targets are omitted.
Skinned meshes use their bind pose with four joints and weights per vertex. An unskinned mesh
attached to a joint, such as a helmet, binds to that joint. An unskinned mesh without a joint
ancestor must be read as a part or this throws. A part holding a skinned mesh binds to the skin
as meshes do; other parts have no skin bindings.
It checks every index, count and range before reading. Invalid glTF, unsupported file versions
and unsupported required features throw with details. Use load for a model whose buffers or
images are separate files. For extensions that need conversion,
errors name the gltf-transform command.
@param ― source the file's bytes, from anywhere
@param ― options.parts names of nodes to keep apart from the rest, each posed about its own origin
or, holding a skinned mesh, by the skin
@param ― options.rotation a turn of the whole model, for one that doesn't face +z
@returns ― plain arrays and images, for meshPool.add
Rotates the whole model around its origin with a unit quaternion [x, y, z, w]. Use this
for models that do not face +z as instances.facing expects. For example, [0, -Math.SQRT1_2, 0, Math.SQRT1_2] turns +x to +z. Parts, skin and clips rotate together; read
separate clip files with the same rotation. Default none.
rotation:[0,-
var Math:Math
An intrinsic object that provides basic mathematics functionality and constants.
Math.
Math.SQRT1_2: number
The square root of 0.5, or, equivalently, one divided by the square root of 2.
SQRT1_2,0,
var Math:Math
An intrinsic object that provides basic mathematics functionality and constants.
Math.
Math.SQRT1_2: number
The square root of 0.5, or, equivalently, one divided by the square root of 2.
SQRT1_2]});// nose from +x to +z
Rotation uses the model origin and applies to parts, the skin and clips. Apply the same rotation when reading a separate clip file for that model.
Images contain encoded bytes and a MIME type, defaulting to image/png if omitted. read copies image bytes so the pool’s texture cache does not retain the whole file. pool.add decodes images, and meshes draw without textures until ready settles. Runtimes without createImageBitmap, including worklets and Node, need another decoder.
Convert these before you ship them. The error names the gltf-transform command. A model that needs Draco without a decoder throws too, naming the same copy command:
The file
Run
compresses its meshes with meshopt
gltf-transform copy in.glb out.glb
keeps its textures in KTX2 only
gltf-transform ktxdecompress in.glb out.glb
read takes one .glb and refuses buffers and images in separate files. load fetches them, or gltf-transform copy in.gltf out.glb packs them into one file.
The reader supports these required extensions: KHR_mesh_quantization, KHR_materials_emissive_strength, KHR_texture_transform and EXT_texture_webp, and KHR_draco_mesh_compression with a decoder. Other required extensions throw.
The reader skips morph targets, cameras and lights. It skips TEXCOORD_1 where no texture reads it, unless read with { uvs1: true }, which keeps the unwrap of a lightmap your own shader samples. It skips later sets.
A texture that reads TEXCOORD_1 needs a pool made with uvs1: true, which meshPool.roomFor sets for such a model. Textures using TEXCOORD_2 or later throw. A texture’s KHR_texture_transform becomes its transform. The cloister reads both from Blender’s export.
Lines and points throw an error such as gltf.read reads triangles, got a primitive of mode 1.
Before following an index, buffer view or accessor range, read checks that it is valid. This matters when loading player uploads:
Accessor 0 exceeds its buffer view. It needs 12000000 bytes, but the view has 36.
Non-binary-glTF bytes, including a server’s 404 page, throw The bytes aren't a binary glTF. A file shorter than the length declared in its header throws before its contents are read.
A node that is its own ancestor, or has two parents, throws.
By default, each node placement copies a mesh. A small file could therefore request millions of copies. Before reading mesh data, read totals the placed vertices and indices and throws above maxBytes, which defaults to 256 MiB. For uploads, lower it with { maxBytes: 32 * 2 ** 20 }. With placements, each mesh counts once. The size error suggests that option. The limit covers the counts accessors declare, and a Draco primitive is decoded before its counts are checked against them, so read Draco files only from sources you trust.
An accessor without a buffer view throws. glTF permits it to request count zero values, which lets a small JSON field request gigabytes. Exporters use these accessors for morph targets, which read skips.
An animation whose key times don’t increase throws.
Meshopt and KTX2 need WebAssembly decoders that the kit does not include. Convert those files.
A mirrored placement turns its mesh’s triangles inside out, so back-face culling hides its fronts.
Part names must match exported node names. A missing name throws when the model loads.
A nested part uses model space rather than its parent part’s space. For a barrel on a rotating turret, compose the turret rotation into the barrel rotation.