function createModule(loader: () => Promise) { const callbacks: Array<(module: T) => void> = []; const mod = { MODULE: undefined as unknown as T, MAYBEMODULE: null as T | null, /** Wait for the module to be loaded (doesn't trigger a load) */ ready(): Promise { if (mod.MODULE) return Promise.resolve(mod.MODULE); return new Promise(resolve => { callbacks.push(resolve); }); }, /** Load the module */ async load(): Promise { if (mod.MODULE) return mod.MODULE; const module = await loader(); mod.MODULE = module; mod.MAYBEMODULE = module; for (const cb of callbacks) cb(module); callbacks.length = 0; return module; } }; return mod; } /** * External dependencies that are loaded on demand either by the engine automatically when needed or they can be loaded manually by calling the `load` function. * * Use the `ready` function to wait for the module to be loaded if you do not wand to trigger a load. * * If a module is already loaded it's also available in the `MODULE` variable. */ export const MODULES = { MaterialX: createModule( () => import("@needle-tools/materialx") ), RAPIER_PHYSICS: createModule( () => import("@dimforge/rapier3d-compat") ), POSTPROCESSING: createModule( () => import("postprocessing") ), POSTPROCESSING_AO: createModule( () => import("n8ao") ), PEERJS: createModule( () => import("peerjs") ), };