Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Using motion-controllers.modules.js
// A barebones example of how to use the motion-controllers library and assets repository to load controller models in yor WebXR app
// This gist will not go into the details of how to set up a WebXR app (See for that)
// but will instead focus on the parts needed to find and load the appropriate controller.
// The motion-controllers library is small enough that it can easily be dropped into your own codebase if you wish, but loading it
// directly from a CDN like jsdelivr is an even easier route to getting up and running.
import { fetchProfile } from '';
// The assets package ( is larger, about 67Mb at time of writing,
// so it may be more beneficial to always use a CDN for it, especially since that will enable your app to pick up new controllers
// as they're added with zero effort on your part. You can still host it on your own server if preferred, though.
const ROOT_ASSETS_PATH = '';
// Do all your usual WebXR app setup here. We'll assume you have an XRSession available.
// The models can be queried at any time with any XRInputSource, but one of the best places to do so is when the input sources
// are first added, which can be detected with the 'inputsourceschange' event.
xrSession.addEventListener('inputsourceschange', async (event) => {
for (xrInputSource of event.added) {
try {
// fetchProfile will look at the 'profiles' array reported by the xrInputSource, match that with the available assets,
// and return the registered profile that best matches the xrInputSource and a URL for the controller asset.
let { profile, assetPath } = await fetchProfile(xrInputSource, ROOT_ASSETS_PATH);
// The assetPath points to a binary glTF file (*.glb). This is an increasingly common format that's easy to parse on
// the web, so there's a good chance that your rendering library already has a way of loading them. If you don't care
// about animating the controller to show things like button presses then all you have to do is load the controller
// and transform it to match the XRInputSource's gripSpace pose every frame. Tada! You're now showing the user's controllers!
} catch (err) {
// No appropriate assets found for the xrInputSource.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment