@displayxr/inline3d 1.47.4 → 1.47.6

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 CHANGED
@@ -7,6 +7,81 @@ which tier they touch, because that is what tells you whether an upgrade can mov
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 1.47.6 — 2026-11-03
11
+
12
+ ### Fixed — a page that destroys PlayCanvas materials no longer keeps their programs (`./splat`, `./model`)
13
+
14
+ Preview tier. When a page destroys a material on a PlayCanvas tile the SDK created, either
15
+ directly or through a glTF container's `asset.unload()`, the SDK now destroys the programs that
16
+ material linked, one frame later, when no mesh instance in the app, no material asset in the
17
+ registry and no still-alive material holds them. A page that follows the engine's own teardown
18
+ (`entity.destroy()` plus destroying or unloading what it drew with) is bounded without calling
19
+ `handle.releaseEntity`. Measured on macOS, 24 swaps of distinct products under one tile: 2 live
20
+ programs (25 created, 23 deleted), against 25 (none deleted) before. A kiosk app with one
21
+ persistent stage had reached 170 live programs over 28 screen changes.
22
+
23
+ Content shown again after its material was destroyed recompiles on its first draw
24
+ (`handle.warmEntity` hides that). A material the page keeps alive keeps its programs.
25
+ `?dxrdiag=keepprograms` turns the release off for an A/B, and the overlay shows
26
+ `release patched (−N)`. It installs only on PlayCanvas 2.22.x's `Material` shape and otherwise
27
+ reports `release skipped: …`. `docs/content-lifecycle-rules.md` rule 1 and §6 are updated.
28
+
29
+ ### Added — `handle.releaseEntity`: swap content in a PlayCanvas tile without leaking its programs (`./splat`, `./model`)
30
+
31
+ Preview tier. PlayCanvas never frees a shader program by itself: its `ProgramLibrary` caches every
32
+ variant for the device's life, and `Material.destroy()` (which `entity.destroy()` and a container's
33
+ `asset.unload()` reach) only empties `material.variants`. A page that swaps glTFs under
34
+ `handle.engine.root` (a carousel, a catalogue) therefore kept every program it ever showed, and a
35
+ desktop driver keeps each linked program's compiled form (about 5 MB per program, measured on one
36
+ Linux driver): a production page's GPU process grew about 8 MB/min for as long as it was open.
37
+
38
+ - `handle.releaseEntity(entity, { asset })` on `addSplat(…, { engine: 'playcanvas' })` and
39
+ PlayCanvas `addModel` handles: collects the programs the entity's materials linked, destroys the
40
+ entity, unloads its glTF container `asset` unless something else in the tile still draws from it,
41
+ then destroys each collected program nothing left uses (`Shader.destroy()`, the engine's own
42
+ release). Returns `{ programs, container }`. A no-op on Spark and three.
43
+ Measured over 24 distinct models: live programs 5 → 47 without it, bounded at 5–16 (the model on
44
+ screen) with it.
45
+
46
+ ### Fixed — the engine kept every compiled shader until the device died (`./splat`, `./model`)
47
+
48
+ Preview tier. PlayCanvas 2.22.3 keeps every compiled vertex and fragment shader in a
49
+ module-private cache keyed by source, and `WebglShader.destroy()` deletes only the program. So
50
+ even with the programs destroyed, two compiled shaders per program stayed (10 → 91 over the same 24
51
+ swaps). The SDK now counts, per cached shader, the programs that use it and deletes it with the last
52
+ one, on every PlayCanvas device it creates (`js/inline3d-pc-shader-cache.js`: a run-time patch of the
53
+ engine's `WebglShader` prototype, since the engine is the page's own dependency; it installs only on
54
+ the 2.22.x shape and otherwise steps aside). With `releaseEntity`, shaders stay at exactly twice the
55
+ live programs. `?dxrdiag=keepshaders` turns it off for an A/B.
56
+
57
+ ### Added — live GL object counts and a leak warning in `?dxrdiag` (`./splat`, `./model`)
58
+
59
+ The diagnostics overlay shows live programs and shaders on the tile's context (created and deleted
60
+ since diag attached) and the shader-cache fix's state; the dump carries them under `glObjects`. At
61
+ each content swap the SDK sees (`setSource`, a glTF container loaded into the tile's registry,
62
+ `releaseEntity`) it samples the live program count, and warns once when it has not dropped across
63
+ 10 swaps of one kind and rose at more than 60% of them. `addModel`'s PlayCanvas tile now honours
64
+ `?dxrdiag` too. Nothing runs when diag is off.
65
+
66
+ ### Docs
67
+
68
+ - New [`docs/content-lifecycle-rules.md`](docs/content-lifecycle-rules.md): what a swap must release,
69
+ PlayCanvas and three.js engine facts, the hook-and-plateau pass test, the SDK's own swap paths
70
+ measured, and what the SDK does vs what the page owns.
71
+
72
+ ## 1.47.5 — 2026-11-01
73
+
74
+ ### Fixed — the camera permission prime could open a phone lens and crash its camera (`./camera`, `./call`)
75
+
76
+ Before camera permission, `openCamera('auto')` primed on `{1280x720, facingMode: 'environment'}`.
77
+ On a phone whose lenses all report the same facing, that picked camera 0, one lens of the 3D
78
+ camera's pair, and on some phones a plain open of that lens, or its teardown, crashes the camera
79
+ service. The prime now asks for the default camera with no constraints. The DisplayXR Browser lists
80
+ its 3D camera first, so the prime opens the pair directly and no lens is opened. A desktop webcam is
81
+ still opened once and kept, and is then asked for the usual 1280x720 mode without a second start.
82
+ With labels visible but no 3D camera listed, the list is read once more before the fallback, since
83
+ a runtime 3D camera can appear late after a runtime restart.
84
+
10
85
  ## 1.47.4 — 2026-10-31
