WebXR controllers without using online repository

Hi all. I was able to answer at least part of my own question, thanks to this previous answer: Issues with current state of WebRequest.CustomRequestHeaders / CustomRequestModifiers

To avoid having to use the remote github repo to download controller models, you can get the relevant files using this bash script:

# Remove pevious version of the git repo.
rm -rf webxr-input-profiles
rm -rf profiles

# A pretty large git repo. May take a bit.
git clone https://github.com/immersive-web/webxr-input-profiles.git

# Change to the appropriate directory.
cd webxr-input-profiles/packages/assets/

# The models and specificiations are in ./profiles/, but the profilesList.json
# file is missing (presumably created on build). I struggled to build this
# part of the repo, but you can just downloaded the profilesList.json file
# directly from their online app to get around it.
curl https://immersive-web.github.io/webxr-input-profiles/packages/viewer/dist/profiles/profilesList.json > profiles/profilesList.json

# The profile.json files are also incomplete. Get each of those from the
# remote server as well.
find profiles -name "profile.json" | awk '{print "curl https://immersive-web.github.io/webxr-input-profiles/packages/viewer/dist/" $1 " > " $1}' | bash

# Move your profiles directory elsewhere.
mv profiles ../../../

# Clean up
cd ../../../
rm -rf webxr-input-profiles

You can then point to the new profiles directory on your own server like this:

BABYLON.WebXRMotionControllerManager.BaseRepositoryUrl = "path/to/directory/containing/profiles/directory/";

Note that the contents of the profiles directory take up about 68M.

One other trick in case it’s helpful. The controllers are rendered using PBR materials. If your scene doesn’t have the appropriate lighting, they will look totally black. See Start with Physically Based Rendering (PBR) - Babylon.js Documentation

You can switch all the materials to StandardMaterials like this (TypeScript):

scene.createDefaultXRExperienceAsync(params).then((vrHelper: any) => {
    vrHelper.input.onControllerAddedObservable.add((inputSource: any) => {
        inputSource.onMeshLoadedObservable.add((controllerMesh: any) => {
            // Switch all materials on controllers to be standard materials.
            let meshes = [controllerMesh];
            let meshIdx = 0;
            while (meshIdx < meshes.length) {
                let mesh = meshes[meshIdx];
                if (mesh.material && mesh.material.albedoTexture) {
                    const newMat = new BABYLON.StandardMaterial(
                        mesh.name + "Material",
                        Vars.scene
                    );

                    newMat.diffuseTexture = mesh.material.albedoTexture;

                    mesh.material = newMat;
                }

                meshes = meshes.concat(mesh.getChildren());
                meshIdx++;
            }
        });
    });
});

In terms of not defaulting to “Generic-Button controller” when BABYLON.WebXRMotionControllerManager.PrioritizeOnlineRepository = false, I think that might be a legitimate bug.

Hope this helps someone.