Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@gltf-transform/functions

donmccurdy155.2kMIT4.1.4TypeScript support: included

Functions for common glTF modifications, written using the core API

gltf, 3d, model, webgl, threejs

readme

glTF Transform

Latest NPM release npm bundle size License Build Status Coverage

glTF 2.0 SDK for JavaScript and TypeScript, on Web and Node.js.

Introduction

glTF Transform supports reading, editing, and writing 3D models in glTF 2.0 format. Unlike 3D modeling tools — which are ideal for artistic changes to geometry, materials, and animation — glTF Transform provides fast, reproducible, and lossless control of the low-level details in a 3D model. The API automatically manages array indices and byte offsets, which would otherwise require careful management when editing files. These traits make it a good choice for bundling, splitting, or optimizing an existing model. It can also be used to apply quick fixes for common issues, to build a model procedurally, or to easily develop custom extensions on top of the glTF format. Because the core SDK is compatible with both Node.js and Web, glTF Transform may be used to develop offline workflows and web applications alike.

Packages:

  • @gltf-transform/core: Core SDK, providing an expressive API to read, edit, and write glTF files.
  • @gltf-transform/extensions: Extensions (optional glTF features) for the Core SDK.
  • @gltf-transform/functions: Functions for common glTF modifications, written using the core API.
  • @gltf-transform/cli: Command-line interface (CLI) to apply functions to glTF files quickly or in batch.

Function symbol, f(📦) → 📦, where the argument and output are a box labeled 'glTF'.

Commercial Use

Using glTF Transform for a personal project? That's great! Sponsorship is neither expected nor required. Feel free to share screenshots if you've made something you're excited about — I enjoy seeing those!

Using glTF Transform in for-profit work? That's wonderful! Your support is important to keep glTF Transform maintained, independent, and open source under MIT License. Please consider a subscription or GitHub sponsorship.

Learn more in the glTF Transform Pro FAQs.

Scripting API

Install the scripting packages:

npm install --save @gltf-transform/core @gltf-transform/extensions @gltf-transform/functions

Read and write glTF scenes with platform I/O utilities WebIO, NodeIO, or DenoIO:

