@limrun/ui 0.18.2 → 0.20.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/README.md +173 -0
- package/dist/{GLTFLoader-C62L6gT7.mjs → GLTFLoader-BjfxfJc4.mjs} +1 -1
- package/dist/{GLTFLoader--3fP8K2r.js → GLTFLoader-Ccp1cQVL.js} +1 -1
- package/dist/components/remote-control.d.ts +22 -68
- package/dist/core/device-stream.d.ts +30 -0
- package/dist/core/jitter-buffer.d.ts +2 -0
- package/dist/core/playback-stats.d.ts +48 -0
- package/dist/core/playback-subscription.d.ts +7 -0
- package/dist/core/stream-options.d.ts +62 -0
- package/dist/core/stream-types.d.ts +66 -0
- package/dist/core/stream-utils.d.ts +6 -0
- package/dist/core/use-playback-stats.d.ts +4 -0
- package/dist/core-BhHpU_lr.mjs +2113 -0
- package/dist/core-DkhLItUD.js +2 -0
- package/dist/core.cjs +1 -0
- package/dist/core.d.ts +12 -0
- package/dist/core.js +21 -0
- package/dist/{duo-frame-B6jf62Rq.mjs → duo-frame-CMiDITQA.mjs} +3 -3
- package/dist/{duo-frame-DAmRgZuT.js → duo-frame-D9832t6H.js} +2 -2
- package/dist/duo-view-Bhr7zyWr.js +1 -0
- package/dist/{duo-view-DSZO0-zg.mjs → duo-view-tndcvbIi.mjs} +64 -64
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/lite.cjs +1 -1
- package/dist/lite.d.ts +1 -0
- package/dist/lite.js +7 -6
- package/dist/remote-control-BBgt4TkM.mjs +1145 -0
- package/dist/remote-control-GLVdY8Xa.js +1 -0
- package/package.json +15 -5
- package/dist/duo-view-hTVLMDcc.js +0 -1
- package/dist/remote-control-B3_Hzmx8.js +0 -2
- package/dist/remote-control-BFxEfAdr.mjs +0 -2774
package/README.md
CHANGED
|
@@ -16,6 +16,76 @@ logo is omitted. Pass your own images through the `assets` prop if you want fram
|
|
|
16
16
|
`onConnectionStateChange` reports `connecting`, `connected`, `reconnecting`, `failed`, and
|
|
17
17
|
`terminated` so a host can show status text without tracking the retry logic.
|
|
18
18
|
|
|
19
|
+
## Playback buffering
|
|
20
|
+
|
|
21
|
+
`jitterBufferTargetMs` sets a preferred browser jitter buffer duration for incoming
|
|
22
|
+
audio and video on Android and iOS streams. It accepts finite numbers from 0 to
|
|
23
|
+
4000 milliseconds. For example:
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
<RemoteControl url={instanceWebsocketUrl} token={instanceToken} jitterBufferTargetMs={50} />
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The default is the browser's automatic buffering. Changing the prop updates active
|
|
30
|
+
receivers without reconnecting and applies to new receivers after a reconnect.
|
|
31
|
+
Remove the prop or set it to `null` to restore automatic buffering. Browsers without
|
|
32
|
+
`RTCRtpReceiver.jitterBufferTarget` ignore the prop. Invalid values produce a console
|
|
33
|
+
warning and leave the receiver's previous target unchanged.
|
|
34
|
+
|
|
35
|
+
The target is a preference, not a maximum buffer size or an end-to-end latency
|
|
36
|
+
guarantee. A lower value can reduce playback delay but increase dropped frames,
|
|
37
|
+
freezes, or audio interruptions on unstable connections. The browser can use a
|
|
38
|
+
different duration and can adjust gradually. Compare first-frame latency after idle,
|
|
39
|
+
steady playback, and drops or freezes on your target browsers and networks before
|
|
40
|
+
choosing a value. The example's 50 ms is not a recommended default.
|
|
41
|
+
|
|
42
|
+
## Playback measurements
|
|
43
|
+
|
|
44
|
+
Pass `onPlaybackStats` to receive browser measurements for incoming iOS and
|
|
45
|
+
Android streams, including phones, tablets, Apple Watch, and both Duo displays.
|
|
46
|
+
The callback and its types are available from `@limrun/ui` and `@limrun/ui/lite`.
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import { useState } from 'react';
|
|
50
|
+
import { RemoteControl, type PlaybackStats } from '@limrun/ui';
|
|
51
|
+
|
|
52
|
+
function Player({ url, token }: { url: string; token: string }) {
|
|
53
|
+
const [stats, setStats] = useState<PlaybackStats | null>(null);
|
|
54
|
+
const primary = stats?.video.find((video) => video.display === 'primary');
|
|
55
|
+
return (
|
|
56
|
+
<>
|
|
57
|
+
<RemoteControl url={url} token={token} onPlaybackStats={setStats} />
|
|
58
|
+
<output>Buffer delay: {primary?.bufferDelayMs?.toFixed(1) ?? '—'} ms</output>
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Collection uses the existing connection about every two seconds while the callback
|
|
65
|
+
is set and the tab is visible. Removing the callback stops collection. A disconnect,
|
|
66
|
+
hidden tab, or collection error emits `null` once after a measurement. Resuming or
|
|
67
|
+
reconnecting starts a fresh baseline. Changing the callback function does not reconnect
|
|
68
|
+
or restart collection. No stats requests run without a subscriber.
|
|
69
|
+
|
|
70
|
+
`PlaybackStats` contains `video` and `audio` arrays, a Unix-millisecond `timestamp`,
|
|
71
|
+
`requestedTargetMs`, and optional selected-connection `rttMs`. A `null` target means
|
|
72
|
+
automatic buffering. An invalid target prop leaves this field undefined. The requested
|
|
73
|
+
target does not confirm browser support or the duration actually used.
|
|
74
|
+
|
|
75
|
+
Each track has `id`, `trackId`, `timestamp`, and optional `intervalMs`,
|
|
76
|
+
`bufferDelayMs`, and `bitrateBps`. Video adds `display`, `fps`, `droppedFrames`, and
|
|
77
|
+
`freezes`. Duo's `primary` and `inner` displays stay separate. Audio is empty when
|
|
78
|
+
the connection has no incoming audio stream. Camera and microphone uploads are excluded.
|
|
79
|
+
|
|
80
|
+
Rates and counts describe the interval since that stream's previous sample.
|
|
81
|
+
Buffer delay divides the change in accumulated jitter-buffer delay by the change
|
|
82
|
+
in emitted frames or audio samples. FPS uses decoded frames; freezes count only
|
|
83
|
+
browser-reported freezes that have completed. Missing browser fields, the first
|
|
84
|
+
sample, and reset counters leave affected measurements undefined. A buffer with
|
|
85
|
+
no emitted frames has no delay measurement; it is not zero. Static screens may
|
|
86
|
+
have low FPS. These measurements do not include tap-to-screen latency or server
|
|
87
|
+
encoding time.
|
|
88
|
+
|
|
19
89
|
## Simulated cameras
|
|
20
90
|
|
|
21
91
|
`RemoteControl` responds automatically when an app in the instance opens,
|
|
@@ -118,3 +188,106 @@ Hardware meshes under `stationary-half` must carry `extras.button` with
|
|
|
118
188
|
`side`, `volumeUp`, or `volumeDown`. All three are required. This is a prepared Duo
|
|
119
189
|
appearance contract, not a general-purpose GLB viewer. Serve the file on the same
|
|
120
190
|
origin or with suitable CORS headers.
|
|
191
|
+
|
|
192
|
+
## Build a custom device viewer
|
|
193
|
+
|
|
194
|
+
Import `createDeviceStream` from `@limrun/ui/core` when you supply your own UI.
|
|
195
|
+
This browser entry has no React, CSS, or device-artwork imports. It uses the same
|
|
196
|
+
connection, input, playback, camera, microphone, and accessibility implementation
|
|
197
|
+
as `RemoteControl`. A browser WebView can use it too; it is not a Node.js WebRTC client.
|
|
198
|
+
|
|
199
|
+
Attach your video element before starting the session. Use the instance WebSocket
|
|
200
|
+
URL and instance token returned by the Limrun API, not your organization API key.
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import { createDeviceStream } from '@limrun/ui/core';
|
|
204
|
+
|
|
205
|
+
function mountDevice(video: HTMLVideoElement, url: string, token: string) {
|
|
206
|
+
video.autoplay = true;
|
|
207
|
+
video.playsInline = true;
|
|
208
|
+
video.muted = true;
|
|
209
|
+
|
|
210
|
+
const stream = createDeviceStream({
|
|
211
|
+
url,
|
|
212
|
+
token,
|
|
213
|
+
autoReconnect: true,
|
|
214
|
+
onStateChange: (state) => console.log(state.connection, state.controlReady),
|
|
215
|
+
onPlaybackStats: (stats) => console.log(stats),
|
|
216
|
+
});
|
|
217
|
+
stream.attachVideo(video);
|
|
218
|
+
stream.start();
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
home: () => stream.pressButton('home'),
|
|
222
|
+
screenshot: () => stream.screenshot(),
|
|
223
|
+
unmount: () => stream.dispose(),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
For a canvas or texture renderer, replace `attachVideo` with `attachFrameSink`.
|
|
229
|
+
The core owns the video element and playback workaround, then delivers decoded
|
|
230
|
+
frames. The frame is borrowed: draw or copy it before `present` returns.
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
stream.attachFrameSink({
|
|
234
|
+
present(source, width, height) {
|
|
235
|
+
if (canvas.width !== width) canvas.width = width;
|
|
236
|
+
if (canvas.height !== height) canvas.height = height;
|
|
237
|
+
canvas.getContext('2d')?.drawImage(source, 0, 0, width, height);
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Both attachment methods return a detach function. `stop()` closes the connection
|
|
243
|
+
and releases capture devices while retaining renderer attachments for `start()`.
|
|
244
|
+
`dispose()` also detaches every renderer and permanently closes the client.
|
|
245
|
+
Neither method terminates the Limrun instance.
|
|
246
|
+
|
|
247
|
+
Map your pointer events to frame pixels and call
|
|
248
|
+
`sendTouch(phase, x, y, width, height, pointerId)`. The phases are `begin`, `move`,
|
|
249
|
+
and `end`. Use `sendKeyEvent`, `sendText`, `pressButton`, and `rotate` for other
|
|
250
|
+
input. `sendControl` accepts messages built by the exported protocol helpers.
|
|
251
|
+
|
|
252
|
+
For Duo devices, attach a second renderer with display `'inner'`. The core
|
|
253
|
+
negotiates both tracks and reports the native display geometry through
|
|
254
|
+
`getState().duoState` and `onStateChange`. Use `sendDisplayTouch` with the native
|
|
255
|
+
`screenId` for panel input, or `sendDuoControl` for hinge and orientation commands.
|
|
256
|
+
|
|
257
|
+
Enable accessibility polling with `inspectMode: true`, receive snapshots with
|
|
258
|
+
`onAxSnapshotChange`, and request a fresh tree with `refreshAxTree()`. Camera and
|
|
259
|
+
microphone demand use the same browser permission prompts and callbacks as
|
|
260
|
+
`RemoteControl`. Your application remains responsible for instance creation and
|
|
261
|
+
termination, UI gestures, and any accessibility overlay.
|
|
262
|
+
|
|
263
|
+
### Connect through your own proxy
|
|
264
|
+
|
|
265
|
+
Supply a transport when your backend authenticates the upstream WebSocket.
|
|
266
|
+
Return a fresh socket on each call, since reconnects call `connect()` again.
|
|
267
|
+
The client owns and closes that socket. Supply `platform` explicitly because a
|
|
268
|
+
proxy URL does not identify the device kind.
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
const stream = createDeviceStream({
|
|
272
|
+
platform: 'ios',
|
|
273
|
+
autoReconnect: true,
|
|
274
|
+
transport: {
|
|
275
|
+
connect: () => new WebSocket(authenticatedProxyUrl),
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The proxy forwards Limrun's signaling messages unchanged. Video and control data
|
|
281
|
+
still travel over WebRTC. The core does not append a Limrun token to a custom
|
|
282
|
+
transport URL. You can fetch a fresh proxy ticket inside an asynchronous
|
|
283
|
+
`connect()` implementation.
|
|
284
|
+
|
|
285
|
+
If your backend can authoritatively report instance termination, implement
|
|
286
|
+
`transport.isTerminated(): Promise<boolean>`. Without it, proxy failures use the
|
|
287
|
+
normal retry policy. The core does not infer termination from a proxy's HTTP status.
|
|
288
|
+
|
|
289
|
+
Call `updateOptions` to change callbacks, accessibility polling, microphone
|
|
290
|
+
capture, reconnect policy, or the jitter buffer preference without replacing the
|
|
291
|
+
connection. A newly enabled `onTrace` callback takes effect on the next reconnect,
|
|
292
|
+
because tracing requires negotiation. Create a new client when changing the
|
|
293
|
+
instance, transport, platform, or session ID.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as Ae, a as G, F as he, M as w, V as fe, C as F, b, S as U, c as Le, P as Me, D as Se, d as K, e as C, I as ye, Q as de, f as we, O as pe, T as be, g as Ne, B as V, h as Ie, i as me, N as Oe, j as Ce, k as Fe, l as Q, m as ge, R as J, n as Pe, o as ke, p as He, q as z, r as De, s as Te, t as ve, u as v, v as Ge, w as Ue, x as Ke, y as Be, z as ee, A as je, E as Ve, G as ze, H as Xe, J as X, K as qe, U as We, W as Ye, X as Qe, Y as Je, Z as Ze, _ as $e, $ as Re, a0 as en, a1 as ne, a2 as te, a3 as se, a4 as ie, a5 as re, a6 as nn, a7 as tn, a8 as sn, a9 as rn, aa as on, ab as an } from "./duo-frame-
|
|
1
|
+
import { L as Ae, a as G, F as he, M as w, V as fe, C as F, b, S as U, c as Le, P as Me, D as Se, d as K, e as C, I as ye, Q as de, f as we, O as pe, T as be, g as Ne, B as V, h as Ie, i as me, N as Oe, j as Ce, k as Fe, l as Q, m as ge, R as J, n as Pe, o as ke, p as He, q as z, r as De, s as Te, t as ve, u as v, v as Ge, w as Ue, x as Ke, y as Be, z as ee, A as je, E as Ve, G as ze, H as Xe, J as X, K as qe, U as We, W as Ye, X as Qe, Y as Je, Z as Ze, _ as $e, $ as Re, a0 as en, a1 as ne, a2 as te, a3 as se, a4 as ie, a5 as re, a6 as nn, a7 as tn, a8 as sn, a9 as rn, aa as on, ab as an } from "./duo-frame-CMiDITQA.mjs";
|
|
2
2
|
function cn(f) {
|
|
3
3
|
const n = /* @__PURE__ */ new Map(), e = /* @__PURE__ */ new Map(), t = f.clone();
|
|
4
4
|
return Ee(f, t, function(s, i) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("./duo-frame-DAmRgZuT.js");function Q(d){const t=new Map,e=new Map,n=d.clone();return q(d,n,function(s,r){t.set(r,s),e.set(s,r)}),n.traverse(function(s){if(!s.isSkinnedMesh)return;const r=s,o=t.get(s),a=o.skeleton.bones;r.skeleton=o.skeleton.clone(),r.bindMatrix.copy(o.bindMatrix),r.skeleton.bones=a.map(function(i){return e.get(i)}),r.bind(r.skeleton,r.bindMatrix)}),n}function q(d,t,e){e(d,t);for(let n=0;n<d.children.length;n++)q(d.children[n],t.children[n],e)}class J extends h.Loader{constructor(t){super(t),this.dracoLoader=null,this.ktx2Loader=null,this.meshoptDecoder=null,this.pluginCallbacks=[],this.register(function(e){return new ne(e)}),this.register(function(e){return new se(e)}),this.register(function(e){return new fe(e)}),this.register(function(e){return new de(e)}),this.register(function(e){return new pe(e)}),this.register(function(e){return new ie(e)}),this.register(function(e){return new oe(e)}),this.register(function(e){return new ae(e)}),this.register(function(e){return new ce(e)}),this.register(function(e){return new te(e)}),this.register(function(e){return new le(e)}),this.register(function(e){return new re(e)}),this.register(function(e){return new he(e)}),this.register(function(e){return new ue(e)}),this.register(function(e){return new $(e)}),this.register(function(e){return new K(e,T.EXT_MESHOPT_COMPRESSION)}),this.register(function(e){return new K(e,T.KHR_MESHOPT_COMPRESSION)}),this.register(function(e){return new me(e)})}load(t,e,n,s){const r=this;let o;if(this.resourcePath!=="")o=this.resourcePath;else if(this.path!==""){const c=h.LoaderUtils.extractUrlBase(t);o=h.LoaderUtils.resolveURL(c,this.path)}else o=h.LoaderUtils.extractUrlBase(t);this.manager.itemStart(t);const a=function(c){s?s(c):console.error(c),r.manager.itemError(t),r.manager.itemEnd(t)},i=new h.FileLoader(this.manager);i.setPath(this.path),i.setResponseType("arraybuffer"),i.setRequestHeader(this.requestHeader),i.setWithCredentials(this.withCredentials),i.load(t,function(c){try{r.parse(c,o,function(u){e(u),r.manager.itemEnd(t)},a)}catch(u){a(u)}},n,a)}setDRACOLoader(t){return this.dracoLoader=t,this}setKTX2Loader(t){return this.ktx2Loader=t,this}setMeshoptDecoder(t){return this.meshoptDecoder=t,this}register(t){return this.pluginCallbacks.indexOf(t)===-1&&this.pluginCallbacks.push(t),this}unregister(t){return this.pluginCallbacks.indexOf(t)!==-1&&this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(t),1),this}parse(t,e,n,s){let r;const o={},a={},i=new TextDecoder;if(typeof t=="string")r=JSON.parse(t);else if(t instanceof ArrayBuffer)if(i.decode(new Uint8Array(t,0,4))===W){try{o[T.KHR_BINARY_GLTF]=new ge(t)}catch(l){s&&s(l);return}r=JSON.parse(o[T.KHR_BINARY_GLTF].content)}else r=JSON.parse(i.decode(t));else r=t;if(r.asset===void 0||r.asset.version[0]<2){s&&s(new Error("THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported."));return}const c=new Ne(r,{path:e||this.resourcePath||"",crossOrigin:this.crossOrigin,requestHeader:this.requestHeader,manager:this.manager,ktx2Loader:this.ktx2Loader,meshoptDecoder:this.meshoptDecoder});c.fileLoader.setRequestHeader(this.requestHeader);for(let u=0;u<this.pluginCallbacks.length;u++){const l=this.pluginCallbacks[u](c);l.name||console.error("THREE.GLTFLoader: Invalid plugin found: missing name"),a[l.name]=l,o[l.name]=!0}if(r.extensionsUsed)for(let u=0;u<r.extensionsUsed.length;++u){const l=r.extensionsUsed[u],f=r.extensionsRequired||[];switch(l){case T.KHR_MATERIALS_UNLIT:o[l]=new ee;break;case T.KHR_DRACO_MESH_COMPRESSION:o[l]=new Te(r,this.dracoLoader);break;case T.KHR_TEXTURE_TRANSFORM:o[l]=new Re;break;case T.KHR_MESH_QUANTIZATION:o[l]=new Me;break;default:f.indexOf(l)>=0&&a[l]===void 0&&console.warn('THREE.GLTFLoader: Unknown extension "'+l+'".')}}c.setExtensions(o),c.setPlugins(a),c.parse(n,s)}parseAsync(t,e){const n=this;return new Promise(function(s,r){n.parse(t,e,s,r)})}}function Z(){let d={};return{get:function(t){return d[t]},add:function(t,e){d[t]=e},remove:function(t){delete d[t]},removeAll:function(){d={}}}}function _(d,t,e){const n=d.json.materials[t];return n.extensions&&n.extensions[e]?n.extensions[e]:null}const T={KHR_BINARY_GLTF:"KHR_binary_glTF",KHR_DRACO_MESH_COMPRESSION:"KHR_draco_mesh_compression",KHR_LIGHTS_PUNCTUAL:"KHR_lights_punctual",KHR_MATERIALS_CLEARCOAT:"KHR_materials_clearcoat",KHR_MATERIALS_DISPERSION:"KHR_materials_dispersion",KHR_MATERIALS_IOR:"KHR_materials_ior",KHR_MATERIALS_SHEEN:"KHR_materials_sheen",KHR_MATERIALS_SPECULAR:"KHR_materials_specular",KHR_MATERIALS_TRANSMISSION:"KHR_materials_transmission",KHR_MATERIALS_IRIDESCENCE:"KHR_materials_iridescence",KHR_MATERIALS_ANISOTROPY:"KHR_materials_anisotropy",KHR_MATERIALS_UNLIT:"KHR_materials_unlit",KHR_MATERIALS_VOLUME:"KHR_materials_volume",KHR_TEXTURE_BASISU:"KHR_texture_basisu",KHR_TEXTURE_TRANSFORM:"KHR_texture_transform",KHR_MESH_QUANTIZATION:"KHR_mesh_quantization",KHR_MATERIALS_EMISSIVE_STRENGTH:"KHR_materials_emissive_strength",EXT_MATERIALS_BUMP:"EXT_materials_bump",EXT_TEXTURE_WEBP:"EXT_texture_webp",EXT_TEXTURE_AVIF:"EXT_texture_avif",EXT_MESHOPT_COMPRESSION:"EXT_meshopt_compression",KHR_MESHOPT_COMPRESSION:"KHR_meshopt_compression",EXT_MESH_GPU_INSTANCING:"EXT_mesh_gpu_instancing"};class ${constructor(t){this.parser=t,this.name=T.KHR_LIGHTS_PUNCTUAL,this.cache={refs:{},uses:{}}}_markDefs(){const t=this.parser,e=this.parser.json.nodes||[];for(let n=0,s=e.length;n<s;n++){const r=e[n];r.extensions&&r.extensions[this.name]&&r.extensions[this.name].light!==void 0&&t._addNodeRef(this.cache,r.extensions[this.name].light)}}_loadLight(t){const e=this.parser,n="light:"+t;let s=e.cache.get(n);if(s)return s;const r=e.json,i=((r.extensions&&r.extensions[this.name]||{}).lights||[])[t];let c;const u=new h.Color(16777215);i.color!==void 0&&u.setRGB(i.color[0],i.color[1],i.color[2],h.LinearSRGBColorSpace);const l=i.range!==void 0?i.range:0;switch(i.type){case"directional":c=new h.DirectionalLight(u),c.target.position.set(0,0,-1),c.add(c.target);break;case"point":c=new h.PointLight(u),c.distance=l;break;case"spot":c=new h.SpotLight(u),c.distance=l,i.spot=i.spot||{},i.spot.innerConeAngle=i.spot.innerConeAngle!==void 0?i.spot.innerConeAngle:0,i.spot.outerConeAngle=i.spot.outerConeAngle!==void 0?i.spot.outerConeAngle:Math.PI/4,c.angle=i.spot.outerConeAngle,c.penumbra=1-i.spot.innerConeAngle/i.spot.outerConeAngle,c.target.position.set(0,0,-1),c.add(c.target);break;default:throw new Error("THREE.GLTFLoader: Unexpected light type: "+i.type)}return c.position.set(0,0,0),w(c,i),i.intensity!==void 0&&(c.intensity=i.intensity),c.name=e.createUniqueName(i.name||"light_"+t),s=Promise.resolve(c),e.cache.add(n,s),s}getDependency(t,e){if(t==="light")return this._loadLight(e)}createNodeAttachment(t){const e=this,n=this.parser,r=n.json.nodes[t],a=(r.extensions&&r.extensions[this.name]||{}).light;return a===void 0?null:this._loadLight(a).then(function(i){return n._getNodeRef(e.cache,a,i)})}}class ee{constructor(){this.name=T.KHR_MATERIALS_UNLIT}getMaterialType(){return h.MeshBasicMaterial}extendParams(t,e,n){const s=[];t.color=new h.Color(1,1,1),t.opacity=1;const r=e.pbrMetallicRoughness;if(r){if(Array.isArray(r.baseColorFactor)){const o=r.baseColorFactor;t.color.setRGB(o[0],o[1],o[2],h.LinearSRGBColorSpace),t.opacity=o[3]}r.baseColorTexture!==void 0&&s.push(n.assignTexture(t,"map",r.baseColorTexture,h.SRGBColorSpace))}return Promise.all(s)}}class te{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_EMISSIVE_STRENGTH}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);return n===null||n.emissiveStrength!==void 0&&(e.emissiveIntensity=n.emissiveStrength),Promise.resolve()}}class ne{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_CLEARCOAT}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];if(n.clearcoatFactor!==void 0&&(e.clearcoat=n.clearcoatFactor),n.clearcoatTexture!==void 0&&s.push(this.parser.assignTexture(e,"clearcoatMap",n.clearcoatTexture)),n.clearcoatRoughnessFactor!==void 0&&(e.clearcoatRoughness=n.clearcoatRoughnessFactor),n.clearcoatRoughnessTexture!==void 0&&s.push(this.parser.assignTexture(e,"clearcoatRoughnessMap",n.clearcoatRoughnessTexture)),n.clearcoatNormalTexture!==void 0&&(s.push(this.parser.assignTexture(e,"clearcoatNormalMap",n.clearcoatNormalTexture)),n.clearcoatNormalTexture.scale!==void 0)){const r=n.clearcoatNormalTexture.scale;e.clearcoatNormalScale=new h.Vector2(r,r)}return Promise.all(s)}}class se{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_DISPERSION}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);return n===null||(e.dispersion=n.dispersion!==void 0?n.dispersion:0),Promise.resolve()}}class re{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_IRIDESCENCE}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];return n.iridescenceFactor!==void 0&&(e.iridescence=n.iridescenceFactor),n.iridescenceTexture!==void 0&&s.push(this.parser.assignTexture(e,"iridescenceMap",n.iridescenceTexture)),n.iridescenceIor!==void 0&&(e.iridescenceIOR=n.iridescenceIor),e.iridescenceThicknessRange===void 0&&(e.iridescenceThicknessRange=[100,400]),n.iridescenceThicknessMinimum!==void 0&&(e.iridescenceThicknessRange[0]=n.iridescenceThicknessMinimum),n.iridescenceThicknessMaximum!==void 0&&(e.iridescenceThicknessRange[1]=n.iridescenceThicknessMaximum),n.iridescenceThicknessTexture!==void 0&&s.push(this.parser.assignTexture(e,"iridescenceThicknessMap",n.iridescenceThicknessTexture)),Promise.all(s)}}class ie{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_SHEEN}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];if(e.sheenColor=new h.Color(0,0,0),e.sheenRoughness=0,e.sheen=1,n.sheenColorFactor!==void 0){const r=n.sheenColorFactor;e.sheenColor.setRGB(r[0],r[1],r[2],h.LinearSRGBColorSpace)}return n.sheenRoughnessFactor!==void 0&&(e.sheenRoughness=n.sheenRoughnessFactor),n.sheenColorTexture!==void 0&&s.push(this.parser.assignTexture(e,"sheenColorMap",n.sheenColorTexture,h.SRGBColorSpace)),n.sheenRoughnessTexture!==void 0&&s.push(this.parser.assignTexture(e,"sheenRoughnessMap",n.sheenRoughnessTexture)),Promise.all(s)}}class oe{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_TRANSMISSION}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];return n.transmissionFactor!==void 0&&(e.transmission=n.transmissionFactor),n.transmissionTexture!==void 0&&s.push(this.parser.assignTexture(e,"transmissionMap",n.transmissionTexture)),Promise.all(s)}}class ae{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_VOLUME}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];e.thickness=n.thicknessFactor!==void 0?n.thicknessFactor:0,n.thicknessTexture!==void 0&&s.push(this.parser.assignTexture(e,"thicknessMap",n.thicknessTexture)),e.attenuationDistance=n.attenuationDistance||1/0;const r=n.attenuationColor||[1,1,1];return e.attenuationColor=new h.Color().setRGB(r[0],r[1],r[2],h.LinearSRGBColorSpace),Promise.all(s)}}class ce{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_IOR}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);return n===null||(e.ior=n.ior!==void 0?n.ior:1.5),Promise.resolve()}}class le{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_SPECULAR}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];e.specularIntensity=n.specularFactor!==void 0?n.specularFactor:1,n.specularTexture!==void 0&&s.push(this.parser.assignTexture(e,"specularIntensityMap",n.specularTexture));const r=n.specularColorFactor||[1,1,1];return e.specularColor=new h.Color().setRGB(r[0],r[1],r[2],h.LinearSRGBColorSpace),n.specularColorTexture!==void 0&&s.push(this.parser.assignTexture(e,"specularColorMap",n.specularColorTexture,h.SRGBColorSpace)),Promise.all(s)}}class ue{constructor(t){this.parser=t,this.name=T.EXT_MATERIALS_BUMP}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];return e.bumpScale=n.bumpFactor!==void 0?n.bumpFactor:1,n.bumpTexture!==void 0&&s.push(this.parser.assignTexture(e,"bumpMap",n.bumpTexture)),Promise.all(s)}}class he{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_ANISOTROPY}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];return n.anisotropyStrength!==void 0&&(e.anisotropy=n.anisotropyStrength),n.anisotropyRotation!==void 0&&(e.anisotropyRotation=n.anisotropyRotation),n.anisotropyTexture!==void 0&&s.push(this.parser.assignTexture(e,"anisotropyMap",n.anisotropyTexture)),Promise.all(s)}}class fe{constructor(t){this.parser=t,this.name=T.KHR_TEXTURE_BASISU}loadTexture(t){const e=this.parser,n=e.json,s=n.textures[t];if(!s.extensions||!s.extensions[this.name])return null;const r=s.extensions[this.name],o=e.options.ktx2Loader;if(!o){if(n.extensionsRequired&&n.extensionsRequired.indexOf(this.name)>=0)throw new Error("THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures");return null}return e.loadTextureImage(t,r.source,o)}}class de{constructor(t){this.parser=t,this.name=T.EXT_TEXTURE_WEBP}loadTexture(t){const e=this.name,n=this.parser,s=n.json,r=s.textures[t];if(!r.extensions||!r.extensions[e])return null;const o=r.extensions[e],a=s.images[o.source];let i=n.textureLoader;if(a.uri){const c=n.options.manager.getHandler(a.uri);c!==null&&(i=c)}return n.loadTextureImage(t,o.source,i)}}class pe{constructor(t){this.parser=t,this.name=T.EXT_TEXTURE_AVIF}loadTexture(t){const e=this.name,n=this.parser,s=n.json,r=s.textures[t];if(!r.extensions||!r.extensions[e])return null;const o=r.extensions[e],a=s.images[o.source];let i=n.textureLoader;if(a.uri){const c=n.options.manager.getHandler(a.uri);c!==null&&(i=c)}return n.loadTextureImage(t,o.source,i)}}class K{constructor(t,e){this.name=e,this.parser=t}loadBufferView(t){const e=this.parser.json,n=e.bufferViews[t];if(n.extensions&&n.extensions[this.name]){const s=n.extensions[this.name],r=this.parser.getDependency("buffer",s.buffer),o=this.parser.options.meshoptDecoder;if(!o||!o.supported){if(e.extensionsRequired&&e.extensionsRequired.indexOf(this.name)>=0)throw new Error("THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files");return null}return r.then(function(a){const i=s.byteOffset||0,c=s.byteLength||0,u=s.count,l=s.byteStride,f=new Uint8Array(a,i,c);return o.decodeGltfBufferAsync?o.decodeGltfBufferAsync(u,l,f,s.mode,s.filter).then(function(p){return p.buffer}):o.ready.then(function(){const p=new ArrayBuffer(u*l);return o.decodeGltfBuffer(new Uint8Array(p),u,l,f,s.mode,s.filter),p})})}else return null}}class me{constructor(t){this.name=T.EXT_MESH_GPU_INSTANCING,this.parser=t}createNodeMesh(t){const e=this.parser.json,n=e.nodes[t];if(!n.extensions||!n.extensions[this.name]||n.mesh===void 0)return null;const s=e.meshes[n.mesh];for(const c of s.primitives)if(c.mode!==S.TRIANGLES&&c.mode!==S.TRIANGLE_STRIP&&c.mode!==S.TRIANGLE_FAN&&c.mode!==void 0)return null;const o=n.extensions[this.name].attributes,a=[],i={};for(const c in o)a.push(this.parser.getDependency("accessor",o[c]).then(u=>(i[c]=u,i[c])));return a.length<1?null:(a.push(this.parser.createNodeMesh(t)),Promise.all(a).then(c=>{const u=c.pop(),l=u.isGroup?u.children:[u],f=c[0].count,p=[];for(const m of l){const M=new h.Matrix4,g=new h.Vector3,R=new h.Quaternion,A=new h.Vector3(1,1,1),x=new h.InstancedMesh(m.geometry,m.material,f);for(let E=0;E<f;E++)i.TRANSLATION&&g.fromBufferAttribute(i.TRANSLATION,E),i.ROTATION&&R.fromBufferAttribute(i.ROTATION,E),i.SCALE&&A.fromBufferAttribute(i.SCALE,E),x.setMatrixAt(E,M.compose(g,R,A));for(const E in i)if(E==="_COLOR_0"){const L=i[E];x.instanceColor=new h.InstancedBufferAttribute(L.array,L.itemSize,L.normalized)}else E!=="TRANSLATION"&&E!=="ROTATION"&&E!=="SCALE"&&m.geometry.setAttribute(E,i[E]);h.Object3D.prototype.copy.call(x,m),this.parser.assignFinalMaterial(x),p.push(x)}return u.isGroup?(u.clear(),u.add(...p),u):p[0]}))}}const W="glTF",F=12,j={JSON:1313821514,BIN:5130562};class ge{constructor(t){this.name=T.KHR_BINARY_GLTF,this.content=null,this.body=null;const e=new DataView(t,0,F),n=new TextDecoder;if(this.header={magic:n.decode(new Uint8Array(t.slice(0,4))),version:e.getUint32(4,!0),length:e.getUint32(8,!0)},this.header.magic!==W)throw new Error("THREE.GLTFLoader: Unsupported glTF-Binary header.");if(this.header.version<2)throw new Error("THREE.GLTFLoader: Legacy binary file detected.");const s=this.header.length-F,r=new DataView(t,F);let o=0;for(;o<s;){const a=r.getUint32(o,!0);o+=4;const i=r.getUint32(o,!0);if(o+=4,i===j.JSON){const c=new Uint8Array(t,F+o,a);this.content=n.decode(c)}else if(i===j.BIN){const c=F+o;this.body=t.slice(c,c+a)}o+=a}if(this.content===null)throw new Error("THREE.GLTFLoader: JSON content not found.")}}class Te{constructor(t,e){if(!e)throw new Error("THREE.GLTFLoader: No DRACOLoader instance provided.");this.name=T.KHR_DRACO_MESH_COMPRESSION,this.json=t,this.dracoLoader=e,this.dracoLoader.preload()}decodePrimitive(t,e){const n=this.json,s=this.dracoLoader,r=t.extensions[this.name].bufferView,o=t.extensions[this.name].attributes,a={},i={},c={};for(const u in o){const l=B[u]||u.toLowerCase();a[l]=o[u]}for(const u in t.attributes){const l=B[u]||u.toLowerCase();if(o[u]!==void 0){const f=n.accessors[t.attributes[u]],p=O[f.componentType];c[l]=p.name,i[l]=f.normalized===!0}}return e.getDependency("bufferView",r).then(function(u){return new Promise(function(l,f){s.decodeDracoFile(u,function(p){for(const m in p.attributes){const M=p.attributes[m],g=i[m];g!==void 0&&(M.normalized=g)}l(p)},a,c,h.LinearSRGBColorSpace,f)})})}}class Re{constructor(){this.name=T.KHR_TEXTURE_TRANSFORM}extendTexture(t,e){return(e.texCoord===void 0||e.texCoord===t.channel)&&e.offset===void 0&&e.rotation===void 0&&e.scale===void 0||(t=t.clone(),e.texCoord!==void 0&&(t.channel=e.texCoord),e.offset!==void 0&&t.offset.fromArray(e.offset),e.rotation!==void 0&&(t.rotation=e.rotation),e.scale!==void 0&&t.repeat.fromArray(e.scale),t.needsUpdate=!0),t}}class Me{constructor(){this.name=T.KHR_MESH_QUANTIZATION}}class Y extends h.Interpolant{constructor(t,e,n,s){super(t,e,n,s)}copySampleValue_(t){const e=this.resultBuffer,n=this.sampleValues,s=this.valueSize,r=t*s*3+s;for(let o=0;o!==s;o++)e[o]=n[r+o];return e}interpolate_(t,e,n,s){const r=this.resultBuffer,o=this.sampleValues,a=this.valueSize,i=a*2,c=a*3,u=s-e,l=(n-e)/u,f=l*l,p=f*l,m=t*c,M=m-c,g=-2*p+3*f,R=p-f,A=1-g,x=R-f+l;for(let E=0;E!==a;E++){const L=o[M+E+a],b=o[M+E+i]*u,y=o[m+E+a],P=o[m+E]*u;r[E]=A*L+x*b+g*y+R*P}return r}}const Ee=new h.Quaternion;class xe extends Y{interpolate_(t,e,n,s){const r=super.interpolate_(t,e,n,s);return Ee.fromArray(r).normalize().toArray(r),r}}const S={POINTS:0,LINES:1,LINE_LOOP:2,LINE_STRIP:3,TRIANGLES:4,TRIANGLE_STRIP:5,TRIANGLE_FAN:6},O={5120:Int8Array,5121:Uint8Array,5122:Int16Array,5123:Uint16Array,5125:Uint32Array,5126:Float32Array},V={9728:h.NearestFilter,9729:h.LinearFilter,9984:h.NearestMipmapNearestFilter,9985:h.LinearMipmapNearestFilter,9986:h.NearestMipmapLinearFilter,9987:h.LinearMipmapLinearFilter},z={33071:h.ClampToEdgeWrapping,33648:h.MirroredRepeatWrapping,10497:h.RepeatWrapping},D={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT2:4,MAT3:9,MAT4:16},B={POSITION:"position",NORMAL:"normal",TANGENT:"tangent",TEXCOORD_0:"uv",TEXCOORD_1:"uv1",TEXCOORD_2:"uv2",TEXCOORD_3:"uv3",COLOR_0:"color",WEIGHTS_0:"skinWeight",JOINTS_0:"skinIndex"},N={scale:"scale",translation:"position",rotation:"quaternion",weights:"morphTargetInfluences"},Ae={CUBICSPLINE:void 0,LINEAR:h.InterpolateLinear,STEP:h.InterpolateDiscrete},G={OPAQUE:"OPAQUE",MASK:"MASK",BLEND:"BLEND"};function _e(d){return d.DefaultMaterial===void 0&&(d.DefaultMaterial=new h.MeshStandardMaterial({color:16777215,emissive:0,metalness:1,roughness:1,transparent:!1,depthTest:!0,side:h.FrontSide})),d.DefaultMaterial}function I(d,t,e){for(const n in e.extensions)d[n]===void 0&&(t.userData.gltfExtensions=t.userData.gltfExtensions||{},t.userData.gltfExtensions[n]=e.extensions[n])}function w(d,t){t.extras!==void 0&&(typeof t.extras=="object"?Object.assign(d.userData,t.extras):console.warn("THREE.GLTFLoader: Ignoring primitive type .extras, "+t.extras))}function Le(d,t,e){let n=!1,s=!1,r=!1;for(let c=0,u=t.length;c<u;c++){const l=t[c];if(l.POSITION!==void 0&&(n=!0),l.NORMAL!==void 0&&(s=!0),l.COLOR_0!==void 0&&(r=!0),n&&s&&r)break}if(!n&&!s&&!r)return Promise.resolve(d);const o=[],a=[],i=[];for(let c=0,u=t.length;c<u;c++){const l=t[c];if(n){const f=l.POSITION!==void 0?e.getDependency("accessor",l.POSITION):d.attributes.position;o.push(f)}if(s){const f=l.NORMAL!==void 0?e.getDependency("accessor",l.NORMAL):d.attributes.normal;a.push(f)}if(r){const f=l.COLOR_0!==void 0?e.getDependency("accessor",l.COLOR_0):d.attributes.color;i.push(f)}}return Promise.all([Promise.all(o),Promise.all(a),Promise.all(i)]).then(function(c){const u=c[0],l=c[1],f=c[2];return n&&(d.morphAttributes.position=u),s&&(d.morphAttributes.normal=l),r&&(d.morphAttributes.color=f),d.morphTargetsRelative=!0,d})}function Se(d,t){if(d.updateMorphTargets(),t.weights!==void 0)for(let e=0,n=t.weights.length;e<n;e++)d.morphTargetInfluences[e]=t.weights[e];if(t.extras&&Array.isArray(t.extras.targetNames)){const e=t.extras.targetNames;if(d.morphTargetInfluences.length===e.length){d.morphTargetDictionary={};for(let n=0,s=e.length;n<s;n++)d.morphTargetDictionary[e[n]]=n}else console.warn("THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.")}}function ye(d){let t;const e=d.extensions&&d.extensions[T.KHR_DRACO_MESH_COMPRESSION];if(e?t="draco:"+e.bufferView+":"+e.indices+":"+v(e.attributes):t=d.indices+":"+v(d.attributes)+":"+d.mode,d.targets!==void 0)for(let n=0,s=d.targets.length;n<s;n++)t+=":"+v(d.targets[n]);return t}function v(d){let t="";const e=Object.keys(d).sort();for(let n=0,s=e.length;n<s;n++)t+=e[n]+":"+d[e[n]]+";";return t}function U(d){switch(d){case Int8Array:return 1/127;case Uint8Array:return 1/255;case Int16Array:return 1/32767;case Uint16Array:return 1/65535;default:throw new Error("THREE.GLTFLoader: Unsupported normalized accessor component type.")}}function we(d){return d.search(/\.jpe?g($|\?)/i)>0||d.search(/^data\:image\/jpeg/)===0?"image/jpeg":d.search(/\.webp($|\?)/i)>0||d.search(/^data\:image\/webp/)===0?"image/webp":d.search(/\.ktx2($|\?)/i)>0||d.search(/^data\:image\/ktx2/)===0?"image/ktx2":"image/png"}const be=new h.Matrix4;class Ne{constructor(t={},e={}){this.json=t,this.extensions={},this.plugins={},this.options=e,this.cache=new Z,this.associations=new Map,this.primitiveCache={},this.nodeCache={},this.meshCache={refs:{},uses:{}},this.cameraCache={refs:{},uses:{}},this.lightCache={refs:{},uses:{}},this.sourceCache={},this.textureCache={},this.nodeNamesUsed={};let n=!1,s=-1,r=!1,o=-1;if(typeof navigator<"u"&&typeof navigator.userAgent<"u"){const a=navigator.userAgent;n=/^((?!chrome|android).)*safari/i.test(a)===!0;const i=a.match(/Version\/(\d+)/);s=n&&i?parseInt(i[1],10):-1,r=a.indexOf("Firefox")>-1,o=r?a.match(/Firefox\/([0-9]+)\./)[1]:-1}typeof createImageBitmap>"u"||n&&s<17||r&&o<98?this.textureLoader=new h.TextureLoader(this.options.manager):this.textureLoader=new h.ImageBitmapLoader(this.options.manager),this.textureLoader.setCrossOrigin(this.options.crossOrigin),this.textureLoader.setRequestHeader(this.options.requestHeader),this.fileLoader=new h.FileLoader(this.options.manager),this.fileLoader.setResponseType("arraybuffer"),this.options.crossOrigin==="use-credentials"&&this.fileLoader.setWithCredentials(!0)}setExtensions(t){this.extensions=t}setPlugins(t){this.plugins=t}parse(t,e){const n=this,s=this.json,r=this.extensions;this.cache.removeAll(),this.nodeCache={},this._invokeAll(function(o){return o._markDefs&&o._markDefs()}),Promise.all(this._invokeAll(function(o){return o.beforeRoot&&o.beforeRoot()})).then(function(){return Promise.all([n.getDependencies("scene"),n.getDependencies("animation"),n.getDependencies("camera")])}).then(function(o){const a={scene:o[0][s.scene||0],scenes:o[0],animations:o[1],cameras:o[2],asset:s.asset,parser:n,userData:{}};return I(r,a,s),w(a,s),Promise.all(n._invokeAll(function(i){return i.afterRoot&&i.afterRoot(a)})).then(function(){for(const i of a.scenes)i.updateMatrixWorld();t(a)})}).catch(e)}_markDefs(){const t=this.json.nodes||[],e=this.json.skins||[],n=this.json.meshes||[];for(let s=0,r=e.length;s<r;s++){const o=e[s].joints;for(let a=0,i=o.length;a<i;a++)t[o[a]].isBone=!0}for(let s=0,r=t.length;s<r;s++){const o=t[s];o.mesh!==void 0&&(this._addNodeRef(this.meshCache,o.mesh),o.skin!==void 0&&(n[o.mesh].isSkinnedMesh=!0)),o.camera!==void 0&&this._addNodeRef(this.cameraCache,o.camera)}}_addNodeRef(t,e){e!==void 0&&(t.refs[e]===void 0&&(t.refs[e]=t.uses[e]=0),t.refs[e]++)}_getNodeRef(t,e,n){if(t.refs[e]<=1)return n;const s=n.clone(),r=(o,a)=>{const i=this.associations.get(o);i!=null&&this.associations.set(a,i);for(const[c,u]of o.children.entries())r(u,a.children[c])};return r(n,s),s.name+="_instance_"+t.uses[e]++,s}_invokeOne(t){const e=Object.values(this.plugins);e.push(this);for(let n=0;n<e.length;n++){const s=t(e[n]);if(s)return s}return null}_invokeAll(t){const e=Object.values(this.plugins);e.unshift(this);const n=[];for(let s=0;s<e.length;s++){const r=t(e[s]);r&&n.push(r)}return n}getDependency(t,e){const n=t+":"+e;let s=this.cache.get(n);if(!s){switch(t){case"scene":s=this.loadScene(e);break;case"node":s=this._invokeOne(function(r){return r.loadNode&&r.loadNode(e)});break;case"mesh":s=this._invokeOne(function(r){return r.loadMesh&&r.loadMesh(e)});break;case"accessor":s=this.loadAccessor(e);break;case"bufferView":s=this._invokeOne(function(r){return r.loadBufferView&&r.loadBufferView(e)});break;case"buffer":s=this.loadBuffer(e);break;case"material":s=this._invokeOne(function(r){return r.loadMaterial&&r.loadMaterial(e)});break;case"texture":s=this._invokeOne(function(r){return r.loadTexture&&r.loadTexture(e)});break;case"skin":s=this.loadSkin(e);break;case"animation":s=this._invokeOne(function(r){return r.loadAnimation&&r.loadAnimation(e)});break;case"camera":s=this.loadCamera(e);break;default:if(s=this._invokeOne(function(r){return r!=this&&r.getDependency&&r.getDependency(t,e)}),!s)throw new Error("Unknown type: "+t);break}this.cache.add(n,s)}return s}getDependencies(t){let e=this.cache.get(t);if(!e){const n=this,s=this.json[t+(t==="mesh"?"es":"s")]||[];e=Promise.all(s.map(function(r,o){return n.getDependency(t,o)})),this.cache.add(t,e)}return e}loadBuffer(t){const e=this.json.buffers[t],n=this.fileLoader;if(e.type&&e.type!=="arraybuffer")throw new Error("THREE.GLTFLoader: "+e.type+" buffer type is not supported.");if(e.uri===void 0&&t===0)return Promise.resolve(this.extensions[T.KHR_BINARY_GLTF].body);const s=this.options;return new Promise(function(r,o){n.load(h.LoaderUtils.resolveURL(e.uri,s.path),r,void 0,function(){o(new Error('THREE.GLTFLoader: Failed to load buffer "'+e.uri+'".'))})})}loadBufferView(t){const e=this.json.bufferViews[t];return this.getDependency("buffer",e.buffer).then(function(n){const s=e.byteLength||0,r=e.byteOffset||0;return n.slice(r,r+s)})}loadAccessor(t){const e=this,n=this.json,s=this.json.accessors[t];if(s.bufferView===void 0&&s.sparse===void 0){const o=D[s.type],a=O[s.componentType],i=s.normalized===!0,c=new a(s.count*o);return Promise.resolve(new h.BufferAttribute(c,o,i))}const r=[];return s.bufferView!==void 0?r.push(this.getDependency("bufferView",s.bufferView)):r.push(null),s.sparse!==void 0&&(r.push(this.getDependency("bufferView",s.sparse.indices.bufferView)),r.push(this.getDependency("bufferView",s.sparse.values.bufferView))),Promise.all(r).then(function(o){const a=o[0],i=D[s.type],c=O[s.componentType],u=c.BYTES_PER_ELEMENT,l=u*i,f=s.byteOffset||0,p=s.bufferView!==void 0?n.bufferViews[s.bufferView].byteStride:void 0,m=s.normalized===!0;let M,g;if(p&&p!==l){const R=Math.floor(f/p),A="InterleavedBuffer:"+s.bufferView+":"+s.componentType+":"+R+":"+s.count;let x=e.cache.get(A);x||(M=new c(a,R*p,s.count*p/u),x=new h.InterleavedBuffer(M,p/u),e.cache.add(A,x)),g=new h.InterleavedBufferAttribute(x,i,f%p/u,m)}else a===null?M=new c(s.count*i):M=new c(a,f,s.count*i),g=new h.BufferAttribute(M,i,m);if(s.sparse!==void 0){const R=D.SCALAR,A=O[s.sparse.indices.componentType],x=s.sparse.indices.byteOffset||0,E=s.sparse.values.byteOffset||0,L=new A(o[1],x,s.sparse.count*R),b=new c(o[2],E,s.sparse.count*i);a!==null&&(g=new h.BufferAttribute(g.array.slice(),g.itemSize,g.normalized)),g.normalized=!1;for(let y=0,P=L.length;y<P;y++){const C=L[y];if(g.setX(C,b[y*i]),i>=2&&g.setY(C,b[y*i+1]),i>=3&&g.setZ(C,b[y*i+2]),i>=4&&g.setW(C,b[y*i+3]),i>=5)throw new Error("THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.")}g.normalized=m}return g})}loadTexture(t){const e=this.json,n=this.options,r=e.textures[t].source,o=e.images[r];let a=this.textureLoader;if(o.uri){const i=n.manager.getHandler(o.uri);i!==null&&(a=i)}return this.loadTextureImage(t,r,a)}loadTextureImage(t,e,n){const s=this,r=this.json,o=r.textures[t],a=r.images[e],i=(a.uri||a.bufferView)+":"+o.sampler;if(this.textureCache[i])return this.textureCache[i];const c=this.loadImageSource(e,n).then(function(u){u.flipY=!1,u.name=o.name||a.name||"",u.name===""&&typeof a.uri=="string"&&a.uri.startsWith("data:image/")===!1&&(u.name=a.uri);const f=(r.samplers||{})[o.sampler]||{};return u.magFilter=V[f.magFilter]||h.LinearFilter,u.minFilter=V[f.minFilter]||h.LinearMipmapLinearFilter,u.wrapS=z[f.wrapS]||h.RepeatWrapping,u.wrapT=z[f.wrapT]||h.RepeatWrapping,u.generateMipmaps=!u.isCompressedTexture&&u.minFilter!==h.NearestFilter&&u.minFilter!==h.LinearFilter,s.associations.set(u,{textures:t}),u}).catch(function(){return null});return this.textureCache[i]=c,c}loadImageSource(t,e){const n=this,s=this.json,r=this.options;if(this.sourceCache[t]!==void 0)return this.sourceCache[t].then(l=>l.clone());const o=s.images[t],a=self.URL||self.webkitURL;let i=o.uri||"",c=!1;if(o.bufferView!==void 0)i=n.getDependency("bufferView",o.bufferView).then(function(l){c=!0;const f=new Blob([l],{type:o.mimeType});return i=a.createObjectURL(f),i});else if(o.uri===void 0)throw new Error("THREE.GLTFLoader: Image "+t+" is missing URI and bufferView");const u=Promise.resolve(i).then(function(l){return new Promise(function(f,p){let m=f;e.isImageBitmapLoader===!0&&(m=function(M){const g=new h.Texture(M);g.needsUpdate=!0,f(g)}),e.load(h.LoaderUtils.resolveURL(l,r.path),m,void 0,p)})}).then(function(l){return c===!0&&a.revokeObjectURL(i),w(l,o),l.userData.mimeType=o.mimeType||we(o.uri),l}).catch(function(l){throw console.error("THREE.GLTFLoader: Couldn't load texture",i),l});return this.sourceCache[t]=u,u}assignTexture(t,e,n,s){const r=this;return this.getDependency("texture",n.index).then(function(o){if(!o)return null;if(n.texCoord!==void 0&&n.texCoord>0&&(o=o.clone(),o.channel=n.texCoord),r.extensions[T.KHR_TEXTURE_TRANSFORM]){const a=n.extensions!==void 0?n.extensions[T.KHR_TEXTURE_TRANSFORM]:void 0;if(a){const i=r.associations.get(o);o=r.extensions[T.KHR_TEXTURE_TRANSFORM].extendTexture(o,a),r.associations.set(o,i)}}return s!==void 0&&(o.colorSpace=s),t[e]=o,o})}assignFinalMaterial(t){const e=t.geometry;let n=t.material;const s=e.attributes.tangent===void 0,r=e.attributes.color!==void 0,o=e.attributes.normal===void 0;if(t.isPoints){const a="PointsMaterial:"+n.uuid;let i=this.cache.get(a);i||(i=new h.PointsMaterial,h.Material.prototype.copy.call(i,n),i.color.copy(n.color),i.map=n.map,i.sizeAttenuation=!1,this.cache.add(a,i)),n=i}else if(t.isLine){const a="LineBasicMaterial:"+n.uuid;let i=this.cache.get(a);i||(i=new h.LineBasicMaterial,h.Material.prototype.copy.call(i,n),i.color.copy(n.color),i.map=n.map,this.cache.add(a,i)),n=i}if(s||r||o){let a="ClonedMaterial:"+n.uuid+":";s&&(a+="derivative-tangents:"),r&&(a+="vertex-colors:"),o&&(a+="flat-shading:");let i=this.cache.get(a);i||(i=n.clone(),r&&(i.vertexColors=!0),o&&(i.flatShading=!0),s&&(i.normalScale&&(i.normalScale.y*=-1),i.clearcoatNormalScale&&(i.clearcoatNormalScale.y*=-1)),this.cache.add(a,i),this.associations.set(i,this.associations.get(n))),n=i}t.material=n}getMaterialType(){return h.MeshStandardMaterial}loadMaterial(t){const e=this,n=this.json,s=this.extensions,r=n.materials[t];let o;const a={},i=r.extensions||{},c=[];if(i[T.KHR_MATERIALS_UNLIT]){const l=s[T.KHR_MATERIALS_UNLIT];o=l.getMaterialType(),c.push(l.extendParams(a,r,e))}else{const l=r.pbrMetallicRoughness||{};if(a.color=new h.Color(1,1,1),a.opacity=1,Array.isArray(l.baseColorFactor)){const f=l.baseColorFactor;a.color.setRGB(f[0],f[1],f[2],h.LinearSRGBColorSpace),a.opacity=f[3]}l.baseColorTexture!==void 0&&c.push(e.assignTexture(a,"map",l.baseColorTexture,h.SRGBColorSpace)),a.metalness=l.metallicFactor!==void 0?l.metallicFactor:1,a.roughness=l.roughnessFactor!==void 0?l.roughnessFactor:1,l.metallicRoughnessTexture!==void 0&&(c.push(e.assignTexture(a,"metalnessMap",l.metallicRoughnessTexture)),c.push(e.assignTexture(a,"roughnessMap",l.metallicRoughnessTexture))),o=this._invokeOne(function(f){return f.getMaterialType&&f.getMaterialType(t)}),c.push(Promise.all(this._invokeAll(function(f){return f.extendMaterialParams&&f.extendMaterialParams(t,a)})))}r.doubleSided===!0&&(a.side=h.DoubleSide);const u=r.alphaMode||G.OPAQUE;if(u===G.BLEND?(a.transparent=!0,a.depthWrite=!1):(a.transparent=!1,u===G.MASK&&(a.alphaTest=r.alphaCutoff!==void 0?r.alphaCutoff:.5)),r.normalTexture!==void 0&&o!==h.MeshBasicMaterial&&(c.push(e.assignTexture(a,"normalMap",r.normalTexture)),a.normalScale=new h.Vector2(1,1),r.normalTexture.scale!==void 0)){const l=r.normalTexture.scale;a.normalScale.set(l,l)}if(r.occlusionTexture!==void 0&&o!==h.MeshBasicMaterial&&(c.push(e.assignTexture(a,"aoMap",r.occlusionTexture)),r.occlusionTexture.strength!==void 0&&(a.aoMapIntensity=r.occlusionTexture.strength)),r.emissiveFactor!==void 0&&o!==h.MeshBasicMaterial){const l=r.emissiveFactor;a.emissive=new h.Color().setRGB(l[0],l[1],l[2],h.LinearSRGBColorSpace)}return r.emissiveTexture!==void 0&&o!==h.MeshBasicMaterial&&c.push(e.assignTexture(a,"emissiveMap",r.emissiveTexture,h.SRGBColorSpace)),Promise.all(c).then(function(){const l=new o(a);return r.name&&(l.name=r.name),w(l,r),e.associations.set(l,{materials:t}),r.extensions&&I(s,l,r),l})}createUniqueName(t){const e=h.PropertyBinding.sanitizeNodeName(t||"");return e in this.nodeNamesUsed?e+"_"+ ++this.nodeNamesUsed[e]:(this.nodeNamesUsed[e]=0,e)}loadGeometries(t){const e=this,n=this.extensions,s=this.primitiveCache;function r(a){return n[T.KHR_DRACO_MESH_COMPRESSION].decodePrimitive(a,e).then(function(i){return X(i,a,e)})}const o=[];for(let a=0,i=t.length;a<i;a++){const c=t[a],u=ye(c),l=s[u];if(l)o.push(l.promise);else{let f;c.extensions&&c.extensions[T.KHR_DRACO_MESH_COMPRESSION]?f=r(c):f=X(new h.BufferGeometry,c,e),s[u]={primitive:c,promise:f},o.push(f)}}return Promise.all(o)}loadMesh(t){const e=this,n=this.json,s=this.extensions,r=n.meshes[t],o=r.primitives,a=[];for(let i=0,c=o.length;i<c;i++){const u=o[i].material===void 0?_e(this.cache):this.getDependency("material",o[i].material);a.push(u)}return a.push(e.loadGeometries(o)),Promise.all(a).then(function(i){const c=i.slice(0,i.length-1),u=i[i.length-1],l=[];for(let p=0,m=u.length;p<m;p++){const M=u[p],g=o[p];let R;const A=c[p];if(g.mode===S.TRIANGLES||g.mode===S.TRIANGLE_STRIP||g.mode===S.TRIANGLE_FAN||g.mode===void 0)R=r.isSkinnedMesh===!0?new h.SkinnedMesh(M,A):new h.Mesh(M,A),R.isSkinnedMesh===!0&&R.normalizeSkinWeights(),g.mode===S.TRIANGLE_STRIP?R.geometry=h.toTrianglesDrawMode(R.geometry,h.TriangleStripDrawMode):g.mode===S.TRIANGLE_FAN&&(R.geometry=h.toTrianglesDrawMode(R.geometry,h.TriangleFanDrawMode));else if(g.mode===S.LINES)R=new h.LineSegments(M,A);else if(g.mode===S.LINE_STRIP)R=new h.Line(M,A);else if(g.mode===S.LINE_LOOP)R=new h.LineLoop(M,A);else if(g.mode===S.POINTS)R=new h.Points(M,A);else throw new Error("THREE.GLTFLoader: Primitive mode unsupported: "+g.mode);Object.keys(R.geometry.morphAttributes).length>0&&Se(R,r),R.name=e.createUniqueName(r.name||"mesh_"+t),w(R,r),g.extensions&&I(s,R,g),e.assignFinalMaterial(R),l.push(R)}for(let p=0,m=l.length;p<m;p++)e.associations.set(l[p],{meshes:t,primitives:p});if(l.length===1)return r.extensions&&I(s,l[0],r),l[0];const f=new h.Group;r.extensions&&I(s,f,r),e.associations.set(f,{meshes:t});for(let p=0,m=l.length;p<m;p++)f.add(l[p]);return f})}loadCamera(t){let e;const n=this.json.cameras[t],s=n[n.type];if(!s){console.warn("THREE.GLTFLoader: Missing camera parameters.");return}return n.type==="perspective"?e=new h.PerspectiveCamera(h.MathUtils.radToDeg(s.yfov),s.aspectRatio||1,s.znear||1,s.zfar||2e6):n.type==="orthographic"&&(e=new h.OrthographicCamera(-s.xmag,s.xmag,s.ymag,-s.ymag,s.znear,s.zfar)),n.name&&(e.name=this.createUniqueName(n.name)),w(e,n),Promise.resolve(e)}loadSkin(t){const e=this.json.skins[t],n=[];for(let s=0,r=e.joints.length;s<r;s++)n.push(this._loadNodeShallow(e.joints[s]));return e.inverseBindMatrices!==void 0?n.push(this.getDependency("accessor",e.inverseBindMatrices)):n.push(null),Promise.all(n).then(function(s){const r=s.pop(),o=s,a=[],i=[];for(let c=0,u=o.length;c<u;c++){const l=o[c];if(l){a.push(l);const f=new h.Matrix4;r!==null&&f.fromArray(r.array,c*16),i.push(f)}else console.warn('THREE.GLTFLoader: Joint "%s" could not be found.',e.joints[c])}return new h.Skeleton(a,i)})}loadAnimation(t){const e=this.json,n=this,s=e.animations[t],r=s.name?s.name:"animation_"+t,o=[],a=[],i=[],c=[],u=[];for(let l=0,f=s.channels.length;l<f;l++){const p=s.channels[l],m=s.samplers[p.sampler],M=p.target,g=M.node,R=s.parameters!==void 0?s.parameters[m.input]:m.input,A=s.parameters!==void 0?s.parameters[m.output]:m.output;M.node!==void 0&&(o.push(this.getDependency("node",g)),a.push(this.getDependency("accessor",R)),i.push(this.getDependency("accessor",A)),c.push(m),u.push(M))}return Promise.all([Promise.all(o),Promise.all(a),Promise.all(i),Promise.all(c),Promise.all(u)]).then(function(l){const f=l[0],p=l[1],m=l[2],M=l[3],g=l[4],R=[];for(let x=0,E=f.length;x<E;x++){const L=f[x],b=p[x],y=m[x],P=M[x],C=g[x];if(L===void 0)continue;L.updateMatrix&&L.updateMatrix();const k=n._createAnimationTracks(L,b,y,P,C);if(k)for(let H=0;H<k.length;H++)R.push(k[H])}const A=new h.AnimationClip(r,void 0,R);return w(A,s),A})}createNodeMesh(t){const e=this.json,n=this,s=e.nodes[t];return s.mesh===void 0?null:n.getDependency("mesh",s.mesh).then(function(r){const o=n._getNodeRef(n.meshCache,s.mesh,r);return s.weights!==void 0&&o.traverse(function(a){if(a.isMesh)for(let i=0,c=s.weights.length;i<c;i++)a.morphTargetInfluences[i]=s.weights[i]}),o})}loadNode(t){const e=this.json,n=this,s=e.nodes[t],r=n._loadNodeShallow(t),o=[],a=s.children||[];for(let c=0,u=a.length;c<u;c++)o.push(n.getDependency("node",a[c]));const i=s.skin===void 0?Promise.resolve(null):n.getDependency("skin",s.skin);return Promise.all([r,Promise.all(o),i]).then(function(c){const u=c[0],l=c[1],f=c[2];f!==null&&u.traverse(function(p){p.isSkinnedMesh&&p.bind(f,be)});for(let p=0,m=l.length;p<m;p++)u.add(l[p]);if(u.userData.pivot!==void 0&&l.length>0){const p=u.userData.pivot,m=l[0];u.pivot=new h.Vector3().fromArray(p),u.position.x-=p[0],u.position.y-=p[1],u.position.z-=p[2],m.position.set(0,0,0),delete u.userData.pivot}return u})}_loadNodeShallow(t){const e=this.json,n=this.extensions,s=this;if(this.nodeCache[t]!==void 0)return this.nodeCache[t];const r=e.nodes[t],o=r.name?s.createUniqueName(r.name):"",a=[],i=s._invokeOne(function(c){return c.createNodeMesh&&c.createNodeMesh(t)});return i&&a.push(i),r.camera!==void 0&&a.push(s.getDependency("camera",r.camera).then(function(c){return s._getNodeRef(s.cameraCache,r.camera,c)})),s._invokeAll(function(c){return c.createNodeAttachment&&c.createNodeAttachment(t)}).forEach(function(c){a.push(c)}),this.nodeCache[t]=Promise.all(a).then(function(c){let u;if(r.isBone===!0?u=new h.Bone:c.length>1?u=new h.Group:c.length===1?u=c[0]:u=new h.Object3D,u!==c[0])for(let l=0,f=c.length;l<f;l++)u.add(c[l]);if(r.name&&(u.userData.name=r.name,u.name=o),w(u,r),r.extensions&&I(n,u,r),r.matrix!==void 0){const l=new h.Matrix4;l.fromArray(r.matrix),u.applyMatrix4(l)}else r.translation!==void 0&&u.position.fromArray(r.translation),r.rotation!==void 0&&u.quaternion.fromArray(r.rotation),r.scale!==void 0&&u.scale.fromArray(r.scale);if(!s.associations.has(u))s.associations.set(u,{});else if(r.mesh!==void 0&&s.meshCache.refs[r.mesh]>1){const l=s.associations.get(u);s.associations.set(u,{...l})}return s.associations.get(u).nodes=t,u}),this.nodeCache[t]}loadScene(t){const e=this.extensions,n=this.json.scenes[t],s=this,r=new h.Group;n.name&&(r.name=s.createUniqueName(n.name)),w(r,n),n.extensions&&I(e,r,n);const o=n.nodes||[],a=[];for(let i=0,c=o.length;i<c;i++)a.push(s.getDependency("node",o[i]));return Promise.all(a).then(function(i){for(let u=0,l=i.length;u<l;u++){const f=i[u];f.parent!==null?r.add(Q(f)):r.add(f)}const c=u=>{const l=new Map;for(const[f,p]of s.associations)(f instanceof h.Material||f instanceof h.Texture)&&l.set(f,p);return u.traverse(f=>{const p=s.associations.get(f);p!=null&&l.set(f,p)}),l};return s.associations=c(r),r})}_createAnimationTracks(t,e,n,s,r){const o=[],a=t.name?t.name:t.uuid,i=[];N[r.path]===N.weights?t.traverse(function(f){f.morphTargetInfluences&&i.push(f.name?f.name:f.uuid)}):i.push(a);let c;switch(N[r.path]){case N.weights:c=h.NumberKeyframeTrack;break;case N.rotation:c=h.QuaternionKeyframeTrack;break;case N.translation:case N.scale:c=h.VectorKeyframeTrack;break;default:n.itemSize===1?c=h.NumberKeyframeTrack:c=h.VectorKeyframeTrack;break}const u=s.interpolation!==void 0?Ae[s.interpolation]:h.InterpolateLinear,l=this._getArrayFromAccessor(n);for(let f=0,p=i.length;f<p;f++){const m=new c(i[f]+"."+N[r.path],e.array,l,u);s.interpolation==="CUBICSPLINE"&&this._createCubicSplineTrackInterpolant(m),o.push(m)}return o}_getArrayFromAccessor(t){let e=t.array;if(t.normalized){const n=U(e.constructor),s=new Float32Array(e.length);for(let r=0,o=e.length;r<o;r++)s[r]=e[r]*n;e=s}return e}_createCubicSplineTrackInterpolant(t){t.createInterpolant=function(n){const s=this instanceof h.QuaternionKeyframeTrack?xe:Y;return new s(this.times,this.values,this.getValueSize()/3,n)},t.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline=!0}}function Ie(d,t,e){const n=t.attributes,s=new h.Box3;if(n.POSITION!==void 0){const a=e.json.accessors[n.POSITION],i=a.min,c=a.max;if(i!==void 0&&c!==void 0){if(s.set(new h.Vector3(i[0],i[1],i[2]),new h.Vector3(c[0],c[1],c[2])),a.normalized){const u=U(O[a.componentType]);s.min.multiplyScalar(u),s.max.multiplyScalar(u)}}else{console.warn("THREE.GLTFLoader: Missing min/max properties for accessor POSITION.");return}}else return;const r=t.targets;if(r!==void 0){const a=new h.Vector3,i=new h.Vector3;for(let c=0,u=r.length;c<u;c++){const l=r[c];if(l.POSITION!==void 0){const f=e.json.accessors[l.POSITION],p=f.min,m=f.max;if(p!==void 0&&m!==void 0){if(i.setX(Math.max(Math.abs(p[0]),Math.abs(m[0]))),i.setY(Math.max(Math.abs(p[1]),Math.abs(m[1]))),i.setZ(Math.max(Math.abs(p[2]),Math.abs(m[2]))),f.normalized){const M=U(O[f.componentType]);i.multiplyScalar(M)}a.max(i)}else console.warn("THREE.GLTFLoader: Missing min/max properties for accessor POSITION.")}}s.expandByVector(a)}d.boundingBox=s;const o=new h.Sphere;s.getCenter(o.center),o.radius=s.min.distanceTo(s.max)/2,d.boundingSphere=o}function X(d,t,e){const n=t.attributes,s=[];function r(o,a){return e.getDependency("accessor",o).then(function(i){d.setAttribute(a,i)})}for(const o in n){const a=B[o]||o.toLowerCase();a in d.attributes||s.push(r(n[o],a))}if(t.indices!==void 0&&!d.index){const o=e.getDependency("accessor",t.indices).then(function(a){d.setIndex(a)});s.push(o)}return h.ColorManagement.workingColorSpace!==h.LinearSRGBColorSpace&&"COLOR_0"in n&&console.warn(`THREE.GLTFLoader: Converting vertex colors from "srgb-linear" to "${h.ColorManagement.workingColorSpace}" not supported.`),w(d,t),Ie(d,t,e),Promise.all(s).then(function(){return t.targets!==void 0?Le(d,t.targets,e):d})}exports.GLTFLoader=J;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("./duo-frame-D9832t6H.js");function Q(d){const t=new Map,e=new Map,n=d.clone();return q(d,n,function(s,r){t.set(r,s),e.set(s,r)}),n.traverse(function(s){if(!s.isSkinnedMesh)return;const r=s,o=t.get(s),a=o.skeleton.bones;r.skeleton=o.skeleton.clone(),r.bindMatrix.copy(o.bindMatrix),r.skeleton.bones=a.map(function(i){return e.get(i)}),r.bind(r.skeleton,r.bindMatrix)}),n}function q(d,t,e){e(d,t);for(let n=0;n<d.children.length;n++)q(d.children[n],t.children[n],e)}class J extends h.Loader{constructor(t){super(t),this.dracoLoader=null,this.ktx2Loader=null,this.meshoptDecoder=null,this.pluginCallbacks=[],this.register(function(e){return new ne(e)}),this.register(function(e){return new se(e)}),this.register(function(e){return new fe(e)}),this.register(function(e){return new de(e)}),this.register(function(e){return new pe(e)}),this.register(function(e){return new ie(e)}),this.register(function(e){return new oe(e)}),this.register(function(e){return new ae(e)}),this.register(function(e){return new ce(e)}),this.register(function(e){return new te(e)}),this.register(function(e){return new le(e)}),this.register(function(e){return new re(e)}),this.register(function(e){return new he(e)}),this.register(function(e){return new ue(e)}),this.register(function(e){return new $(e)}),this.register(function(e){return new K(e,T.EXT_MESHOPT_COMPRESSION)}),this.register(function(e){return new K(e,T.KHR_MESHOPT_COMPRESSION)}),this.register(function(e){return new me(e)})}load(t,e,n,s){const r=this;let o;if(this.resourcePath!=="")o=this.resourcePath;else if(this.path!==""){const c=h.LoaderUtils.extractUrlBase(t);o=h.LoaderUtils.resolveURL(c,this.path)}else o=h.LoaderUtils.extractUrlBase(t);this.manager.itemStart(t);const a=function(c){s?s(c):console.error(c),r.manager.itemError(t),r.manager.itemEnd(t)},i=new h.FileLoader(this.manager);i.setPath(this.path),i.setResponseType("arraybuffer"),i.setRequestHeader(this.requestHeader),i.setWithCredentials(this.withCredentials),i.load(t,function(c){try{r.parse(c,o,function(u){e(u),r.manager.itemEnd(t)},a)}catch(u){a(u)}},n,a)}setDRACOLoader(t){return this.dracoLoader=t,this}setKTX2Loader(t){return this.ktx2Loader=t,this}setMeshoptDecoder(t){return this.meshoptDecoder=t,this}register(t){return this.pluginCallbacks.indexOf(t)===-1&&this.pluginCallbacks.push(t),this}unregister(t){return this.pluginCallbacks.indexOf(t)!==-1&&this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(t),1),this}parse(t,e,n,s){let r;const o={},a={},i=new TextDecoder;if(typeof t=="string")r=JSON.parse(t);else if(t instanceof ArrayBuffer)if(i.decode(new Uint8Array(t,0,4))===W){try{o[T.KHR_BINARY_GLTF]=new ge(t)}catch(l){s&&s(l);return}r=JSON.parse(o[T.KHR_BINARY_GLTF].content)}else r=JSON.parse(i.decode(t));else r=t;if(r.asset===void 0||r.asset.version[0]<2){s&&s(new Error("THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported."));return}const c=new Ne(r,{path:e||this.resourcePath||"",crossOrigin:this.crossOrigin,requestHeader:this.requestHeader,manager:this.manager,ktx2Loader:this.ktx2Loader,meshoptDecoder:this.meshoptDecoder});c.fileLoader.setRequestHeader(this.requestHeader);for(let u=0;u<this.pluginCallbacks.length;u++){const l=this.pluginCallbacks[u](c);l.name||console.error("THREE.GLTFLoader: Invalid plugin found: missing name"),a[l.name]=l,o[l.name]=!0}if(r.extensionsUsed)for(let u=0;u<r.extensionsUsed.length;++u){const l=r.extensionsUsed[u],f=r.extensionsRequired||[];switch(l){case T.KHR_MATERIALS_UNLIT:o[l]=new ee;break;case T.KHR_DRACO_MESH_COMPRESSION:o[l]=new Te(r,this.dracoLoader);break;case T.KHR_TEXTURE_TRANSFORM:o[l]=new Re;break;case T.KHR_MESH_QUANTIZATION:o[l]=new Me;break;default:f.indexOf(l)>=0&&a[l]===void 0&&console.warn('THREE.GLTFLoader: Unknown extension "'+l+'".')}}c.setExtensions(o),c.setPlugins(a),c.parse(n,s)}parseAsync(t,e){const n=this;return new Promise(function(s,r){n.parse(t,e,s,r)})}}function Z(){let d={};return{get:function(t){return d[t]},add:function(t,e){d[t]=e},remove:function(t){delete d[t]},removeAll:function(){d={}}}}function _(d,t,e){const n=d.json.materials[t];return n.extensions&&n.extensions[e]?n.extensions[e]:null}const T={KHR_BINARY_GLTF:"KHR_binary_glTF",KHR_DRACO_MESH_COMPRESSION:"KHR_draco_mesh_compression",KHR_LIGHTS_PUNCTUAL:"KHR_lights_punctual",KHR_MATERIALS_CLEARCOAT:"KHR_materials_clearcoat",KHR_MATERIALS_DISPERSION:"KHR_materials_dispersion",KHR_MATERIALS_IOR:"KHR_materials_ior",KHR_MATERIALS_SHEEN:"KHR_materials_sheen",KHR_MATERIALS_SPECULAR:"KHR_materials_specular",KHR_MATERIALS_TRANSMISSION:"KHR_materials_transmission",KHR_MATERIALS_IRIDESCENCE:"KHR_materials_iridescence",KHR_MATERIALS_ANISOTROPY:"KHR_materials_anisotropy",KHR_MATERIALS_UNLIT:"KHR_materials_unlit",KHR_MATERIALS_VOLUME:"KHR_materials_volume",KHR_TEXTURE_BASISU:"KHR_texture_basisu",KHR_TEXTURE_TRANSFORM:"KHR_texture_transform",KHR_MESH_QUANTIZATION:"KHR_mesh_quantization",KHR_MATERIALS_EMISSIVE_STRENGTH:"KHR_materials_emissive_strength",EXT_MATERIALS_BUMP:"EXT_materials_bump",EXT_TEXTURE_WEBP:"EXT_texture_webp",EXT_TEXTURE_AVIF:"EXT_texture_avif",EXT_MESHOPT_COMPRESSION:"EXT_meshopt_compression",KHR_MESHOPT_COMPRESSION:"KHR_meshopt_compression",EXT_MESH_GPU_INSTANCING:"EXT_mesh_gpu_instancing"};class ${constructor(t){this.parser=t,this.name=T.KHR_LIGHTS_PUNCTUAL,this.cache={refs:{},uses:{}}}_markDefs(){const t=this.parser,e=this.parser.json.nodes||[];for(let n=0,s=e.length;n<s;n++){const r=e[n];r.extensions&&r.extensions[this.name]&&r.extensions[this.name].light!==void 0&&t._addNodeRef(this.cache,r.extensions[this.name].light)}}_loadLight(t){const e=this.parser,n="light:"+t;let s=e.cache.get(n);if(s)return s;const r=e.json,i=((r.extensions&&r.extensions[this.name]||{}).lights||[])[t];let c;const u=new h.Color(16777215);i.color!==void 0&&u.setRGB(i.color[0],i.color[1],i.color[2],h.LinearSRGBColorSpace);const l=i.range!==void 0?i.range:0;switch(i.type){case"directional":c=new h.DirectionalLight(u),c.target.position.set(0,0,-1),c.add(c.target);break;case"point":c=new h.PointLight(u),c.distance=l;break;case"spot":c=new h.SpotLight(u),c.distance=l,i.spot=i.spot||{},i.spot.innerConeAngle=i.spot.innerConeAngle!==void 0?i.spot.innerConeAngle:0,i.spot.outerConeAngle=i.spot.outerConeAngle!==void 0?i.spot.outerConeAngle:Math.PI/4,c.angle=i.spot.outerConeAngle,c.penumbra=1-i.spot.innerConeAngle/i.spot.outerConeAngle,c.target.position.set(0,0,-1),c.add(c.target);break;default:throw new Error("THREE.GLTFLoader: Unexpected light type: "+i.type)}return c.position.set(0,0,0),w(c,i),i.intensity!==void 0&&(c.intensity=i.intensity),c.name=e.createUniqueName(i.name||"light_"+t),s=Promise.resolve(c),e.cache.add(n,s),s}getDependency(t,e){if(t==="light")return this._loadLight(e)}createNodeAttachment(t){const e=this,n=this.parser,r=n.json.nodes[t],a=(r.extensions&&r.extensions[this.name]||{}).light;return a===void 0?null:this._loadLight(a).then(function(i){return n._getNodeRef(e.cache,a,i)})}}class ee{constructor(){this.name=T.KHR_MATERIALS_UNLIT}getMaterialType(){return h.MeshBasicMaterial}extendParams(t,e,n){const s=[];t.color=new h.Color(1,1,1),t.opacity=1;const r=e.pbrMetallicRoughness;if(r){if(Array.isArray(r.baseColorFactor)){const o=r.baseColorFactor;t.color.setRGB(o[0],o[1],o[2],h.LinearSRGBColorSpace),t.opacity=o[3]}r.baseColorTexture!==void 0&&s.push(n.assignTexture(t,"map",r.baseColorTexture,h.SRGBColorSpace))}return Promise.all(s)}}class te{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_EMISSIVE_STRENGTH}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);return n===null||n.emissiveStrength!==void 0&&(e.emissiveIntensity=n.emissiveStrength),Promise.resolve()}}class ne{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_CLEARCOAT}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];if(n.clearcoatFactor!==void 0&&(e.clearcoat=n.clearcoatFactor),n.clearcoatTexture!==void 0&&s.push(this.parser.assignTexture(e,"clearcoatMap",n.clearcoatTexture)),n.clearcoatRoughnessFactor!==void 0&&(e.clearcoatRoughness=n.clearcoatRoughnessFactor),n.clearcoatRoughnessTexture!==void 0&&s.push(this.parser.assignTexture(e,"clearcoatRoughnessMap",n.clearcoatRoughnessTexture)),n.clearcoatNormalTexture!==void 0&&(s.push(this.parser.assignTexture(e,"clearcoatNormalMap",n.clearcoatNormalTexture)),n.clearcoatNormalTexture.scale!==void 0)){const r=n.clearcoatNormalTexture.scale;e.clearcoatNormalScale=new h.Vector2(r,r)}return Promise.all(s)}}class se{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_DISPERSION}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);return n===null||(e.dispersion=n.dispersion!==void 0?n.dispersion:0),Promise.resolve()}}class re{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_IRIDESCENCE}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];return n.iridescenceFactor!==void 0&&(e.iridescence=n.iridescenceFactor),n.iridescenceTexture!==void 0&&s.push(this.parser.assignTexture(e,"iridescenceMap",n.iridescenceTexture)),n.iridescenceIor!==void 0&&(e.iridescenceIOR=n.iridescenceIor),e.iridescenceThicknessRange===void 0&&(e.iridescenceThicknessRange=[100,400]),n.iridescenceThicknessMinimum!==void 0&&(e.iridescenceThicknessRange[0]=n.iridescenceThicknessMinimum),n.iridescenceThicknessMaximum!==void 0&&(e.iridescenceThicknessRange[1]=n.iridescenceThicknessMaximum),n.iridescenceThicknessTexture!==void 0&&s.push(this.parser.assignTexture(e,"iridescenceThicknessMap",n.iridescenceThicknessTexture)),Promise.all(s)}}class ie{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_SHEEN}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];if(e.sheenColor=new h.Color(0,0,0),e.sheenRoughness=0,e.sheen=1,n.sheenColorFactor!==void 0){const r=n.sheenColorFactor;e.sheenColor.setRGB(r[0],r[1],r[2],h.LinearSRGBColorSpace)}return n.sheenRoughnessFactor!==void 0&&(e.sheenRoughness=n.sheenRoughnessFactor),n.sheenColorTexture!==void 0&&s.push(this.parser.assignTexture(e,"sheenColorMap",n.sheenColorTexture,h.SRGBColorSpace)),n.sheenRoughnessTexture!==void 0&&s.push(this.parser.assignTexture(e,"sheenRoughnessMap",n.sheenRoughnessTexture)),Promise.all(s)}}class oe{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_TRANSMISSION}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];return n.transmissionFactor!==void 0&&(e.transmission=n.transmissionFactor),n.transmissionTexture!==void 0&&s.push(this.parser.assignTexture(e,"transmissionMap",n.transmissionTexture)),Promise.all(s)}}class ae{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_VOLUME}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];e.thickness=n.thicknessFactor!==void 0?n.thicknessFactor:0,n.thicknessTexture!==void 0&&s.push(this.parser.assignTexture(e,"thicknessMap",n.thicknessTexture)),e.attenuationDistance=n.attenuationDistance||1/0;const r=n.attenuationColor||[1,1,1];return e.attenuationColor=new h.Color().setRGB(r[0],r[1],r[2],h.LinearSRGBColorSpace),Promise.all(s)}}class ce{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_IOR}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);return n===null||(e.ior=n.ior!==void 0?n.ior:1.5),Promise.resolve()}}class le{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_SPECULAR}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];e.specularIntensity=n.specularFactor!==void 0?n.specularFactor:1,n.specularTexture!==void 0&&s.push(this.parser.assignTexture(e,"specularIntensityMap",n.specularTexture));const r=n.specularColorFactor||[1,1,1];return e.specularColor=new h.Color().setRGB(r[0],r[1],r[2],h.LinearSRGBColorSpace),n.specularColorTexture!==void 0&&s.push(this.parser.assignTexture(e,"specularColorMap",n.specularColorTexture,h.SRGBColorSpace)),Promise.all(s)}}class ue{constructor(t){this.parser=t,this.name=T.EXT_MATERIALS_BUMP}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];return e.bumpScale=n.bumpFactor!==void 0?n.bumpFactor:1,n.bumpTexture!==void 0&&s.push(this.parser.assignTexture(e,"bumpMap",n.bumpTexture)),Promise.all(s)}}class he{constructor(t){this.parser=t,this.name=T.KHR_MATERIALS_ANISOTROPY}getMaterialType(t){return _(this.parser,t,this.name)!==null?h.MeshPhysicalMaterial:null}extendMaterialParams(t,e){const n=_(this.parser,t,this.name);if(n===null)return Promise.resolve();const s=[];return n.anisotropyStrength!==void 0&&(e.anisotropy=n.anisotropyStrength),n.anisotropyRotation!==void 0&&(e.anisotropyRotation=n.anisotropyRotation),n.anisotropyTexture!==void 0&&s.push(this.parser.assignTexture(e,"anisotropyMap",n.anisotropyTexture)),Promise.all(s)}}class fe{constructor(t){this.parser=t,this.name=T.KHR_TEXTURE_BASISU}loadTexture(t){const e=this.parser,n=e.json,s=n.textures[t];if(!s.extensions||!s.extensions[this.name])return null;const r=s.extensions[this.name],o=e.options.ktx2Loader;if(!o){if(n.extensionsRequired&&n.extensionsRequired.indexOf(this.name)>=0)throw new Error("THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures");return null}return e.loadTextureImage(t,r.source,o)}}class de{constructor(t){this.parser=t,this.name=T.EXT_TEXTURE_WEBP}loadTexture(t){const e=this.name,n=this.parser,s=n.json,r=s.textures[t];if(!r.extensions||!r.extensions[e])return null;const o=r.extensions[e],a=s.images[o.source];let i=n.textureLoader;if(a.uri){const c=n.options.manager.getHandler(a.uri);c!==null&&(i=c)}return n.loadTextureImage(t,o.source,i)}}class pe{constructor(t){this.parser=t,this.name=T.EXT_TEXTURE_AVIF}loadTexture(t){const e=this.name,n=this.parser,s=n.json,r=s.textures[t];if(!r.extensions||!r.extensions[e])return null;const o=r.extensions[e],a=s.images[o.source];let i=n.textureLoader;if(a.uri){const c=n.options.manager.getHandler(a.uri);c!==null&&(i=c)}return n.loadTextureImage(t,o.source,i)}}class K{constructor(t,e){this.name=e,this.parser=t}loadBufferView(t){const e=this.parser.json,n=e.bufferViews[t];if(n.extensions&&n.extensions[this.name]){const s=n.extensions[this.name],r=this.parser.getDependency("buffer",s.buffer),o=this.parser.options.meshoptDecoder;if(!o||!o.supported){if(e.extensionsRequired&&e.extensionsRequired.indexOf(this.name)>=0)throw new Error("THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files");return null}return r.then(function(a){const i=s.byteOffset||0,c=s.byteLength||0,u=s.count,l=s.byteStride,f=new Uint8Array(a,i,c);return o.decodeGltfBufferAsync?o.decodeGltfBufferAsync(u,l,f,s.mode,s.filter).then(function(p){return p.buffer}):o.ready.then(function(){const p=new ArrayBuffer(u*l);return o.decodeGltfBuffer(new Uint8Array(p),u,l,f,s.mode,s.filter),p})})}else return null}}class me{constructor(t){this.name=T.EXT_MESH_GPU_INSTANCING,this.parser=t}createNodeMesh(t){const e=this.parser.json,n=e.nodes[t];if(!n.extensions||!n.extensions[this.name]||n.mesh===void 0)return null;const s=e.meshes[n.mesh];for(const c of s.primitives)if(c.mode!==S.TRIANGLES&&c.mode!==S.TRIANGLE_STRIP&&c.mode!==S.TRIANGLE_FAN&&c.mode!==void 0)return null;const o=n.extensions[this.name].attributes,a=[],i={};for(const c in o)a.push(this.parser.getDependency("accessor",o[c]).then(u=>(i[c]=u,i[c])));return a.length<1?null:(a.push(this.parser.createNodeMesh(t)),Promise.all(a).then(c=>{const u=c.pop(),l=u.isGroup?u.children:[u],f=c[0].count,p=[];for(const m of l){const M=new h.Matrix4,g=new h.Vector3,R=new h.Quaternion,A=new h.Vector3(1,1,1),x=new h.InstancedMesh(m.geometry,m.material,f);for(let E=0;E<f;E++)i.TRANSLATION&&g.fromBufferAttribute(i.TRANSLATION,E),i.ROTATION&&R.fromBufferAttribute(i.ROTATION,E),i.SCALE&&A.fromBufferAttribute(i.SCALE,E),x.setMatrixAt(E,M.compose(g,R,A));for(const E in i)if(E==="_COLOR_0"){const L=i[E];x.instanceColor=new h.InstancedBufferAttribute(L.array,L.itemSize,L.normalized)}else E!=="TRANSLATION"&&E!=="ROTATION"&&E!=="SCALE"&&m.geometry.setAttribute(E,i[E]);h.Object3D.prototype.copy.call(x,m),this.parser.assignFinalMaterial(x),p.push(x)}return u.isGroup?(u.clear(),u.add(...p),u):p[0]}))}}const W="glTF",F=12,j={JSON:1313821514,BIN:5130562};class ge{constructor(t){this.name=T.KHR_BINARY_GLTF,this.content=null,this.body=null;const e=new DataView(t,0,F),n=new TextDecoder;if(this.header={magic:n.decode(new Uint8Array(t.slice(0,4))),version:e.getUint32(4,!0),length:e.getUint32(8,!0)},this.header.magic!==W)throw new Error("THREE.GLTFLoader: Unsupported glTF-Binary header.");if(this.header.version<2)throw new Error("THREE.GLTFLoader: Legacy binary file detected.");const s=this.header.length-F,r=new DataView(t,F);let o=0;for(;o<s;){const a=r.getUint32(o,!0);o+=4;const i=r.getUint32(o,!0);if(o+=4,i===j.JSON){const c=new Uint8Array(t,F+o,a);this.content=n.decode(c)}else if(i===j.BIN){const c=F+o;this.body=t.slice(c,c+a)}o+=a}if(this.content===null)throw new Error("THREE.GLTFLoader: JSON content not found.")}}class Te{constructor(t,e){if(!e)throw new Error("THREE.GLTFLoader: No DRACOLoader instance provided.");this.name=T.KHR_DRACO_MESH_COMPRESSION,this.json=t,this.dracoLoader=e,this.dracoLoader.preload()}decodePrimitive(t,e){const n=this.json,s=this.dracoLoader,r=t.extensions[this.name].bufferView,o=t.extensions[this.name].attributes,a={},i={},c={};for(const u in o){const l=B[u]||u.toLowerCase();a[l]=o[u]}for(const u in t.attributes){const l=B[u]||u.toLowerCase();if(o[u]!==void 0){const f=n.accessors[t.attributes[u]],p=O[f.componentType];c[l]=p.name,i[l]=f.normalized===!0}}return e.getDependency("bufferView",r).then(function(u){return new Promise(function(l,f){s.decodeDracoFile(u,function(p){for(const m in p.attributes){const M=p.attributes[m],g=i[m];g!==void 0&&(M.normalized=g)}l(p)},a,c,h.LinearSRGBColorSpace,f)})})}}class Re{constructor(){this.name=T.KHR_TEXTURE_TRANSFORM}extendTexture(t,e){return(e.texCoord===void 0||e.texCoord===t.channel)&&e.offset===void 0&&e.rotation===void 0&&e.scale===void 0||(t=t.clone(),e.texCoord!==void 0&&(t.channel=e.texCoord),e.offset!==void 0&&t.offset.fromArray(e.offset),e.rotation!==void 0&&(t.rotation=e.rotation),e.scale!==void 0&&t.repeat.fromArray(e.scale),t.needsUpdate=!0),t}}class Me{constructor(){this.name=T.KHR_MESH_QUANTIZATION}}class Y extends h.Interpolant{constructor(t,e,n,s){super(t,e,n,s)}copySampleValue_(t){const e=this.resultBuffer,n=this.sampleValues,s=this.valueSize,r=t*s*3+s;for(let o=0;o!==s;o++)e[o]=n[r+o];return e}interpolate_(t,e,n,s){const r=this.resultBuffer,o=this.sampleValues,a=this.valueSize,i=a*2,c=a*3,u=s-e,l=(n-e)/u,f=l*l,p=f*l,m=t*c,M=m-c,g=-2*p+3*f,R=p-f,A=1-g,x=R-f+l;for(let E=0;E!==a;E++){const L=o[M+E+a],b=o[M+E+i]*u,y=o[m+E+a],P=o[m+E]*u;r[E]=A*L+x*b+g*y+R*P}return r}}const Ee=new h.Quaternion;class xe extends Y{interpolate_(t,e,n,s){const r=super.interpolate_(t,e,n,s);return Ee.fromArray(r).normalize().toArray(r),r}}const S={POINTS:0,LINES:1,LINE_LOOP:2,LINE_STRIP:3,TRIANGLES:4,TRIANGLE_STRIP:5,TRIANGLE_FAN:6},O={5120:Int8Array,5121:Uint8Array,5122:Int16Array,5123:Uint16Array,5125:Uint32Array,5126:Float32Array},V={9728:h.NearestFilter,9729:h.LinearFilter,9984:h.NearestMipmapNearestFilter,9985:h.LinearMipmapNearestFilter,9986:h.NearestMipmapLinearFilter,9987:h.LinearMipmapLinearFilter},z={33071:h.ClampToEdgeWrapping,33648:h.MirroredRepeatWrapping,10497:h.RepeatWrapping},D={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT2:4,MAT3:9,MAT4:16},B={POSITION:"position",NORMAL:"normal",TANGENT:"tangent",TEXCOORD_0:"uv",TEXCOORD_1:"uv1",TEXCOORD_2:"uv2",TEXCOORD_3:"uv3",COLOR_0:"color",WEIGHTS_0:"skinWeight",JOINTS_0:"skinIndex"},N={scale:"scale",translation:"position",rotation:"quaternion",weights:"morphTargetInfluences"},Ae={CUBICSPLINE:void 0,LINEAR:h.InterpolateLinear,STEP:h.InterpolateDiscrete},G={OPAQUE:"OPAQUE",MASK:"MASK",BLEND:"BLEND"};function _e(d){return d.DefaultMaterial===void 0&&(d.DefaultMaterial=new h.MeshStandardMaterial({color:16777215,emissive:0,metalness:1,roughness:1,transparent:!1,depthTest:!0,side:h.FrontSide})),d.DefaultMaterial}function I(d,t,e){for(const n in e.extensions)d[n]===void 0&&(t.userData.gltfExtensions=t.userData.gltfExtensions||{},t.userData.gltfExtensions[n]=e.extensions[n])}function w(d,t){t.extras!==void 0&&(typeof t.extras=="object"?Object.assign(d.userData,t.extras):console.warn("THREE.GLTFLoader: Ignoring primitive type .extras, "+t.extras))}function Le(d,t,e){let n=!1,s=!1,r=!1;for(let c=0,u=t.length;c<u;c++){const l=t[c];if(l.POSITION!==void 0&&(n=!0),l.NORMAL!==void 0&&(s=!0),l.COLOR_0!==void 0&&(r=!0),n&&s&&r)break}if(!n&&!s&&!r)return Promise.resolve(d);const o=[],a=[],i=[];for(let c=0,u=t.length;c<u;c++){const l=t[c];if(n){const f=l.POSITION!==void 0?e.getDependency("accessor",l.POSITION):d.attributes.position;o.push(f)}if(s){const f=l.NORMAL!==void 0?e.getDependency("accessor",l.NORMAL):d.attributes.normal;a.push(f)}if(r){const f=l.COLOR_0!==void 0?e.getDependency("accessor",l.COLOR_0):d.attributes.color;i.push(f)}}return Promise.all([Promise.all(o),Promise.all(a),Promise.all(i)]).then(function(c){const u=c[0],l=c[1],f=c[2];return n&&(d.morphAttributes.position=u),s&&(d.morphAttributes.normal=l),r&&(d.morphAttributes.color=f),d.morphTargetsRelative=!0,d})}function Se(d,t){if(d.updateMorphTargets(),t.weights!==void 0)for(let e=0,n=t.weights.length;e<n;e++)d.morphTargetInfluences[e]=t.weights[e];if(t.extras&&Array.isArray(t.extras.targetNames)){const e=t.extras.targetNames;if(d.morphTargetInfluences.length===e.length){d.morphTargetDictionary={};for(let n=0,s=e.length;n<s;n++)d.morphTargetDictionary[e[n]]=n}else console.warn("THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.")}}function ye(d){let t;const e=d.extensions&&d.extensions[T.KHR_DRACO_MESH_COMPRESSION];if(e?t="draco:"+e.bufferView+":"+e.indices+":"+v(e.attributes):t=d.indices+":"+v(d.attributes)+":"+d.mode,d.targets!==void 0)for(let n=0,s=d.targets.length;n<s;n++)t+=":"+v(d.targets[n]);return t}function v(d){let t="";const e=Object.keys(d).sort();for(let n=0,s=e.length;n<s;n++)t+=e[n]+":"+d[e[n]]+";";return t}function U(d){switch(d){case Int8Array:return 1/127;case Uint8Array:return 1/255;case Int16Array:return 1/32767;case Uint16Array:return 1/65535;default:throw new Error("THREE.GLTFLoader: Unsupported normalized accessor component type.")}}function we(d){return d.search(/\.jpe?g($|\?)/i)>0||d.search(/^data\:image\/jpeg/)===0?"image/jpeg":d.search(/\.webp($|\?)/i)>0||d.search(/^data\:image\/webp/)===0?"image/webp":d.search(/\.ktx2($|\?)/i)>0||d.search(/^data\:image\/ktx2/)===0?"image/ktx2":"image/png"}const be=new h.Matrix4;class Ne{constructor(t={},e={}){this.json=t,this.extensions={},this.plugins={},this.options=e,this.cache=new Z,this.associations=new Map,this.primitiveCache={},this.nodeCache={},this.meshCache={refs:{},uses:{}},this.cameraCache={refs:{},uses:{}},this.lightCache={refs:{},uses:{}},this.sourceCache={},this.textureCache={},this.nodeNamesUsed={};let n=!1,s=-1,r=!1,o=-1;if(typeof navigator<"u"&&typeof navigator.userAgent<"u"){const a=navigator.userAgent;n=/^((?!chrome|android).)*safari/i.test(a)===!0;const i=a.match(/Version\/(\d+)/);s=n&&i?parseInt(i[1],10):-1,r=a.indexOf("Firefox")>-1,o=r?a.match(/Firefox\/([0-9]+)\./)[1]:-1}typeof createImageBitmap>"u"||n&&s<17||r&&o<98?this.textureLoader=new h.TextureLoader(this.options.manager):this.textureLoader=new h.ImageBitmapLoader(this.options.manager),this.textureLoader.setCrossOrigin(this.options.crossOrigin),this.textureLoader.setRequestHeader(this.options.requestHeader),this.fileLoader=new h.FileLoader(this.options.manager),this.fileLoader.setResponseType("arraybuffer"),this.options.crossOrigin==="use-credentials"&&this.fileLoader.setWithCredentials(!0)}setExtensions(t){this.extensions=t}setPlugins(t){this.plugins=t}parse(t,e){const n=this,s=this.json,r=this.extensions;this.cache.removeAll(),this.nodeCache={},this._invokeAll(function(o){return o._markDefs&&o._markDefs()}),Promise.all(this._invokeAll(function(o){return o.beforeRoot&&o.beforeRoot()})).then(function(){return Promise.all([n.getDependencies("scene"),n.getDependencies("animation"),n.getDependencies("camera")])}).then(function(o){const a={scene:o[0][s.scene||0],scenes:o[0],animations:o[1],cameras:o[2],asset:s.asset,parser:n,userData:{}};return I(r,a,s),w(a,s),Promise.all(n._invokeAll(function(i){return i.afterRoot&&i.afterRoot(a)})).then(function(){for(const i of a.scenes)i.updateMatrixWorld();t(a)})}).catch(e)}_markDefs(){const t=this.json.nodes||[],e=this.json.skins||[],n=this.json.meshes||[];for(let s=0,r=e.length;s<r;s++){const o=e[s].joints;for(let a=0,i=o.length;a<i;a++)t[o[a]].isBone=!0}for(let s=0,r=t.length;s<r;s++){const o=t[s];o.mesh!==void 0&&(this._addNodeRef(this.meshCache,o.mesh),o.skin!==void 0&&(n[o.mesh].isSkinnedMesh=!0)),o.camera!==void 0&&this._addNodeRef(this.cameraCache,o.camera)}}_addNodeRef(t,e){e!==void 0&&(t.refs[e]===void 0&&(t.refs[e]=t.uses[e]=0),t.refs[e]++)}_getNodeRef(t,e,n){if(t.refs[e]<=1)return n;const s=n.clone(),r=(o,a)=>{const i=this.associations.get(o);i!=null&&this.associations.set(a,i);for(const[c,u]of o.children.entries())r(u,a.children[c])};return r(n,s),s.name+="_instance_"+t.uses[e]++,s}_invokeOne(t){const e=Object.values(this.plugins);e.push(this);for(let n=0;n<e.length;n++){const s=t(e[n]);if(s)return s}return null}_invokeAll(t){const e=Object.values(this.plugins);e.unshift(this);const n=[];for(let s=0;s<e.length;s++){const r=t(e[s]);r&&n.push(r)}return n}getDependency(t,e){const n=t+":"+e;let s=this.cache.get(n);if(!s){switch(t){case"scene":s=this.loadScene(e);break;case"node":s=this._invokeOne(function(r){return r.loadNode&&r.loadNode(e)});break;case"mesh":s=this._invokeOne(function(r){return r.loadMesh&&r.loadMesh(e)});break;case"accessor":s=this.loadAccessor(e);break;case"bufferView":s=this._invokeOne(function(r){return r.loadBufferView&&r.loadBufferView(e)});break;case"buffer":s=this.loadBuffer(e);break;case"material":s=this._invokeOne(function(r){return r.loadMaterial&&r.loadMaterial(e)});break;case"texture":s=this._invokeOne(function(r){return r.loadTexture&&r.loadTexture(e)});break;case"skin":s=this.loadSkin(e);break;case"animation":s=this._invokeOne(function(r){return r.loadAnimation&&r.loadAnimation(e)});break;case"camera":s=this.loadCamera(e);break;default:if(s=this._invokeOne(function(r){return r!=this&&r.getDependency&&r.getDependency(t,e)}),!s)throw new Error("Unknown type: "+t);break}this.cache.add(n,s)}return s}getDependencies(t){let e=this.cache.get(t);if(!e){const n=this,s=this.json[t+(t==="mesh"?"es":"s")]||[];e=Promise.all(s.map(function(r,o){return n.getDependency(t,o)})),this.cache.add(t,e)}return e}loadBuffer(t){const e=this.json.buffers[t],n=this.fileLoader;if(e.type&&e.type!=="arraybuffer")throw new Error("THREE.GLTFLoader: "+e.type+" buffer type is not supported.");if(e.uri===void 0&&t===0)return Promise.resolve(this.extensions[T.KHR_BINARY_GLTF].body);const s=this.options;return new Promise(function(r,o){n.load(h.LoaderUtils.resolveURL(e.uri,s.path),r,void 0,function(){o(new Error('THREE.GLTFLoader: Failed to load buffer "'+e.uri+'".'))})})}loadBufferView(t){const e=this.json.bufferViews[t];return this.getDependency("buffer",e.buffer).then(function(n){const s=e.byteLength||0,r=e.byteOffset||0;return n.slice(r,r+s)})}loadAccessor(t){const e=this,n=this.json,s=this.json.accessors[t];if(s.bufferView===void 0&&s.sparse===void 0){const o=D[s.type],a=O[s.componentType],i=s.normalized===!0,c=new a(s.count*o);return Promise.resolve(new h.BufferAttribute(c,o,i))}const r=[];return s.bufferView!==void 0?r.push(this.getDependency("bufferView",s.bufferView)):r.push(null),s.sparse!==void 0&&(r.push(this.getDependency("bufferView",s.sparse.indices.bufferView)),r.push(this.getDependency("bufferView",s.sparse.values.bufferView))),Promise.all(r).then(function(o){const a=o[0],i=D[s.type],c=O[s.componentType],u=c.BYTES_PER_ELEMENT,l=u*i,f=s.byteOffset||0,p=s.bufferView!==void 0?n.bufferViews[s.bufferView].byteStride:void 0,m=s.normalized===!0;let M,g;if(p&&p!==l){const R=Math.floor(f/p),A="InterleavedBuffer:"+s.bufferView+":"+s.componentType+":"+R+":"+s.count;let x=e.cache.get(A);x||(M=new c(a,R*p,s.count*p/u),x=new h.InterleavedBuffer(M,p/u),e.cache.add(A,x)),g=new h.InterleavedBufferAttribute(x,i,f%p/u,m)}else a===null?M=new c(s.count*i):M=new c(a,f,s.count*i),g=new h.BufferAttribute(M,i,m);if(s.sparse!==void 0){const R=D.SCALAR,A=O[s.sparse.indices.componentType],x=s.sparse.indices.byteOffset||0,E=s.sparse.values.byteOffset||0,L=new A(o[1],x,s.sparse.count*R),b=new c(o[2],E,s.sparse.count*i);a!==null&&(g=new h.BufferAttribute(g.array.slice(),g.itemSize,g.normalized)),g.normalized=!1;for(let y=0,P=L.length;y<P;y++){const C=L[y];if(g.setX(C,b[y*i]),i>=2&&g.setY(C,b[y*i+1]),i>=3&&g.setZ(C,b[y*i+2]),i>=4&&g.setW(C,b[y*i+3]),i>=5)throw new Error("THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.")}g.normalized=m}return g})}loadTexture(t){const e=this.json,n=this.options,r=e.textures[t].source,o=e.images[r];let a=this.textureLoader;if(o.uri){const i=n.manager.getHandler(o.uri);i!==null&&(a=i)}return this.loadTextureImage(t,r,a)}loadTextureImage(t,e,n){const s=this,r=this.json,o=r.textures[t],a=r.images[e],i=(a.uri||a.bufferView)+":"+o.sampler;if(this.textureCache[i])return this.textureCache[i];const c=this.loadImageSource(e,n).then(function(u){u.flipY=!1,u.name=o.name||a.name||"",u.name===""&&typeof a.uri=="string"&&a.uri.startsWith("data:image/")===!1&&(u.name=a.uri);const f=(r.samplers||{})[o.sampler]||{};return u.magFilter=V[f.magFilter]||h.LinearFilter,u.minFilter=V[f.minFilter]||h.LinearMipmapLinearFilter,u.wrapS=z[f.wrapS]||h.RepeatWrapping,u.wrapT=z[f.wrapT]||h.RepeatWrapping,u.generateMipmaps=!u.isCompressedTexture&&u.minFilter!==h.NearestFilter&&u.minFilter!==h.LinearFilter,s.associations.set(u,{textures:t}),u}).catch(function(){return null});return this.textureCache[i]=c,c}loadImageSource(t,e){const n=this,s=this.json,r=this.options;if(this.sourceCache[t]!==void 0)return this.sourceCache[t].then(l=>l.clone());const o=s.images[t],a=self.URL||self.webkitURL;let i=o.uri||"",c=!1;if(o.bufferView!==void 0)i=n.getDependency("bufferView",o.bufferView).then(function(l){c=!0;const f=new Blob([l],{type:o.mimeType});return i=a.createObjectURL(f),i});else if(o.uri===void 0)throw new Error("THREE.GLTFLoader: Image "+t+" is missing URI and bufferView");const u=Promise.resolve(i).then(function(l){return new Promise(function(f,p){let m=f;e.isImageBitmapLoader===!0&&(m=function(M){const g=new h.Texture(M);g.needsUpdate=!0,f(g)}),e.load(h.LoaderUtils.resolveURL(l,r.path),m,void 0,p)})}).then(function(l){return c===!0&&a.revokeObjectURL(i),w(l,o),l.userData.mimeType=o.mimeType||we(o.uri),l}).catch(function(l){throw console.error("THREE.GLTFLoader: Couldn't load texture",i),l});return this.sourceCache[t]=u,u}assignTexture(t,e,n,s){const r=this;return this.getDependency("texture",n.index).then(function(o){if(!o)return null;if(n.texCoord!==void 0&&n.texCoord>0&&(o=o.clone(),o.channel=n.texCoord),r.extensions[T.KHR_TEXTURE_TRANSFORM]){const a=n.extensions!==void 0?n.extensions[T.KHR_TEXTURE_TRANSFORM]:void 0;if(a){const i=r.associations.get(o);o=r.extensions[T.KHR_TEXTURE_TRANSFORM].extendTexture(o,a),r.associations.set(o,i)}}return s!==void 0&&(o.colorSpace=s),t[e]=o,o})}assignFinalMaterial(t){const e=t.geometry;let n=t.material;const s=e.attributes.tangent===void 0,r=e.attributes.color!==void 0,o=e.attributes.normal===void 0;if(t.isPoints){const a="PointsMaterial:"+n.uuid;let i=this.cache.get(a);i||(i=new h.PointsMaterial,h.Material.prototype.copy.call(i,n),i.color.copy(n.color),i.map=n.map,i.sizeAttenuation=!1,this.cache.add(a,i)),n=i}else if(t.isLine){const a="LineBasicMaterial:"+n.uuid;let i=this.cache.get(a);i||(i=new h.LineBasicMaterial,h.Material.prototype.copy.call(i,n),i.color.copy(n.color),i.map=n.map,this.cache.add(a,i)),n=i}if(s||r||o){let a="ClonedMaterial:"+n.uuid+":";s&&(a+="derivative-tangents:"),r&&(a+="vertex-colors:"),o&&(a+="flat-shading:");let i=this.cache.get(a);i||(i=n.clone(),r&&(i.vertexColors=!0),o&&(i.flatShading=!0),s&&(i.normalScale&&(i.normalScale.y*=-1),i.clearcoatNormalScale&&(i.clearcoatNormalScale.y*=-1)),this.cache.add(a,i),this.associations.set(i,this.associations.get(n))),n=i}t.material=n}getMaterialType(){return h.MeshStandardMaterial}loadMaterial(t){const e=this,n=this.json,s=this.extensions,r=n.materials[t];let o;const a={},i=r.extensions||{},c=[];if(i[T.KHR_MATERIALS_UNLIT]){const l=s[T.KHR_MATERIALS_UNLIT];o=l.getMaterialType(),c.push(l.extendParams(a,r,e))}else{const l=r.pbrMetallicRoughness||{};if(a.color=new h.Color(1,1,1),a.opacity=1,Array.isArray(l.baseColorFactor)){const f=l.baseColorFactor;a.color.setRGB(f[0],f[1],f[2],h.LinearSRGBColorSpace),a.opacity=f[3]}l.baseColorTexture!==void 0&&c.push(e.assignTexture(a,"map",l.baseColorTexture,h.SRGBColorSpace)),a.metalness=l.metallicFactor!==void 0?l.metallicFactor:1,a.roughness=l.roughnessFactor!==void 0?l.roughnessFactor:1,l.metallicRoughnessTexture!==void 0&&(c.push(e.assignTexture(a,"metalnessMap",l.metallicRoughnessTexture)),c.push(e.assignTexture(a,"roughnessMap",l.metallicRoughnessTexture))),o=this._invokeOne(function(f){return f.getMaterialType&&f.getMaterialType(t)}),c.push(Promise.all(this._invokeAll(function(f){return f.extendMaterialParams&&f.extendMaterialParams(t,a)})))}r.doubleSided===!0&&(a.side=h.DoubleSide);const u=r.alphaMode||G.OPAQUE;if(u===G.BLEND?(a.transparent=!0,a.depthWrite=!1):(a.transparent=!1,u===G.MASK&&(a.alphaTest=r.alphaCutoff!==void 0?r.alphaCutoff:.5)),r.normalTexture!==void 0&&o!==h.MeshBasicMaterial&&(c.push(e.assignTexture(a,"normalMap",r.normalTexture)),a.normalScale=new h.Vector2(1,1),r.normalTexture.scale!==void 0)){const l=r.normalTexture.scale;a.normalScale.set(l,l)}if(r.occlusionTexture!==void 0&&o!==h.MeshBasicMaterial&&(c.push(e.assignTexture(a,"aoMap",r.occlusionTexture)),r.occlusionTexture.strength!==void 0&&(a.aoMapIntensity=r.occlusionTexture.strength)),r.emissiveFactor!==void 0&&o!==h.MeshBasicMaterial){const l=r.emissiveFactor;a.emissive=new h.Color().setRGB(l[0],l[1],l[2],h.LinearSRGBColorSpace)}return r.emissiveTexture!==void 0&&o!==h.MeshBasicMaterial&&c.push(e.assignTexture(a,"emissiveMap",r.emissiveTexture,h.SRGBColorSpace)),Promise.all(c).then(function(){const l=new o(a);return r.name&&(l.name=r.name),w(l,r),e.associations.set(l,{materials:t}),r.extensions&&I(s,l,r),l})}createUniqueName(t){const e=h.PropertyBinding.sanitizeNodeName(t||"");return e in this.nodeNamesUsed?e+"_"+ ++this.nodeNamesUsed[e]:(this.nodeNamesUsed[e]=0,e)}loadGeometries(t){const e=this,n=this.extensions,s=this.primitiveCache;function r(a){return n[T.KHR_DRACO_MESH_COMPRESSION].decodePrimitive(a,e).then(function(i){return X(i,a,e)})}const o=[];for(let a=0,i=t.length;a<i;a++){const c=t[a],u=ye(c),l=s[u];if(l)o.push(l.promise);else{let f;c.extensions&&c.extensions[T.KHR_DRACO_MESH_COMPRESSION]?f=r(c):f=X(new h.BufferGeometry,c,e),s[u]={primitive:c,promise:f},o.push(f)}}return Promise.all(o)}loadMesh(t){const e=this,n=this.json,s=this.extensions,r=n.meshes[t],o=r.primitives,a=[];for(let i=0,c=o.length;i<c;i++){const u=o[i].material===void 0?_e(this.cache):this.getDependency("material",o[i].material);a.push(u)}return a.push(e.loadGeometries(o)),Promise.all(a).then(function(i){const c=i.slice(0,i.length-1),u=i[i.length-1],l=[];for(let p=0,m=u.length;p<m;p++){const M=u[p],g=o[p];let R;const A=c[p];if(g.mode===S.TRIANGLES||g.mode===S.TRIANGLE_STRIP||g.mode===S.TRIANGLE_FAN||g.mode===void 0)R=r.isSkinnedMesh===!0?new h.SkinnedMesh(M,A):new h.Mesh(M,A),R.isSkinnedMesh===!0&&R.normalizeSkinWeights(),g.mode===S.TRIANGLE_STRIP?R.geometry=h.toTrianglesDrawMode(R.geometry,h.TriangleStripDrawMode):g.mode===S.TRIANGLE_FAN&&(R.geometry=h.toTrianglesDrawMode(R.geometry,h.TriangleFanDrawMode));else if(g.mode===S.LINES)R=new h.LineSegments(M,A);else if(g.mode===S.LINE_STRIP)R=new h.Line(M,A);else if(g.mode===S.LINE_LOOP)R=new h.LineLoop(M,A);else if(g.mode===S.POINTS)R=new h.Points(M,A);else throw new Error("THREE.GLTFLoader: Primitive mode unsupported: "+g.mode);Object.keys(R.geometry.morphAttributes).length>0&&Se(R,r),R.name=e.createUniqueName(r.name||"mesh_"+t),w(R,r),g.extensions&&I(s,R,g),e.assignFinalMaterial(R),l.push(R)}for(let p=0,m=l.length;p<m;p++)e.associations.set(l[p],{meshes:t,primitives:p});if(l.length===1)return r.extensions&&I(s,l[0],r),l[0];const f=new h.Group;r.extensions&&I(s,f,r),e.associations.set(f,{meshes:t});for(let p=0,m=l.length;p<m;p++)f.add(l[p]);return f})}loadCamera(t){let e;const n=this.json.cameras[t],s=n[n.type];if(!s){console.warn("THREE.GLTFLoader: Missing camera parameters.");return}return n.type==="perspective"?e=new h.PerspectiveCamera(h.MathUtils.radToDeg(s.yfov),s.aspectRatio||1,s.znear||1,s.zfar||2e6):n.type==="orthographic"&&(e=new h.OrthographicCamera(-s.xmag,s.xmag,s.ymag,-s.ymag,s.znear,s.zfar)),n.name&&(e.name=this.createUniqueName(n.name)),w(e,n),Promise.resolve(e)}loadSkin(t){const e=this.json.skins[t],n=[];for(let s=0,r=e.joints.length;s<r;s++)n.push(this._loadNodeShallow(e.joints[s]));return e.inverseBindMatrices!==void 0?n.push(this.getDependency("accessor",e.inverseBindMatrices)):n.push(null),Promise.all(n).then(function(s){const r=s.pop(),o=s,a=[],i=[];for(let c=0,u=o.length;c<u;c++){const l=o[c];if(l){a.push(l);const f=new h.Matrix4;r!==null&&f.fromArray(r.array,c*16),i.push(f)}else console.warn('THREE.GLTFLoader: Joint "%s" could not be found.',e.joints[c])}return new h.Skeleton(a,i)})}loadAnimation(t){const e=this.json,n=this,s=e.animations[t],r=s.name?s.name:"animation_"+t,o=[],a=[],i=[],c=[],u=[];for(let l=0,f=s.channels.length;l<f;l++){const p=s.channels[l],m=s.samplers[p.sampler],M=p.target,g=M.node,R=s.parameters!==void 0?s.parameters[m.input]:m.input,A=s.parameters!==void 0?s.parameters[m.output]:m.output;M.node!==void 0&&(o.push(this.getDependency("node",g)),a.push(this.getDependency("accessor",R)),i.push(this.getDependency("accessor",A)),c.push(m),u.push(M))}return Promise.all([Promise.all(o),Promise.all(a),Promise.all(i),Promise.all(c),Promise.all(u)]).then(function(l){const f=l[0],p=l[1],m=l[2],M=l[3],g=l[4],R=[];for(let x=0,E=f.length;x<E;x++){const L=f[x],b=p[x],y=m[x],P=M[x],C=g[x];if(L===void 0)continue;L.updateMatrix&&L.updateMatrix();const k=n._createAnimationTracks(L,b,y,P,C);if(k)for(let H=0;H<k.length;H++)R.push(k[H])}const A=new h.AnimationClip(r,void 0,R);return w(A,s),A})}createNodeMesh(t){const e=this.json,n=this,s=e.nodes[t];return s.mesh===void 0?null:n.getDependency("mesh",s.mesh).then(function(r){const o=n._getNodeRef(n.meshCache,s.mesh,r);return s.weights!==void 0&&o.traverse(function(a){if(a.isMesh)for(let i=0,c=s.weights.length;i<c;i++)a.morphTargetInfluences[i]=s.weights[i]}),o})}loadNode(t){const e=this.json,n=this,s=e.nodes[t],r=n._loadNodeShallow(t),o=[],a=s.children||[];for(let c=0,u=a.length;c<u;c++)o.push(n.getDependency("node",a[c]));const i=s.skin===void 0?Promise.resolve(null):n.getDependency("skin",s.skin);return Promise.all([r,Promise.all(o),i]).then(function(c){const u=c[0],l=c[1],f=c[2];f!==null&&u.traverse(function(p){p.isSkinnedMesh&&p.bind(f,be)});for(let p=0,m=l.length;p<m;p++)u.add(l[p]);if(u.userData.pivot!==void 0&&l.length>0){const p=u.userData.pivot,m=l[0];u.pivot=new h.Vector3().fromArray(p),u.position.x-=p[0],u.position.y-=p[1],u.position.z-=p[2],m.position.set(0,0,0),delete u.userData.pivot}return u})}_loadNodeShallow(t){const e=this.json,n=this.extensions,s=this;if(this.nodeCache[t]!==void 0)return this.nodeCache[t];const r=e.nodes[t],o=r.name?s.createUniqueName(r.name):"",a=[],i=s._invokeOne(function(c){return c.createNodeMesh&&c.createNodeMesh(t)});return i&&a.push(i),r.camera!==void 0&&a.push(s.getDependency("camera",r.camera).then(function(c){return s._getNodeRef(s.cameraCache,r.camera,c)})),s._invokeAll(function(c){return c.createNodeAttachment&&c.createNodeAttachment(t)}).forEach(function(c){a.push(c)}),this.nodeCache[t]=Promise.all(a).then(function(c){let u;if(r.isBone===!0?u=new h.Bone:c.length>1?u=new h.Group:c.length===1?u=c[0]:u=new h.Object3D,u!==c[0])for(let l=0,f=c.length;l<f;l++)u.add(c[l]);if(r.name&&(u.userData.name=r.name,u.name=o),w(u,r),r.extensions&&I(n,u,r),r.matrix!==void 0){const l=new h.Matrix4;l.fromArray(r.matrix),u.applyMatrix4(l)}else r.translation!==void 0&&u.position.fromArray(r.translation),r.rotation!==void 0&&u.quaternion.fromArray(r.rotation),r.scale!==void 0&&u.scale.fromArray(r.scale);if(!s.associations.has(u))s.associations.set(u,{});else if(r.mesh!==void 0&&s.meshCache.refs[r.mesh]>1){const l=s.associations.get(u);s.associations.set(u,{...l})}return s.associations.get(u).nodes=t,u}),this.nodeCache[t]}loadScene(t){const e=this.extensions,n=this.json.scenes[t],s=this,r=new h.Group;n.name&&(r.name=s.createUniqueName(n.name)),w(r,n),n.extensions&&I(e,r,n);const o=n.nodes||[],a=[];for(let i=0,c=o.length;i<c;i++)a.push(s.getDependency("node",o[i]));return Promise.all(a).then(function(i){for(let u=0,l=i.length;u<l;u++){const f=i[u];f.parent!==null?r.add(Q(f)):r.add(f)}const c=u=>{const l=new Map;for(const[f,p]of s.associations)(f instanceof h.Material||f instanceof h.Texture)&&l.set(f,p);return u.traverse(f=>{const p=s.associations.get(f);p!=null&&l.set(f,p)}),l};return s.associations=c(r),r})}_createAnimationTracks(t,e,n,s,r){const o=[],a=t.name?t.name:t.uuid,i=[];N[r.path]===N.weights?t.traverse(function(f){f.morphTargetInfluences&&i.push(f.name?f.name:f.uuid)}):i.push(a);let c;switch(N[r.path]){case N.weights:c=h.NumberKeyframeTrack;break;case N.rotation:c=h.QuaternionKeyframeTrack;break;case N.translation:case N.scale:c=h.VectorKeyframeTrack;break;default:n.itemSize===1?c=h.NumberKeyframeTrack:c=h.VectorKeyframeTrack;break}const u=s.interpolation!==void 0?Ae[s.interpolation]:h.InterpolateLinear,l=this._getArrayFromAccessor(n);for(let f=0,p=i.length;f<p;f++){const m=new c(i[f]+"."+N[r.path],e.array,l,u);s.interpolation==="CUBICSPLINE"&&this._createCubicSplineTrackInterpolant(m),o.push(m)}return o}_getArrayFromAccessor(t){let e=t.array;if(t.normalized){const n=U(e.constructor),s=new Float32Array(e.length);for(let r=0,o=e.length;r<o;r++)s[r]=e[r]*n;e=s}return e}_createCubicSplineTrackInterpolant(t){t.createInterpolant=function(n){const s=this instanceof h.QuaternionKeyframeTrack?xe:Y;return new s(this.times,this.values,this.getValueSize()/3,n)},t.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline=!0}}function Ie(d,t,e){const n=t.attributes,s=new h.Box3;if(n.POSITION!==void 0){const a=e.json.accessors[n.POSITION],i=a.min,c=a.max;if(i!==void 0&&c!==void 0){if(s.set(new h.Vector3(i[0],i[1],i[2]),new h.Vector3(c[0],c[1],c[2])),a.normalized){const u=U(O[a.componentType]);s.min.multiplyScalar(u),s.max.multiplyScalar(u)}}else{console.warn("THREE.GLTFLoader: Missing min/max properties for accessor POSITION.");return}}else return;const r=t.targets;if(r!==void 0){const a=new h.Vector3,i=new h.Vector3;for(let c=0,u=r.length;c<u;c++){const l=r[c];if(l.POSITION!==void 0){const f=e.json.accessors[l.POSITION],p=f.min,m=f.max;if(p!==void 0&&m!==void 0){if(i.setX(Math.max(Math.abs(p[0]),Math.abs(m[0]))),i.setY(Math.max(Math.abs(p[1]),Math.abs(m[1]))),i.setZ(Math.max(Math.abs(p[2]),Math.abs(m[2]))),f.normalized){const M=U(O[f.componentType]);i.multiplyScalar(M)}a.max(i)}else console.warn("THREE.GLTFLoader: Missing min/max properties for accessor POSITION.")}}s.expandByVector(a)}d.boundingBox=s;const o=new h.Sphere;s.getCenter(o.center),o.radius=s.min.distanceTo(s.max)/2,d.boundingSphere=o}function X(d,t,e){const n=t.attributes,s=[];function r(o,a){return e.getDependency("accessor",o).then(function(i){d.setAttribute(a,i)})}for(const o in n){const a=B[o]||o.toLowerCase();a in d.attributes||s.push(r(n[o],a))}if(t.indices!==void 0&&!d.index){const o=e.getDependency("accessor",t.indices).then(function(a){d.setIndex(a)});s.push(o)}return h.ColorManagement.workingColorSpace!==h.LinearSRGBColorSpace&&"COLOR_0"in n&&console.warn(`THREE.GLTFLoader: Converting vertex colors from "srgb-linear" to "${h.ColorManagement.workingColorSpace}" not supported.`),w(d,t),Ie(d,t,e),Promise.all(s).then(function(){return t.targets!==void 0?Le(d,t.targets,e):d})}exports.GLTFLoader=J;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { DevicePlatform } from '../core/stream-utils';
|
|
2
|
+
import { ScreenshotData, ImperativeKeyboardEvent, RemoteControlConnectionState, MicrophoneState, CameraStreamStats } from '../core/stream-types';
|
|
1
3
|
import { default as React } from 'react';
|
|
4
|
+
import { PlaybackStats } from '../core/playback-stats';
|
|
2
5
|
import { AxStatus, AndroidElementTreeOptions } from '../core/ax-fetcher';
|
|
3
6
|
import { AxElement, AxSnapshot } from '../core/ax-tree';
|
|
4
7
|
import { CameraCaptureInfo } from '../core/camera';
|
|
8
|
+
export type { RemoteControlConnectionState, MicrophoneState, CameraStreamStats } from '../core/stream-types';
|
|
9
|
+
export { withAuthenticationToken } from '../core/stream-utils';
|
|
5
10
|
export type { CameraCaptureInfo, CameraFacingMode, CameraRequest, CameraResult } from '../core/camera';
|
|
6
11
|
declare global {
|
|
7
12
|
interface Window {
|
|
@@ -22,6 +27,23 @@ export interface RemoteControlProps {
|
|
|
22
27
|
/** Optional prepared Duo GLB, supplied and licensed by the host application. */
|
|
23
28
|
duoModelUrl?: string;
|
|
24
29
|
autoReconnect?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Preferred playback jitter buffer duration in milliseconds (0–4000), for
|
|
32
|
+
* incoming audio and video. Lower values can reduce latency but increase
|
|
33
|
+
* dropped frames or freezes. This is a preference, not a latency limit.
|
|
34
|
+
* Updates apply without reconnecting. Omit or pass null to use the browser
|
|
35
|
+
* default. Unsupported browsers ignore this prop. Invalid values are ignored
|
|
36
|
+
* with a console warning, leaving the previous target unchanged.
|
|
37
|
+
*/
|
|
38
|
+
jitterBufferTargetMs?: number | null;
|
|
39
|
+
/**
|
|
40
|
+
* Incoming playback stats, sampled every two seconds while subscribed,
|
|
41
|
+
* connected, and visible. Works with iOS and Android, including Duo displays.
|
|
42
|
+
* Missing measurements stay undefined; the first sample establishes a baseline.
|
|
43
|
+
* Emits null when collection pauses, disconnects, or fails after a sample.
|
|
44
|
+
* Buffer delay measures receiving-side buffering, not tap-to-screen latency.
|
|
45
|
+
*/
|
|
46
|
+
onPlaybackStats?: (stats: PlaybackStats | null) => void;
|
|
25
47
|
/**
|
|
26
48
|
* Fires once when the component concludes the instance is permanently
|
|
27
49
|
* gone rather than suffering a recoverable connection blip.
|
|
@@ -185,71 +207,6 @@ export interface RemoteControlProps {
|
|
|
185
207
|
*/
|
|
186
208
|
onMicrophoneStateChange?: (state: MicrophoneState) => void;
|
|
187
209
|
}
|
|
188
|
-
/**
|
|
189
|
-
* Snapshot of the live-microphone pipeline, reported through
|
|
190
|
-
* `onMicrophoneStateChange`.
|
|
191
|
-
*/
|
|
192
|
-
export interface MicrophoneState {
|
|
193
|
-
/** True while the browser mic is captured and streaming to the sim. */
|
|
194
|
-
active: boolean;
|
|
195
|
-
/**
|
|
196
|
-
* Human-readable failure from the last attempt, if any (permission
|
|
197
|
-
* denied, no device, host rejection, ...).
|
|
198
|
-
*/
|
|
199
|
-
error?: string;
|
|
200
|
-
/** Device label of the captured microphone, when available. */
|
|
201
|
-
label?: string;
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Live outbound-camera quality snapshot. Derived from
|
|
205
|
-
* `RTCPeerConnection.getStats()` and rate-derived deltas, sampled
|
|
206
|
-
* once per second while the camera is sending. All fields optional:
|
|
207
|
-
* some browsers omit fields (Safari rarely reports
|
|
208
|
-
* `encoderImplementation`), and the first sample after camera start
|
|
209
|
-
* has no delta-derived numbers yet.
|
|
210
|
-
*/
|
|
211
|
-
export interface CameraStreamStats {
|
|
212
|
-
/** "H264", "HEVC"/"H265", "VP9", "VP8", "AV1", etc. (uppercased). */
|
|
213
|
-
codec?: string;
|
|
214
|
-
/** e.g. "VideoToolbox" (hw), "OpenH264" (sw), "ExternalEncoder". */
|
|
215
|
-
encoderImplementation?: string;
|
|
216
|
-
/**
|
|
217
|
-
* Browser-reported hardware-acceleration hint. Some Chromium
|
|
218
|
-
* versions expose this via `powerEfficientEncoder`; we mirror it
|
|
219
|
-
* here so consumers don't have to know the spec quirk.
|
|
220
|
-
*/
|
|
221
|
-
hardwareAccelerated?: boolean;
|
|
222
|
-
/** Outbound encoded fps over the last sample window. */
|
|
223
|
-
framesPerSecond?: number;
|
|
224
|
-
/** Cumulative encoded frame count. */
|
|
225
|
-
framesEncoded?: number;
|
|
226
|
-
/** Outbound encoded bitrate (bits/s) over the last window. */
|
|
227
|
-
bitrateBps?: number;
|
|
228
|
-
/** Width/height the encoder is currently producing. */
|
|
229
|
-
width?: number;
|
|
230
|
-
height?: number;
|
|
231
|
-
/**
|
|
232
|
-
* One of `'none' | 'cpu' | 'bandwidth' | 'other'`. Mirrors
|
|
233
|
-
* Meet/Zoom's "limited by …" banners. Anything other than
|
|
234
|
-
* `'none'` means the encoder dropped resolution to keep up.
|
|
235
|
-
*/
|
|
236
|
-
qualityLimitationReason?: string;
|
|
237
|
-
/** Round-trip time in milliseconds, from the matching RTCP. */
|
|
238
|
-
rttMs?: number;
|
|
239
|
-
/** Packet-loss percentage over the last sample window (0..100). */
|
|
240
|
-
packetsLostPct?: number;
|
|
241
|
-
}
|
|
242
|
-
interface ScreenshotData {
|
|
243
|
-
dataUri: string;
|
|
244
|
-
}
|
|
245
|
-
export interface ImperativeKeyboardEvent {
|
|
246
|
-
type: 'keydown' | 'keyup';
|
|
247
|
-
code: string;
|
|
248
|
-
shiftKey?: boolean;
|
|
249
|
-
altKey?: boolean;
|
|
250
|
-
ctrlKey?: boolean;
|
|
251
|
-
metaKey?: boolean;
|
|
252
|
-
}
|
|
253
210
|
export interface RemoteControlHandle {
|
|
254
211
|
openUrl: (url: string) => void;
|
|
255
212
|
sendKeyEvent: (event: ImperativeKeyboardEvent) => void;
|
|
@@ -262,9 +219,6 @@ export interface RemoteControlHandle {
|
|
|
262
219
|
setInspectSelection: (element: AxElement | null) => void;
|
|
263
220
|
getAxStatus: () => AxStatus;
|
|
264
221
|
}
|
|
265
|
-
type DevicePlatform = 'ios' | 'android';
|
|
266
|
-
export declare const withAuthenticationToken: (url: string, token: string) => string;
|
|
267
|
-
export type RemoteControlConnectionState = 'connecting' | 'connected' | 'reconnecting' | 'failed' | 'terminated';
|
|
268
222
|
export type RemoteControlPlatformAssets = {
|
|
269
223
|
frame?: string;
|
|
270
224
|
frameLandscape?: string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AxSnapshot } from './ax-tree';
|
|
2
|
+
import { ScreenshotData, ImperativeKeyboardEvent } from './stream-types';
|
|
3
|
+
import { DeviceStreamOptions, DeviceStreamLiveOptions, DeviceStreamState, StreamDisplay, DeviceFrameSink } from './stream-options';
|
|
4
|
+
/** A browser session shared by RemoteControl and custom renderers. No React or CSS required. */
|
|
5
|
+
export declare function createDeviceStream(initialOptions: DeviceStreamOptions): {
|
|
6
|
+
start: () => void;
|
|
7
|
+
stop: () => void;
|
|
8
|
+
attachVideo: (video: HTMLVideoElement, display?: StreamDisplay) => () => void;
|
|
9
|
+
attachFrameSink: (sink: DeviceFrameSink, display?: StreamDisplay) => () => void;
|
|
10
|
+
dispose: () => void;
|
|
11
|
+
getState: () => DeviceStreamState;
|
|
12
|
+
updateOptions: (patch: Partial<DeviceStreamLiveOptions>) => void;
|
|
13
|
+
sendControl: (data: ArrayBuffer) => void;
|
|
14
|
+
sendTouch: (phase: "begin" | "move" | "end", x: number, y: number, width: number, height: number, pointerId?: number) => void;
|
|
15
|
+
sendText: (text: string) => void;
|
|
16
|
+
sendDisplayTouch: (action: number, display: number, x: number, y: number) => void;
|
|
17
|
+
sendDuoControl: (type: string, parameters: object) => Promise<void>;
|
|
18
|
+
pressButton: (button: "home" | "back" | "recents" | "power") => void;
|
|
19
|
+
rotate: () => void;
|
|
20
|
+
bumpActivity: () => void | undefined;
|
|
21
|
+
getAxStatus: () => import('./ax-fetcher').AxStatus;
|
|
22
|
+
openUrl: (newUrl: string) => void;
|
|
23
|
+
sendKeyEvent: (event: ImperativeKeyboardEvent) => void;
|
|
24
|
+
screenshot: (display?: "outer" | "inner") => Promise<ScreenshotData>;
|
|
25
|
+
terminateApp: (bundleId: string) => Promise<void>;
|
|
26
|
+
reconnect: () => void;
|
|
27
|
+
refreshAxTree: () => Promise<AxSnapshot>;
|
|
28
|
+
getAxSnapshot: () => AxSnapshot | null;
|
|
29
|
+
};
|
|
30
|
+
export type DeviceStream = ReturnType<typeof createDeviceStream>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Measurements for one incoming RTP stream. Missing browser fields stay undefined. */
|
|
2
|
+
export interface PlaybackTrackStats {
|
|
3
|
+
/** Browser stats identity. Changes when the RTP stream is replaced. */
|
|
4
|
+
id: string;
|
|
5
|
+
trackId: string;
|
|
6
|
+
/** Browser collection time in Unix milliseconds. */
|
|
7
|
+
timestamp: number;
|
|
8
|
+
/** Time between this stream's samples. Absent on the first sample. */
|
|
9
|
+
intervalMs?: number;
|
|
10
|
+
/** Average receiving-side buffer delay over the interval, not end-to-end latency. */
|
|
11
|
+
bufferDelayMs?: number;
|
|
12
|
+
/** Received media bitrate over the interval, in bits per second. */
|
|
13
|
+
bitrateBps?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface PlaybackVideoStats extends PlaybackTrackStats {
|
|
16
|
+
/** The main display, or the independently streamed inner display on iPhone Duo. */
|
|
17
|
+
display: 'primary' | 'inner';
|
|
18
|
+
/** Decoded frames per second over the interval. Static screens may send few frames. */
|
|
19
|
+
fps?: number;
|
|
20
|
+
/** Frames dropped during the interval, as reported by the browser. */
|
|
21
|
+
droppedFrames?: number;
|
|
22
|
+
/** Browser-reported freezes completed during the interval. */
|
|
23
|
+
freezes?: number;
|
|
24
|
+
}
|
|
25
|
+
export type PlaybackAudioStats = PlaybackTrackStats;
|
|
26
|
+
export interface PlaybackStats {
|
|
27
|
+
/** Latest incoming-stream collection time in Unix milliseconds. */
|
|
28
|
+
timestamp: number;
|
|
29
|
+
/** Configured preference; null means automatic. Absent when the prop is invalid. */
|
|
30
|
+
requestedTargetMs?: number | null;
|
|
31
|
+
/** Current round-trip time of the selected ICE pair, when reported by the browser. */
|
|
32
|
+
rttMs?: number;
|
|
33
|
+
/** Separate measurements for each incoming display; never sum their frame rates. */
|
|
34
|
+
video: PlaybackVideoStats[];
|
|
35
|
+
audio: PlaybackAudioStats[];
|
|
36
|
+
}
|
|
37
|
+
export interface PlaybackReceiver {
|
|
38
|
+
trackId: string;
|
|
39
|
+
kind: string;
|
|
40
|
+
mid: string | null;
|
|
41
|
+
display?: PlaybackVideoStats['display'];
|
|
42
|
+
}
|
|
43
|
+
/** Keep baselines per stream so reconnects and Duo displays cannot contaminate each other. */
|
|
44
|
+
export declare class PlaybackStatsReader {
|
|
45
|
+
private previous;
|
|
46
|
+
reset(): void;
|
|
47
|
+
read(report: RTCStatsReport, receivers: PlaybackReceiver[], target: number | null | undefined): PlaybackStats | null;
|
|
48
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PlaybackStats, PlaybackVideoStats } from './playback-stats';
|
|
2
|
+
export interface PlaybackConnection {
|
|
3
|
+
peer: RTCPeerConnection;
|
|
4
|
+
displays: Map<RTCRtpReceiver, PlaybackVideoStats['display']>;
|
|
5
|
+
}
|
|
6
|
+
/** Poll only visible, connected subscribers and discard stale asynchronous results. */
|
|
7
|
+
export declare function subscribePlaybackStats(connection: PlaybackConnection, callback: () => ((stats: PlaybackStats | null) => void) | undefined, target: () => number | null | undefined): () => void;
|