threejs-asset-pipeline
Shrinking glTF assets for three.js with gltf-transform: inspect, validate and optimize commands, Draco, meshopt and quantization, KTX2, WebP and AVIF textures, the loader setup each output needs, and gltfjsx for React
Install / Use
npx skills add CloudAI-X/threejs-skills --skill threejs-asset-pipelineInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
AutomationSupported Platforms
Our assessment of threejs-asset-pipeline
threejs-asset-pipeline scores 91/100 on our quality scale, 1048th of 2,908 Automation skills we index (top 37%).
Its SKILL.md is 18 KB long, well organised into 18 sections with 11 code examples: a thorough specification that gives an agent plenty to work with.
With 3,371 GitHub stars, it is one of the more widely adopted skills in the catalogue.
Maintenance, license and trust
- The repository was last updated about 4 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.
- No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
- Its trust signals score 86/100, with 1 caution from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
Safety scan
No issues foundOur scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful.
AI review by kimi-k2.7-code on 2026-10-23. Automated pattern scan on 2026-10-23. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.
threejs-asset-pipeline compared with similar skills
All 4 of these similar skills score higher than threejs-asset-pipeline; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| threejs-asset-pipeline (this skill)by CloudAI-X | 91 | 3.4k | 4mo ago | SKILL.md |
| Agent-Reachby Panniantong | 100 | 101.1k | 2d ago | CLAUDE.md |
| Scraplingby D4Vinci | 100 | 89.2k | today | MCP Server |
| rufloby ruvnet | 100 | 78.5k | today | MCP Server |
| algorithmic-artby anthropics | 100 | 177.9k | 30d ago | SKILL.md |
Frequently asked questions
- How do I install threejs-asset-pipeline?
- Run
npx skills add CloudAI-X/threejs-skills --skill threejs-asset-pipeline. The install tabs above show the steps for each supported agent. - Which AI agents does threejs-asset-pipeline work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is threejs-asset-pipeline safe to use?
- Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful. It declares no license and scores 86/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is threejs-asset-pipeline still maintained?
- The repository was last updated about 4 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.
Skill content
View source on GitHubname: threejs-asset-pipeline description: "Shrinking glTF assets for three.js with gltf-transform: inspect, validate and optimize commands, Draco, meshopt and quantization, KTX2, WebP and AVIF textures, the loader setup each output needs, and gltfjsx for React. Use when compressing, optimizing or validating 3D models before loading them."
Three.js Asset Pipeline
Targets three.js r186. Examples use WebGLRenderer; the WebGPU and TSL section uses WebGPURenderer.
Quick Start
Compress on the command line, then load the result. Run inspect before and after to see what the pass saved:
npx @gltf-transform/cli inspect model.glb
npx @gltf-transform/cli optimize model.glb model.opt.glb --compress draco --texture-compress webp --texture-size 2048
npx @gltf-transform/cli inspect model.opt.glb
Draco output needs a DRACOLoader attached; WebP textures decode in the browser:
import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const sun = new THREE.DirectionalLight(0xffffff, 2); // glTF PBR materials render black without lights or an environment
sun.position.set(3, 5, 2);
scene.add(sun, new THREE.HemisphereLight(0xffffff, 0x444444, 1.5));
const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(2, 1.5, 3);
camera.lookAt(0, 0, 0);
const gltf = await new GLTFLoader()
.setDRACOLoader(new DRACOLoader()) // the Draco WASM decoder loads from the three package
.loadAsync("model.opt.glb");
scene.add(gltf.scene);
function animate() {
renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);
Inspect and Validate
Never guess where the bytes are. inspect prints an overview (generator, extensionsUsed, extensionsRequired) and one table each for scenes, meshes, materials, textures and animations, so a geometry-heavy file and a texture-heavy file are obvious at a glance.
npx @gltf-transform/cli inspect model.glb
npx @gltf-transform/cli inspect model.opt.glb --format csv
npx @gltf-transform/cli validate model.glb --ignore ACCESSOR_WEIGHTS_NON_NORMALIZED
extensionsRequired is the runtime contract: KHR_draco_mesh_compression, EXT_meshopt_compression and KHR_texture_basisu each map to a piece of loader wiring below, while KHR_mesh_quantization, EXT_mesh_gpu_instancing, EXT_texture_webp and EXT_texture_avif need nothing at runtime. validate runs the official glTF validator and reports errors, warnings and hints; it exits nonzero when errors are found, so it works as a CI gate. The commands in this skill that write a file log the input and output sizes when they finish; inspect the output to see which table the savings came from.
The optimize Command
optimize chains the common passes in one run: dedup, instance, palette, flatten, join, weld, simplify, resample, prune and sparse data, then texture compression, and geometry compression last. With no flags it applies meshopt compression and recompresses textures in their original format. Defaults are aggressive but generic — inspect first, then tune:
# draco geometry + webp textures, capped at 2048px
npx @gltf-transform/cli optimize model.glb model.opt.glb --compress draco --texture-compress webp --texture-size 2048
# GPU textures instead of download size, keep every triangle
npx @gltf-transform/cli optimize model.glb model.opt.glb --texture-compress ktx2 --simplify false
Main flags (booleans take an explicit value, like --simplify false):
--compress draco|meshopt|quantize— geometry and animation compression (defaultmeshopt).--texture-compress ktx2|webp|avif— texture codec (defaultauto, recompress in the original format).--texture-size <px>— cap texture dimensions, default 2048.--simplify <bool>,--simplify-ratio <0-1>,--simplify-error <fraction>,--simplify-lock-border <bool>— mesh simplification; ratio 0 and error 0.0001 by default.--instance <bool>,--instance-min <count>— GPU instancing for repeated meshes.--join <bool>,--join-meshes <bool>,--join-named <bool>,--flatten <bool>— draw-call reduction;--joinrequires--flatten.--weld <bool>— merge duplicate vertices;dracowelds by itself even with--weld false, whilesimplifywelds only unindexed primitives, so keep--weld truewhen simplifying.--prune <bool>,--resample <bool>,--palette <bool>,--sparse <bool>,--meshopt-level medium|high.
With --texture-compress ktx2, optimize picks bitstreams itself: UASTC for the normal, occlusion and metallic-roughness slots, ETC1S for everything else. For alternatives outside this skill's lane, gltfpack covers similar ground; gltf-transform is enough here.
Geometry Compression
Three codecs with different tradeoffs — pick per model, not per project:
- Draco (
--compress draco,dracocommand): compresses triangle-mesh geometry only — animation, morph targets, textures, points and lines are not compressed. Runtime: DRACOLoader. - Meshopt (
--compress meshopt,meshoptcommand): compresses point, line and triangle geometry, morph targets and animation tracks, and decodes very quickly; pair it with lossless gzip or brotli over the wire. Runtime: MeshoptDecoder. - Quantize (
quantizecommand): stores float attributes as 8- or 16-bit integers under KHR_mesh_quantization — smaller on disk and in GPU memory, and no decoder to wire; GLTFLoader reads quantized attributes natively.
npx @gltf-transform/cli draco model.glb model.opt.glb --method edgebreaker --quantize-position 14
npx @gltf-transform/cli meshopt model.glb model.opt.glb --level high
npx @gltf-transform/cli quantize model.glb model.opt.glb
npx @gltf-transform/cli gzip model.opt.glb
gzip writes model.opt.glb.gz next to its input; serve it with Content-Encoding: gzip and the browser decompresses it transparently. It adds little on top of Draco or JPEG textures, and earns the most on top of meshopt and quantize.
Make draco, meshopt or optimize the last command in a chain: every other command that rewrites the model decodes Draco and meshopt geometry when it reads the file (it warns "Decoded KHR_draco_mesh_compression. Further compression will be lossy.") and writes it back uncompressed.
Texture Compression
Two different problems: KTX2 (Basis Universal) stays compressed in GPU memory wherever the GPU supports one of its transcode targets (KTX2Loader falls back to uncompressed RGBA otherwise) and uploads fast — it optimizes GPU memory and performance — while WebP and AVIF shrink the download and are decompressed to raw pixels in GPU memory, which can occupy 4-8x more there.
# KTX2: ETC1S for color (smaller, lossier), UASTC for normal maps (larger, cleaner)
npx @gltf-transform/cli etc1s model.glb model.opt.glb --quality 128
npx @gltf-transform/cli uastc model.glb model.opt.glb --level 4
# Download size: WebP or AVIF, quality 1-100
npx @gltf-transform/cli webp model.glb model.opt.glb --quality 80
# Cap dimensions of PNG or JPEG textures; never enlarges them
npx @gltf-transform/cli resize model.glb model.opt.glb --width 1024 --height 1024
KTX2 output — etc1s, uastc or optimize --texture-compress ktx2 — shells out to the ktx command from KTX-Software (4.4.0 or newer), so install that first; WebP and AVIF are encoded in-process. The single etc1s and uastc commands convert every texture to one bitstream; the per-slot split (UASTC for normal, occlusion and metallic-roughness, ETC1S for the rest) is what optimize --texture-compress ktx2 does for you, and --slots selects texture roles by name when you need a custom split. Runtime: KTX2 needs KTX2Loader with detectSupport; WebP and AVIF decode in the browser.
Scene Optimization Commands
Run these when inspect shows the problem is draw calls or vertex count rather than bytes:
npx @gltf-transform/cli weld model.glb model.opt.glb
npx @gltf-transform/cli simplify model.glb model.opt.glb --ratio 0.5 --error 0.001
npx @gltf-transform/cli join model.glb model.opt.glb
npx @gltf-transform/cli instance model.glb model.opt.glb --min 5
npx @gltf-transform/cli dedup model.glb model.opt.glb
npx @gltf-transform/cli prune model.glb model.opt.glb
weldmerges bitwise-identical vertices and indexes the primitive (points are skipped).dracowelds by itself;simplifywelds only unindexed primitives andmeshoptnone, and meshopt's reorder step skips unindexed primitives (it warns when none are indexed), so runweldbeforesimplifyandmeshopt.simplifyremoves triangles, aiming for--ratio(fraction of vertices to keep) while staying under--error(fraction of mesh extent);--lock-border truepreserves open edges. It is lossy.joinmerges compatible primitives to cut draw calls; it runs dedup and flatten itself first. In scenes that reuse one mesh heavily it inflates vertex count — useinstancethere instead.instancewrites EXT_mesh_gpu_instancing for meshes referenced by several nodes (--mindefaults to 5); GLTFLoader renders those batches as an InstancedMesh with no runtime setup. It skips any file that contains an animation, and instanced meshes must share materials.dedupmerges redundant accessors, materials, meshes, skins and textures left by exporters.prunedeletes properties no Scene references, including animations that target nothing attached to a scene.
Loader Setup for Each Output
The pipeline choice decides the loader wiring. The Draco decoder and the Basis transcoder load from the three package by default — call setDecoderPath or setTranscoderPath only when you host those files yourself, and then pin the path to the three release you ship. Create one KTX2Loader for the app and share it between GLTFLoaders: each active instance loads its own transcoder and workers, and three.js warns when several are active.
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
import { KTX2Loader } from "three/addons/loaders/KTX2Loader.js";
import { MeshoptDecoder } from "three/addons/libs/meshopt_decoder.module.js";
// Wire every codec the pipeline may emit; a missing one throws at load time
const gltfLoader = new GLTFLoader()
.setDRACOLoader(new DRACOLoader()) // KHR_draco_mesh_compression
.setMeshoptDecoder(MeshoptDecoder) // EXT_meshopt_compression
.setKTX2Loader(new KTX2Loader().detectSupport(renderer)); // KHR_texture_basisu
const gltf = await gltfLoader.loadAsync("model.opt.glb");
scene.add(gltf.scene);
What each missing piece throws: a Draco file without a DRACOLoader ("No DRACOLoader instance provided"), a meshopt file without a decoder ("setMeshoptDecoder must be called before loading compressed files"), a KTX2 file without a KTX2Loader ("setKTX2Loader must be called before loading KTX2 textures"), and a KTX2Loader that never ran detectSupport ("Missing initialization with .detectSupport( renderer )"). WebP and AVIF textures, quantized attributes and EXT_mesh_gpu_instancing need none of this.
Scripted Pipelines
When the CLI stops fitting — per-project defaults, CI, many files — script the same transforms with the SDK. A Node script, run with node pipeline.mjs:
// deps: @gltf-transform/core @gltf-transform/extensions @gltf-transform/functions draco3dgltf
import { NodeIO } from "@gltf-transform/core";
import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
import { dedup, prune, weld, draco } from "@gltf-transform/functions";
import draco3d from "draco
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
101.1kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
Scrapling
89.2k🕷️ A Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
ruflo
78.5k🌊 The original agent harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, federation, vector RAG integration, and native Claude Code / Codex / Hermes and many more Integrated
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
