@driftengine/script 4.7.4 → 4.8.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.
@@ -37,12 +37,39 @@
37
37
  */
38
38
 
39
39
  import { type CapabilityDefinition, type OpaqueType, defineCapability } from 'driftscript';
40
- import { JOINT_INDEX } from '@driftengine/xr';
40
+ import { type Variant, hostEnum } from './variants.ts';
41
+ import { HAND_JOINTS, JOINT_INDEX } from '@driftengine/xr';
41
42
  import type { ControllerState, HandSkeleton, Handedness, XrSupport } from '@driftengine/xr';
42
43
 
43
44
  export const XR_MODULE = 'drift/xr';
44
45
 
45
- export const XR_TYPES: readonly OpaqueType[] = [];
46
+ /** Which hand, one variant per `Handedness`; `None` is the source a runtime gives no side. */
47
+ const HAND = hostEnum(
48
+ XR_MODULE,
49
+ 'Hand',
50
+ ['Left', 'Right', 'None'],
51
+ 'Which hand: left, right, or the input source with no side.',
52
+ );
53
+ const HANDEDNESS: readonly Handedness[] = ['left', 'right', 'none'];
54
+
55
+ /**
56
+ * A hand joint, one variant per name in `@driftengine/xr`'s `HAND_JOINTS`, in its order:
57
+ * `index-finger-tip` is `IndexFingerTip`. Derived from that list, so a joint the package adds is a
58
+ * variant here with nothing else to change, and a script cannot ask for one it misspelt.
59
+ */
60
+ const HAND_JOINT = hostEnum(
61
+ XR_MODULE,
62
+ 'HandJoint',
63
+ HAND_JOINTS.map((name) =>
64
+ name
65
+ .split('-')
66
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
67
+ .join(''),
68
+ ),
69
+ 'One of the twenty-five joints WebXR tracks on a hand, from the wrist to each fingertip.',
70
+ );
71
+
72
+ export const XR_TYPES: readonly OpaqueType[] = [HAND.type, HAND_JOINT.type];
46
73
 
47
74
  const define = (
48
75
  name: string,
@@ -68,8 +95,8 @@ const define = (
68
95
  implementation,
69
96
  });
70
97
 
71
- /** `left`, `right`, or anything else for the source with no handedness. */
72
- const HAND = { name: 'hand', type: 'String' };
98
+ const HAND_PARAM = { name: 'hand', type: 'Hand' };
99
+ const JOINT_PARAM = { name: 'joint', type: 'HandJoint' };
73
100
 
