constructor(xrInputSource, profile, assetUrl) {
        if (!xrInputSource) {
            throw new Error('No xrInputSource supplied');
        }

        if (!profile) {
            throw new Error('No profile supplied');
        }

        this.xrInputSource = xrInputSource;
        this.assetUrl = assetUrl;
        this.id = profile.profileId;

        // Build child components as described in the profile description
        this.layoutDescription = profile.layouts[xrInputSource.handedness];
        this.components = {};
        Object.keys(this.layoutDescription.components).forEach((componentId) => {
            const componentDescription = this.layoutDescription.components[componentId];
            this.components[componentId] = new Component(componentId, componentDescription);
        });

        // Initialize components based on current gamepad state
        this.updateFromGamepad();
    }
@param {Object} xrInputSource - The XRInputSource to build the MotionController around
@param {Object} profile - The best matched profile description for the supplied xrInputSource
@param {Object} assetUrl