@displayxr/inline3d 1.31.0 → 1.33.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/js/inline3d.js CHANGED
@@ -34,6 +34,8 @@ export { undock, undockAvailable, undockUrl, tileScreenRect };
34
34
  import { setSessionViewerEase } from './inline3d-viewer-ease.js';
35
35
  // The tracking-acquisition ease, for pages that render their own addScene from the views.
36
36
  export { ViewerEase, resolveViewerEaseOption, frameTrackingState, VIEWER_EASE_DEFAULT_MS } from './inline3d-viewer-ease.js';
37
+ export { DISPLAY_METRICS_DEFAULTS, displayMetricsFrom } from './inline3d-display-metrics.js';
38
+ import { displayMetricsFrom } from './inline3d-display-metrics.js';
37
39
 
38
40
  // The eased 2D<->3D transition. A pure state machine (no DOM, no WebXR) ported from the native
39
41
  // `dxr::ModeSwitch`, so the browser eases the disparity around a mode switch the same way — and in
@@ -133,6 +135,7 @@ const hasViewRig = () => {
133
135
  // required — a browser with a partial set is a browser mid-implementation, and treating it as
134
136
  // supported would hand a page a `requestRenderingMode is not a function` at the worst moment.
135
137
  const DISPLAY_MODE_METHODS = ['getDisplayInfo', 'getRenderingModes', 'requestRenderingMode'];
138
+
136
139
  // The two display events, fired on the XRSession rather than the layer — so a page hears about a
137
140
  // mode or hardware-state change even while its tile's layer is closed (lazy mode), and one
138
141
  // subscription covers every window in the document.
@@ -1088,6 +1091,24 @@ class Inline3D {
1088
1091
  * @returns {Promise<object|null>}
1089
1092
  */
1090
1093
  getDisplayInfo: () => this._layerCall(win, 'getDisplayInfo', 'getDisplayInfo()'),
1094
+ /**
1095
+ * This window in PHYSICAL units: the canvas's size in metres, metres per CSS px, the panel,
1096
+ * the nominal viewer distance and the eye separation — from getDisplayInfo(), with every
1097
+ * value that could not be measured filled from a stated default (see `source`). Never
1098
+ * rejects: no display API, no live layer, no glasses-free display all resolve the defaults.
1099
+ * The canvas size is re-read at each call (call it again after a resize).
1100
+ *
1101
+ * @returns {Promise<object>}
1102
+ */
1103
+ displayMetrics: async () => {
1104
+ let info = null;
1105
+ try {
1106
+ info = await this._layerCall(win, 'getDisplayInfo', 'getDisplayInfo()');
1107
+ } catch {
1108
+ /* no display API / no live layer: the defaults */
1109
+ }
1110
+ return displayMetricsFrom(info, canvas.getBoundingClientRect(), globalThis.devicePixelRatio || 1);
1111
+ },
1091
1112
  /**
1092
1113
  * Every rendering mode the runtime can put this display in, as reported by the runtime:
1093
1114
  * `{modeIndex, modeName, viewCount, viewScaleX, viewScaleY, tileColumns, tileRows,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@displayxr/inline3d",
3
- "version": "1.31.0",
3
+ "version": "1.33.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",
@@ -65,6 +65,7 @@
65
65
  "files": [
66
66
  "js/inline3d.js",
67
67
  "js/inline3d-undock.js",
68
+ "js/inline3d-display-metrics.js",
68
69
  "js/inline3d-mode-switch.js",
69
70
  "js/inline3d-buffer-limit.js",
70
71
  "js/inline3d-viewer-ease.js",
package/splat.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // EXPERIMENTAL — not covered by the 1.x semver promise. See docs/sdk-stability.md.
3
3
 
4
4
  import type { SceneViewer, SubjectBounds, OrbitPose } from './viewer.js';
5
- import type { FirstWovenResult, ViewerEaseOption } from './index.js';
5
+ import type { FirstWovenResult, ViewerEaseOption, DisplayMetrics } from './index.js';
6
6
 
7
7
  /**
8
8
  * The knobs behind `SplatOptions.perf`. Every one is a Spark 2.1.0 setting except `alphaRadius`,
@@ -174,8 +174,11 @@ export interface ResolvedRig {
174
174
  focusDistances: { subject_m: number | null; near_m: number | null; far_m: number | null } | null;
175
175
  /** Focus distance along the rest camera's view axis — the zero-disparity PLANE. */
176
176
  convergence: number;
177
+ /** In force — `setStereo`'s values when set, else `stereoDefault`'s. */
177
178
  ipdFactor: number;
178
179
  parallaxFactor: number;
180
+ /** The asset's own scalars (block `dxr`, else addSplat's options, else 1) — what `setStereo(null)` restores. PlayCanvas backend. */
181
+ stereoDefault?: { ipdFactor: number; parallaxFactor: number };
179
182
  }
180
183
 
181
184
  /**
@@ -731,6 +734,41 @@ export interface SplatSetRigDisplayOptions {
731
734
  frame?: { center: number[] | { x: number; y: number; z: number }; extent: number[] | { x: number; y: number; z: number } };
732
735
  }
733
736
 
737
+ /** A rectangle in canvas fractions: origin top-left, y DOWN (a DOM rect / canvas size). */
738
+ export interface SplatCanvasRect {
739
+ x: number;
740
+ y: number;
741
+ w: number;
742
+ h: number;
743
+ }
744
+
745
+ /** `handle.setDepthEnvelope`'s options. Metres are on the panel. */
746
+ export interface SplatDepthEnvelopeOptions {
747
+ /** The out-of-glass cap well inside the frame. Default 0.02. */
748
+ maxFrontM?: number;
749
+ /** The cap AT a stage edge / rect edge. Default 0.001 (clamped to `maxFrontM`). */
750
+ edgeM?: number;
751
+ /** Ramp width from `edgeM` to `maxFrontM`. Default 0.016. */
752
+ bandM?: number;
753
+ /** The window content may come out in. Default (or `null`): the whole canvas. */
754
+ stage?: SplatCanvasRect | null;
755
+ /** 2D elements over the canvas to keep flat around; `weight` 0..1 (default 1) fades one in/out. The 8 heaviest are kept. */
756
+ rects?: Array<SplatCanvasRect & { weight?: number }> | null;
757
+ /** Viewer distance override; default `nominalViewerPosition.z`, else 0.65. */
758
+ viewerM?: number | null;
759
+ /** Canvas physical size override, [w, h]; default the CSS box × the panel's metres per CSS px. */
760
+ canvasSizeM?: [number, number] | null;
761
+ }
762
+
763
+ /** `handle.setStereo`'s options. Each a finite number >= 0; `null` = back to the asset's own. */
764
+ export interface SplatStereoOptions {
765
+ ipdFactor?: number | null;
766
+ parallaxFactor?: number | null;
767
+ /** RELATIVE to the asset's own (`rig.stereoDefault`): re-applied to each asset `setSource` brings in. Exclusive with `ipdFactor`; the last one given wins. */
768
+ ipdScale?: number | null;
769
+ parallaxScale?: number | null;
770
+ }
771
+
734
772
  /** `setSource`'s options. */
735
773
  export interface SplatSourceOptions {
736
774
  /** > 0 = a crossfade of this length (the 1.10 option; same as `transition: 'crossfade'`). */
@@ -1017,6 +1055,36 @@ export interface SplatHandle {
1017
1055
  */
1018
1056
  setRig(type: 'display', opts?: SplatSetRigDisplayOptions): Promise<SplatHandle>;
1019
1057
  setRig(type: 'camera' | 'auto'): Promise<SplatHandle>;
1058
+ /**
1059
+ * PlayCanvas backend only — throws on Spark. Live stereo strength: re-declares the rig in force
1060
+ * with these scalars on the next frame, with NO cut (pose, focus and framing stay) — a depth
1061
+ * slider. A key given replaces; a key set to `null` returns to the asset's own value (the SOG
1062
+ * camera block's `dxr`, else addSplat's options, else 1); `setStereo(null)` clears both. Sticky
1063
+ * across `setSource` and `setRig`. On a camera rig the values are ABSOLUTE, exactly like
1064
+ * addSplat's `ipdFactor`/`parallaxFactor`; on a display rig they replace the declared display
1065
+ * rig's factors. `controls:'page'` applies them from the next tick. A stereo video holds its own
1066
+ * display rig; a value set meanwhile applies when the video exits. `handle.rig.ipdFactor` /
1067
+ * `parallaxFactor` read what is in force. The 2D↔3D mode-switch ramp still multiplies on top.
1068
+ */
1069
+ setStereo(opts: SplatStereoOptions | null): SplatHandle;
1070
+ /** This tile in physical units — the core `TileHandle.displayMetrics()`, on the splat handle. Never rejects. */
1071
+ displayMetrics(): Promise<DisplayMetrics>;
1072
+ /**
1073
+ * PlayCanvas backend only — throws on Spark. THE FRAME ENVELOPE: content may come OUT of the
1074
+ * glass only well inside the frame. At each screen spot the out-of-glass cap is
1075
+ * `edgeM + (maxFrontM − edgeM) · smoothstep(0, bandM, distance)`, where `distance` (metres on the
1076
+ * panel) is to the nearest `stage` edge or to any `rects` entry (weighted). A gaussian beyond the
1077
+ * cap slides back along its own ray from the declared camera rig (centre and scale together), so
1078
+ * the 2D picture is unchanged, the sort stays valid and both eyes agree; behind the glass is never
1079
+ * touched. Tile-wide and LIVE: every asset — an incoming one from its first frame, both sides of
1080
+ * a crossfade — is judged through the rig declared now (its convergence, lens, `ipdFactor` ×
1081
+ * `metersToVirtual`, so `setStereo` is accounted for). Camera rigs only (incl. `controls:'page'`);
1082
+ * inert on a display rig and while a stereo video holds the rig. Physical size comes from
1083
+ * `getDisplayInfo()` (see `displayMetrics()`), overridable with `canvasSizeM` / `viewerM`.
1084
+ * A key given replaces; `null` turns it off. Cheap to call per layout change: uniforms only.
1085
+ * docs/splat-effects.md §Depth envelope.
1086
+ */
1087
+ setDepthEnvelope(opts: SplatDepthEnvelopeOptions | null): SplatHandle;
1020
1088
  /**
1021
1089
  * PlayCanvas backend only — throws on Spark, and with `controls:'page'`. Play a stereo video ON
1022
1090
  * this handle: no new canvas, layer or session (docs/playcanvas-adapter.md §setVideo). The splat