@realitycollective/webxr-interactions 0.1.1-preview.2 → 0.1.1-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 +11 -0
- package/README.md +1 -0
- package/dist/contract-cases.js +69 -0
- package/dist/contract-cases.js.map +1 -1
- package/dist/descriptor.d.ts +7 -1
- package/dist/descriptor.js.map +1 -1
- package/dist/gaze.d.ts +50 -0
- package/dist/gaze.js +162 -0
- package/dist/gaze.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/memory-physics.d.ts +41 -0
- package/dist/memory-physics.js +168 -0
- package/dist/memory-physics.js.map +1 -0
- package/dist/near-pointer-contract-cases.d.ts +16 -0
- package/dist/near-pointer-contract-cases.js +235 -0
- package/dist/near-pointer-contract-cases.js.map +1 -0
- package/dist/near-pointer.d.ts +131 -0
- package/dist/near-pointer.js +128 -0
- package/dist/near-pointer.js.map +1 -0
- package/dist/physics-contract-cases.d.ts +11 -0
- package/dist/physics-contract-cases.js +229 -0
- package/dist/physics-contract-cases.js.map +1 -0
- package/dist/physics.d.ts +148 -0
- package/dist/physics.js +35 -0
- package/dist/physics.js.map +1 -0
- package/dist/ports.d.ts +15 -0
- package/dist/ports.js.map +1 -1
- package/dist/runtime.d.ts +93 -4
- package/dist/runtime.js +299 -37
- package/dist/runtime.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"physics-contract-cases.js","sourceRoot":"","sources":["../src/physics-contract-cases.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The shared `PhysicsFacility` conformance suite: what every platform's\n * physics must do with the core's defaults (`physics.ts`). Runner-free, like\n * the other suites; a binding's test file loops over the cases with a\n * factory that builds a FRESH facility per case:\n *\n * ```ts\n * for (const contractCase of physicsFacilityContractCases()) {\n * it(contractCase.name, () => contractCase.run({ facility: makeFacility() }));\n * }\n * ```\n *\n * The scene every case builds is a static box floor whose top is at y = 0\n * and a 10 cm sphere dropped from 1 m. Tolerances allow for the different\n * integrators and contact solvers of real engines (Havok, Rapier, Jolt,\n * RealityKit): a rest is within 2 cm of the surface with under 5 cm/s of\n * motion, a bounce is a clear upward velocity, and a hold is exact to 1 mm.\n */\nimport type { PoseTuple, Vec3Tuple } from \"@realitycollective/webxr-input\";\nimport { PHYSICS_DEFAULTS, type PhysicsFacility } from \"./physics.js\";\n\n/** The facility under test. Build a FRESH one per case. */\nexport interface PhysicsFacilityContractSubject {\n facility: PhysicsFacility;\n}\n\n/** One check a {@link PhysicsFacility} implementation must pass. */\nexport interface PhysicsFacilityContractCase {\n name: string;\n run(subject: PhysicsFacilityContractSubject): void;\n}\n\nexport function physicsFacilityContractCases(): readonly PhysicsFacilityContractCase[] {\n return PHYSICS_CASES;\n}\n\nconst DT = 1 / PHYSICS_DEFAULTS.stepHz;\nconst BALL_RADIUS = 0.1;\nconst DROP_HEIGHT = 1;\n/** Steps in three seconds: enough for a 1 m drop to land and settle on every engine. */\nconst SETTLE_STEPS = 180;\nconst IDENTITY: PoseTuple[\"quaternion\"] = [0, 0, 0, 1];\nconst REST_EPS = 0.02;\nconst REST_SPEED = 0.05;\nconst HOLD_EPS = 1e-3;\n\nfunction pose(x: number, y: number, z: number): PoseTuple {\n return { position: [x, y, z], quaternion: [...IDENTITY] as PoseTuple[\"quaternion\"] };\n}\n\n/** A static box floor, 20 m square and 0.1 m thick, whose top face is y = 0. */\nfunction floor(facility: PhysicsFacility): void {\n facility.addBody(\"floor\", pose(0, -0.05, 0), { state: \"static\" }, { kind: \"box\", dimensions: [20, 0.1, 20] });\n}\n\nfunction ball(facility: PhysicsFacility, restitution = 0, gravityFactor = 1): void {\n facility.addBody(\"ball\", pose(0, DROP_HEIGHT, 0), { gravityFactor }, { kind: \"sphere\", dimensions: [BALL_RADIUS, 0, 0], restitution });\n}\n\nfunction steps(facility: PhysicsFacility, count: number): void {\n for (let i = 0; i < count; i++) facility.step(DT);\n}\n\nfunction assert(condition: boolean, message: string): asserts condition {\n if (!condition) throw new Error(message);\n}\n\nfunction close(a: Readonly<Vec3Tuple>, b: Readonly<Vec3Tuple>, eps: number): boolean {\n return Math.abs(a[0] - b[0]) <= eps && Math.abs(a[1] - b[1]) <= eps && Math.abs(a[2] - b[2]) <= eps;\n}\n\nfunction speed(v: Vec3Tuple): number {\n return Math.hypot(v[0], v[1], v[2]);\n}\n\nconst PHYSICS_CASES: readonly PhysicsFacilityContractCase[] = [\n {\n name: \"starts with IWSDK's gravity, and a body added with no spec is dynamic until removed\",\n run({ facility }) {\n assert(close(facility.getGravity(), PHYSICS_DEFAULTS.gravity, 1e-6), `gravity must start at ${JSON.stringify(PHYSICS_DEFAULTS.gravity)}, got ${JSON.stringify(facility.getGravity())}`);\n assert(typeof facility.engine === \"string\" && facility.engine.length > 0, \"the facility must name its engine\");\n facility.addBody(\"ball\", pose(0, 1, 0), undefined, { kind: \"sphere\", dimensions: [BALL_RADIUS, 0, 0] });\n assert(facility.hasBody(\"ball\"), \"a body just added must be there\");\n assert(facility.getBodyState(\"ball\") === \"dynamic\", `a body with no spec must be dynamic, got ${facility.getBodyState(\"ball\")}`);\n assert(facility.isSuspended(\"ball\") === false, \"a body just added is not suspended\");\n const at = facility.getBodyPose(\"ball\");\n assert(close(at.position, [0, 1, 0], 1e-6), `a body just added sits where it was added, got ${JSON.stringify(at.position)}`);\n facility.removeBody(\"ball\");\n assert(!facility.hasBody(\"ball\"), \"a removed body must be gone\");\n let threw = false;\n try {\n facility.getBodyPose(\"ball\");\n } catch (error) {\n threw = /no physics body/.test((error as Error).message);\n }\n assert(threw, 'reading a missing body must throw an error naming it (\"no physics body\")');\n facility.removeBody(\"ball\");\n },\n },\n {\n name: \"a dynamic sphere falls under gravity and comes to rest on a static box\",\n run({ facility }) {\n floor(facility);\n ball(facility);\n steps(facility, 30);\n const falling = facility.getBodyPose(\"ball\").position[1];\n // Half a second of free fall drops about 1.2 m from rest; it has hit\n // the floor by now, or is well on its way: at most 0.5 m of the drop left.\n assert(falling < DROP_HEIGHT - 0.5, `after 0.5 s the ball must have fallen at least 0.5 m, it is at y = ${falling}`);\n steps(facility, SETTLE_STEPS - 30);\n const rest = facility.getBodyPose(\"ball\").position;\n assert(Math.abs(rest[1] - BALL_RADIUS) <= REST_EPS, `the ball must rest on the floor at y = ${BALL_RADIUS} (2 cm), it is at y = ${rest[1]}`);\n assert(Math.abs(rest[0]) <= REST_EPS && Math.abs(rest[2]) <= REST_EPS, `the ball must not drift sideways, it is at ${JSON.stringify(rest)}`);\n assert(speed(facility.getVelocity(\"ball\").linear) <= REST_SPEED, `a resting ball must be still, its speed is ${speed(facility.getVelocity(\"ball\").linear)}`);\n const floorPose = facility.getBodyPose(\"floor\");\n assert(close(floorPose.position, [0, -0.05, 0], 1e-3), \"a static floor never moves\");\n },\n },\n {\n name: \"restitution bounces: a lively ball leaves the floor again, a dead one does not\",\n run({ facility }) {\n floor(facility);\n ball(facility, 0.8);\n let landed = false;\n let bounced = false;\n for (let i = 0; i < SETTLE_STEPS && !bounced; i++) {\n facility.step(DT);\n const vy = facility.getVelocity(\"ball\").linear[1];\n if (vy < -0.5) landed = true;\n if (landed && vy > 0.5) bounced = true;\n }\n assert(bounced, \"a ball with restitution 0.8 dropped from 1 m must bounce back up at over 0.5 m/s\");\n facility.removeBody(\"ball\");\n ball(facility, 0);\n landed = false;\n let rose = 0;\n for (let i = 0; i < SETTLE_STEPS; i++) {\n facility.step(DT);\n const vy = facility.getVelocity(\"ball\").linear[1];\n if (vy < -0.5) landed = true;\n if (landed && vy > rose) rose = vy;\n }\n assert(rose <= 0.3, `a ball with restitution 0 must not bounce, it rose at ${rose} m/s`);\n },\n },\n {\n name: \"a static body never moves and a kinematic body moves only by pose writes\",\n run({ facility }) {\n facility.addBody(\"wall\", pose(0, 1, 0), { state: \"static\" }, { kind: \"box\", dimensions: [1, 1, 1] });\n facility.addBody(\"lift\", pose(2, 1, 0), { state: \"kinematic\" }, { kind: \"sphere\", dimensions: [BALL_RADIUS, 0, 0] });\n steps(facility, 60);\n assert(close(facility.getBodyPose(\"wall\").position, [0, 1, 0], HOLD_EPS), \"a static body must not fall\");\n assert(close(facility.getBodyPose(\"lift\").position, [2, 1, 0], HOLD_EPS), \"a kinematic body must not fall\");\n assert(facility.getBodyState(\"lift\") === \"kinematic\", \"the state reads back as kinematic\");\n facility.setBodyPose(\"lift\", pose(2, 2, 0));\n steps(facility, 10);\n assert(close(facility.getBodyPose(\"lift\").position, [2, 2, 0], HOLD_EPS), \"a kinematic body follows a pose write and stays\");\n facility.setBodyState(\"lift\", \"dynamic\");\n steps(facility, 30);\n assert(facility.getBodyPose(\"lift\").position[1] < 2 - 0.5, \"once dynamic, the same body falls\");\n },\n },\n {\n name: \"suspend holds the body still and pose writes stick exactly, until resume\",\n run({ facility }) {\n ball(facility);\n facility.suspend(\"ball\");\n assert(facility.isSuspended(\"ball\"), \"isSuspended reports the hold\");\n steps(facility, 30);\n assert(close(facility.getBodyPose(\"ball\").position, [0, DROP_HEIGHT, 0], HOLD_EPS), `a suspended body must not fall, it is at ${JSON.stringify(facility.getBodyPose(\"ball\").position)}`);\n facility.setBodyPose(\"ball\", pose(0.5, 2, 0.25));\n steps(facility, 30);\n assert(close(facility.getBodyPose(\"ball\").position, [0.5, 2, 0.25], HOLD_EPS), \"a pose written to a suspended body sticks exactly\");\n facility.suspend(\"ball\");\n assert(facility.isSuspended(\"ball\"), \"suspending twice is still one hold\");\n facility.resume(\"ball\", { linearVelocity: [0, 0, 0], angularVelocity: [0, 0, 0] });\n assert(!facility.isSuspended(\"ball\"), \"resume ends the hold\");\n assert(facility.getBodyState(\"ball\") === \"dynamic\", \"resume restores the state the body had\");\n steps(facility, 30);\n assert(facility.getBodyPose(\"ball\").position[1] < 2 - 0.5, \"a resumed body falls again\");\n },\n },\n {\n name: \"resume with a release velocity throws the body, and with zeros lets it rest\",\n run({ facility }) {\n ball(facility, 0, 0);\n facility.suspend(\"ball\");\n facility.resume(\"ball\", { linearVelocity: [2, 0, 0], angularVelocity: [0, 0, 0] });\n facility.step(DT);\n const moved = facility.getBodyPose(\"ball\").position[0];\n assert(moved > 2 * DT * 0.5, `a release at 2 m/s must move the body that way within one step, moved ${moved}`);\n facility.resume(\"ball\", { linearVelocity: [0, 0, 0], angularVelocity: [0, 0, 0] });\n const after = facility.getBodyPose(\"ball\").position[0];\n facility.step(DT);\n assert(Math.abs(facility.getBodyPose(\"ball\").position[0] - after) > 2 * DT * 0.5, \"resuming a body that is not suspended changes nothing: it keeps flying\");\n facility.suspend(\"ball\");\n facility.resume(\"ball\", { linearVelocity: [0, 0, 0], angularVelocity: [0, 0, 0] });\n const rest = facility.getBodyPose(\"ball\").position;\n steps(facility, 10);\n assert(close(facility.getBodyPose(\"ball\").position, rest, HOLD_EPS), \"a zero release rests the body (no gravity here, gravity factor 0)\");\n },\n },\n {\n name: \"setBodyPose while not suspended teleports the body and clears its velocity\",\n run({ facility }) {\n ball(facility);\n facility.setVelocity(\"ball\", { linear: [50, 0, 0], angular: [0, 0, 0] });\n facility.step(DT);\n assert(facility.getBodyPose(\"ball\").position[0] > 0.5, \"a body given 50 m/s moves in one step\");\n const target = pose(-1, 3, 0.5);\n facility.setBodyPose(\"ball\", target);\n facility.step(DT);\n const at = facility.getBodyPose(\"ball\").position;\n // One step of gravity from rest is about 1.4 mm; a kept velocity would be 0.83 m away.\n assert(close(at, target.position, REST_EPS), `a teleported body must be at the pose one step later, not carrying its old velocity; it is at ${JSON.stringify(at)}`);\n assert(speed(facility.getVelocity(\"ball\").linear) < 1, \"a teleport clears the velocity\");\n },\n },\n {\n name: \"setVelocity and getVelocity round-trip, and every tuple handed back is fresh\",\n run({ facility }) {\n ball(facility, 0, 0);\n facility.setVelocity(\"ball\", { linear: [1, 2, 3], angular: [0, 0.5, 0] });\n const read = facility.getVelocity(\"ball\");\n assert(close(read.linear, [1, 2, 3], 1e-3) && close(read.angular, [0, 0.5, 0], 1e-3), `velocity must read back as set, got ${JSON.stringify(read)}`);\n read.linear[0] = 99;\n assert(facility.getVelocity(\"ball\").linear[0] !== 99, \"the tuple handed back must be the caller's own copy\");\n const at = facility.getBodyPose(\"ball\");\n at.position[0] = 99;\n assert(facility.getBodyPose(\"ball\").position[0] !== 99, \"the pose handed back must be the caller's own copy\");\n const g = facility.getGravity();\n g[1] = 0;\n assert(facility.getGravity()[1] !== 0, \"the gravity handed back must be the caller's own copy\");\n },\n },\n {\n name: \"gravity factor 0 floats, and setGravity changes the world for every dynamic body\",\n run({ facility }) {\n ball(facility, 0, 0);\n steps(facility, 60);\n assert(close(facility.getBodyPose(\"ball\").position, [0, DROP_HEIGHT, 0], HOLD_EPS), \"a body with gravity factor 0 floats\");\n facility.addBody(\"stone\", pose(1, DROP_HEIGHT, 0), undefined, { kind: \"sphere\", dimensions: [BALL_RADIUS, 0, 0] });\n facility.setGravity([0, 0, 0]);\n assert(close(facility.getGravity(), [0, 0, 0], 1e-6), \"setGravity reads back\");\n steps(facility, 60);\n assert(close(facility.getBodyPose(\"stone\").position, [1, DROP_HEIGHT, 0], HOLD_EPS), \"with no gravity a dynamic body floats too\");\n facility.setGravity([0, -9.81, 0]);\n steps(facility, 60);\n assert(facility.getBodyPose(\"stone\").position[1] < DROP_HEIGHT - 0.5, \"with gravity back it falls\");\n },\n },\n {\n name: \"dispose removes every body\",\n run({ facility }) {\n floor(facility);\n ball(facility);\n facility.dispose();\n assert(!facility.hasBody(\"ball\") && !facility.hasBody(\"floor\"), \"dispose must remove every body\");\n },\n },\n];\n"]}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Physics - the platform facility every binding provides, with one contract
|
|
3
|
+
* and one set of defaults, so a body behaves the same under Havok on IWSDK
|
|
4
|
+
* and Babylon, Rapier on three.js and XR Blocks, and the native host's
|
|
5
|
+
* engine (Jolt on Quest and Android, RealityKit on visionOS).
|
|
6
|
+
*
|
|
7
|
+
* The template is IWSDK 1.0.0's physics (`@iwsdk/core` `dist/physics/`):
|
|
8
|
+
* `PhysicsSystem` steps Havok at 60 Hz with interpolation on and gravity
|
|
9
|
+
* `[0, -9.81, 0]`; a `PhysicsBody` is Dynamic with no damping and a gravity
|
|
10
|
+
* factor of 1; a `PhysicsShape` is Auto (from the mesh geometry) with density
|
|
11
|
+
* 1, restitution 0 and friction 0.5. `PHYSICS_DEFAULTS` restates those, and
|
|
12
|
+
* `physicsFacilityContractCases()` proves each platform's facility applies
|
|
13
|
+
* them: a body falls and rests, restitution bounces, a hold suspends, a
|
|
14
|
+
* release throws, a teleport clears velocity.
|
|
15
|
+
*
|
|
16
|
+
* The facility is what the Interactions ports lean on for the held pose
|
|
17
|
+
* (`TransformPort.beginHold`/`endHold`): a binding registers an object's
|
|
18
|
+
* body with its facility, and the port suspends and resumes it there. An
|
|
19
|
+
* app may replace the default engine by passing its own facility to the
|
|
20
|
+
* binding's setup; "this platform has no physics engine" is not a state
|
|
21
|
+
* the family recognises.
|
|
22
|
+
*
|
|
23
|
+
* Units: metres, seconds, radians, kilograms per cubic metre. Poses are
|
|
24
|
+
* world space, quaternions `[x, y, z, w]`, +Y up. Every tuple returned is a
|
|
25
|
+
* fresh value the caller owns; a tuple passed in is read and not kept.
|
|
26
|
+
*/
|
|
27
|
+
import type { PoseTuple, Vec3Tuple } from "@realitycollective/webxr-input";
|
|
28
|
+
import type { HoldRelease } from "./ports.js";
|
|
29
|
+
/**
|
|
30
|
+
* How a body moves. `"dynamic"` responds to forces, collisions and gravity;
|
|
31
|
+
* `"static"` never moves and collides as scenery; `"kinematic"` moves only
|
|
32
|
+
* by pose writes and pushes dynamic bodies. IWSDK: `PhysicsState.Dynamic`,
|
|
33
|
+
* `.Static`, `.Kinematic`.
|
|
34
|
+
*/
|
|
35
|
+
export type PhysicsBodyState = "dynamic" | "static" | "kinematic";
|
|
36
|
+
/**
|
|
37
|
+
* The collider's shape. `"auto"` is derived by the binding from the object's
|
|
38
|
+
* own geometry (IWSDK `PhysicsShapeType.Auto`, a convex hull of the mesh);
|
|
39
|
+
* the explicit kinds take `dimensions`: a box's full extents, a sphere's
|
|
40
|
+
* `[radius, 0, 0]`, a capsule's `[radius, height, 0]`.
|
|
41
|
+
*/
|
|
42
|
+
export type PhysicsShapeKind = "auto" | "box" | "sphere" | "capsule";
|
|
43
|
+
export interface PhysicsBodySpec {
|
|
44
|
+
/** Default `"dynamic"`. IWSDK `PhysicsBody.state`. */
|
|
45
|
+
state?: PhysicsBodyState;
|
|
46
|
+
/** Linear velocity damping per second, 0 for none. Default 0. IWSDK `linearDamping`. */
|
|
47
|
+
linearDamping?: number;
|
|
48
|
+
/** Angular velocity damping per second, 0 for none. Default 0. IWSDK `angularDamping`. */
|
|
49
|
+
angularDamping?: number;
|
|
50
|
+
/** Multiplier on the world's gravity for this body: 0 floats, 1 falls normally. Default 1. IWSDK `gravityFactor`. */
|
|
51
|
+
gravityFactor?: number;
|
|
52
|
+
}
|
|
53
|
+
export interface PhysicsShapeSpec {
|
|
54
|
+
/** Default `"auto"`. IWSDK `PhysicsShape.shape`. */
|
|
55
|
+
kind?: PhysicsShapeKind;
|
|
56
|
+
/** Metres; meaning per `kind`. Default `[0, 0, 0]`, which `"auto"` ignores. IWSDK `dimensions`. */
|
|
57
|
+
dimensions?: Vec3Tuple;
|
|
58
|
+
/** Kilograms per cubic metre; mass follows from it. Default 1. IWSDK `density`. */
|
|
59
|
+
density?: number;
|
|
60
|
+
/** Bounciness 0..1: 0 stops dead, 1 keeps all its speed. Default 0. IWSDK `restitution`. */
|
|
61
|
+
restitution?: number;
|
|
62
|
+
/** Coulomb friction, 0 slides freely. Default 0.5. IWSDK `friction`. */
|
|
63
|
+
friction?: number;
|
|
64
|
+
}
|
|
65
|
+
/** IWSDK 1.0.0's physics defaults, from `physics-system.js`, `physicsBody.js` and `physicsShape.js`. */
|
|
66
|
+
export declare const PHYSICS_DEFAULTS: Readonly<{
|
|
67
|
+
/** Metres per second squared, world space. */
|
|
68
|
+
gravity: readonly [number, number, number];
|
|
69
|
+
/** Simulation steps per second. */
|
|
70
|
+
stepHz: 60;
|
|
71
|
+
/** Render poses are interpolated between steps. */
|
|
72
|
+
interpolation: true;
|
|
73
|
+
body: Readonly<Required<PhysicsBodySpec>>;
|
|
74
|
+
shape: Readonly<Required<PhysicsShapeSpec>>;
|
|
75
|
+
}>;
|
|
76
|
+
/** A body spec with every default filled in. */
|
|
77
|
+
export declare function resolvePhysicsBody(spec?: PhysicsBodySpec): Required<PhysicsBodySpec>;
|
|
78
|
+
/** A shape spec with every default filled in. */
|
|
79
|
+
export declare function resolvePhysicsShape(spec?: PhysicsShapeSpec): Required<PhysicsShapeSpec>;
|
|
80
|
+
/** The velocity of a body: linear in metres per second, angular as an axis scaled by radians per second, world space. */
|
|
81
|
+
export interface PhysicsVelocity {
|
|
82
|
+
linear: Vec3Tuple;
|
|
83
|
+
angular: Vec3Tuple;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* One physics world on a platform. A binding names its default engine and
|
|
87
|
+
* builds this over it; an app may pass its own.
|
|
88
|
+
*
|
|
89
|
+
* Bodies are keyed by the same string ids the Interactions runtime uses for
|
|
90
|
+
* interactables, so a binding can look a registered object's body up when it
|
|
91
|
+
* builds the object's `TransformPort`.
|
|
92
|
+
*/
|
|
93
|
+
export interface PhysicsFacility {
|
|
94
|
+
/** The engine behind this facility, for reports: `"havok"`, `"rapier"`, `"jolt"`, `"realitykit"`, or an app's own name. */
|
|
95
|
+
readonly engine: string;
|
|
96
|
+
/** World gravity, metres per second squared. Starts at `PHYSICS_DEFAULTS.gravity`. */
|
|
97
|
+
getGravity(): Vec3Tuple;
|
|
98
|
+
setGravity(gravity: Vec3Tuple): void;
|
|
99
|
+
/**
|
|
100
|
+
* Add a body at `pose` with the given specs (defaults filled in as
|
|
101
|
+
* `resolvePhysicsBody`/`resolvePhysicsShape`). Adding an id that exists
|
|
102
|
+
* replaces it. IWSDK: `entity.addComponent(PhysicsBody, ...)` and
|
|
103
|
+
* `addComponent(PhysicsShape, ...)`.
|
|
104
|
+
*/
|
|
105
|
+
addBody(id: string, pose: PoseTuple, body?: PhysicsBodySpec, shape?: PhysicsShapeSpec): void;
|
|
106
|
+
/** Remove a body; a missing id is ignored. IWSDK: `removeComponent(PhysicsBody)`. */
|
|
107
|
+
removeBody(id: string): void;
|
|
108
|
+
hasBody(id: string): boolean;
|
|
109
|
+
/** Change how a body moves. IWSDK: `setValue(PhysicsBody, "state", ...)`. */
|
|
110
|
+
setBodyState(id: string, state: PhysicsBodyState): void;
|
|
111
|
+
getBodyState(id: string): PhysicsBodyState;
|
|
112
|
+
/** Where the body is now, world space. */
|
|
113
|
+
getBodyPose(id: string): PoseTuple;
|
|
114
|
+
/**
|
|
115
|
+
* Teleport: put the body at `pose` and clear its velocity, so it comes to
|
|
116
|
+
* rest there rather than carrying what it was doing. IWSDK:
|
|
117
|
+
* `PhysicsSystem.setBodyTransform`, which clears velocity by default.
|
|
118
|
+
*/
|
|
119
|
+
setBodyPose(id: string, pose: PoseTuple): void;
|
|
120
|
+
getVelocity(id: string): PhysicsVelocity;
|
|
121
|
+
/** Set both velocities, world space. IWSDK: `PhysicsManipulation` with `linearVelocity`/`angularVelocity`. */
|
|
122
|
+
setVelocity(id: string, velocity: PhysicsVelocity): void;
|
|
123
|
+
/**
|
|
124
|
+
* Suspend a body for a hold: from here until `resume`, it is not simulated
|
|
125
|
+
* (no gravity, no collision response) and `setBodyPose` writes are exact
|
|
126
|
+
* and carry no velocity. IWSDK: `beginHold` removes the `PhysicsBody`.
|
|
127
|
+
* Suspending a suspended body changes nothing.
|
|
128
|
+
*/
|
|
129
|
+
suspend(id: string): void;
|
|
130
|
+
/**
|
|
131
|
+
* Resume a suspended body in the state it had before the hold, with
|
|
132
|
+
* `release` as its velocity so a throw carries through; zeros rest it.
|
|
133
|
+
* IWSDK: `endHold` re-adds the `PhysicsBody` and a `PhysicsManipulation`.
|
|
134
|
+
* Resuming a body that is not suspended changes nothing.
|
|
135
|
+
*/
|
|
136
|
+
resume(id: string, release: HoldRelease): void;
|
|
137
|
+
isSuspended(id: string): boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Advance the world by `dtSeconds`. A facility whose engine steps itself
|
|
140
|
+
* (IWSDK's `PhysicsSystem`, the native host's loop) may take this as a
|
|
141
|
+
* hint and return; the contract cases then read poses the engine wrote.
|
|
142
|
+
*/
|
|
143
|
+
step(dtSeconds: number): void;
|
|
144
|
+
/** Release the world and every body. */
|
|
145
|
+
dispose(): void;
|
|
146
|
+
}
|
|
147
|
+
/** Error for a body id the facility does not have: one message on every platform. */
|
|
148
|
+
export declare function missingBody(id: string): Error;
|
package/dist/physics.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** IWSDK 1.0.0's physics defaults, from `physics-system.js`, `physicsBody.js` and `physicsShape.js`. */
|
|
2
|
+
export const PHYSICS_DEFAULTS = Object.freeze({
|
|
3
|
+
/** Metres per second squared, world space. */
|
|
4
|
+
gravity: Object.freeze([0, -9.81, 0]),
|
|
5
|
+
/** Simulation steps per second. */
|
|
6
|
+
stepHz: 60,
|
|
7
|
+
/** Render poses are interpolated between steps. */
|
|
8
|
+
interpolation: true,
|
|
9
|
+
body: Object.freeze({ state: "dynamic", linearDamping: 0, angularDamping: 0, gravityFactor: 1 }),
|
|
10
|
+
shape: Object.freeze({ kind: "auto", dimensions: [0, 0, 0], density: 1, restitution: 0, friction: 0.5 }),
|
|
11
|
+
});
|
|
12
|
+
/** A body spec with every default filled in. */
|
|
13
|
+
export function resolvePhysicsBody(spec = {}) {
|
|
14
|
+
const resolved = { ...PHYSICS_DEFAULTS.body, ...spec };
|
|
15
|
+
if (resolved.linearDamping < 0 || resolved.angularDamping < 0) {
|
|
16
|
+
throw new Error("[webxr-interactions] physics damping must be >= 0");
|
|
17
|
+
}
|
|
18
|
+
return resolved;
|
|
19
|
+
}
|
|
20
|
+
/** A shape spec with every default filled in. */
|
|
21
|
+
export function resolvePhysicsShape(spec = {}) {
|
|
22
|
+
const resolved = { ...PHYSICS_DEFAULTS.shape, ...spec, dimensions: [...(spec.dimensions ?? PHYSICS_DEFAULTS.shape.dimensions)] };
|
|
23
|
+
if (resolved.density <= 0)
|
|
24
|
+
throw new Error("[webxr-interactions] physics density must be > 0");
|
|
25
|
+
if (resolved.restitution < 0 || resolved.restitution > 1)
|
|
26
|
+
throw new Error("[webxr-interactions] physics restitution must be 0..1");
|
|
27
|
+
if (resolved.friction < 0)
|
|
28
|
+
throw new Error("[webxr-interactions] physics friction must be >= 0");
|
|
29
|
+
return resolved;
|
|
30
|
+
}
|
|
31
|
+
/** Error for a body id the facility does not have: one message on every platform. */
|
|
32
|
+
export function missingBody(id) {
|
|
33
|
+
return new Error(`[webxr-interactions] no physics body "${id}"`);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=physics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"physics.js","sourceRoot":"","sources":["../src/physics.ts"],"names":[],"mappings":"AAqEA,wGAAwG;AACxG,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5C,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAc,CAAC;IAClD,mCAAmC;IACnC,MAAM,EAAE,EAAE;IACV,mDAAmD;IACnD,aAAa,EAAE,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAA+B,CAAC;IAC7H,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAc,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAgC,CAAC;CACpJ,CAAC,CAAC;AAEH,gDAAgD;AAChD,MAAM,UAAU,kBAAkB,CAAC,OAAwB,EAAE;IAC3D,MAAM,QAAQ,GAAG,EAAE,GAAG,gBAAgB,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;IACvD,IAAI,QAAQ,CAAC,aAAa,GAAG,CAAC,IAAI,QAAQ,CAAC,cAAc,GAAG,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,mBAAmB,CAAC,OAAyB,EAAE;IAC7D,MAAM,QAAQ,GAAG,EAAE,GAAG,gBAAgB,CAAC,KAAK,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAc,EAAE,CAAC;IAC9I,IAAI,QAAQ,CAAC,OAAO,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IAC/F,IAAI,QAAQ,CAAC,WAAW,GAAG,CAAC,IAAI,QAAQ,CAAC,WAAW,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACnI,IAAI,QAAQ,CAAC,QAAQ,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACjG,OAAO,QAAQ,CAAC;AAClB,CAAC;AAuED,qFAAqF;AACrF,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,IAAI,KAAK,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAC;AACnE,CAAC","sourcesContent":["/**\n * Physics - the platform facility every binding provides, with one contract\n * and one set of defaults, so a body behaves the same under Havok on IWSDK\n * and Babylon, Rapier on three.js and XR Blocks, and the native host's\n * engine (Jolt on Quest and Android, RealityKit on visionOS).\n *\n * The template is IWSDK 1.0.0's physics (`@iwsdk/core` `dist/physics/`):\n * `PhysicsSystem` steps Havok at 60 Hz with interpolation on and gravity\n * `[0, -9.81, 0]`; a `PhysicsBody` is Dynamic with no damping and a gravity\n * factor of 1; a `PhysicsShape` is Auto (from the mesh geometry) with density\n * 1, restitution 0 and friction 0.5. `PHYSICS_DEFAULTS` restates those, and\n * `physicsFacilityContractCases()` proves each platform's facility applies\n * them: a body falls and rests, restitution bounces, a hold suspends, a\n * release throws, a teleport clears velocity.\n *\n * The facility is what the Interactions ports lean on for the held pose\n * (`TransformPort.beginHold`/`endHold`): a binding registers an object's\n * body with its facility, and the port suspends and resumes it there. An\n * app may replace the default engine by passing its own facility to the\n * binding's setup; \"this platform has no physics engine\" is not a state\n * the family recognises.\n *\n * Units: metres, seconds, radians, kilograms per cubic metre. Poses are\n * world space, quaternions `[x, y, z, w]`, +Y up. Every tuple returned is a\n * fresh value the caller owns; a tuple passed in is read and not kept.\n */\nimport type { PoseTuple, Vec3Tuple } from \"@realitycollective/webxr-input\";\nimport type { HoldRelease } from \"./ports.js\";\n\n/**\n * How a body moves. `\"dynamic\"` responds to forces, collisions and gravity;\n * `\"static\"` never moves and collides as scenery; `\"kinematic\"` moves only\n * by pose writes and pushes dynamic bodies. IWSDK: `PhysicsState.Dynamic`,\n * `.Static`, `.Kinematic`.\n */\nexport type PhysicsBodyState = \"dynamic\" | \"static\" | \"kinematic\";\n\n/**\n * The collider's shape. `\"auto\"` is derived by the binding from the object's\n * own geometry (IWSDK `PhysicsShapeType.Auto`, a convex hull of the mesh);\n * the explicit kinds take `dimensions`: a box's full extents, a sphere's\n * `[radius, 0, 0]`, a capsule's `[radius, height, 0]`.\n */\nexport type PhysicsShapeKind = \"auto\" | \"box\" | \"sphere\" | \"capsule\";\n\nexport interface PhysicsBodySpec {\n /** Default `\"dynamic\"`. IWSDK `PhysicsBody.state`. */\n state?: PhysicsBodyState;\n /** Linear velocity damping per second, 0 for none. Default 0. IWSDK `linearDamping`. */\n linearDamping?: number;\n /** Angular velocity damping per second, 0 for none. Default 0. IWSDK `angularDamping`. */\n angularDamping?: number;\n /** Multiplier on the world's gravity for this body: 0 floats, 1 falls normally. Default 1. IWSDK `gravityFactor`. */\n gravityFactor?: number;\n}\n\nexport interface PhysicsShapeSpec {\n /** Default `\"auto\"`. IWSDK `PhysicsShape.shape`. */\n kind?: PhysicsShapeKind;\n /** Metres; meaning per `kind`. Default `[0, 0, 0]`, which `\"auto\"` ignores. IWSDK `dimensions`. */\n dimensions?: Vec3Tuple;\n /** Kilograms per cubic metre; mass follows from it. Default 1. IWSDK `density`. */\n density?: number;\n /** Bounciness 0..1: 0 stops dead, 1 keeps all its speed. Default 0. IWSDK `restitution`. */\n restitution?: number;\n /** Coulomb friction, 0 slides freely. Default 0.5. IWSDK `friction`. */\n friction?: number;\n}\n\n/** IWSDK 1.0.0's physics defaults, from `physics-system.js`, `physicsBody.js` and `physicsShape.js`. */\nexport const PHYSICS_DEFAULTS = Object.freeze({\n /** Metres per second squared, world space. */\n gravity: Object.freeze([0, -9.81, 0] as Vec3Tuple),\n /** Simulation steps per second. */\n stepHz: 60,\n /** Render poses are interpolated between steps. */\n interpolation: true,\n body: Object.freeze({ state: \"dynamic\", linearDamping: 0, angularDamping: 0, gravityFactor: 1 } as Required<PhysicsBodySpec>),\n shape: Object.freeze({ kind: \"auto\", dimensions: [0, 0, 0] as Vec3Tuple, density: 1, restitution: 0, friction: 0.5 } as Required<PhysicsShapeSpec>),\n});\n\n/** A body spec with every default filled in. */\nexport function resolvePhysicsBody(spec: PhysicsBodySpec = {}): Required<PhysicsBodySpec> {\n const resolved = { ...PHYSICS_DEFAULTS.body, ...spec };\n if (resolved.linearDamping < 0 || resolved.angularDamping < 0) {\n throw new Error(\"[webxr-interactions] physics damping must be >= 0\");\n }\n return resolved;\n}\n\n/** A shape spec with every default filled in. */\nexport function resolvePhysicsShape(spec: PhysicsShapeSpec = {}): Required<PhysicsShapeSpec> {\n const resolved = { ...PHYSICS_DEFAULTS.shape, ...spec, dimensions: [...(spec.dimensions ?? PHYSICS_DEFAULTS.shape.dimensions)] as Vec3Tuple };\n if (resolved.density <= 0) throw new Error(\"[webxr-interactions] physics density must be > 0\");\n if (resolved.restitution < 0 || resolved.restitution > 1) throw new Error(\"[webxr-interactions] physics restitution must be 0..1\");\n if (resolved.friction < 0) throw new Error(\"[webxr-interactions] physics friction must be >= 0\");\n return resolved;\n}\n\n/** The velocity of a body: linear in metres per second, angular as an axis scaled by radians per second, world space. */\nexport interface PhysicsVelocity {\n linear: Vec3Tuple;\n angular: Vec3Tuple;\n}\n\n/**\n * One physics world on a platform. A binding names its default engine and\n * builds this over it; an app may pass its own.\n *\n * Bodies are keyed by the same string ids the Interactions runtime uses for\n * interactables, so a binding can look a registered object's body up when it\n * builds the object's `TransformPort`.\n */\nexport interface PhysicsFacility {\n /** The engine behind this facility, for reports: `\"havok\"`, `\"rapier\"`, `\"jolt\"`, `\"realitykit\"`, or an app's own name. */\n readonly engine: string;\n /** World gravity, metres per second squared. Starts at `PHYSICS_DEFAULTS.gravity`. */\n getGravity(): Vec3Tuple;\n setGravity(gravity: Vec3Tuple): void;\n /**\n * Add a body at `pose` with the given specs (defaults filled in as\n * `resolvePhysicsBody`/`resolvePhysicsShape`). Adding an id that exists\n * replaces it. IWSDK: `entity.addComponent(PhysicsBody, ...)` and\n * `addComponent(PhysicsShape, ...)`.\n */\n addBody(id: string, pose: PoseTuple, body?: PhysicsBodySpec, shape?: PhysicsShapeSpec): void;\n /** Remove a body; a missing id is ignored. IWSDK: `removeComponent(PhysicsBody)`. */\n removeBody(id: string): void;\n hasBody(id: string): boolean;\n /** Change how a body moves. IWSDK: `setValue(PhysicsBody, \"state\", ...)`. */\n setBodyState(id: string, state: PhysicsBodyState): void;\n getBodyState(id: string): PhysicsBodyState;\n /** Where the body is now, world space. */\n getBodyPose(id: string): PoseTuple;\n /**\n * Teleport: put the body at `pose` and clear its velocity, so it comes to\n * rest there rather than carrying what it was doing. IWSDK:\n * `PhysicsSystem.setBodyTransform`, which clears velocity by default.\n */\n setBodyPose(id: string, pose: PoseTuple): void;\n getVelocity(id: string): PhysicsVelocity;\n /** Set both velocities, world space. IWSDK: `PhysicsManipulation` with `linearVelocity`/`angularVelocity`. */\n setVelocity(id: string, velocity: PhysicsVelocity): void;\n /**\n * Suspend a body for a hold: from here until `resume`, it is not simulated\n * (no gravity, no collision response) and `setBodyPose` writes are exact\n * and carry no velocity. IWSDK: `beginHold` removes the `PhysicsBody`.\n * Suspending a suspended body changes nothing.\n */\n suspend(id: string): void;\n /**\n * Resume a suspended body in the state it had before the hold, with\n * `release` as its velocity so a throw carries through; zeros rest it.\n * IWSDK: `endHold` re-adds the `PhysicsBody` and a `PhysicsManipulation`.\n * Resuming a body that is not suspended changes nothing.\n */\n resume(id: string, release: HoldRelease): void;\n isSuspended(id: string): boolean;\n /**\n * Advance the world by `dtSeconds`. A facility whose engine steps itself\n * (IWSDK's `PhysicsSystem`, the native host's loop) may take this as a\n * hint and return; the contract cases then read poses the engine wrote.\n */\n step(dtSeconds: number): void;\n /** Release the world and every body. */\n dispose(): void;\n}\n\n/** Error for a body id the facility does not have: one message on every platform. */\nexport function missingBody(id: string): Error {\n return new Error(`[webxr-interactions] no physics body \"${id}\"`);\n}\n"]}
|
package/dist/ports.d.ts
CHANGED
|
@@ -50,6 +50,21 @@ export interface HitTester {
|
|
|
50
50
|
* {@link hitRay} applies here.
|
|
51
51
|
*/
|
|
52
52
|
hitProximity(point: Vec3Tuple, radius: number): InteractableHit | null;
|
|
53
|
+
/**
|
|
54
|
+
* Eye-gaze targeting: the best target inside a cone of `halfAngle` radians
|
|
55
|
+
* about `ray`, no farther than `maxLength` metres, or `null`. A target the
|
|
56
|
+
* ray itself reaches (as {@link hitRay}) wins outright; otherwise the
|
|
57
|
+
* target whose silhouette is nearest the ray in angle, and, within half a
|
|
58
|
+
* degree of each other, the nearer one. `distance` is metres to the point
|
|
59
|
+
* aimed at and `point` is that point on the target, which a selection then
|
|
60
|
+
* aims at from the pinching hand. This is IWSDK's `GazeConecaster`
|
|
61
|
+
* (`@iwsdk/xr-input` 1.0.0), which measures the angle to the closest point
|
|
62
|
+
* on the target's oriented bounding box; a sphere target measures to its
|
|
63
|
+
* silhouette, `coneHitForSpheres` in `gaze.ts`. The same hidden-target rule
|
|
64
|
+
* as {@link hitRay} applies. Absent, the runtime targets eye gaze with
|
|
65
|
+
* {@link hitRay} alone, without cone assistance.
|
|
66
|
+
*/
|
|
67
|
+
hitCone?(ray: RayTuple, halfAngle: number, maxLength: number): InteractableHit | null;
|
|
53
68
|
}
|
|
54
69
|
/**
|
|
55
70
|
* The release velocities handed to {@link TransformPort.endHold} - the
|
package/dist/ports.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ports.js","sourceRoot":"","sources":["../src/ports.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Engine-side ports - the space queries and transform writes the core\n * cannot perform itself. Adapters implement these against their scene\n * graph; the core only ever speaks tuples and interactable ids.\n */\nimport type { PoseTuple, QuatTuple, RayTuple, Vec3Tuple } from \"@realitycollective/webxr-input\";\n\nexport interface InteractableHit {\n interactableId: string;\n /** Distance from the query origin (ray origin / probe point). */\n distance: number;\n /** World-space hit or closest point. */\n point: Vec3Tuple;\n}\n\n/**\n * Resolves which interactable a ray or a proximity probe touches.\n * Implemented by the adapter (three.js Raycaster, engine BVH, …). A\n * provider that pre-resolves targeting (IWSDK) may make this redundant -\n * provider hints always take precedence over hit-tester results.\n *\n * Each hit, and the `point` tuple in it, is a fresh value the caller owns.\n * A ray or point passed in is read during the call and not kept.\n */\nexport interface HitTester {\n /**\n * The nearest target along `ray` (origin in metres, direction normalised),\n * or `null`. A target counts when its centre is within its own radius of\n * the ray line and in front of the origin; `distance` is the ray parameter\n * `t` of the closest point, and `t <= 0` never hits. This is IWSDK's\n * `EntityHitTester.hitRay` (`iwsdk-interactions/src/register.ts`). A\n * mesh-accurate tester may report the surface it hit instead, within the\n * target's radius of that answer; `hitTesterContractCases()` holds both to\n * the same tolerance.\n *\n * A target hidden by its engine's own visibility flag - including one\n * inherited from an ancestor - is never a candidate, even on an engine\n * whose own raycast ignores that flag by design (three.js's `Raycaster`\n * does; see `ThreeHitTester.hitRay`). The adapter re-applies the rule\n * itself in that case.\n */\n hitRay(ray: RayTuple): InteractableHit | null;\n /**\n * The nearest target to `point` within `radius` metres of its SURFACE, or\n * `null`. `distance` is `max(0, |centre - point| - targetRadius)`: a point\n * 3 cm outside a 10 cm target reports 0.03, and a point inside reports 0.\n * Never the distance to the centre, which would put every fingertip out of\n * poke range. This is IWSDK's `EntityHitTester.hitProximity`, and a target\n * registered with no declared radius is a 0.1 m sphere - IWSDK's default,\n * and the one every adapter that lets a target omit its radius (three.js,\n * XR Blocks, Babylon) uses too. The same hidden-target rule as\n * {@link hitRay} applies here.\n */\n hitProximity(point: Vec3Tuple, radius: number): InteractableHit | null;\n}\n\n/**\n * The release velocities handed to {@link TransformPort.endHold} - the\n * grabbing source's velocity at the moment of release, so a throw carries\n * through. Linear is metres per second, angular is radians per second,\n * both in world space, both plain tuples: this crosses the same boundary\n * `PoseTuple`/`Vec3Tuple` do, so it carries no engine object either.\n */\nexport interface HoldRelease {\n linearVelocity: Vec3Tuple;\n angularVelocity: Vec3Tuple;\n}\n\n/**\n * The transform/effect surface of ONE interactable's scene object.\n * Behaviours write through this; the adapter owns how writes land\n * (Object3D fields, ECS components, …).\n *\n * Offsets/rotations are FROM REST: the adapter captures the rest pose at\n * registration and applies these relative to it, so behaviours compose\n * with anything else animating the same object (the pale-signal\n * non-destructive-offset rule).\n *\n * Every tuple a port returns is a fresh value the caller owns. The port\n * keeps no reference to it and never writes to it again. A tuple passed in\n * is read during the call and not kept, so the caller may reuse it.\n */\nexport interface TransformPort {\n /**\n * The LIVE world pose: where the object is now, after every offset,\n * rotation and world-pose write, including a write made by anything else.\n */\n getWorldPose(): PoseTuple;\n /**\n * The rest pose captured at registration, in world space. Offsets and\n * rotations are measured from it, so it stays put while the port writes.\n * It follows a parent that moves.\n */\n getRestWorldPose(): PoseTuple;\n /** Local-space pose relative to the captured rest (dragged observation). */\n getLocalOffset(): Vec3Tuple;\n /** Additive local-space offset from rest (driven press / slide). */\n setLocalOffset(offset: Vec3Tuple): void;\n /** Local rotation about the rest orientation (hinge / dial output). */\n setLocalRotation(quaternion: QuatTuple): void;\n /**\n * Follow a world pose while grabbed (poseOnly grab fulfilment), or place\n * the object directly the rest of the time (reset / teleport).\n *\n * On a host whose object has physics, the two situations mean different\n * things and a conforming port tells them apart with {@link beginHold}/\n * {@link endHold}: WHILE HELD - between a `beginHold` and its matching\n * `endHold` - the object follows every write exactly and its velocities\n * are left untouched, because physics is suspended for the hold. NOT\n * HELD, a write teleports the object there and clears its velocities, so\n * it comes to rest at the pose (\"back to the tee\") rather than carrying\n * whatever it was doing a moment before. A host with no physics has only\n * the one meaning: the object is simply placed there.\n */\n setWorldPose?(pose: PoseTuple): void;\n /**\n * Presentation effect (the pulse behaviour): `scale` multiplies the REST\n * scale (1 is rest size) and `emissive` is ADDED to the material's base\n * emissive intensity (0 is none). Each field replaces the previous value\n * for this object: the last write wins, and nothing accumulates across\n * calls, so a behaviour that combines effects (pulse stacking on a press)\n * computes the combined value before it writes. An omitted field is left\n * as it is. This is `IWSDKTransformPort.setEffect`.\n */\n setEffect?(effect: { scale?: number; emissive?: number }): void;\n /**\n * Suspend physics for this object: from here until the matching\n * `endHold`, it follows `setWorldPose` writes exactly and gravity /\n * collisions stop moving it - see {@link setWorldPose}.\n *\n * Present only on a port whose object carries a physics body; a port\n * with no physics never grows this member, so it behaves exactly as\n * before. A platform that fulfils grabs natively through its own engine\n * (`grabsNative`) must show the same three behaviours (held / released /\n * reset) through that engine - the runtime never calls `beginHold` for\n * one, because the engine, not `webxr-interactions`, already owns the\n * hold.\n */\n beginHold?(): void;\n /**\n * Resume physics, applying `release` as the body's new velocity so a\n * throw carries through. Present on the same terms as {@link beginHold}.\n */\n endHold?(release: HoldRelease): void;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ports.js","sourceRoot":"","sources":["../src/ports.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Engine-side ports - the space queries and transform writes the core\n * cannot perform itself. Adapters implement these against their scene\n * graph; the core only ever speaks tuples and interactable ids.\n */\nimport type { PoseTuple, QuatTuple, RayTuple, Vec3Tuple } from \"@realitycollective/webxr-input\";\n\nexport interface InteractableHit {\n interactableId: string;\n /** Distance from the query origin (ray origin / probe point). */\n distance: number;\n /** World-space hit or closest point. */\n point: Vec3Tuple;\n}\n\n/**\n * Resolves which interactable a ray or a proximity probe touches.\n * Implemented by the adapter (three.js Raycaster, engine BVH, …). A\n * provider that pre-resolves targeting (IWSDK) may make this redundant -\n * provider hints always take precedence over hit-tester results.\n *\n * Each hit, and the `point` tuple in it, is a fresh value the caller owns.\n * A ray or point passed in is read during the call and not kept.\n */\nexport interface HitTester {\n /**\n * The nearest target along `ray` (origin in metres, direction normalised),\n * or `null`. A target counts when its centre is within its own radius of\n * the ray line and in front of the origin; `distance` is the ray parameter\n * `t` of the closest point, and `t <= 0` never hits. This is IWSDK's\n * `EntityHitTester.hitRay` (`iwsdk-interactions/src/register.ts`). A\n * mesh-accurate tester may report the surface it hit instead, within the\n * target's radius of that answer; `hitTesterContractCases()` holds both to\n * the same tolerance.\n *\n * A target hidden by its engine's own visibility flag - including one\n * inherited from an ancestor - is never a candidate, even on an engine\n * whose own raycast ignores that flag by design (three.js's `Raycaster`\n * does; see `ThreeHitTester.hitRay`). The adapter re-applies the rule\n * itself in that case.\n */\n hitRay(ray: RayTuple): InteractableHit | null;\n /**\n * The nearest target to `point` within `radius` metres of its SURFACE, or\n * `null`. `distance` is `max(0, |centre - point| - targetRadius)`: a point\n * 3 cm outside a 10 cm target reports 0.03, and a point inside reports 0.\n * Never the distance to the centre, which would put every fingertip out of\n * poke range. This is IWSDK's `EntityHitTester.hitProximity`, and a target\n * registered with no declared radius is a 0.1 m sphere - IWSDK's default,\n * and the one every adapter that lets a target omit its radius (three.js,\n * XR Blocks, Babylon) uses too. The same hidden-target rule as\n * {@link hitRay} applies here.\n */\n hitProximity(point: Vec3Tuple, radius: number): InteractableHit | null;\n /**\n * Eye-gaze targeting: the best target inside a cone of `halfAngle` radians\n * about `ray`, no farther than `maxLength` metres, or `null`. A target the\n * ray itself reaches (as {@link hitRay}) wins outright; otherwise the\n * target whose silhouette is nearest the ray in angle, and, within half a\n * degree of each other, the nearer one. `distance` is metres to the point\n * aimed at and `point` is that point on the target, which a selection then\n * aims at from the pinching hand. This is IWSDK's `GazeConecaster`\n * (`@iwsdk/xr-input` 1.0.0), which measures the angle to the closest point\n * on the target's oriented bounding box; a sphere target measures to its\n * silhouette, `coneHitForSpheres` in `gaze.ts`. The same hidden-target rule\n * as {@link hitRay} applies. Absent, the runtime targets eye gaze with\n * {@link hitRay} alone, without cone assistance.\n */\n hitCone?(ray: RayTuple, halfAngle: number, maxLength: number): InteractableHit | null;\n}\n\n/**\n * The release velocities handed to {@link TransformPort.endHold} - the\n * grabbing source's velocity at the moment of release, so a throw carries\n * through. Linear is metres per second, angular is radians per second,\n * both in world space, both plain tuples: this crosses the same boundary\n * `PoseTuple`/`Vec3Tuple` do, so it carries no engine object either.\n */\nexport interface HoldRelease {\n linearVelocity: Vec3Tuple;\n angularVelocity: Vec3Tuple;\n}\n\n/**\n * The transform/effect surface of ONE interactable's scene object.\n * Behaviours write through this; the adapter owns how writes land\n * (Object3D fields, ECS components, …).\n *\n * Offsets/rotations are FROM REST: the adapter captures the rest pose at\n * registration and applies these relative to it, so behaviours compose\n * with anything else animating the same object (the pale-signal\n * non-destructive-offset rule).\n *\n * Every tuple a port returns is a fresh value the caller owns. The port\n * keeps no reference to it and never writes to it again. A tuple passed in\n * is read during the call and not kept, so the caller may reuse it.\n */\nexport interface TransformPort {\n /**\n * The LIVE world pose: where the object is now, after every offset,\n * rotation and world-pose write, including a write made by anything else.\n */\n getWorldPose(): PoseTuple;\n /**\n * The rest pose captured at registration, in world space. Offsets and\n * rotations are measured from it, so it stays put while the port writes.\n * It follows a parent that moves.\n */\n getRestWorldPose(): PoseTuple;\n /** Local-space pose relative to the captured rest (dragged observation). */\n getLocalOffset(): Vec3Tuple;\n /** Additive local-space offset from rest (driven press / slide). */\n setLocalOffset(offset: Vec3Tuple): void;\n /** Local rotation about the rest orientation (hinge / dial output). */\n setLocalRotation(quaternion: QuatTuple): void;\n /**\n * Follow a world pose while grabbed (poseOnly grab fulfilment), or place\n * the object directly the rest of the time (reset / teleport).\n *\n * On a host whose object has physics, the two situations mean different\n * things and a conforming port tells them apart with {@link beginHold}/\n * {@link endHold}: WHILE HELD - between a `beginHold` and its matching\n * `endHold` - the object follows every write exactly and its velocities\n * are left untouched, because physics is suspended for the hold. NOT\n * HELD, a write teleports the object there and clears its velocities, so\n * it comes to rest at the pose (\"back to the tee\") rather than carrying\n * whatever it was doing a moment before. A host with no physics has only\n * the one meaning: the object is simply placed there.\n */\n setWorldPose?(pose: PoseTuple): void;\n /**\n * Presentation effect (the pulse behaviour): `scale` multiplies the REST\n * scale (1 is rest size) and `emissive` is ADDED to the material's base\n * emissive intensity (0 is none). Each field replaces the previous value\n * for this object: the last write wins, and nothing accumulates across\n * calls, so a behaviour that combines effects (pulse stacking on a press)\n * computes the combined value before it writes. An omitted field is left\n * as it is. This is `IWSDKTransformPort.setEffect`.\n */\n setEffect?(effect: { scale?: number; emissive?: number }): void;\n /**\n * Suspend physics for this object: from here until the matching\n * `endHold`, it follows `setWorldPose` writes exactly and gravity /\n * collisions stop moving it - see {@link setWorldPose}.\n *\n * Present only on a port whose object carries a physics body; a port\n * with no physics never grows this member, so it behaves exactly as\n * before. A platform that fulfils grabs natively through its own engine\n * (`grabsNative`) must show the same three behaviours (held / released /\n * reset) through that engine - the runtime never calls `beginHold` for\n * one, because the engine, not `webxr-interactions`, already owns the\n * hold.\n */\n beginHold?(): void;\n /**\n * Resume physics, applying `release` as the body's new velocity so a\n * throw carries through. Present on the same terms as {@link beginHold}.\n */\n endHold?(release: HoldRelease): void;\n}\n"]}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -13,13 +13,14 @@
|
|
|
13
13
|
* unregister, enable and disable; behaviours disabled by capability
|
|
14
14
|
* negotiation announce themselves with a `behaviourDisabled` event.
|
|
15
15
|
*/
|
|
16
|
-
import { type InputCapabilities, type InputProvider, type InputSourceSnapshot, type Unsubscribe } from "@realitycollective/webxr-input";
|
|
16
|
+
import { type EyeGazeOptions, type InputCapabilities, type InputProvider, type InputSourceSnapshot, type Unsubscribe } from "@realitycollective/webxr-input";
|
|
17
17
|
import type { Behaviour } from "./behaviours/behaviour.js";
|
|
18
18
|
import type { InteractableDescriptor } from "./descriptor.js";
|
|
19
19
|
import { type InteractionEventListener } from "./events.js";
|
|
20
20
|
import type { FeedbackListener } from "./feedback.js";
|
|
21
21
|
import { type DwellConfig } from "./gaze.js";
|
|
22
22
|
import type { HitTester, TransformPort } from "./ports.js";
|
|
23
|
+
import { type ActivePointerKind, type NearPointerOptions, type PointerVisuals } from "./near-pointer.js";
|
|
23
24
|
import { type VelocityTrackerOptions } from "./velocity-tracker.js";
|
|
24
25
|
/** Interactor id used when gaze is synthesized from the head pose. */
|
|
25
26
|
export declare const HEAD_GAZE_INTERACTOR_ID = "head-gaze";
|
|
@@ -39,12 +40,26 @@ export interface InteractionRuntimeOptions {
|
|
|
39
40
|
provider: InputProvider;
|
|
40
41
|
hitTester?: HitTester;
|
|
41
42
|
dwellDefaults?: DwellConfig;
|
|
43
|
+
/**
|
|
44
|
+
* Eye-gaze targeting, when the provider reports `capabilities.eyeGaze`:
|
|
45
|
+
* the selection cone, dwell window, near-pointer suppression and whether a
|
|
46
|
+
* gaze-started drag follows the pinching hand. Defaults are IWSDK 1.0.0's
|
|
47
|
+
* (`EYE_GAZE_DEFAULTS`).
|
|
48
|
+
*/
|
|
49
|
+
eyeGaze?: EyeGazeOptions;
|
|
42
50
|
/**
|
|
43
51
|
* Per-source velocity tracking. On by default with no smoothing; pass
|
|
44
52
|
* `false` to skip it, or options to smooth. The tracker only fills in
|
|
45
53
|
* what the provider did not supply.
|
|
46
54
|
*/
|
|
47
55
|
velocity?: VelocityTrackerOptions | false;
|
|
56
|
+
/**
|
|
57
|
+
* The near-pointer rule's distances: touch hover enter and exit, touch
|
|
58
|
+
* press, grip grab radius. Defaults are IWSDK 1.0.0's
|
|
59
|
+
* (`NEAR_POINTER_DEFAULTS`). An interactable's own `pokeRadius` overrides
|
|
60
|
+
* the touch hover enter distance for that target alone.
|
|
61
|
+
*/
|
|
62
|
+
nearPointer?: Partial<NearPointerOptions>;
|
|
48
63
|
}
|
|
49
64
|
export interface RegisterPorts {
|
|
50
65
|
transform?: TransformPort;
|
|
@@ -58,11 +73,21 @@ export declare class InteractionRuntime {
|
|
|
58
73
|
private readonly events;
|
|
59
74
|
private readonly feedbackEmitter;
|
|
60
75
|
private readonly afterSample;
|
|
76
|
+
private readonly visualsEmitter;
|
|
77
|
+
private readonly nearPointer;
|
|
78
|
+
private lastVisuals;
|
|
61
79
|
private readonly velocityTracker;
|
|
62
80
|
private lastSources;
|
|
63
81
|
private capabilities;
|
|
64
82
|
private readonly unsubscribeCaps;
|
|
65
83
|
private disposed;
|
|
84
|
+
private readonly eyeGaze;
|
|
85
|
+
private readonly gazeConsensus;
|
|
86
|
+
/** The eye-gaze source's target this frame: cone, consensus and suppression applied. */
|
|
87
|
+
private eyeGazeTarget;
|
|
88
|
+
/** Where the eye-gaze ray last aimed at each target, for the pinching hand to aim at. */
|
|
89
|
+
private readonly gazePoints;
|
|
90
|
+
private gazeHold;
|
|
66
91
|
constructor(options: InteractionRuntimeOptions);
|
|
67
92
|
registerInteractable(def: InteractableDescriptor, ports?: RegisterPorts): void;
|
|
68
93
|
unregisterInteractable(id: string): void;
|
|
@@ -104,15 +129,79 @@ export declare class InteractionRuntime {
|
|
|
104
129
|
getSource(id: string): InputSourceSnapshot | undefined;
|
|
105
130
|
getCapabilities(): InputCapabilities;
|
|
106
131
|
getProvider(): InputProvider;
|
|
132
|
+
/** The near-pointer distances in force (the defaults, or the options given). */
|
|
133
|
+
getNearPointerOptions(): Readonly<NearPointerOptions>;
|
|
134
|
+
/**
|
|
135
|
+
* The pointer that owns a source this frame: `"touch"`, `"grab"`, `"ray"`
|
|
136
|
+
* or `"gaze"`, or null when no pointer has a candidate (or the source is
|
|
137
|
+
* unknown). Decided by the core rule in `near-pointer.ts`, on every
|
|
138
|
+
* platform; a provider hint names the target but never the pointer.
|
|
139
|
+
*/
|
|
140
|
+
getActivePointer(sourceId: string): ActivePointerKind | null;
|
|
141
|
+
/**
|
|
142
|
+
* What to draw for every source this frame: the ray only while the ray is
|
|
143
|
+
* the active pointer or nothing is, the cursor at the active pointer's
|
|
144
|
+
* candidate. Published once per `update`, after the sources; a binding
|
|
145
|
+
* applies it to its ray and cursor visuals, and a native binding hands it
|
|
146
|
+
* to the host as `applyPointerVisuals`. The list and its entries are fresh
|
|
147
|
+
* each frame and never written to again.
|
|
148
|
+
*/
|
|
149
|
+
onPointerVisuals(listener: (visuals: readonly PointerVisuals[]) => void): Unsubscribe;
|
|
150
|
+
/** The visuals last published for a source, or undefined before its first frame. */
|
|
151
|
+
getPointerVisuals(sourceId: string): PointerVisuals | undefined;
|
|
107
152
|
update(dt: number): void;
|
|
108
153
|
dispose(): void;
|
|
154
|
+
/**
|
|
155
|
+
* The targeting half of the eye-gaze rule (`@realitycollective/webxr-input`
|
|
156
|
+
* `eye-gaze.ts` states the whole of it): the cone's best candidate this
|
|
157
|
+
* frame, then the dwell consensus over the window, and nothing at all while
|
|
158
|
+
* a hand's near pointer is hovering or selecting (IWSDK
|
|
159
|
+
* `suppressWhenDirectPointerActive`). A frame with no valid gaze ray clears
|
|
160
|
+
* the record, as IWSDK resets its conecaster, unless a selection is held.
|
|
161
|
+
*/
|
|
162
|
+
private resolveEyeGaze;
|
|
163
|
+
/** A hand's near pointer is hovering or selecting: touch or grab owns the hand, or a grab is held. */
|
|
164
|
+
private directPointerActive;
|
|
165
|
+
/**
|
|
166
|
+
* Once a gaze selection is held, the pinching hand drives the pointer
|
|
167
|
+
* (IWSDK `pointerTransformFollowsHand`): the frame the hold starts, a ray
|
|
168
|
+
* from the hand's ray space is aimed at the gaze hit and its orientation
|
|
169
|
+
* relative to the hand recorded; every later frame the gaze snapshot's ray
|
|
170
|
+
* is that hand's ray space turned by the same amount. When the hand could
|
|
171
|
+
* not reach the hit, or the option is off, the ray stays where the
|
|
172
|
+
* selection was made. Consumers of `onSample` and `getSource`, and every
|
|
173
|
+
* behaviour, see the followed ray.
|
|
174
|
+
*/
|
|
175
|
+
private followHand;
|
|
176
|
+
/** Start, keep or end the gaze hold from the gaze source's press and grab state this frame. */
|
|
177
|
+
private trackGazeHold;
|
|
109
178
|
private sourceState;
|
|
110
179
|
private interactorInfo;
|
|
111
|
-
/**
|
|
180
|
+
/**
|
|
181
|
+
* Resolve this source's target and its active pointer. The pointer is the
|
|
182
|
+
* core rule (`near-pointer.ts`): touch, then grab, then ray, the first with
|
|
183
|
+
* a candidate, locked while it presses or grabs. The target is a provider
|
|
184
|
+
* hint when there is one (provider power: IWSDK's mesh-accurate tags), else
|
|
185
|
+
* the active pointer's candidate. An eye-gaze source targets through the
|
|
186
|
+
* cone and consensus instead.
|
|
187
|
+
*/
|
|
112
188
|
private resolveTarget;
|
|
189
|
+
/**
|
|
190
|
+
* The touch pointer's candidate this frame, advancing the source's touch
|
|
191
|
+
* machine: the nearest target within the widest touch band, hovering by
|
|
192
|
+
* that target's own enter and exit distances. One proximity query at the
|
|
193
|
+
* largest radius any interactable asked for, then the nearest hit must be
|
|
194
|
+
* inside ITS OWN band; the trade is that a farther target with a wider
|
|
195
|
+
* band is not found behind a nearer one with a narrower band.
|
|
196
|
+
*/
|
|
197
|
+
private touchCandidate;
|
|
198
|
+
/** The grab pointer's candidate: the nearest target whose surface the grip sphere reaches. */
|
|
199
|
+
private grabCandidate;
|
|
200
|
+
/** The ray pointer's candidate: the nearest target along the ray. */
|
|
201
|
+
private rayCandidate;
|
|
113
202
|
private targetable;
|
|
114
|
-
/** The
|
|
115
|
-
private
|
|
203
|
+
/** The widest touch exit band among enabled interactables; the default exit distance when none is registered. */
|
|
204
|
+
private touchQueryRadius;
|
|
116
205
|
private flags;
|
|
117
206
|
private updateSource;
|
|
118
207
|
private gazeAllows;
|