@vincentt-xr/sdk 2.0.0-alpha.7 → 2.0.0-alpha.8

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.
Files changed (275) hide show
  1. package/GROUNDING.md +1109 -13
  2. package/dist/{DebuggerUI-BjOMr8q_.js → DebuggerUI-C-ldiozL.js} +1 -1
  3. package/dist/{DebuggerUI-B6bP6P9r.cjs → DebuggerUI-CWX5EtQv.cjs} +1 -1
  4. package/dist/FaceMeshRenderer-BEEXZwS6.cjs +158 -0
  5. package/dist/FaceMeshRenderer-UuH5sTXG.js +1322 -0
  6. package/dist/FaceRetouch-C7h7x9kd.js +683 -0
  7. package/dist/FaceRetouch-DqftT26Y.cjs +134 -0
  8. package/dist/GLTFLoader-C5q63sKO.js +1633 -0
  9. package/dist/GLTFLoader-Cb_CRwmG.cjs +1 -0
  10. package/dist/SegmentationOverlay-DQuW3dsc.js +133 -0
  11. package/dist/SegmentationOverlay-aWVod8Kl.cjs +1 -0
  12. package/dist/assets/cache.d.ts +99 -0
  13. package/dist/assets/estimate.d.ts +11 -0
  14. package/dist/assets/index.d.ts +7 -0
  15. package/dist/assets/loaders.d.ts +28 -0
  16. package/dist/assets/react.d.ts +33 -0
  17. package/dist/calibration/calibration.d.ts +70 -0
  18. package/dist/calibration/index.d.ts +6 -0
  19. package/dist/calibration/storage.d.ts +13 -0
  20. package/dist/calibration/types.d.ts +53 -0
  21. package/dist/calibration/useXRCalibration.d.ts +46 -0
  22. package/dist/camera/CameraPermissionGate.d.ts +26 -0
  23. package/dist/camera/devices.d.ts +26 -0
  24. package/dist/camera/index.d.ts +8 -0
  25. package/dist/camera/permission.d.ts +86 -0
  26. package/dist/camera/useCameraPermission.d.ts +35 -0
  27. package/dist/capabilities/detect.d.ts +45 -0
  28. package/dist/capabilities/index.d.ts +5 -0
  29. package/dist/capabilities/types.d.ts +120 -0
  30. package/dist/capabilities/useXRCapabilities.d.ts +18 -0
  31. package/dist/compat/environment.d.ts +5 -0
  32. package/dist/compat/index.d.ts +4 -0
  33. package/dist/compat/run.d.ts +18 -0
  34. package/dist/compat/scenarios.d.ts +10 -0
  35. package/dist/compat/types.d.ts +101 -0
  36. package/dist/components/BodyTracker/index.d.ts +9 -0
  37. package/dist/components/FaceMesh/canonical/CanonicalFaceMeshRenderer.d.ts +33 -3
  38. package/dist/components/FaceMesh/canonical/parseCanonicalFaceModel.d.ts +12 -0
  39. package/dist/components/FaceMesh/canonical/shaders.d.ts +1 -1
  40. package/dist/components/FaceMesh/index.d.ts +1 -1
  41. package/dist/components/GestureListener/index.d.ts +11 -0
  42. package/dist/components/HandTracker/index.d.ts +10 -0
  43. package/dist/components/HolisticTracker/index.d.ts +69 -0
  44. package/dist/components/HolisticTracker/settings.d.ts +58 -0
  45. package/dist/components/HolisticTracker/signals.d.ts +49 -0
  46. package/dist/components/IrisEffect/IrisMaterial.d.ts +73 -0
  47. package/dist/components/IrisEffect/index.d.ts +51 -0
  48. package/dist/components/IrisEffect/settings.d.ts +117 -0
  49. package/dist/components/LipEffect/LipEffect.d.ts +7 -1
  50. package/dist/components/LipEffect/LipEffectMaterial.d.ts +43 -7
  51. package/dist/components/LipEffect/LipEffects.d.ts +9 -0
  52. package/dist/components/LipEffect/defaults.d.ts +27 -4
  53. package/dist/components/LipEffect/index.d.ts +11 -3
  54. package/dist/components/LipEffect/settings.d.ts +271 -0
  55. package/dist/components/LipEffect/types.d.ts +56 -9
  56. package/dist/components/LipEffect/useLipDesignTextures.d.ts +11 -0
  57. package/dist/components/LipEffect/uvGuide.d.ts +59 -0
  58. package/dist/components/PersonCutout/index.d.ts +50 -0
  59. package/dist/components/PersonCutout/personCutout.d.ts +16 -0
  60. package/dist/components/ScreenImage/components/ScreenImageBody.d.ts +1 -1
  61. package/dist/components/ScreenImage/index.d.ts +3 -1
  62. package/dist/components/ScreenImage/materials/ScreenImageBlendMaterial.d.ts +1 -1
  63. package/dist/components/ScreenImage/materials/ScreenImageMaskMaterial.d.ts +11 -0
  64. package/dist/components/ScreenImage/source.d.ts +6 -0
  65. package/dist/components/ScreenImage/types.d.ts +18 -0
  66. package/dist/components/SegmentationOverlay/SegmentationOverlay.d.ts +37 -0
  67. package/dist/components/SegmentationOverlay/SegmentationOverlayMaterial.d.ts +31 -0
  68. package/dist/components/SegmentationOverlay/index.d.ts +9 -0
  69. package/dist/components/SegmentationOverlay/maskTexture.d.ts +23 -0
  70. package/dist/components/SegmentationOverlay/providers.d.ts +72 -0
  71. package/dist/components/SegmentationOverlay/settings.d.ts +65 -0
  72. package/dist/components/XRProvider/index.d.ts +16 -2
  73. package/dist/components/XRViewport/hooks/useViewportExternalFaces.d.ts +1 -1
  74. package/dist/components/XRViewport/hooks/useViewportMediaSource.d.ts +1 -1
  75. package/dist/components/XRViewport/hooks/useViewportPipeline.d.ts +1 -1
  76. package/dist/components/index.d.ts +3 -0
  77. package/dist/constants/index.d.ts +4 -1
  78. package/dist/contexts-CO0sd4JQ.cjs +1 -0
  79. package/dist/{contexts-ByhzppYl.js → contexts-FzlnnMYD.js} +252 -246
  80. package/dist/coordinates/feed.d.ts +52 -0
  81. package/dist/coordinates/index.d.ts +5 -0
  82. package/dist/coordinates/spaces.d.ts +49 -0
  83. package/dist/coordinates/viewport.d.ts +22 -0
  84. package/dist/coordinates/world.d.ts +15 -0
  85. package/dist/debug-ui/gesture-settings/index.d.ts +14 -0
  86. package/dist/debug-ui/holistic-tracker-settings/index.d.ts +16 -0
  87. package/dist/debug-ui/index.d.ts +14 -0
  88. package/dist/debug-ui/iris-effect-settings/index.d.ts +12 -0
  89. package/dist/debug-ui/lip-effect-settings/index.d.ts +15 -0
  90. package/dist/debug-ui/media-source.cjs +1 -1
  91. package/dist/debug-ui/media-source.js +1 -1
  92. package/dist/debug-ui/product-hotspots/index.d.ts +24 -0
  93. package/dist/debug-ui/segmentation-overlay-settings/index.d.ts +12 -0
  94. package/dist/debug-ui/xr-diagnostics/index.d.ts +25 -0
  95. package/dist/debug-ui.cjs +3 -3
  96. package/dist/debug-ui.js +2057 -1687
  97. package/dist/detector-K8aej4MB.js +59 -0
  98. package/dist/detector-ijypGtse.cjs +1 -0
  99. package/dist/entries/core.d.ts +18 -1
  100. package/dist/entries/face-effects.d.ts +11 -3
  101. package/dist/entries/low-level.d.ts +22 -3
  102. package/dist/entries/product.d.ts +11 -0
  103. package/dist/entries/tracking.d.ts +24 -1
  104. package/dist/face-effects.cjs +155 -1
  105. package/dist/face-effects.js +1134 -2197
  106. package/dist/gestures/definitions.d.ts +85 -0
  107. package/dist/gestures/detector.d.ts +87 -0
  108. package/dist/gestures/index.d.ts +8 -0
  109. package/dist/gestures/measures.d.ts +101 -0
  110. package/dist/gestures/settings.d.ts +49 -0
  111. package/dist/{getFaceInfo-C4QpCQIY.js → getFaceInfo-BkZfaQs-.js} +5 -5
  112. package/dist/{getFaceInfo-fA1bFBub.cjs → getFaceInfo-ahPxQFGu.cjs} +1 -1
  113. package/dist/hooks/selectors.d.ts +68 -1
  114. package/dist/hooks/useCalibrationFaceTracker.d.ts +1 -1
  115. package/dist/hooks/useFaceInfo.d.ts +13 -1
  116. package/dist/hooks/useFaceInfos.d.ts +1 -1
  117. package/dist/hooks/useGesture.d.ts +32 -0
  118. package/dist/hooks/useIrisTracking.d.ts +45 -0
  119. package/dist/hooks/useXRDiagnostics.d.ts +81 -0
  120. package/dist/hooks/useXRModel.d.ts +7 -0
  121. package/dist/hooks/useXRSession/facade.d.ts +42 -2
  122. package/dist/hooks/useXRSession/index.d.ts +2 -2
  123. package/dist/hooks/useXRSession/reason.d.ts +3 -1
  124. package/dist/hooks/useXRSession/registry.d.ts +14 -0
  125. package/dist/hooks/useXRSession/store.d.ts +52 -3
  126. package/dist/index--RgGzZ6X.cjs +47 -0
  127. package/dist/{index-VJ0SJwmG.js → index-CHVbH0hz.js} +4 -4
  128. package/dist/index-CeVkgsag.cjs +1 -0
  129. package/dist/index-CnGox6Xr.js +3054 -0
  130. package/dist/{index-ByoNj0QP.js → index-CsUdQ-pn.js} +113 -111
  131. package/dist/{index-BjmTe9eM.cjs → index-DKBAh6hV.cjs} +1 -1
  132. package/dist/index-DsZwTfG0.cjs +1 -0
  133. package/dist/index-Dw6tj2Mi.js +144 -0
  134. package/dist/index-OCPjOaeP.cjs +1 -0
  135. package/dist/{index-DXT3WccE.js → index-s9pF4zkG.js} +1065 -1101
  136. package/dist/internal-BYza1h8_.cjs +1 -0
  137. package/dist/{internal-Dmk1cTXq.js → internal-vsfNQycj.js} +15 -16
  138. package/dist/internal.cjs +1 -1
  139. package/dist/internal.js +2 -2
  140. package/dist/iris/compute.d.ts +25 -0
  141. package/dist/iris/index.d.ts +4 -0
  142. package/dist/iris/lead.d.ts +19 -0
  143. package/dist/iris/types.d.ts +87 -0
  144. package/dist/landmarkMask-CbTFzBYG.js +224 -0
  145. package/dist/landmarkMask-u7es2k4X.cjs +1 -0
  146. package/dist/low-level.cjs +1 -1
  147. package/dist/low-level.js +1085 -634
  148. package/dist/main.cjs +1 -1
  149. package/dist/main.js +1519 -465
  150. package/dist/measures-9dQPdw96.js +154 -0
  151. package/dist/measures-KfJzpvod.cjs +1 -0
  152. package/dist/models/Base/index.d.ts +49 -0
  153. package/dist/models/Body/index.d.ts +1 -1
  154. package/dist/models/Face/index.d.ts +1 -1
  155. package/dist/models/Hand/GestureTracking.d.ts +1 -1
  156. package/dist/models/Hand/HandTracking.d.ts +1 -1
  157. package/dist/models/Holistic/index.d.ts +49 -0
  158. package/dist/models/Holistic/result.d.ts +68 -0
  159. package/dist/models/SemanticSegmentation/index.d.ts +31 -0
  160. package/dist/models/SemanticSegmentation/presets.d.ts +28 -0
  161. package/dist/models/index.d.ts +2 -0
  162. package/dist/product/ProductDimensions.d.ts +16 -0
  163. package/dist/product/ProductHotspot.d.ts +16 -0
  164. package/dist/product/ProductViewer.d.ts +9 -0
  165. package/dist/product/details.d.ts +53 -0
  166. package/dist/product/index.d.ts +14 -0
  167. package/dist/product/loadModelViewer.d.ts +4 -0
  168. package/dist/product/types.d.ts +71 -0
  169. package/dist/product/useProductAr.d.ts +37 -0
  170. package/dist/product/useProductDetails.d.ts +60 -0
  171. package/dist/product.cjs +1 -0
  172. package/dist/product.js +414 -0
  173. package/dist/providers-C0Dlhh9Z.js +365 -0
  174. package/dist/providers-YNwkmNeK.cjs +62 -0
  175. package/dist/quality/XRQualityController.d.ts +25 -0
  176. package/dist/quality/controller.d.ts +33 -0
  177. package/dist/quality/index.d.ts +6 -0
  178. package/dist/quality/types.d.ts +100 -0
  179. package/dist/quality/useXRQuality.d.ts +28 -0
  180. package/dist/{renderGroups-KZk6eRiY.js → renderGroups-CN1cGFUo.js} +1 -1
  181. package/dist/{renderGroups-80H3DpTl.cjs → renderGroups-O4KmaMl9.cjs} +1 -1
  182. package/dist/renderPasses-Cg-zqmEz.cjs +21 -0
  183. package/dist/renderPasses-NnKZVfBy.js +1460 -0
  184. package/dist/scene-object.cjs +1 -1
  185. package/dist/scene-object.js +2 -2
  186. package/dist/screenTransform-BenfCtZt.js +44 -0
  187. package/dist/screenTransform-BiXdpVf0.cjs +1 -0
  188. package/dist/segmentation-9PhSvc-R.cjs +1 -0
  189. package/dist/segmentation-CeOTKemr.js +5 -0
  190. package/dist/segmentation2d/faceMemory.d.ts +28 -0
  191. package/dist/segmentation2d/faceRegions.d.ts +24 -0
  192. package/dist/segmentation2d/index.d.ts +9 -0
  193. package/dist/segmentation2d/maskUv.d.ts +23 -0
  194. package/dist/segmentation2d/rasterize.d.ts +14 -0
  195. package/dist/segmentation2d/types.d.ts +46 -0
  196. package/dist/selectors-C5G1PMYL.js +195 -0
  197. package/dist/selectors-Du_PsVnW.cjs +1 -0
  198. package/dist/{session-CpkiK5YA.cjs → session-BBr0yN8h.cjs} +7 -7
  199. package/dist/{session-DLFN_VII.js → session-Cy0m7l7-.js} +76 -76
  200. package/dist/settings-DRR7-snV.cjs +1 -0
  201. package/dist/settings-aQk845NJ.js +73 -0
  202. package/dist/subjects/index.d.ts +2 -0
  203. package/dist/subjects/select.d.ts +62 -0
  204. package/dist/subjects/types.d.ts +55 -0
  205. package/dist/tracking-config/apply.d.ts +57 -0
  206. package/dist/tracking-config/index.d.ts +7 -0
  207. package/dist/tracking-config/resolve.d.ts +25 -0
  208. package/dist/tracking-config/storage.d.ts +8 -0
  209. package/dist/tracking-config/types.d.ts +106 -0
  210. package/dist/tracking-config/useXRTrackingConfig.d.ts +38 -0
  211. package/dist/tracking.cjs +1 -1
  212. package/dist/tracking.js +1056 -383
  213. package/dist/types/compositor.d.ts +21 -0
  214. package/dist/types/holistic.d.ts +121 -0
  215. package/dist/types/index.d.ts +1 -0
  216. package/dist/types/model.d.ts +22 -2
  217. package/dist/types/nodes.d.ts +27 -2
  218. package/dist/types/segmentation.d.ts +19 -0
  219. package/dist/types/session.d.ts +41 -3
  220. package/dist/useFaceInfo-Blf7FCu3.js +303 -0
  221. package/dist/useFaceInfo-C5mO8NQY.cjs +1 -0
  222. package/dist/useXRCapabilities-B1R2ghy-.cjs +1 -0
  223. package/dist/useXRCapabilities-C68v__wB.js +30 -0
  224. package/dist/utils/fns.d.ts +6 -3
  225. package/dist/utils/integrity.d.ts +4 -1
  226. package/dist/utils/updateThrottle.d.ts +2 -0
  227. package/dist/utils/useStableUniforms.d.ts +18 -0
  228. package/docs/api/adaptive-quality.mdx +104 -0
  229. package/docs/api/asset-lifecycle.mdx +78 -0
  230. package/docs/api/camera-permission.mdx +142 -0
  231. package/docs/api/coordinate-spaces.mdx +165 -0
  232. package/docs/api/cross-camera.mdx +88 -0
  233. package/docs/api/diagnostics-calibration.mdx +97 -0
  234. package/docs/api/face-effects.mdx +6 -0
  235. package/docs/api/face-mesh.mdx +4 -2
  236. package/docs/api/gestures.mdx +173 -0
  237. package/docs/api/holistic-tracker.mdx +159 -0
  238. package/docs/api/iris-tracking.mdx +242 -0
  239. package/docs/api/multi-subject.mdx +95 -0
  240. package/docs/api/person-cutout.mdx +136 -0
  241. package/docs/api/product-ar.mdx +111 -0
  242. package/docs/api/product-details.mdx +78 -0
  243. package/docs/api/screen-space-coordinates.mdx +4 -1
  244. package/docs/api/segmentation-overlay.mdx +301 -0
  245. package/docs/api/session-lifecycle.mdx +136 -0
  246. package/docs/api/trackers.mdx +5 -0
  247. package/docs/api/tracking-config.mdx +108 -0
  248. package/docs/docs.json +23 -1
  249. package/docs/examples/lip-shaders.mdx +224 -0
  250. package/docs/guides/lip-effect-textures.mdx +292 -0
  251. package/docs/guides/lip-uv-template.png +0 -0
  252. package/docs/guides/lip-uv-template.svg +1 -0
  253. package/package.json +13 -1
  254. package/dist/FaceMeshRenderer-C5l6VLdO.cjs +0 -155
  255. package/dist/FaceMeshRenderer-wjAHrJzP.js +0 -1270
  256. package/dist/FaceRetouch-BkJzoA79.cjs +0 -134
  257. package/dist/FaceRetouch-DwbKQJAN.js +0 -551
  258. package/dist/contexts-Dr62It_K.cjs +0 -1
  259. package/dist/index-9dlAQAhy.js +0 -1462
  260. package/dist/index-BpEf2BBb.cjs +0 -1
  261. package/dist/index-CyUUurQT.cjs +0 -1
  262. package/dist/index-DCiMbxC3.cjs +0 -1
  263. package/dist/index-DpI-qo5X.cjs +0 -17
  264. package/dist/index-DyVF4vEW.js +0 -111
  265. package/dist/internal-Cq-TEQ5Y.cjs +0 -1
  266. package/dist/renderLayers-lDtL0_43.cjs +0 -1
  267. package/dist/renderLayers-zrK2pv5O.js +0 -13
  268. package/dist/renderPasses-BOoBSr8z.cjs +0 -21
  269. package/dist/renderPasses-BcquyVtu.js +0 -1500
  270. package/dist/selectors-B8H97CKA.js +0 -59
  271. package/dist/selectors-CZLKT2Iv.cjs +0 -1
  272. package/dist/useFaceInfo-BJ8-_MOs.cjs +0 -1
  273. package/dist/useFaceInfo-Dk426LTu.js +0 -62
  274. package/dist/useFaceResults-CtetsO9M.js +0 -19
  275. package/dist/useFaceResults-wBJF3zyp.cjs +0 -1
