three-stdlib 2.20.5 → 2.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -249,3 +249,4 @@ export * from './curves/NURBSCurve';
249
249
  export * from './curves/NURBSSurface';
250
250
  export * from './curves/CurveExtras';
251
251
  export * from './deprecated/Geometry';
252
+ export * from './libs/MotionControllers';
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e={Handedness:Object.freeze({NONE:"none",LEFT:"left",RIGHT:"right"}),ComponentState:Object.freeze({DEFAULT:"default",TOUCHED:"touched",PRESSED:"pressed"}),ComponentProperty:Object.freeze({BUTTON:"button",X_AXIS:"xAxis",Y_AXIS:"yAxis",STATE:"state"}),ComponentType:Object.freeze({TRIGGER:"trigger",SQUEEZE:"squeeze",TOUCHPAD:"touchpad",THUMBSTICK:"thumbstick",BUTTON:"button"}),ButtonTouchThreshold:.05,AxisTouchThreshold:.1,VisualResponseProperty:Object.freeze({TRANSFORM:"transform",VISIBILITY:"visibility"})};async function t(e){const t=await fetch(e);if(t.ok)return t.json();throw new Error(t.statusText)}async function s(e){if(!e)throw new Error("No basePath supplied");return await t(`${e}/profilesList.json`)}const o={xAxis:0,yAxis:0,button:0,state:e.ComponentState.DEFAULT};class a{constructor(t){this.componentProperty=t.componentProperty,this.states=t.states,this.valueNodeName=t.valueNodeName,this.valueNodeProperty=t.valueNodeProperty,this.valueNodeProperty===e.VisualResponseProperty.TRANSFORM&&(this.minNodeName=t.minNodeName,this.maxNodeName=t.maxNodeName),this.value=0,this.updateFromComponent(o)}updateFromComponent({xAxis:t,yAxis:s,button:o,state:a}){const{normalizedXAxis:i,normalizedYAxis:n}=function(e=0,t=0){let s=e,o=t;if(Math.sqrt(e*e+t*t)>1){const a=Math.atan2(t,e);s=Math.cos(a),o=Math.sin(a)}return{normalizedXAxis:.5*s+.5,normalizedYAxis:.5*o+.5}}(t,s);switch(this.componentProperty){case e.ComponentProperty.X_AXIS:this.value=this.states.includes(a)?i:.5;break;case e.ComponentProperty.Y_AXIS:this.value=this.states.includes(a)?n:.5;break;case e.ComponentProperty.BUTTON:this.value=this.states.includes(a)?o:0;break;case e.ComponentProperty.STATE:this.valueNodeProperty===e.VisualResponseProperty.VISIBILITY?this.value=this.states.includes(a):this.value=this.states.includes(a)?1:0;break;default:throw new Error(`Unexpected visualResponse componentProperty ${this.componentProperty}`)}}}class i{constructor(t,s){if(!(t&&s&&s.visualResponses&&s.gamepadIndices&&0!==Object.keys(s.gamepadIndices).length))throw new Error("Invalid arguments supplied");this.id=t,this.type=s.type,this.rootNodeName=s.rootNodeName,this.touchPointNodeName=s.touchPointNodeName,this.visualResponses={},Object.keys(s.visualResponses).forEach((e=>{const t=new a(s.visualResponses[e]);this.visualResponses[e]=t})),this.gamepadIndices=Object.assign({},s.gamepadIndices),this.values={state:e.ComponentState.DEFAULT,button:void 0!==this.gamepadIndices.button?0:void 0,xAxis:void 0!==this.gamepadIndices.xAxis?0:void 0,yAxis:void 0!==this.gamepadIndices.yAxis?0:void 0}}get data(){return{id:this.id,...this.values}}updateFromGamepad(t){if(this.values.state=e.ComponentState.DEFAULT,void 0!==this.gamepadIndices.button&&t.buttons.length>this.gamepadIndices.button){const s=t.buttons[this.gamepadIndices.button];this.values.button=s.value,this.values.button=this.values.button<0?0:this.values.button,this.values.button=this.values.button>1?1:this.values.button,s.pressed||1===this.values.button?this.values.state=e.ComponentState.PRESSED:(s.touched||this.values.button>e.ButtonTouchThreshold)&&(this.values.state=e.ComponentState.TOUCHED)}void 0!==this.gamepadIndices.xAxis&&t.axes.length>this.gamepadIndices.xAxis&&(this.values.xAxis=t.axes[this.gamepadIndices.xAxis],this.values.xAxis=this.values.xAxis<-1?-1:this.values.xAxis,this.values.xAxis=this.values.xAxis>1?1:this.values.xAxis,this.values.state===e.ComponentState.DEFAULT&&Math.abs(this.values.xAxis)>e.AxisTouchThreshold&&(this.values.state=e.ComponentState.TOUCHED)),void 0!==this.gamepadIndices.yAxis&&t.axes.length>this.gamepadIndices.yAxis&&(this.values.yAxis=t.axes[this.gamepadIndices.yAxis],this.values.yAxis=this.values.yAxis<-1?-1:this.values.yAxis,this.values.yAxis=this.values.yAxis>1?1:this.values.yAxis,this.values.state===e.ComponentState.DEFAULT&&Math.abs(this.values.yAxis)>e.AxisTouchThreshold&&(this.values.state=e.ComponentState.TOUCHED)),Object.values(this.visualResponses).forEach((e=>{e.updateFromComponent(this.values)}))}}exports.MotionController=class{constructor(e,t,s){if(!e)throw new Error("No xrInputSource supplied");if(!t)throw new Error("No profile supplied");this.xrInputSource=e,this.assetUrl=s,this.id=t.profileId,this.layoutDescription=t.layouts[e.handedness],this.components={},Object.keys(this.layoutDescription.components).forEach((e=>{const t=this.layoutDescription.components[e];this.components[e]=new i(e,t)})),this.updateFromGamepad()}get gripSpace(){return this.xrInputSource.gripSpace}get targetRaySpace(){return this.xrInputSource.targetRaySpace}get data(){const e=[];return Object.values(this.components).forEach((t=>{e.push(t.data)})),e}updateFromGamepad(){Object.values(this.components).forEach((e=>{e.updateFromGamepad(this.xrInputSource.gamepad)}))}},exports.MotionControllerConstants=e,exports.fetchProfile=async function(e,o,a=null,i=!0){if(!e)throw new Error("No xrInputSource supplied");if(!o)throw new Error("No basePath supplied");const n=await s(o);let r;if(e.profiles.some((e=>{const t=n[e];return t&&(r={profileId:e,profilePath:`${o}/${t.path}`,deprecated:!!t.deprecated}),!!r})),!r){if(!a)throw new Error("No matching profile name found");const e=n[a];if(!e)throw new Error(`No matching profile name found and default profile "${a}" missing.`);r={profileId:a,profilePath:`${o}/${e.path}`,deprecated:!!e.deprecated}}const h=await t(r.profilePath);let u;if(i){let t;if(t="any"===e.handedness?h.layouts[Object.keys(h.layouts)[0]]:h.layouts[e.handedness],!t)throw new Error(`No matching handedness, ${e.handedness}, in profile ${r.profileId}`);t.assetPath&&(u=r.profilePath.replace("profile.json",t.assetPath))}return{profile:h,assetPath:u}},exports.fetchProfilesList=s;
1
+ "use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}Object.defineProperty(exports,"__esModule",{value:!0});var t=e(require("@babel/runtime/helpers/defineProperty"));const s={Handedness:Object.freeze({NONE:"none",LEFT:"left",RIGHT:"right"}),ComponentState:Object.freeze({DEFAULT:"default",TOUCHED:"touched",PRESSED:"pressed"}),ComponentProperty:Object.freeze({BUTTON:"button",X_AXIS:"xAxis",Y_AXIS:"yAxis",STATE:"state"}),ComponentType:Object.freeze({TRIGGER:"trigger",SQUEEZE:"squeeze",TOUCHPAD:"touchpad",THUMBSTICK:"thumbstick",BUTTON:"button"}),ButtonTouchThreshold:.05,AxisTouchThreshold:.1,VisualResponseProperty:Object.freeze({TRANSFORM:"transform",VISIBILITY:"visibility"})};async function o(e){const t=await fetch(e);if(t.ok)return t.json();throw new Error(t.statusText)}async function i(e){if(!e)throw new Error("No basePath supplied");return await o(`${e}/profilesList.json`)}const a={xAxis:0,yAxis:0,button:0,state:s.ComponentState.DEFAULT};class n{constructor(e){t.default(this,"value",void 0),t.default(this,"componentProperty",void 0),t.default(this,"states",void 0),t.default(this,"valueNodeName",void 0),t.default(this,"valueNodeProperty",void 0),t.default(this,"minNodeName",void 0),t.default(this,"maxNodeName",void 0),t.default(this,"valueNode",void 0),t.default(this,"minNode",void 0),t.default(this,"maxNode",void 0),this.componentProperty=e.componentProperty,this.states=e.states,this.valueNodeName=e.valueNodeName,this.valueNodeProperty=e.valueNodeProperty,this.valueNodeProperty===s.VisualResponseProperty.TRANSFORM&&(this.minNodeName=e.minNodeName,this.maxNodeName=e.maxNodeName),this.value=0,this.updateFromComponent(a)}updateFromComponent({xAxis:e,yAxis:t,button:o,state:i}){const{normalizedXAxis:a,normalizedYAxis:n}=function(e=0,t=0){let s=e,o=t;if(Math.sqrt(e*e+t*t)>1){const i=Math.atan2(t,e);s=Math.cos(i),o=Math.sin(i)}return{normalizedXAxis:.5*s+.5,normalizedYAxis:.5*o+.5}}(e,t);switch(this.componentProperty){case s.ComponentProperty.X_AXIS:this.value=this.states.includes(i)?a:.5;break;case s.ComponentProperty.Y_AXIS:this.value=this.states.includes(i)?n:.5;break;case s.ComponentProperty.BUTTON:this.value=this.states.includes(i)&&o?o:0;break;case s.ComponentProperty.STATE:this.valueNodeProperty===s.VisualResponseProperty.VISIBILITY?this.value=this.states.includes(i):this.value=this.states.includes(i)?1:0;break;default:throw new Error(`Unexpected visualResponse componentProperty ${this.componentProperty}`)}}}class r{constructor(e,o){if(t.default(this,"id",void 0),t.default(this,"values",void 0),t.default(this,"type",void 0),t.default(this,"gamepadIndices",void 0),t.default(this,"rootNodeName",void 0),t.default(this,"visualResponses",void 0),t.default(this,"touchPointNodeName",void 0),t.default(this,"touchPointNode",void 0),!(e&&o&&o.visualResponses&&o.gamepadIndices&&0!==Object.keys(o.gamepadIndices).length))throw new Error("Invalid arguments supplied");this.id=e,this.type=o.type,this.rootNodeName=o.rootNodeName,this.touchPointNodeName=o.touchPointNodeName,this.visualResponses={},Object.keys(o.visualResponses).forEach((e=>{const t=new n(o.visualResponses[e]);this.visualResponses[e]=t})),this.gamepadIndices=Object.assign({},o.gamepadIndices),this.values={state:s.ComponentState.DEFAULT,button:void 0!==this.gamepadIndices.button?0:void 0,xAxis:void 0!==this.gamepadIndices.xAxis?0:void 0,yAxis:void 0!==this.gamepadIndices.yAxis?0:void 0}}get data(){return{id:this.id,...this.values}}updateFromGamepad(e){if(this.values.state=s.ComponentState.DEFAULT,void 0!==this.gamepadIndices.button&&e.buttons.length>this.gamepadIndices.button){const t=e.buttons[this.gamepadIndices.button];this.values.button=t.value,this.values.button=this.values.button<0?0:this.values.button,this.values.button=this.values.button>1?1:this.values.button,t.pressed||1===this.values.button?this.values.state=s.ComponentState.PRESSED:(t.touched||this.values.button>s.ButtonTouchThreshold)&&(this.values.state=s.ComponentState.TOUCHED)}void 0!==this.gamepadIndices.xAxis&&e.axes.length>this.gamepadIndices.xAxis&&(this.values.xAxis=e.axes[this.gamepadIndices.xAxis],this.values.xAxis=this.values.xAxis<-1?-1:this.values.xAxis,this.values.xAxis=this.values.xAxis>1?1:this.values.xAxis,this.values.state===s.ComponentState.DEFAULT&&Math.abs(this.values.xAxis)>s.AxisTouchThreshold&&(this.values.state=s.ComponentState.TOUCHED)),void 0!==this.gamepadIndices.yAxis&&e.axes.length>this.gamepadIndices.yAxis&&(this.values.yAxis=e.axes[this.gamepadIndices.yAxis],this.values.yAxis=this.values.yAxis<-1?-1:this.values.yAxis,this.values.yAxis=this.values.yAxis>1?1:this.values.yAxis,this.values.state===s.ComponentState.DEFAULT&&Math.abs(this.values.yAxis)>s.AxisTouchThreshold&&(this.values.state=s.ComponentState.TOUCHED)),Object.values(this.visualResponses).forEach((e=>{e.updateFromComponent(this.values)}))}}exports.MotionController=class{constructor(e,s,o){if(t.default(this,"xrInputSource",void 0),t.default(this,"assetUrl",void 0),t.default(this,"layoutDescription",void 0),t.default(this,"id",void 0),t.default(this,"components",void 0),!e)throw new Error("No xrInputSource supplied");if(!s)throw new Error("No profile supplied");if(!s.layouts[e.handedness])throw new Error("No layout for "+e.handedness+" handedness");this.xrInputSource=e,this.assetUrl=o,this.id=s.profileId,this.layoutDescription=s.layouts[e.handedness],this.components={},Object.keys(this.layoutDescription.components).forEach((e=>{const t=this.layoutDescription.components[e];this.components[e]=new r(e,t)})),this.updateFromGamepad()}get gripSpace(){return this.xrInputSource.gripSpace}get targetRaySpace(){return this.xrInputSource.targetRaySpace}get data(){const e=[];return Object.values(this.components).forEach((t=>{e.push(t.data)})),e}updateFromGamepad(){Object.values(this.components).forEach((e=>{e.updateFromGamepad(this.xrInputSource.gamepad)}))}},exports.MotionControllerConstants=s,exports.fetchProfile=async function(e,t,s=null,a=!0){if(!e)throw new Error("No xrInputSource supplied");if(!t)throw new Error("No basePath supplied");const n=await i(t);let r;if(e.profiles.some((e=>{const s=n[e];return s&&(r={profileId:e,profilePath:`${t}/${s.path}`,deprecated:!!s.deprecated}),!!r})),!r){if(!s)throw new Error("No matching profile name found");const e=n[s];if(!e)throw new Error(`No matching profile name found and default profile "${s}" missing.`);r={profileId:s,profilePath:`${t}/${e.path}`,deprecated:!!e.deprecated}}const d=await o(r.profilePath);let u;if(a){let t;if(t="any"===e.handedness?d.layouts[Object.keys(d.layouts)[0]]:d.layouts[e.handedness],!t)throw new Error(`No matching handedness, ${e.handedness}, in profile ${r.profileId}`);t.assetPath&&(u=r.profilePath.replace("profile.json",t.assetPath))}return{profile:d,assetPath:u}},exports.fetchProfilesList=i;
@@ -0,0 +1,132 @@
1
+ import type { Object3D, XRGamepad, XRHandedness, XRInputSource } from 'three';
2
+ interface GamepadIndices {
3
+ button: number;
4
+ xAxis?: number;
5
+ yAxis?: number;
6
+ }
7
+ interface VisualResponseDescription {
8
+ componentProperty: string;
9
+ states: string[];
10
+ valueNodeProperty: string;
11
+ valueNodeName: string;
12
+ minNodeName?: string;
13
+ maxNodeName?: string;
14
+ }
15
+ declare type VisualResponses = Record<string, VisualResponseDescription>;
16
+ interface ComponentDescription {
17
+ type: string;
18
+ gamepadIndices: GamepadIndices;
19
+ rootNodeName: string;
20
+ visualResponses: VisualResponses;
21
+ touchPointNodeName?: string;
22
+ }
23
+ interface Components {
24
+ [componentKey: string]: ComponentDescription;
25
+ }
26
+ interface LayoutDescription {
27
+ selectComponentId: string;
28
+ components: Components;
29
+ gamepadMapping: string;
30
+ rootNodeName: string;
31
+ assetPath: string;
32
+ }
33
+ declare type Layouts = Partial<Record<XRHandedness, LayoutDescription>>;
34
+ export interface Profile {
35
+ profileId: string;
36
+ fallbackProfileIds: string[];
37
+ layouts: Layouts;
38
+ }
39
+ interface ProfilesList {
40
+ [profileId: string]: {
41
+ path: string;
42
+ deprecated?: boolean;
43
+ } | undefined;
44
+ }
45
+ declare const MotionControllerConstants: {
46
+ Handedness: Readonly<{
47
+ NONE: string;
48
+ LEFT: string;
49
+ RIGHT: string;
50
+ }>;
51
+ ComponentState: Readonly<{
52
+ DEFAULT: string;
53
+ TOUCHED: string;
54
+ PRESSED: string;
55
+ }>;
56
+ ComponentProperty: Readonly<{
57
+ BUTTON: string;
58
+ X_AXIS: string;
59
+ Y_AXIS: string;
60
+ STATE: string;
61
+ }>;
62
+ ComponentType: Readonly<{
63
+ TRIGGER: string;
64
+ SQUEEZE: string;
65
+ TOUCHPAD: string;
66
+ THUMBSTICK: string;
67
+ BUTTON: string;
68
+ }>;
69
+ ButtonTouchThreshold: number;
70
+ AxisTouchThreshold: number;
71
+ VisualResponseProperty: Readonly<{
72
+ TRANSFORM: string;
73
+ VISIBILITY: string;
74
+ }>;
75
+ };
76
+ declare function fetchProfilesList(basePath: string): Promise<ProfilesList>;
77
+ declare function fetchProfile(xrInputSource: XRInputSource, basePath: string, defaultProfile?: string | null, getAssetPath?: boolean): Promise<{
78
+ profile: Profile;
79
+ assetPath: string | undefined;
80
+ }>;
81
+ declare class VisualResponse implements VisualResponseDescription {
82
+ value: number | boolean;
83
+ componentProperty: string;
84
+ states: string[];
85
+ valueNodeName: string;
86
+ valueNodeProperty: string;
87
+ minNodeName?: string;
88
+ maxNodeName?: string;
89
+ valueNode: Object3D | undefined;
90
+ minNode: Object3D | undefined;
91
+ maxNode: Object3D | undefined;
92
+ constructor(visualResponseDescription: VisualResponseDescription);
93
+ updateFromComponent({ xAxis, yAxis, button, state, }: {
94
+ xAxis?: number;
95
+ yAxis?: number;
96
+ button?: number;
97
+ state: string;
98
+ }): void;
99
+ }
100
+ declare class Component implements ComponentDescription {
101
+ id: string;
102
+ values: {
103
+ state: string;
104
+ button: number | undefined;
105
+ xAxis: number | undefined;
106
+ yAxis: number | undefined;
107
+ };
108
+ type: string;
109
+ gamepadIndices: GamepadIndices;
110
+ rootNodeName: string;
111
+ visualResponses: Record<string, VisualResponse>;
112
+ touchPointNodeName?: string | undefined;
113
+ touchPointNode?: Object3D;
114
+ constructor(componentId: string, componentDescription: ComponentDescription);
115
+ get data(): {
116
+ id: Component['id'];
117
+ } & Component['values'];
118
+ updateFromGamepad(gamepad: XRGamepad): void;
119
+ }
120
+ declare class MotionController {
121
+ xrInputSource: XRInputSource;
122
+ assetUrl: string;
123
+ layoutDescription: LayoutDescription;
124
+ id: string;
125
+ components: Record<string, Component>;
126
+ constructor(xrInputSource: XRInputSource, profile: Profile, assetUrl: string);
127
+ get gripSpace(): XRInputSource['gripSpace'];
128
+ get targetRaySpace(): XRInputSource['targetRaySpace'];
129
+ get data(): Array<Component['data']>;
130
+ updateFromGamepad(): void;
131
+ }
132
+ export { MotionControllerConstants, MotionController, fetchProfile, fetchProfilesList };
@@ -1,3 +1,5 @@
1
+ import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
2
+
1
3
  /**
2
4
  * @webxr-input-profiles/motion-controllers 1.0.0 https://github.com/immersive-web/webxr-input-profiles
3
5
  */
