@displayxr/inline3d 1.35.0 → 1.36.0
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 +36 -0
- package/cursor-depth.d.ts +76 -0
- package/dist/call.js +1 -1
- package/js/inline3d-cursor-depth-playcanvas.js +281 -0
- package/js/inline3d-cursor-depth.js +311 -0
- package/js/inline3d-model-playcanvas.js +1 -0
- package/js/inline3d-model.js +2 -1
- package/js/inline3d-playcanvas-engine.js +3 -0
- package/js/inline3d-splat-playcanvas.js +19 -0
- package/js/inline3d-splat.js +4 -1
- package/js/inline3d-three.js +201 -0
- package/js/inline3d-viewer.js +24 -0
- package/model.d.ts +10 -0
- package/package.json +9 -1
- package/splat.d.ts +10 -0
- package/three.d.ts +49 -0
package/js/inline3d-viewer.js
CHANGED
|
@@ -737,6 +737,11 @@ export class SceneViewer {
|
|
|
737
737
|
this._cacheGood(views, vps, !eye);
|
|
738
738
|
const g = this._lastGood;
|
|
739
739
|
if (eye) (this.viewerEase ||= viewerEaseFor(frame, this._viewerEaseOpt)).apply(g.entries, frameTrackingState(frame));
|
|
740
|
+
// cursor: 'depth' (ADR-046) — only when a page opted in; null otherwise.
|
|
741
|
+
if (this.cursorDepth) {
|
|
742
|
+
this.scene.updateMatrixWorld(); // the hit test reads THIS frame's subject pose
|
|
743
|
+
this.cursorDepth.update(g.entries.map((e) => ({ projectionMatrix: e.proj, transformMatrix: e.pose })));
|
|
744
|
+
}
|
|
740
745
|
const r = this.renderer;
|
|
741
746
|
// getViewport() splits canvas.width; a drawing buffer the browser clamped behind our back
|
|
742
747
|
// (bufferScale().mismatch) gets the same split mapped onto its real size, never canvas.width/2.
|
|
@@ -771,6 +776,22 @@ export class SceneViewer {
|
|
|
771
776
|
return this;
|
|
772
777
|
}
|
|
773
778
|
|
|
779
|
+
/**
|
|
780
|
+
* `cursor: 'depth'` (ADR-046): a cursor that rises to the subject under it instead of being
|
|
781
|
+
* drawn on the glass behind content that pops out. Called by ./model and ./splat on opt-in
|
|
782
|
+
* only — without it nothing is built and every hook below is skipped. Injected, like
|
|
783
|
+
* useEyeCamera, so this module never imports three.js itself.
|
|
784
|
+
* @param {Function} DepthCursorClass ./three's DepthCursor.
|
|
785
|
+
* @param {(content: object) => Function} hitTestFor builds the hit test over the subject group.
|
|
786
|
+
* @param {object} [opts] extra DepthCursor options (./splat passes `raysPerFrame`).
|
|
787
|
+
*/
|
|
788
|
+
useDepthCursor(DepthCursorClass, hitTestFor, opts = {}) {
|
|
789
|
+
if (this.cursorDepth) return this;
|
|
790
|
+
this.cursorDepth = new DepthCursorClass(this._THREE, { ...opts, canvas: this.canvas, hitTest: hitTestFor(this.content) });
|
|
791
|
+
this.scene.add(this.cursorDepth.object);
|
|
792
|
+
return this;
|
|
793
|
+
}
|
|
794
|
+
|
|
774
795
|
/** Drive a flat, single-camera render loop for browsers without inline-3D. */
|
|
775
796
|
startMono() {
|
|
776
797
|
if (this._monoRaf || this._disposed) return;
|
|
@@ -780,6 +801,7 @@ export class SceneViewer {
|
|
|
780
801
|
if (this._disposed) return;
|
|
781
802
|
this._monoRaf = requestAnimationFrame(loop);
|
|
782
803
|
this._tick();
|
|
804
|
+
this.cursorDepth?.update(null); // 2D: no sprite, the normal cursor
|
|
783
805
|
const r = this.renderer;
|
|
784
806
|
r.clear();
|
|
785
807
|
const b = this._bufScale();
|
|
@@ -809,6 +831,8 @@ export class SceneViewer {
|
|
|
809
831
|
if (this._ro) this._ro.disconnect();
|
|
810
832
|
else removeEventListener('resize', this._onResize);
|
|
811
833
|
this._unbindOrbit();
|
|
834
|
+
this.cursorDepth?.dispose();
|
|
835
|
+
this.cursorDepth = null;
|
|
812
836
|
this.renderer.dispose();
|
|
813
837
|
}
|
|
814
838
|
|
package/model.d.ts
CHANGED
|
@@ -48,6 +48,16 @@ export interface ModelOptions {
|
|
|
48
48
|
* `createInline3D({ viewerEase })`, else on. `false` restores the snap.
|
|
49
49
|
*/
|
|
50
50
|
viewerEase?: ViewerEaseOption;
|
|
51
|
+
/**
|
|
52
|
+
* `'depth'`: a cursor that rises to the subject under it instead of being drawn on the glass,
|
|
53
|
+
* behind content that pops out (ADR-046, same maths as native `XR_DXR_cursor_depth`). A
|
|
54
|
+
* crosshair just in front of the nearest content under the pointer's footprint; the CSS cursor
|
|
55
|
+
* is hidden while it shows and comes back in 2D and off the canvas. OPT-IN: without it nothing
|
|
56
|
+
* is loaded or run. PlayCanvas: hit-tested with the engine's depth picker (meshes and splats,
|
|
57
|
+
* one low-res pass every other frame while the pointer is over the tile). three: a raycast
|
|
58
|
+
* against the subject.
|
|
59
|
+
*/
|
|
60
|
+
cursor?: 'depth';
|
|
51
61
|
/**
|
|
52
62
|
* How the mesh is lit.
|
|
53
63
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@displayxr/inline3d",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.36.0",
|
|
4
4
|
"description": "Turn any HTML <canvas> into a 3D window on a spatial display, inside an ordinary web page, for the DisplayXR Browser. Dependency-free; progressive enhancement (falls back to plain 2D everywhere else).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
"types": "./three.d.ts",
|
|
16
16
|
"import": "./js/inline3d-three.js"
|
|
17
17
|
},
|
|
18
|
+
"./cursor-depth": {
|
|
19
|
+
"types": "./cursor-depth.d.ts",
|
|
20
|
+
"import": "./js/inline3d-cursor-depth.js"
|
|
21
|
+
},
|
|
18
22
|
"./viewer": {
|
|
19
23
|
"types": "./viewer.d.ts",
|
|
20
24
|
"import": "./js/inline3d-viewer.js"
|
|
@@ -70,6 +74,8 @@
|
|
|
70
74
|
"js/inline3d-buffer-limit.js",
|
|
71
75
|
"js/inline3d-viewer-ease.js",
|
|
72
76
|
"js/inline3d-three.js",
|
|
77
|
+
"js/inline3d-cursor-depth.js",
|
|
78
|
+
"js/inline3d-cursor-depth-playcanvas.js",
|
|
73
79
|
"js/inline3d-viewer.js",
|
|
74
80
|
"js/inline3d-splat.js",
|
|
75
81
|
"js/inline3d-splat-pc-entry.js",
|
|
@@ -100,6 +106,7 @@
|
|
|
100
106
|
"dist/",
|
|
101
107
|
"index.d.ts",
|
|
102
108
|
"three.d.ts",
|
|
109
|
+
"cursor-depth.d.ts",
|
|
103
110
|
"viewer.d.ts",
|
|
104
111
|
"splat.d.ts",
|
|
105
112
|
"splat-playcanvas.d.ts",
|
|
@@ -167,6 +174,7 @@
|
|
|
167
174
|
"prepack": "node tools/dist/build.mjs",
|
|
168
175
|
"test:e2e": "node test/e2e/call-element.e2e.mjs",
|
|
169
176
|
"test:e2e:camera": "node test/e2e/camera.e2e.mjs",
|
|
177
|
+
"test:e2e:cursor": "node test/e2e/cursor-depth.e2e.mjs",
|
|
170
178
|
"api:check": "node tools/api-surface.mjs --check",
|
|
171
179
|
"api:update": "node tools/api-surface.mjs --update",
|
|
172
180
|
"check:snippets": "node tools/check-snippets.mjs",
|
package/splat.d.ts
CHANGED
|
@@ -472,6 +472,16 @@ export interface SplatOptions {
|
|
|
472
472
|
* `createInline3D({ viewerEase })`, else on. `false` restores the snap.
|
|
473
473
|
*/
|
|
474
474
|
viewerEase?: ViewerEaseOption;
|
|
475
|
+
/**
|
|
476
|
+
* `'depth'`: a cursor that rises to the subject under it instead of being drawn on the glass,
|
|
477
|
+
* behind content that pops out (ADR-046, same maths as native `XR_DXR_cursor_depth`). A
|
|
478
|
+
* crosshair just in front of the nearest content under the pointer's footprint; the CSS cursor
|
|
479
|
+
* is hidden while it shows and comes back in 2D and off the canvas. OPT-IN: without it nothing
|
|
480
|
+
* is loaded or run. PlayCanvas: hit-tested with the engine's depth picker (meshes and splats,
|
|
481
|
+
* one low-res pass every other frame while the pointer is over the tile). three: a raycast
|
|
482
|
+
* against the subject.
|
|
483
|
+
*/
|
|
484
|
+
cursor?: 'depth';
|
|
475
485
|
/** Camera rig only: the distance in world metres that sits ON the glass. */
|
|
476
486
|
convergence?: number;
|
|
477
487
|
/**
|
package/three.d.ts
CHANGED
|
@@ -142,3 +142,52 @@ export class EdgeFeather {
|
|
|
142
142
|
vp: { x: number; y: number; width: number; height: number },
|
|
143
143
|
): void;
|
|
144
144
|
}
|
|
145
|
+
|
|
146
|
+
import type { CursorPlacement, CursorView } from './cursor-depth.js';
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* A hit test for {@link DepthCursor} that raycasts three.js objects (recursively): the first hit
|
|
150
|
+
* along the ray as a world point, or null.
|
|
151
|
+
*/
|
|
152
|
+
export function raycastHitTest(
|
|
153
|
+
THREE: unknown,
|
|
154
|
+
targets: unknown[],
|
|
155
|
+
): (origin: number[], direction: number[]) => number[] | null;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* A cursor that rises to the depth of the content under it, so it is never drawn behind something
|
|
159
|
+
* that pops out of the glass. Same maths and defaults as the runtime's XR_DXR_cursor_depth
|
|
160
|
+
* (ADR-046). Tracks the pointer over `canvas`, hit-tests the cursor FOOTPRINT, places a crosshair
|
|
161
|
+
* (`object`, add it to your scene) and hides the CSS cursor exactly while the crosshair replaces it.
|
|
162
|
+
* Opt-in: nothing runs unless you construct one and call `update(views)` each frame.
|
|
163
|
+
*
|
|
164
|
+
* Head motion leaves the crosshair's image on the glass where it is (it stays under the mouse like
|
|
165
|
+
* the OS cursor); only its depth follows the content under that line of sight.
|
|
166
|
+
*/
|
|
167
|
+
export class DepthCursor {
|
|
168
|
+
constructor(
|
|
169
|
+
THREE: unknown,
|
|
170
|
+
opts: {
|
|
171
|
+
/** The woven canvas; the pointer is tracked over it. */
|
|
172
|
+
canvas: HTMLElement;
|
|
173
|
+
/** Nearest content point along a WORLD ray, or null. For splats return the expected depth along the ray. */
|
|
174
|
+
hitTest: (origin: number[], direction: number[]) => number[] | null;
|
|
175
|
+
/** Sprite height as a fraction of the canvas height (default 0.03). */
|
|
176
|
+
height?: number;
|
|
177
|
+
/** Crosshair colour (default 0xffd419). */
|
|
178
|
+
color?: number;
|
|
179
|
+
/** Attach pattern: the Object3D the eye cameras hang off; its world matrix carries the views to world. */
|
|
180
|
+
viewSpace?: unknown;
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
/** The crosshair (a `THREE.LineSegments`, depth test off, drawn last). Add it to the scene root. */
|
|
184
|
+
readonly object: unknown;
|
|
185
|
+
/** The last placement, for diagnostics. */
|
|
186
|
+
readonly placement: CursorPlacement | { active: false };
|
|
187
|
+
/** Place the sprite for this frame — call with the views you are about to render, before rendering. */
|
|
188
|
+
update(views: ArrayLike<XRView | CursorView>, nowMs?: number): CursorPlacement | { active: false };
|
|
189
|
+
/** Set the pointer directly (canvas-normalised, v down), or null — for scripted input. */
|
|
190
|
+
setPointer(u: number | null, v?: number): void;
|
|
191
|
+
/** Remove listeners, restore the CSS cursor, free the sprite's GPU resources. */
|
|
192
|
+
dispose(): void;
|
|
193
|
+
}
|