11
86
 
12
87
  ### Fixed — a declared 3D camera with portrait eyes was dropped for a plain one (`./camera`, `./call`)
package/README.md CHANGED
@@ -166,7 +166,8 @@ No projection math lands in your page or in the SDK — the off-axis frustum sta
166
166
  Full API + authoring guidance: [`docs/authoring-inline-3d.md`](docs/authoring-inline-3d.md).
167
167
  Before you ship a page that navigates or remounts, read
168
168
  [`docs/woven-canvas-rules.md`](docs/woven-canvas-rules.md): how to avoid a raw side-by-side
169
- flash, and releasing a poster on `handle.firstWoven`.
169
+ flash, and releasing a poster on `handle.firstWoven`. A page that swaps content in a window (a
170
+ carousel, a catalogue): [`docs/content-lifecycle-rules.md`](docs/content-lifecycle-rules.md).
170
171
  Three.js glue (an off-axis `EyeCamera`) in [`js/inline3d-three.js`](js/inline3d-three.js).
171
172
 
172
173
  ## What's here
@@ -198,6 +199,8 @@ js/
198
199
  inline3d-model-entry.js experimental: addModel() — picks the engine (PlayCanvas default)
199
200
  inline3d-model-playcanvas.js the PlayCanvas model backend (Sample-Viewer lighting, engine decoders)
200
201
  inline3d-pc-look.js PlayCanvas look helpers for both adapters (environments, transmission)
202
+ inline3d-pc-release.js handle.releaseEntity: content under engine.root out, its programs + container released
203
+ inline3d-pc-shader-cache.js engine fix: a compiled shader is deleted with the last program using it
201
204
  inline3d-model.js the three.js model backend (engine:'three'; ./model/three)
202
205
  inline3d-playcanvas-engine.js named playcanvas imports for both PlayCanvas adapters (tree-shaking)
203
206
  inline3d-splat-effects.js splat shader effects: the runner, the effect registry (PlayCanvas)
@@ -215,6 +218,9 @@ docs/
215
218
  the WebXR→inline-3d mapping table and the whole render loop
216
219
  woven-canvas-rules.md never show a raw side-by-side frame: the join, the rules,
217
220
  handle.firstWoven / rewoven(), reading the browser's `withheld` log line
221
+ content-lifecycle-rules.md
222
+ release what a content swap replaces (programs included):
223
+ handle.releaseEntity, engine facts, the hook-and-plateau pass test
218
224
  camera.md The 3D camera primitive (/camera): openCamera, the mirrored self view,
219
225
  capturePhoto / record with the stereo record inside the file.
220
226
  call.md 3D video calls: the <dxr-call> / mountCall() one-line embed, options,