Skills Agentes

Threejs Loaders

Carga de activos en Three.js: GLTF, texturas, imágenes, modelos y patrones asíncronos. Úsalo al cargar modelos 3D, texturas o entornos HDR, y al gestionar el progreso de carga.

Estrellas
49.5k

en todo el repo

Actividad
36

0–100, la ruta de este skill

Actualizado
hace 4 meses

último commit aquí

Commits
0

últimos 90 días

Contexto
3.5k tok

40 tok en reposo

Paquete
1 archivo

14 KB

Instalar

Funciona con cualquier agente que lea SKILL.md

npx -y skills add calesthio/OpenMontage --skill threejs-loaders --agent claude-code

Se instala solo en este repositorio.

Este skill makes network requests.

Qué hace

  • Cubre la carga de activos en Three.js: texturas, GLTF/GLB y otros formatos de modelo
  • Explica `LoadingManager` para seguir el progreso de carga
  • Trae patrones de carga asíncrona con promesas, y caché
  • Cubre carga desde distintos orígenes y manejo de errores

Úsalo cuando

  • Cargar modelos 3D o texturas
  • Cargar entornos HDR
  • Gestionar el progreso de carga de una escena

No lo uses cuando

    Qué lo activa

    Di cualquiera de estas frases y el agente debería cargar este skill.

    • Carga este modelo GLB en la escena
    • Muestra una barra de progreso mientras cargan los activos
    • Carga un HDR como entorno
    • Maneja los errores si el modelo no carga

    SKILL.md

    En inglés

    Three.js Loaders

    Quick Start

    import * as THREE from "three";
    import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
    
    // Load GLTF model
    const loader = new GLTFLoader();
    loader.load("model.glb", (gltf) => {
      scene.add(gltf.scene);
    });
    
    // Load texture
    const textureLoader = new THREE.TextureLoader();
    const texture = textureLoader.load("texture.jpg");
    

    LoadingManager

    Coordinate multiple loaders and track progress.

    const manager = new THREE.LoadingManager();
    
    // Callbacks
    manager.onStart = (url, loaded, total) => {
      console.log(`Started loading: ${url}`);
    };
    
    manager.onLoad = () => {
      console.log("All assets loaded!");
      startGame();
    };
    
    manager.onProgress = (url, loaded, total) => {
      const progress = (loaded / total) * 100;
      console.log(`Loading: ${progress.toFixed(1)}%`);
      updateProgressBar(progress);
    };
    
    manager.onError = (url) => {
      console.error(`Error loading: ${url}`);
    };
    
    // Use manager with loaders
    const textureLoader = new THREE.TextureLoader(manager);
    const gltfLoader = new GLTFLoader(manager);
    
    // Load assets
    textureLoader.load("texture1.jpg");
    textureLoader.load("texture2.jpg");
    gltfLoader.load("model.glb");
    // onLoad fires when ALL are complete
    

    Texture Loading

    TextureLoader

    const loader = new THREE.TextureLoader();
    
    // Callback style
    loader.load(
      "texture.jpg",
      (texture) => {
        // onLoad
        material.map = texture;
        material.needsUpdate = true;
      },
      undefined, // onProgress - not supported for image loading
      (error) => {
        // onError
        console.error("Error loading texture", error);
      },
    );
    
    // Synchronous (returns texture, loads async)
    const texture = loader.load("texture.jpg");
    material.map = texture;
    

    Texture Configuration

    const texture = loader.load("texture.jpg", (tex) => {
      // Color space (important for color accuracy)
      tex.colorSpace = THREE.SRGBColorSpace; // For color/albedo maps
      // tex.colorSpace = THREE.LinearSRGBColorSpace;  // For data maps (normal, roughness)
    
      // Wrapping
      tex.wrapS = THREE.RepeatWrapping;
      tex.wrapT = THREE.RepeatWrapping;
      // ClampToEdgeWrapping, RepeatWrapping, MirroredRepeatWrapping
    
      // Repeat/offset
      tex.repeat.set(2, 2);
      tex.offset.set(0.5, 0.5);
      tex.rotation = Math.PI / 4;
      tex.center.set(0.5, 0.5);
    
      // Filtering
      tex.minFilter = THREE.LinearMipmapLinearFilter; // Default
      tex.magFilter = THREE.LinearFilter; // Default
      // NearestFilter - pixelated
      // LinearFilter - smooth
      // LinearMipmapLinearFilter - smooth with mipmaps
    
      // Anisotropic filtering (sharper at angles)
      tex.anisotropy = renderer.capabilities.getMaxAnisotropy();
    
      // Flip Y (usually true for standard textures)
      tex.flipY = true;
    
      tex.needsUpdate = true;
    });
    

    CubeTextureLoader

    For environment maps and skyboxes.

    const loader = new THREE.CubeTextureLoader();
    
    // Load 6 faces
    const cubeTexture = loader.load([
      "px.jpg",
      "nx.jpg", // positive/negative X
      "py.jpg",
      "ny.jpg", // positive/negative Y
      "pz.jpg",
      "nz.jpg", // positive/negative Z
    ]);
    
    // Use as background
    scene.background = cubeTexture;
    
    // Use as environment map
    scene.environment = cubeTexture;
    material.envMap = cubeTexture;
    

    HDR/EXR Loading

    import { RGBELoader } from "three/addons/loaders/RGBELoader.js";
    import { EXRLoader } from "three/addons/loaders/EXRLoader.js";
    
    // HDR
    const rgbeLoader = new RGBELoader();
    rgbeLoader.load("environment.hdr", (texture) => {
      texture.mapping = THREE.EquirectangularReflectionMapping;
      scene.environment = texture;
      scene.background = texture;
    });
    
    // EXR
    const exrLoader = new EXRLoader();
    exrLoader.load("environment.exr", (texture) => {
      texture.mapping = THREE.EquirectangularReflectionMapping;
      scene.environment = texture;
    });
    

    PMREMGenerator

    Generate prefiltered environment maps for PBR.

    import { RGBELoader } from "three/addons/loaders/RGBELoader.js";
    
    const pmremGenerator = new THREE.PMREMGenerator(renderer);
    pmremGenerator.compileEquirectangularShader();
    
    new RGBELoader().load("environment.hdr", (texture) => {
      const envMap = pmremGenerator.fromEquirectangular(texture).texture;
    
      scene.environment = envMap;
      scene.background = envMap;
    
      texture.dispose();
      pmremGenerator.dispose();
    });
    

    GLTF/GLB Loading

    The most common 3D format for web.

    import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
    
    const loader = new GLTFLoader();
    
    loader.load("model.glb", (gltf) => {
      // The loaded scene
      const model = gltf.scene;
      scene.add(model);
    
      // Animations
      const animations = gltf.animations;
      if (animations.length > 0) {
        const mixer = new THREE.AnimationMixer(model);
        animations.forEach((clip) => {
          mixer.clipAction(clip).play();
        });
      }
    
      // Cameras (if any)
      const cameras = gltf.cameras;
    
      // Asset info
      console.log(gltf.asset); // Version, generator, etc.
    
      // User data from Blender/etc
      console.log(gltf.userData);
    });
    

    GLTF with Draco Compression

    import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
    import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
    
    const dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath(
      "https://www.gstatic.com/draco/versioned/decoders/1.5.6/",
    );
    dracoLoader.preload();
    
    const gltfLoader = new GLTFLoader();
    gltfLoader.setDRACOLoader(dracoLoader);
    
    gltfLoader.load("compressed-model.glb", (gltf) => {
      scene.add(gltf.scene);
    });
    

    GLTF with KTX2 Textures

    import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
    import { KTX2Loader } from "three/addons/loaders/KTX2Loader.js";
    
    const ktx2Loader = new KTX2Loader();
    ktx2Loader.setTranscoderPath(
      "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/basis/",
    );
    ktx2Loader.detectSupport(renderer);
    
    const gltfLoader = new GLTFLoader();
    gltfLoader.setKTX2Loader(ktx2Loader);
    
    gltfLoader.load("model-with-ktx2.glb", (gltf) => {
      scene.add(gltf.scene);
    });
    

    Process GLTF Content

    loader.load("model.glb", (gltf) => {
      const model = gltf.scene;
    
      // Enable shadows
      model.traverse((child) => {
        if (child.isMesh) {
          child.castShadow = true;
          child.receiveShadow = true;
        }
      });
    
      // Find specific mesh
      const head = model.getObjectByName("Head");
    
      // Adjust materials
      model.traverse((child) => {
        if (child.isMesh && child.material) {
          child.material.envMapIntensity = 0.5;
        }
      });
    
      // Center and scale
      const box = new THREE.Box3().setFromObject(model);
      const center = box.getCenter(new THREE.Vector3());
      const size = box.getSize(new THREE.Vector3());
    
      model.position.sub(center);
      const maxDim = Math.max(size.x, size.y, size.z);
      model.scale.setScalar(1 / maxDim);
    
      scene.add(model);
    });
    

    Other Model Formats

    OBJ + MTL

    import { OBJLoader } from "three/addons/loaders/OBJLoader.js";
    import { MTLLoader } from "three/addons/loaders/MTLLoader.js";
    
    const mtlLoader = new MTLLoader();
    mtlLoader.load("model.mtl", (materials) => {
      materials.preload();
    
      const objLoader = new OBJLoader();
      objLoader.setMaterials(materials);
      objLoader.load("model.obj", (object) => {
        scene.add(object);
      });
    });
    

    FBX

    import { FBXLoader } from "three/addons/loaders/FBXLoader.js";
    
    const loader = new FBXLoader();
    loader.load("model.fbx", (object) => {
      // FBX often has large scale
      object.scale.setScalar(0.01);
    
      // Animations
      const mixer = new THREE.AnimationMixer(object);
      object.animations.forEach((clip) => {
        mixer.clipAction(clip).play();
      });
    
      scene.add(object);
    });
    

    STL

    import { STLLoader } from "three/addons/loaders/STLLoader.js";
    
    const loader = new STLLoader();
    loader.load("model.stl", (geometry) => {
      const material = new THREE.MeshStandardMaterial({ color: 0x888888 });
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
    });
    

    PLY

    import { PLYLoader } from "three/addons/loaders/PLYLoader.js";
    
    const loader = new PLYLoader();
    loader.load("model.ply", (geometry) => {
      geometry.computeVertexNormals();
      const material = new THREE.MeshStandardMaterial({ vertexColors: true });
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
    });
    

    Async/Promise Loading

    Promisified Loader

    function loadModel(url) {
      return new Promise((resolve, reject) => {
        loader.load(url, resolve, undefined, reject);
      });
    }
    
    // Usage
    async function init() {
      try {
        const gltf = await loadModel("model.glb");
        scene.add(gltf.scene);
      } catch (error) {
        console.error("Failed to load model:", error);
      }
    }
    

    Load Multiple Assets

    async function loadAssets() {
      const [modelGltf, envTexture, colorTexture] = await Promise.all([
        loadGLTF("model.glb"),
        loadRGBE("environment.hdr"),
        loadTexture("color.jpg"),
      ]);
    
      scene.add(modelGltf.scene);
      scene.environment = envTexture;
      material.map = colorTexture;
    }
    
    // Helper functions
    function loadGLTF(url) {
      return new Promise((resolve, reject) => {
        new GLTFLoader().load(url, resolve, undefined, reject);
      });
    }
    
    function loadRGBE(url) {
      return new Promise((resolve, reject) => {
        new RGBELoader().load(
          url,
          (texture) => {
            texture.mapping = THREE.EquirectangularReflectionMapping;
            resolve(texture);
          },
          undefined,
          reject,
        );
      });
    }
    
    function loadTexture(url) {
      return new Promise((resolve, reject) => {
        new THREE.TextureLoader().load(url, resolve, undefined, reject);
      });
    }
    

    Caching

    Built-in Cache

    // Enable cache
    THREE.Cache.enabled = true;
    
    // Clear cache
    THREE.Cache.clear();
    
    // Manual cache management
    THREE.Cache.add("key", data);
    THREE.Cache.get("key");
    THREE.Cache.remove("key");
    

    Custom Asset Manager

    class AssetManager {
      constructor() {
        this.textures = new Map();
        this.models = new Map();
        this.gltfLoader = new GLTFLoader();
        this.textureLoader = new THREE.TextureLoader();
      }
    
      async loadTexture(key, url) {
        if (this.textures.has(key)) {
          return this.textures.get(key);
        }
    
        const texture = await new Promise((resolve, reject) => {
          this.textureLoader.load(url, resolve, undefined, reject);
        });
    
        this.textures.set(key, texture);
        return texture;
      }
    
      async loadModel(key, url) {
        if (this.models.has(key)) {
          return this.models.get(key).clone();
        }
    
        const gltf = await new Promise((resolve, reject) => {
          this.gltfLoader.load(url, resolve, undefined, reject);
        });
    
        this.models.set(key, gltf.scene);
        return gltf.scene.clone();
      }
    
      dispose() {
        this.textures.forEach((t) => t.dispose());
        this.textures.clear();
        this.models.clear();
      }
    }
    
    // Usage
    const assets = new AssetManager();
    const texture = await assets.loadTexture("brick", "brick.jpg");
    const model = await assets.loadModel("tree", "tree.glb");
    

    Loading from Different Sources

    Data URL / Base64

    const loader = new THREE.TextureLoader();
    const texture = loader.load("data:image/png;base64,iVBORw0KGgo...");
    

    Blob URL

    async function loadFromBlob(blob) {
      const url = URL.createObjectURL(blob);
      const texture = await loadTexture(url);
      URL.revokeObjectURL(url);
      return texture;
    }
    

    ArrayBuffer

    // From fetch
    const response = await fetch("model.glb");
    const buffer = await response.arrayBuffer();
    
    // Parse with loader
    const loader = new GLTFLoader();
    loader.parse(buffer, "", (gltf) => {
      scene.add(gltf.scene);
    });
    

    Custom Path/URL

    // Set base path
    loader.setPath("assets/models/");
    loader.load("model.glb"); // Loads from assets/models/model.glb
    
    // Set resource path (for textures referenced in model)
    loader.setResourcePath("assets/textures/");
    
    // Custom URL modifier
    manager.setURLModifier((url) => {
      return `https://cdn.example.com/${url}`;
    });
    

    Error Handling

    // Graceful fallback
    async function loadWithFallback(primaryUrl, fallbackUrl) {
      try {
        return await loadModel(primaryUrl);
      } catch (error) {
        console.warn(`Primary failed, trying fallback: ${error}`);
        return await loadModel(fallbackUrl);
      }
    }
    
    // Retry logic
    async function loadWithRetry(url, maxRetries = 3) {
      for (let i = 0; i < maxRetries; i++) {
        try {
          return await loadModel(url);
        } catch (error) {
          if (i === maxRetries - 1) throw error;
          await new Promise((r) => setTimeout(r, 1000 * (i + 1)));
        }
      }
    }
    
    // Timeout
    async function loadWithTimeout(url, timeout = 30000) {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), timeout);
    
      try {
        const response = await fetch(url, { signal: controller.signal });
        clearTimeout(timeoutId);
        return response;
      } catch (error) {
        if (error.name === "AbortError") {
          throw new Error("Loading timed out");
        }
        throw error;
      }
    }
    

    Performance Tips

    1. Use compressed formats: DRACO for geometry, KTX2/Basis for textures
    2. Load progressively: Show placeholders while loading
    3. Lazy load: Only load what's needed
    4. Use CDN: Faster asset delivery
    5. Enable cache: THREE.Cache.enabled = true
    // Progressive loading with placeholder
    const placeholder = new THREE.Mesh(
      new THREE.BoxGeometry(1, 1, 1),
      new THREE.MeshBasicMaterial({ wireframe: true }),
    );
    scene.add(placeholder);
    
    loadModel("model.glb").then((gltf) => {
      scene.remove(placeholder);
      scene.add(gltf.scene);
    });
    

    See Also

    • threejs-textures - Texture configuration
    • threejs-animation - Playing loaded animations
    • threejs-materials - Material from loaded models

    Reproducido de calesthio/OpenMontage bajo licencia AGPL-3.0. Leer esta página en markdown.

    Archivos

    1 archivo en el paquete. Solo se lee SKILL.md al activarse — las referencias se cargan si el skill decide que las necesita.

    Detalles

    Creador
    calesthio
    Categoría
    Diseño y UI
    Licencia
    AGPL-3.0
    Recursos incluidos
    Solo SKILL.md
    Código fuente
    Ver SKILL.md

    Etiquetas

    Más de calesthio/OpenMontage

    Este repo incluye 89 skills. Si instalas uno, normalmente ya tienes los demás.

    Comfyui

    49.5k

    Úsalo al trabajar con workflows de ComfyUI en OpenMontage: comfyui_image/video/music, workflows propios, selección de output_node, modelos que faltan, LoRAs, poca VRAM e importación de workflows de la comunidad.

    Costo de contexto al activarse
    1.9k tok
    Tamaño del paquete
    1 archivo
    Última actualización
    hace 9 días
    diseno ui

    Genera vídeo cinematográfico de 4-30 s con ByteDance Seedance 2.5 por fal.ai, Volcengine Ark, Runway o ComfyUI. Cubre el contrato de prompt 2.5, cortes duros, locks de continuidad y voz.

    Costo de contexto al activarse
    3.2k tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 4 días
    diseno ui

    Genera narración expresiva y multilingüe con fish.audio (modelos S1 / S2) y reutiliza voces clonadas mediante reference_id.

    Costo de contexto al activarse
    1.4k tok
    Tamaño del paquete
    1 archivo
    Última actualización
    hace 9 días
    diseno ui

    Genera y edita conversacionalmente vídeos cortos con Google Gemini Omni Flash: itera con ediciones en lenguaje natural, clips de 3-10s a 720p con audio y texto en pantalla, e imágenes de referencia por etiquetas.

    Costo de contexto al activarse
    2.1k tok
    Tamaño del paquete
    1 archivo
    Última actualización
    hace 9 días
    Permisos
    diseno ui

    Genera vídeo con MiniMax H3 (Hailuo 3.0) por la API oficial v2, fal.ai, Runway, nodos partner de ComfyUI o pesos abiertos locales. Clips de 4-15s a 2K con animación de primer/último fotograma.

    Costo de contexto al activarse
    582 tok
    Tamaño del paquete
    1 archivo
    Última actualización
    hace 9 días
    diseno ui

    Genera, reconstruye, inspecciona y enruta activos 3D de producción para mundos de OpenMontage con Atlas Cloud, fal.ai, catálogos con licencia y Blender.

    Costo de contexto al activarse
    1.2k tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 9 días
    diseno ui

    Skills relacionados

    Genera, reconstruye, inspecciona y enruta activos 3D de producción para mundos de OpenMontage con Atlas Cloud, fal.ai, catálogos con licencia y Blender.

    Costo de contexto al activarse
    1.2k tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 9 días
    diseno ui

    Acestep

    49.5k

    Generación musical con ACE-Step 1.5: música de fondo, pistas con voz, versiones y extracción de stems para producción de vídeo.

    Costo de contexto al activarse
    2.3k tok
    Tamaño del paquete
    1 archivo
    Última actualización
    hace 4 meses
    diseno ui

    Genera vídeos con IA desde texto usando varias pasarelas — HeyGen, fal.ai, Kling y Gemini — con soporte de imagen a vídeo y comparación entre VEO, Kling, Sora, Runway, Seedance y MiniMax.

    Costo de contexto al activarse
    3k tok
    Tamaño del paquete
    1 archivo
    Última actualización
    el mes pasado
    diseno ui