import { Document, NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
import draco3d from 'draco3dgltf';

// Configure I/O.
const io = new NodeIO()
    .registerExtensions(ALL_EXTENSIONS)
    .registerDependencies({
        'draco3d.decoder': await draco3d.createDecoderModule(), // Optional.
        'draco3d.encoder': await draco3d.createEncoderModule(), // Optional.
    });

// Read from URL.
const document = await io.read('path/to/model.glb');

// Write to byte array (Uint8Array).
const glb = await io.writeBinary(document);

To perform changes to an existing glTF Document, import off-the-shelf scripts from the Functions package, or write your own using API classes like Material, Primitive, and Texture.

import { resample, prune, dedup, draco, textureCompress } from '@gltf-transform/functions';
import sharp from 'sharp'; // Node.js only.

await document.transform(
    // Losslessly resample animation frames.
    resample(),
    // Remove unused nodes, textures, or other data.
    prune(),
    // Remove duplicate vertex or texture data, if any.
    dedup(),
    // Compress mesh geometry with Draco.
    draco(),
    // Convert textures to WebP (Requires glTF Transform v3 and Node.js).
    textureCompress({
        encoder: sharp,
        targetFormat: 'webp',
        resize: [1024, 2024],
    }),
    // Custom transform.
    backfaceCulling({cull: true}),
);

// Custom transform: enable/disable backface culling.
function backfaceCulling(options) {
    return (document) => {
        for (const material of document.getRoot().listMaterials()) {
            material.setDoubleSided(!options.cull);
        }
    };
}

To learn how glTF Transform works, and the architecture of the scripting API, start with Concepts. To try out the scripting API without installing anything, visit gltf.report/, load a glTF model, and open the Script tab.

Command-line API

Install the CLI, supported in Node.js LTS versions.

npm install --global @gltf-transform/cli

List available CLI commands:

gltf-transform --help

Optimize everything all at once:

gltf-transform optimize input.glb output.glb --texture-compress webp

Or pick and choose your optimizations, building a custom pipeline.

Compress mesh geometry with Draco or Meshoptimizer:

# Draco (compresses geometry).
gltf-transform draco input.glb output.glb --method edgebreaker

# Meshopt (compresses geometry, morph targets, and keyframe animation).
gltf-transform meshopt input.glb output.glb --level medium

Resize and compress textures with Sharp, or improve VRAM usage and performance with KTX2 and Basis Universal:

# Resize textures.
gltf-transform resize input.glb output.glb --width 1024 --height 1024

# Compress textures with WebP.
gltf-transform webp input.glb output.glb --slots "baseColor"

# Compress textures with KTX2 + Basis Universal codecs, UASTC and ETC1S.
gltf-transform uastc input.glb output1.glb \
    --slots "{normalTexture,occlusionTexture,metallicRoughnessTexture}" \
    --level 4 --rdo --rdo-lambda 4 --zstd 18 --verbose
gltf-transform etc1s output1.glb output2.glb --quality 255 --verbose

... and much more.

Credits

See Credits.

License

Copyright 2024, MIT License.

changelog

Changelog

v4.x

v4.2 (🚧 Unreleased)

  • TODO

v4.1

Features:

  • functions: Adds uninstance() and createInstanceNodes() #1525
  • cli: Add ktxdecompress command for decoding KTX2 textures #1622

Performance:

  • core: Update to property-graph v3 #1543
    • Removes .dispatch, .addEventListener, and other event-related behaviors from GraphEdge class

Other:

  • fix(core): Handle duplicate URIs on read/write #1522
  • fix(functions,cli): Locale-based numeric formatting #1512
  • fix(extensions): Fix error decoding sparse accessors in draco-compressed meshes #1623
  • chore(repo): Replace ESLint and Prettier with Biome #1624

v4.0

Breaking changes:

  • core: Renames NodeIO#setAllowHttp to setAllowNetwork #1392
  • core: Removes Document#merge and Document#clone methods #1375
    • Use mergeDocuments and cloneDocument from /functions package
  • core: Renames bounds to getBounds and moves from /core to /functions #1340
  • core: Renames Node#getParent to Node#getParentNode and Node#listNodeScenes #1211
  • core: Renames MathUtils#denormalize to decodeNormalizedInt, and MathUtils#normalize to encodeNormalizedInt #1211
  • core,extensions: Removes hexadecimal getters/setters #1211
  • extensions: Upgrade to property-graph v2 #1141
    • Affects implementations of custom extensions. See changes to official extensions in #1141
  • functions: Removes 'overwrite' and 'skipIndices' options from transformMesh() and transformPrimitive() functions #1397
  • functions: Removes lossy weld() options #1357
  • functions: Merges textureResize into textureCompress function #1211
  • cli: Update to Sharp v0.33 #1402
  • cli: Upgrade to KTX-Software v4.3 #1277, #1369, #1376, #1378
  • cli: Renames --allow-http to --allow-net #1392
  • cli: Change default compression of optimize command to Meshopt #1377
  • core,cli: Requires Node.js >=18; other runtimes (Web and Deno) unaffected

Features:

  • extensions: Adds KHR_materials_diffuse_transmission #1159
  • extensions: Adds KHR_materials_dispersion #1262
  • functions: Adds mergeDocuments(target, source) #1375
  • functions: Adds cloneDocument(source) #1375
  • functions: Adds copyToDocument(target, source, sourceProperties) #1375
  • functions: Adds moveToDocument(target, source, sourceProperties) #1375
  • functions: Adds compactPrimitive() to remove unused vertices #1397
  • functions: Adds convertPrimitiveToLines and convertPrimitiveToTriangles, support conversions of various primitive topologies to triangle lists and line lists #1316
  • functions: Adds more aggressive prune() defaults #1199, #1270
  • cli: Expose --simplify-ratio and --simplify-lock-border options on optimize command #1354 by @jo-chemla
  • cli: Expose prune-related options on optimize command #1298 by @subho57
  • cli: MikkTSpace tangent calculation handles unwelding and welding automatically #1241
  • functions: Add vertex count helpers, getSceneVertexCount, getNodeVertexCount, getMeshVertexCount, getPrimitiveVertexCount #1320, #1327, #1393
  • functions: Add keepExtras option to prune() #1302 by @Archimagus
  • functions: Add support for point cloud simplification, via meshoptimizer v0.20 #1291
  • functions: Add power-of-two options to textureCompress #1221

Performance:

  • functions: Improves weld() performance #1237, #1238, #1344, #1351
  • functions: Improves join() and joinPrimitives() performance #1242, #1397
  • functions: Improves transformMesh() transformPrimitive() performance #1397
  • functions: Improves quantize() performance #1395
  • functions: Improves partition() performance #1373
  • functions: Improves reorder() performance #1358
  • core: NodeIO now writes files to disk in batches #1383
  • functions: Improves simplify() performance on indexed primitives #1381

Other:

  • chore(repo): Update to Yarn v4 #1401
  • chore(repo): Adds CI for local builds on windows #959
  • chore(repo): Add benchmarks
  • chore(repo): Packages are now published as unminified code #1212
  • docs(core): Fix errors in Accessor documentation #1235 by @harrycollin
  • docs(extensions): Add more illustrations for extensions
  • docs(repo): Show 'experimental' tags in API documentation c3a693
  • fix(core): Clamp when encoding normalized ints #1286
  • fix(extensions): Bug fixes for Draco compression #1388, #1385
  • fix(extensions): Group Meshopt-compressed accessors by parent #1384
  • fix(extensions): Improve order-independence in extension implementations #1257
  • fix(functions): Various fixes for pruning and welding #1284
  • fix(functions): Fixes for instancing bugs #1269
  • fix(functions): Fixes for simplification bugs #1268
  • fix(cli): Reformat 'validate' output as valid CSV #1252

v3.x

v3.9 (Milestone)

Features:

  • Update prune() to remove redundant mesh indices #1164
  • Update meshoptimizer to v0.20

v3.8 (Milestone)

Features:

  • Add quantization options in meshopt() function #1144
  • Improve encoding of morh normals with quantization and meshopt encoding #1151

v3.7 (Milestone)

Features:

  • Reduced CLI initialization time #1091, #1093
  • Add pruneSolidTextures option to prune() be73c8

Other:

  • Fix encoding of special characters in filenames when writing to disk #1118
  • Fixed regression in quality of Draco compression #1077
  • Updated sharp CLI dependency to address high-priority WebP vulnerability in libwebp

v3.6 (Milestone)

Features:

  • Add limited textureCompress() support in web browsers (PNG, JPEG, WebP) #1075
  • Bug fixes and quality improvements in optimize(), dedup(), instance(), flatten() and join() operations #1073
  • textureCompress() PNG compression is now lossless by default #1068
  • join() now supports quantized meshes #1067
  • simplify() now cleans up degenerate mesh primitives #1066
  • Moved CLI to a fork of Caporal.js #1065

v3.5 (Milestone)

Features:

  • Improvements to weld() #1029 by @rotu
  • Add --pattern flag in etc1s and uastc CLI commands #1037
  • Add toleranceNormal option in weld() #1046
    • Default vertex normal tolerance has been reduced (#1035), reducing loss of quality in some cases. Where more aggressive welding is required (such as simplification and LODs), users should specify toleranceNormal=0.5 to restore the previous default.

v3.4 (Milestone)

Special thanks to Muse for supporting development of the palette() feature.

Features:

  • Add palette() function #952
  • Add "resize" option in toktx() #968

v3.3 (Milestone)

Special thanks to @kzhsw for help with performance improvements in v3.3.

Features:

  • Add listTextureInfoByMaterial() function #947
  • Add getTextureColorSpace function #944
  • Sync with KHR_materials_anisotropy release candidate #946
  • Improve performance of dedup #945
  • Improve performance of resample, port to WASM #934

Internal:

  • Migrate documentation from TypeDoc to Greendoc #940
  • Update to TypeScript v5

v3.2 (Milestone)

Features:

  • Improve optimize and simplify() defaults #901
  • Rename colorspace() to vertexColorSpace() #899

v3.1 (Milestone)

Features:

  • Add --join <bool> and --flatten <bool> flags to `optimize' CLI command #838 by @xlsfs
  • Add KHR_materials_anisotropy extension #748
  • Allow root Nodes to be shared by multiple Scenes #833
    • Deprecate Node#getParent(), prefer Node#getParentNode()
    • Deprecate getNodeScene(), prefer listNodeScenes()

v3.0 (Milestone)

Features:

  • Add optimize multi-command to CLI, "optimize all the things" #819
  • Replace Squoosh with Sharp, new textureCompress() API #752
    • Add AVIF compression #771
    • Add quality, effort, and other compression settings #816
    • Improved texture resizing performance and stability on Node.js
  • Add flatten() function, reduce scene graph nesting #790
  • Add join() and joinPrimitives() functions, reduce draw calls #707, #658
  • Add support for sparse accessors #793
  • Add --format option to CLI validate command #778
  • NodeIO creates missing directories when writing .gltf resources #779
  • Add clearNodeParent(), clearNodeTransform(), getNodeScene() #784
  • (EXPERIMENTAL) Add --config flag to CLI, support userland extensions and commands #791

Breaking changes:

  • Rename extension classes, include vendor prefixes #776
  • Rename bounds()getBounds() #774
  • Rename MathUtils normalize() / denormalize()encodeNormalizedInt() / decodeNormalizedInt() #777
  • Rename ImageUtils getMemSize()getVRAMByteLength() #812
  • Replace Squoosh with Sharp, new textureCompress() API #752
  • Update signatures of listTextureChannels, listTextureInfo, listTextureSlots, and getTextureChannelMask to not require document parameter #787
  • Store array literals (color, vector, ...) as copies #796

Internal:

  • Migrate unit tests to Ava #799
  • Upgrade /cli package to pure ESM #798

v2.x

v2.5 (Milestone)

Features:

  • Add weldPrimitive(document, prim, options) function #767 by @marwie
  • Support resampling quaternion keyframe tracks in resample() #760
  • Remove unused vertex attributes in prune() #759
  • Display KTX2 compression type in inspect() report #757
  • Add morph target support in transformMesh(), transformPrimitive() #756
  • Improve detection of duplicate meshes in dedup() #663 by @robertlong

v2.4 — (Milestone)

Features:

  • Add sortPrimitiveWeights(prim, limit) function #670
  • Add listTextureInfo(texture) function #692
  • Add transformMesh(mesh, matrix) and transformPrimitive(prim, matrix) functions #657
  • Rewrite weld() function, improving weld results #661
  • Handle conflicting URLs during merge #677
  • Add documentation for writing custom extensions #678

v2.3 (Milestone)

Features:

  • Add simplify() function. #655
  • Add ILogger interface for user-specified logging. #653
  • Add support for .extras on TextureInfo. #646
  • Show normalized attributes in inspect() output. #638

v2.2 (Milestone)

Features:

  • Changed package.json#module entrypoint extension to .mjs #619
  • Add 'slots' option to textureResize() function. #622 by @snagy

v2.1 (Milestone)

Features:

  • Vastly improved KTX compression speed. #389 by @mikejurka, @spatialsys
  • Add KHR_materials_iridescence extension. #518
  • Add WebP, OxiPNG, and MozJPEG image optimization with @squoosh/lib. #506
  • Add draco(), meshopt(), unlit(), and ktxfix() functions to @gltf-transform/functions (moved from CLI). #544
  • Add listTextureSlots(), listTextureChannels(), getTextureChannelMask(). #506

v2.0 (Milestone)

Features:

  • Improved and simplified extension API. #437
  • Add a.equals(b) method for all property types. #437
  • Add KHR_xmp_json_ld extension. #468
  • Add NodeIO.setAllowHTTP(<boolean>). #466
  • Non-blocking NodeIO read/write. #441
  • Add DenoIO (experimental). #380
  • Add normals() function. #497

Breaking changes:

  • API for custom extensions updated. #437
  • I/O, Texture and other classes use Uint8Array for binary data, not ArrayBuffer. #447
  • I/O read/write methods are now asynchronous. #441
  • Removed support for Node.js ≤ 12.x

v1.x

v1.2 (Milestone)

Features:

  • Add dequantize() function. #431
  • Add KHR_materials_emissive_strength extension. #422
  • Add ImageUtils.getMimeType(buffer). #432

v1.1 (Milestone)

Features:

  • Extensions registered with I/O are written if used; unregistered extensions are skipped. #421
  • Stages in document.transform() can detect other stages and optimize accordingly. #417
  • Added material.equals(otherMaterial) method. #405 by @MrMagicPenguin
  • Added support for materials in dedup() function. #407 by @MrMagicPenguin

v1.0 (Milestone)

Stable release.

v0.x

v0.12 (Milestone)

Features:

  • Add compression/decompression support for EXT_meshopt_compression. #314 #323
  • Add reorder() function. #321
  • Faster, smaller CLI installation. #281
  • Improved textureResize() API. #282
  • Add node.setMatrix(...). #270
  • Parse in-memory Data URIs with readJSON. #266
  • Support .extras on Root object #339

Breaking changes:

  • Remove ao() function and dependencies. #281

v0.11 (Milestone)

Features:

  • Add textureResize() function. #267
  • Add quantizationVolume: 'scene' | 'mesh' option to quantize() and Draco compression. Fixes #257. #272
  • Support GLB files without binary data (e.g. just a node graph). #245
  • Improve type-checking throughout the library, with TypeScript's strict checks.
  • Add API documentation for @gltf-transform/extensions and @gltf-transform/functions, with Typedoc v0.20.

Breaking changes:

  • Rename @gltf-transform/lib to @gltf-transform/functions. #249
  • Move ao() from @gltf-transform/functions to the CLI, cutting size and dependencies of the functions package.
  • I/O writeJSON option isGLB: true changed to format: Format.GLB.

v0.10 (Milestone)

Features:

  • Add 'ktxfix' command in CLI. #222
  • Add getter/setter for default Scene on Root. #202

Breaking changes:

  • Material extensions now track RGBA channel usage of each texture, allowing improvements in KTX 2.0 support. #221

v0.9 (Milestone)

Features:

  • Add 'instance' transform. #169
  • Add 'prune' transform. #162
  • Add 'resample' transform. #158
  • Add 'tangents' transform. #175
  • Add 'quantize' transform. #59
  • Add KHR_materials_volume extension. #161
  • Add EXT_mesh_gpu_instancing extension. #115
  • Add --format={pretty,csv,md} output options for CLI inspect command.
  • Add --vertex-layout={interleaved,separate} options for CLI output.

Breaking changes:

  • Stricter type checking.
  • Enum values moved from GLTF.* to static properties of the relevant class. Primitive enum values are now allowed.
  • Enable esModuleInterop in TS config.
  • 'dedup' transform takes a propertyTypes: string[] array, rather than boolean flags for each property type.
  • 'draco' CLI command options renamed (hyphenated) for consistency.

v0.8 (Milestone)

Features:

  • Add 'weld' and 'unweld' transforms.
  • Add encoding/compression support for KHR_draco_mesh_compression.
  • Add KTX and WebP support in utils and 'inspect' function.
  • Add KHR_materials_variants extension.

Breaking changes:

  • Stricter type checking.
  • External type definitions are now installed as dependencies.

v0.7 (Milestone)

Features:

  • Add 'center' and 'sequence' transforms.
  • Add 'bounds' helper.
  • Enhance 'partition' transform to support animations.
  • Add KHR_draco_mesh_compression extension (decode only).
  • Add KHR_texture_transform extension.
  • Add EXT_texture_webp extension.
  • Add KHR_materials_sheen extension.

Breaking changes:

  • Merged TextureSampler properties into TextureInfo.
  • TextureInfo now extends from ExtensibleProperty.
  • Simplified I/O API. Renamed:
    • NativeDocument -> JSONDocument
    • unpackGLB -> readBinary
    • packGLB -> writeBinary
    • createDocument -> readJSON
    • createNativeDocument -> writeJSON
    • unpackGLBToNativeDocument -> binaryToJSON

v0.6 (Milestone)

Features:

  • Add world transform API (getWorldTranslation/getWorldRotation/getWorldScale/getWorldMatrix) and getMatrix to Node.
  • Add ColorUtils and helper methods to work with colors in hexadecimal and sRGB.
  • Add traverse method to Node.
  • Simplified Extension API.
  • Add Extras API.

CLI:

  • Accept textures in merge command.

Breaking changes:

  • getExtension/setExtension syntax changed to accept extension names, not constructors. See ExtensibleProperty.
  • Scene addNode/removeNode/listNodes are now addChild/removeChild/listChildren, for consistency with Node API.

v0.5 (Milestone)

v0.4 (Milestone)

v0.2 (Milestone)

v0.1 (Milestone)