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
You can’t perform that action at this time.