74
101
  export const XR_CAPABILITIES: readonly CapabilityDefinition[] = [
75
102
  define(
@@ -128,7 +155,7 @@ export const XR_CAPABILITIES: readonly CapabilityDefinition[] = [
128
155
  ),
129
156
  define(
130
157
  'trigger',
131
- [HAND],
158
+ [HAND_PARAM],
132
159
  'f32',
133
160
  ['input.read'],
134
161
  'How far a hand’s trigger is pulled, 0 to 1. Zero for a hand that is not there.',
@@ -136,7 +163,7 @@ export const XR_CAPABILITIES: readonly CapabilityDefinition[] = [
136
163
  ),
137
164
  define(
138
165
  'squeeze',
139
- [HAND],
166
+ [HAND_PARAM],
140
167
  'f32',
141
168
  ['input.read'],
142
169
  'How far a hand’s grip is squeezed, 0 to 1. Zero for a hand that is not there.',
@@ -144,7 +171,7 @@ export const XR_CAPABILITIES: readonly CapabilityDefinition[] = [
144
171
  ),
145
172
  define(
146
173
  'holding',
147
- [HAND],
174
+ [HAND_PARAM],
148
175
  'bool',
149
176
  ['input.read'],
150
177
  'Whether a hand is tracked this frame. False while a controller is set down or out of view.',
@@ -159,31 +186,31 @@ export const XR_CAPABILITIES: readonly CapabilityDefinition[] = [
159
186
  */
160
187
  define(
161
188
  'jointX',
162
- [HAND, { name: 'joint', type: 'String' }],
189
+ [HAND_PARAM, JOINT_PARAM],
163
190
  'f32',
164
191
  ['input.read'],
165
- 'Where a named hand joint is, in metres. Zero for a joint that is not tracked.',
192
+ 'Where a hand joint is, in metres. Zero for a joint that is not tracked.',
166
193
  'XrRuntime.jointX',
167
194
  ),
168
195
  define(
169
196
  'jointY',
170
- [HAND, { name: 'joint', type: 'String' }],
197
+ [HAND_PARAM, JOINT_PARAM],
171
198
  'f32',
172
199
  ['input.read'],
173
- 'Where a named hand joint is, in metres. Zero for a joint that is not tracked.',
200
+ 'Where a hand joint is, in metres. Zero for a joint that is not tracked.',
174
201
  'XrRuntime.jointY',
175
202
  ),
176
203
  define(
177
204
  'jointZ',
178
- [HAND, { name: 'joint', type: 'String' }],
205
+ [HAND_PARAM, JOINT_PARAM],
179
206
  'f32',
180
207
  ['input.read'],
181
- 'Where a named hand joint is, in metres. Zero for a joint that is not tracked.',
208
+ 'Where a hand joint is, in metres. Zero for a joint that is not tracked.',
182
209
  'XrRuntime.jointZ',
183
210
  ),
184
211
  define(
185
212
  'pinching',
186
- [HAND],
213
+ [HAND_PARAM],
187
214
  'bool',
188
215
  ['input.read'],
189
216
  'Whether a hand’s thumb and index tips are close enough to count as a pinch.',
@@ -208,8 +235,8 @@ export interface XrRuntime {
208
235
  /** How close two fingertips count as a pinch, in metres. */
209
236
  const PINCH_METRES = 0.025;
210
237
 
211
- function handOf(value: string): Handedness {
212
- return value === 'left' ? 'left' : value === 'right' ? 'right' : 'none';
238
+ function handOf(hand: Variant): Handedness {
239
+ return HANDEDNESS[HAND.code(hand)] ?? 'none';
213
240
  }
214
241
 
215
242
  export function xrImplementation(runtime: XrRuntime): Readonly<Record<string, unknown>> {
@@ -218,13 +245,13 @@ export function xrImplementation(runtime: XrRuntime): Readonly<Record<string, un
218
245
 
219
246
  const head = (axis: number): number => runtime.headPosition?.[axis] ?? 0;
220
247
 
221
- const joint = (hand: string, name: string, axis: number): number => {
248
+ const joint = (hand: Variant, name: Variant, axis: number): number => {
222
249
  const skeleton = runtime.hand(handOf(hand));
223
250
  if (skeleton === null) return 0;
224
251
  /* The flat arrays the package already fills are read directly. `jointPosition` would answer the
225
252
  same question through a `Float32Array` this would then have to unpack, three times per joint
226
253
  per frame. */
227
- const index = jointIndexOf(name);
254
+ const index = HAND_JOINT.code(name);
228
255
  if (index < 0 || skeleton.tracked[index] !== 1) return 0;
229
256
  return skeleton.matrices[index * 16 + 12 + axis] ?? 0;
230
257
  };
@@ -236,13 +263,13 @@ export function xrImplementation(runtime: XrRuntime): Readonly<Record<string, un
236
263
  headX: (): number => head(0),
237
264
  headY: (): number => head(1),
238
265
  headZ: (): number => head(2),
239
- trigger: (hand: string): number => runtime.controller(handOf(hand))?.buttons[0] ?? 0,
240
- squeeze: (hand: string): number => runtime.controller(handOf(hand))?.buttons[1] ?? 0,
241
- holding: (hand: string): boolean => runtime.controller(handOf(hand))?.tracked ?? false,
242
- jointX: (hand: string, name: string): number => joint(hand, name, 0),
243
- jointY: (hand: string, name: string): number => joint(hand, name, 1),
244
- jointZ: (hand: string, name: string): number => joint(hand, name, 2),
245
- pinching: (hand: string): boolean => {
266
+ trigger: (hand: Variant): number => runtime.controller(handOf(hand))?.buttons[0] ?? 0,
267
+ squeeze: (hand: Variant): number => runtime.controller(handOf(hand))?.buttons[1] ?? 0,
268
+ holding: (hand: Variant): boolean => runtime.controller(handOf(hand))?.tracked ?? false,
269
+ jointX: (hand: Variant, name: Variant): number => joint(hand, name, 0),
270
+ jointY: (hand: Variant, name: Variant): number => joint(hand, name, 1),
271
+ jointZ: (hand: Variant, name: Variant): number => joint(hand, name, 2),
272
+ pinching: (hand: Variant): boolean => {
246
273
  const skeleton = runtime.hand(handOf(hand));
247
274
  if (skeleton === null) return false;
248
275
  const thumb = jointIndexOf('thumb-tip');