@realitycollective/iwsdk-interactions 0.1.0-preview.2 → 0.1.0-preview.3
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/CHANGELOG.md +14 -3
- package/dist/provider.d.ts +22 -16
- package/dist/provider.js +44 -13
- package/dist/provider.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -13,20 +13,31 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
|
13
13
|
- `@realitycollective/iwsdk-interactions` - Meta IWSDK adapter: player-rig poses and stateful gamepads as the provider, IWSDK's own targeting (`Pressed` / `Grabbed` tags) forwarded as pre-resolved hints, and native grab fulfilment when the app enables IWSDK grabbing/physics. One-call `registerInteractions(world)` setup.
|
|
14
14
|
- `@realitycollective/xrblocks-interactions` - EXPERIMENTAL Google XR Blocks adapter, structurally typed against xrblocks v0.20.0 (`Input.getFrame()` ray sources and direct touches, pooled structs copied, no haptics upstream).
|
|
15
15
|
- `demos/playground` - the standalone interaction playground: the full station set from one portable `InteractionDescriptor`, with client-side audio cues, opt-in controller haptics and client-side toss ballistics.
|
|
16
|
-
- `@realitycollective/webxr-interactions` - per-source velocity. `VelocityTracker` differentiates the grip poses the runtime already samples into linear and angular velocity, and the runtime runs one by default (`velocity: false` turns it off, `{ smoothing }` averages it). A source on its first frame, or one that reappears after dropping out, reports no velocity rather than a jump from its last known pose, and a provider that supplies its own velocity keeps it. Read it from `runtime.onSample(...)` or `runtime.getSource(id)`. `
|
|
16
|
+
- `@realitycollective/webxr-interactions` - per-source velocity. `VelocityTracker` differentiates the grip poses the runtime already samples into linear and angular velocity, and the runtime runs one by default (`velocity: false` turns it off, `{ smoothing }` averages it). A source on its first frame, or one that reappears after dropping out, reports no velocity rather than a jump from its last known pose, and a provider that supplies its own velocity keeps it. Read it from `runtime.onSample(...)` or `runtime.getSource(id)`. The differentiation itself is `velocityBetween` from `@realitycollective/webxr-input`, re-exported here; `clampDeadzone` joins the math helpers.
|
|
17
17
|
- `@realitycollective/webxr-interactions` - `routeAudioToSink`, the audio counterpart to `routeHapticsToProvider`: an opt-in that plays the cues named in a map through a client-supplied sink. Cues absent from the map are ignored, so an app sonifies only the moments it has sounds for.
|
|
18
|
-
- `@realitycollective/iwsdk-interactions` and `@realitycollective/threejs-interactions` - presence control. `setPresenceVisible(target, visible)` shows and hides the hand and controller visuals per side; the IWSDK adapter adds `setPresenceModality(mode)` to force hands or controllers over the automatic choice, and the three.js adapter takes the app's own models through `registerVisual(handedness, root)`.
|
|
18
|
+
- `@realitycollective/iwsdk-interactions` and `@realitycollective/threejs-interactions` - presence control. `setPresenceVisible(target, visible)` shows and hides the hand and controller visuals per side; the IWSDK adapter adds `setPresenceModality(mode)` to force hands or controllers over the automatic choice, and the three.js adapter takes the app's own models through `registerVisual(handedness, root)`. Every provider reports whether it can do this through `capabilities.presence`; the XR Blocks adapter reports false, since XR Blocks exposes no way to hide its visuals.
|
|
19
19
|
- `@realitycollective/threejs-interactions` - native WebXR pose velocity. Where the browser reports `linearVelocity` or `angularVelocity` with a grip pose (or with the wrist joint a hand falls back to), the provider passes it through on the snapshot and the core's tracker leaves it alone; where it does not, the tracker derives velocity from consecutive poses as before. The desktop mouse source synthesises nothing: its grip rides the camera ray, so the derived velocity is camera motion, and hand mechanics should be gated on `handedness !== "none"`.
|
|
20
20
|
- `@realitycollective/babylon-interactions` - a Babylon.js adapter, the fourth engine. It reads a `WebXRDefaultExperience` (controllers, motion controller trigger and squeeze, hand-tracking joints, session manager) for input, with `scene.onPointerObservable` as the desktop fallback, haptics through the motion controller's `pulse`, and presence over the visuals Babylon builds - motion controller root meshes and hand meshes. Babylon picks the visual per input source, so there is no modality switch. Hit-testing is a sphere test over registered nodes, with an optional `pickWithRay` hook for mesh-accurate targeting; the transform port moves, rotates and scales Babylon nodes from rest. Structurally typed against the Babylon API rather than importing `@babylonjs/core`, as the XR Blocks adapter is, so an upstream release cannot break the install - and so the whole adapter is covered headlessly by structural fakes. Written against the documented Babylon 7 API and not yet exercised against a real Babylon runtime.
|
|
21
|
-
- Tests for `@realitycollective/iwsdk-interactions`, which had none. `@iwsdk/core` imports headlessly in node, so the provider is covered against a structural fake world with no module mocking, and a parity suite instantiates all
|
|
21
|
+
- Tests for `@realitycollective/iwsdk-interactions`, which had none. `@iwsdk/core` imports headlessly in node, so the provider is covered against a structural fake world with no module mocking, and a parity suite instantiates all four providers and runs the shared contract suite against each one. The package's coverage ratchet moves off zero, and the other three ratchets rise to the floor they now measure.
|
|
22
22
|
|
|
23
23
|
### Changed
|
|
24
24
|
|
|
25
|
+
- Every provider reports presence through `capabilities.presence`, the required key `@realitycollective/webxr-input` 0.1.1 adds to `InputCapabilities`. The class-level `supportsPresence` field the four adapters carried while that key was unpublished is gone. This fixes a client-visible defect on the IWSDK adapter, which built its capabilities without a `presence` key at all: an app that read `capabilities.presence` saw false and hid a feature that worked. The value each provider reports is the one its own field computed - always true on IWSDK, true once Babylon has built a visual to hide, true on three.js once a model is registered, and always false on XR Blocks.
|
|
26
|
+
- `@realitycollective/threejs-interactions` - `registerVisual` and the new `unregisterVisual` now re-derive capabilities and notify `onCapabilitiesChanged`. Presence on this adapter is genuinely conditional: your app builds its own hand and controller models, so `capabilities.presence` is false until you hand the first one over and false again once you take the last one back.
|
|
27
|
+
- The Input 0.1.1 types replace the local stand-ins that were waiting on them. `InputSourceSnapshot` now carries `linearVelocity` and `angularVelocity` itself, so the `InputSourceSnapshotWithVelocity` alias is gone; the local `poseVelocity` is gone in favour of the shipped `velocityBetween`; and the per-adapter `PresenceTarget` and `PresenceModality` declarations are gone. `PresenceModality` now comes from the contracts, and a presence target is written as the contract writes it, `Handedness | "all"`. All three names were re-exported from these packages and are removed from that surface.
|
|
28
|
+
- Every package now requires `@realitycollective/webxr-input` at `^0.1.1` rather than `^0.1.0`, because the code above uses members that only exist from 0.1.1. A fresh install resolved to 0.1.1 either way; the range says so now, so a consumer holding an older lockfile fails at install rather than at run time.
|
|
29
|
+
- The provider parity suite is now three lines over `inputProviderContractCases()` from `@realitycollective/webxr-input`, run against all four adapters, instead of a hand-written copy of the same checks. The shared cases are stricter: they assert the capability record has exactly the contract's keys and that every snapshot is well formed. Two adapter-specific checks stay on top of them.
|
|
30
|
+
- `@realitycollective/iwsdk-interactions` - `setPresenceVisible` and `setPresenceModality` write nothing when nothing changed. The provider holds what it last applied per side - visibility, modality and the hand-tracking capability presence is derived from - and skips a side whose three inputs are unchanged. An app pushing presence from a state subscription, which is the documented pattern, no longer walks every descendant of both visual families on every unrelated state change. The per-frame re-apply during `sample()` stays unconditional, because IWSDK re-asserts its own visuals from its update loop and a capability refresh can change the modality underneath the adapter.
|
|
31
|
+
|
|
25
32
|
- `@realitycollective/iwsdk-interactions` - `pulse` resolves the side from the handedness recorded while sampling, rather than parsing the source id. Parsing the id remains the fallback for an id the provider did not produce.
|
|
26
33
|
|
|
27
34
|
- `@realitycollective/iwsdk-interactions` targets **IWSDK 0.5.x**. Its peer range is now `>=0.5.0 <0.6.0` and it is developed and tested against `@iwsdk/core` 0.5.3. The adapter is source-compatible with 0.4.x and needed no code change, but 0.5 is the only line exercised, so it is the only line supported. Every symbol and runtime member the provider uses is present in both, and it already reads `world.input.xr.gamepads` rather than the accessor 0.5 deprecates.
|
|
28
35
|
- `demos/playground` no longer compiles UIKitML at build time. `@iwsdk/vite-plugin-uikitml` was discontinued at 0.4.2 and only ever did `JSON.stringify(parse(source))`, so the panel is served as `.uikitml` from `public/ui/` and parsed on load. The demo drops that plugin, and its station markup uses `rgba()` rather than `background-opacity`, which the 0.5 parser removed.
|
|
29
36
|
|
|
37
|
+
### Deprecated
|
|
38
|
+
|
|
39
|
+
- `@realitycollective/webxr-interactions` - `InteractionRuntime.onSourcesSampled` is deprecated in favour of `onSample`. They are the same stream, and since `InputSourceSnapshot` carries the velocity fields itself the two signatures are now identical, so only one name is needed. Nothing is removed: existing callers keep working and the method will go in a later major release.
|
|
40
|
+
|
|
30
41
|
### Notes
|
|
31
42
|
|
|
32
43
|
- All five packages depend on `@realitycollective/webxr-input`, released independently from the [WebXR-Input](https://github.com/realitycollective/WebXR-Input) repository. That package must be published before this one.
|
package/dist/provider.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* core consumes IN PLACE of its own hit-testing.
|
|
15
15
|
*/
|
|
16
16
|
import { type World } from "@iwsdk/core";
|
|
17
|
-
import { type HeadPose, type InputCapabilities, type InputHitHint, type InputProvider, type InputSourceSnapshot, type Unsubscribe } from "@realitycollective/webxr-input";
|
|
17
|
+
import { type Handedness, type HeadPose, type InputCapabilities, type InputHitHint, type InputProvider, type InputSourceSnapshot, type PresenceModality, type Unsubscribe } from "@realitycollective/webxr-input";
|
|
18
18
|
export interface IWSDKProviderOptions {
|
|
19
19
|
/**
|
|
20
20
|
* The app enabled IWSDK's `features.grabbing` (+ physics where needed),
|
|
@@ -23,20 +23,7 @@ export interface IWSDKProviderOptions {
|
|
|
23
23
|
nativeGrab?: boolean;
|
|
24
24
|
}
|
|
25
25
|
type Side = "left" | "right";
|
|
26
|
-
/** Which side's visuals a presence call targets. `"all"` is both. */
|
|
27
|
-
export type PresenceTarget = "left" | "right" | "none" | "all";
|
|
28
|
-
/**
|
|
29
|
-
* Which family of visuals presence shows. `"auto"` follows the engine:
|
|
30
|
-
* hand visuals while hand tracking is live, controller visuals otherwise.
|
|
31
|
-
*/
|
|
32
|
-
export type PresenceModality = "hands" | "controllers" | "auto";
|
|
33
26
|
export declare class IWSDKInputProvider implements InputProvider {
|
|
34
|
-
/**
|
|
35
|
-
* This provider can show and hide the controller/hand visuals.
|
|
36
|
-
* Becomes `capabilities.presence` at
|
|
37
|
-
* `@realitycollective/webxr-input` 0.1.1.
|
|
38
|
-
*/
|
|
39
|
-
readonly supportsPresence = true;
|
|
40
27
|
private readonly world;
|
|
41
28
|
private readonly nativeGrab;
|
|
42
29
|
private capabilities;
|
|
@@ -47,6 +34,8 @@ export declare class IWSDKInputProvider implements InputProvider {
|
|
|
47
34
|
/** Snapshot id -> side, filled by `sample()` so `pulse` need not parse ids. */
|
|
48
35
|
private readonly sideBySourceId;
|
|
49
36
|
private readonly presenceVisible;
|
|
37
|
+
/** What was last written per side, so an unchanged call writes nothing. */
|
|
38
|
+
private readonly presenceApplied;
|
|
50
39
|
private presenceModality;
|
|
51
40
|
/** Presence is only re-applied once a client has actually asked for it. */
|
|
52
41
|
private presenceRequested;
|
|
@@ -74,15 +63,32 @@ export declare class IWSDKInputProvider implements InputProvider {
|
|
|
74
63
|
*
|
|
75
64
|
* `"none"` targets no side - the handedness value that has no visual
|
|
76
65
|
* here - so the call reports availability without changing anything.
|
|
66
|
+
*
|
|
67
|
+
* A call that asks for what is already applied writes nothing, so an app
|
|
68
|
+
* that pushes presence from a state subscription costs nothing on the
|
|
69
|
+
* state changes that did not touch presence.
|
|
77
70
|
*/
|
|
78
|
-
setPresenceVisible(target:
|
|
71
|
+
setPresenceVisible(target: Handedness | "all", visible: boolean): boolean;
|
|
79
72
|
/**
|
|
80
73
|
* Choose which family of visuals is shown. `"hands"` and `"controllers"`
|
|
81
74
|
* force one family and hide the other; `"auto"` follows the engine's own
|
|
82
|
-
* modality (hand visuals while hand tracking is live).
|
|
75
|
+
* modality (hand visuals while hand tracking is live). A repeat of the
|
|
76
|
+
* current modality writes nothing.
|
|
83
77
|
*/
|
|
84
78
|
setPresenceModality(mode: PresenceModality): boolean;
|
|
85
79
|
private visualAdapters;
|
|
80
|
+
/**
|
|
81
|
+
* Write the desired presence into IWSDK's visuals.
|
|
82
|
+
*
|
|
83
|
+
* Each side is skipped when the three inputs presence depends on - the
|
|
84
|
+
* side's visibility, the modality and the hand-tracking capability - are
|
|
85
|
+
* all unchanged since the last write. Walking every descendant of both
|
|
86
|
+
* visual families is not free, and an app pushing presence from a state
|
|
87
|
+
* subscription calls this on every unrelated state change.
|
|
88
|
+
*
|
|
89
|
+
* `force` skips the diff, for the per-frame re-apply that has to win
|
|
90
|
+
* against IWSDK's own writes.
|
|
91
|
+
*/
|
|
86
92
|
private applyPresence;
|
|
87
93
|
getHeadPose(): HeadPose;
|
|
88
94
|
pulse(sourceId: string, intensity: number, durationMs: number): boolean;
|
package/dist/provider.js
CHANGED
|
@@ -41,12 +41,6 @@ function setDescendantsVisible(adapter, visible) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
export class IWSDKInputProvider {
|
|
44
|
-
/**
|
|
45
|
-
* This provider can show and hide the controller/hand visuals.
|
|
46
|
-
* Becomes `capabilities.presence` at
|
|
47
|
-
* `@realitycollective/webxr-input` 0.1.1.
|
|
48
|
-
*/
|
|
49
|
-
supportsPresence = true;
|
|
50
44
|
world;
|
|
51
45
|
nativeGrab;
|
|
52
46
|
capabilities;
|
|
@@ -57,6 +51,11 @@ export class IWSDKInputProvider {
|
|
|
57
51
|
/** Snapshot id -> side, filled by `sample()` so `pulse` need not parse ids. */
|
|
58
52
|
sideBySourceId = new Map();
|
|
59
53
|
presenceVisible = { left: true, right: true };
|
|
54
|
+
/** What was last written per side, so an unchanged call writes nothing. */
|
|
55
|
+
presenceApplied = {
|
|
56
|
+
left: null,
|
|
57
|
+
right: null,
|
|
58
|
+
};
|
|
60
59
|
presenceModality = "auto";
|
|
61
60
|
/** Presence is only re-applied once a client has actually asked for it. */
|
|
62
61
|
presenceRequested = false;
|
|
@@ -123,6 +122,9 @@ export class IWSDKInputProvider {
|
|
|
123
122
|
gaze: true,
|
|
124
123
|
headPose: true,
|
|
125
124
|
haptics,
|
|
125
|
+
// IWSDK builds and owns both visual families, so presence is always
|
|
126
|
+
// available - `applyPresence` only needs the adapters to have appeared.
|
|
127
|
+
presence: true,
|
|
126
128
|
};
|
|
127
129
|
if (JSON.stringify(next) !== JSON.stringify(this.capabilities)) {
|
|
128
130
|
this.capabilities = next;
|
|
@@ -156,8 +158,11 @@ export class IWSDKInputProvider {
|
|
|
156
158
|
this.sideBySourceId.clear();
|
|
157
159
|
// Adapters are created as input sources connect, which can be after the
|
|
158
160
|
// client set its presence, so the desired state is re-applied here.
|
|
161
|
+
// Unconditionally: `@iwsdk/xr-input` re-asserts the visuals from its own
|
|
162
|
+
// per-frame update, and a capability refresh can change the modality
|
|
163
|
+
// underneath us, so the desired state has to be pushed again.
|
|
159
164
|
if (this.presenceRequested)
|
|
160
|
-
this.applyPresence();
|
|
165
|
+
this.applyPresence(true);
|
|
161
166
|
if (!this.world.session)
|
|
162
167
|
return [];
|
|
163
168
|
if (this.world.visibilityState.peek() !== VisibilityState.Visible)
|
|
@@ -222,6 +227,10 @@ export class IWSDKInputProvider {
|
|
|
222
227
|
*
|
|
223
228
|
* `"none"` targets no side - the handedness value that has no visual
|
|
224
229
|
* here - so the call reports availability without changing anything.
|
|
230
|
+
*
|
|
231
|
+
* A call that asks for what is already applied writes nothing, so an app
|
|
232
|
+
* that pushes presence from a state subscription costs nothing on the
|
|
233
|
+
* state changes that did not touch presence.
|
|
225
234
|
*/
|
|
226
235
|
setPresenceVisible(target, visible) {
|
|
227
236
|
this.presenceRequested = true;
|
|
@@ -234,7 +243,8 @@ export class IWSDKInputProvider {
|
|
|
234
243
|
/**
|
|
235
244
|
* Choose which family of visuals is shown. `"hands"` and `"controllers"`
|
|
236
245
|
* force one family and hide the other; `"auto"` follows the engine's own
|
|
237
|
-
* modality (hand visuals while hand tracking is live).
|
|
246
|
+
* modality (hand visuals while hand tracking is live). A repeat of the
|
|
247
|
+
* current modality writes nothing.
|
|
238
248
|
*/
|
|
239
249
|
setPresenceModality(mode) {
|
|
240
250
|
this.presenceRequested = true;
|
|
@@ -245,18 +255,39 @@ export class IWSDKInputProvider {
|
|
|
245
255
|
const xr = this.world.input?.xr;
|
|
246
256
|
return xr?.visualAdapters ?? null;
|
|
247
257
|
}
|
|
248
|
-
|
|
258
|
+
/**
|
|
259
|
+
* Write the desired presence into IWSDK's visuals.
|
|
260
|
+
*
|
|
261
|
+
* Each side is skipped when the three inputs presence depends on - the
|
|
262
|
+
* side's visibility, the modality and the hand-tracking capability - are
|
|
263
|
+
* all unchanged since the last write. Walking every descendant of both
|
|
264
|
+
* visual families is not free, and an app pushing presence from a state
|
|
265
|
+
* subscription calls this on every unrelated state change.
|
|
266
|
+
*
|
|
267
|
+
* `force` skips the diff, for the per-frame re-apply that has to win
|
|
268
|
+
* against IWSDK's own writes.
|
|
269
|
+
*/
|
|
270
|
+
applyPresence(force = false) {
|
|
249
271
|
const adapters = this.visualAdapters();
|
|
250
272
|
if (!adapters)
|
|
251
273
|
return false;
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
const
|
|
255
|
-
|
|
274
|
+
const handJoints = this.capabilities.handJoints;
|
|
275
|
+
const modality = this.presenceModality;
|
|
276
|
+
const hands = modality === "hands" || (modality === "auto" && handJoints);
|
|
277
|
+
const controllers = modality === "controllers" || (modality === "auto" && !handJoints);
|
|
256
278
|
for (const side of SIDES) {
|
|
257
279
|
const wanted = this.presenceVisible[side];
|
|
280
|
+
const last = this.presenceApplied[side];
|
|
281
|
+
if (!force &&
|
|
282
|
+
last !== null &&
|
|
283
|
+
last.visible === wanted &&
|
|
284
|
+
last.modality === modality &&
|
|
285
|
+
last.handJoints === handJoints) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
258
288
|
setDescendantsVisible(adapters.hand?.[side], wanted && hands);
|
|
259
289
|
setDescendantsVisible(adapters.controller?.[side], wanted && controllers);
|
|
290
|
+
this.presenceApplied[side] = { visible: wanted, modality, handJoints };
|
|
260
291
|
}
|
|
261
292
|
return true;
|
|
262
293
|
}
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * IWSDKInputProvider - feeds Meta IWSDK's input machinery into the shared\n * input contracts, in place of the standalone WebXR provider.\n *\n * Poses come from the IWSDK player rig (`world.playerSpaceEntities`:\n * ray/grip/index-tip spaces, head), signals from the stateful XR gamepads\n * (`world.input.xr.gamepads` - analog trigger/squeeze with `getSelecting`\n * fallback, which also covers hand pinch). Capabilities derive from the\n * LIVE session and re-publish on visibility/input-source changes.\n *\n * Provider power: IWSDK resolves its own targeting (BVH raycasts →\n * `Pressed`/`Grabbed` tags). The bridge system turns those tags into\n * pre-resolved hints (`setHints`) and flags native grabbing, which the\n * core consumes IN PLACE of its own hit-testing.\n */\nimport { InputComponent, VisibilityState, type World } from \"@iwsdk/core\";\nimport {\n NO_CAPABILITIES,\n type HeadPose,\n type InputCapabilities,\n type InputHitHint,\n type InputProvider,\n type InputSourceSnapshot,\n type Unsubscribe,\n} from \"@realitycollective/webxr-input\";\n\nexport interface IWSDKProviderOptions {\n /**\n * The app enabled IWSDK's `features.grabbing` (+ physics where needed),\n * so grab behaviours are fulfilled NATIVELY by the engine.\n */\n nativeGrab?: boolean;\n}\n\ntype Side = \"left\" | \"right\";\nconst SIDES: readonly Side[] = [\"left\", \"right\"];\n\n/** Which side's visuals a presence call targets. `\"all\"` is both. */\nexport type PresenceTarget = \"left\" | \"right\" | \"none\" | \"all\";\n\n/**\n * Which family of visuals presence shows. `\"auto\"` follows the engine:\n * hand visuals while hand tracking is live, controller visuals otherwise.\n */\nexport type PresenceModality = \"hands\" | \"controllers\" | \"auto\";\n\n/**\n * Structural slice of `world.input.xr.visualAdapters`. Only two fields are\n * needed and the real typings drag the whole `@iwsdk/xr-input` visual\n * stack in for them, so the shape is declared here. A per-side adapter,\n * and its `visual`, are both absent until that input source connects.\n */\ninterface PresenceObjectLike {\n visible: boolean;\n children?: readonly PresenceObjectLike[];\n}\n\ninterface PresenceAdapterLike {\n visual?: { model?: PresenceObjectLike } | undefined;\n}\n\ninterface PresenceAdaptersLike {\n controller?: Partial<Record<Side, PresenceAdapterLike | undefined>> | undefined;\n hand?: Partial<Record<Side, PresenceAdapterLike | undefined>> | undefined;\n}\n\n/**\n * Show or hide a visual by walking its DESCENDANTS rather than setting\n * `visible` on the root.\n *\n * Verified against `@iwsdk/xr-input` 0.5.3 (`dist/xr-input-manager.js`, the\n * per-frame update): IWSDK writes `visualAdapter.visual.model.visible =\n * inputSourceData.isPrimary` every frame, so a root-level write is undone\n * before it is drawn. The engine never touches the descendants, so hiding\n * them is the write that sticks, independent of system ordering.\n */\nfunction setDescendantsVisible(adapter: PresenceAdapterLike | undefined, visible: boolean): void {\n const model = adapter?.visual?.model;\n if (!model) return;\n const stack: PresenceObjectLike[] = [...(model.children ?? [])];\n while (stack.length > 0) {\n const node = stack.pop();\n if (!node) continue;\n node.visible = visible;\n for (const child of node.children ?? []) stack.push(child);\n }\n}\n\nexport class IWSDKInputProvider implements InputProvider {\n /**\n * This provider can show and hide the controller/hand visuals.\n * Becomes `capabilities.presence` at\n * `@realitycollective/webxr-input` 0.1.1.\n */\n readonly supportsPresence = true;\n\n private readonly world: World;\n private readonly nativeGrab: boolean;\n private capabilities: InputCapabilities;\n private readonly capsListeners = new Set<(c: InputCapabilities) => void>();\n private readonly sourceListeners = new Set<() => void>();\n private hints: InputHitHint[] = [];\n private readonly nativeGrabbing: Record<Side, boolean> = { left: false, right: false };\n /** Snapshot id -> side, filled by `sample()` so `pulse` need not parse ids. */\n private readonly sideBySourceId = new Map<string, Side>();\n private readonly presenceVisible: Record<Side, boolean> = { left: true, right: true };\n private presenceModality: PresenceModality = \"auto\";\n /** Presence is only re-applied once a client has actually asked for it. */\n private presenceRequested = false;\n private readonly disposers: Unsubscribe[] = [];\n private boundSession: XRSession | null = null;\n private readonly onSourcesChange = () => {\n this.refreshCapabilities();\n for (const listener of [...this.sourceListeners]) listener();\n };\n\n constructor(world: World, options: IWSDKProviderOptions = {}) {\n this.world = world;\n this.nativeGrab = options.nativeGrab ?? false;\n this.capabilities = { ...NO_CAPABILITIES };\n const unsubscribe = world.visibilityState.subscribe(() => {\n this.bindSession();\n this.refreshCapabilities();\n });\n this.disposers.push(unsubscribe);\n this.bindSession();\n this.refreshCapabilities();\n }\n\n private bindSession(): void {\n const session = this.world.session ?? null;\n if (session === this.boundSession) return;\n this.boundSession?.removeEventListener(\"inputsourceschange\", this.onSourcesChange);\n this.boundSession = session;\n session?.addEventListener(\"inputsourceschange\", this.onSourcesChange);\n }\n\n private hasTrackedHand(): boolean {\n const session = this.world.session;\n if (!session) return false;\n for (const source of session.inputSources) {\n if (source.hand) return true;\n }\n return false;\n }\n\n private refreshCapabilities(): void {\n const session = this.world.session;\n const immersive = !!session;\n const handTracking =\n immersive &&\n ((session?.enabledFeatures?.includes(\"hand-tracking\") ?? false) || this.hasTrackedHand());\n let buttonsAxes = false;\n let haptics = false;\n for (const side of SIDES) {\n const gamepad = this.world.input.xr.gamepads[side];\n if (gamepad?.gamepad) buttonsAxes = true;\n if ((gamepad?.gamepad?.hapticActuators?.length ?? 0) > 0) haptics = true;\n }\n const next: InputCapabilities = {\n ...NO_CAPABILITIES,\n rays: immersive,\n // Index-tip spaces exist for controllers too (fall back to ray pose).\n pokes: immersive,\n grabs: immersive ? (this.nativeGrab ? \"native\" : \"poseOnly\") : \"none\",\n handJoints: handTracking,\n pinch: handTracking,\n buttonsAxes,\n gaze: true,\n headPose: true,\n haptics,\n };\n if (JSON.stringify(next) !== JSON.stringify(this.capabilities)) {\n this.capabilities = next;\n for (const listener of [...this.capsListeners]) listener(next);\n }\n }\n\n getCapabilities(): InputCapabilities {\n return this.capabilities;\n }\n\n onCapabilitiesChanged(listener: (c: InputCapabilities) => void): Unsubscribe {\n this.capsListeners.add(listener);\n return () => this.capsListeners.delete(listener);\n }\n\n onSourcesChanged(listener: () => void): Unsubscribe {\n this.sourceListeners.add(listener);\n return () => this.sourceListeners.delete(listener);\n }\n\n /** Bridge-system input: this frame's pre-resolved tag hints. */\n setHints(hints: InputHitHint[]): void {\n this.hints = hints;\n }\n\n sampleHints(): readonly InputHitHint[] {\n return this.hints;\n }\n\n /** Bridge-system input: a side is currently native-grabbing. */\n setNativeGrabbing(side: Side, grabbing: boolean): void {\n this.nativeGrabbing[side] = grabbing;\n }\n\n sample(): readonly InputSourceSnapshot[] {\n this.sideBySourceId.clear();\n // Adapters are created as input sources connect, which can be after the\n // client set its presence, so the desired state is re-applied here.\n if (this.presenceRequested) this.applyPresence();\n if (!this.world.session) return [];\n if (this.world.visibilityState.peek() !== VisibilityState.Visible) return [];\n\n const spaces = this.world.playerSpaceEntities;\n const snapshots: InputSourceSnapshot[] = [];\n for (const side of SIDES) {\n const rayObject = spaces.raySpaces[side].object3D;\n if (!rayObject) continue;\n const gamepad = this.world.input.xr.gamepads[side];\n const hand = this.capabilities.handJoints;\n\n rayObject.updateWorldMatrix(true, false);\n const rayPos = rayObject.getWorldPosition(TEMP.v1);\n const rayQuat = rayObject.getWorldQuaternion(TEMP.q1);\n const forward = TEMP.v2.set(0, 0, -1).applyQuaternion(rayQuat);\n\n const select = gamepad\n ? Math.max(gamepad.getButtonValue(InputComponent.Trigger), gamepad.getSelecting() ? 1 : 0)\n : 0;\n const squeeze = gamepad ? gamepad.getButtonValue(InputComponent.Squeeze) : 0;\n\n const snapshot: InputSourceSnapshot = {\n id: `${side}-input`,\n kind: hand ? \"hand\" : \"controller\",\n handedness: side,\n ray: {\n origin: [rayPos.x, rayPos.y, rayPos.z],\n direction: [forward.x, forward.y, forward.z],\n },\n select,\n squeeze,\n };\n\n const gripObject = spaces.gripSpaces[side].object3D;\n if (gripObject) {\n const gripPos = gripObject.getWorldPosition(TEMP.v1);\n const gripQuat = gripObject.getWorldQuaternion(TEMP.q1);\n snapshot.gripPose = {\n position: [gripPos.x, gripPos.y, gripPos.z],\n quaternion: [gripQuat.x, gripQuat.y, gripQuat.z, gripQuat.w],\n };\n }\n const tipObject = spaces.indexTipSpaces[side].object3D;\n if (tipObject) {\n const tipPos = tipObject.getWorldPosition(TEMP.v1);\n snapshot.indexTip = [tipPos.x, tipPos.y, tipPos.z];\n }\n if (this.nativeGrabbing[side]) snapshot.nativeGrabbing = true;\n if ((gamepad?.gamepad?.hapticActuators?.length ?? 0) > 0) {\n snapshot.hapticsAvailable = true;\n }\n this.sideBySourceId.set(snapshot.id, side);\n snapshots.push(snapshot);\n }\n return snapshots;\n }\n\n // -- presence ---------------------------------------------------------------\n\n /**\n * Show or hide this session's controller/hand visuals. Returns false when\n * IWSDK has published no visual adapters, which is the case outside a\n * session. The request is remembered and re-applied on every sample, so\n * a call made before the adapters exist still lands.\n *\n * `\"none\"` targets no side - the handedness value that has no visual\n * here - so the call reports availability without changing anything.\n */\n setPresenceVisible(target: PresenceTarget, visible: boolean): boolean {\n this.presenceRequested = true;\n for (const side of SIDES) {\n if (target === \"all\" || target === side) this.presenceVisible[side] = visible;\n }\n return this.applyPresence();\n }\n\n /**\n * Choose which family of visuals is shown. `\"hands\"` and `\"controllers\"`\n * force one family and hide the other; `\"auto\"` follows the engine's own\n * modality (hand visuals while hand tracking is live).\n */\n setPresenceModality(mode: PresenceModality): boolean {\n this.presenceRequested = true;\n this.presenceModality = mode;\n return this.applyPresence();\n }\n\n private visualAdapters(): PresenceAdaptersLike | null {\n const xr = this.world.input?.xr as unknown as\n | { visualAdapters?: PresenceAdaptersLike }\n | undefined;\n return xr?.visualAdapters ?? null;\n }\n\n private applyPresence(): boolean {\n const adapters = this.visualAdapters();\n if (!adapters) return false;\n const hands =\n this.presenceModality === \"hands\" ||\n (this.presenceModality === \"auto\" && this.capabilities.handJoints);\n const controllers =\n this.presenceModality === \"controllers\" ||\n (this.presenceModality === \"auto\" && !this.capabilities.handJoints);\n for (const side of SIDES) {\n const wanted = this.presenceVisible[side];\n setDescendantsVisible(adapters.hand?.[side], wanted && hands);\n setDescendantsVisible(adapters.controller?.[side], wanted && controllers);\n }\n return true;\n }\n\n getHeadPose(): HeadPose {\n const head = this.world.playerSpaceEntities.head.object3D;\n if (!head) return { position: [0, 0, 0], quaternion: [0, 0, 0, 1] };\n const position = head.getWorldPosition(TEMP.v1);\n const quaternion = head.getWorldQuaternion(TEMP.q1);\n return {\n position: [position.x, position.y, position.z],\n quaternion: [quaternion.x, quaternion.y, quaternion.z, quaternion.w],\n };\n }\n\n pulse(sourceId: string, intensity: number, durationMs: number): boolean {\n // The side comes from the handedness recorded when the snapshot was\n // built. Parsing the id is the fallback for an id this provider did not\n // produce (a caller's own naming, or a pulse before the first sample).\n const side =\n this.sideBySourceId.get(sourceId) ??\n (sourceId.startsWith(\"left\") ? \"left\" : sourceId.startsWith(\"right\") ? \"right\" : null);\n if (!side) return false;\n const actuator = this.world.input.xr.gamepads[side]?.gamepad?.hapticActuators?.[0];\n if (!actuator) return false;\n void (actuator as { pulse?: (i: number, d: number) => Promise<boolean> }).pulse?.(\n Math.min(1, Math.max(0, intensity)),\n durationMs,\n );\n return true;\n }\n\n dispose(): void {\n this.boundSession?.removeEventListener(\"inputsourceschange\", this.onSourcesChange);\n for (const dispose of this.disposers) dispose();\n this.disposers.length = 0;\n this.sideBySourceId.clear();\n }\n}\n\n// Shared scratch objects (single-threaded frame sampling).\nimport { Quaternion, Vector3 } from \"@iwsdk/core\";\nconst TEMP = { v1: new Vector3(), v2: new Vector3(), q1: new Quaternion() };\n"]}
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * IWSDKInputProvider - feeds Meta IWSDK's input machinery into the shared\n * input contracts, in place of the standalone WebXR provider.\n *\n * Poses come from the IWSDK player rig (`world.playerSpaceEntities`:\n * ray/grip/index-tip spaces, head), signals from the stateful XR gamepads\n * (`world.input.xr.gamepads` - analog trigger/squeeze with `getSelecting`\n * fallback, which also covers hand pinch). Capabilities derive from the\n * LIVE session and re-publish on visibility/input-source changes.\n *\n * Provider power: IWSDK resolves its own targeting (BVH raycasts →\n * `Pressed`/`Grabbed` tags). The bridge system turns those tags into\n * pre-resolved hints (`setHints`) and flags native grabbing, which the\n * core consumes IN PLACE of its own hit-testing.\n */\nimport { InputComponent, VisibilityState, type World } from \"@iwsdk/core\";\nimport {\n NO_CAPABILITIES,\n type Handedness,\n type HeadPose,\n type InputCapabilities,\n type InputHitHint,\n type InputProvider,\n type InputSourceSnapshot,\n type PresenceModality,\n type Unsubscribe,\n} from \"@realitycollective/webxr-input\";\n\nexport interface IWSDKProviderOptions {\n /**\n * The app enabled IWSDK's `features.grabbing` (+ physics where needed),\n * so grab behaviours are fulfilled NATIVELY by the engine.\n */\n nativeGrab?: boolean;\n}\n\ntype Side = \"left\" | \"right\";\nconst SIDES: readonly Side[] = [\"left\", \"right\"];\n\n/**\n * Structural slice of `world.input.xr.visualAdapters`. Only two fields are\n * needed and the real typings drag the whole `@iwsdk/xr-input` visual\n * stack in for them, so the shape is declared here. A per-side adapter,\n * and its `visual`, are both absent until that input source connects.\n */\ninterface PresenceObjectLike {\n visible: boolean;\n children?: readonly PresenceObjectLike[];\n}\n\ninterface PresenceAdapterLike {\n visual?: { model?: PresenceObjectLike } | undefined;\n}\n\ninterface PresenceAdaptersLike {\n controller?: Partial<Record<Side, PresenceAdapterLike | undefined>> | undefined;\n hand?: Partial<Record<Side, PresenceAdapterLike | undefined>> | undefined;\n}\n\n/**\n * Show or hide a visual by walking its DESCENDANTS rather than setting\n * `visible` on the root.\n *\n * Verified against `@iwsdk/xr-input` 0.5.3 (`dist/xr-input-manager.js`, the\n * per-frame update): IWSDK writes `visualAdapter.visual.model.visible =\n * inputSourceData.isPrimary` every frame, so a root-level write is undone\n * before it is drawn. The engine never touches the descendants, so hiding\n * them is the write that sticks, independent of system ordering.\n */\nfunction setDescendantsVisible(adapter: PresenceAdapterLike | undefined, visible: boolean): void {\n const model = adapter?.visual?.model;\n if (!model) return;\n const stack: PresenceObjectLike[] = [...(model.children ?? [])];\n while (stack.length > 0) {\n const node = stack.pop();\n if (!node) continue;\n node.visible = visible;\n for (const child of node.children ?? []) stack.push(child);\n }\n}\n\n/**\n * The state one side's visuals were last actually written with. Presence is\n * a function of these three, so a repeat call with all three unchanged has\n * nothing to write.\n */\ninterface AppliedPresence {\n visible: boolean;\n modality: PresenceModality;\n handJoints: boolean;\n}\n\nexport class IWSDKInputProvider implements InputProvider {\n private readonly world: World;\n private readonly nativeGrab: boolean;\n private capabilities: InputCapabilities;\n private readonly capsListeners = new Set<(c: InputCapabilities) => void>();\n private readonly sourceListeners = new Set<() => void>();\n private hints: InputHitHint[] = [];\n private readonly nativeGrabbing: Record<Side, boolean> = { left: false, right: false };\n /** Snapshot id -> side, filled by `sample()` so `pulse` need not parse ids. */\n private readonly sideBySourceId = new Map<string, Side>();\n private readonly presenceVisible: Record<Side, boolean> = { left: true, right: true };\n /** What was last written per side, so an unchanged call writes nothing. */\n private readonly presenceApplied: Record<Side, AppliedPresence | null> = {\n left: null,\n right: null,\n };\n private presenceModality: PresenceModality = \"auto\";\n /** Presence is only re-applied once a client has actually asked for it. */\n private presenceRequested = false;\n private readonly disposers: Unsubscribe[] = [];\n private boundSession: XRSession | null = null;\n private readonly onSourcesChange = () => {\n this.refreshCapabilities();\n for (const listener of [...this.sourceListeners]) listener();\n };\n\n constructor(world: World, options: IWSDKProviderOptions = {}) {\n this.world = world;\n this.nativeGrab = options.nativeGrab ?? false;\n this.capabilities = { ...NO_CAPABILITIES };\n const unsubscribe = world.visibilityState.subscribe(() => {\n this.bindSession();\n this.refreshCapabilities();\n });\n this.disposers.push(unsubscribe);\n this.bindSession();\n this.refreshCapabilities();\n }\n\n private bindSession(): void {\n const session = this.world.session ?? null;\n if (session === this.boundSession) return;\n this.boundSession?.removeEventListener(\"inputsourceschange\", this.onSourcesChange);\n this.boundSession = session;\n session?.addEventListener(\"inputsourceschange\", this.onSourcesChange);\n }\n\n private hasTrackedHand(): boolean {\n const session = this.world.session;\n if (!session) return false;\n for (const source of session.inputSources) {\n if (source.hand) return true;\n }\n return false;\n }\n\n private refreshCapabilities(): void {\n const session = this.world.session;\n const immersive = !!session;\n const handTracking =\n immersive &&\n ((session?.enabledFeatures?.includes(\"hand-tracking\") ?? false) || this.hasTrackedHand());\n let buttonsAxes = false;\n let haptics = false;\n for (const side of SIDES) {\n const gamepad = this.world.input.xr.gamepads[side];\n if (gamepad?.gamepad) buttonsAxes = true;\n if ((gamepad?.gamepad?.hapticActuators?.length ?? 0) > 0) haptics = true;\n }\n const next: InputCapabilities = {\n ...NO_CAPABILITIES,\n rays: immersive,\n // Index-tip spaces exist for controllers too (fall back to ray pose).\n pokes: immersive,\n grabs: immersive ? (this.nativeGrab ? \"native\" : \"poseOnly\") : \"none\",\n handJoints: handTracking,\n pinch: handTracking,\n buttonsAxes,\n gaze: true,\n headPose: true,\n haptics,\n // IWSDK builds and owns both visual families, so presence is always\n // available - `applyPresence` only needs the adapters to have appeared.\n presence: true,\n };\n if (JSON.stringify(next) !== JSON.stringify(this.capabilities)) {\n this.capabilities = next;\n for (const listener of [...this.capsListeners]) listener(next);\n }\n }\n\n getCapabilities(): InputCapabilities {\n return this.capabilities;\n }\n\n onCapabilitiesChanged(listener: (c: InputCapabilities) => void): Unsubscribe {\n this.capsListeners.add(listener);\n return () => this.capsListeners.delete(listener);\n }\n\n onSourcesChanged(listener: () => void): Unsubscribe {\n this.sourceListeners.add(listener);\n return () => this.sourceListeners.delete(listener);\n }\n\n /** Bridge-system input: this frame's pre-resolved tag hints. */\n setHints(hints: InputHitHint[]): void {\n this.hints = hints;\n }\n\n sampleHints(): readonly InputHitHint[] {\n return this.hints;\n }\n\n /** Bridge-system input: a side is currently native-grabbing. */\n setNativeGrabbing(side: Side, grabbing: boolean): void {\n this.nativeGrabbing[side] = grabbing;\n }\n\n sample(): readonly InputSourceSnapshot[] {\n this.sideBySourceId.clear();\n // Adapters are created as input sources connect, which can be after the\n // client set its presence, so the desired state is re-applied here.\n // Unconditionally: `@iwsdk/xr-input` re-asserts the visuals from its own\n // per-frame update, and a capability refresh can change the modality\n // underneath us, so the desired state has to be pushed again.\n if (this.presenceRequested) this.applyPresence(true);\n if (!this.world.session) return [];\n if (this.world.visibilityState.peek() !== VisibilityState.Visible) return [];\n\n const spaces = this.world.playerSpaceEntities;\n const snapshots: InputSourceSnapshot[] = [];\n for (const side of SIDES) {\n const rayObject = spaces.raySpaces[side].object3D;\n if (!rayObject) continue;\n const gamepad = this.world.input.xr.gamepads[side];\n const hand = this.capabilities.handJoints;\n\n rayObject.updateWorldMatrix(true, false);\n const rayPos = rayObject.getWorldPosition(TEMP.v1);\n const rayQuat = rayObject.getWorldQuaternion(TEMP.q1);\n const forward = TEMP.v2.set(0, 0, -1).applyQuaternion(rayQuat);\n\n const select = gamepad\n ? Math.max(gamepad.getButtonValue(InputComponent.Trigger), gamepad.getSelecting() ? 1 : 0)\n : 0;\n const squeeze = gamepad ? gamepad.getButtonValue(InputComponent.Squeeze) : 0;\n\n const snapshot: InputSourceSnapshot = {\n id: `${side}-input`,\n kind: hand ? \"hand\" : \"controller\",\n handedness: side,\n ray: {\n origin: [rayPos.x, rayPos.y, rayPos.z],\n direction: [forward.x, forward.y, forward.z],\n },\n select,\n squeeze,\n };\n\n const gripObject = spaces.gripSpaces[side].object3D;\n if (gripObject) {\n const gripPos = gripObject.getWorldPosition(TEMP.v1);\n const gripQuat = gripObject.getWorldQuaternion(TEMP.q1);\n snapshot.gripPose = {\n position: [gripPos.x, gripPos.y, gripPos.z],\n quaternion: [gripQuat.x, gripQuat.y, gripQuat.z, gripQuat.w],\n };\n }\n const tipObject = spaces.indexTipSpaces[side].object3D;\n if (tipObject) {\n const tipPos = tipObject.getWorldPosition(TEMP.v1);\n snapshot.indexTip = [tipPos.x, tipPos.y, tipPos.z];\n }\n if (this.nativeGrabbing[side]) snapshot.nativeGrabbing = true;\n if ((gamepad?.gamepad?.hapticActuators?.length ?? 0) > 0) {\n snapshot.hapticsAvailable = true;\n }\n this.sideBySourceId.set(snapshot.id, side);\n snapshots.push(snapshot);\n }\n return snapshots;\n }\n\n // -- presence ---------------------------------------------------------------\n\n /**\n * Show or hide this session's controller/hand visuals. Returns false when\n * IWSDK has published no visual adapters, which is the case outside a\n * session. The request is remembered and re-applied on every sample, so\n * a call made before the adapters exist still lands.\n *\n * `\"none\"` targets no side - the handedness value that has no visual\n * here - so the call reports availability without changing anything.\n *\n * A call that asks for what is already applied writes nothing, so an app\n * that pushes presence from a state subscription costs nothing on the\n * state changes that did not touch presence.\n */\n setPresenceVisible(target: Handedness | \"all\", visible: boolean): boolean {\n this.presenceRequested = true;\n for (const side of SIDES) {\n if (target === \"all\" || target === side) this.presenceVisible[side] = visible;\n }\n return this.applyPresence();\n }\n\n /**\n * Choose which family of visuals is shown. `\"hands\"` and `\"controllers\"`\n * force one family and hide the other; `\"auto\"` follows the engine's own\n * modality (hand visuals while hand tracking is live). A repeat of the\n * current modality writes nothing.\n */\n setPresenceModality(mode: PresenceModality): boolean {\n this.presenceRequested = true;\n this.presenceModality = mode;\n return this.applyPresence();\n }\n\n private visualAdapters(): PresenceAdaptersLike | null {\n const xr = this.world.input?.xr as unknown as\n | { visualAdapters?: PresenceAdaptersLike }\n | undefined;\n return xr?.visualAdapters ?? null;\n }\n\n /**\n * Write the desired presence into IWSDK's visuals.\n *\n * Each side is skipped when the three inputs presence depends on - the\n * side's visibility, the modality and the hand-tracking capability - are\n * all unchanged since the last write. Walking every descendant of both\n * visual families is not free, and an app pushing presence from a state\n * subscription calls this on every unrelated state change.\n *\n * `force` skips the diff, for the per-frame re-apply that has to win\n * against IWSDK's own writes.\n */\n private applyPresence(force = false): boolean {\n const adapters = this.visualAdapters();\n if (!adapters) return false;\n const handJoints = this.capabilities.handJoints;\n const modality = this.presenceModality;\n const hands = modality === \"hands\" || (modality === \"auto\" && handJoints);\n const controllers = modality === \"controllers\" || (modality === \"auto\" && !handJoints);\n for (const side of SIDES) {\n const wanted = this.presenceVisible[side];\n const last = this.presenceApplied[side];\n if (\n !force &&\n last !== null &&\n last.visible === wanted &&\n last.modality === modality &&\n last.handJoints === handJoints\n ) {\n continue;\n }\n setDescendantsVisible(adapters.hand?.[side], wanted && hands);\n setDescendantsVisible(adapters.controller?.[side], wanted && controllers);\n this.presenceApplied[side] = { visible: wanted, modality, handJoints };\n }\n return true;\n }\n\n getHeadPose(): HeadPose {\n const head = this.world.playerSpaceEntities.head.object3D;\n if (!head) return { position: [0, 0, 0], quaternion: [0, 0, 0, 1] };\n const position = head.getWorldPosition(TEMP.v1);\n const quaternion = head.getWorldQuaternion(TEMP.q1);\n return {\n position: [position.x, position.y, position.z],\n quaternion: [quaternion.x, quaternion.y, quaternion.z, quaternion.w],\n };\n }\n\n pulse(sourceId: string, intensity: number, durationMs: number): boolean {\n // The side comes from the handedness recorded when the snapshot was\n // built. Parsing the id is the fallback for an id this provider did not\n // produce (a caller's own naming, or a pulse before the first sample).\n const side =\n this.sideBySourceId.get(sourceId) ??\n (sourceId.startsWith(\"left\") ? \"left\" : sourceId.startsWith(\"right\") ? \"right\" : null);\n if (!side) return false;\n const actuator = this.world.input.xr.gamepads[side]?.gamepad?.hapticActuators?.[0];\n if (!actuator) return false;\n void (actuator as { pulse?: (i: number, d: number) => Promise<boolean> }).pulse?.(\n Math.min(1, Math.max(0, intensity)),\n durationMs,\n );\n return true;\n }\n\n dispose(): void {\n this.boundSession?.removeEventListener(\"inputsourceschange\", this.onSourcesChange);\n for (const dispose of this.disposers) dispose();\n this.disposers.length = 0;\n this.sideBySourceId.clear();\n }\n}\n\n// Shared scratch objects (single-threaded frame sampling).\nimport { Quaternion, Vector3 } from \"@iwsdk/core\";\nconst TEMP = { v1: new Vector3(), v2: new Vector3(), q1: new Quaternion() };\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@realitycollective/iwsdk-interactions",
|
|
3
|
-
"version": "0.1.0-preview.
|
|
3
|
+
"version": "0.1.0-preview.3",
|
|
4
4
|
"description": "Meta IWSDK adapter for the Reality Collective Interaction Extensions - feeds IWSDK's input machinery (Pressed/Grabbed tags, poke/ray interactables, grabbables, XR gamepads, hand joints) into the engine-free @realitycollective/webxr-interactions core, with native grab fulfilment. Re-exports the core.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"realitycollective",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@realitycollective/webxr-input": "^0.1.
|
|
36
|
-
"@realitycollective/webxr-interactions": "^0.1.0-preview.
|
|
35
|
+
"@realitycollective/webxr-input": "^0.1.1",
|
|
36
|
+
"@realitycollective/webxr-interactions": "^0.1.0-preview.3"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@iwsdk/core": ">=0.5.0 <0.6.0"
|