PROCITY/web/js/core/loaders.js
2026-07-14 10:46:40 +10:00

40 lines
1.7 KiB
JavaScript

// PROCITY core loaders — promise-cached, fail-soft (house pattern from both parent games).
// Missing asset ⇒ null / flat colour; callers keep their placeholder. The game runs asset-free.
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
export const DEPOT = 'https://digalot.fyi/3god'; // shared GLB CDN: GET /a/<file>, /api/list
const gltfLoader = new GLTFLoader();
const texLoader = new THREE.TextureLoader();
const GLB_CACHE = {}; // url → Promise<gltf|null>
const TEX_CACHE = {}; // url → THREE.Texture (may still be loading; fallback colour beneath)
// loadGLB('gen/x.glb' | 'depot:file.glb' | full URL) → Promise<gltf|null>, cached, never rejects
export function loadGLB(ref) {
const url = ref.startsWith('depot:') ? `${DEPOT}/a/${ref.slice(6)}` : ref;
return (GLB_CACHE[url] ||= gltfLoader.loadAsync(url).catch(err => {
console.warn('[loaders] GLB failed, placeholder stays:', url, err?.message || err);
return null;
}));
}
// loadTex(url, {repeat:[u,v]}) → texture immediately (fills in when loaded), sRGB, aniso 4
export function loadTex(url, opts = {}) {
if (TEX_CACHE[url]) return TEX_CACHE[url];
const t = texLoader.load(url, undefined, undefined,
() => console.warn('[loaders] tex failed, fallback colour stays:', url));
t.colorSpace = THREE.SRGBColorSpace;
t.anisotropy = 4;
if (opts.repeat) { t.wrapS = t.wrapT = THREE.RepeatWrapping; t.repeat.set(...opts.repeat); }
TEX_CACHE[url] = t;
return t;
}
// fetch + cache the depot listing (editor palettes, Lane E validation)
let _depotList = null;
export async function depotList() {
return (_depotList ||= fetch(`${DEPOT}/api/list`).then(r => r.json()).catch(() => []));
}