skills/anthemflynn/ccmp/asset-pipeline-3d

asset-pipeline-3d

SKILL.md

3D Asset Pipeline

Prepare and optimize 3D assets for performant web delivery.

Tool Versions (2026)

  • gltf-transform: v4+
  • Meshoptimizer: v0.21+
  • Basis Universal: v1.16+
  • Blender: 4.2+

Decision Frameworks

When to Use Which Compression

Geometry Compression:
├─ Need fastest decode time? → Meshopt (recommended)
├─ Need smallest file size? → Draco (10-20% smaller)
├─ Animated models (skinned/morphs)? → Meshopt (better animation support)
├─ Static meshes only? → Either works
└─ Maximum compatibility? → No compression (larger files)

Texture Compression:
├─ GPU-compressed (fastest rendering)? → KTX2/Basis Universal
├─ Good balance (size vs quality)? → WebP
├─ Best quality at cost of size? → PNG (lossless) or AVIF
├─ Need alpha channel? → WebP, PNG, KTX2, or AVIF
└─ Photo textures, no alpha? → JPEG or WebP

When to Use Which Pipeline

Single hero model (product viewer)?
  → gltf-transform optimize with high quality settings

Many similar models (e-commerce)?
  → Batch processing script with consistent settings

Game assets (performance critical)?
  → Aggressive compression + LODs + texture atlases

Architectural visualization?
  → High poly + baked lighting + KTX2 textures

Real-time application?
  → Meshopt + KTX2 + LODs + strict budgets

Compression Decision Matrix

Scenario Geometry Textures LODs
Product viewer Meshopt WebP/KTX2 Optional
Game assets Meshopt KTX2 Required
Archviz Meshopt KTX2 2048px Per-room
Mobile Meshopt KTX2 512-1024px Required
E-commerce batch Draco (smaller) WebP Optional

GLTF/GLB Overview

GLTF (GL Transmission Format) is the standard for web 3D. GLB is the binary version (single file).

GLTF supports:

  • Meshes, materials (PBR), textures
  • Skeletal animations, morph targets
  • Scene hierarchy, cameras, lights
  • Extensions for advanced features

File structure:

  • .gltf - JSON with external binary/textures
  • .glb - Single binary file (preferred for web)

Compression Tools

gltf-transform (Recommended)

Node.js CLI for GLTF optimization. Install: npm install -g @gltf-transform/cli

# Meshopt compression (recommended - faster decode)
gltf-transform meshopt input.glb output.glb

# Draco compression (smaller files, slower decode)
gltf-transform draco input.glb output.glb

# Texture compression to KTX2/Basis (GPU-compressed)
gltf-transform ktx input.glb output.glb --compress uastc

# Full optimization pipeline (2026 recommended)
gltf-transform optimize input.glb output.glb \
  --compress meshopt \
  --texture-compress ktx2

# WebP textures (good balance, wider support)
gltf-transform optimize input.glb output.glb \
  --compress meshopt \
  --texture-compress webp

# Resize textures (power of 2)
gltf-transform resize input.glb output.glb --width 1024 --height 1024

# Flatten scene hierarchy (reduces draw calls)
gltf-transform flatten input.glb output.glb

# Merge meshes sharing materials
gltf-transform join input.glb output.glb

# Remove unused data
gltf-transform prune input.glb output.glb

# Deduplicate accessors
gltf-transform dedup input.glb output.glb

# Generate simplified LOD
gltf-transform simplify input.glb output.glb --ratio 0.5 --error 0.001

# Full production pipeline
gltf-transform optimize input.glb output.glb \
  --compress meshopt \
  --texture-compress ktx2 \
  --texture-size 1024

gltfpack

Alternative CLI (part of meshoptimizer). Faster, less flexible.

# Basic optimization
gltfpack -i input.glb -o output.glb

# With Meshopt compression
gltfpack -i input.glb -o output.glb -cc

# With KTX2 texture compression
gltfpack -i input.glb -o output.glb -tc

# Simplify (50% triangle reduction)
gltfpack -i input.glb -o output.glb -si 0.5

# All optimizations (production ready)
gltfpack -i input.glb -o output.glb -cc -tc -si 0.5

Texture Optimization

Format Selection

Format Use Case Alpha Compression GPU Decode
KTX2/Basis GPU-compressed (best) Yes UASTC/ETC1S Native
WebP General textures Yes Lossy/Lossless CPU
AVIF Best file compression Yes Lossy CPU
JPEG Photos, no alpha No Lossy CPU
PNG UI, sharp edges Yes Lossless CPU

KTX2/Basis Universal is preferred for 2026 - textures stay compressed in GPU memory.

Size Guidelines

Texture Type Mobile Desktop Notes
Diffuse/Albedo 512-1024 1024-2048 sRGB color space
Normal 512-1024 1024-2048 Linear, tangent space
Roughness/Metal 256-512 512-1024 Linear, can pack
AO 256-512 512-1024 Linear, can pack
Environment 256-512 512-1024 HDR for reflections

Power of 2: Always use power-of-2 dimensions (256, 512, 1024, 2048) for mipmapping.

Compression Commands

