@displayxr/inline3d 1.13.1 → 1.15.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 CHANGED
@@ -5,6 +5,99 @@ 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.15.0 — 2026-09-24
9
+
10
+ Touches the **preview tier** (`./splat`, `engine: 'playcanvas'` only). Additive; the existing transitions
11
+ and reveals render the same pixels.
12
+
13
+ ### Added
14
+
15
+ - **Particle transitions for `setSource`** (#36): `transition: 'swarm' | 'burst' | 'shimmer-cross' | 'dust'`.
16
+ They play the particle reveals across a slide change, with both photos live, in 3D and in 2D.
17
+ The old photo plays its effect backwards while the new one plays it forwards, on overlapping
18
+ spans of one clock (`overlap`).
19
+ - `swarm`: the old photo disperses into a curl-noise swarm and the new one assembles out of one.
20
+ - `burst`: the old photo collapses into its focus and the new one bursts out of its own.
21
+ - `shimmer-cross`: twinkling points out and twinkling points in; nothing moves.
22
+ - `dust`: drifting dust out, gathering dust in.
23
+
24
+ Defaults are 2.6–2.8 s on a linear shared clock; each particle eases on its own path. The end
25
+ state is a `cut`, MAE 0.000 in colour and alpha in both eyes, and VRAM goes back to baseline.
26
+ A hidden tab gets the crossfade.
27
+ See [`docs/splat-effects.md` § Particle transitions](docs/splat-effects.md#particle-transitions).
28
+ - They render at RENDER TIME. One tile-scope chunk serves both photos, and each photo's values
29
+ sit on the mesh instance of the gsplat manager that draws it. A first cut used entity-scope
30
+ work-buffer modifiers, which rewrote both 1.18M work buffers and re-sorted both every frame.
31
+ Measured in a visible Chrome, that cost 2D pacing its 120 Hz: p95 went from 16.7 ms to 9.8–10.1.
32
+ A photo with nothing to draw skips its draw.
33
+ - **`prepareSource(src, { transition, … })`**: with a particle transition, this also compiles and
34
+ links its shaders in the dwell. Otherwise the first transition of each kind blocks its first
35
+ frame on the link: 35–50 ms, and 190 + 260 ms on a variant the machine has never compiled.
36
+ - Particle options `vanish` (fade over the first part of the flight) and `density` (the share
37
+ drawn in flight). Both are off for the reveals.
38
+
39
+ ### Not changed
40
+
41
+ - The live `crossfade` / `wavefront` still run at about 40 Hz in stereo on an M1 (median 25.6 ms).
42
+ They draw both photos in full for the whole window. The same skip-what-is-not-visible idea may
43
+ apply there; that is a follow-up.
44
+
45
+ ## 1.14.0 — 2026-09-24
46
+
47
+ Touches the **preview tier** (`./splat`, `engine: 'playcanvas'` only). New particle reveals are additive. One default changes pixels
48
+ DURING a transition in a woven 3D session (the old photo is now live); end states and 2D are
49
+ unchanged.
50
+
51
+ ### Changed
52
+
53
+ - **`crossfade` / `wavefront`: the outgoing photo is LIVE in a woven 3D session** (#36). Before, it
54
+ was a frozen frame for the whole window, and on a tracked panel a still image under a moving head
55
+ reads as "eye tracking hung, then resumed". The old asset now stays resident. A second camera
56
+ with its own layer, RenderViews and render target keeps rendering it through the same eye views,
57
+ and the overlay lerps or wipes the two live images per eye with the same maths as before. Measured
58
+ on the GPU with a fake 2-view wall, the old photo at four head poses matches its own plain render
59
+ with MAE 0.000 in both eyes, across the rig switch; 1.13.0 showed one image at every pose. End
60
+ state == `cut`, MAE 0.000, colour and alpha, both eyes. Cost: about 2× splat draw for the
61
+ window, and both assets resident (+73 MB of GPU textures at 1.18M gaussians).
62
+ `outgoing: 'frozen'` restores 1.13.0; it stays the default in 2D. See
63
+ [`docs/splat-effects.md` § Live or frozen outgoing](docs/splat-effects.md#live-or-frozen-outgoing).
64
+ - The frozen-frame texture is freed when a transition ends; it used to stay allocated (7 MB at
65
+ 2560×720).
66
+ - The framing pass (the percentile core per axis, then the window pass) runs in steps with yields
67
+ between them, with bit-identical results. It was a single 60–80 ms main-thread task per 1.18M
68
+ gaussians at 4× CPU. It now runs under 50 ms per step, so the longest task left in a load is the
69
+ engine's own centre readback (≈60 ms at 4×).
70
+
71
+ ### Added
72
+
73
+ - **`handle.prepareSource(src) → Promise<SplatPreparedSource>`**: fetch, decode and upload the next
74
+ asset in the background, without rendering it. The SDK's own passes run in idle periods. Then
75
+ `setSource(prepared, opts)` starts on the next frame, with no load on the transition path.
76
+ `prepared.dispose()`, single use; `remove()` disposes what is left.
77
+ Measured with 4× / 6× CPU throttling on an M1 (1,179,648 gaussians): from the `setSource` call to
78
+ the first transition frame, the longest main-thread task goes from 104 / 159 ms to none over 50 ms, and the
79
+ longest rAF gap from 138 / 196 ms to 18 / 17 ms. Memory: +22.5 MB of GPU textures plus the
80
+ engine's centre array (≈14 MB) per prepared 1.18M SOG, until used.
81
+ - `setSource`'s `outgoing: 'live' | 'frozen'` option; `SplatPreparedSource` in `splat.d.ts`.
82
+ - **Particle reveals** ([`docs/splat-effects.md` §Particle reveals](docs/splat-effects.md#particle-reveals)),
83
+ usable as `reveal: '<name>'`, `playEffect(name)` and `setSource(…, { reveal })`. Every gaussian is
84
+ a particle with its own start time:
85
+ - `assemble`: a swarm that flies home along spiralling curl-noise paths.
86
+ - `dissolve-in`: a dissolve played backwards; dust drifts in and gathers patch by patch.
87
+ - `converge`: a burst from the focus that flies out and settles.
88
+ - `shimmer`: twinkling points that grow into the picture.
89
+ - Options: `order` (`'radial'`, `'depth'`, `'noise'`, `'random'`, or `'layers'` for SHARP grid
90
+ order via `splat.index`, which is entity scope only), `stagger`, `jitter`, `dotSize`, `grow`,
91
+ `flightAlpha`, `color`/`glow`, `noiseScale`, plus per-effect shape options.
92
+ - Comfort cap `maxDisparity` (default 0.004 of the view width, exact at every depth; nominal
93
+ separation in 2D). The swarm never comes nearer the viewer than that.
94
+ - Every effect ends bit-identical to the plain render. Measured on the real GPU: MAE 0.000,
95
+ colour and alpha, mono and fake stereo, tile and entity scope; removal is exact too.
96
+ - In-flight particles are ~1 px dots until nearly home, which hides the engine's
97
+ original-centre sort order.
98
+ - The eye frame that effects receive now carries `tanHalfFovY` (internal; the `'radial'` key spans the
99
+ view actually seen).
100
+
8
101
  ## 1.13.1 — 2026-09-24
9
102
 
10
103
  Touches the **preview tier** (`./splat`, `engine: 'playcanvas'` only). No pixel change.
@@ -22,7 +115,6 @@ Touches the **preview tier** (`./splat`, `engine: 'playcanvas'` only). No pixel
22
115
  frame time at 4× CPU throttling went from 1.9–2.1 ms to 0.2–0.7 ms. GPU-synced frame time at 1×
23
116
  went from 16.0 ms to 14.4–14.6 ms, the same as after a `crossfade` (14.3–14.7 ms), which never
24
117
  had the bug.
25
-
26
118
  ## 1.13.0 — 2026-09-24
27
119
 
28
120
  Touches the **preview tier** (`./splat`, `engine: 'playcanvas'` only), additively. A page that
package/README.md CHANGED
@@ -55,9 +55,9 @@ so the unused ~40% of the engine tree-shakes away); its sort workers are Blob UR
55
55
 
56
56
  **Splat effects (preview, `engine: 'playcanvas'`).** Shader effects on the splats themselves,
57
57
  keyed on world position and time so both eyes agree: `addSplat(…, { reveal: 'inflate' | 'sweep' |
58
- 'dissolve' | 'fade' })` (plays once the tile is woven), `handle.playEffect` / `setEffect` /
59
- `stopEffect` / `effects()` (inflate, deflate, sweep, dissolve, fade, pulse, grade, clip, custom
60
- GLSL), and `setSource(src, { transition: 'crossfade' | 'flip' | 'wavefront', reveal })`. Spark
58
+ 'dissolve' | 'fade' | 'assemble' | 'dissolve-in' | 'converge' | 'shimmer' })` (plays once the tile
59
+ is woven; the last four are particle reveals), `handle.playEffect` / `setEffect` / `stopEffect` /
60
+ `effects()` (the reveals, deflate, pulse, grade, clip, custom GLSL), and `setSource(src, { transition: 'crossfade' | 'flip' | 'wavefront', reveal })`. Spark
61
61
  throws on all of them for now. [`docs/splat-effects.md`](docs/splat-effects.md).
62
62
 
63
63
  Splat and model rendering on the PlayCanvas backend uses the PlayCanvas engine (MIT); see
@@ -173,6 +173,7 @@ js/
173
173
  inline3d-model.js the three.js model backend (engine:'three'; ./model/three)
174
174
  inline3d-playcanvas-engine.js named playcanvas imports for both PlayCanvas adapters (tree-shaking)
175
175
  inline3d-splat-effects.js splat shader effects: the runner, the effect registry (PlayCanvas)
176
+ inline3d-splat-live.js setSource's live outgoing photo: its own camera, layer and target (PlayCanvas)
176
177
  from what the asset declares (you serve the decoder files — see the guide)
177
178
  docs/
178
179
  authoring-inline-3d.md the authoring guide
@@ -56,6 +56,8 @@ export {
56
56
  // setSource's frame snapshot
57
57
  RenderTarget,
58
58
  FILTER_NEAREST,
59
+ // setSource's live outgoing asset (./inline3d-splat-live.js)
60
+ Layer,
59
61
  // splats
60
62
  WORKBUFFER_UPDATE_AUTO,
61
63
  WORKBUFFER_UPDATE_ALWAYS,