threejs-loaders by cloudai-x/threejs-skills
npx skills add https://github.com/cloudai-x/threejs-skills --skill threejs-loadersimport * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
// 加载 GLTF 模型
const loader = new GLTFLoader();
loader.load("model.glb", (gltf) => {
scene.add(gltf.scene);
});
// 加载纹理
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load("texture.jpg");
协调多个加载器并跟踪进度。
const manager = new THREE.LoadingManager();
// 回调函数
manager.onStart = (url, loaded, total) => {
console.log(`开始加载: ${url}`);
};
manager.onLoad = () => {
console.log("所有资源加载完成!");
startGame();
};
manager.onProgress = (url, loaded, total) => {
const progress = (loaded / total) * 100;
console.log(`加载进度: ${progress.toFixed(1)}%`);
updateProgressBar(progress);
};
manager.onError = (url) => {
console.error(`加载错误: ${url}`);
};
// 将管理器用于加载器
const textureLoader = new THREE.TextureLoader(manager);
const gltfLoader = new GLTFLoader(manager);
// 加载资源
textureLoader.load("texture1.jpg");
textureLoader.load("texture2.jpg");
gltfLoader.load("model.glb");
// 当所有资源加载完成时触发 onLoad
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
const loader = new THREE.TextureLoader();
// 回调函数风格
loader.load(
"texture.jpg",
(texture) => {
// onLoad
material.map = texture;
material.needsUpdate = true;
},
undefined, // onProgress - 图像加载不支持
(error) => {
// onError
console.error("加载纹理错误", error);
},
);
// 同步方式(返回纹理,异步加载)
const texture = loader.load("texture.jpg");
material.map = texture;
const texture = loader.load("texture.jpg", (tex) => {
// 色彩空间(对色彩准确性很重要)
tex.colorSpace = THREE.SRGBColorSpace; // 用于颜色/反照率贴图
// tex.colorSpace = THREE.LinearSRGBColorSpace; // 用于数据贴图(法线、粗糙度)
// 包裹方式
tex.wrapS = THREE.RepeatWrapping;
tex.wrapT = THREE.RepeatWrapping;
// ClampToEdgeWrapping, RepeatWrapping, MirroredRepeatWrapping
// 重复/偏移
tex.repeat.set(2, 2);
tex.offset.set(0.5, 0.5);
tex.rotation = Math.PI / 4;
tex.center.set(0.5, 0.5);
// 过滤
tex.minFilter = THREE.LinearMipmapLinearFilter; // 默认值
tex.magFilter = THREE.LinearFilter; // 默认值
// NearestFilter - 像素化
// LinearFilter - 平滑
// LinearMipmapLinearFilter - 带 mipmap 的平滑
// 各向异性过滤(在角度上更清晰)
tex.anisotropy = renderer.capabilities.getMaxAnisotropy();
// 翻转 Y 轴(标准纹理通常为 true)
tex.flipY = true;
tex.needsUpdate = true;
});
用于环境贴图和天空盒。
const loader = new THREE.CubeTextureLoader();
// 加载 6 个面
const cubeTexture = loader.load([
"px.jpg",
"nx.jpg", // 正/负 X 轴
"py.jpg",
"ny.jpg", // 正/负 Y 轴
"pz.jpg",
"nz.jpg", // 正/负 Z 轴
]);
// 用作背景
scene.background = cubeTexture;
// 用作环境贴图
scene.environment = cubeTexture;
material.envMap = cubeTexture;
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;
});
为 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();
});
Web 上最常见的 3D 格式。
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
const loader = new GLTFLoader();
loader.load("model.glb", (gltf) => {
// 加载的场景
const model = gltf.scene;
scene.add(model);
// 动画
const animations = gltf.animations;
if (animations.length > 0) {
const mixer = new THREE.AnimationMixer(model);
animations.forEach((clip) => {
mixer.clipAction(clip).play();
});
}
// 相机(如果有)
const cameras = gltf.cameras;
// 资源信息
console.log(gltf.asset); // 版本、生成器等
// 来自 Blender 等的用户数据
console.log(gltf.userData);
});
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);
});
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);
});
loader.load("model.glb", (gltf) => {
const model = gltf.scene;
// 启用阴影
model.traverse((child) => {
if (child.isMesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
// 查找特定网格
const head = model.getObjectByName("Head");
// 调整材质
model.traverse((child) => {
if (child.isMesh && child.material) {
child.material.envMapIntensity = 0.5;
}
});
// 居中和缩放
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);
});
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);
});
});
import { FBXLoader } from "three/addons/loaders/FBXLoader.js";
const loader = new FBXLoader();
loader.load("model.fbx", (object) => {
// FBX 通常具有较大的缩放比例
object.scale.setScalar(0.01);
// 动画
const mixer = new THREE.AnimationMixer(object);
object.animations.forEach((clip) => {
mixer.clipAction(clip).play();
});
scene.add(object);
});
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);
});
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);
});
function loadModel(url) {
return new Promise((resolve, reject) => {
loader.load(url, resolve, undefined, reject);
});
}
// 用法
async function init() {
try {
const gltf = await loadModel("model.glb");
scene.add(gltf.scene);
} catch (error) {
console.error("加载模型失败:", error);
}
}
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;
}
// 辅助函数
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);
});
}
// 启用缓存
THREE.Cache.enabled = true;
// 清除缓存
THREE.Cache.clear();
// 手动缓存管理
THREE.Cache.add("key", data);
THREE.Cache.get("key");
THREE.Cache.remove("key");
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();
}
}
// 用法
const assets = new AssetManager();
const texture = await assets.loadTexture("brick", "brick.jpg");
const model = await assets.loadModel("tree", "tree.glb");
const loader = new THREE.TextureLoader();
const texture = loader.load("data:image/png;base64,iVBORw0KGgo...");
async function loadFromBlob(blob) {
const url = URL.createObjectURL(blob);
const texture = await loadTexture(url);
URL.revokeObjectURL(url);
return texture;
}
// 从 fetch 获取
const response = await fetch("model.glb");
const buffer = await response.arrayBuffer();
// 使用加载器解析
const loader = new GLTFLoader();
loader.parse(buffer, "", (gltf) => {
scene.add(gltf.scene);
});
// 设置基础路径
loader.setPath("assets/models/");
loader.load("model.glb"); // 从 assets/models/model.glb 加载
// 设置资源路径(用于模型中引用的纹理)
loader.setResourcePath("assets/textures/");
// 自定义 URL 修改器
manager.setURLModifier((url) => {
return `https://cdn.example.com/${url}`;
});
// 优雅降级
async function loadWithFallback(primaryUrl, fallbackUrl) {
try {
return await loadModel(primaryUrl);
} catch (error) {
console.warn(`主资源加载失败,尝试备用资源: ${error}`);
return await loadModel(fallbackUrl);
}
}
// 重试逻辑
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)));
}
}
}
// 超时处理
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("加载超时");
}
throw error;
}
}
THREE.Cache.enabled = true// 带占位符的渐进式加载
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);
});
threejs-textures - 纹理配置threejs-animation - 播放加载的动画threejs-materials - 从加载的模型获取材质每周安装量
1.3K
代码仓库
GitHub 星标数
1.8K
首次出现
2026年1月20日
安全审计
安装于
opencode1.0K
gemini-cli996
claude-code988
codex907
cursor879
github-copilot769
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");
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
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;
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;
});
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;
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;
});
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();
});
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);
});
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);
});
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);
});
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);
});
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);
});
});
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);
});
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);
});
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);
});
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);
}
}
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);
});
}
// 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");
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");
const loader = new THREE.TextureLoader();
const texture = loader.load("data:image/png;base64,iVBORw0KGgo...");
async function loadFromBlob(blob) {
const url = URL.createObjectURL(blob);
const texture = await loadTexture(url);
URL.revokeObjectURL(url);
return texture;
}
// 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);
});
// 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}`;
});
// 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;
}
}
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);
});
threejs-textures - Texture configurationthreejs-animation - Playing loaded animationsthreejs-materials - Material from loaded modelsWeekly Installs
1.3K
Repository
GitHub Stars
1.8K
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
opencode1.0K
gemini-cli996
claude-code988
codex907
cursor879
github-copilot769
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
AI代码审查工具 - 自动化安全漏洞检测与代码质量分析 | 支持多领域检查清单
1,200 周安装
AI智能体长期记忆系统 - 精英级架构,融合6种方法,永不丢失上下文
1,200 周安装
AI新闻播客制作技能:实时新闻转对话式播客脚本与音频生成
1,200 周安装
Word文档处理器:DOCX创建、编辑、分析与修订痕迹处理全指南 | 自动化办公解决方案
1,200 周安装
React Router 框架模式指南:全栈开发、文件路由、数据加载与渲染策略
1,200 周安装
Nano Banana AI 图像生成工具:使用 Gemini 3 Pro 生成与编辑高分辨率图像
1,200 周安装