How to inject `@babylonjs/ktx2decoder` into Babylon?

Good questions! Here’s a braindump from what I remember about all this…


If the only goal is to avoid using the CDN, the simplest option is to rely on URLConfig. Just grab the bundled UMD files from the CDN, host them yourself (which you’ve already done :slight_smile: ), and point Babylon to your copies:

const baseUrl = "/lib";
KhronosTextureContainer2.URLConfig = {
    // Copy of https://cdn.babylonjs.com/babylon.ktx2Decoder.js
    jsDecoderModule: baseUrl + "/babylon.ktx2Decoder.js", 
    // Copy of https://cdn.babylonjs.com/ktx2Transcoders/1/msc_basis_transcoder.js 
    jsMSCTranscoder: baseUrl + "/ktx2Transcoders/1/msc_basis_transcoder.js",
    // Copy of https://cdn.babylonjs.com/ktx2Transcoders/1/msc_basis_transcoder.wasm
    wasmMSCTranscoder: baseUrl + "/ktx2Transcoders/1/msc_basis_transcoder.wasm",
};

More info: CDN Babylon.js Packages.

Do note, though, that the URLConfig approach won’t really work with @babylonjs/ktx2decoder. As the post you linked shows (“How do I use @babylonjs/ktx2decoder properly?”), you may run into this:

import ktx2DecoderUrl from '@babylonjs/ktx2decoder/ktx2Decoder.js?url';
import uastcAstcWasmUrl from "@babylonjs/ktx2decoder/wasm/uastc_astc.wasm?url";

KhronosTextureContainer2.URLConfig = {
    jsDecoderModule: ktx2DecoderUrl, // <- Errors
    wasmUASTCToASTC: uastcAstcWasmUrl; // OK
};

The issue is that the decoder URL ultimately gets loaded through LoadScript(), which expects a self‑contained module, and @babylonjs/ktx2decoder/ktx2Decoder.js alone isn’t structured that way.

You may have better luck pointing the URLs of the JS modules to their UMD counterparts over in the babylonjs-ktx2decoders NPM package, but I haven’t tested this.


There’s also the worker-based approach like you’ve taken, which is the most robust but complex option. It was originally added to support strict CSP environments, so it leans fully into supplying your own assets, including the worker itself. Because you’re providing the worker, you can import the decoder module however you need before injecting it. This avoids the aforementioned limitations of the URLConfig approach.


Normally there’d be a middle-ground solution-- like simple module injection without a worker, which you mentioned-- but that doesn’t exist yet. Some of the internal scaffolding is already there (like someone pointed out in the same thread), but the feature hasn’t been built out.

1 Like