@displayxr/inline3d 1.29.0 → 1.30.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 +124 -0
- package/README.md +4 -0
- package/call.d.ts +269 -238
- package/camera.d.ts +257 -0
- package/dist/call.js +17 -12
- package/js/call/capture.js +4 -212
- package/js/call/disparity.js +4 -432
- package/js/call/element.js +14 -10
- package/js/call/options.js +132 -0
- package/js/call/ui.js +106 -9
- package/js/call/wire.js +8 -153
- package/js/camera/capture.js +220 -0
- package/js/camera/converge.js +82 -0
- package/js/camera/disparity.js +432 -0
- package/js/camera/geometry.js +80 -0
- package/js/camera/metadata.js +398 -0
- package/js/inline3d-call.js +404 -319
- package/js/inline3d-camera.js +678 -0
- package/js/inline3d-splat-deferred.js +153 -0
- package/js/inline3d-splat-pc-entry.js +45 -0
- package/js/inline3d-splat.js +2 -145
- package/package.json +19 -1
- package/splat-playcanvas.d.ts +4 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// inline3d-splat-deferred.js — the engine:'playcanvas' handle, shared by both splat entries.
|
|
2
|
+
//
|
|
3
|
+
// Internal. ./splat (Spark by default) and ./splat/playcanvas (PlayCanvas only) both build their
|
|
4
|
+
// PlayCanvas handle here. This module must never import `three` or `@sparkjsdev/spark`, directly
|
|
5
|
+
// or through anything it imports: that is what lets ./splat/playcanvas keep both off the page
|
|
6
|
+
// (test/splat-pc-entry.test.mjs walks the import graph to hold it to that).
|
|
7
|
+
|
|
8
|
+
import { normalizeCameraPose } from './inline3d-splat-shared.js';
|
|
9
|
+
import { validateEffectCall } from './inline3d-splat-effects.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The `engine: 'playcanvas'` handle, returned SYNCHRONOUSLY like the Spark one.
|
|
13
|
+
*
|
|
14
|
+
* The adapter module is loaded on demand, so for a moment the handle exists before its
|
|
15
|
+
* implementation does. Rather than make every caller await something new, the handle starts as
|
|
16
|
+
* stubs that QUEUE: `exclude()` (which a product page calls on the very next line), `setPose`,
|
|
17
|
+
* `setFocus`, `remove` — and the adapter replays the queue into the real implementation, on the
|
|
18
|
+
* SAME object, the moment it arrives. `ready` resolves to this object, as it does on Spark.
|
|
19
|
+
* Fields (`viewer`, `mesh`, `rig`, …) are null until then; `viewer` in particular appears one
|
|
20
|
+
* module-load later than on Spark.
|
|
21
|
+
*/
|
|
22
|
+
/** setRig's type/options shape, checked at the call before the adapter has loaded (it re-checks all of it). */
|
|
23
|
+
function validateSetRigArgs(type, o) {
|
|
24
|
+
if (!['display', 'camera', 'auto'].includes(type)) {
|
|
25
|
+
throw new Error(`@displayxr/inline3d/splat: setRig("${type}") — expected 'display', 'camera' or 'auto'.`);
|
|
26
|
+
}
|
|
27
|
+
if (o !== undefined && (o === null || typeof o !== 'object')) {
|
|
28
|
+
throw new TypeError('@displayxr/inline3d/splat: setRig options must be an object.');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function addSplatDeferred(wall, canvas, src, opts) {
|
|
33
|
+
const pending = [];
|
|
34
|
+
const queue = (name) => (...args) => {
|
|
35
|
+
pending.push([name, args]);
|
|
36
|
+
return name === 'setFocus' ? out : undefined;
|
|
37
|
+
};
|
|
38
|
+
const page = opts.controls === 'page';
|
|
39
|
+
const pageOnly = (name) => () => {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`@displayxr/inline3d/splat: ${name}() is not available with controls:'page' — the page owns the ` +
|
|
42
|
+
'camera. Drive it with handle.setCameraPose(matrixWorld, { verticalFovDeg, near, far }).',
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
// Before the adapter lands, a page calling setCameraPose every frame keeps ONE pending pose
|
|
46
|
+
// (validated now, so a bad call throws at its own line): last call wins, as it will after.
|
|
47
|
+
let pendingPose = null;
|
|
48
|
+
const out = {
|
|
49
|
+
backend: 'playcanvas',
|
|
50
|
+
engine: null,
|
|
51
|
+
viewer: null,
|
|
52
|
+
mesh: null,
|
|
53
|
+
frame: null,
|
|
54
|
+
camera: null,
|
|
55
|
+
rig: null,
|
|
56
|
+
perf: null,
|
|
57
|
+
setPose: page ? pageOnly('setPose') : queue('setPose'),
|
|
58
|
+
resetPose: page ? pageOnly('resetPose') : queue('resetPose'),
|
|
59
|
+
setCameraPose(matrixWorld, o) {
|
|
60
|
+
if (!page) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
"@displayxr/inline3d/splat: setCameraPose() needs addSplat(…, { controls:'page' }) — " +
|
|
63
|
+
'with the default controls the SDK owns the camera (use setPose).',
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
const pose = normalizeCameraPose(matrixWorld, o);
|
|
67
|
+
if (pendingPose) pendingPose[1] = [pose.matrixWorld, pose];
|
|
68
|
+
else pending.push((pendingPose = ['setCameraPose', [pose.matrixWorld, pose]]));
|
|
69
|
+
return out;
|
|
70
|
+
},
|
|
71
|
+
getCameraPose: () =>
|
|
72
|
+
pendingPose
|
|
73
|
+
? {
|
|
74
|
+
matrixWorld: Float32Array.from(pendingPose[1][1].matrixWorld),
|
|
75
|
+
verticalFovDeg: pendingPose[1][1].verticalFovDeg,
|
|
76
|
+
near: pendingPose[1][1].near,
|
|
77
|
+
far: pendingPose[1][1].far,
|
|
78
|
+
convergence: pendingPose[1][1].convergence,
|
|
79
|
+
}
|
|
80
|
+
: null,
|
|
81
|
+
setFocus: queue('setFocus'),
|
|
82
|
+
// A swap requested before the first asset has landed runs once it has (the adapter's own
|
|
83
|
+
// setSource replaces this stub on the same object by then).
|
|
84
|
+
setSource: (...args) => out.ready.then(() => out.setSource(...args)),
|
|
85
|
+
prepareSource: (...args) => out.ready.then(() => out.prepareSource(...args)),
|
|
86
|
+
// A rig switch before the first asset has landed: validated now (controls:'page' and a bad
|
|
87
|
+
// type throw at the call's own line), applied once it has.
|
|
88
|
+
setRig: page
|
|
89
|
+
? pageOnly('setRig')
|
|
90
|
+
: (type, o) => {
|
|
91
|
+
validateSetRigArgs(type, o);
|
|
92
|
+
return out.ready.then(() => out.setRig(type, o));
|
|
93
|
+
},
|
|
94
|
+
// A video before the first asset has landed: controls:'page' throws at the call's own line,
|
|
95
|
+
// the rest is validated by the adapter's setVideo, which runs once the asset is on screen.
|
|
96
|
+
setVideo: page ? pageOnly('setVideo') : (src, o) => out.ready.then(() => out.setVideo(src, o)),
|
|
97
|
+
// Effects before the adapter has loaded: validated NOW (a bad call throws at its own line),
|
|
98
|
+
// then run once the first asset is on screen.
|
|
99
|
+
playEffect: (name, o) => {
|
|
100
|
+
validateEffectCall(name, o, 'play');
|
|
101
|
+
return out.ready.then(() => out.playEffect(name, o));
|
|
102
|
+
},
|
|
103
|
+
setEffect: (name, params) => {
|
|
104
|
+
validateEffectCall(name, params, 'set');
|
|
105
|
+
pending.push(['setEffect', [name, params]]);
|
|
106
|
+
return out;
|
|
107
|
+
},
|
|
108
|
+
stopEffect: queue('stopEffect'),
|
|
109
|
+
// A layer-rig request before the adapter has loaded: queued, replayed in order once it has
|
|
110
|
+
// (it needs no asset, only the engine's layers — which the adapter resolves lazily).
|
|
111
|
+
setLayerRig: (...args) => {
|
|
112
|
+
pending.push(['setLayerRig', args]);
|
|
113
|
+
return out;
|
|
114
|
+
},
|
|
115
|
+
setLayerRigOptions: (...args) => {
|
|
116
|
+
pending.push(['setLayerRigOptions', args]);
|
|
117
|
+
return out;
|
|
118
|
+
},
|
|
119
|
+
layerRigState: () => ({ display: [], disabled: false, path: null, engaged: false, rounded: false, reason: 'the PlayCanvas adapter has not loaded yet', viewerDistance: 0.6, gain: null, planeM: null, photoConvergenceM: null, planeOffset: 0, located: null }),
|
|
120
|
+
makeSbsMaterial: () => {
|
|
121
|
+
throw new Error('@displayxr/inline3d/splat: makeSbsMaterial() needs the engine — call it after `await handle.ready`.');
|
|
122
|
+
},
|
|
123
|
+
effects: () => [],
|
|
124
|
+
getFocus: () => null,
|
|
125
|
+
// A plain data slot the adapter reads at call time, so a callback assigned on the very next
|
|
126
|
+
// line after addSplat — before the module has loaded — is the one that fires.
|
|
127
|
+
onFocusChange: null,
|
|
128
|
+
pick: () => null,
|
|
129
|
+
// Splat accounting (resident / budget / first frame); null until the adapter has loaded.
|
|
130
|
+
stats: () => null,
|
|
131
|
+
remove: queue('remove'),
|
|
132
|
+
exclude: queue('exclude'),
|
|
133
|
+
unexclude: queue('unexclude'),
|
|
134
|
+
};
|
|
135
|
+
// `firstWoven` exists from the first line, like every other field a page reads right away; the
|
|
136
|
+
// adapter settles it with the core handle's own once the module has loaded.
|
|
137
|
+
out.firstWoven = new Promise((resolve) => {
|
|
138
|
+
out._resolveFirstWoven = resolve;
|
|
139
|
+
});
|
|
140
|
+
// The ONE owner of `ready`: the adapter returns its load promise and never touches this field.
|
|
141
|
+
out.ready = import('./inline3d-splat-playcanvas.js')
|
|
142
|
+
.then((m) => m.attachPlayCanvasSplat(out, wall, canvas, src, opts, pending))
|
|
143
|
+
.catch((err) => {
|
|
144
|
+
// The adapter warns about its own load failures; this is for the module not arriving.
|
|
145
|
+
if (!out.viewer) console.warn('[inline3d/splat] engine:playcanvas failed to start', err);
|
|
146
|
+
if (out._resolveFirstWoven) {
|
|
147
|
+
out._resolveFirstWoven(Object.freeze({ woven: false, confirmed: false, reason: 'layer-failed', ms: 0 }));
|
|
148
|
+
delete out._resolveFirstWoven;
|
|
149
|
+
}
|
|
150
|
+
throw err;
|
|
151
|
+
});
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// inline3d-splat-pc-entry.js — `@displayxr/inline3d/splat/playcanvas`: addSplat on PlayCanvas only.
|
|
2
|
+
//
|
|
3
|
+
// EXPERIMENTAL, like ./splat. Same addSplat, same handle, same options, with the engine fixed to
|
|
4
|
+
// 'playcanvas'. The difference is what the page downloads: ./splat statically imports `three`
|
|
5
|
+
// and `@sparkjsdev/spark` because Spark is its default engine and its Spark path is synchronous,
|
|
6
|
+
// so a page passing engine:'playcanvas' there still pays for both (~1.7 MB gzipped). This entry
|
|
7
|
+
// imports neither, directly or transitively. `playcanvas` itself is still loaded on demand, when
|
|
8
|
+
// the first splat is added.
|
|
9
|
+
//
|
|
10
|
+
// import { createInline3D } from '@displayxr/inline3d';
|
|
11
|
+
// import { addSplat } from '@displayxr/inline3d/splat/playcanvas';
|
|
12
|
+
//
|
|
13
|
+
// const wall = await createInline3D();
|
|
14
|
+
// const scene = addSplat(wall, canvas, 'lake.sog', { reveal: 'sweep' });
|
|
15
|
+
//
|
|
16
|
+
// Not here: measureSplatBounds (it measures a Spark mesh — import it from ./splat).
|
|
17
|
+
|
|
18
|
+
import { resolveRevealOption } from './inline3d-splat-effects.js';
|
|
19
|
+
import { CAPTURE_FITS, playcanvasCannotRead, resolveControls } from './inline3d-splat-shared.js';
|
|
20
|
+
import { addSplatDeferred } from './inline3d-splat-deferred.js';
|
|
21
|
+
|
|
22
|
+
export { applySplatPerf, SPLAT_PERF_PRESETS } from './inline3d-splat-perf.js';
|
|
23
|
+
export { readSogCamera, readSogMeta } from './inline3d-sog.js';
|
|
24
|
+
export { resolveRig } from './inline3d-splat-rig.js';
|
|
25
|
+
|
|
26
|
+
/** addSplat with `engine: 'playcanvas'`; the same validation, at the call, as ./splat's. */
|
|
27
|
+
export function addSplat(wall, canvas, src, opts = {}) {
|
|
28
|
+
if (opts.engine !== undefined && opts.engine !== 'playcanvas') {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`@displayxr/inline3d/splat/playcanvas: engine "${opts.engine}" — this entry is PlayCanvas ` +
|
|
31
|
+
"only. Import addSplat from '@displayxr/inline3d/splat' for Spark.",
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if (opts.captureFit !== undefined && !CAPTURE_FITS.includes(opts.captureFit)) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`@displayxr/inline3d/splat: captureFit "${opts.captureFit}" — expected ` +
|
|
37
|
+
`${CAPTURE_FITS.map((f) => `'${f}'`).join(' or ')}.`,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
resolveControls(opts);
|
|
41
|
+
resolveRevealOption(opts.reveal);
|
|
42
|
+
const why = playcanvasCannotRead(src, opts);
|
|
43
|
+
if (why) throw new Error(`@displayxr/inline3d/splat: ${why}`);
|
|
44
|
+
return addSplatDeferred(wall, canvas, src, { ...opts, engine: 'playcanvas' });
|
|
45
|
+
}
|
package/js/inline3d-splat.js
CHANGED
|
@@ -23,8 +23,9 @@ import { SparkRenderer, SplatMesh } from '@sparkjsdev/spark';
|
|
|
23
23
|
import { EyeCamera, EdgeFeather, cameraRigFromCamera } from './inline3d-three.js';
|
|
24
24
|
import { SceneViewer, boundsFromPositions } from './inline3d-viewer.js';
|
|
25
25
|
import { readSogCamera } from './inline3d-sog.js';
|
|
26
|
-
import { resolveRevealOption, effectsNotOnSpark
|
|
26
|
+
import { resolveRevealOption, effectsNotOnSpark } from './inline3d-splat-effects.js';
|
|
27
27
|
import { applySplatPerf, splatPerfMeshOptions } from './inline3d-splat-perf.js';
|
|
28
|
+
import { addSplatDeferred } from './inline3d-splat-deferred.js';
|
|
28
29
|
import {
|
|
29
30
|
toArray3,
|
|
30
31
|
canvasNdc,
|
|
@@ -36,7 +37,6 @@ import {
|
|
|
36
37
|
isStreamedUrl,
|
|
37
38
|
STREAMED_NEEDS_PLAYCANVAS,
|
|
38
39
|
resolveControls,
|
|
39
|
-
normalizeCameraPose,
|
|
40
40
|
declareViewRig,
|
|
41
41
|
} from './inline3d-splat-shared.js';
|
|
42
42
|
import {
|
|
@@ -677,149 +677,6 @@ export function addSplat(wall, canvas, src, opts = {}) {
|
|
|
677
677
|
return out;
|
|
678
678
|
}
|
|
679
679
|
|
|
680
|
-
/**
|
|
681
|
-
* The `engine: 'playcanvas'` handle, returned SYNCHRONOUSLY like the Spark one.
|
|
682
|
-
*
|
|
683
|
-
* The adapter module is loaded on demand, so for a moment the handle exists before its
|
|
684
|
-
* implementation does. Rather than make every caller await something new, the handle starts as
|
|
685
|
-
* stubs that QUEUE: `exclude()` (which a product page calls on the very next line), `setPose`,
|
|
686
|
-
* `setFocus`, `remove` — and the adapter replays the queue into the real implementation, on the
|
|
687
|
-
* SAME object, the moment it arrives. `ready` resolves to this object, as it does on Spark.
|
|
688
|
-
* Fields (`viewer`, `mesh`, `rig`, …) are null until then; `viewer` in particular appears one
|
|
689
|
-
* module-load later than on Spark.
|
|
690
|
-
*/
|
|
691
|
-
/** setRig's type/options shape, checked at the call before the adapter has loaded (it re-checks all of it). */
|
|
692
|
-
function validateSetRigArgs(type, o) {
|
|
693
|
-
if (!['display', 'camera', 'auto'].includes(type)) {
|
|
694
|
-
throw new Error(`@displayxr/inline3d/splat: setRig("${type}") — expected 'display', 'camera' or 'auto'.`);
|
|
695
|
-
}
|
|
696
|
-
if (o !== undefined && (o === null || typeof o !== 'object')) {
|
|
697
|
-
throw new TypeError('@displayxr/inline3d/splat: setRig options must be an object.');
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
function addSplatDeferred(wall, canvas, src, opts) {
|
|
702
|
-
const pending = [];
|
|
703
|
-
const queue = (name) => (...args) => {
|
|
704
|
-
pending.push([name, args]);
|
|
705
|
-
return name === 'setFocus' ? out : undefined;
|
|
706
|
-
};
|
|
707
|
-
const page = opts.controls === 'page';
|
|
708
|
-
const pageOnly = (name) => () => {
|
|
709
|
-
throw new Error(
|
|
710
|
-
`@displayxr/inline3d/splat: ${name}() is not available with controls:'page' — the page owns the ` +
|
|
711
|
-
'camera. Drive it with handle.setCameraPose(matrixWorld, { verticalFovDeg, near, far }).',
|
|
712
|
-
);
|
|
713
|
-
};
|
|
714
|
-
// Before the adapter lands, a page calling setCameraPose every frame keeps ONE pending pose
|
|
715
|
-
// (validated now, so a bad call throws at its own line): last call wins, as it will after.
|
|
716
|
-
let pendingPose = null;
|
|
717
|
-
const out = {
|
|
718
|
-
backend: 'playcanvas',
|
|
719
|
-
engine: null,
|
|
720
|
-
viewer: null,
|
|
721
|
-
mesh: null,
|
|
722
|
-
frame: null,
|
|
723
|
-
camera: null,
|
|
724
|
-
rig: null,
|
|
725
|
-
perf: null,
|
|
726
|
-
setPose: page ? pageOnly('setPose') : queue('setPose'),
|
|
727
|
-
resetPose: page ? pageOnly('resetPose') : queue('resetPose'),
|
|
728
|
-
setCameraPose(matrixWorld, o) {
|
|
729
|
-
if (!page) {
|
|
730
|
-
throw new Error(
|
|
731
|
-
"@displayxr/inline3d/splat: setCameraPose() needs addSplat(…, { controls:'page' }) — " +
|
|
732
|
-
'with the default controls the SDK owns the camera (use setPose).',
|
|
733
|
-
);
|
|
734
|
-
}
|
|
735
|
-
const pose = normalizeCameraPose(matrixWorld, o);
|
|
736
|
-
if (pendingPose) pendingPose[1] = [pose.matrixWorld, pose];
|
|
737
|
-
else pending.push((pendingPose = ['setCameraPose', [pose.matrixWorld, pose]]));
|
|
738
|
-
return out;
|
|
739
|
-
},
|
|
740
|
-
getCameraPose: () =>
|
|
741
|
-
pendingPose
|
|
742
|
-
? {
|
|
743
|
-
matrixWorld: Float32Array.from(pendingPose[1][1].matrixWorld),
|
|
744
|
-
verticalFovDeg: pendingPose[1][1].verticalFovDeg,
|
|
745
|
-
near: pendingPose[1][1].near,
|
|
746
|
-
far: pendingPose[1][1].far,
|
|
747
|
-
convergence: pendingPose[1][1].convergence,
|
|
748
|
-
}
|
|
749
|
-
: null,
|
|
750
|
-
setFocus: queue('setFocus'),
|
|
751
|
-
// A swap requested before the first asset has landed runs once it has (the adapter's own
|
|
752
|
-
// setSource replaces this stub on the same object by then).
|
|
753
|
-
setSource: (...args) => out.ready.then(() => out.setSource(...args)),
|
|
754
|
-
prepareSource: (...args) => out.ready.then(() => out.prepareSource(...args)),
|
|
755
|
-
// A rig switch before the first asset has landed: validated now (controls:'page' and a bad
|
|
756
|
-
// type throw at the call's own line), applied once it has.
|
|
757
|
-
setRig: page
|
|
758
|
-
? pageOnly('setRig')
|
|
759
|
-
: (type, o) => {
|
|
760
|
-
validateSetRigArgs(type, o);
|
|
761
|
-
return out.ready.then(() => out.setRig(type, o));
|
|
762
|
-
},
|
|
763
|
-
// A video before the first asset has landed: controls:'page' throws at the call's own line,
|
|
764
|
-
// the rest is validated by the adapter's setVideo, which runs once the asset is on screen.
|
|
765
|
-
setVideo: page ? pageOnly('setVideo') : (src, o) => out.ready.then(() => out.setVideo(src, o)),
|
|
766
|
-
// Effects before the adapter has loaded: validated NOW (a bad call throws at its own line),
|
|
767
|
-
// then run once the first asset is on screen.
|
|
768
|
-
playEffect: (name, o) => {
|
|
769
|
-
validateEffectCall(name, o, 'play');
|
|
770
|
-
return out.ready.then(() => out.playEffect(name, o));
|
|
771
|
-
},
|
|
772
|
-
setEffect: (name, params) => {
|
|
773
|
-
validateEffectCall(name, params, 'set');
|
|
774
|
-
pending.push(['setEffect', [name, params]]);
|
|
775
|
-
return out;
|
|
776
|
-
},
|
|
777
|
-
stopEffect: queue('stopEffect'),
|
|
778
|
-
// A layer-rig request before the adapter has loaded: queued, replayed in order once it has
|
|
779
|
-
// (it needs no asset, only the engine's layers — which the adapter resolves lazily).
|
|
780
|
-
setLayerRig: (...args) => {
|
|
781
|
-
pending.push(['setLayerRig', args]);
|
|
782
|
-
return out;
|
|
783
|
-
},
|
|
784
|
-
setLayerRigOptions: (...args) => {
|
|
785
|
-
pending.push(['setLayerRigOptions', args]);
|
|
786
|
-
return out;
|
|
787
|
-
},
|
|
788
|
-
layerRigState: () => ({ display: [], disabled: false, path: null, engaged: false, rounded: false, reason: 'the PlayCanvas adapter has not loaded yet', viewerDistance: 0.6, gain: null, planeM: null, photoConvergenceM: null, planeOffset: 0, located: null }),
|
|
789
|
-
makeSbsMaterial: () => {
|
|
790
|
-
throw new Error('@displayxr/inline3d/splat: makeSbsMaterial() needs the engine — call it after `await handle.ready`.');
|
|
791
|
-
},
|
|
792
|
-
effects: () => [],
|
|
793
|
-
getFocus: () => null,
|
|
794
|
-
// A plain data slot the adapter reads at call time, so a callback assigned on the very next
|
|
795
|
-
// line after addSplat — before the module has loaded — is the one that fires.
|
|
796
|
-
onFocusChange: null,
|
|
797
|
-
pick: () => null,
|
|
798
|
-
// Splat accounting (resident / budget / first frame); null until the adapter has loaded.
|
|
799
|
-
stats: () => null,
|
|
800
|
-
remove: queue('remove'),
|
|
801
|
-
exclude: queue('exclude'),
|
|
802
|
-
unexclude: queue('unexclude'),
|
|
803
|
-
};
|
|
804
|
-
// `firstWoven` exists from the first line, like every other field a page reads right away; the
|
|
805
|
-
// adapter settles it with the core handle's own once the module has loaded.
|
|
806
|
-
out.firstWoven = new Promise((resolve) => {
|
|
807
|
-
out._resolveFirstWoven = resolve;
|
|
808
|
-
});
|
|
809
|
-
// The ONE owner of `ready`: the adapter returns its load promise and never touches this field.
|
|
810
|
-
out.ready = import('./inline3d-splat-playcanvas.js')
|
|
811
|
-
.then((m) => m.attachPlayCanvasSplat(out, wall, canvas, src, opts, pending))
|
|
812
|
-
.catch((err) => {
|
|
813
|
-
// The adapter warns about its own load failures; this is for the module not arriving.
|
|
814
|
-
if (!out.viewer) console.warn('[inline3d/splat] engine:playcanvas failed to start', err);
|
|
815
|
-
if (out._resolveFirstWoven) {
|
|
816
|
-
out._resolveFirstWoven(Object.freeze({ woven: false, confirmed: false, reason: 'layer-failed', ms: 0 }));
|
|
817
|
-
delete out._resolveFirstWoven;
|
|
818
|
-
}
|
|
819
|
-
throw err;
|
|
820
|
-
});
|
|
821
|
-
return out;
|
|
822
|
-
}
|
|
823
680
|
|
|
824
681
|
/**
|
|
825
682
|
* Percentile bounds from the loaded splats — the fallback when no sidecar was supplied.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@displayxr/inline3d",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.0",
|
|
4
4
|
"description": "Turn any HTML <canvas> into a glasses-free-3D window on a DisplayXR display, inside an ordinary web page. Dependency-free; progressive enhancement (falls back to plain 2D everywhere else).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
"types": "./splat.d.ts",
|
|
24
24
|
"import": "./js/inline3d-splat.js"
|
|
25
25
|
},
|
|
26
|
+
"./splat/playcanvas": {
|
|
27
|
+
"types": "./splat-playcanvas.d.ts",
|
|
28
|
+
"import": "./js/inline3d-splat-pc-entry.js"
|
|
29
|
+
},
|
|
26
30
|
"./model": {
|
|
27
31
|
"types": "./model.d.ts",
|
|
28
32
|
"import": "./js/inline3d-model-entry.js"
|
|
@@ -36,6 +40,10 @@
|
|
|
36
40
|
"types": "./player.d.ts",
|
|
37
41
|
"import": "./js/inline3d-player.js"
|
|
38
42
|
},
|
|
43
|
+
"./camera": {
|
|
44
|
+
"types": "./camera.d.ts",
|
|
45
|
+
"import": "./js/inline3d-camera.js"
|
|
46
|
+
},
|
|
39
47
|
"./call": {
|
|
40
48
|
"types": "./call.d.ts",
|
|
41
49
|
"import": "./js/inline3d-call.js"
|
|
@@ -62,6 +70,8 @@
|
|
|
62
70
|
"js/inline3d-three.js",
|
|
63
71
|
"js/inline3d-viewer.js",
|
|
64
72
|
"js/inline3d-splat.js",
|
|
73
|
+
"js/inline3d-splat-pc-entry.js",
|
|
74
|
+
"js/inline3d-splat-deferred.js",
|
|
65
75
|
"js/inline3d-sog.js",
|
|
66
76
|
"js/inline3d-splat-perf.js",
|
|
67
77
|
"js/inline3d-splat-rig.js",
|
|
@@ -79,8 +89,10 @@
|
|
|
79
89
|
"js/inline3d-pc-look.js",
|
|
80
90
|
"js/inline3d-playcanvas-engine.js",
|
|
81
91
|
"js/inline3d-player.js",
|
|
92
|
+
"js/inline3d-camera.js",
|
|
82
93
|
"js/inline3d-call.js",
|
|
83
94
|
"js/inline3d-call-full.js",
|
|
95
|
+
"js/camera/",
|
|
84
96
|
"js/call/",
|
|
85
97
|
"js/lift/",
|
|
86
98
|
"dist/",
|
|
@@ -88,8 +100,10 @@
|
|
|
88
100
|
"three.d.ts",
|
|
89
101
|
"viewer.d.ts",
|
|
90
102
|
"splat.d.ts",
|
|
103
|
+
"splat-playcanvas.d.ts",
|
|
91
104
|
"model.d.ts",
|
|
92
105
|
"player.d.ts",
|
|
106
|
+
"camera.d.ts",
|
|
93
107
|
"call.d.ts",
|
|
94
108
|
"call-full.d.ts",
|
|
95
109
|
"CHANGELOG.md",
|
|
@@ -149,6 +163,10 @@
|
|
|
149
163
|
"build:dist": "node tools/dist/build.mjs",
|
|
150
164
|
"prepack": "node tools/dist/build.mjs",
|
|
151
165
|
"test:e2e": "node test/e2e/call-element.e2e.mjs",
|
|
166
|
+
"test:e2e:camera": "node test/e2e/camera.e2e.mjs",
|
|
167
|
+
"api:check": "node tools/api-surface.mjs --check",
|
|
168
|
+
"api:update": "node tools/api-surface.mjs --update",
|
|
169
|
+
"check:snippets": "node tools/check-snippets.mjs",
|
|
152
170
|
"test:bundlers": "node test/bundlers/run.mjs"
|
|
153
171
|
},
|
|
154
172
|
"devDependencies": {
|