@displayxr/inline3d 1.28.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 +233 -0
- package/README.md +10 -3
- package/call-full.d.ts +21 -0
- package/call.d.ts +328 -217
- package/camera.d.ts +257 -0
- package/dist/call.js +86 -0
- package/index.d.ts +27 -1
- package/js/call/capture.js +4 -167
- package/js/call/disparity.js +4 -0
- package/js/call/element.js +221 -0
- package/js/call/lift.js +9 -0
- package/js/call/options.js +132 -0
- package/js/call/signaling.js +7 -202
- package/js/call/ui.js +106 -9
- package/js/call/wire.js +8 -147
- 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-full.js +48 -0
- package/js/inline3d-call.js +609 -318
- package/js/inline3d-camera.js +678 -0
- package/js/inline3d-player.js +646 -216
- package/js/inline3d-splat-deferred.js +153 -0
- package/js/inline3d-splat-pc-entry.js +45 -0
- package/js/inline3d-splat-playcanvas.js +46 -3
- package/js/inline3d-splat-video.js +328 -29
- package/js/inline3d-splat.js +2 -145
- package/js/inline3d.js +130 -1
- package/js/lift/index.js +15 -0
- package/package.json +39 -4
- package/player.d.ts +46 -2
- package/splat-playcanvas.d.ts +4 -0
- package/splat.d.ts +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,230 @@ entry points (`.`, `./three`) are frozen for 1.x, while the **scene subpaths** (
|
|
|
5
5
|
`./splat`, `./model`) are a preview tier whose options may change in any release. Entries below say
|
|
6
6
|
which tier they touch, because that is what tells you whether an upgrade can move your pixels.
|
|
7
7
|
|
|
8
|
+
## 1.30.0 — 2026-10-05
|
|
9
|
+
|
|
10
|
+
Touches the **preview tier** only (`./call`, `./call/full`, the new `./camera` and `./splat/playcanvas`). RFC 0003
|
|
11
|
+
**phase C2**: the `./call` public surface is trimmed to what a page needs (one warning release
|
|
12
|
+
for the old names), options are regrouped, theming gets a real API, and the stereo camera
|
|
13
|
+
becomes its own subpath. The core entry points are untouched.
|
|
14
|
+
|
|
15
|
+
### `./splat/playcanvas` — new preview subpath: splats without Spark/three on the page
|
|
16
|
+
|
|
17
|
+
- **`addSplat` from `@displayxr/inline3d/splat/playcanvas`** is `./splat`'s `addSplat` with the
|
|
18
|
+
engine fixed to `'playcanvas'`: same options, same synchronous handle. `./splat` imports `three`
|
|
19
|
+
and `@sparkjsdev/spark` statically (Spark is its default engine and its Spark path is
|
|
20
|
+
synchronous), so a page passing `engine: 'playcanvas'` there still downloaded both, measured at
|
|
21
|
+
~1.7 MB gzipped on displayxr.org. This entry imports neither. `playcanvas` is still loaded on
|
|
22
|
+
demand, at the first `addSplat`. Passing any other `engine` throws at the call.
|
|
23
|
+
- Internal: the deferred PlayCanvas handle moved from `inline3d-splat.js` to
|
|
24
|
+
`inline3d-splat-deferred.js`, shared by both entries. `./splat` behaves exactly as before.
|
|
25
|
+
- `test/splat-pc-entry.test.mjs` walks the entry's static import graph and fails on any bare
|
|
26
|
+
package import, so the property can't silently regress.
|
|
27
|
+
|
|
28
|
+
### `./camera` — new preview subpath (RFC 0003 §4)
|
|
29
|
+
|
|
30
|
+
- **`openCamera(opts)`** → a `StereoCamera`: device selection (`prefer: 'auto' | 'stereo' | 'mono'
|
|
31
|
+
| deviceId | MediaStream`, the `displayxrStereo` hint, the > 2.5:1 pair heuristic, the
|
|
32
|
+
busy-device skip), `calibration` / `rectify` (moved here from `./call`), `format` / `stereo`
|
|
33
|
+
(`{ rectified, baselineMm, horizontalFovDeg }`) / `stream` / `video`, `on('ended')` (revoked,
|
|
34
|
+
unplugged, taken — never fired by `close()`), `close()`. Rejects only when no camera opens, with
|
|
35
|
+
`code` `'camera-busy'` | `'permission-denied'` (new: a refused prompt / policy / insecure
|
|
36
|
+
context) | `'no-camera'`.
|
|
37
|
+
- **`addCameraView(wall, canvas, cam, { mirror, autoConverge, depth, aspect })`** — the self view:
|
|
38
|
+
woven on a 3D wall, flat elsewhere, mirrored **correctly** (each half mirrored AND the halves
|
|
39
|
+
swapped — pinned by a synthetic-pair test: a subject in front stays in front; the naive per-half
|
|
40
|
+
mirror is proven pseudoscopic). `autoConverge` runs the call's disparity tracker on the face.
|
|
41
|
+
- **`cam.capturePhoto({ type, quality, name })`** → `{ blob, width, height, layout, convergencePx,
|
|
42
|
+
stereo, suggestedName: '<base>_2x1.jpg', xmp }`: the RAW pair, with the stereo record written
|
|
43
|
+
INTO the JPEG as XMP (`dxr:` namespace — layout, columns×rows, convergence, baseline, FOV,
|
|
44
|
+
rectified, eye size, software). **`cam.record({ mimeType, mono, audio })`** → `stop()` →
|
|
45
|
+
`{ blob, mono?, suggestedName: '<base>_2x1.webm', monoSuggestedName?, convergencePx, tagged }`,
|
|
46
|
+
the record as `DXR_*` Matroska tags; `mono: true` adds a left-eye copy (Decision 13). Readers:
|
|
47
|
+
`readJpegStereoMeta`, `readWebmStereoMeta`, `readJpegXmp`, `parseStereoXmp`. Decision 9: the
|
|
48
|
+
metadata lives in the file, no sidecar. `suggestedName`, `isStereoCamera`, `CAMERA_SDK`.
|
|
49
|
+
- The call is built on it: `CallOptions.camera` accepts a `StereoCamera` (left open when the
|
|
50
|
+
call ends), `camera: 'auto'` opens one through `openCamera()`, and the call's self view IS an
|
|
51
|
+
`addCameraView` — one implementation of capture, mirroring and convergence. A camera that ends
|
|
52
|
+
under a call (`ended`) drops it to audio-only with "Retry camera".
|
|
53
|
+
- Also in the CDN bundle `dist/call.js` (~153 KB min now, was ~124). `camera.d.ts`,
|
|
54
|
+
`docs/camera.md`, `samples/camera/`.
|
|
55
|
+
|
|
56
|
+
### `./call` — the public surface (RFC 0003 §2)
|
|
57
|
+
|
|
58
|
+
**Renamed / regrouped options** (the 1.29 spelling still works for this release with one
|
|
59
|
+
`console.warn` per key; removed in 1.31):
|
|
60
|
+
|
|
61
|
+
| 1.29 | 1.30 |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `accent` | `theme.accent` |
|
|
64
|
+
| `tileAspect` | `theme.tileAspect` |
|
|
65
|
+
| `inviteBase`, `updateUrl` | `invite: { base, updateUrl }` |
|
|
66
|
+
| `browserUrl` | `landing: { browserUrl, allow2D }` |
|
|
67
|
+
| `maxLifted` | `liftOptions.max` |
|
|
68
|
+
| `calibration`, `rectify` | `openCamera({ calibration, rectify })` of `./camera`, passed as `camera` |
|
|
69
|
+
| `log` | `debug: true` + `diagnostics()` |
|
|
70
|
+
| `recoverSession`, `wallOptions` | removed — a call always recovers the document's session (`sharedInline3D()`) |
|
|
71
|
+
| `scrollIntoView` | removed — always on with `ui: true` |
|
|
72
|
+
|
|
73
|
+
**New options:** `theme` (`accent`, `ink`, `shell`, `danger`, `radius`, `font`, `tileAspect`,
|
|
74
|
+
`strings`) → CSS custom properties `--dxr-accent/-ink/-shell/-danger/-radius/-font` on the host
|
|
75
|
+
and the string table; `ui: 'tiles'` (badges + plates only); `layout: 'none'` (tiles carry
|
|
76
|
+
`data-dxr-peer`, `call.tile(id)` returns them, the grid box steps aside); `landing.allow2D`.
|
|
77
|
+
`<dxr-call>` attributes are unchanged (`accent`, `tile-aspect`, `invite-base`, `browser-url` map
|
|
78
|
+
to the new groups) plus `ui="tiles"`.
|
|
79
|
+
|
|
80
|
+
**Handle renames:** `cameraOff(on)` → `setCameraOff(on)` with **`cameraOff` now the boolean
|
|
81
|
+
getter**; `format` → `localFormat`; `join()` resolves `void`; **new** `tile(peerId)`,
|
|
82
|
+
`diagnostics()` (explicitly unstable: the wall, the transport, per-peer `hello` / `route` /
|
|
83
|
+
`convergencePx` / `autoConverge` / `lift` / `quality`, the lift pool). **Removed from the public
|
|
84
|
+
handle** (kept as non-enumerable getters that warn once, gone in 1.31): `wall`, `format`,
|
|
85
|
+
`sendHint`, `_debug`. `CallPeer` is trimmed to `id`, `format`, `display` (`'3D' | '2D→3D' |
|
|
86
|
+
'2D'`), `state`, `muted`, `cameraOff`, `speaking`; the rest is in `diagnostics()`.
|
|
87
|
+
`handle.state` no longer lists `'idle'`.
|
|
88
|
+
|
|
89
|
+
**Events:** `format` → **`display`** `{ id, display }` (the old event still fires for a listener
|
|
90
|
+
that subscribes to it, with a warning; gone in 1.31); `session` is internal (subscribing warns);
|
|
91
|
+
`left` carries `reason`. New types `CallErrorCode` (adds `'permission-denied'`), `CallWarningCode`,
|
|
92
|
+
`CallDisplay`, `CallTheme`, `CallStrings`, `LiftFunction`.
|
|
93
|
+
|
|
94
|
+
**Removed from the `./call` entry — 38 internal helpers**, each kept for this release as a
|
|
95
|
+
`@deprecated` wrapper that `console.warn`s once on first use (a primitive constant cannot warn)
|
|
96
|
+
and removed in 1.31; all stay importable by file path from `js/call/*.js` / `js/camera/*.js`:
|
|
97
|
+
`normalizeCallOptions`, `newRoomId`, `isValidRoomId`, `buildInviteLink`, `normalizeHello`,
|
|
98
|
+
`makeHello`, `routeFor`, `badgeFor`, `createLiveGate`, `convergenceShiftPx`, `lowPass`,
|
|
99
|
+
`clampShift`, `eyeCropRect`, `mirrorSwapOps`, `mirrorSwapPixels`, `maxBitrateKbps`,
|
|
100
|
+
`measureFocusDisparity`, `preferVideoCodecs`, `sortCodecCapabilities`, `VIDEO_CODEC_ORDER`,
|
|
101
|
+
`MeshTransport`, `clampMaxPeers`, `qrEncode`, `roomKey`, `SIGNAL_PROTOCOL`, `WIRE_VERSION`,
|
|
102
|
+
`CALL_SDK`, `PLATE_TEXT` (→ `theme.strings`), `CALL_ACCENTS` (→ `theme.accent` takes the names),
|
|
103
|
+
`normalizeMono3D`, `resolveLift`, `createLiftPool`, `createFrameWatch`, `liftConvergenceFor`,
|
|
104
|
+
`liftPriorityFor`, `setLiftPriority`, `defaultLiftSpecifier`, `LIFT_PRIORITY`. Types gone with
|
|
105
|
+
them: `CallHello`, `CallCalibration`, `CallRoute`, `Mono3DReason`, `CallMono3DInfo`,
|
|
106
|
+
`CallLiftHandle`, `CallLiftFunction` (→ `LiftFunction`), `LiftStreamPriority`, `CallLiftPool`.
|
|
107
|
+
**Stays public:** `mountCall`, `addCall`, `dxrSignaling`, `DXR_SIGNAL_DEFAULT`,
|
|
108
|
+
`parseInviteLink` (Decision 7), `DxrCallElement`, `defineCallElement`, `attrsToOpts`,
|
|
109
|
+
`CALL_EVENT_PREFIX` — 9 value exports (from 47).
|
|
110
|
+
|
|
111
|
+
Internal moves (no API): `js/call/capture.js` → `js/camera/capture.js`, `js/call/disparity.js` →
|
|
112
|
+
`js/camera/disparity.js`, the SBS geometry and convergence math → `js/camera/geometry.js` /
|
|
113
|
+
`js/camera/converge.js`, option normalisation → `js/call/options.js`; the old paths re-export.
|
|
114
|
+
|
|
115
|
+
### Gates (RFC 0003 §7, C2)
|
|
116
|
+
|
|
117
|
+
- **API snapshot:** `tools/api-surface.mjs` pins the public surface of `call.d.ts`,
|
|
118
|
+
`call-full.d.ts` and `camera.d.ts` in `test/api-snapshot/*.api.txt`; `npm test` (and CI) fail
|
|
119
|
+
when the surface changes without `node tools/api-surface.mjs --update` in the same change. The
|
|
120
|
+
deprecated set is part of the record, so 1.31's removal is a visible diff.
|
|
121
|
+
- **Snippets:** `tools/check-snippets.mjs` compiles every fenced `js`/`ts`/`jsx` block of
|
|
122
|
+
`docs/call.md` + `docs/camera.md` and every call/camera sample against the public `.d.ts` only
|
|
123
|
+
(and fails on a deprecated import); run by `npm test` where `typescript` is installed and by
|
|
124
|
+
CI's typecheck job.
|
|
125
|
+
- **Tests:** camera unit tests (the mirror-and-swap proof, XMP/WebM round-trips, error codes,
|
|
126
|
+
view routes), the surface tests (deprecation wrappers, legacy options, handle renames, theme /
|
|
127
|
+
strings / parts / `ui: 'tiles'` / `layout: 'none'`), and a headless Chrome e2e
|
|
128
|
+
(`npm run test:e2e:camera`: the mirrored pair's pixels on a mock woven wall, a JPEG whose XMP
|
|
129
|
+
parses, a WebM whose tags parse). Panel runs still required: the mirrored self view on glass,
|
|
130
|
+
an SBS photo opened in `/player`.
|
|
131
|
+
|
|
132
|
+
## 1.29.0 — 2026-09-30
|
|
133
|
+
|
|
134
|
+
Touches the **core** (additive: `sharedInline3D()`, `handle.rewoven()`) and the **preview tier**
|
|
135
|
+
(`./call` — RFC 0003 C1, the one-line path; `./player`, `./splat` `engine: 'playcanvas'`). One
|
|
136
|
+
**removal** in the preview tier: `peerjsCloud`. Otherwise additive; no change for a page that does
|
|
137
|
+
not call the new API.
|
|
138
|
+
|
|
139
|
+
### `./call` — the one-line path (RFC 0003 §1, phase C1)
|
|
140
|
+
|
|
141
|
+
- **`mountCall(el, opts?)`** — `addCall` with every argument optional: the wall is the document's
|
|
142
|
+
shared manager (`sharedInline3D()`, below), signalling defaults to the hosted server, the camera
|
|
143
|
+
to `'auto'`, the SDK chrome to on. `addCall(wall, container, opts)` stays as the explicit form.
|
|
144
|
+
A call's session recovery now re-opens through the shared manager too, so it joins a wall the
|
|
145
|
+
page re-created rather than opening a second session.
|
|
146
|
+
- **`<dxr-call>`** — the same thing as markup, registered by importing `./call` (or `./call/full`,
|
|
147
|
+
or the CDN bundle): mounts on connect, `leave()`s on disconnect (a DOM move IS a teardown —
|
|
148
|
+
woven-canvas rule 2), re-dispatches every call event as a bubbling, composed `CustomEvent`
|
|
149
|
+
named `dxr-call:<event>` with the payload in `detail`, and exposes the handle as `el.call`
|
|
150
|
+
(plus a `ready` promise). Attributes are the string-typed options: `room`, `signaling` (a
|
|
151
|
+
URL), `key`, `camera`, `layout`, `accent`, `max-peers`, `no-ui`, `auto-join`, `mono3d="off"`,
|
|
152
|
+
`no-audio`, `no-self-view`, `no-auto-converge`, `tile-aspect`, `invite-base`, `browser-url`,
|
|
153
|
+
`debug`; anything else is `el.options = { … }`, set before connect (options win). Light DOM, no
|
|
154
|
+
shadow root, **no globals** (RFC 0003 Decision 11). `auto-join` joins during the mount, so the
|
|
155
|
+
element replays `joined` and one `peer` per participant already in the room once it can
|
|
156
|
+
subscribe. Exported: `DxrCallElement`, `defineCallElement`, `attrsToOpts`, `CALL_EVENT_PREFIX`.
|
|
157
|
+
- **`@displayxr/inline3d/call/full`** — `./call` with `mono3D` defaulted to a **statically
|
|
158
|
+
imported** `lift`, the one shape a bundler can follow; importing it also points `<dxr-call>` at
|
|
159
|
+
that `mountCall`. `liftBundled` says whether this copy of the SDK carries the module. **Until
|
|
160
|
+
`./lift` lands on `main`, `js/lift/index.js` is a placeholder** (`lift === null`): the entry
|
|
161
|
+
builds and behaves like `./call`, and `liftBundled` is `false`.
|
|
162
|
+
- **CDN bundle `dist/call.js`** — one pre-bundled ESM file (core + call + element, ~124 KB min,
|
|
163
|
+
no three/PlayCanvas), built by `npm run build:dist` (esbuild) and by `prepack` into every
|
|
164
|
+
published tarball, so jsDelivr serves it as `https://cdn.jsdelivr.net/npm/@displayxr/inline3d@1/dist/call.js`.
|
|
165
|
+
`<script type="module">` only; lift is a lazy sibling chunk (`dist/lift.js`) once the module
|
|
166
|
+
is present. `dist/` is not committed.
|
|
167
|
+
- **`warning` event, code `'lift-not-bundled'`** — a 2D participant is on a 3D display, `mono3D`
|
|
168
|
+
is `'auto'`, and the lift module could not be imported from this build (a bundler that could
|
|
169
|
+
not follow the computed import, or a copy without `./lift`). Emitted once per call with one
|
|
170
|
+
`console.warn` naming the fix (`mono3D: lift` or `./call/full`); the lobby reads "2D→3D
|
|
171
|
+
unavailable in this build". Previously a silent flat tile and an info line. A display that
|
|
172
|
+
honestly cannot lift is unchanged (`handle.mono3D.reason`).
|
|
173
|
+
- **`key`** — `dxrSignaling(url, { key })` / `CallOptions.key` / `<dxr-call key>`: a publishable
|
|
174
|
+
key for the hosted service (RFC 0003 §5a), sent as a query parameter on connect. Accepted and
|
|
175
|
+
forwarded now; the server ignores it until C3.
|
|
176
|
+
- **Removed: `peerjsCloud`** (RFC 0003 Decision 12 — no known external user, so no warning
|
|
177
|
+
release). The demo adapter over the public PeerJS broker lives on as
|
|
178
|
+
`samples/call/peerjs-cloud.js`; the sample's `?signal=peerjs` still works. `dxrSignaling()`
|
|
179
|
+
(the hosted server) has been the default since 1.28.
|
|
180
|
+
- **Types:** `mountCall`, `CallOptions.wall` / `.key`, `CallEvents.warning`, `DxrCallElement`,
|
|
181
|
+
`attrsToOpts`, `defineCallElement`, `DxrCallEventMap` (+ `HTMLElementTagNameMap` /
|
|
182
|
+
`HTMLElementEventMap` augmentations), `call-full.d.ts`.
|
|
183
|
+
- **Tests:** element unit tests (attribute→option table, events, disconnect = leave); a
|
|
184
|
+
headless Chrome ↔ Chrome end-to-end run of `<dxr-call>` (source and CDN bundle) over the
|
|
185
|
+
hosted server (`npm run test:e2e`); Vite/webpack/esbuild smoke builds of `./call/full` and
|
|
186
|
+
`./call` that also run the bundles (`npm run test:bundlers`). Neither is part of `npm test`.
|
|
187
|
+
|
|
188
|
+
### Core — additive
|
|
189
|
+
|
|
190
|
+
- **`sharedInline3D(opts?)`** — the document's shared manager: the live `createInline3D()`
|
|
191
|
+
result if one exists, else a new one (concurrent callers share one creation; an unsupported
|
|
192
|
+
browser is never cached). Woven-canvas rule 1 as an API: a module that needs a wall it did not
|
|
193
|
+
create (`mountCall`, `<dxr-call>`) uses this and never opens a second session next to the
|
|
194
|
+
page's own; a page that made its wall first gets that same wall back here. Semver-covered.
|
|
195
|
+
|
|
196
|
+
- **`./splat` `setVideo` crossfade, band and on-screen rect** (#105, RFC 0001 A5.1-A5.3,
|
|
197
|
+
`engine: 'playcanvas'`). `transition: 'crossfade'` (`durationMs` 600, `easing`
|
|
198
|
+
'easeInOutSine', the player's defaults) dissolves on the GPU from the video already on the plane:
|
|
199
|
+
its quad is frozen and drawn blended over the incoming one, the buffer opaque throughout; from the
|
|
200
|
+
splat and on `setVideo(null)` it stays a cut. `band: 2.39 | '2.39:1'` fits the picture into a
|
|
201
|
+
centred letterbox slot (`cover` fills the band and crops each eye about its centre). The result
|
|
202
|
+
gains `transition`, `band`, `rect` (the picture in CSS px, canvas-relative, clipped) and
|
|
203
|
+
`onRectChange(cb)`. `attachPlayer` now crossfades and takes `band` (controls in the bars) through
|
|
204
|
+
these instead of cutting / ignoring them. **Behaviour change for `attachPlayer(…, { skin: 'call' })`:**
|
|
205
|
+
that skin defaults `band` to 2.39, which surface mode used to ignore; the video now plays in a
|
|
206
|
+
2.39 letterbox. Pass `band: null` to keep the full tile.
|
|
207
|
+
- **`handle.rewoven()`** — `firstWoven`, measured from the call, for a canvas that is already woven
|
|
208
|
+
but whose rect is about to change (fullscreen, a layout resize). Same `{ woven, confirmed,
|
|
209
|
+
reason, ms }` shape, never rejects; a change of the canvas's CSS size or devicePixelRatio while
|
|
210
|
+
pending restarts the hold (checked every frame, every window kind), and it settles anyway with
|
|
211
|
+
the new reason `'hold-capped'` four holds after the call if the size never stops changing;
|
|
212
|
+
before the first join it is `firstWoven`. Woven-canvas rule 11.
|
|
213
|
+
- **Player: `fullscreenCover`** (opt-in, default false). Entering or leaving fullscreen puts an
|
|
214
|
+
opaque cover over the canvas (on top, hard cut, below the controls) until `rewoven()` settles.
|
|
215
|
+
Off by default because a blind A/B on the Leia panel showed no raw side-by-side pair without it
|
|
216
|
+
and ~1.2 s of no picture with it; the flash that did show is browser-wide (rule 11).
|
|
217
|
+
- **Docs:** woven-canvas rules 9–11 (black goes under the canvas — previously only in the
|
|
218
|
+
authoring guide; no `backdrop-filter` over the weave; a resize is a fresh-canvas moment). The
|
|
219
|
+
authoring guide's short list now matches, 1–11.
|
|
220
|
+
- **`attachPlayer(splat, src, opts)`** — surface mode (RFC 0001 Addendum A): the player's
|
|
221
|
+
transport, playlist and events on an existing PlayCanvas splat handle's `setVideo`, with no
|
|
222
|
+
canvas of its own. `detach()` gives the slot back (`setVideo(null)`: scene, pose, lens and rig
|
|
223
|
+
as they were); `'detached'` `{ reason: 'superseded' | 'released' }` when something else takes or
|
|
224
|
+
empties the slot. Cut transitions only for now; `fullscreen` defaults off. Panel-checked on one
|
|
225
|
+
persistent canvas: attach, next/back, detach, scene state identical after.
|
|
226
|
+
- **`addPlayer` refactor:** one player core on a surface adapter. No behaviour change.
|
|
227
|
+
- **`./splat`:** read-only `handle.videoElement` (the `<video>` the plane shows, or null) and
|
|
228
|
+
`handle.canvas`.
|
|
229
|
+
- **Types:** `attachPlayer`, `AttachPlayerOptions`, `AttachedPlayerHandle`, `PlayerDetachedEvent`,
|
|
230
|
+
`'detached'` in `PlayerEvent`; `SplatHandle.videoElement` / `.canvas`.
|
|
231
|
+
|
|
8
232
|
## 1.28.0 — 2026-09-27
|
|
9
233
|
|
|
10
234
|
Touches the **preview tier** (a new subpath, `./call`; the SBS store clamp below) and two **core**
|
|
@@ -39,6 +263,15 @@ clamped to the device's GL limits.
|
|
|
39
263
|
`setRenderScale` still accepts (0, 4]. `SceneViewer` gains `effectiveRenderScale`. Nothing changes
|
|
40
264
|
on a device whose limit holds the store.
|
|
41
265
|
|
|
266
|
+
### Added — call: auto-convergence on the point between the remote person's eyes
|
|
267
|
+
|
|
268
|
+
- SBS tiles now converge by MEASUREMENT: the receiver finds the disparity of the point between the
|
|
269
|
+
remote person's eyes in the decoded frames and shifts each eye by half of it, so that person sits at
|
|
270
|
+
the display plane. No calibration, works for any SBS sender. Tracks a small template after the first
|
|
271
|
+
lock (~1 ms per measurement at 5 Hz). `autoConverge: false` restores the pair as sent; the depth
|
|
272
|
+
slider stays an offset on top; lifted (mono) tiles are untouched. `measureFocusDisparity` is
|
|
273
|
+
exported for pages that want to reuse it.
|
|
274
|
+
|
|
42
275
|
### Fixed — core: image/video buffers capped at the source's per-eye resolution
|
|
43
276
|
|
|
44
277
|
- An image or video window's backing buffer was sized box x devicePixelRatio per eye regardless of
|
package/README.md
CHANGED
|
@@ -24,6 +24,8 @@ npm install @displayxr/inline3d
|
|
|
24
24
|
import { createInline3D } from '@displayxr/inline3d';
|
|
25
25
|
import { EyeCamera, EdgeFeather } from '@displayxr/inline3d/three'; // optional three.js glue
|
|
26
26
|
import { addSplat } from '@displayxr/inline3d/splat'; // experimental: 3DGS in a tile
|
|
27
|
+
// …or '@displayxr/inline3d/splat/playcanvas': the same addSplat on PlayCanvas, without the
|
|
28
|
+
// three + Spark download (use it whenever you pass engine: 'playcanvas')
|
|
27
29
|
import { addModel } from '@displayxr/inline3d/model'; // experimental: glTF/GLB in a tile
|
|
28
30
|
// (Draco / meshopt / KTX2 too —
|
|
29
31
|
// you serve the decoder files)
|
|
@@ -199,7 +201,8 @@ js/
|
|
|
199
201
|
inline3d-splat-live.js setSource's live outgoing photo: its own camera, layer and target (PlayCanvas)
|
|
200
202
|
from what the asset declares (you serve the decoder files — see the guide)
|
|
201
203
|
inline3d-player.js preview: addPlayer() — a media player window built on addVideo (stereo
|
|
202
|
-
paint, display modes and the fallback are inherited) + an SDK transport bar
|
|
204
|
+
paint, display modes and the fallback are inherited) + an SDK transport bar;
|
|
205
|
+
attachPlayer() — the same player on a PlayCanvas splat handle's setVideo
|
|
203
206
|
docs/
|
|
204
207
|
authoring-inline-3d.md the authoring guide
|
|
205
208
|
authoring-motion-and-effects.md
|
|
@@ -207,8 +210,12 @@ docs/
|
|
|
207
210
|
that is not the API
|
|
208
211
|
porting-three-js-apps.md porting an existing three.js app (WebXR or plain) to inline 3D —
|
|
209
212
|
the WebXR→inline-3d mapping table and the whole render loop
|
|
210
|
-
woven-canvas-rules.md never show a raw side-by-side frame: the join, the
|
|
211
|
-
handle.firstWoven, reading the browser's `withheld` log line
|
|
213
|
+
woven-canvas-rules.md never show a raw side-by-side frame: the join, the rules,
|
|
214
|
+
handle.firstWoven / rewoven(), reading the browser's `withheld` log line
|
|
215
|
+
camera.md The 3D camera primitive (/camera): openCamera, the mirrored self view,
|
|
216
|
+
capturePhoto / record with the stereo record inside the file.
|
|
217
|
+
call.md 3D video calls: the <dxr-call> / mountCall() one-line embed, options,
|
|
218
|
+
events, headless, theming, React, self-hosting, troubleshooting
|
|
212
219
|
proposals/ browser-side asks the SDK is waiting on
|
|
213
220
|
```
|
|
214
221
|
|
package/call-full.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Type definitions for @displayxr/inline3d/call/full — the call entry with 2D→3D bundled.
|
|
2
|
+
// PREVIEW tier — not covered by the 1.x semver promise. See docs/sdk-stability.md.
|
|
3
|
+
//
|
|
4
|
+
// Same surface as `./call` (re-exported), except `mountCall` / `addCall` default `mono3D` to a
|
|
5
|
+
// STATICALLY imported `lift` (`./lift`), which is what lets a bundler ship it. Use this entry in a
|
|
6
|
+
// bundled app that wants 2D participants lifted to 3D; use `./call` when you do not want the
|
|
7
|
+
// depth-model plumbing (it then warns `lift-not-bundled` the first time a 2D peer would have been
|
|
8
|
+
// lifted on a 3D display). Importing this entry also points `<dxr-call>` at this `mountCall`.
|
|
9
|
+
|
|
10
|
+
import type { CallHandle, CallOptions } from './call.js';
|
|
11
|
+
|
|
12
|
+
export * from './call.js';
|
|
13
|
+
|
|
14
|
+
/** True when this copy of the SDK carries the lift module; false on a build where `./lift` has not landed yet. */
|
|
15
|
+
export const liftBundled: boolean;
|
|
16
|
+
|
|
17
|
+
/** `mountCall` of `./call` with `mono3D` defaulted to the bundled `lift` (unless you pass your own). */
|
|
18
|
+
export function mountCall(el: HTMLElement, opts?: CallOptions): Promise<CallHandle>;
|
|
19
|
+
|
|
20
|
+
/** `addCall` of `./call` with `mono3D` defaulted to the bundled `lift` (unless you pass your own). */
|
|
21
|
+
export function addCall(wall: unknown, container: HTMLElement, opts?: CallOptions): Promise<CallHandle>;
|