@@ -69,7 +71,7 @@ async function fetchProfile(xrInputSource, basePath, defaultProfile = null, getA
69
71
 
70
72
  const supportedProfilesList = await fetchProfilesList(basePath); // Find the relative path to the first requested profile that is recognized
71
73
 
72
- let match;
74
+ let match = undefined;
73
75
  xrInputSource.profiles.some(profileId => {
74
76
  const supportedProfile = supportedProfilesList[profileId];
75
77
 
@@ -103,7 +105,7 @@ async function fetchProfile(xrInputSource, basePath, defaultProfile = null, getA
103
105
  }
104
106
 
105
107
  const profile = await fetchJsonFile(match.profilePath);
106
- let assetPath;
108
+ let assetPath = undefined;
107
109
 
108
110
  if (getAssetPath) {
109
111
  let layout;
@@ -142,8 +144,8 @@ const defaultComponentValues = {
142
144
  * API) to the range 0 to 1 (for interpolation). Also caps the X, Y values to be bounded within
143
145
  * a circle. This ensures that thumbsticks are not animated outside the bounds of their physical
144
146
  * range of motion and touchpads do not report touch locations off their physical bounds.
145
- * @param {number} x The original x coordinate in the range -1 to 1
146
- * @param {number} y The original y coordinate in the range -1 to 1
147
+ * @param {number | undefined} x The original x coordinate in the range -1 to 1
148
+ * @param {number | undefined} y The original y coordinate in the range -1 to 1
147
149
  */
148
150
 
149
151
  function normalizeAxes(x = 0, y = 0) {
@@ -179,6 +181,26 @@ function normalizeAxes(x = 0, y = 0) {
179
181
 
180
182
  class VisualResponse {
181
183
  constructor(visualResponseDescription) {
184
+ _defineProperty(this, "value", void 0);
185
+
186
+ _defineProperty(this, "componentProperty", void 0);
187
+
188
+ _defineProperty(this, "states", void 0);
189
+
190
+ _defineProperty(this, "valueNodeName", void 0);
191
+
192
+ _defineProperty(this, "valueNodeProperty", void 0);
193
+
194
+ _defineProperty(this, "minNodeName", void 0);
195
+
196
+ _defineProperty(this, "maxNodeName", void 0);
197
+
198
+ _defineProperty(this, "valueNode", void 0);
199
+
200
+ _defineProperty(this, "minNode", void 0);
201
+
202
+ _defineProperty(this, "maxNode", void 0);
203
+
182
204
  this.componentProperty = visualResponseDescription.componentProperty;
183
205
  this.states = visualResponseDescription.states;
184
206
  this.valueNodeName = visualResponseDescription.valueNodeName;
@@ -196,9 +218,9 @@ class VisualResponse {
196
218
  /**
197
219
  * Computes the visual response's interpolation weight based on component state
198
220
  * @param {Object} componentValues - The component from which to update
199
- * @param {number} xAxis - The reported X axis value of the component
200
- * @param {number} yAxis - The reported Y axis value of the component
201
- * @param {number} button - The reported value of the component's button
221
+ * @param {number | undefined} xAxis - The reported X axis value of the component
222
+ * @param {number | undefined} yAxis - The reported Y axis value of the component
223
+ * @param {number | undefined} button - The reported value of the component's button
202
224
  * @param {string} state - The component's active state
203
225
  */
204
226
 
@@ -224,7 +246,7 @@ class VisualResponse {
224
246
  break;
225
247
 
226
248
  case MotionControllerConstants.ComponentProperty.BUTTON:
227
- this.value = this.states.includes(state) ? button : 0;
249
+ this.value = this.states.includes(state) && button ? button : 0;
228
250
  break;
229
251
 
230
252
  case MotionControllerConstants.ComponentProperty.STATE:
@@ -245,10 +267,26 @@ class VisualResponse {
245
267
 
246
268
  class Component {
247
269
  /**
248
- * @param {Object} componentId - Id of the component
249
- * @param {Object} componentDescription - Description of the component to be created
270
+ * @param {string} componentId - Id of the component
271
+ * @param {InputProfileComponent} componentDescription - Description of the component to be created
250
272
  */
251
273
  constructor(componentId, componentDescription) {
274
+ _defineProperty(this, "id", void 0);
275
+
276
+ _defineProperty(this, "values", void 0);
277
+
278
+ _defineProperty(this, "type", void 0);
279
+
280
+ _defineProperty(this, "gamepadIndices", void 0);
281
+
282
+ _defineProperty(this, "rootNodeName", void 0);
283
+
284
+ _defineProperty(this, "visualResponses", void 0);
285
+
286
+ _defineProperty(this, "touchPointNodeName", void 0);
287
+
288
+ _defineProperty(this, "touchPointNode", void 0);
289
+
252
290
  if (!componentId || !componentDescription || !componentDescription.visualResponses || !componentDescription.gamepadIndices || Object.keys(componentDescription.gamepadIndices).length === 0) {
253
291
  throw new Error('Invalid arguments supplied');
254
292
  }
@@ -341,11 +379,21 @@ class Component {
341
379
 
342
380
  class MotionController {
343
381
  /**
344
- * @param {Object} xrInputSource - The XRInputSource to build the MotionController around
345
- * @param {Object} profile - The best matched profile description for the supplied xrInputSource
346
- * @param {Object} assetUrl
382
+ * @param {XRInputSource} xrInputSource - The XRInputSource to build the MotionController around
383
+ * @param {Profile} profile - The best matched profile description for the supplied xrInputSource
384
+ * @param {string} assetUrl
347
385
  */
348
386
  constructor(xrInputSource, profile, assetUrl) {
387
+ _defineProperty(this, "xrInputSource", void 0);
388
+
389
+ _defineProperty(this, "assetUrl", void 0);
390
+
391
+ _defineProperty(this, "layoutDescription", void 0);
392
+
393
+ _defineProperty(this, "id", void 0);
394
+
395
+ _defineProperty(this, "components", void 0);
396
+
349
397
  if (!xrInputSource) {
350
398
  throw new Error('No xrInputSource supplied');
351
399
  }
@@ -354,6 +402,10 @@ class MotionController {
354
402
  throw new Error('No profile supplied');
355
403
  }
356
404
 
405
+ if (!profile.layouts[xrInputSource.handedness]) {
406
+ throw new Error('No layout for ' + xrInputSource.handedness + ' handedness');
407
+ }
408
+
357
409
  this.xrInputSource = xrInputSource;
358
410
  this.assetUrl = assetUrl;
359
411
  this.id = profile.profileId; // Build child components as described in the profile description
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-stdlib",
3
- "version": "2.20.5",
3
+ "version": "2.21.1",
4
4
  "private": false,
5
5
  "description": "stand-alone library of threejs examples",
6
6
  "main": "index.cjs.js",
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("three"),o=require("../loaders/GLTFLoader.cjs.js"),t=require("../libs/MotionControllers.cjs.js");class n extends e.Object3D{constructor(){super(),this.motionController=null,this.envMap=null}setEnvironmentMap(e){return this.envMap==e||(this.envMap=e,this.traverse((e=>{e.isMesh&&(e.material.envMap=this.envMap,e.material.needsUpdate=!0)}))),this}updateMatrixWorld(e){super.updateMatrixWorld(e),this.motionController&&(this.motionController.updateFromGamepad(),Object.values(this.motionController.components).forEach((e=>{Object.values(e.visualResponses).forEach((e=>{const{valueNode:o,minNode:n,maxNode:r,value:s,valueNodeProperty:a}=e;o&&(a===t.MotionControllerConstants.VisualResponseProperty.VISIBILITY?o.visible=s:a===t.MotionControllerConstants.VisualResponseProperty.TRANSFORM&&(o.quaternion.slerpQuaternions(n.quaternion,r.quaternion,s),o.position.lerpVectors(n.position,r.position,s)))}))})))}}function r(o,n){!function(o,n){Object.values(o.components).forEach((o=>{const{type:r,touchPointNodeName:s,visualResponses:a}=o;if(r===t.MotionControllerConstants.ComponentType.TOUCHPAD)if(o.touchPointNode=n.getObjectByName(s),o.touchPointNode){const t=new e.SphereGeometry(.001),n=new e.MeshBasicMaterial({color:255}),r=new e.Mesh(t,n);o.touchPointNode.add(r)}else console.warn(`Could not find touch dot, ${o.touchPointNodeName}, in touchpad component ${o.id}`);Object.values(a).forEach((e=>{const{valueNodeName:o,minNodeName:r,maxNodeName:s,valueNodeProperty:a}=e;if(a===t.MotionControllerConstants.VisualResponseProperty.TRANSFORM){if(e.minNode=n.getObjectByName(r),e.maxNode=n.getObjectByName(s),!e.minNode)return void console.warn(`Could not find ${r} in the model`);if(!e.maxNode)return void console.warn(`Could not find ${s} in the model`)}e.valueNode=n.getObjectByName(o),e.valueNode||console.warn(`Could not find ${o} in the model`)}))}))}(o.motionController,n),o.envMap&&n.traverse((e=>{e.isMesh&&(e.material.envMap=o.envMap,e.material.needsUpdate=!0)})),o.add(n)}exports.XRControllerModelFactory=class{constructor(e=null){this.gltfLoader=e,this.path="https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles",this._assetCache={},this.gltfLoader||(this.gltfLoader=new o.GLTFLoader)}createControllerModel(e){const o=new n;let s=null;return e.addEventListener("connected",(e=>{const n=e.data;"tracked-pointer"===n.targetRayMode&&n.gamepad&&t.fetchProfile(n,this.path,"generic-trigger").then((({profile:e,assetPath:a})=>{o.motionController=new t.MotionController(n,e,a);const l=this._assetCache[o.motionController.assetUrl];if(l)s=l.scene.clone(),r(o,s);else{if(!this.gltfLoader)throw new Error("GLTFLoader not set.");this.gltfLoader.setPath(""),this.gltfLoader.load(o.motionController.assetUrl,(e=>{this._assetCache[o.motionController.assetUrl]=e,s=e.scene.clone(),r(o,s)}),null,(()=>{throw new Error(`Asset ${o.motionController.assetUrl} missing or malformed.`)}))}})).catch((e=>{console.warn(e)}))})),e.addEventListener("disconnected",(()=>{o.motionController=null,o.remove(s),s=null})),o}};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/defineProperty"),o=require("three"),t=require("../loaders/GLTFLoader.cjs.js"),n=require("../libs/MotionControllers.cjs.js");function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var s=r(e);const a=(e,t)=>{t.traverse((t=>{t instanceof o.Mesh&&"envMap"in t.material&&(t.material.envMap=e,t.material.needsUpdate=!0)}))};class i extends o.Object3D{constructor(){super(),s.default(this,"envMap",void 0),s.default(this,"motionController",void 0),this.motionController=null,this.envMap=null}setEnvironmentMap(e){return this.envMap==e||(this.envMap=e,a(this.envMap,this)),this}updateMatrixWorld(e){super.updateMatrixWorld(e),this.motionController&&(this.motionController.updateFromGamepad(),Object.values(this.motionController.components).forEach((e=>{Object.values(e.visualResponses).forEach((e=>{const{valueNode:o,minNode:t,maxNode:r,value:s,valueNodeProperty:a}=e;o&&(a===n.MotionControllerConstants.VisualResponseProperty.VISIBILITY&&"boolean"==typeof s?o.visible=s:a===n.MotionControllerConstants.VisualResponseProperty.TRANSFORM&&t&&r&&"number"==typeof s&&(o.quaternion.slerpQuaternions(t.quaternion,r.quaternion,s),o.position.lerpVectors(t.position,r.position,s)))}))})))}}function l(e,t){!function(e,t){Object.values(e.components).forEach((e=>{const{type:r,touchPointNodeName:s,visualResponses:a}=e;if(r===n.MotionControllerConstants.ComponentType.TOUCHPAD&&s)if(e.touchPointNode=t.getObjectByName(s),e.touchPointNode){const t=new o.SphereGeometry(.001),n=new o.MeshBasicMaterial({color:255}),r=new o.Mesh(t,n);e.touchPointNode.add(r)}else console.warn(`Could not find touch dot, ${e.touchPointNodeName}, in touchpad component ${e.id}`);Object.values(a).forEach((e=>{const{valueNodeName:o,minNodeName:r,maxNodeName:s,valueNodeProperty:a}=e;if(a===n.MotionControllerConstants.VisualResponseProperty.TRANSFORM&&r&&s){if(e.minNode=t.getObjectByName(r),e.maxNode=t.getObjectByName(s),!e.minNode)return void console.warn(`Could not find ${r} in the model`);if(!e.maxNode)return void console.warn(`Could not find ${s} in the model`)}e.valueNode=t.getObjectByName(o),e.valueNode||console.warn(`Could not find ${o} in the model`)}))}))}(e.motionController,t),e.envMap&&a(e.envMap,t),e.add(t)}exports.XRControllerModelFactory=class{constructor(e=null){s.default(this,"gltfLoader",void 0),s.default(this,"path",void 0),s.default(this,"_assetCache",void 0),this.gltfLoader=e,this.path="https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles",this._assetCache={},this.gltfLoader||(this.gltfLoader=new t.GLTFLoader)}createControllerModel(e){const o=new i;let t=null;const r=e=>{const r=e.data;"tracked-pointer"===r.targetRayMode&&r.gamepad&&n.fetchProfile(r,this.path,"generic-trigger").then((({profile:e,assetPath:s})=>{if(!s)throw new Error("no asset path");o.motionController=new n.MotionController(r,e,s);const a=o.motionController.assetUrl,i=this._assetCache[a];if(i)t=i.scene.clone(),l(o,t);else{if(!this.gltfLoader)throw new Error("GLTFLoader not set.");this.gltfLoader.setPath(""),this.gltfLoader.load(o.motionController.assetUrl,(e=>{o.motionController?(this._assetCache[a]=e,t=e.scene.clone(),l(o,t)):console.warn("motionController gone while gltf load, bailing...")}),null,(()=>{throw new Error(`Asset ${a} missing or malformed.`)}))}})).catch((e=>{console.warn(e)}))};e.addEventListener("connected",r);const s=()=>{e.removeEventListener("connected",r),e.removeEventListener("disconnected",s),o.motionController=null,t&&o.remove(t),t=null};return e.addEventListener("disconnected",s),o}};
@@ -1,19 +1,19 @@
1
- import { Group, Object3D, Texture } from 'three';
2
-
1
+ import { Object3D } from 'three';
2
+ import type { Texture, Group } from 'three';
3
3
  import { GLTFLoader } from '../loaders/GLTFLoader';
4
-
5
- export class XRControllerModel extends Object3D {
4
+ import { MotionController } from '../libs/MotionControllers';
5
+ declare class XRControllerModel extends Object3D {
6
+ envMap: Texture | null;
7
+ motionController: MotionController | null;
6
8
  constructor();
7
-
8
- motionController: any;
9
-
10
9
  setEnvironmentMap(envMap: Texture): XRControllerModel;
10
+ updateMatrixWorld(force: boolean): void;
11
11
  }
12
-
13
- export class XRControllerModelFactory {
14
- constructor(gltfLoader?: GLTFLoader);
15
- gltfLoader: GLTFLoader | null;
12
+ declare class XRControllerModelFactory {
13
+ gltfLoader: GLTFLoader;
16
14
  path: string;
17
-
15
+ private _assetCache;
16
+ constructor(gltfLoader?: GLTFLoader);
18
17
  createControllerModel(controller: Group): XRControllerModel;
19
18
  }
19
+ export { XRControllerModelFactory };
@@ -1,13 +1,28 @@
1
- import { Object3D, SphereGeometry, MeshBasicMaterial, Mesh } from 'three';
1
+ import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
2
+ import { Object3D, Mesh, SphereGeometry, MeshBasicMaterial } from 'three';
2
3
  import { GLTFLoader } from '../loaders/GLTFLoader.js';
3
- import { fetchProfile, MotionController, MotionControllerConstants } from '../libs/MotionControllers.js';
4
+ import { MotionControllerConstants, fetchProfile, MotionController } from '../libs/MotionControllers.js';
4
5
 
5
6
  const DEFAULT_PROFILES_PATH = 'https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles';
6
7
  const DEFAULT_PROFILE = 'generic-trigger';
7
8
 
9
+ const applyEnvironmentMap = (envMap, obj) => {
10
+ obj.traverse(child => {
11
+ if (child instanceof Mesh && 'envMap' in child.material) {
12
+ child.material.envMap = envMap;
13
+ child.material.needsUpdate = true;
14
+ }
15
+ });
16
+ };
17
+
8
18
  class XRControllerModel extends Object3D {
9
19
  constructor() {
10
20
  super();
21
+
22
+ _defineProperty(this, "envMap", void 0);
23
+
24
+ _defineProperty(this, "motionController", void 0);
25
+
11
26
  this.motionController = null;
12
27
  this.envMap = null;
13
28
  }
@@ -18,12 +33,7 @@ class XRControllerModel extends Object3D {
18
33
  }
19
34
 
20
35
  this.envMap = envMap;
21
- this.traverse(child => {
22
- if (child.isMesh) {
23
- child.material.envMap = this.envMap;
24
- child.material.needsUpdate = true;
25
- }
26
- });
36
+ applyEnvironmentMap(this.envMap, this);
27
37
  return this;
28
38
  }
29
39
  /**
@@ -52,9 +62,9 @@ class XRControllerModel extends Object3D {
52
62
 
53
63
  if (!valueNode) return; // Calculate the new properties based on the weight supplied
54
64
 
55
- if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.VISIBILITY) {
65
+ if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.VISIBILITY && typeof value === 'boolean') {
56
66
  valueNode.visible = value;
57
- } else if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM) {
67
+ } else if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM && minNode && maxNode && typeof value === 'number') {
58
68
  valueNode.quaternion.slerpQuaternions(minNode.quaternion, maxNode.quaternion, value);
59
69
  valueNode.position.lerpVectors(minNode.position, maxNode.position, value);
60
70
  }
@@ -79,7 +89,7 @@ function findNodes(motionController, scene) {
79
89
  visualResponses
80
90
  } = component;
81
91
 
82
- if (type === MotionControllerConstants.ComponentType.TOUCHPAD) {
92
+ if (type === MotionControllerConstants.ComponentType.TOUCHPAD && touchPointNodeName) {
83
93
  component.touchPointNode = scene.getObjectByName(touchPointNodeName);
84
94
 
85
95
  if (component.touchPointNode) {
@@ -104,7 +114,7 @@ function findNodes(motionController, scene) {
104
114
  valueNodeProperty
105
115
  } = visualResponse; // If animating a transform, find the two nodes to be interpolated between.
106
116
 
107
- if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM) {
117
+ if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM && minNodeName && maxNodeName) {
108
118
  visualResponse.minNode = scene.getObjectByName(minNodeName);
109
119
  visualResponse.maxNode = scene.getObjectByName(maxNodeName); // If the extents cannot be found, skip this animation
110
120
 
@@ -134,12 +144,7 @@ function addAssetSceneToControllerModel(controllerModel, scene) {
134
144
  findNodes(controllerModel.motionController, scene); // Apply any environment map that the mesh already has set.
135
145
 
136
146
  if (controllerModel.envMap) {
137
- scene.traverse(child => {
138
- if (child.isMesh) {
139
- child.material.envMap = controllerModel.envMap;
140
- child.material.needsUpdate = true;
141
- }
142
- });
147
+ applyEnvironmentMap(controllerModel.envMap, scene);
143
148
  } // Add the glTF scene to the controllerModel.
144
149
 
145
150
 
@@ -148,6 +153,12 @@ function addAssetSceneToControllerModel(controllerModel, scene) {
148
153
 
149
154
  class XRControllerModelFactory {
150
155
  constructor(gltfLoader = null) {
156
+ _defineProperty(this, "gltfLoader", void 0);
157
+
158
+ _defineProperty(this, "path", void 0);
159
+
160
+ _defineProperty(this, "_assetCache", void 0);
161
+
151
162
  this.gltfLoader = gltfLoader;
152
163
  this.path = DEFAULT_PROFILES_PATH;
153
164
  this._assetCache = {}; // If a GLTFLoader wasn't supplied to the constructor create a new one.
@@ -160,15 +171,21 @@ class XRControllerModelFactory {
160
171
  createControllerModel(controller) {
161
172
  const controllerModel = new XRControllerModel();
162
173
  let scene = null;
163
- controller.addEventListener('connected', event => {
174
+
175
+ const onConnected = event => {
164
176
  const xrInputSource = event.data;
165
177
  if (xrInputSource.targetRayMode !== 'tracked-pointer' || !xrInputSource.gamepad) return;
166
178
  fetchProfile(xrInputSource, this.path, DEFAULT_PROFILE).then(({
167
179
  profile,
168
180
  assetPath
169
181
  }) => {
182
+ if (!assetPath) {
183
+ throw new Error('no asset path');
184
+ }
185
+
170
186
  controllerModel.motionController = new MotionController(xrInputSource, profile, assetPath);
171
- const cachedAsset = this._assetCache[controllerModel.motionController.assetUrl];
187
+ const assetUrl = controllerModel.motionController.assetUrl;
188
+ const cachedAsset = this._assetCache[assetUrl];
172
189
 
173
190
  if (cachedAsset) {
174
191
  scene = cachedAsset.scene.clone();
@@ -180,22 +197,38 @@ class XRControllerModelFactory {
180
197
 
181
198
  this.gltfLoader.setPath('');
182
199
  this.gltfLoader.load(controllerModel.motionController.assetUrl, asset => {
183
- this._assetCache[controllerModel.motionController.assetUrl] = asset;
200
+ if (!controllerModel.motionController) {
201
+ console.warn('motionController gone while gltf load, bailing...');
202
+ return;
203
+ }
204
+
205
+ this._assetCache[assetUrl] = asset;
184
206
  scene = asset.scene.clone();
185
207
  addAssetSceneToControllerModel(controllerModel, scene);
186
208
  }, null, () => {
187
- throw new Error(`Asset ${controllerModel.motionController.assetUrl} missing or malformed.`);
209
+ throw new Error(`Asset ${assetUrl} missing or malformed.`);
188
210
  });
189
211
  }
190
212
  }).catch(err => {
191
213
  console.warn(err);
192
214
  });
193
- });
194
- controller.addEventListener('disconnected', () => {
215
+ };
216
+
217
+ controller.addEventListener('connected', onConnected);
218
+
219
+ const onDisconnected = () => {
220
+ controller.removeEventListener('connected', onConnected);
221
+ controller.removeEventListener('disconnected', onDisconnected);
195
222
  controllerModel.motionController = null;
196
- controllerModel.remove(scene);
223
+
224
+ if (scene) {
225
+ controllerModel.remove(scene);
226
+ }
227
+
197
228
  scene = null;
198
- });
229
+ };
230
+
231
+ controller.addEventListener('disconnected', onDisconnected);
199
232
  return controllerModel;
200
233
  }
201
234