@@ -0,0 +1,3054 @@
1
+ var ns = Object.defineProperty;
2
+ var rs = (t, s, e) => s in t ? ns(t, s, { enumerable: !0, configurable: !0, writable: !0, value: e }) : t[s] = e;
3
+ var d = (t, s, e) => rs(t, typeof s != "symbol" ? s + "" : s, e);
4
+ import { jsxs as as, jsx as et } from "react/jsx-runtime";
5
+ import { useRef as ie, useMemo as he, useEffect as ce, useContext as De, useCallback as tt, createElement as is, createContext as ut, useState as os } from "react";
6
+ import { FilesetResolver as j, PoseLandmarker as cs, FaceLandmarker as ls, GestureRecognizer as ds, HolisticLandmarker as us, HandLandmarker as hs, ImageSegmenter as ht, DrawingUtils as ms } from "@mediapipe/tasks-vision";
7
+ import * as B from "three";
8
+ import { RGBAFormat as mt, LinearFilter as pe, CanvasTexture as ft, SRGBColorSpace as fs } from "three";
9
+ const gs = (t, s) => s, U = {
10
+ apiBaseUrl: gs(void 0, "https://api.vincentt.studio"),
11
+ // Pinned to the CDN, NOT build-env-driven: a stale VITE_ASSET_STORAGE_ENDPOINT
12
+ // baked a now-deleted CloudFront domain into every published bundle, breaking
13
+ // WASM/model loads at runtime. The host must never come from a mutable env value.
14
+ assetStorageEndpoint: "https://cdn.vincentt.studio",
15
+ // Versioned bucket for SDK-shipped reference assets (canonical face model, face textures, etc.).
16
+ sdkAssetsBaseUrl: "https://cdn.vincentt.studio/assets/sdk/face/v1",
17
+ loggerPrefix: "[vincentt-xr]:",
18
+ sessionCheckInterval: 3e4
19
+ };
20
+ var F = /* @__PURE__ */ ((t) => (t.WEBCAM = "webcam", t.STREAM = "stream", t.CANVAS = "canvas", t))(F || {}), R = /* @__PURE__ */ ((t) => (t.HAND_TRACKER = "vincentt.xr.hand-tracker", t.GESTURE_TRACKER = "vincentt.xr.gesture-tracker", t.FACE_TRACKER = "vincentt.xr.face-tracker", t.BODY_TRACKER = "vincentt.xr.body-tracker", t.HOLISTIC_TRACKER = "vincentt.xr.holistic-tracker", t.BACKGROUND_SEGMENTATION = "vincentt.xr.background-segmentation", t.SEMANTIC_SEGMENTATION = "vincentt.xr.semantic-segmentation", t))(R || {});
21
+ const Ee = (t) => Array.from({ length: t }, () => ({ x: 0, y: 0, z: 0 }));
22
+ class ps {
23
+ constructor(s) {
24
+ d(this, "slots", []);
25
+ this.options = s;
26
+ }
27
+ setOptions(s) {
28
+ this.options = s;
29
+ }
30
+ /** Landmark sets to draw this frame: live faces, plus held/predicted ones. */
31
+ update(s, e) {
32
+ const { holdMs: n, predictMs: r, maxVelocityGapMs: a = 250 } = this.options, o = [], c = Math.max(s.length, this.slots.length);
33
+ for (let l = 0; l < c; l += 1) {
34
+ const h = s[l], f = this.slots[l] ?? null;
35
+ if (h && h.length > 0) {
36
+ const S = f && f.points.length === h.length ? f : null, k = S ?? {
37
+ points: Ee(h.length),
38
+ velocity: Ee(h.length),
39
+ lastSeen: e,
40
+ output: Ee(h.length)
41
+ }, x = (e - k.lastSeen) / 1e3, T = S !== null && x > 0 && x * 1e3 <= a;
42
+ for (let _ = 0; _ < h.length; _ += 1) {
43
+ const g = h[_], v = k.points[_], y = k.velocity[_], C = g.z ?? 0;
44
+ T ? (y.x = 0.5 * y.x + 0.5 * ((g.x - v.x) / x), y.y = 0.5 * y.y + 0.5 * ((g.y - v.y) / x), y.z = 0.5 * y.z + 0.5 * ((C - v.z) / x)) : (y.x = 0, y.y = 0, y.z = 0), v.x = g.x, v.y = g.y, v.z = C;
45
+ }
46
+ k.lastSeen = e, this.slots[l] = k, o.push(h);
47
+ continue;
48
+ }
49
+ if (!f) continue;
50
+ const u = e - f.lastSeen;
51
+ if (u > n) {
52
+ this.slots[l] = null;
53
+ continue;
54
+ }
55
+ const w = Math.max(0, Math.min(u, r)) / 1e3;
56
+ for (let S = 0; S < f.points.length; S += 1)
57
+ f.output[S].x = f.points[S].x + f.velocity[S].x * w, f.output[S].y = f.points[S].y + f.velocity[S].y * w, f.output[S].z = f.points[S].z + f.velocity[S].z * w;
58
+ o.push(f.output);
59
+ }
60
+ for (; this.slots.length > 0 && this.slots[this.slots.length - 1] === null; ) this.slots.pop();
61
+ return o;
62
+ }
63
+ reset() {
64
+ this.slots = [];
65
+ }
66
+ }
67
+ const le = (t, s = { x: 0, y: 0, z: 0 }) => (s.x = t.x * 2 - 1, s.y = 1 - t.y * 2, s.z = -t.z, s), Qn = (t, s = { x: 0, y: 0, z: 0 }) => (s.x = (t.x + 1) / 2, s.y = (1 - t.y) / 2, s.z = -t.z, s), gt = "https://storage.googleapis.com/mediapipe-models/holistic_landmarker/holistic_landmarker/float16/latest/holistic_landmarker.task", ys = 250, ws = 0, vs = 768, Pe = (t) => ({
68
+ hands: (t == null ? void 0 : t.hands) ?? "both",
69
+ analysisMaxDimension: (t == null ? void 0 : t.analysisMaxDimension) ?? vs,
70
+ holdMs: (t == null ? void 0 : t.holdMs) ?? ys,
71
+ predictMs: (t == null ? void 0 : t.predictMs) ?? ws
72
+ }), Ss = () => ({
73
+ version: 0,
74
+ timestampMs: 0,
75
+ face: null,
76
+ leftHand: null,
77
+ rightHand: null,
78
+ pose: null
79
+ }), st = [
80
+ 0,
81
+ 4,
82
+ 5,
83
+ 6,
84
+ 1,
85
+ 2,
86
+ 3,
87
+ 8,
88
+ 7,
89
+ 10,
90
+ 9,
91
+ 12,
92
+ 11,
93
+ 14,
94
+ 13,
95
+ 16,
96
+ 15,
97
+ 18,
98
+ 17,
99
+ 20,
100
+ 19,
101
+ 22,
102
+ 21,
103
+ 24,
104
+ 23,
105
+ 26,
106
+ 25,
107
+ 28,
108
+ 27,
109
+ 30,
110
+ 29,
111
+ 32,
112
+ 31
113
+ ], nt = (t, s) => {
114
+ if (t.length !== st.length) return t;
115
+ s.length = t.length;
116
+ for (let e = 0; e < t.length; e += 1) s[e] = t[st[e]];
117
+ return s;
118
+ };
119
+ class ge {
120
+ constructor(s, e) {
121
+ d(this, "memory");
122
+ d(this, "holdMs");
123
+ d(this, "lastLiveMs", -1 / 0);
124
+ d(this, "lastConfidence", 0);
125
+ this.holdMs = s, this.memory = new ps({ holdMs: s, predictMs: e });
126
+ }
127
+ setOptions(s, e) {
128
+ this.holdMs = s, this.memory.setOptions({ holdMs: s, predictMs: e });
129
+ }
130
+ reset() {
131
+ this.memory.reset(), this.lastLiveMs = -1 / 0, this.lastConfidence = 0;
132
+ }
133
+ /**
134
+ * Returns the landmarks to publish this frame (live, or replayed from
135
+ * memory), or `undefined` when the stream is neither detected nor held.
136
+ * A held stream's confidence decays linearly from the last live value to
137
+ * 0 at `holdMs`.
138
+ */
139
+ bridge(s, e, n) {
140
+ const r = s !== void 0 && s.length > 0, a = this.memory.update(r ? [s] : [], n)[0];
141
+ if (!a) return;
142
+ if (r)
143
+ return this.lastLiveMs = n, this.lastConfidence = e, { points: a, held: !1, confidence: e };
144
+ const o = n - this.lastLiveMs, c = this.holdMs > 0 ? Math.max(0, 1 - o / this.holdMs) : 0;
145
+ return { points: a, held: !0, confidence: this.lastConfidence * c };
146
+ }
147
+ }
148
+ const ae = (t, s, e) => {
149
+ for (t.length > s && (t.length = s); t.length < s; ) t.push(e());
150
+ return t;
151
+ }, Ae = (t, s) => {
152
+ t.x = s.x, t.y = s.y, t.z = s.z;
153
+ }, Ms = (t) => {
154
+ if (t.length === 0) return 0;
155
+ let s = 0;
156
+ for (let e = 0; e < t.length; e += 1) s += t[e].visibility ?? 0;
157
+ return s / t.length;
158
+ };
159
+ class ks {
160
+ constructor(s) {
161
+ d(this, "options", Pe());
162
+ d(this, "faceMemory", new ge(this.options.holdMs, this.options.predictMs));
163
+ d(this, "leftHandMemory", new ge(this.options.holdMs, this.options.predictMs));
164
+ d(this, "rightHandMemory", new ge(this.options.holdMs, this.options.predictMs));
165
+ d(this, "poseMemory", new ge(this.options.holdMs, this.options.predictMs));
166
+ d(this, "face", {
167
+ landmarks: [],
168
+ blendshapes: {},
169
+ confidence: 0,
170
+ held: !1
171
+ });
172
+ d(this, "leftHand", {
173
+ handedness: "left",
174
+ landmarks: [],
175
+ worldLandmarks: [],
176
+ confidence: 0,
177
+ held: !1
178
+ });
179
+ d(this, "rightHand", {
180
+ handedness: "right",
181
+ landmarks: [],
182
+ worldLandmarks: [],
183
+ confidence: 0,
184
+ held: !1
185
+ });
186
+ d(this, "poseScratch", []);
187
+ d(this, "poseWorldScratch", []);
188
+ d(this, "pose", {
189
+ landmarks: [],
190
+ worldLandmarks: [],
191
+ visibility: [],
192
+ confidence: 0,
193
+ held: !1
194
+ });
195
+ this.setOptions(s);
196
+ }
197
+ getOptions() {
198
+ return this.options;
199
+ }
200
+ setOptions(s) {
201
+ this.options = Pe({ ...this.options, ...s });
202
+ const { holdMs: e, predictMs: n } = this.options;
203
+ for (const r of this.memories()) r.setOptions(e, n);
204
+ }
205
+ reset() {
206
+ for (const s of this.memories()) s.reset();
207
+ }
208
+ memories() {
209
+ return [this.faceMemory, this.leftHandMemory, this.rightHandMemory, this.poseMemory];
210
+ }
211
+ /**
212
+ * Publish `raw` (or a miss when `undefined`) into `result` at `nowMs`.
213
+ *
214
+ * `mirrored` says the analysed frame is a mirror of the person (the
215
+ * session's webcam feed). Pose left/right follow the image, and holistic
216
+ * assigns hands from the pose, so on a mirrored frame MediaPipe's "left"
217
+ * is the person's right. Swap both the hands and the pose's left/right
218
+ * landmarks so the whole result is anatomical and self-consistent
219
+ * (`leftHand` and pose wrist 15 are the same physical hand), matching the
220
+ * convention `HandTracker` reports on that feed.
221
+ */
222
+ update(s, e, n, r = !1) {
223
+ var h, f, u, w;
224
+ n.face = this.updateFace(s, e);
225
+ const a = {
226
+ landmarks: (h = s == null ? void 0 : s.leftHandLandmarks) == null ? void 0 : h[0],
227
+ world: (f = s == null ? void 0 : s.leftHandWorldLandmarks) == null ? void 0 : f[0]
228
+ }, o = {
229
+ landmarks: (u = s == null ? void 0 : s.rightHandLandmarks) == null ? void 0 : u[0],
230
+ world: (w = s == null ? void 0 : s.rightHandWorldLandmarks) == null ? void 0 : w[0]
231
+ }, c = r ? o : a, l = r ? a : o;
232
+ return n.leftHand = this.updateHand("left", c.landmarks, c.world, e), n.rightHand = this.updateHand("right", l.landmarks, l.world, e), n.pose = this.updatePose(s, e, r), n.timestampMs = e, n.version += 1, n;
233
+ }
234
+ updateFace(s, e) {
235
+ var c, l, h, f;
236
+ const n = (c = s == null ? void 0 : s.faceLandmarks) == null ? void 0 : c[0], r = this.faceMemory.bridge(n, 1, e);
237
+ if (!r) return null;
238
+ const { face: a } = this, o = !r.held && n;
239
+ ae(a.landmarks, r.points.length, () => ({
240
+ x: 0,
241
+ y: 0,
242
+ z: 0,
243
+ visibility: 0
244
+ }));
245
+ for (let u = 0; u < r.points.length; u += 1) {
246
+ const w = a.landmarks[u];
247
+ Ae(w, r.points[u]), w.visibility = o ? ((l = n[u]) == null ? void 0 : l.visibility) ?? 0 : 0;
248
+ }
249
+ if (o) {
250
+ const u = (f = (h = s == null ? void 0 : s.faceBlendshapes) == null ? void 0 : h[0]) == null ? void 0 : f.categories;
251
+ if (u)
252
+ for (const w of u) a.blendshapes[w.categoryName] = w.score;
253
+ }
254
+ return a.confidence = r.confidence, a.held = r.held, a;
255
+ }
256
+ updateHand(s, e, n, r) {
257
+ const a = s === "left" ? this.leftHandMemory : this.rightHandMemory, { hands: o } = this.options;
258
+ if (o === "none" || o !== "both" && o !== s)
259
+ return a.reset(), null;
260
+ const c = a.bridge(e, 1, r);
261
+ if (!c) return null;
262
+ const l = s === "left" ? this.leftHand : this.rightHand;
263
+ ae(l.landmarks, c.points.length, () => ({ x: 0, y: 0, z: 0 }));
264
+ for (let h = 0; h < c.points.length; h += 1)
265
+ le(c.points[h], l.landmarks[h]);
266
+ if (!c.held && n) {
267
+ ae(l.worldLandmarks, n.length, () => ({ x: 0, y: 0, z: 0 }));
268
+ for (let h = 0; h < n.length; h += 1) Ae(l.worldLandmarks[h], n[h]);
269
+ }
270
+ return l.confidence = c.confidence, l.held = c.held, l;
271
+ }
272
+ updatePose(s, e, n) {
273
+ var u, w, S;
274
+ const r = (u = s == null ? void 0 : s.poseLandmarks) == null ? void 0 : u[0], a = r && n ? nt(r, this.poseScratch) : r, o = this.poseMemory.bridge(a, a ? Ms(a) : 0, e);
275
+ if (!o) return null;
276
+ const { pose: c } = this, l = !o.held && a;
277
+ ae(c.landmarks, o.points.length, () => ({ x: 0, y: 0, z: 0 })), ae(c.visibility, o.points.length, () => 0);
278
+ for (let k = 0; k < o.points.length; k += 1)
279
+ le(o.points[k], c.landmarks[k]), l && (c.visibility[k] = ((w = a[k]) == null ? void 0 : w.visibility) ?? 0);
280
+ const h = (S = s == null ? void 0 : s.poseWorldLandmarks) == null ? void 0 : S[0], f = h && n ? nt(h, this.poseWorldScratch) : h;
281
+ if (l && f) {
282
+ ae(c.worldLandmarks, f.length, () => ({ x: 0, y: 0, z: 0 }));
283
+ for (let k = 0; k < f.length; k += 1) Ae(c.worldLandmarks[k], f[k]);
284
+ }
285
+ return c.confidence = o.confidence, c.held = o.held, c;
286
+ }
287
+ }
288
+ const pt = {
289
+ "camera-permission-denied": "Camera access was blocked. Allow camera permissions in your browser, then refresh.",
290
+ "camera-in-use": "Camera is already in use by another app or browser tab. Close it and refresh.",
291
+ "no-camera": "No camera was found on this device.",
292
+ "camera-insecure-context": "Camera access needs HTTPS (or localhost). Open the page over HTTPS.",
293
+ "camera-unsupported": "This browser cannot open the camera.",
294
+ "camera-lost": "The camera stopped sending frames (disconnected, revoked, or taken by another app).",
295
+ "webgl-unavailable": "WebGL is unavailable, so nothing can render or track.",
296
+ "offscreen-canvas-unavailable": "OffscreenCanvas is unavailable; the tracker feed cannot be built.",
297
+ "wasm-unavailable": "WebAssembly is unavailable; the tracking engine cannot load.",
298
+ "model-unreachable": "The tracker model could not be downloaded.",
299
+ "model-integrity": "The tracker model failed its integrity check.",
300
+ "model-init-failed": "The tracker failed to initialize on this device.",
301
+ "placement-unsupported": "This device cannot place 3D objects in the room (no WebXR, Scene Viewer or Quick Look).",
302
+ unknown: "Tracking is unavailable for an unknown reason."
303
+ }, Cs = {
304
+ "camera-permission-denied": !0,
305
+ "camera-in-use": !0,
306
+ "no-camera": !1,
307
+ "camera-insecure-context": !1,
308
+ "camera-unsupported": !1,
309
+ "camera-lost": !0,
310
+ "webgl-unavailable": !1,
311
+ "offscreen-canvas-unavailable": !1,
312
+ "wasm-unavailable": !1,
313
+ "model-unreachable": !0,
314
+ "model-integrity": !1,
315
+ "model-init-failed": !1,
316
+ "placement-unsupported": !1,
317
+ unknown: !0
318
+ }, I = (t, s = pt[t]) => ({ code: t, message: s, recoverable: Cs[t] }), xs = {
319
+ [R.FACE_TRACKER]: "/assets/xr/models/face_tracking.task",
320
+ [R.HAND_TRACKER]: "/assets/xr/models/hand_tracking.task",
321
+ [R.GESTURE_TRACKER]: "/assets/xr/models/gesture_tracking.task",
322
+ [R.BODY_TRACKER]: "/assets/xr/models/body_tracking.task",
323
+ [R.BACKGROUND_SEGMENTATION]: "/assets/xr/models/segmentation.tflite",
324
+ [R.SEMANTIC_SEGMENTATION]: "/assets/xr/models/selfie_multiclass_256x256.tflite",
325
+ [R.HOLISTIC_TRACKER]: gt
326
+ }, yt = (t) => {
327
+ const s = xs[t];
328
+ return s ? /^https?:/.test(s) ? s : new URL(s, U.assetStorageEndpoint).toString() : null;
329
+ }, bs = Object.values(R), Ts = () => {
330
+ var e, n, r;
331
+ const t = typeof window < "u", s = typeof document < "u";
332
+ return {
333
+ navigator: typeof navigator < "u" ? navigator : void 0,
334
+ isSecureContext: t ? window.isSecureContext : void 0,
335
+ createCanvas: s ? () => document.createElement("canvas") : void 0,
336
+ offscreenCanvas: typeof OffscreenCanvas < "u",
337
+ wasm: typeof WebAssembly < "u",
338
+ fetch: typeof fetch < "u" ? fetch.bind(globalThis) : void 0,
339
+ now: () => typeof performance < "u" ? performance.now() : Date.now(),
340
+ xrSessionSupported: typeof navigator < "u" && ((e = navigator.xr) != null && e.isSessionSupported) ? (a) => navigator.xr.isSessionSupported(a).catch(() => !1) : void 0,
341
+ relSupportsAr: s ? ((r = (n = document.createElement("a").relList) == null ? void 0 : n.supports) == null ? void 0 : r.call(n, "ar")) === !0 : void 0,
342
+ userAgent: typeof navigator < "u" ? navigator.userAgent : void 0
343
+ };
344
+ }, Es = (t) => !!t && /Android/.test(t) && /(Chrome|SamsungBrowser)\//.test(t) && !/Firefox|OPR\//.test(t), As = async (t) => {
345
+ let s = !1;
346
+ if (t.xrSessionSupported)
347
+ try {
348
+ s = await t.xrSessionSupported("immersive-ar");
349
+ } catch {
350
+ s = !1;
351
+ }
352
+ const e = Es(t.userAgent), n = t.relSupportsAr === !0, r = s || e || n;
353
+ return {
354
+ webxr: s,
355
+ sceneViewer: e,
356
+ quickLook: n,
357
+ any: r,
358
+ reason: r ? null : I("placement-unsupported")
359
+ };
360
+ }, Rs = (t) => {
361
+ switch (t) {
362
+ case "granted":
363
+ return "supported";
364
+ case "denied":
365
+ return "permission-denied";
366
+ case "prompt":
367
+ return "permission-prompt";
368
+ default:
369
+ return "unknown";
370
+ }
371
+ }, Fs = async (t, s) => {
372
+ var c, l, h;
373
+ const e = t.isSecureContext ?? !0, n = (c = t.navigator) == null ? void 0 : c.mediaDevices;
374
+ if (!e)
375
+ return {
376
+ status: "unsupported",
377
+ reason: I("camera-insecure-context"),
378
+ deviceCount: null,
379
+ secureContext: e
380
+ };
381
+ if (!n || typeof n.getUserMedia != "function")
382
+ return {
383
+ status: "unsupported",
384
+ reason: I("camera-unsupported"),
385
+ deviceCount: null,
386
+ secureContext: e
387
+ };
388
+ let r = "unknown";
389
+ if (s && ((h = (l = t.navigator) == null ? void 0 : l.permissions) != null && h.query))
390
+ try {
391
+ const f = await t.navigator.permissions.query({ name: "camera" });
392
+ r = Rs(f.state);
393
+ } catch {
394
+ r = "unknown";
395
+ }
396
+ let a = null, o = !1;
397
+ if (typeof n.enumerateDevices == "function")
398
+ try {
399
+ const f = await n.enumerateDevices();
400
+ a = f.filter((u) => u.kind === "videoinput").length, o = f.some((u) => !!u.label);
401
+ } catch {
402
+ a = null;
403
+ }
404
+ return r === "permission-denied" ? {
405
+ status: r,
406
+ reason: I("camera-permission-denied"),
407
+ deviceCount: a,
408
+ secureContext: e
409
+ } : a === 0 && (r === "supported" || o) ? {
410
+ status: "unsupported",
411
+ reason: I("no-camera"),
412
+ deviceCount: a,
413
+ secureContext: e
414
+ } : { status: r, reason: null, deviceCount: a, secureContext: e };
415
+ }, Is = (t) => {
416
+ var e;
417
+ const s = (e = t.createCanvas) == null ? void 0 : e.call(t);
418
+ if (!s) return 0;
419
+ try {
420
+ if (s.getContext("webgl2")) return 2;
421
+ if (s.getContext("webgl") || s.getContext("experimental-webgl")) return 1;
422
+ } catch {
423
+ return 0;
424
+ }
425
+ return 0;
426
+ }, _s = (t) => {
427
+ var o;
428
+ const s = Is(t), e = t.offscreenCanvas ?? !1, n = t.wasm ?? !1, r = !!((o = t.navigator) != null && o.gpu);
429
+ let a = null;
430
+ return s === 0 ? a = I("webgl-unavailable") : e ? n || (a = I("wasm-unavailable")) : a = I("offscreen-canvas-unavailable"), {
431
+ status: a ? "unsupported" : "supported",
432
+ reason: a,
433
+ webglVersion: s,
434
+ webgpu: r,
435
+ offscreenCanvas: e,
436
+ wasm: n
437
+ };
438
+ }, Ps = async (t, s, e) => {
439
+ var o, c;
440
+ const n = yt(t);
441
+ if (!n || !s.fetch)
442
+ return { model: t, status: "unknown", reason: null, url: n, bytes: null };
443
+ const r = typeof AbortController < "u" ? new AbortController() : void 0, a = setTimeout(() => r == null ? void 0 : r.abort(), e);
444
+ try {
445
+ const l = await s.fetch(n, { method: "HEAD", signal: r == null ? void 0 : r.signal });
446
+ if (!l.ok)
447
+ return {
448
+ model: t,
449
+ status: "unsupported",
450
+ reason: I(
451
+ "model-unreachable",
452
+ `${pt["model-unreachable"]} (${l.status})`
453
+ ),
454
+ url: n,
455
+ bytes: null
456
+ };
457
+ const h = Number(((c = (o = l.headers) == null ? void 0 : o.get) == null ? void 0 : c.call(o, "content-length")) ?? NaN);
458
+ return {
459
+ model: t,
460
+ status: "supported",
461
+ reason: null,
462
+ url: n,
463
+ bytes: Number.isFinite(h) && h > 0 ? h : null
464
+ };
465
+ } catch {
466
+ return {
467
+ model: t,
468
+ status: "unsupported",
469
+ reason: I("model-unreachable"),
470
+ url: n,
471
+ bytes: null
472
+ };
473
+ } finally {
474
+ clearTimeout(a);
475
+ }
476
+ }, jn = async (t = {}, s = Ts()) => {
477
+ const e = t.timeoutMs ?? 4e3, n = new Set(t.models ?? []), [r, a, o] = await Promise.all([
478
+ Fs(s, t.queryPermission ?? !0),
479
+ Promise.all(
480
+ bs.map(
481
+ async (h) => n.has(h) ? Ps(h, s, e) : {
482
+ model: h,
483
+ status: "unknown",
484
+ reason: null,
485
+ url: yt(h),
486
+ bytes: null
487
+ }
488
+ )
489
+ ),
490
+ As(s)
491
+ ]), c = _s(s), l = Object.fromEntries(a.map((h) => [h.model, h]));
492
+ return {
493
+ camera: r,
494
+ rendering: c,
495
+ placement: o,
496
+ models: l,
497
+ canRunTracking: c.status === "supported" && r.status !== "unsupported",
498
+ checkedAt: s.now ? s.now() : Date.now()
499
+ };
500
+ }, wt = (t) => {
501
+ switch (t) {
502
+ case "permission-denied":
503
+ return I("camera-permission-denied");
504
+ case "camera-in-use":
505
+ return I("camera-in-use");
506
+ case "no-camera":
507
+ return I("no-camera");
508
+ case "camera-lost":
509
+ return I("camera-lost");
510
+ case "unsupported":
511
+ return I("camera-unsupported");
512
+ default:
513
+ return I("unknown");
514
+ }
515
+ }, Zn = (t, s) => {
516
+ const { camera: e, rendering: n } = t, r = t.models[s], a = e.status === "permission-prompt" || e.status === "unknown";
517
+ return n.reason ? { supported: !1, reason: n.reason, needsPermission: a } : e.reason ? { supported: !1, reason: e.reason, needsPermission: a } : r != null && r.reason ? { supported: !1, reason: r.reason, needsPermission: a } : { supported: !0, reason: null, needsPermission: a };
518
+ }, $n = (t) => {
519
+ const s = t instanceof Error ? t.message : String(t ?? ""), e = s.toLowerCase();
520
+ return e.includes("integrity") || e.includes("sha-384") || e.includes("sha384") ? I("model-integrity", s) : e.includes("failed to fetch") || e.includes("networkerror") || e.includes("load failed") || /\b(404|403|5\d\d)\b/.test(e) || e.includes("fetch") ? I("model-unreachable", s) : e.includes("webgl") || e.includes("gpu") ? I("webgl-unavailable", s) : s ? I("model-init-failed", s) : I("unknown");
521
+ }, vt = (t) => {
522
+ switch (t instanceof DOMException ? t.name : "") {
523
+ case "NotAllowedError":
524
+ case "PermissionDeniedError":
525
+ return "permission-denied";
526
+ case "NotReadableError":
527
+ case "TrackStartError":
528
+ return "camera-in-use";
529
+ case "NotFoundError":
530
+ case "DevicesNotFoundError":
531
+ return "no-camera";
532
+ case "NotSupportedError":
533
+ case "SecurityError":
534
+ case "OverconstrainedError":
535
+ return "unsupported";
536
+ default:
537
+ return t instanceof TypeError ? "unsupported" : "unknown";
538
+ }
539
+ }, rt = {
540
+ "permission-denied": "Camera access was blocked. Allow camera permissions in your browser, then refresh.",
541
+ "camera-in-use": "Camera is already in use by another app or browser tab. Close it and refresh.",
542
+ "no-camera": "No camera was found on this device.",
543
+ "camera-lost": "The camera stopped sending frames. Reconnect it or re-allow access, then start again.",
544
+ unsupported: "Unable to access camera. Allow camera permissions in your browser, then refresh.",
545
+ unknown: "Unable to access camera. Allow camera permissions in your browser, then refresh."
546
+ }, Oe = () => ({
547
+ mediaDevices: typeof navigator < "u" ? navigator.mediaDevices : void 0,
548
+ permissions: typeof navigator < "u" ? navigator.permissions : void 0,
549
+ isSecureContext: typeof window < "u" ? window.isSecureContext : void 0
550
+ }), St = async (t = Oe()) => {
551
+ var s;
552
+ if (!((s = t.permissions) != null && s.query)) return { state: "unknown", prompt: !1 };
553
+ try {
554
+ const e = await t.permissions.query({ name: "camera" });
555
+ return e.state === "granted" ? { state: "granted", prompt: !1 } : e.state === "denied" ? { state: "blocked", prompt: !1 } : { state: "unknown", prompt: e.state === "prompt" };
556
+ } catch {
557
+ return { state: "unknown", prompt: !1 };
558
+ }
559
+ }, Mt = (t, s) => t === "permission-denied" ? {
560
+ state: s === "blocked" ? "blocked" : "denied",
561
+ reason: I("camera-permission-denied")
562
+ } : { state: "unavailable", reason: wt(t) }, Jn = async (t = {}, s = Oe()) => {
563
+ var n;
564
+ if (s.isSecureContext === !1)
565
+ return {
566
+ state: "unavailable",
567
+ reason: I("camera-insecure-context"),
568
+ stream: null
569
+ };
570
+ const e = (n = s.mediaDevices) == null ? void 0 : n.getUserMedia;
571
+ if (typeof e != "function")
572
+ return {
573
+ state: "unavailable",
574
+ reason: I("camera-unsupported"),
575
+ stream: null
576
+ };
577
+ try {
578
+ const r = await e.call(
579
+ s.mediaDevices,
580
+ t.constraints ?? { video: { facingMode: "user" } }
581
+ );
582
+ return t.keepStream ? { state: "granted", reason: null, stream: r } : (r.getTracks().forEach((a) => a.stop()), { state: "granted", reason: null, stream: null });
583
+ } catch (r) {
584
+ const a = vt(r), o = await St(s);
585
+ return { ...Mt(a, o.state), stream: null };
586
+ }
587
+ }, er = async (t, s = Oe()) => {
588
+ var e, n;
589
+ if (!((e = s.permissions) != null && e.query)) return () => {
590
+ };
591
+ try {
592
+ const r = await s.permissions.query({ name: "camera" }), a = () => {
593
+ r.state === "granted" ? t({ state: "granted", prompt: !1 }) : r.state === "denied" ? t({ state: "blocked", prompt: !1 }) : t({ state: "unknown", prompt: r.state === "prompt" });
594
+ };
595
+ return (n = r.addEventListener) == null || n.call(r, "change", a), () => {
596
+ var o;
597
+ return (o = r.removeEventListener) == null ? void 0 : o.call(r, "change", a);
598
+ };
599
+ } catch {
600
+ return () => {
601
+ };
602
+ }
603
+ }, tr = (t) => t === "unknown" || t === "denied" || t === "granted", sr = {
604
+ unknown: "This experience uses your camera. Nothing is recorded or uploaded.",
605
+ requesting: "Waiting for you to allow the camera…",
606
+ granted: "Camera access granted.",
607
+ denied: "Camera access was not allowed. You can try again.",
608
+ blocked: "Camera access is blocked for this site. Allow it in your browser's site settings, then reload.",
609
+ unavailable: "The camera is unavailable on this device right now."
610
+ }, Ls = (t, s, e = "cover", n = 1) => {
611
+ if (t.width <= 0 || t.height <= 0 || s.width <= 0 || s.height <= 0)
612
+ return null;
613
+ const r = Number.isFinite(n) && n > 0 ? n : 1, a = s.width / t.width, o = s.height / t.height, c = e === "contain" ? o <= a : o >= a, l = (c ? o : a) * r, h = c ? t.width * o * r : s.width * r, f = c ? s.height * r : t.height * a * r;
614
+ return {
615
+ scale: l,
616
+ drawWidth: h,
617
+ drawHeight: f,
618
+ offsetX: (s.width - h) / 2,
619
+ offsetY: (s.height - f) / 2
620
+ };
621
+ }, He = (t) => t === "webcam" || t === void 0, Ds = ({
622
+ source: t,
623
+ feed: s,
624
+ zoom: e = 1,
625
+ mirrored: n = !1
626
+ }) => {
627
+ const r = Ls(t, s, "cover", e);
628
+ return r ? { ...r, source: t, feed: s, zoom: Number.isFinite(e) && e > 0 ? e : 1, mirrored: n } : null;
629
+ }, nr = (t, s, e = { x: 0, y: 0 }) => {
630
+ const n = s.mirrored ? s.source.width - t.x : t.x;
631
+ return e.x = (s.offsetX + n * s.scale) / s.feed.width, e.y = (s.offsetY + t.y * s.scale) / s.feed.height, e;
632
+ }, Os = (t, s, e = { x: 0, y: 0 }) => {
633
+ const n = (t.x * s.feed.width - s.offsetX) / s.scale;
634
+ return e.x = s.mirrored ? s.source.width - n : n, e.y = (t.y * s.feed.height - s.offsetY) / s.scale, e;
635
+ }, rr = (t, s) => {
636
+ const e = Os(t, s);
637
+ return e.x >= 0 && e.x <= s.source.width && e.y >= 0 && e.y <= s.source.height;
638
+ }, ar = (t, s = { x: 0, y: 0 }) => (s.x = 1 - t.x, s.y = t.y, t.z !== void 0 && (s.z = t.z), s), ir = (t, s, e, n = { x: 0, y: 0 }) => {
639
+ switch (e) {
640
+ case 90:
641
+ return n.x = s.height - t.y, n.y = t.x, n;
642
+ case 180:
643
+ return n.x = s.width - t.x, n.y = s.height - t.y, n;
644
+ case 270:
645
+ return n.x = t.y, n.y = s.width - t.x, n;
646
+ default:
647
+ return n.x = t.x, n.y = t.y, n;
648
+ }
649
+ }, or = (t, s) => s === 90 || s === 270 ? { width: t.height, height: t.width } : { width: t.width, height: t.height };
650
+ class O extends Error {
651
+ constructor(s) {
652
+ super(s), this.name = "VincenttXRError";
653
+ }
654
+ }
655
+ class Hs {
656
+ constructor(s) {
657
+ d(this, "options");
658
+ const e = {
659
+ verbose: !1,
660
+ prefix: U.loggerPrefix
661
+ };
662
+ this.options = { ...e, ...s };
663
+ }
664
+ log(...s) {
665
+ const { verbose: e, prefix: n } = this.options;
666
+ e && console.info(n, ...s);
667
+ }
668
+ error(...s) {
669
+ const { verbose: e, prefix: n } = this.options;
670
+ e && console.error(n, ...s);
671
+ }
672
+ }
673
+ const at = new B.Vector3(), Re = new B.Vector3(), kt = (t, s, e, n, r) => {
674
+ at.set(t, s, 0).unproject(e), Re.copy(at).sub(e.position).normalize();
675
+ const a = (n - e.position.z) / Re.z;
676
+ return r.copy(e.position).addScaledVector(Re, a);
677
+ }, Us = (t, s, e = new B.Vector3(), n = 0) => kt((t.x - 0.5) * 2, (0.5 - t.y) * 2, s, n, e), cr = (t, s, e = new B.Vector3(), n = 0) => kt(t.x, t.y, s, n, e), X = new B.Vector3(), lr = (t, s, e = { x: 0, y: 0, z: 0 }) => (X.set(t.x, t.y, t.z).project(s), e.x = X.x / 2 + 0.5, e.y = 0.5 - X.y / 2, e.z = X.z, e), dr = (t, s, e = { x: 0, y: 0, z: 0 }) => (X.set(t.x, t.y, t.z).project(s), e.x = X.x, e.y = X.y, e.z = X.z, e), Fe = (t, s, e) => Us(t, s, e, 0), Ns = (t, s, e = 0.2) => e * s + (1 - e) * t;
678
+ class de {
679
+ constructor(s) {
680
+ d(this, "canvas");
681
+ d(this, "scale", 1);
682
+ this.maxDimension = s;
683
+ }
684
+ /** Multiply the cap (0.25..1); the adaptive-quality tier sets it. */
685
+ setScale(s) {
686
+ this.scale = Math.min(1, Math.max(0.25, Number.isFinite(s) && s > 0 ? s : 1));
687
+ }
688
+ /**
689
+ * Returns a downscaled copy of `source` capped to `maxDimension` on its
690
+ * longest side (or `source` unchanged if it's already within the cap, or if a
691
+ * 2D context can't be obtained). The returned canvas is reused across calls.
692
+ */
693
+ draw(s) {
694
+ const e = s.width, n = s.height, r = Math.min(
695
+ 1,
696
+ this.maxDimension * this.scale / Math.max(e, n)
697
+ );
698
+ if (r >= 1) return s;
699
+ const a = Math.max(1, Math.round(e * r)), o = Math.max(1, Math.round(n * r));
700
+ (!this.canvas || this.canvas.width !== a || this.canvas.height !== o) && (this.canvas = new OffscreenCanvas(a, o));
701
+ const c = this.canvas.getContext("2d");
702
+ return c ? (c.setTransform(1, 0, 0, 1, 0, 0), c.clearRect(0, 0, a, o), c.drawImage(s, 0, 0, a, o), this.canvas) : s;
703
+ }
704
+ dispose() {
705
+ this.canvas = void 0;
706
+ }
707
+ }
708
+ const Bs = {
709
+ "/assets/xr/models/face_tracking.task": "sha384-tYQh+yJE8llY+zO4RviZmWaSKs5W9tsB0ix5rjQVpF5/CLTqmwtP7bYtkUi2w65P",
710
+ "/assets/xr/models/hand_tracking.task": "sha384-uWvruVKd887ov8k43S+DBHCsi7UXXS+CKvvdM1PX00rjPzx/B0QrAPfJ1U9yKcze",
711
+ "/assets/xr/models/gesture_tracking.task": "sha384-2zuseP9JKKWAYlWQGKA2N+ooabB8V/yIxu23Mv8mtY7SowcySB+xKiOmqBhVvlUC",
712
+ "/assets/xr/models/body_tracking.task": "sha384-3Wk9dvRYo36b3Nc9xVjKamb4wCKt9FwiPjcHKfrvyJL/jXoGs+uRLnii6yjWLKul",
713
+ "/assets/xr/models/segmentation.tflite": "sha384-A2bQ8+iZyQM3KIGVBUf0FyetqxuynyKpjsjCE8uzoJEnj1ghCu6ge2daiRffAiS5",
714
+ "/assets/xr/3d-models/head-occluder-v2.glb": "sha384-+0G60Q6EBVE6hpITxGzQgofAeKexPltpsfPq5T5et9GGBjRhFP5HOdsKAhe73OaI",
715
+ // Category segmenters behind XRModel.SEMANTIC_SEGMENTATION. The same bytes
716
+ // are pinned under the SDK CDN paths (not yet published) and under
717
+ // MediaPipe's published paths, which the presets load by default.
718
+ "/assets/xr/models/hair_segmenter.tflite": "sha384-1Eu/EdJcYV/7talPYVVbxPZBLg7UIxqsKisUNh/pEsyvAuUcE49HuqijSXWSHXHK",
719
+ "/mediapipe-models/image_segmenter/hair_segmenter/float32/latest/hair_segmenter.tflite": "sha384-1Eu/EdJcYV/7talPYVVbxPZBLg7UIxqsKisUNh/pEsyvAuUcE49HuqijSXWSHXHK",
720
+ "/assets/xr/models/selfie_multiclass_256x256.tflite": "sha384-LPLPyzBZ6TTE8146rnDx8CZ5LykB8memkmeO8FNVbGlNthvlUltn3W3KeJmtq9bL",
721
+ "/mediapipe-models/image_segmenter/selfie_multiclass_256x256/float32/latest/selfie_multiclass_256x256.tflite": "sha384-LPLPyzBZ6TTE8146rnDx8CZ5LykB8memkmeO8FNVbGlNthvlUltn3W3KeJmtq9bL",
722
+ // MediaPipe Holistic Landmarker (face + hands + pose in one graph) behind
723
+ // XRModel.HOLISTIC_TRACKER. Same bytes pinned under the SDK CDN path (not yet
724
+ // published) and MediaPipe's published path, which the tracker loads by default.
725
+ "/assets/xr/models/holistic_landmarker.task": "sha384-6Y2fQ5yP5QtlvJIasfv0fHEyoMqRYYpLtEpsyeXjYDOuFCEXfKIZPZSXq8TLXmsg",
726
+ "/mediapipe-models/holistic_landmarker/holistic_landmarker/float16/latest/holistic_landmarker.task": "sha384-6Y2fQ5yP5QtlvJIasfv0fHEyoMqRYYpLtEpsyeXjYDOuFCEXfKIZPZSXq8TLXmsg",
727
+ "/assets/sdk/face/v1/canonical_face_model.obj": "sha384-xP8YM/72TXKvbMptXB9a8JUlUf3MZQ8uLurExrsZc05v6/P5RrsaNGMUYS/BZx8A",
728
+ "/opencv/facial_expression_recognition/resolve/main/facial_expression_recognition_mobilefacenet_2022july_int8.onnx": "sha384-g8mtFubiIc/yhqi591RsxD76AJLw2CfYgKhKbVkIiFlwBmIyG7ZAIVyGPXafrDGB"
729
+ };
730
+ async function zs(t, s) {
731
+ const e = await fetch(t, s != null && s.signal ? { signal: s.signal } : void 0);
732
+ if (!e.ok)
733
+ throw new Error(`fetchAndVerify: ${e.status} ${t}`);
734
+ const n = await e.arrayBuffer(), r = Vs(t);
735
+ if (!r) {
736
+ if (Ws(t))
737
+ throw new Error(`[xr-sdk integrity] no SRI hash for SDK asset ${t}`);
738
+ return console.warn(`[xr-sdk integrity] no SRI hash for ${t} — passing through`), n;
739
+ }
740
+ const a = await qs(n);
741
+ if (a !== r)
742
+ throw new Error(
743
+ `[xr-sdk integrity] SRI mismatch for ${t}: expected ${r}, got ${a}`
744
+ );
745
+ return n;
746
+ }
747
+ function Ws(t) {
748
+ try {
749
+ return new URL(t).origin === new URL(U.assetStorageEndpoint).origin;
750
+ } catch {
751
+ return !1;
752
+ }
753
+ }
754
+ async function Z(t) {
755
+ const s = await zs(t);
756
+ return new Uint8Array(s);
757
+ }
758
+ function Vs(t) {
759
+ try {
760
+ const s = new URL(t);
761
+ return Bs[s.pathname];
762
+ } catch {
763
+ return;
764
+ }
765
+ }
766
+ async function qs(t) {
767
+ const s = await crypto.subtle.digest("SHA-384", t), e = new Uint8Array(s);
768
+ let n = "";
769
+ for (let r = 0; r < e.byteLength; r++)
770
+ n += String.fromCharCode(e[r]);
771
+ return `sha384-${btoa(n)}`;
772
+ }
773
+ const Ie = /* @__PURE__ */ new Map();
774
+ function $(t) {
775
+ const s = t.wasmBinaryPath;
776
+ let e = Ie.get(s);
777
+ return e || (e = Ks(s).catch(() => {
778
+ Ie.delete(s);
779
+ }), Ie.set(s, e)), e;
780
+ }
781
+ async function Ks(t) {
782
+ const s = await fetch(t, { credentials: "same-origin" });
783
+ if (!s.ok || !s.body)
784
+ throw new Error(`warmVisionWasm: ${s.status} ${t}`);
785
+ const e = s.body.getReader();
786
+ for (; ; ) {
787
+ const { done: n } = await e.read();
788
+ if (n) return;
789
+ }
790
+ }
791
+ class J {
792
+ constructor() {
793
+ d(this, "disposed", !1);
794
+ d(this, "paused", !1);
795
+ d(this, "rafId", null);
796
+ // Inference bookkeeping behind `getDiagnostics()`. Subclasses call
797
+ // `recordInference(startMs)` right after their detect call and
798
+ // `recordDetections(count, confidence)` after reading the result.
799
+ d(this, "statInferenceMs", null);
800
+ d(this, "statInferences", 0);
801
+ d(this, "statWindowStart", 0);
802
+ d(this, "statWindowCount", 0);
803
+ d(this, "statFps", 0);
804
+ d(this, "statSkipped", 0);
805
+ d(this, "statDetections", null);
806
+ d(this, "statConfidence", null);
807
+ d(this, "statStatus", "ready");
808
+ d(this, "statError", null);
809
+ // Inference-rate throttle. `targetFrameIntervalMs` is 0 when uncapped
810
+ // (detect every frame); a positive value skips detection until that many ms
811
+ // have elapsed since the last inference. `run()` sets this from
812
+ // `params.targetFps`; subclasses call `shouldRunInference()` in their RAF
813
+ // loop to gate the expensive MediaPipe call.
814
+ d(this, "targetFrameIntervalMs", 0);
815
+ d(this, "lastInferenceMs", 0);
816
+ /** Analysis-resolution multiplier (0.25..1) from the quality tier; subclasses read it where they downscale. */
817
+ d(this, "analysisScale", 1);
818
+ }
819
+ /** Record one completed inference that started at `startMs` (`performance.now()`). */
820
+ recordInference(s, e = performance.now()) {
821
+ const n = e - s;
822
+ this.statInferenceMs = n, this.statInferences += 1, this.statWindowCount += 1, this.statWindowStart === 0 && (this.statWindowStart = e);
823
+ const r = e - this.statWindowStart;
824
+ return r >= 1e3 && (this.statFps = this.statWindowCount * 1e3 / r, this.statWindowStart = e, this.statWindowCount = 0), n;
825
+ }
826
+ /** Record what the last inference found (subjects and the primary confidence). */
827
+ recordDetections(s, e = null) {
828
+ this.statDetections = s, this.statConfidence = e;
829
+ }
830
+ /** Record an inference failure (or clear it with `null`). */
831
+ recordInferenceError(s) {
832
+ this.statStatus = s ? "error" : "ready", this.statError = s;
833
+ }
834
+ /** Current health snapshot. Allocates a small object; sample it at UI rate, not per frame. */
835
+ getDiagnostics() {
836
+ const s = this.statWindowStart > 0 && performance.now() - this.statWindowStart > 1500;
837
+ return {
838
+ inferenceMs: this.statInferenceMs,
839
+ inferenceFps: s ? 0 : this.statFps,
840
+ inferences: this.statInferences,
841
+ skippedFrames: this.statSkipped,
842
+ detections: this.statDetections,
843
+ confidence: this.statConfidence,
844
+ status: this.statStatus,
845
+ error: this.statError,
846
+ paused: this.paused,
847
+ disposed: this.disposed
848
+ };
849
+ }
850
+ /** Clamp and store the analysis scale; subclasses with a downscaler forward it. */
851
+ setAnalysisScale(s) {
852
+ this.analysisScale = s !== void 0 && Number.isFinite(s) && s > 0 ? Math.min(1, Math.max(0.25, s)) : 1;
853
+ }
854
+ /** Set the per-frame inference cap. fps <= 0 (or undefined) → uncapped. */
855
+ setTargetFps(s) {
856
+ this.targetFrameIntervalMs = s && s > 0 ? 1e3 / s : 0;
857
+ }
858
+ /**
859
+ * True if enough time has elapsed to run inference this frame (and records
860
+ * the timestamp). Always true when uncapped. Call once per RAF tick, right
861
+ * before the detect call; skip the detect (but keep rescheduling RAF) when
862
+ * it returns false.
863
+ */
864
+ shouldRunInference() {
865
+ if (this.targetFrameIntervalMs <= 0) return !0;
866
+ const s = performance.now();
867
+ return s - this.lastInferenceMs < this.targetFrameIntervalMs ? (this.statSkipped += 1, !1) : (this.lastInferenceMs = s, !0);
868
+ }
869
+ // load models
870
+ async initialize(s) {
871
+ }
872
+ // setup for running + start running
873
+ async run(s) {
874
+ }
875
+ // get model's data while processing
876
+ getModelNode() {
877
+ return {};
878
+ }
879
+ async getPerformanceData() {
880
+ return {
881
+ name: this.constructor.name,
882
+ processingTime: null
883
+ };
884
+ }
885
+ // Cancel the per-frame RAF loop without releasing MediaPipe resources or
886
+ // dropping refs. Subclasses' process* methods check `paused` and return
887
+ // without rescheduling. Idempotent.
888
+ pause() {
889
+ this.paused = !0, this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null);
890
+ }
891
+ // Resume a paused loop by running the process function once. Subclasses
892
+ // override to kick their specific process* method. Idempotent — no-op if
893
+ // not paused. Calling resume() before run() is a no-op.
894
+ resume() {
895
+ this.paused = !1;
896
+ }
897
+ // Release MediaPipe landmarkers, cancel rAF loops, drop refs.
898
+ // Subclasses MUST override and call super.dispose() at the end.
899
+ dispose() {
900
+ this.disposed = !0, this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null);
901
+ }
902
+ }
903
+ const Gs = 768;
904
+ class Xs extends J {
905
+ constructor() {
906
+ super();
907
+ d(this, "landmarker", null);
908
+ d(this, "processingTime", null);
909
+ d(this, "coordinates");
910
+ d(this, "sourceCanvas");
911
+ d(this, "downscaler", new de(Gs));
912
+ }
913
+ async getBodyData() {
914
+ if (!this.landmarker || !this.sourceCanvas)
915
+ return;
916
+ const e = this.downscaler.draw(this.sourceCanvas), n = performance.now(), r = this.landmarker.detectForVideo(e, n), a = performance.now();
917
+ this.processingTime = a - n, this.recordInference(n, a);
918
+ const o = r.landmarks, c = o == null ? void 0 : o[0];
919
+ this.recordDetections(
920
+ (o == null ? void 0 : o.length) ?? 0,
921
+ c && c.length ? c.reduce((h, f) => h + (f.visibility ?? 0), 0) / c.length : null
922
+ );
923
+ const l = [];
924
+ if (o)
925
+ return o.forEach((h, f) => {
926
+ l[f] || (l[f] = []), h.forEach((u) => {
927
+ l[f].push(le(u));
928
+ });
929
+ }), {
930
+ coordinatesList: l
931
+ };
932
+ }
933
+ async processBodyTracking() {
934
+ if (!(this.disposed || this.paused || !this.landmarker)) {
935
+ if (this.shouldRunInference()) {
936
+ const e = await this.getBodyData();
937
+ e && (this.coordinates = e.coordinatesList);
938
+ }
939
+ this.disposed || this.paused || (this.rafId = requestAnimationFrame(this.processBodyTracking.bind(this)));
940
+ }
941
+ }
942
+ resume() {
943
+ this.paused && (super.resume(), this.processBodyTracking());
944
+ }
945
+ dispose() {
946
+ if (super.dispose(), this.landmarker) {
947
+ try {
948
+ this.landmarker.close();
949
+ } catch {
950
+ }
951
+ this.landmarker = null;
952
+ }
953
+ this.sourceCanvas = void 0, this.downscaler.dispose(), this.coordinates = void 0;
954
+ }
955
+ getLandmarks2D(e = 0) {
956
+ if (this.coordinates)
957
+ return this.coordinates[e];
958
+ }
959
+ async initialize(e) {
960
+ const n = await j.forVisionTasks(
961
+ new URL("/assets/xr/wasm", U.assetStorageEndpoint).toString()
962
+ ), [r] = await Promise.all([
963
+ Z(
964
+ new URL("/assets/xr/models/body_tracking.task", U.assetStorageEndpoint).toString()
965
+ ),
966
+ $(n)
967
+ ]);
968
+ this.landmarker = await cs.createFromOptions(n, {
969
+ baseOptions: {
970
+ modelAssetBuffer: r,
971
+ delegate: "GPU"
972
+ },
973
+ runningMode: "VIDEO",
974
+ numPoses: (e == null ? void 0 : e.numPoses) || 1
975
+ });
976
+ }
977
+ async run({ sourceCanvas: e, targetFps: n, analysisScale: r }) {
978
+ this.setAnalysisScale(r), this.downscaler.setScale(this.analysisScale), this.sourceCanvas = e, this.setTargetFps(n), this.rafId === null && await this.processBodyTracking();
979
+ }
980
+ getModelNode() {
981
+ return {
982
+ getLandmarks2D: this.getLandmarks2D.bind(this)
983
+ };
984
+ }
985
+ async getPerformanceData() {
986
+ return {
987
+ name: this.constructor.name,
988
+ processingTime: this.processingTime
989
+ };
990
+ }
991
+ }
992
+ const Ys = 0.11, Qs = 4e-3, js = (t, s) => s.set(t.x, -t.y, t.z);
993
+ class Zs extends J {
994
+ constructor() {
995
+ super();
996
+ d(this, "landmarker", null);
997
+ d(this, "processingTime", null);
998
+ d(this, "sourceCanvas");
999
+ d(this, "analysisCanvas");
1000
+ d(this, "getSource");
1001
+ d(this, "detectionResults");
1002
+ d(this, "numFaces", 1);
1003
+ d(this, "cameras", []);
1004
+ // camera object to unproject each face's translation
1005
+ d(this, "faces", []);
1006
+ // Reused per-face work vectors. Allocated once per face index and mutated
1007
+ // in place each frame, so the published Face[] doesn't churn the GC at
1008
+ // 30+ fps. Per-face indexing means two faces don't alias each other's
1009
+ // transforms; consumers see "current value" each frame.
1010
+ d(this, "leftCheekScratch", []);
1011
+ d(this, "rightCheekScratch", []);
1012
+ // Reused per-frame landmark used to feed unprojectToZZeroInto with an
1013
+ // x-mirrored copy for non-webcam sources, without allocating a new
1014
+ // landmark array (~468 entries) each frame.
1015
+ d(this, "landmarkScratch", { x: 0, y: 0, z: 0, visibility: 0 });
1016
+ // Reused per-frame rotation scratch (matrix -> quaternion -> mirror -> euler),
1017
+ // allocated once to avoid per-frame churn at 30+ fps.
1018
+ d(this, "rotMatrixScratch", new B.Matrix4());
1019
+ d(this, "rotQuatScratch", new B.Quaternion());
1020
+ d(this, "rotEulerScratch", new B.Euler());
1021
+ }
1022
+ // For non-webcam sources MediaPipe landmarks read as mirrored; flip x in
1023
+ // place into the reused scratch so downstream unprojection sees the
1024
+ // corrected position. Webcam input is already correct, so it's returned
1025
+ // by reference.
1026
+ landmarkForSource(e, n) {
1027
+ return n ? (this.landmarkScratch.x = 1 - e.x, this.landmarkScratch.y = e.y, this.landmarkScratch.z = e.z, this.landmarkScratch.visibility = e.visibility, this.landmarkScratch) : e;
1028
+ }
1029
+ extractAndUpdateFaceData(e) {
1030
+ var r;
1031
+ if (!e.faceLandmarks.length) {
1032
+ this.faces = [];
1033
+ return;
1034
+ }
1035
+ const n = e.faceLandmarks.length;
1036
+ for (this.faces.length > n && (this.faces.length = n, this.leftCheekScratch.length = n, this.rightCheekScratch.length = n); this.faces.length < n; )
1037
+ this.faces.push({
1038
+ transform: {
1039
+ position: new B.Vector3(),
1040
+ rotation: new B.Vector3(),
1041
+ scale: new B.Vector3()
1042
+ },
1043
+ gestures: {}
1044
+ }), this.leftCheekScratch.push(new B.Vector3()), this.rightCheekScratch.push(new B.Vector3());
1045
+ for (let a = 0; a < n; a += 1) {
1046
+ if (!this.cameras[a])
1047
+ continue;
1048
+ const o = this.faces[a], c = !He((r = this.getSource) == null ? void 0 : r.call(this)), l = e.faceLandmarks[a], h = e.facialTransformationMatrixes[a];
1049
+ this.rotMatrixScratch.fromArray(h.data), this.rotQuatScratch.setFromRotationMatrix(this.rotMatrixScratch), this.rotQuatScratch.set(
1050
+ -this.rotQuatScratch.x,
1051
+ this.rotQuatScratch.y,
1052
+ this.rotQuatScratch.z,
1053
+ this.rotQuatScratch.w
1054
+ ), this.rotEulerScratch.setFromQuaternion(this.rotQuatScratch, "XYZ"), js(this.rotEulerScratch, o.transform.rotation), Fe(
1055
+ this.landmarkForSource(l[4], c),
1056
+ this.cameras[a],
1057
+ o.transform.position
1058
+ ), Fe(
1059
+ this.landmarkForSource(l[50], c),
1060
+ this.cameras[a],
1061
+ this.leftCheekScratch[a]
1062
+ ), Fe(
1063
+ this.landmarkForSource(l[280], c),
1064
+ this.cameras[a],
1065
+ this.rightCheekScratch[a]
1066
+ );
1067
+ const u = this.leftCheekScratch[a].distanceTo(this.rightCheekScratch[a]) * Ys, w = Math.abs(B.MathUtils.radToDeg(this.rotEulerScratch.y)), S = u + w * Qs, k = o.transform.scale.x, x = Ns(
1068
+ isNaN(k) ? 0 : k,
1069
+ S
1070
+ );
1071
+ o.transform.scale.set(x, x, x);
1072
+ const T = o.gestures, _ = e.faceBlendshapes[a].categories;
1073
+ for (const g of _)
1074
+ T[g.categoryName] = g.score;
1075
+ }
1076
+ }
1077
+ async processFaceTracking() {
1078
+ if (this.disposed || this.paused || !this.landmarker || !this.sourceCanvas)
1079
+ return null;
1080
+ if (!this.shouldRunInference()) {
1081
+ this.rafId = requestAnimationFrame(this.processFaceTracking.bind(this));
1082
+ return;
1083
+ }
1084
+ const e = $s(this.numFaces) * this.analysisScale, n = this.sourceCanvas.width, r = this.sourceCanvas.height, a = Math.min(1, e / Math.max(n, r)), o = Math.max(1, Math.round(n * a)), c = Math.max(1, Math.round(r * a));
1085
+ (!this.analysisCanvas || this.analysisCanvas.width !== o || this.analysisCanvas.height !== c) && (this.analysisCanvas = new OffscreenCanvas(o, c));
1086
+ const l = this.analysisCanvas.getContext("2d");
1087
+ if (!l) {
1088
+ this.rafId = requestAnimationFrame(this.processFaceTracking.bind(this));
1089
+ return;
1090
+ }
1091
+ l.setTransform(1, 0, 0, 1, 0, 0), l.clearRect(0, 0, o, c), l.drawImage(this.sourceCanvas, 0, 0, o, c);
1092
+ const h = performance.now(), f = this.landmarker.detectForVideo(this.analysisCanvas, h), u = performance.now();
1093
+ this.processingTime = u - h, this.recordInference(h, u), this.recordDetections(f.faceLandmarks.length, null), this.detectionResults = f, this.extractAndUpdateFaceData(f), !(this.disposed || this.paused) && (this.rafId = requestAnimationFrame(this.processFaceTracking.bind(this)));
1094
+ }
1095
+ resume() {
1096
+ this.paused && (super.resume(), this.processFaceTracking());
1097
+ }
1098
+ dispose() {
1099
+ if (super.dispose(), this.landmarker) {
1100
+ try {
1101
+ this.landmarker.close();
1102
+ } catch {
1103
+ }
1104
+ this.landmarker = null;
1105
+ }
1106
+ this.sourceCanvas = void 0, this.analysisCanvas = void 0, this.getSource = void 0, this.detectionResults = void 0, this.processingTime = null, this.cameras = [], this.faces = [], this.leftCheekScratch = [], this.rightCheekScratch = [];
1107
+ }
1108
+ getFace(e = 0) {
1109
+ return this.faces[e];
1110
+ }
1111
+ getDetectionResults() {
1112
+ return this.detectionResults;
1113
+ }
1114
+ getRawFaceTrackingData(e = 0) {
1115
+ var n, r, a, o;
1116
+ if (this.detectionResults)
1117
+ return {
1118
+ landmarks: (n = this.detectionResults.faceLandmarks) == null ? void 0 : n[e],
1119
+ blendshapes: (a = (r = this.detectionResults.faceBlendshapes) == null ? void 0 : r[e]) == null ? void 0 : a.categories,
1120
+ transformationMatrix: (o = this.detectionResults.facialTransformationMatrixes) == null ? void 0 : o[e]
1121
+ };
1122
+ }
1123
+ async initialize(e) {
1124
+ this.numFaces = (e == null ? void 0 : e.numFaces) || 1;
1125
+ const n = await j.forVisionTasks(
1126
+ new URL("/assets/xr/wasm", U.assetStorageEndpoint).toString()
1127
+ ), [r] = await Promise.all([
1128
+ Z(
1129
+ new URL("/assets/xr/models/face_tracking.task", U.assetStorageEndpoint).toString()
1130
+ ),
1131
+ $(n)
1132
+ ]), a = await ls.createFromOptions(n, {
1133
+ baseOptions: {
1134
+ modelAssetBuffer: r,
1135
+ delegate: "GPU"
1136
+ },
1137
+ // Keep detection permissive for calibration workflows with dark webcam input.
1138
+ minFaceDetectionConfidence: 0.3,
1139
+ minFacePresenceConfidence: 0.3,
1140
+ minTrackingConfidence: 0.3,
1141
+ outputFaceBlendshapes: !0,
1142
+ outputFacialTransformationMatrixes: !0,
1143
+ runningMode: "VIDEO",
1144
+ numFaces: this.numFaces
1145
+ });
1146
+ if (this.disposed) {
1147
+ a.close();
1148
+ return;
1149
+ }
1150
+ this.landmarker = a;
1151
+ }
1152
+ async run({
1153
+ sourceCanvas: e,
1154
+ getSource: n,
1155
+ targetFps: r,
1156
+ analysisScale: a
1157
+ }) {
1158
+ this.sourceCanvas = e, this.getSource = n, this.setTargetFps(r), this.setAnalysisScale(a), this.analysisCanvas = void 0, this.rafId === null && this.processFaceTracking();
1159
+ }
1160
+ getModelNode() {
1161
+ const e = this;
1162
+ return {
1163
+ get detectionResults() {
1164
+ return e.detectionResults;
1165
+ },
1166
+ getDetectionResults: this.getDetectionResults.bind(this),
1167
+ getFace: this.getFace.bind(this),
1168
+ getRawFaceTrackingData: this.getRawFaceTrackingData.bind(this),
1169
+ setCamera: (r, a = 0) => {
1170
+ this.cameras[a] = r;
1171
+ }
1172
+ };
1173
+ }
1174
+ async getPerformanceData() {
1175
+ return {
1176
+ name: this.constructor.name,
1177
+ processingTime: this.processingTime
1178
+ };
1179
+ }
1180
+ }
1181
+ const $s = (t) => t > 1 ? 1024 : 512;
1182
+ var G = /* @__PURE__ */ ((t) => (t.ClosedFist = "closed_fist", t.OpenPalm = "open_palm", t.PointingUp = "pointing_up", t.ThumbDown = "thumb_down", t.ThumbUp = "thumb_up", t.Victory = "victory", t.ILoveYou = "i_love_you", t.None = "none", t))(G || {});
1183
+ const Js = 512, en = {
1184
+ Closed_Fist: G.ClosedFist,
1185
+ Open_Palm: G.OpenPalm,
1186
+ Pointing_Up: G.PointingUp,
1187
+ Thumb_Down: G.ThumbDown,
1188
+ Thumb_Up: G.ThumbUp,
1189
+ Victory: G.Victory,
1190
+ ILoveYou: G.ILoveYou,
1191
+ None: G.None
1192
+ }, tn = 15;
1193
+ class sn extends J {
1194
+ constructor() {
1195
+ super();
1196
+ d(this, "landmarker", null);
1197
+ d(this, "processingTime", null);
1198
+ d(this, "coordinates");
1199
+ d(this, "gesture");
1200
+ d(this, "sourceCanvas");
1201
+ d(this, "downscaler", new de(Js));
1202
+ }
1203
+ async getGestureData() {
1204
+ var l, h;
1205
+ if (!this.landmarker || !this.sourceCanvas)
1206
+ return;
1207
+ const e = this.downscaler.draw(this.sourceCanvas), n = performance.now(), r = this.landmarker.recognizeForVideo(e, n), a = performance.now();
1208
+ this.processingTime = a - n, this.recordInference(n, a), this.recordDetections(r.landmarks.length, ((h = (l = r.gestures[0]) == null ? void 0 : l[0]) == null ? void 0 : h.score) ?? null);
1209
+ const o = r.landmarks[0], c = [];
1210
+ if (o) {
1211
+ const f = r.gestures[0][0].categoryName;
1212
+ return o.forEach((u) => {
1213
+ c.push(le(u));
1214
+ }), {
1215
+ coordinates: c,
1216
+ gesture: en[f]
1217
+ };
1218
+ }
1219
+ return { coordinates: void 0, gesture: void 0 };
1220
+ }
1221
+ async processGestureTracking() {
1222
+ if (!this.disposed) {
1223
+ if (this.shouldRunInference()) {
1224
+ const e = await this.getGestureData();
1225
+ e && (this.coordinates = e.coordinates, this.gesture = e.gesture);
1226
+ }
1227
+ this.disposed || this.paused || (this.rafId = requestAnimationFrame(this.processGestureTracking.bind(this)));
1228
+ }
1229
+ }
1230
+ resume() {
1231
+ this.paused && (super.resume(), this.processGestureTracking());
1232
+ }
1233
+ dispose() {
1234
+ if (super.dispose(), this.landmarker) {
1235
+ try {
1236
+ this.landmarker.close();
1237
+ } catch {
1238
+ }
1239
+ this.landmarker = null;
1240
+ }
1241
+ this.sourceCanvas = void 0, this.downscaler.dispose(), this.coordinates = void 0, this.gesture = void 0;
1242
+ }
1243
+ async initialize() {
1244
+ const e = await j.forVisionTasks(
1245
+ new URL("/assets/xr/wasm", U.assetStorageEndpoint).toString()
1246
+ ), [n] = await Promise.all([
1247
+ Z(
1248
+ new URL(
1249
+ "/assets/xr/models/gesture_tracking.task",
1250
+ U.assetStorageEndpoint
1251
+ ).toString()
1252
+ ),
1253
+ $(e)
1254
+ ]), r = await ds.createFromOptions(e, {
1255
+ baseOptions: {
1256
+ modelAssetBuffer: n,
1257
+ delegate: "GPU"
1258
+ },
1259
+ runningMode: "VIDEO",
1260
+ numHands: 1
1261
+ });
1262
+ this.landmarker = r;
1263
+ }
1264
+ async run({ sourceCanvas: e, targetFps: n, analysisScale: r }) {
1265
+ this.setAnalysisScale(r), this.downscaler.setScale(this.analysisScale), this.sourceCanvas = e, this.setTargetFps(n ?? tn), this.rafId === null && await this.processGestureTracking();
1266
+ }
1267
+ getModelNode() {
1268
+ const e = this;
1269
+ return {
1270
+ get coordinates() {
1271
+ return e.coordinates;
1272
+ },
1273
+ get gesture() {
1274
+ return e.gesture;
1275
+ }
1276
+ };
1277
+ }
1278
+ async getPerformanceData() {
1279
+ return {
1280
+ name: this.constructor.name,
1281
+ processingTime: this.processingTime
1282
+ };
1283
+ }
1284
+ }
1285
+ class nn extends J {
1286
+ constructor() {
1287
+ super();
1288
+ d(this, "landmarker", null);
1289
+ d(this, "status", "loading");
1290
+ d(this, "error", null);
1291
+ d(this, "processingTime", null);
1292
+ d(this, "sourceCanvas");
1293
+ d(this, "getSource");
1294
+ d(this, "downscaler", new de(Pe().analysisMaxDimension));
1295
+ d(this, "raw");
1296
+ d(this, "delegatePolicy", "auto");
1297
+ d(this, "delegate", "GPU");
1298
+ /** Kept so the graph can be rebuilt on another delegate without refetching. */
1299
+ d(this, "vision", null);
1300
+ d(this, "modelBuffer", null);
1301
+ d(this, "graphOptions", {});
1302
+ d(this, "rebuilding", !1);
1303
+ d(this, "fallbackAttempted", !1);
1304
+ d(this, "result", Ss());
1305
+ d(this, "builder", new ks());
1306
+ d(this, "node");
1307
+ this.node = {
1308
+ getResult: () => this.result,
1309
+ getRawResult: () => this.raw,
1310
+ getStatus: () => this.status,
1311
+ getError: () => this.error,
1312
+ getDelegate: () => this.delegate,
1313
+ setOptions: (e) => this.setRuntimeOptions(e)
1314
+ };
1315
+ }
1316
+ setRuntimeOptions(e) {
1317
+ const n = this.builder.getOptions().analysisMaxDimension;
1318
+ this.builder.setOptions(e);
1319
+ const r = this.builder.getOptions().analysisMaxDimension;
1320
+ r !== n && (this.downscaler.dispose(), this.downscaler = new de(r), this.downscaler.setScale(this.analysisScale));
1321
+ }
1322
+ async initialize(e) {
1323
+ this.status = "loading", this.error = null, this.setRuntimeOptions(e ?? {});
1324
+ try {
1325
+ const n = await j.forVisionTasks(
1326
+ new URL("/assets/xr/wasm", U.assetStorageEndpoint).toString()
1327
+ ), [r] = await Promise.all([
1328
+ Z((e == null ? void 0 : e.modelUrl) ?? gt),
1329
+ $(n)
1330
+ ]);
1331
+ this.vision = n, this.modelBuffer = r, this.graphOptions = {
1332
+ runningMode: "VIDEO",
1333
+ outputFaceBlendshapes: (e == null ? void 0 : e.outputFaceBlendshapes) ?? !0,
1334
+ minFaceDetectionConfidence: e == null ? void 0 : e.minFaceDetectionConfidence,
1335
+ minFacePresenceConfidence: e == null ? void 0 : e.minFacePresenceConfidence,
1336
+ minPoseDetectionConfidence: e == null ? void 0 : e.minPoseDetectionConfidence,
1337
+ minPosePresenceConfidence: e == null ? void 0 : e.minPosePresenceConfidence,
1338
+ minHandLandmarksConfidence: e == null ? void 0 : e.minHandLandmarksConfidence
1339
+ }, this.delegatePolicy = (e == null ? void 0 : e.delegate) ?? "auto", this.delegate = this.delegatePolicy === "CPU" ? "CPU" : "GPU";
1340
+ const a = await this.createLandmarker(this.delegate);
1341
+ if (this.disposed) {
1342
+ a.close();
1343
+ return;
1344
+ }
1345
+ this.landmarker = a, this.status = "ready";
1346
+ } catch (n) {
1347
+ throw this.status = "error", this.error = n instanceof Error ? n : new Error(String(n)), this.error;
1348
+ }
1349
+ }
1350
+ createLandmarker(e) {
1351
+ if (!this.vision || !this.modelBuffer)
1352
+ throw new Error("HolisticTrackingModel: initialize() has not loaded the model");
1353
+ return us.createFromOptions(this.vision, {
1354
+ baseOptions: { modelAssetBuffer: this.modelBuffer, delegate: e },
1355
+ ...this.graphOptions
1356
+ });
1357
+ }
1358
+ /**
1359
+ * The GPU graph can fail on its first run (the face-blendshape stage has no
1360
+ * WebGL kernel for one of its ops). Rebuild on the CPU once, keep the RAF
1361
+ * loop alive meanwhile, and run one detection right away so static sources
1362
+ * (which pulse models once) still get a result.
1363
+ */
1364
+ async fallbackToCpu(e) {
1365
+ this.fallbackAttempted = !0, this.rebuilding = !0, this.status = "loading", console.warn(
1366
+ "[xr-sdk holistic] GPU inference failed; rebuilding the graph on the CPU delegate.",
1367
+ e.message
1368
+ );
1369
+ const n = this.landmarker;
1370
+ try {
1371
+ const r = await this.createLandmarker("CPU");
1372
+ if (this.disposed) {
1373
+ r.close();
1374
+ return;
1375
+ }
1376
+ this.landmarker = r, this.delegate = "CPU", this.status = "ready", this.error = null;
1377
+ try {
1378
+ n == null || n.close();
1379
+ } catch {
1380
+ }
1381
+ this.rebuilding = !1, this.detectOnce();
1382
+ } catch (r) {
1383
+ this.rebuilding = !1, this.status = "error", this.error = r instanceof Error ? r : new Error(String(r));
1384
+ }
1385
+ }
1386
+ /** One detect + publish outside the loop (used after a delegate rebuild). */
1387
+ detectOnce() {
1388
+ this.disposed || !this.landmarker || !this.sourceCanvas || (this.detect(), this.builder.update(this.raw, performance.now(), this.result, this.isMirrored()));
1389
+ }
1390
+ detect() {
1391
+ var r, a, o, c, l;
1392
+ if (!this.landmarker || !this.sourceCanvas) return;
1393
+ const e = this.downscaler.draw(this.sourceCanvas), n = performance.now();
1394
+ try {
1395
+ this.raw = this.landmarker.detectForVideo(e, n), this.status === "error" && (this.status = "ready", this.error = null), this.recordInferenceError(null);
1396
+ const h = this.raw, f = ((r = h.faceLandmarks) != null && r.length ? 1 : 0) + ((a = h.leftHandLandmarks) != null && a.length ? 1 : 0) + ((o = h.rightHandLandmarks) != null && o.length ? 1 : 0) + ((c = h.poseLandmarks) != null && c.length ? 1 : 0), u = (l = h.poseLandmarks) == null ? void 0 : l[0];
1397
+ this.recordDetections(
1398
+ f,
1399
+ u && u.length ? u.reduce((w, S) => w + (S.visibility ?? 0), 0) / u.length : null
1400
+ );
1401
+ } catch (h) {
1402
+ const f = h instanceof Error ? h : new Error(String(h));
1403
+ this.delegatePolicy === "auto" && this.delegate === "GPU" && !this.fallbackAttempted ? this.fallbackToCpu(f) : (this.status = "error", this.error = f, this.recordInferenceError(f));
1404
+ }
1405
+ this.processingTime = performance.now() - n, this.recordInference(n);
1406
+ }
1407
+ /** The session mirrors only the webcam feed (an unknown kind is treated as webcam). */
1408
+ isMirrored() {
1409
+ var e;
1410
+ return He((e = this.getSource) == null ? void 0 : e.call(this));
1411
+ }
1412
+ async run({
1413
+ sourceCanvas: e,
1414
+ getSource: n,
1415
+ targetFps: r,
1416
+ analysisScale: a
1417
+ }) {
1418
+ this.sourceCanvas = e, this.getSource = n, this.setTargetFps(r), this.setAnalysisScale(a), this.downscaler.setScale(this.analysisScale), this.rafId === null && await this.process();
1419
+ }
1420
+ async process() {
1421
+ this.disposed || this.paused || !this.landmarker || (!this.rebuilding && this.shouldRunInference() && this.detect(), this.builder.update(this.raw, performance.now(), this.result, this.isMirrored()), !(this.disposed || this.paused) && (this.rafId = requestAnimationFrame(this.process.bind(this))));
1422
+ }
1423
+ resume() {
1424
+ this.paused && (super.resume(), this.process());
1425
+ }
1426
+ dispose() {
1427
+ if (super.dispose(), this.landmarker) {
1428
+ try {
1429
+ this.landmarker.close();
1430
+ } catch {
1431
+ }
1432
+ this.landmarker = null;
1433
+ }
1434
+ this.sourceCanvas = void 0, this.getSource = void 0, this.downscaler.dispose(), this.vision = null, this.modelBuffer = null, this.raw = void 0, this.builder.reset(), this.result.face = null, this.result.leftHand = null, this.result.rightHand = null, this.result.pose = null;
1435
+ }
1436
+ getModelNode() {
1437
+ return this.node;
1438
+ }
1439
+ async getPerformanceData() {
1440
+ return { name: this.constructor.name, processingTime: this.processingTime };
1441
+ }
1442
+ }
1443
+ const rn = 512;
1444
+ class an extends J {
1445
+ constructor() {
1446
+ super();
1447
+ d(this, "landmarker", null);
1448
+ d(this, "processingTime", null);
1449
+ d(this, "hands");
1450
+ d(this, "coordinates");
1451
+ d(this, "gesture");
1452
+ d(this, "handedness");
1453
+ d(this, "sourceCanvas");
1454
+ d(this, "downscaler", new de(rn));
1455
+ }
1456
+ async getHandData() {
1457
+ var h, f;
1458
+ if (!this.landmarker || !this.sourceCanvas)
1459
+ return;
1460
+ const e = this.downscaler.draw(this.sourceCanvas), n = performance.now(), r = this.landmarker.detectForVideo(e, n), a = performance.now();
1461
+ this.processingTime = a - n, this.recordInference(n, a);
1462
+ const o = [], c = r.handedness ?? r.handednesses ?? [];
1463
+ if (this.recordDetections(r.landmarks.length, ((f = (h = c[0]) == null ? void 0 : h[0]) == null ? void 0 : f.score) ?? null), r.landmarks.forEach((u, w) => {
1464
+ var _, g, v;
1465
+ if (!u || u.length === 0)
1466
+ return;
1467
+ const S = u.map(
1468
+ (y) => le(y)
1469
+ ), k = (v = (g = (_ = c[w]) == null ? void 0 : _[0]) == null ? void 0 : g.categoryName) == null ? void 0 : v.toLowerCase(), x = k === "left" || k === "right" ? k : void 0, T = u[0].z < 0 ? "closed_fist" : "open_palm";
1470
+ o.push({ coordinates: S, gesture: T, handedness: x });
1471
+ }), !o.length)
1472
+ return {
1473
+ hands: void 0,
1474
+ coordinates: void 0,
1475
+ gesture: void 0,
1476
+ handedness: void 0
1477
+ };
1478
+ const l = o[0];
1479
+ return {
1480
+ hands: o,
1481
+ coordinates: l.coordinates,
1482
+ gesture: l.gesture,
1483
+ handedness: l.handedness
1484
+ };
1485
+ }
1486
+ async processHandTracking() {
1487
+ if (!this.disposed) {
1488
+ if (this.shouldRunInference()) {
1489
+ const e = await this.getHandData();
1490
+ e && (this.hands = e.hands, this.coordinates = e.coordinates, this.gesture = e.gesture, this.handedness = e.handedness);
1491
+ }
1492
+ this.disposed || this.paused || (this.rafId = requestAnimationFrame(this.processHandTracking.bind(this)));
1493
+ }
1494
+ }
1495
+ resume() {
1496
+ this.paused && (super.resume(), this.processHandTracking());
1497
+ }
1498
+ dispose() {
1499
+ if (super.dispose(), this.landmarker) {
1500
+ try {
1501
+ this.landmarker.close();
1502
+ } catch {
1503
+ }
1504
+ this.landmarker = null;
1505
+ }
1506
+ this.sourceCanvas = void 0, this.hands = void 0, this.downscaler.dispose(), this.coordinates = void 0, this.gesture = void 0, this.handedness = void 0;
1507
+ }
1508
+ async initialize() {
1509
+ const e = await j.forVisionTasks(
1510
+ new URL("/assets/xr/wasm", U.assetStorageEndpoint).toString()
1511
+ ), [n] = await Promise.all([
1512
+ Z(
1513
+ new URL("/assets/xr/models/hand_tracking.task", U.assetStorageEndpoint).toString()
1514
+ ),
1515
+ $(e)
1516
+ ]), r = await hs.createFromOptions(e, {
1517
+ baseOptions: {
1518
+ modelAssetBuffer: n,
1519
+ delegate: "GPU"
1520
+ },
1521
+ runningMode: "VIDEO",
1522
+ numHands: 2
1523
+ });
1524
+ this.landmarker = r;
1525
+ }
1526
+ async run({ sourceCanvas: e, targetFps: n, analysisScale: r }) {
1527
+ this.setAnalysisScale(r), this.downscaler.setScale(this.analysisScale), this.sourceCanvas = e, this.setTargetFps(n), this.rafId === null && await this.processHandTracking();
1528
+ }
1529
+ getModelNode() {
1530
+ const e = this;
1531
+ return {
1532
+ get hands() {
1533
+ return e.hands;
1534
+ },
1535
+ get coordinates() {
1536
+ return e.coordinates;
1537
+ },
1538
+ get gesture() {
1539
+ return e.gesture;
1540
+ },
1541
+ get handedness() {
1542
+ return e.handedness;
1543
+ }
1544
+ };
1545
+ }
1546
+ async getPerformanceData() {
1547
+ return {
1548
+ name: this.constructor.name,
1549
+ processingTime: this.processingTime
1550
+ };
1551
+ }
1552
+ }
1553
+ const on = 24, cn = 720, ln = [
1554
+ [255, 255, 255, 255],
1555
+ // 0: background → green 255, kept
1556
+ [0, 0, 0, 0]
1557
+ // 1: person → green 0, discarded
1558
+ ];
1559
+ class dn extends J {
1560
+ constructor() {
1561
+ super();
1562
+ d(this, "segmenter", null);
1563
+ d(this, "processingTime", null);
1564
+ d(this, "sourceCanvas");
1565
+ // input source canvas
1566
+ d(this, "processCanvas");
1567
+ // downscaled canvas of sourceCanvas for processing
1568
+ d(this, "filterCanvas");
1569
+ // post-processing (blur) canvas
1570
+ // Optional high-resolution input override. The shared session feed canvas is
1571
+ // sized to the on-screen display layout (often a small, display-fit crop),
1572
+ // which starves the segmenter of the resolution it needs to capture the whole
1573
+ // body. When a consumer supplies a native-resolution source here (e.g. the raw
1574
+ // <video>/<img>), the segmenter runs on THAT instead — letterboxed into the
1575
+ // process canvas so nothing is cropped. Falls back to `sourceCanvas` when unset.
1576
+ d(this, "inputSource");
1577
+ d(this, "inputSourceSize");
1578
+ // The segmenter's own WebGL2 context. DrawingUtils renders the inverted mask
1579
+ // into this context on the GPU; we then blit that GL canvas straight into the
1580
+ // mask canvas with a single `drawImage` — a GPU→GPU transfer, no CPU readback
1581
+ // and no per-pixel JS loop. (A spike proved `drawImage(glCanvas)` reads the
1582
+ // full DrawingUtils output correctly; the earlier "reads empty" wall that once
1583
+ // forced a readPixels path was a false alarm.)
1584
+ d(this, "glCanvas");
1585
+ d(this, "drawingUtils");
1586
+ d(this, "useGpuMaskPath", !1);
1587
+ // CPU-fallback reused ImageData, allocated on size change only. Used ONLY when
1588
+ // WebGL2 is unavailable and we must read the single-channel mask back by hand.
1589
+ d(this, "maskImageData");
1590
+ d(this, "maskCanvas", null);
1591
+ d(this, "segmentationMaskTexture");
1592
+ d(this, "isMaskSetup", !1);
1593
+ d(this, "isProcessing", !1);
1594
+ // Live clone of the most recent category mask, kept so getRawSegmentationData()
1595
+ // can read the single-channel Uint8Array lazily — that readback is paid ONLY
1596
+ // when a consumer actually asks for raw data. Cloned because the mask returned
1597
+ // by segmentForVideo is invalidated on the next inference call.
1598
+ d(this, "latestMask", null);
1599
+ // Per-frame cache of the read-back array, so repeated getRawSegmentationData()
1600
+ // calls within one frame don't re-run the GPU→CPU transfer.
1601
+ d(this, "rawCache", null);
1602
+ d(this, "quality", "medium");
1603
+ d(this, "stagingCanvas");
1604
+ }
1605
+ getQualityScaleFactor() {
1606
+ switch (this.quality) {
1607
+ case "low":
1608
+ return 0.5;
1609
+ case "medium":
1610
+ return 0.75;
1611
+ case "high":
1612
+ return 1;
1613
+ default:
1614
+ return 0.5;
1615
+ }
1616
+ }
1617
+ /**
1618
+ * Set (or clear) a high-resolution input override. Pass the raw <video>/<img>
1619
+ * (or any CanvasImageSource with intrinsic dimensions) to run segmentation on
1620
+ * native-resolution, uncropped frames instead of the small display-fit session
1621
+ * feed. Pass `undefined` to revert to the shared feed canvas.
1622
+ */
1623
+ setInputSource(e) {
1624
+ this.inputSource = e, this.inputSourceSize = e ? this.readIntrinsicSize(e) : void 0;
1625
+ }
1626
+ readIntrinsicSize(e) {
1627
+ if (e instanceof HTMLVideoElement)
1628
+ return e.videoWidth > 0 ? { width: e.videoWidth, height: e.videoHeight } : void 0;
1629
+ if (e instanceof HTMLImageElement)
1630
+ return e.naturalWidth > 0 ? { width: e.naturalWidth, height: e.naturalHeight } : void 0;
1631
+ const n = e.width, r = e.height;
1632
+ return typeof n == "number" && n > 0 && typeof r == "number" && r > 0 ? { width: n, height: r } : void 0;
1633
+ }
1634
+ /**
1635
+ * Size the process canvas to the override input's aspect ratio, bounded by
1636
+ * PROCESS_MAX_DIM on the long edge, and keep the GL canvas in sync so the GPU
1637
+ * mask renders at the same resolution. No-op when there is no override, or when
1638
+ * the intrinsic size hasn't changed since the last frame.
1639
+ */
1640
+ ensureProcessCanvasForInput() {
1641
+ if (!this.processCanvas || !this.inputSource) return;
1642
+ const e = this.readIntrinsicSize(this.inputSource);
1643
+ if (!e) return;
1644
+ this.inputSourceSize = e;
1645
+ const n = Math.min(1, cn / Math.max(e.width, e.height)), r = Math.max(1, Math.round(e.width * n)), a = Math.max(1, Math.round(e.height * n));
1646
+ this.processCanvas.width === r && this.processCanvas.height === a || (this.processCanvas.width = r, this.processCanvas.height = a, this.glCanvas && (this.glCanvas.width = r, this.glCanvas.height = a), this.maskImageData = void 0);
1647
+ }
1648
+ async processSegmentation() {
1649
+ if (this.disposed || !this.isProcessing || !this.maskCanvas || !this.processCanvas)
1650
+ return;
1651
+ if (!this.shouldRunInference()) {
1652
+ if (this.disposed || this.paused) return;
1653
+ this.rafId = requestAnimationFrame(this.processSegmentation.bind(this));
1654
+ return;
1655
+ }
1656
+ const e = this.inputSource ?? this.sourceCanvas;
1657
+ if (!this.segmenter || !e) {
1658
+ if (this.disposed || this.paused) return;
1659
+ this.rafId = requestAnimationFrame(this.processSegmentation.bind(this));
1660
+ return;
1661
+ }
1662
+ const n = performance.now();
1663
+ this.ensureProcessCanvasForInput();
1664
+ const r = this.processCanvas.getContext("2d");
1665
+ if (r) {
1666
+ const c = this.processCanvas.width, l = this.processCanvas.height;
1667
+ if (r.clearRect(0, 0, c, l), this.inputSource && this.inputSourceSize) {
1668
+ const { width: h, height: f } = this.inputSourceSize, u = Math.min(c / h, l / f), w = h * u, S = f * u;
1669
+ r.drawImage(this.inputSource, (c - w) / 2, (l - S) / 2, w, S);
1670
+ } else
1671
+ r.drawImage(e, 0, 0, c, l);
1672
+ }
1673
+ const o = this.segmenter.segmentForVideo(
1674
+ this.processCanvas,
1675
+ performance.now()
1676
+ ).categoryMask;
1677
+ if (!o) {
1678
+ if (this.disposed || this.paused) return;
1679
+ this.rafId = requestAnimationFrame(this.processSegmentation.bind(this));
1680
+ return;
1681
+ }
1682
+ if (this.rawCache = null, this.latestMask && (this.latestMask.close(), this.latestMask = null), this.useGpuMaskPath && this.drawingUtils && this.glCanvas)
1683
+ this.drawingUtils.drawCategoryMask(o, ln), this.latestMask = o.clone(), o.close(), this.blitGlToMask();
1684
+ else {
1685
+ this.latestMask = o.clone();
1686
+ const c = this.readMaskToImageData(o);
1687
+ o.close(), c && this.blitImageDataToMask(c);
1688
+ }
1689
+ this.segmentationMaskTexture && (this.isMaskSetup || (this.segmentationMaskTexture.format = mt, this.segmentationMaskTexture.minFilter = pe, this.segmentationMaskTexture.magFilter = pe, this.segmentationMaskTexture.generateMipmaps = !1, this.isMaskSetup = !0), this.segmentationMaskTexture.needsUpdate = !0), this.processingTime = performance.now() - n, this.recordInference(n), this.recordDetections(1, null), !(this.disposed || this.paused) && (this.rafId = requestAnimationFrame(this.processSegmentation.bind(this)));
1690
+ }
1691
+ /**
1692
+ * Blit the GPU-rendered mask (already RGBA-inverted by drawCategoryMask)
1693
+ * straight from the GL canvas into the mask canvas, cover-fitted through the
1694
+ * soft-edge blur. `drawImage(glCanvas)` is a GPU→GPU transfer — no readPixels,
1695
+ * no CPU array, no ImageData, no row flip (the 2D canvas presents the WebGL
1696
+ * canvas right-side-up). This is the zero-readback path.
1697
+ */
1698
+ blitGlToMask() {
1699
+ if (!this.maskCanvas || !this.filterCanvas || !this.glCanvas) return;
1700
+ const e = this.maskCanvas.getContext("2d"), n = this.filterCanvas.getContext("2d");
1701
+ !e || !n || (n.filter = "blur(0.5px)", n.clearRect(0, 0, this.filterCanvas.width, this.filterCanvas.height), n.drawImage(this.glCanvas, 0, 0, this.filterCanvas.width, this.filterCanvas.height), e.clearRect(0, 0, this.maskCanvas.width, this.maskCanvas.height), e.drawImage(this.filterCanvas, 0, 0, this.maskCanvas.width, this.maskCanvas.height));
1702
+ }
1703
+ /**
1704
+ * CPU-fallback inverted-alpha ImageData build (only when the GPU path is off).
1705
+ * The single-channel mask is expanded to RGBA with the person→transparent,
1706
+ * background→opaque convention (green carries the signal for the alphaMap).
1707
+ */
1708
+ readMaskToImageData(e) {
1709
+ const n = e.getAsUint8Array(), { width: r, height: a } = e;
1710
+ if (!n || r <= 0 || a <= 0) return null;
1711
+ (!this.maskImageData || this.maskImageData.width !== r || this.maskImageData.height !== a) && (this.maskImageData = new ImageData(r, a));
1712
+ const o = this.maskImageData.data;
1713
+ for (let c = 0; c < n.length; c += 1) {
1714
+ const l = n[c] === 255 ? 0 : 255;
1715
+ o[c * 4] = 255, o[c * 4 + 1] = l, o[c * 4 + 2] = 255, o[c * 4 + 3] = l;
1716
+ }
1717
+ return this.maskImageData;
1718
+ }
1719
+ /**
1720
+ * CPU-fallback blit: put the inverted-alpha mask ImageData into maskCanvas
1721
+ * with a soft-edge blur, cover-fitted to the render target. Only used when the
1722
+ * GPU path is off; the GPU path blits the GL canvas directly (blitGlToMask).
1723
+ */
1724
+ blitImageDataToMask(e) {
1725
+ if (!this.maskCanvas || !this.filterCanvas) return;
1726
+ const n = this.maskCanvas.getContext("2d"), r = this.filterCanvas.getContext("2d");
1727
+ if (!n || !r) return;
1728
+ const a = this.getStagingCanvas(e.width, e.height), o = a.getContext("2d");
1729
+ o && (o.putImageData(e, 0, 0), r.filter = "blur(0.5px)", r.clearRect(0, 0, this.filterCanvas.width, this.filterCanvas.height), r.drawImage(a, 0, 0, this.filterCanvas.width, this.filterCanvas.height), n.clearRect(0, 0, this.maskCanvas.width, this.maskCanvas.height), n.drawImage(this.filterCanvas, 0, 0, this.maskCanvas.width, this.maskCanvas.height));
1730
+ }
1731
+ getStagingCanvas(e, n) {
1732
+ return this.stagingCanvas || (this.stagingCanvas = document.createElement("canvas")), this.stagingCanvas.width !== e && (this.stagingCanvas.width = e), this.stagingCanvas.height !== n && (this.stagingCanvas.height = n), this.stagingCanvas;
1733
+ }
1734
+ resume() {
1735
+ this.paused && (super.resume(), this.processSegmentation());
1736
+ }
1737
+ dispose() {
1738
+ if (super.dispose(), this.isProcessing = !1, this.latestMask) {
1739
+ try {
1740
+ this.latestMask.close();
1741
+ } catch {
1742
+ }
1743
+ this.latestMask = null;
1744
+ }
1745
+ if (this.rawCache = null, this.segmenter) {
1746
+ try {
1747
+ this.segmenter.close();
1748
+ } catch {
1749
+ }
1750
+ this.segmenter = null;
1751
+ }
1752
+ this.drawingUtils = void 0, this.glCanvas = void 0, this.maskImageData = void 0, this.segmentationMaskTexture && (this.segmentationMaskTexture.dispose(), this.segmentationMaskTexture = void 0), this.sourceCanvas = void 0, this.inputSource = void 0, this.inputSourceSize = void 0, this.processCanvas = void 0, this.filterCanvas = void 0, this.stagingCanvas = void 0, this.maskCanvas = null;
1753
+ }
1754
+ async initialize(e) {
1755
+ this.quality = (e == null ? void 0 : e.quality) ?? "low";
1756
+ const n = await j.forVisionTasks(
1757
+ new URL("/assets/xr/wasm", U.assetStorageEndpoint).toString()
1758
+ ), [r] = await Promise.all([
1759
+ Z(
1760
+ new URL("/assets/xr/models/segmentation.tflite", U.assetStorageEndpoint).toString()
1761
+ ),
1762
+ $(n)
1763
+ ]);
1764
+ this.glCanvas = new OffscreenCanvas(1, 1);
1765
+ const a = this.glCanvas.getContext("webgl2", {
1766
+ preserveDrawingBuffer: !0
1767
+ });
1768
+ this.segmenter = await ht.createFromOptions(n, {
1769
+ baseOptions: {
1770
+ modelAssetBuffer: r,
1771
+ delegate: "GPU"
1772
+ },
1773
+ ...a ? { canvas: this.glCanvas } : {},
1774
+ outputCategoryMask: !0,
1775
+ outputConfidenceMasks: !1,
1776
+ runningMode: "VIDEO"
1777
+ }), a ? (this.drawingUtils = new ms(a), this.useGpuMaskPath = !0) : this.useGpuMaskPath = !1;
1778
+ }
1779
+ async run({
1780
+ sourceCanvas: e,
1781
+ renderWidth: n,
1782
+ renderHeight: r,
1783
+ targetFps: a
1784
+ }) {
1785
+ var c;
1786
+ if (!e)
1787
+ return;
1788
+ this.setTargetFps(a ?? on), this.isProcessing = !1, this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null);
1789
+ const o = this.getQualityScaleFactor();
1790
+ this.sourceCanvas = e, this.processCanvas = document.createElement("canvas"), this.processCanvas.width = e.width * o, this.processCanvas.height = e.height * o, this.glCanvas && (this.glCanvas.width = this.processCanvas.width, this.glCanvas.height = this.processCanvas.height), this.maskImageData = void 0, this.maskCanvas = document.createElement("canvas"), this.maskCanvas.width = n, this.maskCanvas.height = r, this.filterCanvas = document.createElement("canvas"), this.filterCanvas.width = n, this.filterCanvas.height = r, (c = this.segmentationMaskTexture) == null || c.dispose(), this.segmentationMaskTexture = new ft(this.maskCanvas), this.isMaskSetup = !1, this.rawCache = null, this.isProcessing = !0, this.lastInferenceMs = 0, this.rafId = requestAnimationFrame(this.processSegmentation.bind(this));
1791
+ }
1792
+ /**
1793
+ * Lazily read the single-channel mask back to a Uint8Array. Only invoked when
1794
+ * a consumer calls getRawSegmentationData(); the default texture path never
1795
+ * touches it, so apps that only use <VideoBackground> pay no extra readback.
1796
+ */
1797
+ getRawSegmentationData() {
1798
+ if (this.rawCache) return this.rawCache;
1799
+ if (!this.latestMask) return null;
1800
+ const e = this.latestMask.getAsUint8Array();
1801
+ return this.rawCache = {
1802
+ maskData: e,
1803
+ width: this.latestMask.width,
1804
+ height: this.latestMask.height
1805
+ }, this.rawCache;
1806
+ }
1807
+ getModelNode() {
1808
+ const e = this;
1809
+ return {
1810
+ get backgroundSegmentationMask() {
1811
+ return e.segmentationMaskTexture;
1812
+ },
1813
+ getMaskCanvas: () => e.maskCanvas,
1814
+ getRawSegmentationData: () => e.getRawSegmentationData(),
1815
+ setInputSource: (n) => e.setInputSource(n ?? void 0)
1816
+ };
1817
+ }
1818
+ async getPerformanceData() {
1819
+ return {
1820
+ name: this.constructor.name,
1821
+ processingTime: this.processingTime
1822
+ };
1823
+ }
1824
+ }
1825
+ const un = (t, s, e, n = "feed") => ({
1826
+ width: Math.max(1, Math.round(t)),
1827
+ height: Math.max(1, Math.round(s)),
1828
+ indices: new Uint8Array(Math.max(1, Math.round(t)) * Math.max(1, Math.round(s))),
1829
+ labels: e,
1830
+ space: n,
1831
+ version: 0
1832
+ }), ur = (t) => {
1833
+ t.indices.fill(0);
1834
+ }, hr = (t, s) => t.labels.indexOf(s), hn = (t, s, e) => {
1835
+ const { width: n, height: r, indices: a } = t, o = s.length;
1836
+ if (o < 3) return;
1837
+ let c = 1 / 0, l = -1 / 0;
1838
+ for (let w = 0; w < o; w += 1) {
1839
+ const S = s[w].y * r;
1840
+ S < c && (c = S), S > l && (l = S);
1841
+ }
1842
+ const h = Math.max(0, Math.floor(c)), f = Math.min(r - 1, Math.ceil(l)), u = [];
1843
+ for (let w = h; w <= f; w += 1) {
1844
+ const S = w + 0.5;
1845
+ u.length = 0;
1846
+ for (let x = 0; x < o; x += 1) {
1847
+ const T = s[x], _ = s[(x + 1) % o], g = T.y * r, v = _.y * r;
1848
+ if (S < g == S < v) continue;
1849
+ const y = (S - g) / (v - g);
1850
+ u.push((T.x + y * (_.x - T.x)) * n);
1851
+ }
1852
+ u.sort((x, T) => x - T);
1853
+ const k = w * n;
1854
+ for (let x = 0; x + 1 < u.length; x += 2) {
1855
+ const T = Math.max(0, Math.round(u[x])), _ = Math.min(n, Math.round(u[x + 1]));
1856
+ for (let g = T; g < _; g += 1) a[k + g] = e;
1857
+ }
1858
+ }
1859
+ }, mr = (t, s, e, n, r = []) => {
1860
+ r.length = 0;
1861
+ for (let a = 0; a < e.length; a += 1) {
1862
+ const o = s[e[a]];
1863
+ if (!o) return;
1864
+ r.push(o);
1865
+ }
1866
+ hn(t, r, n);
1867
+ }, it = (t) => t, ot = {
1868
+ hair: {
1869
+ labels: ["bg", "hair"],
1870
+ assetPath: "/assets/xr/models/hair_segmenter.tflite",
1871
+ defaultUrl: "https://storage.googleapis.com/mediapipe-models/image_segmenter/hair_segmenter/float32/latest/hair_segmenter.tflite",
1872
+ decode: it
1873
+ },
1874
+ multiclass: {
1875
+ labels: ["bg", "hair", "body_skin", "face_skin", "clothes", "others"],
1876
+ assetPath: "/assets/xr/models/selfie_multiclass_256x256.tflite",
1877
+ defaultUrl: "https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_multiclass_256x256/float32/latest/selfie_multiclass_256x256.tflite",
1878
+ decode: it
1879
+ }
1880
+ }, mn = (t, s, e) => {
1881
+ const n = e.length === t.length ? e : new Uint8Array(t.length);
1882
+ for (let r = 0; r < t.length; r += 1) n[r] = s(t[r]);
1883
+ return n;
1884
+ }, fn = 15, gn = { low: 0.5, medium: 0.75, high: 1 };
1885
+ class pn extends J {
1886
+ constructor() {
1887
+ super();
1888
+ d(this, "segmenter", null);
1889
+ d(this, "preset", "hair");
1890
+ d(this, "quality", "medium");
1891
+ d(this, "status", "loading");
1892
+ d(this, "error", null);
1893
+ d(this, "processingTime", null);
1894
+ d(this, "sourceCanvas");
1895
+ d(this, "processCanvas");
1896
+ d(this, "isProcessing", !1);
1897
+ d(this, "mask", un(1, 1, ["bg"]));
1898
+ d(this, "node");
1899
+ this.node = {
1900
+ getMask: () => this.mask,
1901
+ getStatus: () => this.status,
1902
+ getError: () => this.error
1903
+ };
1904
+ }
1905
+ async initialize(e) {
1906
+ this.preset = (e == null ? void 0 : e.preset) ?? "hair", this.quality = (e == null ? void 0 : e.quality) ?? "medium";
1907
+ const n = ot[this.preset];
1908
+ this.mask.labels = n.labels, this.status = "loading", this.error = null;
1909
+ try {
1910
+ const r = await j.forVisionTasks(
1911
+ new URL("/assets/xr/wasm", U.assetStorageEndpoint).toString()
1912
+ ), a = (e == null ? void 0 : e.modelUrl) ?? n.defaultUrl, [o] = await Promise.all([
1913
+ Z(a),
1914
+ $(r)
1915
+ ]);
1916
+ this.segmenter = await ht.createFromOptions(r, {
1917
+ baseOptions: { modelAssetBuffer: o, delegate: "GPU" },
1918
+ outputCategoryMask: !0,
1919
+ outputConfidenceMasks: !1,
1920
+ runningMode: "VIDEO"
1921
+ }), this.status = "ready";
1922
+ } catch (r) {
1923
+ throw this.status = "error", this.error = r instanceof Error ? r : new Error(String(r)), this.error;
1924
+ }
1925
+ }
1926
+ async run({ sourceCanvas: e, targetFps: n }) {
1927
+ e && (this.setTargetFps(n ?? fn), this.isProcessing = !1, this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null), this.sourceCanvas = e, this.processCanvas = document.createElement("canvas"), this.isProcessing = !0, this.lastInferenceMs = 0, this.rafId = requestAnimationFrame(this.process.bind(this)));
1928
+ }
1929
+ process() {
1930
+ if (this.disposed || this.paused || !this.isProcessing) return;
1931
+ const { segmenter: e, sourceCanvas: n, processCanvas: r } = this;
1932
+ if (!e || !n || !r || !this.shouldRunInference()) {
1933
+ this.rafId = requestAnimationFrame(this.process.bind(this));
1934
+ return;
1935
+ }
1936
+ const a = performance.now(), o = gn[this.quality], c = Math.max(1, Math.round(n.width * o)), l = Math.max(1, Math.round(n.height * o));
1937
+ (r.width !== c || r.height !== l) && (r.width = c, r.height = l);
1938
+ const h = r.getContext("2d");
1939
+ h && h.drawImage(n, 0, 0, c, l);
1940
+ try {
1941
+ const u = e.segmentForVideo(r, performance.now()).categoryMask;
1942
+ if (u) {
1943
+ const w = u.getAsUint8Array();
1944
+ (this.mask.width !== u.width || this.mask.height !== u.height) && (this.mask.width = u.width, this.mask.height = u.height), this.mask.indices = mn(
1945
+ w,
1946
+ ot[this.preset].decode,
1947
+ this.mask.indices
1948
+ ), this.mask.version += 1, u.close();
1949
+ }
1950
+ this.status === "error" && (this.status = "ready", this.error = null), this.recordInferenceError(null), this.recordDetections(u ? 1 : 0, null);
1951
+ } catch (f) {
1952
+ this.status = "error", this.error = f instanceof Error ? f : new Error(String(f)), this.recordInferenceError(this.error);
1953
+ }
1954
+ this.processingTime = performance.now() - a, this.recordInference(a), !(this.disposed || this.paused) && (this.rafId = requestAnimationFrame(this.process.bind(this)));
1955
+ }
1956
+ resume() {
1957
+ this.paused && (super.resume(), this.isProcessing && (this.rafId = requestAnimationFrame(this.process.bind(this))));
1958
+ }
1959
+ getModelNode() {
1960
+ return this.node;
1961
+ }
1962
+ async getPerformanceData() {
1963
+ return { name: this.constructor.name, processingTime: this.processingTime };
1964
+ }
1965
+ dispose() {
1966
+ var e;
1967
+ super.dispose(), this.isProcessing = !1;
1968
+ try {
1969
+ (e = this.segmenter) == null || e.close();
1970
+ } catch {
1971
+ }
1972
+ this.segmenter = null, this.sourceCanvas = void 0, this.processCanvas = void 0;
1973
+ }
1974
+ }
1975
+ const ct = {
1976
+ [R.BACKGROUND_SEGMENTATION]: dn,
1977
+ [R.SEMANTIC_SEGMENTATION]: pn,
1978
+ [R.HAND_TRACKER]: an,
1979
+ [R.GESTURE_TRACKER]: sn,
1980
+ [R.FACE_TRACKER]: Zs,
1981
+ [R.BODY_TRACKER]: Xs,
1982
+ [R.HOLISTIC_TRACKER]: nn
1983
+ }, yn = async (t) => {
1984
+ const s = document.createElement("video");
1985
+ s.srcObject = t, s.muted = !0, s.playsInline = !0, s.autoplay = !0, await new Promise((n) => {
1986
+ s.onloadedmetadata = () => {
1987
+ s.play(), n();
1988
+ };
1989
+ });
1990
+ const e = s;
1991
+ return await new Promise((n) => {
1992
+ const r = setTimeout(n, 150), a = () => {
1993
+ clearTimeout(r), n();
1994
+ };
1995
+ typeof e.requestVideoFrameCallback == "function" ? e.requestVideoFrameCallback(a) : requestAnimationFrame(() => requestAnimationFrame(() => a()));
1996
+ }), s;
1997
+ }, wn = (t) => {
1998
+ const s = new ft(t);
1999
+ return s.colorSpace = fs, s.format = mt, s.minFilter = pe, s.magFilter = pe, s.generateMipmaps = !1, s.needsUpdate = !0, s;
2000
+ }, vn = (t, s) => {
2001
+ const e = t.videoWidth, n = t.videoHeight;
2002
+ e > 0 && n > 0 && (s.width !== e && (s.width = e), s.height !== n && (s.height = n));
2003
+ const r = s.getContext("2d", {
2004
+ colorSpace: "srgb"
2005
+ });
2006
+ r.save(), r.scale(-1, 1), r.drawImage(t, -s.width, 0, s.width, s.height), r.restore();
2007
+ }, Sn = (t, s, e = 1) => {
2008
+ const n = s.getContext("2d", {
2009
+ colorSpace: "srgb"
2010
+ }), r = Ds({
2011
+ source: { width: t.width, height: t.height },
2012
+ feed: { width: s.width, height: s.height },
2013
+ zoom: e
2014
+ });
2015
+ r && (n.setTransform(1, 0, 0, 1, 0, 0), n.clearRect(0, 0, s.width, s.height), n.drawImage(
2016
+ t,
2017
+ 0,
2018
+ 0,
2019
+ t.width,
2020
+ t.height,
2021
+ r.offsetX,
2022
+ r.offsetY,
2023
+ r.drawWidth,
2024
+ r.drawHeight
2025
+ ));
2026
+ }, Mn = (t, s, e) => {
2027
+ const n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new WeakSet();
2028
+ let a = !1;
2029
+ const o = (g, v) => {
2030
+ const y = t.getSnapshot().modelErrors;
2031
+ if (v === null && !y.has(g)) return;
2032
+ const C = new Map(y);
2033
+ v === null ? C.delete(g) : C.set(g, { model: g, error: v, at: performance.now() }), t.set({ modelErrors: C });
2034
+ }, c = (g, v) => {
2035
+ var y;
2036
+ try {
2037
+ (y = v.dispose) == null || y.call(v);
2038
+ } catch (C) {
2039
+ console.warn(`[xr-sdk registry] dispose threw for ${g}`, C);
2040
+ }
2041
+ };
2042
+ return {
2043
+ acquire: async (g, v, y) => {
2044
+ let C = n.get(g);
2045
+ if (C)
2046
+ return C.refs.add(v), C.activeRefs.add(v), C.initPromise;
2047
+ const N = s[g];
2048
+ if (!N)
2049
+ throw new Error(`Invalid model: ${g}`);
2050
+ const E = new N(), V = /* @__PURE__ */ new Set([v]), q = /* @__PURE__ */ new Set([v]);
2051
+ o(g, null);
2052
+ const L = (async () => {
2053
+ await E.initialize(y);
2054
+ const A = n.get(g);
2055
+ if (!A || A.model !== E || A.refs.size === 0)
2056
+ return c(g, E), E;
2057
+ e && await e(g, E);
2058
+ const W = n.get(g);
2059
+ return W && W.refs.size > 0 && (r.add(E), t.setPipeline((K) => K.set(g, E))), E;
2060
+ })();
2061
+ return C = { model: E, refs: V, activeRefs: q, initPromise: L, options: y }, n.set(g, C), L.catch((A) => {
2062
+ n.get(g) === C && (n.delete(g), t.setPipeline((K) => K.delete(g)), o(g, A instanceof Error ? A : new Error(String(A)))), c(g, E);
2063
+ }), L;
2064
+ },
2065
+ release: (g, v) => {
2066
+ const y = n.get(g);
2067
+ y && (y.refs.delete(v), y.activeRefs.delete(v) && y.refs.size > 0 && y.activeRefs.size === 0 && y.model.pause(), !(y.refs.size > 0) && (n.delete(g), c(g, y.model), t.setPipeline((C) => C.delete(g))));
2068
+ },
2069
+ setActive: (g, v, y) => {
2070
+ const C = n.get(g);
2071
+ if (!C || !C.refs.has(v)) return;
2072
+ const N = C.activeRefs.size > 0;
2073
+ y ? C.activeRefs.add(v) : C.activeRefs.delete(v);
2074
+ const E = C.activeRefs.size > 0;
2075
+ N !== E && (E && !a ? C.model.resume() : C.model.pause());
2076
+ },
2077
+ suspendAll: () => {
2078
+ a = !0;
2079
+ for (const g of n.values())
2080
+ g.model.pause();
2081
+ },
2082
+ resumeActive: () => {
2083
+ a = !1;
2084
+ for (const g of n.values())
2085
+ g.activeRefs.size > 0 && g.model.resume();
2086
+ },
2087
+ get: (g) => {
2088
+ var v;
2089
+ return (v = n.get(g)) == null ? void 0 : v.model;
2090
+ },
2091
+ getOptions: (g) => {
2092
+ var v;
2093
+ return (v = n.get(g)) == null ? void 0 : v.options;
2094
+ },
2095
+ releaseAll: () => {
2096
+ for (const g of Array.from(n.keys())) {
2097
+ const v = n.get(g);
2098
+ v && (v.refs.clear(), n.delete(g), c(g, v.model));
2099
+ }
2100
+ t.setPipeline((g) => g.clear());
2101
+ },
2102
+ getState: (g) => {
2103
+ const v = n.get(g);
2104
+ return v ? r.has(v.model) ? "ready" : "initializing" : t.getSnapshot().modelErrors.has(g) ? "error" : "idle";
2105
+ },
2106
+ getOwners: (g) => {
2107
+ const v = n.get(g);
2108
+ return {
2109
+ refs: v ? Array.from(v.refs) : [],
2110
+ active: v ? Array.from(v.activeRefs) : []
2111
+ };
2112
+ }
2113
+ };
2114
+ }, kn = {
2115
+ lifecycle: "idle",
2116
+ ready: !1,
2117
+ error: void 0,
2118
+ cameraTexture: void 0,
2119
+ renderWidth: 0,
2120
+ renderHeight: 0,
2121
+ source: void 0,
2122
+ sourceKind: void 0,
2123
+ cameraFacing: null,
2124
+ cameraDeviceId: null,
2125
+ orientation: { type: "portrait", angle: 0 },
2126
+ quality: null,
2127
+ qualityConfig: null,
2128
+ sourceWidth: 0,
2129
+ sourceHeight: 0,
2130
+ cameraZoom: 1.2,
2131
+ pipeline: /* @__PURE__ */ new Map(),
2132
+ modelErrors: /* @__PURE__ */ new Map(),
2133
+ cameraPermission: "unknown",
2134
+ cameraPermissionReason: null,
2135
+ feedFrames: 0
2136
+ }, Cn = () => {
2137
+ let t = { ...kn, pipeline: /* @__PURE__ */ new Map(), modelErrors: /* @__PURE__ */ new Map() };
2138
+ const s = /* @__PURE__ */ new Set(), e = () => {
2139
+ s.forEach((n) => n());
2140
+ };
2141
+ return {
2142
+ getSnapshot: () => t,
2143
+ set: (n) => {
2144
+ let r = !1;
2145
+ for (const a of Object.keys(n))
2146
+ if (n[a] !== t[a]) {
2147
+ r = !0;
2148
+ break;
2149
+ }
2150
+ r && (t = { ...t, ...n }, e());
2151
+ },
2152
+ setPipeline: (n) => {
2153
+ const r = new Map(t.pipeline);
2154
+ return n(r), t = { ...t, pipeline: r }, e(), r;
2155
+ },
2156
+ subscribe: (n) => (s.add(n), () => {
2157
+ s.delete(n);
2158
+ })
2159
+ };
2160
+ }, lt = (t, s) => s ?? t === "user", xn = ({
2161
+ renderHeight: t,
2162
+ renderWidth: s,
2163
+ videoHeight: e,
2164
+ videoWidth: n
2165
+ }) => ({
2166
+ height: t || e,
2167
+ width: s || n
2168
+ }), bn = (t, s) => {
2169
+ const e = new Hs({ verbose: !0 }), n = Cn();
2170
+ n.set({ cameraZoom: (t == null ? void 0 : t.cameraZoom) ?? 1.2 });
2171
+ let r = s, a = t;
2172
+ const o = (i) => {
2173
+ var p;
2174
+ const m = (p = z.getOptions(i)) == null ? void 0 : p.targetFps;
2175
+ return typeof m == "number" ? m : a == null ? void 0 : a.targetFps;
2176
+ };
2177
+ let c, l, h, f, u, w, S, k, x, T, _, g, v = !1, y = !1, C = !1, N = 0, E, V, q, L = !1, A = 0, W = /* @__PURE__ */ new WeakSet();
2178
+ const K = /* @__PURE__ */ new Set(), me = (i) => {
2179
+ const m = n.getSnapshot().cameraTexture;
2180
+ m && m.dispose();
2181
+ const p = wn(i);
2182
+ return n.set({ cameraTexture: p }), p;
2183
+ }, we = async (i, m) => {
2184
+ if (W.has(m) || n.getSnapshot().lifecycle !== "running" || !u) return;
2185
+ W.add(m);
2186
+ const p = A;
2187
+ try {
2188
+ await m.run({
2189
+ sourceCanvas: u,
2190
+ renderWidth: n.getSnapshot().renderWidth,
2191
+ renderHeight: n.getSnapshot().renderHeight,
2192
+ getSource: () => n.getSnapshot().sourceKind,
2193
+ targetFps: o(i),
2194
+ analysisScale: a == null ? void 0 : a.analysisScale
2195
+ }), L && (await new Promise((M) => requestAnimationFrame(() => M())), await new Promise((M) => requestAnimationFrame(() => M())), L && A === p && z.suspendAll());
2196
+ } catch (M) {
2197
+ throw W.delete(m), M;
2198
+ }
2199
+ }, z = Mn(n, ct, (i, m) => we(i, m));
2200
+ n.subscribe(() => {
2201
+ if (n.getSnapshot().lifecycle !== "running") return;
2202
+ const i = n.getSnapshot().pipeline;
2203
+ for (const [m, p] of i.entries())
2204
+ W.has(p) || we(m, p);
2205
+ });
2206
+ const Ne = () => {
2207
+ g !== void 0 && (cancelAnimationFrame(g), g = void 0);
2208
+ }, ee = () => {
2209
+ if (Ne(), E == null || E(), E = void 0, l) {
2210
+ try {
2211
+ l.pause();
2212
+ } catch {
2213
+ }
2214
+ try {
2215
+ l.srcObject = null;
2216
+ } catch {
2217
+ }
2218
+ l = void 0;
2219
+ }
2220
+ if (h) {
2221
+ try {
2222
+ h.getTracks().forEach((i) => i.stop());
2223
+ } catch {
2224
+ }
2225
+ h = void 0;
2226
+ }
2227
+ }, ve = () => {
2228
+ if (v || !l || !f || !u) return;
2229
+ const i = typeof window < "u" ? window.__xr_debugger_metrics : void 0;
2230
+ if (i != null && i.trackCameraFrame && i.trackCameraFrame(), He(n.getSnapshot().sourceKind))
2231
+ vn(l, f);
2232
+ else {
2233
+ const b = f.getContext("2d");
2234
+ if (!b) return;
2235
+ const P = l.videoWidth, D = l.videoHeight;
2236
+ f.width !== P && (f.width = P), f.height !== D && (f.height = D), b.setTransform(1, 0, 0, 1, 0, 0), b.clearRect(0, 0, P, D), b.drawImage(l, 0, 0, P, D);
2237
+ }
2238
+ Sn(f, u, (a == null ? void 0 : a.cameraZoom) ?? 1.2);
2239
+ const p = n.getSnapshot();
2240
+ (p.sourceWidth !== l.videoWidth || p.sourceHeight !== l.videoHeight) && n.set({ sourceWidth: l.videoWidth, sourceHeight: l.videoHeight }), N += 1, N % 10 === 0 && n.set({ feedFrames: N });
2241
+ const M = n.getSnapshot().cameraTexture;
2242
+ M && (M.needsUpdate = !0);
2243
+ }, Se = () => {
2244
+ if (!l || !f || !u) return;
2245
+ if (L) {
2246
+ ve();
2247
+ return;
2248
+ }
2249
+ const i = () => {
2250
+ g = requestAnimationFrame(i), ve();
2251
+ };
2252
+ g = requestAnimationFrame(i);
2253
+ }, Rt = async (i, m) => {
2254
+ if (i.source === F.WEBCAM)
2255
+ try {
2256
+ const p = a != null && a.camRes && a.camRes > 0 ? a.camRes : 960;
2257
+ n.set({ cameraPermission: "requesting", cameraPermissionReason: null });
2258
+ const M = i.deviceId ? { deviceId: { exact: i.deviceId } } : { facingMode: { ideal: i.facingMode ?? "user" } }, b = {
2259
+ frameRate: { min: 24, ideal: 30, max: 60 },
2260
+ width: { ideal: p },
2261
+ ...M
2262
+ };
2263
+ let P;
2264
+ try {
2265
+ P = await navigator.mediaDevices.getUserMedia({ video: b });
2266
+ } catch (D) {
2267
+ if (!(D instanceof DOMException && D.name === "OverconstrainedError")) throw D;
2268
+ P = await navigator.mediaDevices.getUserMedia({
2269
+ video: { frameRate: { ideal: 30 }, width: { ideal: p }, ...M }
2270
+ });
2271
+ }
2272
+ return m === A && n.set({ cameraPermission: "granted", cameraPermissionReason: null }), P;
2273
+ } catch (p) {
2274
+ const M = vt(p), b = rt[M], P = await St(), D = Mt(M, P.state);
2275
+ throw m === A && n.set({
2276
+ error: { error: "PermissionError", message: b, reason: M },
2277
+ cameraPermission: D.state,
2278
+ cameraPermissionReason: D.reason
2279
+ }), new O(p instanceof Error ? p.message : "getUserMedia failed");
2280
+ }
2281
+ return i.stream;
2282
+ }, Be = (i) => {
2283
+ const { lifecycle: m } = n.getSnapshot();
2284
+ m === "idle" || m === "stopped" || v || (ee(), z.suspendAll(), A += 1, c = void 0, n.set({
2285
+ lifecycle: "stopped",
2286
+ ready: !1,
2287
+ error: { error: "PermissionError", message: rt[i], reason: i },
2288
+ cameraPermission: i === "permission-denied" ? "blocked" : "unavailable",
2289
+ cameraPermissionReason: wt(i)
2290
+ }), e.log("XR session stopped: camera lost.", i));
2291
+ }, Ft = (i) => {
2292
+ var M;
2293
+ E == null || E();
2294
+ const m = ((M = i.getVideoTracks) == null ? void 0 : M.call(i)) ?? [], p = () => {
2295
+ h === i && Be("camera-lost");
2296
+ };
2297
+ m.forEach((b) => {
2298
+ var P;
2299
+ return (P = b.addEventListener) == null ? void 0 : P.call(b, "ended", p);
2300
+ }), E = () => {
2301
+ m.forEach((b) => {
2302
+ var P;
2303
+ return (P = b.removeEventListener) == null ? void 0 : P.call(b, "ended", p);
2304
+ });
2305
+ };
2306
+ }, It = async () => {
2307
+ if (V || typeof navigator > "u") return;
2308
+ const i = navigator.permissions;
2309
+ if (i != null && i.query)
2310
+ try {
2311
+ const m = await i.query({ name: "camera" });
2312
+ if (y) return;
2313
+ V = m, q = () => {
2314
+ m.state === "denied" && (c == null ? void 0 : c.source) === F.WEBCAM && Be("permission-denied");
2315
+ }, m.addEventListener("change", q);
2316
+ } catch {
2317
+ }
2318
+ }, _t = () => {
2319
+ var i;
2320
+ V && q && ((i = V.removeEventListener) == null || i.call(V, "change", q)), V = void 0, q = void 0;
2321
+ }, Me = async (i) => {
2322
+ var Ze, fe, $e;
2323
+ const m = A, p = await Rt(i, m);
2324
+ if (m !== A)
2325
+ throw p.getTracks().forEach((re) => re.stop()), new O("Media source superseded by a newer bind");
2326
+ h = p, Ft(p);
2327
+ const M = await yn(p);
2328
+ if (m !== A || y)
2329
+ throw p.getTracks().forEach((re) => re.stop()), new O("Media source superseded by a newer bind");
2330
+ l = M, f = new OffscreenCanvas(M.videoWidth, M.videoHeight);
2331
+ const { renderWidth: b, renderHeight: P } = n.getSnapshot(), D = xn({
2332
+ renderWidth: b,
2333
+ renderHeight: P,
2334
+ videoWidth: M.videoWidth,
2335
+ videoHeight: M.videoHeight
2336
+ });
2337
+ u ? (u.width !== D.width || u.height !== D.height) && (u.width = D.width, u.height = D.height, me(u)) : (u = new OffscreenCanvas(D.width, D.height), me(u));
2338
+ const je = i.source === F.STREAM ? i.static === !0 : !1;
2339
+ L = je;
2340
+ const ne = ($e = (fe = (Ze = p.getVideoTracks) == null ? void 0 : Ze.call(p)[0]) == null ? void 0 : fe.getSettings) == null ? void 0 : $e.call(fe), Te = ne == null ? void 0 : ne.facingMode, ss = Te === "user" || Te === "environment" ? Te : null;
2341
+ if (i.source === F.WEBCAM) {
2342
+ const re = ss ?? i.facingMode ?? "user", Je = lt(re, i.mirrored);
2343
+ c = {
2344
+ source: F.WEBCAM,
2345
+ sourceKind: Je ? "webcam" : "rear-camera",
2346
+ facingMode: re,
2347
+ deviceId: i.deviceId,
2348
+ mirrored: Je
2349
+ };
2350
+ } else
2351
+ c = {
2352
+ source: F.STREAM,
2353
+ stream: i.stream,
2354
+ static: je,
2355
+ sourceKind: i.sourceKind ?? "webcam"
2356
+ };
2357
+ n.set({
2358
+ source: i.source,
2359
+ sourceKind: c.sourceKind,
2360
+ cameraFacing: c.source === F.WEBCAM ? c.facingMode : null,
2361
+ cameraDeviceId: c.source === F.WEBCAM ? (ne == null ? void 0 : ne.deviceId) ?? c.deviceId ?? null : null,
2362
+ sourceWidth: M.videoWidth,
2363
+ sourceHeight: M.videoHeight,
2364
+ error: void 0
2365
+ }), i.source === F.WEBCAM && It();
2366
+ }, ke = async (i) => {
2367
+ const m = i.sourceKind ?? "webcam";
2368
+ u = i.canvas;
2369
+ const p = me(u);
2370
+ n.set({
2371
+ cameraTexture: p,
2372
+ source: F.CANVAS,
2373
+ sourceKind: m,
2374
+ cameraFacing: null,
2375
+ cameraDeviceId: null,
2376
+ renderWidth: u.width,
2377
+ renderHeight: u.height,
2378
+ error: void 0
2379
+ }), c = {
2380
+ source: F.CANVAS,
2381
+ canvas: i.canvas,
2382
+ sourceKind: m
2383
+ };
2384
+ }, Pt = (i, m) => {
2385
+ if (!m || i.source !== m.source) return !1;
2386
+ if (i.source === F.STREAM && m.source === F.STREAM)
2387
+ return i.stream === m.stream && (i.sourceKind ?? "webcam") === m.sourceKind;
2388
+ if (i.source === F.WEBCAM && m.source === F.WEBCAM) {
2389
+ const p = i.facingMode ?? "user";
2390
+ return p === m.facingMode && i.deviceId === m.deviceId && lt(p, i.mirrored) === m.mirrored;
2391
+ }
2392
+ return !1;
2393
+ }, ze = async () => {
2394
+ if (!u) return;
2395
+ const i = A, m = n.getSnapshot().pipeline;
2396
+ for (const [, p] of m.entries())
2397
+ p.resume();
2398
+ await new Promise((p) => requestAnimationFrame(() => p())), await new Promise((p) => requestAnimationFrame(() => p())), L && A === i && z.suspendAll();
2399
+ }, Lt = (i, m) => !m || m.source !== F.CANVAS ? !1 : i.canvas === m.canvas && (i.sourceKind ?? "webcam") === m.sourceKind, Ce = async (i) => {
2400
+ const m = i.source;
2401
+ if (m !== F.WEBCAM && m !== F.STREAM)
2402
+ throw new O(`Invalid media source: ${String(m)}`);
2403
+ if (y) throw new O("session.setMediaSource() called after the provider unmounted");
2404
+ if (Pt(i, c)) {
2405
+ e.log("Media source unchanged, skipping rebind.");
2406
+ return;
2407
+ }
2408
+ A += 1;
2409
+ const { lifecycle: p } = n.getSnapshot();
2410
+ if (p === "idle" || p === "stopped") {
2411
+ await Me(i), n.set({ lifecycle: "media-bound" }), e.log("Media source set to:", i.source);
2412
+ return;
2413
+ }
2414
+ if (p === "media-bound") {
2415
+ ee(), await Me(i), e.log("Media source rebound to:", i.source);
2416
+ return;
2417
+ }
2418
+ const M = p === "paused";
2419
+ v = !0, await new Promise((b) => requestAnimationFrame(() => b())), ee();
2420
+ try {
2421
+ await Me(i);
2422
+ } finally {
2423
+ v = !1;
2424
+ }
2425
+ if (M) {
2426
+ l == null || l.pause(), e.log("Media source swapped (paused) to:", i.source);
2427
+ return;
2428
+ }
2429
+ Se(), L ? await ze() : z.resumeActive(), e.log("Media source swapped to:", i.source);
2430
+ }, Dt = async (i) => {
2431
+ if (y) throw new O("session.setFrameSource() called after the provider unmounted");
2432
+ if (Lt(i, c)) {
2433
+ e.log("Frame source unchanged, skipping rebind.");
2434
+ return;
2435
+ }
2436
+ A += 1;
2437
+ const { lifecycle: m } = n.getSnapshot();
2438
+ if (m === "idle" || m === "stopped") {
2439
+ await ke(i), n.set({ lifecycle: "media-bound" }), e.log("Frame source set to canvas.");
2440
+ return;
2441
+ }
2442
+ if (m === "media-bound") {
2443
+ ee(), await ke(i), e.log("Frame source rebound to canvas.");
2444
+ return;
2445
+ }
2446
+ v = !0, await new Promise((p) => requestAnimationFrame(() => p())), ee();
2447
+ try {
2448
+ await ke(i);
2449
+ } finally {
2450
+ v = !1;
2451
+ }
2452
+ e.log("Frame source swapped to canvas.");
2453
+ }, We = async () => {
2454
+ if (y) throw new O("session.start() called after the provider unmounted");
2455
+ const { lifecycle: i } = n.getSnapshot();
2456
+ if (i === "running") return;
2457
+ if (i === "paused") {
2458
+ await xe();
2459
+ return;
2460
+ }
2461
+ if (i === "idle")
2462
+ throw new O("session.start() called before setMediaSource — call setMediaSource first");
2463
+ if (!u)
2464
+ throw new O("session.start(): media source not bound");
2465
+ const m = (c == null ? void 0 : c.source) === F.CANVAS;
2466
+ if (!m && (!l || !f))
2467
+ throw i === "stopped" ? new O(
2468
+ "session.start() called from stopped state without a media source — call setMediaSource first"
2469
+ ) : new O("session.start(): media source not bound");
2470
+ m || Se(), z.resumeActive(), n.set({ lifecycle: "running" }), await new Promise((M) => requestAnimationFrame(() => M()));
2471
+ const p = n.getSnapshot().pipeline;
2472
+ for (const [M, b] of p.entries())
2473
+ await we(M, b);
2474
+ n.set({ ready: !0 }), e.log("XR session started.");
2475
+ }, Ve = () => {
2476
+ if (n.getSnapshot().lifecycle === "running") {
2477
+ Ne(), z.suspendAll();
2478
+ try {
2479
+ l == null || l.pause();
2480
+ } catch {
2481
+ }
2482
+ n.set({ lifecycle: "paused" }), e.log("XR session paused.");
2483
+ }
2484
+ }, xe = async () => {
2485
+ if (y) throw new O("session.resume() called after the provider unmounted");
2486
+ n.getSnapshot().lifecycle === "paused" && (C = !1, l && l.play().catch(() => {
2487
+ }), (c == null ? void 0 : c.source) !== F.CANVAS && Se(), n.set({ lifecycle: "running" }), L ? await ze() : z.resumeActive(), e.log("XR session resumed."));
2488
+ }, Ot = async (i = {}) => {
2489
+ await Ce({ source: F.WEBCAM, ...i });
2490
+ const { lifecycle: m } = n.getSnapshot();
2491
+ return (m === "media-bound" || m === "stopped") && await We(), n.getSnapshot().cameraFacing ?? i.facingMode ?? "user";
2492
+ }, qe = async () => {
2493
+ const { lifecycle: i } = n.getSnapshot();
2494
+ i === "stopped" || i === "idle" || (C = !1, ee(), z.suspendAll(), c = void 0, n.set({ lifecycle: "stopped", ready: !1 }), e.log("XR session stopped."));
2495
+ }, Ke = async () => {
2496
+ await qe(), z.releaseAll(), K.clear();
2497
+ const i = n.getSnapshot().cameraTexture;
2498
+ i && i.dispose(), W = /* @__PURE__ */ new WeakSet(), c = void 0, A += 1, u = void 0, f = void 0, S = void 0, L = !1, _t(), n.set({
2499
+ lifecycle: "idle",
2500
+ cameraTexture: void 0,
2501
+ source: void 0,
2502
+ sourceKind: void 0,
2503
+ cameraFacing: null,
2504
+ cameraDeviceId: null,
2505
+ error: void 0,
2506
+ modelErrors: /* @__PURE__ */ new Map(),
2507
+ cameraPermission: "unknown",
2508
+ cameraPermissionReason: null
2509
+ }), e.log("XR session reset.");
2510
+ }, Ht = async () => {
2511
+ y || (y = !0, se == null || se(), se = void 0, te == null || te(), te = void 0, await Ke(), e.log("XR session disposed."));
2512
+ }, Ut = () => {
2513
+ y && (y = !1, Qe(), Ye(), e.log("XR session re-armed."));
2514
+ }, Nt = () => y, Bt = async (i) => {
2515
+ const m = "legacy:registerXRPipeline", p = [];
2516
+ await Promise.all(
2517
+ i.map(async (M) => {
2518
+ const { model: b } = M;
2519
+ if (!ct[b])
2520
+ throw new O(`Invalid model: ${b}`);
2521
+ K.has(b) || p.push(b);
2522
+ const P = "options" in M ? M.options : void 0;
2523
+ await z.acquire(b, m, P);
2524
+ })
2525
+ ), p.length > 0 && (p.forEach((M) => K.add(M)), e.log("XR pipeline registered."));
2526
+ }, zt = (i) => {
2527
+ const m = z.get(i);
2528
+ if (!m)
2529
+ throw new O(`Model ${i} is not registered in the pipeline`);
2530
+ return m.getModelNode();
2531
+ }, Ge = async (i, m) => {
2532
+ i <= 0 || m <= 0 || (n.set({ renderWidth: i, renderHeight: m }), u && (u.width !== i || u.height !== m) && (u.width = i, u.height = m, me(u), L && ve()), e.log(`Source canvas set. Render size: ${i}x${m}`));
2533
+ }, Wt = async (i) => {
2534
+ var b;
2535
+ w = i;
2536
+ const m = (b = i.getBoundingClientRect) == null ? void 0 : b.call(i), p = m && m.width > 0 ? Math.round(m.width) : i.clientWidth, M = m && m.height > 0 ? Math.round(m.height) : i.clientHeight;
2537
+ await Ge(p, M);
2538
+ }, Vt = (i) => {
2539
+ S = i;
2540
+ }, be = () => w && k && x && T ? w : S, qt = (i) => {
2541
+ k = i.renderer, x = i.scene, T = i.camera, _ = i.renderFrame;
2542
+ }, Xe = () => {
2543
+ if (!k || !x || !T)
2544
+ throw new O(
2545
+ "XR frame render requested before the R3F state was bound — make sure <XRScene> is mounted"
2546
+ );
2547
+ _ ? _() : k.render(x, T);
2548
+ }, Kt = () => {
2549
+ const i = w;
2550
+ if (i && be() === i)
2551
+ return Xe(), i.toDataURL("image/png");
2552
+ const m = be();
2553
+ if (m) return m.toDataURL("image/png");
2554
+ throw new O(
2555
+ "session.captureFrame() called before an XRScene or XRMediaSurface capture target was bound"
2556
+ );
2557
+ }, Gt = (i = 30) => {
2558
+ const m = be();
2559
+ if (!(m != null && m.captureStream))
2560
+ throw new O(
2561
+ "session.captureStream() called before an XRScene or XRMediaSurface capture target was bound"
2562
+ );
2563
+ return m.captureStream(i);
2564
+ }, Xt = () => l, Yt = () => u ?? null, Qt = (i) => {
2565
+ if (a = i, n.set({ cameraZoom: (i == null ? void 0 : i.cameraZoom) ?? 1.2 }), n.getSnapshot().lifecycle !== "running" || !u) return;
2566
+ const m = n.getSnapshot().pipeline;
2567
+ for (const [p, M] of m.entries())
2568
+ M.run({
2569
+ sourceCanvas: u,
2570
+ renderWidth: n.getSnapshot().renderWidth,
2571
+ renderHeight: n.getSnapshot().renderHeight,
2572
+ getSource: () => n.getSnapshot().sourceKind,
2573
+ targetFps: o(p),
2574
+ analysisScale: a == null ? void 0 : a.analysisScale
2575
+ });
2576
+ }, jt = () => a, Zt = async () => {
2577
+ if (!c || c.source !== F.WEBCAM) return;
2578
+ const { facingMode: i, deviceId: m, mirrored: p } = c;
2579
+ c = void 0, await Ce({ source: F.WEBCAM, facingMode: i, deviceId: m, mirrored: p });
2580
+ }, $t = (i) => {
2581
+ n.set({ quality: i });
2582
+ }, Jt = (i) => {
2583
+ n.set({ qualityConfig: i });
2584
+ }, es = (i) => {
2585
+ r = i;
2586
+ }, ts = () => {
2587
+ var b;
2588
+ if (typeof window > "u") return { type: "portrait", angle: 0 };
2589
+ const i = (b = window.screen) == null ? void 0 : b.orientation, m = (i == null ? void 0 : i.angle) ?? 0, p = m === 90 || m === 180 || m === 270 ? m : 0;
2590
+ return { type: i != null && i.type ? i.type.startsWith("landscape") ? "landscape" : "portrait" : window.innerWidth > window.innerHeight ? "landscape" : "portrait", angle: p };
2591
+ }, oe = () => {
2592
+ const i = ts(), m = n.getSnapshot().orientation, p = m.type !== i.type || m.angle !== i.angle ? { orientation: i } : {};
2593
+ l && l.videoWidth > 0 && (p.sourceWidth = l.videoWidth, p.sourceHeight = l.videoHeight), Object.keys(p).length && n.set(p);
2594
+ };
2595
+ let te;
2596
+ const Ye = () => {
2597
+ var m, p, M;
2598
+ if (te || typeof window > "u") return;
2599
+ const i = (m = window.screen) == null ? void 0 : m.orientation;
2600
+ (p = i == null ? void 0 : i.addEventListener) == null || p.call(i, "change", oe), (M = window.addEventListener) == null || M.call(window, "resize", oe), te = () => {
2601
+ var b, P;
2602
+ (b = i == null ? void 0 : i.removeEventListener) == null || b.call(i, "change", oe), (P = window.removeEventListener) == null || P.call(window, "resize", oe);
2603
+ }, oe();
2604
+ };
2605
+ let se;
2606
+ const Qe = () => {
2607
+ if (se || typeof document > "u" || typeof document.addEventListener != "function") return;
2608
+ const i = () => {
2609
+ if (!y) {
2610
+ if (document.hidden) {
2611
+ r != null && r.pauseWhenHidden && n.getSnapshot().lifecycle === "running" && (Ve(), C = !0);
2612
+ return;
2613
+ }
2614
+ if (C && n.getSnapshot().lifecycle === "paused") {
2615
+ xe();
2616
+ return;
2617
+ }
2618
+ n.getSnapshot().lifecycle === "running" && (l != null && l.paused) && l.play().catch(() => {
2619
+ });
2620
+ }
2621
+ };
2622
+ document.addEventListener("visibilitychange", i), se = () => document.removeEventListener("visibilitychange", i);
2623
+ };
2624
+ return Qe(), Ye(), {
2625
+ store: n,
2626
+ registry: z,
2627
+ setMediaSource: Ce,
2628
+ start: We,
2629
+ stop: qe,
2630
+ reset: Ke,
2631
+ pause: Ve,
2632
+ resume: xe,
2633
+ switchCamera: Ot,
2634
+ dispose: Ht,
2635
+ rearm: Ut,
2636
+ isDisposed: Nt,
2637
+ setFrameSource: Dt,
2638
+ registerXRPipeline: Bt,
2639
+ getModelNode: zt,
2640
+ captureFrame: Kt,
2641
+ captureStream: Gt,
2642
+ getInputFrame: Yt,
2643
+ _setRenderTarget: Wt,
2644
+ _setCaptureTarget: Vt,
2645
+ _setRenderSize: Ge,
2646
+ _setR3FState: qt,
2647
+ _renderFrame: Xe,
2648
+ _getVideoElement: Xt,
2649
+ _setPerf: Qt,
2650
+ _setLifecycle: es,
2651
+ _rebindMedia: Zt,
2652
+ _setQuality: $t,
2653
+ _setQualityConfig: Jt,
2654
+ _getPerf: jt
2655
+ };
2656
+ }, Tn = (t, s) => {
2657
+ const e = ie(t), n = ie(s), r = he(
2658
+ () => bn(e.current, n.current),
2659
+ []
2660
+ ), a = JSON.stringify(s ?? {});
2661
+ ce(() => {
2662
+ r._setLifecycle(s);
2663
+ }, [r, a]), ce(() => (r.rearm(), () => void r.dispose()), [r]);
2664
+ const o = JSON.stringify(t ?? {});
2665
+ return ce(() => {
2666
+ r._setPerf(t);
2667
+ }, [r, o]), r;
2668
+ }, _e = /* @__PURE__ */ new Map(), En = () => ({
2669
+ register: (t, s) => {
2670
+ s ? _e.set(t, s) : _e.delete(t);
2671
+ },
2672
+ resolve: (t) => t ? _e.get(t) ?? null : null
2673
+ }), Ct = En(), xt = ut(null), An = ({ children: t }) => {
2674
+ const s = ie(/* @__PURE__ */ new Map()), e = tt((a, o) => {
2675
+ o ? s.current.set(a, o) : s.current.delete(a);
2676
+ }, []), n = tt(
2677
+ (a) => a ? s.current.get(a) ?? null : null,
2678
+ []
2679
+ ), r = he(() => ({ register: e, resolve: n }), [e, n]);
2680
+ return is(xt.Provider, { value: r }, t);
2681
+ }, bt = () => De(xt) ?? Ct, fr = () => bt().register, gr = () => bt().resolve;
2682
+ Ct.register;
2683
+ const Rn = {
2684
+ [R.FACE_TRACKER]: "face",
2685
+ [R.HAND_TRACKER]: "hand",
2686
+ [R.GESTURE_TRACKER]: "gesture",
2687
+ [R.BODY_TRACKER]: "body",
2688
+ [R.HOLISTIC_TRACKER]: "holistic",
2689
+ [R.BACKGROUND_SEGMENTATION]: "segmentation",
2690
+ [R.SEMANTIC_SEGMENTATION]: "semantic-seg"
2691
+ }, dt = Object.values(R), Fn = (t, s) => {
2692
+ var n;
2693
+ const e = (n = t.registry.getOptions(s)) == null ? void 0 : n.targetFps;
2694
+ return typeof e == "number" ? e : null;
2695
+ }, Le = (t, s, e, n = performance.now()) => {
2696
+ const r = t.store.getSnapshot(), a = e ? n - e.sampledAt : 0, o = e && a > 0 ? Math.max(0, (r.feedFrames - e.feedFrames) * 1e3 / a) : 0, c = r.lifecycle === "running", l = s.map((f) => {
2697
+ var T;
2698
+ const u = t.registry.getState(f), w = t.store.getSnapshot().pipeline.get(f), S = ((T = r.modelErrors.get(f)) == null ? void 0 : T.error) ?? null, k = (w == null ? void 0 : w.getDiagnostics()) ?? {
2699
+ inferenceMs: null,
2700
+ inferenceFps: 0,
2701
+ inferences: 0,
2702
+ skippedFrames: 0,
2703
+ detections: null,
2704
+ confidence: null,
2705
+ status: S ? "error" : "ready",
2706
+ error: S,
2707
+ paused: !1,
2708
+ disposed: !1
2709
+ };
2710
+ let x;
2711
+ return u === "error" || k.status === "error" ? x = "error" : u === "idle" ? x = "unavailable" : u === "initializing" ? x = "loading" : k.paused || !c ? x = "paused" : x = "ready", {
2712
+ ...k,
2713
+ error: k.error ?? S,
2714
+ model: f,
2715
+ label: Rn[f] ?? f,
2716
+ state: x,
2717
+ targetFps: Fn(t, f),
2718
+ owners: t.registry.getOwners(f)
2719
+ };
2720
+ }), h = r.quality;
2721
+ return {
2722
+ quality: h ? {
2723
+ tier: h.decision.tier.name,
2724
+ index: h.index,
2725
+ locked: h.locked,
2726
+ reason: h.decision.reason
2727
+ } : null,
2728
+ session: {
2729
+ lifecycle: r.lifecycle,
2730
+ ready: r.ready,
2731
+ error: r.error,
2732
+ source: r.source,
2733
+ sourceKind: r.sourceKind,
2734
+ sourceWidth: r.sourceWidth,
2735
+ sourceHeight: r.sourceHeight,
2736
+ renderWidth: r.renderWidth,
2737
+ renderHeight: r.renderHeight,
2738
+ feedFps: o,
2739
+ feedFrames: r.feedFrames
2740
+ },
2741
+ models: l,
2742
+ inferenceMsTotal: l.reduce(
2743
+ (f, u) => f + (u.state === "ready" ? u.inferenceMs ?? 0 : 0),
2744
+ 0
2745
+ ),
2746
+ sampledAt: n
2747
+ };
2748
+ }, pr = (t = {}) => {
2749
+ const { intervalMs: s = 250, enabled: e = !0 } = t, { session: n } = At(), r = (t.models ?? dt).join("|"), a = he(
2750
+ () => t.models && t.models.length ? t.models : dt,
2751
+ // modelsKey captures the list by value.
2752
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2753
+ [r]
2754
+ ), o = ie(null), [c, l] = os(
2755
+ () => Le(n, a, null)
2756
+ );
2757
+ return ce(() => {
2758
+ if (!e) return;
2759
+ const h = () => {
2760
+ const u = Le(n, a, o.current);
2761
+ o.current = { feedFrames: u.session.feedFrames, sampledAt: u.sampledAt }, l(u);
2762
+ };
2763
+ h();
2764
+ const f = window.setInterval(h, Math.max(50, s));
2765
+ return () => window.clearInterval(f);
2766
+ }, [n, a, s, e]), c;
2767
+ }, In = [
2768
+ { name: "high", targetFps: 30, renderScale: 1, analysisScale: 1, camRes: 960 },
2769
+ { name: "medium", targetFps: 24, renderScale: 0.8, analysisScale: 0.85, camRes: 720 },
2770
+ { name: "low", targetFps: 15, renderScale: 0.6, analysisScale: 0.7, camRes: 640 }
2771
+ ], Q = {
2772
+ maxFrameMs: 1e3 / 24,
2773
+ maxInferenceMs: 24,
2774
+ maxMemoryMb: null,
2775
+ sampleMs: 1e3,
2776
+ downgradeAfter: 2,
2777
+ upgradeAfter: 6,
2778
+ upgradeHeadroom: 0.75,
2779
+ cooldownMs: 4e3
2780
+ }, Tt = {
2781
+ frameMs: null,
2782
+ fps: null,
2783
+ inferenceMs: null,
2784
+ feedFps: null,
2785
+ memoryMb: null,
2786
+ deviceMemoryGb: null,
2787
+ hardwareConcurrency: null,
2788
+ thermal: "unknown"
2789
+ }, ue = (t, s, e) => Math.min(e, Math.max(s, t)), H = (t, s) => typeof t == "number" && Number.isFinite(t) ? t : s, _n = (t, s) => ({
2790
+ name: typeof t.name == "string" && t.name ? t.name : `tier-${s}`,
2791
+ ...H(t.targetFps, NaN) > 0 ? { targetFps: H(t.targetFps, 0) } : {},
2792
+ ...H(t.renderScale, NaN) > 0 ? { renderScale: ue(H(t.renderScale, 1), 0.25, 1) } : {},
2793
+ ...H(t.analysisScale, NaN) > 0 ? { analysisScale: ue(H(t.analysisScale, 1), 0.25, 1) } : {},
2794
+ ...H(t.camRes, NaN) > 0 ? { camRes: Math.round(H(t.camRes, 0)) } : {},
2795
+ ...t.rebindCamera ? { rebindCamera: !0 } : {}
2796
+ }), Pn = (t = {}) => ({
2797
+ maxFrameMs: Math.max(1, H(t.maxFrameMs, Q.maxFrameMs)),
2798
+ maxInferenceMs: Math.max(
2799
+ 0,
2800
+ H(t.maxInferenceMs, Q.maxInferenceMs)
2801
+ ),
2802
+ maxMemoryMb: t.maxMemoryMb === null || t.maxMemoryMb === void 0 ? null : Math.max(1, H(t.maxMemoryMb, 0)) || null,
2803
+ sampleMs: Math.max(100, H(t.sampleMs, Q.sampleMs)),
2804
+ downgradeAfter: Math.max(
2805
+ 1,
2806
+ Math.round(H(t.downgradeAfter, Q.downgradeAfter))
2807
+ ),
2808
+ upgradeAfter: Math.max(
2809
+ 1,
2810
+ Math.round(H(t.upgradeAfter, Q.upgradeAfter))
2811
+ ),
2812
+ upgradeHeadroom: ue(
2813
+ H(t.upgradeHeadroom, Q.upgradeHeadroom),
2814
+ 0.1,
2815
+ 1
2816
+ ),
2817
+ cooldownMs: Math.max(0, H(t.cooldownMs, Q.cooldownMs))
2818
+ }), Y = (t, s, e) => {
2819
+ if (typeof s == "number" && Number.isInteger(s) && s >= 0 && s < t.length)
2820
+ return s;
2821
+ if (typeof s == "string") {
2822
+ const n = t.findIndex((r) => r.name === s);
2823
+ if (n >= 0) return n;
2824
+ }
2825
+ return e;
2826
+ }, Ln = (t = {}) => {
2827
+ const s = t.tiers && t.tiers.length ? t.tiers.map((r, a) => _n(r, a)) : In, e = Y(s, t.maxTier, 0), n = Math.max(e, Y(s, t.minTier, s.length - 1));
2828
+ return {
2829
+ tiers: s,
2830
+ budget: Pn(t.budget),
2831
+ ...t.initialTier !== void 0 ? { initialTier: t.initialTier } : {},
2832
+ minTier: n,
2833
+ maxTier: e,
2834
+ adaptive: t.adaptive !== !1,
2835
+ historySize: Math.max(1, Math.round(H(t.historySize, 20)))
2836
+ };
2837
+ }, Dn = (t, s) => {
2838
+ const e = Y(t.tiers, t.maxTier, 0), n = Y(t.tiers, t.minTier, t.tiers.length - 1);
2839
+ if (t.initialTier !== void 0)
2840
+ return ue(Y(t.tiers, t.initialTier, e), e, n);
2841
+ const r = s.deviceMemoryGb !== null && s.deviceMemoryGb <= 4 || s.hardwareConcurrency !== null && s.hardwareConcurrency <= 4;
2842
+ return ue(r ? e + 1 : e, e, n);
2843
+ }, Et = (t, s = Tt, e = 0) => {
2844
+ const n = Dn(t, s), r = { index: n, tier: t.tiers[n], reason: "init", at: e };
2845
+ return {
2846
+ index: n,
2847
+ locked: !1,
2848
+ badStreak: 0,
2849
+ goodStreak: 0,
2850
+ lastChangeAt: e,
2851
+ decision: r,
2852
+ history: [r],
2853
+ signals: s
2854
+ };
2855
+ }, ye = (t, s, e, n, r, a = t.signals) => {
2856
+ const o = { index: e, tier: s.tiers[e], reason: n, at: r };
2857
+ return {
2858
+ ...t,
2859
+ index: e,
2860
+ badStreak: 0,
2861
+ goodStreak: 0,
2862
+ lastChangeAt: r,
2863
+ decision: o,
2864
+ history: [o, ...t.history].slice(0, s.historySize),
2865
+ signals: a
2866
+ };
2867
+ }, On = (t, s) => t.thermal === "critical" ? "thermal" : s.maxMemoryMb !== null && t.memoryMb !== null && t.memoryMb > s.maxMemoryMb ? "memory" : t.inferenceMs !== null && t.inferenceMs > s.maxInferenceMs ? "inference" : t.frameMs !== null && t.frameMs > s.maxFrameMs ? "frame-time" : null, Hn = (t, s, e, n) => {
2868
+ const { budget: r } = e, a = Y(e.tiers, e.maxTier, 0), o = Y(e.tiers, e.minTier, e.tiers.length - 1);
2869
+ if (t.locked || !e.adaptive) return { ...t, signals: s };
2870
+ const c = On(s, r), l = c === null && s.frameMs !== null && s.frameMs <= r.maxFrameMs * r.upgradeHeadroom && (s.inferenceMs === null || s.inferenceMs <= r.maxInferenceMs * r.upgradeHeadroom), h = c ? t.badStreak + 1 : 0, f = l ? t.goodStreak + 1 : 0, u = n - t.lastChangeAt >= r.cooldownMs;
2871
+ if (c && h >= r.downgradeAfter && u) {
2872
+ if (t.index < o)
2873
+ return ye(t, e, t.index + 1, c, n, s);
2874
+ const w = c === "frame-time" ? "suspected" : s.thermal;
2875
+ return { ...t, badStreak: h, goodStreak: f, signals: { ...s, thermal: w } };
2876
+ }
2877
+ return l && f >= r.upgradeAfter && u && t.index > a ? ye(t, e, t.index - 1, "recovered", n, s) : { ...t, badStreak: h, goodStreak: f, signals: s };
2878
+ }, yr = (t, s, e, n) => {
2879
+ const r = Y(s.tiers, e, t.index);
2880
+ return r === t.index ? t : ye(t, s, r, "manual", n);
2881
+ }, wr = (t, s, e, n) => e === t.locked ? t : { ...ye(t, s, t.index, e ? "locked" : "manual", n), locked: e }, Un = (t, s) => t.decision.tier === s ? null : t.decision.tier, vr = (t, s, e) => {
2882
+ const n = Et(t, s, e);
2883
+ return {
2884
+ ...n,
2885
+ decision: { ...n.decision, reason: "reset" },
2886
+ history: [{ ...n.decision, reason: "reset" }]
2887
+ };
2888
+ }, Nn = Object.values(R), Bn = () => {
2889
+ if (typeof navigator > "u") return { deviceMemoryGb: null, hardwareConcurrency: null };
2890
+ const t = navigator;
2891
+ return {
2892
+ deviceMemoryGb: typeof t.deviceMemory == "number" ? t.deviceMemory : null,
2893
+ hardwareConcurrency: typeof t.hardwareConcurrency == "number" ? t.hardwareConcurrency : null
2894
+ };
2895
+ }, zn = () => {
2896
+ const t = performance.memory;
2897
+ return t ? t.usedJSHeapSize / 1048576 : null;
2898
+ }, Wn = ({ config: t, thermal: s, onDecision: e }) => {
2899
+ const { session: n } = At(), r = JSON.stringify(t ?? {}), a = he(() => Ln(t), [r]), o = ie(s ?? "unknown");
2900
+ o.current = s ?? "unknown";
2901
+ const c = ie(e);
2902
+ return c.current = e, ce(() => {
2903
+ const l = Bn();
2904
+ let h = Et(
2905
+ a,
2906
+ { ...Tt, ...l },
2907
+ performance.now()
2908
+ );
2909
+ const f = n.store.getSnapshot().quality;
2910
+ f && f.index < a.tiers.length && (h = {
2911
+ ...f,
2912
+ decision: { ...f.decision, tier: a.tiers[f.index] }
2913
+ }), n._setQualityConfig(a), n._setQuality(h);
2914
+ let u = n._getPerf(), w = null;
2915
+ const S = async (y, C) => {
2916
+ const N = {
2917
+ ...u,
2918
+ ...y.targetFps !== void 0 ? { targetFps: y.targetFps } : {},
2919
+ ...y.analysisScale !== void 0 ? { analysisScale: y.analysisScale } : {},
2920
+ ...y.camRes !== void 0 && y.rebindCamera ? { camRes: y.camRes } : {}
2921
+ };
2922
+ n._setPerf(N), y.rebindCamera && y.camRes !== void 0 && y.camRes !== (C == null ? void 0 : C.camRes) && await n._rebindMedia().catch(() => {
2923
+ });
2924
+ };
2925
+ w = h.decision.tier, S(h.decision.tier, null);
2926
+ let k = 0, x = performance.now(), T = 0;
2927
+ const _ = () => {
2928
+ k += 1, T = requestAnimationFrame(_);
2929
+ };
2930
+ T = requestAnimationFrame(_);
2931
+ let g = null;
2932
+ const v = window.setInterval(() => {
2933
+ var W;
2934
+ if (typeof document < "u" && document.hidden) {
2935
+ k = 0, x = performance.now();
2936
+ return;
2937
+ }
2938
+ const y = performance.now(), C = y - x, N = Le(n, Nn, g, y);
2939
+ g = { feedFrames: N.session.feedFrames, sampledAt: y };
2940
+ const E = n.store.getSnapshot().lifecycle === "running", V = {
2941
+ frameMs: k > 0 && C > 0 && E ? C / k : null,
2942
+ fps: k > 0 && C > 0 ? k * 1e3 / C : null,
2943
+ inferenceMs: E ? N.inferenceMsTotal : null,
2944
+ feedFps: N.session.feedFps,
2945
+ memoryMb: zn(),
2946
+ ...l,
2947
+ thermal: o.current
2948
+ };
2949
+ k = 0, x = y;
2950
+ const q = n.store.getSnapshot().quality ?? h, L = Hn(q, V, a, y);
2951
+ h = L, n._setQuality(L);
2952
+ const A = Un(L, w);
2953
+ if (A) {
2954
+ const K = w;
2955
+ w = A, S(A, K), (W = c.current) == null || W.call(c, L);
2956
+ }
2957
+ }, a.budget.sampleMs);
2958
+ return () => {
2959
+ cancelAnimationFrame(T), window.clearInterval(v);
2960
+ const y = (w == null ? void 0 : w.rebindCamera) && w.camRes !== void 0;
2961
+ n._setPerf(u), y && (u == null ? void 0 : u.camRes) !== (w == null ? void 0 : w.camRes) && n._rebindMedia().catch(() => {
2962
+ }), u = void 0, n._setQualityConfig(null);
2963
+ };
2964
+ }, [n, a]), null;
2965
+ }, Ue = ut(void 0), At = () => {
2966
+ const t = De(Ue);
2967
+ if (!t)
2968
+ throw new O(
2969
+ "XR context can only be used inside XRProvider, did you forget to wrap your app in <XRProvider>?"
2970
+ );
2971
+ return t;
2972
+ }, Sr = () => De(Ue) ?? null, Mr = ({ children: t, perf: s, lifecycle: e, quality: n }) => {
2973
+ const r = Tn(s, e), a = he(() => ({ session: r }), [r]);
2974
+ return /* @__PURE__ */ as(Ue.Provider, { value: a, children: [
2975
+ n !== !1 && /* @__PURE__ */ et(Wn, { config: n || void 0 }),
2976
+ /* @__PURE__ */ et(An, { children: t })
2977
+ ] });
2978
+ };
2979
+ export {
2980
+ er as $,
2981
+ Zn as A,
2982
+ vt as B,
2983
+ Mt as C,
2984
+ gt as D,
2985
+ pr as E,
2986
+ ps as F,
2987
+ Rn as G,
2988
+ Rs as H,
2989
+ Tt as I,
2990
+ Et as J,
2991
+ On as K,
2992
+ wr as L,
2993
+ Bn as M,
2994
+ vr as N,
2995
+ Dn as O,
2996
+ Pn as P,
2997
+ _n as Q,
2998
+ yr as R,
2999
+ ot as S,
3000
+ Hn as T,
3001
+ Un as U,
3002
+ hn as V,
3003
+ hr as W,
3004
+ R as X,
3005
+ Oe as Y,
3006
+ St as Z,
3007
+ Jn as _,
3008
+ Ls as a,
3009
+ tr as a0,
3010
+ sr as a1,
3011
+ Ln as a2,
3012
+ Ws as a3,
3013
+ Mr as a4,
3014
+ Os as a5,
3015
+ rr as a6,
3016
+ ar as a7,
3017
+ ir as a8,
3018
+ or as a9,
3019
+ nr as aa,
3020
+ lr as ab,
3021
+ dr as ac,
3022
+ pt as ad,
3023
+ xs as ae,
3024
+ yt as af,
3025
+ Q as ag,
3026
+ In as ah,
3027
+ Wn as ai,
3028
+ fr as aj,
3029
+ ur as b,
3030
+ Ds as c,
3031
+ jn as d,
3032
+ un as e,
3033
+ mr as f,
3034
+ F as g,
3035
+ Sr as h,
3036
+ He as i,
3037
+ I as j,
3038
+ Fe as k,
3039
+ U as l,
3040
+ $n as m,
3041
+ le as n,
3042
+ Us as o,
3043
+ zs as p,
3044
+ gr as q,
3045
+ cr as r,
3046
+ wt as s,
3047
+ Qn as t,
3048
+ At as u,
3049
+ Pe as v,
3050
+ ys as w,
3051
+ ws as x,
3052
+ vs as y,
3053
+ Le as z
3054
+ };