@displayxr/inline3d 1.14.0 → 1.16.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 +72 -0
- package/README.md +4 -1
- package/js/inline3d-model-playcanvas.js +1 -1
- package/js/inline3d-splat-effects.js +213 -5
- package/js/inline3d-splat-playcanvas.js +618 -31
- package/js/inline3d-splat.js +25 -0
- package/package.json +1 -1
- package/splat.d.ts +110 -5
package/js/inline3d-splat.js
CHANGED
|
@@ -373,6 +373,13 @@ export function addSplat(wall, canvas, src, opts = {}) {
|
|
|
373
373
|
prepareSource() {
|
|
374
374
|
throw new Error("@displayxr/inline3d/splat: prepareSource() is implemented on the PlayCanvas backend only.");
|
|
375
375
|
},
|
|
376
|
+
/** Not on this backend: the live rig switch is a PlayCanvas-backend feature. */
|
|
377
|
+
setRig() {
|
|
378
|
+
throw new Error(
|
|
379
|
+
"@displayxr/inline3d/splat: setRig() is implemented on the PlayCanvas backend only " +
|
|
380
|
+
"(addSplat(…, { engine:'playcanvas' })).",
|
|
381
|
+
);
|
|
382
|
+
},
|
|
376
383
|
/** Not on this backend (splat effects are PlayCanvas-only in this version). */
|
|
377
384
|
playEffect() {
|
|
378
385
|
throw effectsNotOnSpark('playEffect()');
|
|
@@ -657,6 +664,16 @@ export function addSplat(wall, canvas, src, opts = {}) {
|
|
|
657
664
|
* Fields (`viewer`, `mesh`, `rig`, …) are null until then; `viewer` in particular appears one
|
|
658
665
|
* module-load later than on Spark.
|
|
659
666
|
*/
|
|
667
|
+
/** setRig's type/options shape, checked at the call before the adapter has loaded (it re-checks all of it). */
|
|
668
|
+
function validateSetRigArgs(type, o) {
|
|
669
|
+
if (!['display', 'camera', 'auto'].includes(type)) {
|
|
670
|
+
throw new Error(`@displayxr/inline3d/splat: setRig("${type}") — expected 'display', 'camera' or 'auto'.`);
|
|
671
|
+
}
|
|
672
|
+
if (o !== undefined && (o === null || typeof o !== 'object')) {
|
|
673
|
+
throw new TypeError('@displayxr/inline3d/splat: setRig options must be an object.');
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
660
677
|
function addSplatDeferred(wall, canvas, src, opts) {
|
|
661
678
|
const pending = [];
|
|
662
679
|
const queue = (name) => (...args) => {
|
|
@@ -711,6 +728,14 @@ function addSplatDeferred(wall, canvas, src, opts) {
|
|
|
711
728
|
// setSource replaces this stub on the same object by then).
|
|
712
729
|
setSource: (...args) => out.ready.then(() => out.setSource(...args)),
|
|
713
730
|
prepareSource: (...args) => out.ready.then(() => out.prepareSource(...args)),
|
|
731
|
+
// A rig switch before the first asset has landed: validated now (controls:'page' and a bad
|
|
732
|
+
// type throw at the call's own line), applied once it has.
|
|
733
|
+
setRig: page
|
|
734
|
+
? pageOnly('setRig')
|
|
735
|
+
: (type, o) => {
|
|
736
|
+
validateSetRigArgs(type, o);
|
|
737
|
+
return out.ready.then(() => out.setRig(type, o));
|
|
738
|
+
},
|
|
714
739
|
// Effects before the adapter has loaded: validated NOW (a bad call throws at its own line),
|
|
715
740
|
// then run once the first asset is on screen.
|
|
716
741
|
playEffect: (name, o) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@displayxr/inline3d",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.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",
|
package/splat.d.ts
CHANGED
|
@@ -131,7 +131,8 @@ export interface SogCamera {
|
|
|
131
131
|
*/
|
|
132
132
|
export interface ResolvedRig {
|
|
133
133
|
type: 'camera' | 'display';
|
|
134
|
-
|
|
134
|
+
/** `'setRig'` after `handle.setRig('display' | 'camera')`; the waterfall's step otherwise. */
|
|
135
|
+
typeSource: 'caller' | 'block' | 'block-present' | 'default' | 'setRig';
|
|
135
136
|
rest: { position: number[]; rotation: number[] };
|
|
136
137
|
intrinsics: SogIntrinsics;
|
|
137
138
|
intrinsicsSource: 'block' | 'caller' | 'estimated' | 'fallback-28mm';
|
|
@@ -154,7 +155,14 @@ export interface ResolvedRig {
|
|
|
154
155
|
| 'median-disparity'
|
|
155
156
|
| 'default'
|
|
156
157
|
| 'picked'
|
|
157
|
-
| 'set'
|
|
158
|
+
| 'set'
|
|
159
|
+
| 'frame';
|
|
160
|
+
/**
|
|
161
|
+
* On a display rig set by `handle.setRig('display')`: what it framed, in `handle.engine.root`'s
|
|
162
|
+
* space, and where that came from (the page's meshes, meshes + the shown splat, the splat alone,
|
|
163
|
+
* or the caller's `frame`). Absent otherwise.
|
|
164
|
+
*/
|
|
165
|
+
frame?: { center: number[]; extent: number[]; source: 'root' | 'root+splat' | 'splat' | 'caller' } | null;
|
|
158
166
|
/** The block's own `focus.source` string (e.g. `'convergence'`, `'cloud-median'`), for diagnostics. */
|
|
159
167
|
blockFocusSource: string | null;
|
|
160
168
|
/** Fraction of the central crop's opacity-weighted mass the winning clump carried (`nearest-clump` only). */
|
|
@@ -187,6 +195,13 @@ export interface SplatOptions {
|
|
|
187
195
|
* the knob for the weave's zero-copy read race on large canvases.
|
|
188
196
|
*/
|
|
189
197
|
preserveDrawingBuffer?: boolean;
|
|
198
|
+
/**
|
|
199
|
+
* `engine: 'playcanvas'` only: create the tile's WebGL context with MSAA (default false — it buys
|
|
200
|
+
* nothing on alpha-blended splats). Turn it on when the page draws meshes under
|
|
201
|
+
* `handle.engine.root` and wants addModel's silhouettes (addModel's context has MSAA on);
|
|
202
|
+
* `setRig('display')` is then pixel-identical to an addModel tile. Fixed at context creation.
|
|
203
|
+
*/
|
|
204
|
+
antialias?: boolean;
|
|
190
205
|
/**
|
|
191
206
|
* `engine: 'playcanvas'` only: the `playcanvas` module namespace to use instead of
|
|
192
207
|
* `import('playcanvas')` — for a page that already bundles its own copy.
|
|
@@ -374,6 +389,10 @@ export interface SplatParticleOptions {
|
|
|
374
389
|
* home; max 0.05). In 2D a nominal 64 mm-at-1.7 m separation is assumed.
|
|
375
390
|
*/
|
|
376
391
|
maxDisparity?: number;
|
|
392
|
+
/** Fade a particle over the first `vanish` of its flight (0 = off, the reveals' default; the particle transitions use ~0.3–0.45). */
|
|
393
|
+
vanish?: number;
|
|
394
|
+
/** Share of the gaussians drawn while in flight, 0..1 (1 = all, the reveals' default; the swarm uses 0.2). */
|
|
395
|
+
density?: number;
|
|
377
396
|
/** `order: 'layers'`: gaussians per layer (default 768² = 589 824, SHARP). */
|
|
378
397
|
layerSize?: number;
|
|
379
398
|
/** `assemble`: how far out the swarm starts (half-view-widths), its spiral (rad), its curl turbulence, how coherent its start field is (0..1), and how much of it reaches back in depth (0..1). */
|
|
@@ -486,6 +505,46 @@ export interface SplatEffectState {
|
|
|
486
505
|
progress: number;
|
|
487
506
|
}
|
|
488
507
|
|
|
508
|
+
/**
|
|
509
|
+
* `handle.setRig('display', opts)`'s options. Every default is addModel's, so a mesh framed this
|
|
510
|
+
* way renders exactly as `addModel(url, { engine: 'playcanvas' })` renders it.
|
|
511
|
+
* docs/playcanvas-adapter.md §setRig.
|
|
512
|
+
*/
|
|
513
|
+
export interface SplatSetRigDisplayOptions {
|
|
514
|
+
/** Default 0.24. */
|
|
515
|
+
virtualDisplayHeight?: number;
|
|
516
|
+
/** Default `'contain'`. */
|
|
517
|
+
fit?: 'contain' | 'cover' | 'height' | 'none';
|
|
518
|
+
/** Default 0.8. */
|
|
519
|
+
margin?: number;
|
|
520
|
+
/** Default 4. */
|
|
521
|
+
depthLimit?: number;
|
|
522
|
+
/** Default true. */
|
|
523
|
+
fitSweep?: boolean;
|
|
524
|
+
/** Idle turntable, °/s after 2.5 s without input. Default 8 (addModel's); 0 for a still product. */
|
|
525
|
+
idleSpin?: number;
|
|
526
|
+
/** On the declared display rig. Default 1 each. */
|
|
527
|
+
ipdFactor?: number;
|
|
528
|
+
parallaxFactor?: number;
|
|
529
|
+
perspectiveFactor?: number;
|
|
530
|
+
/**
|
|
531
|
+
* The eye camera's tone mapping WHILE THE SPLAT IS HIDDEN (the splat's display-referred colours
|
|
532
|
+
* keep `'none'` whenever it is shown). Default `'neutral'` — addModel's (Khronos PBR Neutral).
|
|
533
|
+
*/
|
|
534
|
+
toneMapping?: 'none' | 'linear' | 'neutral' | 'aces' | 'aces2' | 'filmic' | 'hejl';
|
|
535
|
+
/**
|
|
536
|
+
* `'room'` (default; `'neutral'` is the same): install addModel's generated neutral-studio IBL
|
|
537
|
+
* when the scene has no `envAtlas` of its own, removed again when the rig switches away. A page
|
|
538
|
+
* that lights its own meshes is never touched. `'none'`: never install it.
|
|
539
|
+
*/
|
|
540
|
+
environment?: 'room' | 'neutral' | 'none';
|
|
541
|
+
/**
|
|
542
|
+
* Frame THIS box (in `handle.engine.root`'s space) instead of measuring. Default: the enabled
|
|
543
|
+
* meshes under root (+ the splat's box when it is shown); with no meshes, the splat itself.
|
|
544
|
+
*/
|
|
545
|
+
frame?: { center: number[] | { x: number; y: number; z: number }; extent: number[] | { x: number; y: number; z: number } };
|
|
546
|
+
}
|
|
547
|
+
|
|
489
548
|
/** `setSource`'s options. */
|
|
490
549
|
export interface SplatSourceOptions {
|
|
491
550
|
/** > 0 = a crossfade of this length (the 1.10 option; same as `transition: 'crossfade'`). */
|
|
@@ -497,8 +556,15 @@ export interface SplatSourceOptions {
|
|
|
497
556
|
* inflates out of its own; default 2200 ms), `'wavefront'` (a soft front crosses left → right
|
|
498
557
|
* with a thin depth ridge riding it; default 2000 ms, ease-in-out; falls back to the crossfade
|
|
499
558
|
* in a hidden tab). For photo slideshows: `crossfade` or `wavefront`.
|
|
500
|
-
|
|
501
|
-
|
|
559
|
+
*
|
|
560
|
+
* The particle transitions (docs/splat-effects.md §Particle transitions): `'swarm'` (the old
|
|
561
|
+
* photo disperses into a curl-noise swarm while the new one assembles out of one), `'burst'`
|
|
562
|
+
* (the old one collapses into its focus, the new one bursts out of its own), `'shimmer-cross'`
|
|
563
|
+
* (nothing moves: twinkling points out, twinkling points in) and `'dust'` (drifting dust out,
|
|
564
|
+
* gathering dust in). 2.6–2.8 s, linear shared clock (each particle eases itself). The old
|
|
565
|
+
* photo is live, in 2D too; a hidden tab gets the crossfade.
|
|
566
|
+
*/
|
|
567
|
+
transition?: 'cut' | 'crossfade' | 'flip' | 'wavefront' | SplatParticleTransitionName;
|
|
502
568
|
durationMs?: number;
|
|
503
569
|
easing?: SplatEasing;
|
|
504
570
|
/** `cut`/`crossfade` only: reveal the INCOMING asset (entity scope) while the old one fades. */
|
|
@@ -519,8 +585,34 @@ export interface SplatSourceOptions {
|
|
|
519
585
|
* the single-camera RenderView path always use `'frozen'`.
|
|
520
586
|
*/
|
|
521
587
|
outgoing?: 'live' | 'frozen';
|
|
588
|
+
/** Particle transitions: particle options for BOTH photos (the shared ones of the particle reveals). */
|
|
589
|
+
order?: SplatParticleOptions['order'];
|
|
590
|
+
stagger?: number;
|
|
591
|
+
jitter?: number;
|
|
592
|
+
maxDisparity?: number;
|
|
593
|
+
dotSize?: number;
|
|
594
|
+
noiseScale?: number;
|
|
595
|
+
layerSize?: number;
|
|
596
|
+
origin?: SplatEffectOrigin;
|
|
597
|
+
/** Particle transitions: how much of the clock the two photos' spans share, 0..1 (0 = one after the other). */
|
|
598
|
+
overlap?: number;
|
|
599
|
+
/** Particle transitions: option overrides for the OUTGOING photo's effect. */
|
|
600
|
+
outgoingFx?: SplatParticleOptions & Record<string, unknown>;
|
|
601
|
+
/** Particle transitions: option overrides for the INCOMING photo's effect. */
|
|
602
|
+
incomingFx?: SplatParticleOptions & Record<string, unknown>;
|
|
522
603
|
}
|
|
523
604
|
|
|
605
|
+
/**
|
|
606
|
+
* `prepareSource`'s options: the `setSource` options the prepared asset will be swapped in with.
|
|
607
|
+
* For a particle transition, its shaders are compiled and linked NOW, in the dwell — otherwise the
|
|
608
|
+
* first transition of each kind in a page blocks its first frame on the link (tens of ms, hundreds
|
|
609
|
+
* the first time a machine sees the variant). Validated like setSource's.
|
|
610
|
+
*/
|
|
611
|
+
export type SplatPrepareOptions = SplatSourceOptions;
|
|
612
|
+
|
|
613
|
+
/** setSource's particle transitions (docs/splat-effects.md §Particle transitions). */
|
|
614
|
+
export type SplatParticleTransitionName = 'swarm' | 'burst' | 'shimmer-cross' | 'dust';
|
|
615
|
+
|
|
524
616
|
/**
|
|
525
617
|
* What `prepareSource()` resolves to: an opaque, single-use handle for `setSource`. The asset is
|
|
526
618
|
* fully resident (GPU textures + the engine's centre array) until used or disposed.
|
|
@@ -689,7 +781,20 @@ export interface SplatHandle {
|
|
|
689
781
|
* Memory: two full assets resident until the swap (≈ +70 MB of GPU textures per 1.18M-gaussian
|
|
690
782
|
* SOG). `remove()` disposes any still unused.
|
|
691
783
|
*/
|
|
692
|
-
prepareSource(src: string | Blob | ArrayBuffer | Uint8Array): Promise<SplatPreparedSource>;
|
|
784
|
+
prepareSource(src: string | Blob | ArrayBuffer | Uint8Array, opts?: SplatPrepareOptions): Promise<SplatPreparedSource>;
|
|
785
|
+
/**
|
|
786
|
+
* PlayCanvas backend only — throws on Spark, and with `controls:'page'` (the page's camera IS
|
|
787
|
+
* the rig). Switch the rig live, on the next frame: no remount, no reload, no new session.
|
|
788
|
+
*
|
|
789
|
+
* `'display'` frames the page's meshes under `handle.engine.root` (+ the splat when shown) on
|
|
790
|
+
* addModel's defaults and declares a display rig; `'camera'` returns to the asset's capture rig,
|
|
791
|
+
* re-resolved from the waterfall's own inputs (lens, captureFit, focus rung); `'auto'` is what
|
|
792
|
+
* the load resolved. The pose resets to the new rig's rest; the declared view rig switches with
|
|
793
|
+
* it; the choice is sticky across `setSource` until `'auto'`. A clean cut (no eased transition).
|
|
794
|
+
* `handle.rig.typeSource` reads `'setRig'`. Resolves once applied. docs/playcanvas-adapter.md §setRig.
|
|
795
|
+
*/
|
|
796
|
+
setRig(type: 'display', opts?: SplatSetRigDisplayOptions): Promise<SplatHandle>;
|
|
797
|
+
setRig(type: 'camera' | 'auto'): Promise<SplatHandle>;
|
|
693
798
|
/**
|
|
694
799
|
* `engine: 'playcanvas'` only (throws on Spark). Play a transition/pulse/custom effect;
|
|
695
800
|
* validated at the call, run once the first asset is on screen. Resolves `{ finished }` —
|