@displayxr/inline3d 1.49.2 → 1.49.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 +18 -0
- package/camera.d.ts +5 -0
- package/dist/call.js +6 -6
- package/js/inline3d-call.js +1 -1
- package/js/inline3d-camera.js +30 -1
- package/js/inline3d.js +16 -1
- package/package.json +1 -1
package/js/inline3d-call.js
CHANGED
|
@@ -2565,7 +2565,7 @@ class SelfTile {
|
|
|
2565
2565
|
|
|
2566
2566
|
/** For `call.diagnostics().self`: what the self view actually shows. */
|
|
2567
2567
|
diag() {
|
|
2568
|
-
if (!this.view) return { route: null, woven: false, reason: 'no-camera', firstWoven: null, layerRetries: 0 };
|
|
2568
|
+
if (!this.view) return { route: null, woven: false, reason: 'no-camera', firstWoven: null, layerRetries: 0, frameAgeMs: null };
|
|
2569
2569
|
return this.view.weaveState();
|
|
2570
2570
|
}
|
|
2571
2571
|
|
package/js/inline3d-camera.js
CHANGED
|
@@ -564,6 +564,8 @@ class CameraView {
|
|
|
564
564
|
this._scratch = null;
|
|
565
565
|
this._luma = null; // the latest grayscale source copy (auto-convergence and the depth cursor read it)
|
|
566
566
|
this.disparityPx = null;
|
|
567
|
+
this._lastFrameAt = 0; // performance.now() of the last NEW camera frame (0 = none yet)
|
|
568
|
+
this._lastVideoTime = -1;
|
|
567
569
|
// `cursor: 'depth'` (ADR-046 on a pair): validated now, its module loaded only on opt-in.
|
|
568
570
|
this._cursorOpt = resolvePairCursorOption(o.cursor, '@displayxr/inline3d/camera');
|
|
569
571
|
/** The depth cursor once its module has loaded; null without `cursor: 'depth'`. */
|
|
@@ -598,9 +600,28 @@ class CameraView {
|
|
|
598
600
|
reason: this.fallbackReason,
|
|
599
601
|
firstWoven: this.route === 'woven-sbs' ? (this._fw ? { ...this._fw } : 'pending') : null,
|
|
600
602
|
layerRetries: this._layerFails,
|
|
603
|
+
frameAgeMs: this.frameAgeMs,
|
|
601
604
|
};
|
|
602
605
|
}
|
|
603
606
|
|
|
607
|
+
/**
|
|
608
|
+
* Milliseconds since the camera last delivered a NEW frame to this view (its video's
|
|
609
|
+
* `currentTime` moved), or null before the first one. A view whose track stalls (a camera taken
|
|
610
|
+
* by another app, a suspended capture) keeps painting its last frame; this is how a page tells.
|
|
611
|
+
*/
|
|
612
|
+
get frameAgeMs() {
|
|
613
|
+
return this._lastFrameAt ? Math.round(performance.now() - this._lastFrameAt) : null;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/** Note a new camera frame (the video's clock moved since the last paint). */
|
|
617
|
+
_noteFrame(v) {
|
|
618
|
+
if ((v.readyState || 0) < 2) return;
|
|
619
|
+
const t = v.currentTime;
|
|
620
|
+
if (t === this._lastVideoTime) return;
|
|
621
|
+
this._lastVideoTime = t;
|
|
622
|
+
this._lastFrameAt = performance.now();
|
|
623
|
+
}
|
|
624
|
+
|
|
604
625
|
/** The per-eye convergence shift currently painted, source px. */
|
|
605
626
|
get convergencePx() {
|
|
606
627
|
return this.conv.current;
|
|
@@ -658,7 +679,14 @@ class CameraView {
|
|
|
658
679
|
}
|
|
659
680
|
|
|
660
681
|
_registerWoven() {
|
|
661
|
-
if (!this.buffer)
|
|
682
|
+
if (!this.buffer) {
|
|
683
|
+
// Empty until the camera's first frame is painted into it: the wall does not count an empty
|
|
684
|
+
// buffer as a stereo frame, so firstWoven cannot settle "woven" over a tile that never
|
|
685
|
+
// showed the camera (a track that delivers no frames).
|
|
686
|
+
this.buffer = document.createElement('canvas');
|
|
687
|
+
this.buffer.width = 0;
|
|
688
|
+
this.buffer.height = 0;
|
|
689
|
+
}
|
|
662
690
|
this._paintWoven(); // the first frame exists before the layer does
|
|
663
691
|
const handle = this.rectCover === undefined ? this.wall.addImage(this.canvas, this.buffer) : this.wall.addImage(this.canvas, this.buffer, { rectCover: this.rectCover });
|
|
664
692
|
this.handle = handle;
|
|
@@ -737,6 +765,7 @@ class CameraView {
|
|
|
737
765
|
if (this.removed) return;
|
|
738
766
|
const v = this.cam.video;
|
|
739
767
|
if (!v || this.cam.state === 'closed') return;
|
|
768
|
+
this._noteFrame(v);
|
|
740
769
|
if (this.route === 'woven-sbs') this._paintWoven();
|
|
741
770
|
else this._paintFlat(v);
|
|
742
771
|
}
|
package/js/inline3d.js
CHANGED
|
@@ -3345,7 +3345,10 @@ class Inline3D {
|
|
|
3345
3345
|
this._paint(win, views);
|
|
3346
3346
|
// An SBS paint with a real source behind it. Before the image has loaded (or while a
|
|
3347
3347
|
// video has never had a frame) the tile holds nothing worth revealing yet.
|
|
3348
|
-
|
|
3348
|
+
// A canvas source counts once it has pixels: an empty (0x0) buffer is a page that has not
|
|
3349
|
+
// drawn its first frame yet (a camera view before the camera's first frame), and settling
|
|
3350
|
+
// firstWoven on it reported a tile woven that had never shown anything.
|
|
3351
|
+
if (win.sbs && (win.kind === 'video' ? ((win.video && win.video.readyState) || 0) >= 2 : sourceHasPixels(win.img))) {
|
|
3349
3352
|
win.fwStereo = true;
|
|
3350
3353
|
win.lfStereo = true;
|
|
3351
3354
|
if (win.rw) win.rw.stereo = true;
|
|
@@ -3867,6 +3870,18 @@ function firstWovenHold(v) {
|
|
|
3867
3870
|
return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : FIRST_WOVEN_HOLD_MS;
|
|
3868
3871
|
}
|
|
3869
3872
|
|
|
3873
|
+
/**
|
|
3874
|
+
* True when an image source has something to draw: a loaded image, a sized canvas or bitmap. A
|
|
3875
|
+
* source that reports no size at all (a test double) keeps the old rule: present = drawable.
|
|
3876
|
+
*/
|
|
3877
|
+
function sourceHasPixels(src) {
|
|
3878
|
+
if (!src) return false;
|
|
3879
|
+
const w = src.naturalWidth ?? src.videoWidth ?? src.width;
|
|
3880
|
+
const h = src.naturalHeight ?? src.videoHeight ?? src.height;
|
|
3881
|
+
if (w === undefined && h === undefined) return true;
|
|
3882
|
+
return w > 0 && h > 0;
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3870
3885
|
function loadImage(source) {
|
|
3871
3886
|
if (typeof source !== 'string') return Promise.resolve(source); // element/bitmap/canvas
|
|
3872
3887
|
return new Promise((resolve, reject) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@displayxr/inline3d",
|
|
3
|
-
"version": "1.49.
|
|
3
|
+
"version": "1.49.3",
|
|
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",
|