{"version":3,"file":"MotionControllers.cjs","sources":["../../src/libs/MotionControllers.ts"],"sourcesContent":["/**\n * @webxr-input-profiles/motion-controllers 1.0.0 https://github.com/immersive-web/webxr-input-profiles\n */\n\nimport type { Object3D } from 'three'\n\ninterface GamepadIndices {\n  button: number\n  xAxis?: number\n  yAxis?: number\n}\n\ninterface VisualResponseDescription {\n  componentProperty: string\n  states: string[]\n  valueNodeProperty: string\n  valueNodeName: string\n  minNodeName?: string\n  maxNodeName?: string\n}\n\ntype VisualResponses = Record<string, VisualResponseDescription>\n\ninterface ComponentDescription {\n  type: string\n  gamepadIndices: GamepadIndices\n  rootNodeName: string\n  visualResponses: VisualResponses\n  touchPointNodeName?: string\n}\n\ninterface Components {\n  [componentKey: string]: ComponentDescription\n}\n\ninterface LayoutDescription {\n  selectComponentId: string\n  components: Components\n  gamepadMapping: string\n  rootNodeName: string\n  assetPath: string\n}\n\ntype Layouts = Partial<Record<XRHandedness, LayoutDescription>>\n\nexport interface Profile {\n  profileId: string\n  fallbackProfileIds: string[]\n  layouts: Layouts\n}\n\ninterface ProfilesList {\n  [profileId: string]: { path: string; deprecated?: boolean } | undefined\n}\n\nconst MotionControllerConstants = {\n  Handedness: {\n    NONE: 'none',\n    LEFT: 'left',\n    RIGHT: 'right',\n  },\n\n  ComponentState: {\n    DEFAULT: 'default',\n    TOUCHED: 'touched',\n    PRESSED: 'pressed',\n  },\n\n  ComponentProperty: {\n    BUTTON: 'button',\n    X_AXIS: 'xAxis',\n    Y_AXIS: 'yAxis',\n    STATE: 'state',\n  },\n\n  ComponentType: {\n    TRIGGER: 'trigger',\n    SQUEEZE: 'squeeze',\n    TOUCHPAD: 'touchpad',\n    THUMBSTICK: 'thumbstick',\n    BUTTON: 'button',\n  },\n\n  ButtonTouchThreshold: 0.05,\n\n  AxisTouchThreshold: 0.1,\n\n  VisualResponseProperty: {\n    TRANSFORM: 'transform',\n    VISIBILITY: 'visibility',\n  },\n}\n\n/**\n * @description Static helper function to fetch a JSON file and turn it into a JS object\n * @param {string} path - Path to JSON file to be fetched\n */\nasync function fetchJsonFile<T>(path: string): Promise<T> {\n  const response = await fetch(path)\n  if (!response.ok) {\n    throw new Error(response.statusText)\n  } else {\n    return response.json()\n  }\n}\n\nasync function fetchProfilesList(basePath: string): Promise<ProfilesList> {\n  if (!basePath) {\n    throw new Error('No basePath supplied')\n  }\n\n  const profileListFileName = 'profilesList.json'\n  const profilesList = await fetchJsonFile<ProfilesList>(`${basePath}/${profileListFileName}`)\n  return profilesList\n}\n\nasync function fetchProfile(\n  xrInputSource: XRInputSource,\n  basePath: string,\n  defaultProfile: string | null = null,\n  getAssetPath = true,\n): Promise<{ profile: Profile; assetPath: string | undefined }> {\n  if (!xrInputSource) {\n    throw new Error('No xrInputSource supplied')\n  }\n\n  if (!basePath) {\n    throw new Error('No basePath supplied')\n  }\n\n  // Get the list of profiles\n  const supportedProfilesList = await fetchProfilesList(basePath)\n\n  // Find the relative path to the first requested profile that is recognized\n  let match: { profileId: string; profilePath: string; deprecated: boolean } | undefined = undefined\n  xrInputSource.profiles.some((profileId: string) => {\n    const supportedProfile = supportedProfilesList[profileId]\n    if (supportedProfile) {\n      match = {\n        profileId,\n        profilePath: `${basePath}/${supportedProfile.path}`,\n        deprecated: !!supportedProfile.deprecated,\n      }\n    }\n    return !!match\n  })\n\n  if (!match) {\n    if (!defaultProfile) {\n      throw new Error('No matching profile name found')\n    }\n\n    const supportedProfile = supportedProfilesList[defaultProfile]\n    if (!supportedProfile) {\n      throw new Error(`No matching profile name found and default profile \"${defaultProfile}\" missing.`)\n    }\n\n    match = {\n      profileId: defaultProfile,\n      profilePath: `${basePath}/${supportedProfile.path}`,\n      deprecated: !!supportedProfile.deprecated,\n    }\n  }\n\n  const profile = await fetchJsonFile<Profile>(match.profilePath)\n\n  let assetPath: string | undefined = undefined\n  if (getAssetPath) {\n    let layout\n    if ((xrInputSource.handedness as string) === 'any') {\n      layout = profile.layouts[Object.keys(profile.layouts)[0] as XRHandedness]\n    } else {\n      layout = profile.layouts[xrInputSource.handedness]\n    }\n    if (!layout) {\n      throw new Error(`No matching handedness, ${xrInputSource.handedness}, in profile ${match.profileId}`)\n    }\n\n    if (layout.assetPath) {\n      assetPath = match.profilePath.replace('profile.json', layout.assetPath)\n    }\n  }\n\n  return { profile, assetPath }\n}\n\n/** @constant {Object} */\nconst defaultComponentValues = {\n  xAxis: 0,\n  yAxis: 0,\n  button: 0,\n  state: MotionControllerConstants.ComponentState.DEFAULT,\n}\n\n/**\n * @description Converts an X, Y coordinate from the range -1 to 1 (as reported by the Gamepad\n * API) to the range 0 to 1 (for interpolation). Also caps the X, Y values to be bounded within\n * a circle. This ensures that thumbsticks are not animated outside the bounds of their physical\n * range of motion and touchpads do not report touch locations off their physical bounds.\n * @param {number | undefined} x The original x coordinate in the range -1 to 1\n * @param {number | undefined} y The original y coordinate in the range -1 to 1\n */\nfunction normalizeAxes(\n  x: number | undefined = 0,\n  y: number | undefined = 0,\n): { normalizedXAxis: number; normalizedYAxis: number } {\n  let xAxis = x\n  let yAxis = y\n\n  // Determine if the point is outside the bounds of the circle\n  // and, if so, place it on the edge of the circle\n  const hypotenuse = Math.sqrt(x * x + y * y)\n  if (hypotenuse > 1) {\n    const theta = Math.atan2(y, x)\n    xAxis = Math.cos(theta)\n    yAxis = Math.sin(theta)\n  }\n\n  // Scale and move the circle so values are in the interpolation range.  The circle's origin moves\n  // from (0, 0) to (0.5, 0.5). The circle's radius scales from 1 to be 0.5.\n  const result = {\n    normalizedXAxis: xAxis * 0.5 + 0.5,\n    normalizedYAxis: yAxis * 0.5 + 0.5,\n  }\n  return result\n}\n\n/**\n * Contains the description of how the 3D model should visually respond to a specific user input.\n * This is accomplished by initializing the object with the name of a node in the 3D model and\n * property that need to be modified in response to user input, the name of the nodes representing\n * the allowable range of motion, and the name of the input which triggers the change. In response\n * to the named input changing, this object computes the appropriate weighting to use for\n * interpolating between the range of motion nodes.\n */\nclass VisualResponse implements VisualResponseDescription {\n  value: number | boolean\n  componentProperty: string\n  states: string[]\n  valueNodeName: string\n  valueNodeProperty: string\n  minNodeName?: string\n  maxNodeName?: string\n  valueNode: Object3D | undefined\n  minNode: Object3D | undefined\n  maxNode: Object3D | undefined\n  constructor(visualResponseDescription: VisualResponseDescription) {\n    this.componentProperty = visualResponseDescription.componentProperty\n    this.states = visualResponseDescription.states\n    this.valueNodeName = visualResponseDescription.valueNodeName\n    this.valueNodeProperty = visualResponseDescription.valueNodeProperty\n\n    if (this.valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM) {\n      this.minNodeName = visualResponseDescription.minNodeName\n      this.maxNodeName = visualResponseDescription.maxNodeName\n    }\n\n    // Initializes the response's current value based on default data\n    this.value = 0\n    this.updateFromComponent(defaultComponentValues)\n  }\n\n  /**\n   * Computes the visual response's interpolation weight based on component state\n   * @param {Object} componentValues - The component from which to update\n   * @param {number | undefined} xAxis - The reported X axis value of the component\n   * @param {number | undefined} yAxis - The reported Y axis value of the component\n   * @param {number | undefined} button - The reported value of the component's button\n   * @param {string} state - The component's active state\n   */\n  updateFromComponent({\n    xAxis,\n    yAxis,\n    button,\n    state,\n  }: {\n    xAxis?: number\n    yAxis?: number\n    button?: number\n    state: string\n  }): void {\n    const { normalizedXAxis, normalizedYAxis } = normalizeAxes(xAxis, yAxis)\n    switch (this.componentProperty) {\n      case MotionControllerConstants.ComponentProperty.X_AXIS:\n        this.value = this.states.includes(state) ? normalizedXAxis : 0.5\n        break\n      case MotionControllerConstants.ComponentProperty.Y_AXIS:\n        this.value = this.states.includes(state) ? normalizedYAxis : 0.5\n        break\n      case MotionControllerConstants.ComponentProperty.BUTTON:\n        this.value = this.states.includes(state) && button ? button : 0\n        break\n      case MotionControllerConstants.ComponentProperty.STATE:\n        if (this.valueNodeProperty === MotionControllerConstants.VisualResponseProperty.VISIBILITY) {\n          this.value = this.states.includes(state)\n        } else {\n          this.value = this.states.includes(state) ? 1.0 : 0.0\n        }\n        break\n      default:\n        throw new Error(`Unexpected visualResponse componentProperty ${this.componentProperty}`)\n    }\n  }\n}\n\nclass Component implements ComponentDescription {\n  id: string\n  values: {\n    state: string\n    button: number | undefined\n    xAxis: number | undefined\n    yAxis: number | undefined\n  }\n\n  type: string\n  gamepadIndices: GamepadIndices\n  rootNodeName: string\n  visualResponses: Record<string, VisualResponse>\n  touchPointNodeName?: string | undefined\n  touchPointNode?: Object3D\n\n  /**\n   * @param {string} componentId - Id of the component\n   * @param {InputProfileComponent} componentDescription - Description of the component to be created\n   */\n  constructor(componentId: string, componentDescription: ComponentDescription) {\n    if (\n      !componentId ||\n      !componentDescription ||\n      !componentDescription.visualResponses ||\n      !componentDescription.gamepadIndices ||\n      Object.keys(componentDescription.gamepadIndices).length === 0\n    ) {\n      throw new Error('Invalid arguments supplied')\n    }\n\n    this.id = componentId\n    this.type = componentDescription.type\n    this.rootNodeName = componentDescription.rootNodeName\n    this.touchPointNodeName = componentDescription.touchPointNodeName\n\n    // Build all the visual responses for this component\n    this.visualResponses = {}\n    Object.keys(componentDescription.visualResponses).forEach((responseName) => {\n      const visualResponse = new VisualResponse(componentDescription.visualResponses[responseName])\n      this.visualResponses[responseName] = visualResponse\n    })\n\n    // Set default values\n    this.gamepadIndices = Object.assign({}, componentDescription.gamepadIndices)\n\n    this.values = {\n      state: MotionControllerConstants.ComponentState.DEFAULT,\n      button: this.gamepadIndices.button !== undefined ? 0 : undefined,\n      xAxis: this.gamepadIndices.xAxis !== undefined ? 0 : undefined,\n      yAxis: this.gamepadIndices.yAxis !== undefined ? 0 : undefined,\n    }\n  }\n\n  get data(): { id: Component['id'] } & Component['values'] {\n    const data = { id: this.id, ...this.values }\n    return data\n  }\n\n  /**\n   * @description Poll for updated data based on current gamepad state\n   * @param {Object} gamepad - The gamepad object from which the component data should be polled\n   */\n  updateFromGamepad(gamepad: Gamepad): void {\n    // Set the state to default before processing other data sources\n    this.values.state = MotionControllerConstants.ComponentState.DEFAULT\n\n    // Get and normalize button\n    if (this.gamepadIndices.button !== undefined && gamepad.buttons.length > this.gamepadIndices.button) {\n      const gamepadButton = gamepad.buttons[this.gamepadIndices.button]\n      this.values.button = gamepadButton.value\n      this.values.button = this.values.button! < 0 ? 0 : this.values.button\n      this.values.button = this.values.button! > 1 ? 1 : this.values.button\n\n      // Set the state based on the button\n      if (gamepadButton.pressed || this.values.button === 1) {\n        this.values.state = MotionControllerConstants.ComponentState.PRESSED\n      } else if (gamepadButton.touched || this.values.button! > MotionControllerConstants.ButtonTouchThreshold) {\n        this.values.state = MotionControllerConstants.ComponentState.TOUCHED\n      }\n    }\n\n    // Get and normalize x axis value\n    if (this.gamepadIndices.xAxis !== undefined && gamepad.axes.length > this.gamepadIndices.xAxis) {\n      this.values.xAxis = gamepad.axes[this.gamepadIndices.xAxis]\n      this.values.xAxis = this.values.xAxis! < -1 ? -1 : this.values.xAxis\n      this.values.xAxis = this.values.xAxis! > 1 ? 1 : this.values.xAxis\n\n      // If the state is still default, check if the xAxis makes it touched\n      if (\n        this.values.state === MotionControllerConstants.ComponentState.DEFAULT &&\n        Math.abs(this.values.xAxis!) > MotionControllerConstants.AxisTouchThreshold\n      ) {\n        this.values.state = MotionControllerConstants.ComponentState.TOUCHED\n      }\n    }\n\n    // Get and normalize Y axis value\n    if (this.gamepadIndices.yAxis !== undefined && gamepad.axes.length > this.gamepadIndices.yAxis) {\n      this.values.yAxis = gamepad.axes[this.gamepadIndices.yAxis]\n      this.values.yAxis = this.values.yAxis! < -1 ? -1 : this.values.yAxis\n      this.values.yAxis = this.values.yAxis! > 1 ? 1 : this.values.yAxis\n\n      // If the state is still default, check if the yAxis makes it touched\n      if (\n        this.values.state === MotionControllerConstants.ComponentState.DEFAULT &&\n        Math.abs(this.values.yAxis!) > MotionControllerConstants.AxisTouchThreshold\n      ) {\n        this.values.state = MotionControllerConstants.ComponentState.TOUCHED\n      }\n    }\n\n    // Update the visual response weights based on the current component data\n    Object.values(this.visualResponses).forEach((visualResponse) => {\n      visualResponse.updateFromComponent(this.values)\n    })\n  }\n}\n/**\n * @description Builds a motion controller with components and visual responses based on the\n * supplied profile description. Data is polled from the xrInputSource's gamepad.\n * @author Nell Waliczek / https://github.com/NellWaliczek\n */\nclass MotionController {\n  xrInputSource: XRInputSource\n  assetUrl: string\n  layoutDescription: LayoutDescription\n  id: string\n  components: Record<string, Component>\n  /**\n   * @param {XRInputSource} xrInputSource - The XRInputSource to build the MotionController around\n   * @param {Profile} profile - The best matched profile description for the supplied xrInputSource\n   * @param {string} assetUrl\n   */\n  constructor(xrInputSource: XRInputSource, profile: Profile, assetUrl: string) {\n    if (!xrInputSource) {\n      throw new Error('No xrInputSource supplied')\n    }\n\n    if (!profile) {\n      throw new Error('No profile supplied')\n    }\n\n    if (!profile.layouts[xrInputSource.handedness]) {\n      throw new Error('No layout for ' + xrInputSource.handedness + ' handedness')\n    }\n\n    this.xrInputSource = xrInputSource\n    this.assetUrl = assetUrl\n    this.id = profile.profileId\n\n    // Build child components as described in the profile description\n    this.layoutDescription = profile.layouts[xrInputSource.handedness]!\n\n    this.components = {}\n    Object.keys(this.layoutDescription.components).forEach((componentId) => {\n      const componentDescription = this.layoutDescription.components[componentId]\n      this.components[componentId] = new Component(componentId, componentDescription)\n    })\n\n    // Initialize components based on current gamepad state\n    this.updateFromGamepad()\n  }\n\n  get gripSpace(): XRInputSource['gripSpace'] {\n    return this.xrInputSource.gripSpace\n  }\n\n  get targetRaySpace(): XRInputSource['targetRaySpace'] {\n    return this.xrInputSource.targetRaySpace\n  }\n\n  /**\n   * @description Returns a subset of component data for simplified debugging\n   */\n  get data(): Array<Component['data']> {\n    const data: Array<Component['data']> = []\n    Object.values(this.components).forEach((component) => {\n      data.push(component.data)\n    })\n    return data\n  }\n\n  /**\n   * @description Poll for updated data based on current gamepad state\n   */\n  updateFromGamepad(): void {\n    Object.values(this.components).forEach((component) => {\n      component.updateFromGamepad(this.xrInputSource.gamepad!)\n    })\n  }\n}\n\nexport { MotionControllerConstants, MotionController, fetchProfile, fetchProfilesList }\n"],"names":[],"mappings":"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"}