# ImageMagick - resize and convert
magick input.png -resize 1024x1024 -quality 85 output.webp

# cwebp (WebP)
cwebp -q 80 input.png -o output.webp

# Basis Universal (KTX2) - high quality UASTC
basisu -uastc -uastc_level 2 input.png -output_file output.ktx2

# Basis Universal - smaller ETC1S (lower quality)
basisu input.png -output_file output.ktx2

# toktx (Khronos tool)
toktx --t2 --uastc 2 output.ktx2 input.png

# Squoosh CLI (WebP/AVIF)
squoosh-cli --webp '{quality:80}' input.png
squoosh-cli --avif '{quality:60}' input.png

Channel Packing (ORM)

Combine grayscale maps into RGBA channels to reduce texture count:

R: Ambient Occlusion
G: Roughness
B: Metalness
A: (unused or height)
// Three.js with packed ORM texture
const ormTexture = textureLoader.load('/orm.png')
ormTexture.colorSpace = THREE.LinearSRGBColorSpace

const material = new THREE.MeshStandardNodeMaterial({
  aoMap: ormTexture,
  roughnessMap: ormTexture,
  metalnessMap: ormTexture,
  // Channel selection happens automatically in ORM workflow
})

Blender Export Settings

GLTF Export Checklist

  1. Apply transforms: Ctrl+A → All Transforms
  2. Apply modifiers: Check "Apply Modifiers" in export
  3. Check scale: Blender default 1 unit = 1 meter
  4. Clean up: Remove unused materials, objects, shape keys

Export Settings (Blender 4.2+)

Format: GLB (single file)

Include:
  [x] Selected Objects (if exporting subset)
  [x] Custom Properties
  [x] Cameras (if needed)
  [x] Punctual Lights (if needed)

Transform:
  +Y Up (standard for web)

Data:
  Mesh:
    [x] Apply Modifiers
    [x] UVs
    [x] Normals
    [ ] Tangents (let Three.js compute)
    [ ] Vertex Colors (unless needed)

  Material:
    [x] Materials → Export
    [x] Images → Automatic (embeds in GLB)

  Shape Keys: [x] (if using morph targets)
  Skinning: [x] (if using armatures)
  Armature:
    [x] Export Deformation Bones Only

Animation:
  [x] Animations
  Sampling Rate: 24 or match source

Compression:
  [ ] Draco (prefer post-processing with gltf-transform)

Common Export Issues

Problem Solution
Model too big/small Apply scale (Ctrl+A) before export
Missing textures Pack textures (File → External Data → Pack)
Broken normals Recalculate normals (Shift+N in Edit mode)
Flipped faces Check normals direction, flip if needed
Animation jitter Increase keyframe sampling rate
Materials wrong Use Principled BSDF, check texture paths
Bones missing Check "Export Deformation Bones Only"

Loading in Three.js

WebGPU Setup (2026)

import * as THREE from 'three/webgpu'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js'
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'

const loader = new GLTFLoader()

// Meshopt decoder (recommended)
loader.setMeshoptDecoder(MeshoptDecoder)

// KTX2 textures (requires renderer for format detection)
const ktx2Loader = new KTX2Loader()
ktx2Loader.setTranscoderPath('https://cdn.jsdelivr.net/npm/three@0.171.0/examples/jsm/libs/basis/')
ktx2Loader.detectSupport(renderer) // Required!
loader.setKTX2Loader(ktx2Loader)

// Load
const gltf = await loader.loadAsync('/model.glb')
scene.add(gltf.scene)

Draco Fallback (if needed)

import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'

const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.7/')
loader.setDRACOLoader(dracoLoader)

React Three Fiber

import { useGLTF } from '@react-three/drei'

// Drei handles Meshopt and Draco automatically
const { scene, nodes, materials, animations } = useGLTF('/model.glb')

// Preload for instant display
useGLTF.preload('/model.glb')

Performance Budgets

Target Metrics

Platform Triangles Draw Calls Texture Memory File Size
Mobile <100K <50 <50MB <5MB
Desktop <500K <100 <200MB <20MB
High-end <2M <200 <500MB <50MB

Profiling

// Three.js render info (call after render)
console.log(renderer.info.render)
// { calls, triangles, points, lines, frame }

console.log(renderer.info.memory)
// { geometries, textures }

// Performance monitor
import Stats from 'stats.js'
const stats = new Stats()
stats.showPanel(0) // 0: fps, 1: ms, 2: mb
document.body.appendChild(stats.dom)

function animate() {
  stats.begin()
  renderer.render(scene, camera)
  stats.end()
}
renderer.setAnimationLoop(animate)

Asset Validation

# Validate GLTF structure
npx gltf-validator model.glb

# Online validation
# https://gltf.report

# Check file size breakdown
gltf-transform inspect model.glb

Related Skills

When you need... Use skill
Build 3D scenes with Three.js threejs
Build 3D scenes with React react-three-fiber
Debug rendering/performance issues graphics-troubleshooting

Reference Files

Weekly Installs
25
GitHub Stars
3
First Seen
Jan 22, 2026
Installed on
opencode22
claude-code22
gemini-cli21
codex20
cursor20
antigravity18