@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
@@ -1,1462 +0,0 @@
1
- var De = Object.defineProperty;
2
- var _e = (a, s, e) => s in a ? De(a, s, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[s] = e;
3
- var h = (a, s, e) => _e(a, typeof s != "symbol" ? s + "" : s, e);
4
- import { jsx as ce } from "react/jsx-runtime";
5
- import { useRef as ue, useMemo as ee, useEffect as Oe, useContext as le, useCallback as he, createElement as Ue, createContext as ge } from "react";
6
- import { FilesetResolver as V, PoseLandmarker as ze, FaceLandmarker as Le, GestureRecognizer as Be, HandLandmarker as Ve, ImageSegmenter as Ke, DrawingUtils as Ne } from "@mediapipe/tasks-vision";
7
- import * as E from "three";
8
- import { RGBAFormat as me, LinearFilter as G, CanvasTexture as fe, SRGBColorSpace as He } from "three";
9
- var T = /* @__PURE__ */ ((a) => (a.WEBCAM = "webcam", a.STREAM = "stream", a.CANVAS = "canvas", a))(T || {}), U = /* @__PURE__ */ ((a) => (a.HAND_TRACKER = "vincentt.xr.hand-tracker", a.GESTURE_TRACKER = "vincentt.xr.gesture-tracker", a.FACE_TRACKER = "vincentt.xr.face-tracker", a.BODY_TRACKER = "vincentt.xr.body-tracker", a.BACKGROUND_SEGMENTATION = "vincentt.xr.background-segmentation", a))(U || {});
10
- class b extends Error {
11
- constructor(s) {
12
- super(s), this.name = "VincenttXRError";
13
- }
14
- }
15
- const qe = (a, s) => s, I = {
16
- apiBaseUrl: qe(void 0, "https://api.vincentt.studio"),
17
- // Pinned to the CDN, NOT build-env-driven: a stale VITE_ASSET_STORAGE_ENDPOINT
18
- // baked a now-deleted CloudFront domain into every published bundle, breaking
19
- // WASM/model loads at runtime. The host must never come from a mutable env value.
20
- assetStorageEndpoint: "https://cdn.vincentt.studio",
21
- // Versioned bucket for SDK-shipped reference assets (canonical face model, face textures, etc.).
22
- sdkAssetsBaseUrl: "https://cdn.vincentt.studio/assets/sdk/face/v1",
23
- loggerPrefix: "[vincentt-xr]:",
24
- sessionCheckInterval: 3e4
25
- };
26
- class Ge {
27
- constructor(s) {
28
- h(this, "options");
29
- const e = {
30
- verbose: !1,
31
- prefix: I.loggerPrefix
32
- };
33
- this.options = { ...e, ...s };
34
- }
35
- log(...s) {
36
- const { verbose: e, prefix: t } = this.options;
37
- e && console.info(t, ...s);
38
- }
39
- error(...s) {
40
- const { verbose: e, prefix: t } = this.options;
41
- e && console.error(t, ...s);
42
- }
43
- }
44
- const te = (a, s = { x: 0, y: 0, z: 0 }) => (s.x = a.x * 2 - 1, s.y = 1 - a.y * 2, s.z = -a.z, s), Vt = (a, s = { x: 0, y: 0, z: 0 }) => (s.x = (a.x + 1) / 2, s.y = (1 - a.y) / 2, s.z = -a.z, s), Q = new E.Vector3(), $ = new E.Vector3(), q = ({ x: a, y: s, z: e }, t, i) => {
45
- Q.set((a - 0.5) * 2, (0.5 - s) * 2, -e), Q.unproject(t), $.copy(Q).sub(t.position).normalize();
46
- const r = -t.position.z / $.z;
47
- return i.copy(t.position).addScaledVector($, r), i;
48
- }, Kt = (a, s) => q(a, s, new E.Vector3()), We = (a, s, e = 0.2) => e * s + (1 - e) * a;
49
- class se {
50
- constructor(s) {
51
- h(this, "canvas");
52
- this.maxDimension = s;
53
- }
54
- /**
55
- * Returns a downscaled copy of `source` capped to `maxDimension` on its
56
- * longest side (or `source` unchanged if it's already within the cap, or if a
57
- * 2D context can't be obtained). The returned canvas is reused across calls.
58
- */
59
- draw(s) {
60
- const e = s.width, t = s.height, i = Math.min(1, this.maxDimension / Math.max(e, t));
61
- if (i >= 1) return s;
62
- const r = Math.max(1, Math.round(e * i)), c = Math.max(1, Math.round(t * i));
63
- (!this.canvas || this.canvas.width !== r || this.canvas.height !== c) && (this.canvas = new OffscreenCanvas(r, c));
64
- const d = this.canvas.getContext("2d");
65
- return d ? (d.setTransform(1, 0, 0, 1, 0, 0), d.clearRect(0, 0, r, c), d.drawImage(s, 0, 0, r, c), this.canvas) : s;
66
- }
67
- dispose() {
68
- this.canvas = void 0;
69
- }
70
- }
71
- const Xe = {
72
- "/assets/xr/models/face_tracking.task": "sha384-tYQh+yJE8llY+zO4RviZmWaSKs5W9tsB0ix5rjQVpF5/CLTqmwtP7bYtkUi2w65P",
73
- "/assets/xr/models/hand_tracking.task": "sha384-uWvruVKd887ov8k43S+DBHCsi7UXXS+CKvvdM1PX00rjPzx/B0QrAPfJ1U9yKcze",
74
- "/assets/xr/models/gesture_tracking.task": "sha384-2zuseP9JKKWAYlWQGKA2N+ooabB8V/yIxu23Mv8mtY7SowcySB+xKiOmqBhVvlUC",
75
- "/assets/xr/models/body_tracking.task": "sha384-3Wk9dvRYo36b3Nc9xVjKamb4wCKt9FwiPjcHKfrvyJL/jXoGs+uRLnii6yjWLKul",
76
- "/assets/xr/models/segmentation.tflite": "sha384-A2bQ8+iZyQM3KIGVBUf0FyetqxuynyKpjsjCE8uzoJEnj1ghCu6ge2daiRffAiS5",
77
- "/assets/xr/3d-models/head-occluder-v2.glb": "sha384-+0G60Q6EBVE6hpITxGzQgofAeKexPltpsfPq5T5et9GGBjRhFP5HOdsKAhe73OaI",
78
- "/assets/sdk/face/v1/canonical_face_model.obj": "sha384-xP8YM/72TXKvbMptXB9a8JUlUf3MZQ8uLurExrsZc05v6/P5RrsaNGMUYS/BZx8A",
79
- "/opencv/facial_expression_recognition/resolve/main/facial_expression_recognition_mobilefacenet_2022july_int8.onnx": "sha384-g8mtFubiIc/yhqi591RsxD76AJLw2CfYgKhKbVkIiFlwBmIyG7ZAIVyGPXafrDGB"
80
- };
81
- async function je(a) {
82
- const s = await fetch(a);
83
- if (!s.ok)
84
- throw new Error(`fetchAndVerify: ${s.status} ${a}`);
85
- const e = await s.arrayBuffer(), t = Qe(a);
86
- if (!t) {
87
- if (Ye(a))
88
- throw new Error(`[xr-sdk integrity] no SRI hash for SDK asset ${a}`);
89
- return console.warn(`[xr-sdk integrity] no SRI hash for ${a} — passing through`), e;
90
- }
91
- const i = await $e(e);
92
- if (i !== t)
93
- throw new Error(
94
- `[xr-sdk integrity] SRI mismatch for ${a}: expected ${t}, got ${i}`
95
- );
96
- return e;
97
- }
98
- function Ye(a) {
99
- try {
100
- return new URL(a).origin === new URL(I.assetStorageEndpoint).origin;
101
- } catch {
102
- return !1;
103
- }
104
- }
105
- async function K(a) {
106
- const s = await je(a);
107
- return new Uint8Array(s);
108
- }
109
- function Qe(a) {
110
- try {
111
- const s = new URL(a);
112
- return Xe[s.pathname];
113
- } catch {
114
- return;
115
- }
116
- }
117
- async function $e(a) {
118
- const s = await crypto.subtle.digest("SHA-384", a), e = new Uint8Array(s);
119
- let t = "";
120
- for (let i = 0; i < e.byteLength; i++)
121
- t += String.fromCharCode(e[i]);
122
- return `sha384-${btoa(t)}`;
123
- }
124
- const Z = /* @__PURE__ */ new Map();
125
- function N(a) {
126
- const s = a.wasmBinaryPath;
127
- let e = Z.get(s);
128
- return e || (e = Ze(s).catch(() => {
129
- Z.delete(s);
130
- }), Z.set(s, e)), e;
131
- }
132
- async function Ze(a) {
133
- const s = await fetch(a, { credentials: "same-origin" });
134
- if (!s.ok || !s.body)
135
- throw new Error(`warmVisionWasm: ${s.status} ${a}`);
136
- const e = s.body.getReader();
137
- for (; ; ) {
138
- const { done: t } = await e.read();
139
- if (t) return;
140
- }
141
- }
142
- class H {
143
- constructor() {
144
- h(this, "disposed", !1);
145
- h(this, "paused", !1);
146
- h(this, "rafId", null);
147
- // Inference-rate throttle. `targetFrameIntervalMs` is 0 when uncapped
148
- // (detect every frame); a positive value skips detection until that many ms
149
- // have elapsed since the last inference. `run()` sets this from
150
- // `params.targetFps`; subclasses call `shouldRunInference()` in their RAF
151
- // loop to gate the expensive MediaPipe call.
152
- h(this, "targetFrameIntervalMs", 0);
153
- h(this, "lastInferenceMs", 0);
154
- }
155
- /** Set the per-frame inference cap. fps <= 0 (or undefined) → uncapped. */
156
- setTargetFps(s) {
157
- this.targetFrameIntervalMs = s && s > 0 ? 1e3 / s : 0;
158
- }
159
- /**
160
- * True if enough time has elapsed to run inference this frame (and records
161
- * the timestamp). Always true when uncapped. Call once per RAF tick, right
162
- * before the detect call; skip the detect (but keep rescheduling RAF) when
163
- * it returns false.
164
- */
165
- shouldRunInference() {
166
- if (this.targetFrameIntervalMs <= 0) return !0;
167
- const s = performance.now();
168
- return s - this.lastInferenceMs < this.targetFrameIntervalMs ? !1 : (this.lastInferenceMs = s, !0);
169
- }
170
- // load models
171
- async initialize(s) {
172
- }
173
- // setup for running + start running
174
- async run(s) {
175
- }
176
- // get model's data while processing
177
- getModelNode() {
178
- return {};
179
- }
180
- async getPerformanceData() {
181
- return {
182
- name: this.constructor.name,
183
- processingTime: null
184
- };
185
- }
186
- // Cancel the per-frame RAF loop without releasing MediaPipe resources or
187
- // dropping refs. Subclasses' process* methods check `paused` and return
188
- // without rescheduling. Idempotent.
189
- pause() {
190
- this.paused = !0, this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null);
191
- }
192
- // Resume a paused loop by running the process function once. Subclasses
193
- // override to kick their specific process* method. Idempotent — no-op if
194
- // not paused. Calling resume() before run() is a no-op.
195
- resume() {
196
- this.paused = !1;
197
- }
198
- // Release MediaPipe landmarkers, cancel rAF loops, drop refs.
199
- // Subclasses MUST override and call super.dispose() at the end.
200
- dispose() {
201
- this.disposed = !0, this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null);
202
- }
203
- }
204
- const Je = 768;
205
- class et extends H {
206
- constructor() {
207
- super();
208
- h(this, "landmarker", null);
209
- h(this, "processingTime", null);
210
- h(this, "coordinates");
211
- h(this, "sourceCanvas");
212
- h(this, "downscaler", new se(Je));
213
- }
214
- async getBodyData() {
215
- if (!this.landmarker || !this.sourceCanvas)
216
- return;
217
- const e = this.downscaler.draw(this.sourceCanvas), t = performance.now(), i = this.landmarker.detectForVideo(e, t), r = performance.now();
218
- this.processingTime = r - t;
219
- const c = i.landmarks, d = [];
220
- if (c)
221
- return c.forEach((m, u) => {
222
- d[u] || (d[u] = []), m.forEach((C) => {
223
- d[u].push(te(C));
224
- });
225
- }), {
226
- coordinatesList: d
227
- };
228
- }
229
- async processBodyTracking() {
230
- if (!(this.disposed || this.paused || !this.landmarker)) {
231
- if (this.shouldRunInference()) {
232
- const e = await this.getBodyData();
233
- e && (this.coordinates = e.coordinatesList);
234
- }
235
- this.disposed || this.paused || (this.rafId = requestAnimationFrame(this.processBodyTracking.bind(this)));
236
- }
237
- }
238
- resume() {
239
- this.paused && (super.resume(), this.processBodyTracking());
240
- }
241
- dispose() {
242
- if (super.dispose(), this.landmarker) {
243
- try {
244
- this.landmarker.close();
245
- } catch {
246
- }
247
- this.landmarker = null;
248
- }
249
- this.sourceCanvas = void 0, this.downscaler.dispose(), this.coordinates = void 0;
250
- }
251
- getLandmarks2D(e = 0) {
252
- if (this.coordinates)
253
- return this.coordinates[e];
254
- }
255
- async initialize(e) {
256
- const t = await V.forVisionTasks(
257
- new URL("/assets/xr/wasm", I.assetStorageEndpoint).toString()
258
- ), [i] = await Promise.all([
259
- K(
260
- new URL("/assets/xr/models/body_tracking.task", I.assetStorageEndpoint).toString()
261
- ),
262
- N(t)
263
- ]);
264
- this.landmarker = await ze.createFromOptions(t, {
265
- baseOptions: {
266
- modelAssetBuffer: i,
267
- delegate: "GPU"
268
- },
269
- runningMode: "VIDEO",
270
- numPoses: (e == null ? void 0 : e.numPoses) || 1
271
- });
272
- }
273
- async run({ sourceCanvas: e, targetFps: t }) {
274
- this.sourceCanvas = e, this.setTargetFps(t), this.rafId === null && await this.processBodyTracking();
275
- }
276
- getModelNode() {
277
- return {
278
- getLandmarks2D: this.getLandmarks2D.bind(this)
279
- };
280
- }
281
- async getPerformanceData() {
282
- return {
283
- name: this.constructor.name,
284
- processingTime: this.processingTime
285
- };
286
- }
287
- }
288
- const tt = 0.11, st = 4e-3, at = (a, s) => s.set(a.x, -a.y, a.z);
289
- class nt extends H {
290
- constructor() {
291
- super();
292
- h(this, "landmarker", null);
293
- h(this, "processingTime", null);
294
- h(this, "sourceCanvas");
295
- h(this, "analysisCanvas");
296
- h(this, "getSource");
297
- h(this, "detectionResults");
298
- h(this, "numFaces", 1);
299
- h(this, "cameras", []);
300
- // camera object to unproject each face's translation
301
- h(this, "faces", []);
302
- // Reused per-face work vectors. Allocated once per face index and mutated
303
- // in place each frame, so the published Face[] doesn't churn the GC at
304
- // 30+ fps. Per-face indexing means two faces don't alias each other's
305
- // transforms; consumers see "current value" each frame.
306
- h(this, "leftCheekScratch", []);
307
- h(this, "rightCheekScratch", []);
308
- // Reused per-frame landmark used to feed unprojectToZZeroInto with an
309
- // x-mirrored copy for non-webcam sources, without allocating a new
310
- // landmark array (~468 entries) each frame.
311
- h(this, "landmarkScratch", { x: 0, y: 0, z: 0, visibility: 0 });
312
- // Reused per-frame rotation scratch (matrix -> quaternion -> mirror -> euler),
313
- // allocated once to avoid per-frame churn at 30+ fps.
314
- h(this, "rotMatrixScratch", new E.Matrix4());
315
- h(this, "rotQuatScratch", new E.Quaternion());
316
- h(this, "rotEulerScratch", new E.Euler());
317
- }
318
- // For non-webcam sources MediaPipe landmarks read as mirrored; flip x in
319
- // place into the reused scratch so downstream unprojection sees the
320
- // corrected position. Webcam input is already correct, so it's returned
321
- // by reference.
322
- landmarkForSource(e, t) {
323
- return t ? (this.landmarkScratch.x = 1 - e.x, this.landmarkScratch.y = e.y, this.landmarkScratch.z = e.z, this.landmarkScratch.visibility = e.visibility, this.landmarkScratch) : e;
324
- }
325
- extractAndUpdateFaceData(e) {
326
- var i;
327
- if (!e.faceLandmarks.length) {
328
- this.faces = [];
329
- return;
330
- }
331
- const t = e.faceLandmarks.length;
332
- for (this.faces.length > t && (this.faces.length = t, this.leftCheekScratch.length = t, this.rightCheekScratch.length = t); this.faces.length < t; )
333
- this.faces.push({
334
- transform: {
335
- position: new E.Vector3(),
336
- rotation: new E.Vector3(),
337
- scale: new E.Vector3()
338
- },
339
- gestures: {}
340
- }), this.leftCheekScratch.push(new E.Vector3()), this.rightCheekScratch.push(new E.Vector3());
341
- for (let r = 0; r < t; r += 1) {
342
- if (!this.cameras[r])
343
- continue;
344
- const c = this.faces[r], d = (i = this.getSource) == null ? void 0 : i.call(this), m = !(d === "webcam" || !d), u = e.faceLandmarks[r], C = e.facialTransformationMatrixes[r];
345
- this.rotMatrixScratch.fromArray(C.data), this.rotQuatScratch.setFromRotationMatrix(this.rotMatrixScratch), this.rotQuatScratch.set(
346
- -this.rotQuatScratch.x,
347
- this.rotQuatScratch.y,
348
- this.rotQuatScratch.z,
349
- this.rotQuatScratch.w
350
- ), this.rotEulerScratch.setFromQuaternion(this.rotQuatScratch, "XYZ"), at(this.rotEulerScratch, c.transform.rotation), q(
351
- this.landmarkForSource(u[4], m),
352
- this.cameras[r],
353
- c.transform.position
354
- ), q(
355
- this.landmarkForSource(u[50], m),
356
- this.cameras[r],
357
- this.leftCheekScratch[r]
358
- ), q(
359
- this.landmarkForSource(u[280], m),
360
- this.cameras[r],
361
- this.rightCheekScratch[r]
362
- );
363
- const M = this.leftCheekScratch[r].distanceTo(this.rightCheekScratch[r]) * tt, F = Math.abs(E.MathUtils.radToDeg(this.rotEulerScratch.y)), l = M + F * st, f = c.transform.scale.x, v = We(
364
- isNaN(f) ? 0 : f,
365
- l
366
- );
367
- c.transform.scale.set(v, v, v);
368
- const p = c.gestures, k = e.faceBlendshapes[r].categories;
369
- for (const S of k)
370
- p[S.categoryName] = S.score;
371
- }
372
- }
373
- async processFaceTracking() {
374
- if (this.disposed || this.paused || !this.landmarker || !this.sourceCanvas)
375
- return null;
376
- if (!this.shouldRunInference()) {
377
- this.rafId = requestAnimationFrame(this.processFaceTracking.bind(this));
378
- return;
379
- }
380
- const e = it(this.numFaces), t = this.sourceCanvas.width, i = this.sourceCanvas.height, r = Math.min(1, e / Math.max(t, i)), c = Math.max(1, Math.round(t * r)), d = Math.max(1, Math.round(i * r));
381
- (!this.analysisCanvas || this.analysisCanvas.width !== c || this.analysisCanvas.height !== d) && (this.analysisCanvas = new OffscreenCanvas(c, d));
382
- const m = this.analysisCanvas.getContext("2d");
383
- if (!m) {
384
- this.rafId = requestAnimationFrame(this.processFaceTracking.bind(this));
385
- return;
386
- }
387
- m.setTransform(1, 0, 0, 1, 0, 0), m.clearRect(0, 0, c, d), m.drawImage(this.sourceCanvas, 0, 0, c, d);
388
- const u = performance.now(), C = this.landmarker.detectForVideo(this.analysisCanvas, u), x = performance.now();
389
- this.processingTime = x - u, this.detectionResults = C, this.extractAndUpdateFaceData(C), !(this.disposed || this.paused) && (this.rafId = requestAnimationFrame(this.processFaceTracking.bind(this)));
390
- }
391
- resume() {
392
- this.paused && (super.resume(), this.processFaceTracking());
393
- }
394
- dispose() {
395
- if (super.dispose(), this.landmarker) {
396
- try {
397
- this.landmarker.close();
398
- } catch {
399
- }
400
- this.landmarker = null;
401
- }
402
- 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 = [];
403
- }
404
- getFace(e = 0) {
405
- return this.faces[e];
406
- }
407
- getDetectionResults() {
408
- return this.detectionResults;
409
- }
410
- getRawFaceTrackingData(e = 0) {
411
- var t, i, r, c;
412
- if (this.detectionResults)
413
- return {
414
- landmarks: (t = this.detectionResults.faceLandmarks) == null ? void 0 : t[e],
415
- blendshapes: (r = (i = this.detectionResults.faceBlendshapes) == null ? void 0 : i[e]) == null ? void 0 : r.categories,
416
- transformationMatrix: (c = this.detectionResults.facialTransformationMatrixes) == null ? void 0 : c[e]
417
- };
418
- }
419
- async initialize(e) {
420
- this.numFaces = (e == null ? void 0 : e.numFaces) || 1;
421
- const t = await V.forVisionTasks(
422
- new URL("/assets/xr/wasm", I.assetStorageEndpoint).toString()
423
- ), [i] = await Promise.all([
424
- K(
425
- new URL("/assets/xr/models/face_tracking.task", I.assetStorageEndpoint).toString()
426
- ),
427
- N(t)
428
- ]), r = await Le.createFromOptions(t, {
429
- baseOptions: {
430
- modelAssetBuffer: i,
431
- delegate: "GPU"
432
- },
433
- // Keep detection permissive for calibration workflows with dark webcam input.
434
- minFaceDetectionConfidence: 0.3,
435
- minFacePresenceConfidence: 0.3,
436
- minTrackingConfidence: 0.3,
437
- outputFaceBlendshapes: !0,
438
- outputFacialTransformationMatrixes: !0,
439
- runningMode: "VIDEO",
440
- numFaces: this.numFaces
441
- });
442
- if (this.disposed) {
443
- r.close();
444
- return;
445
- }
446
- this.landmarker = r;
447
- }
448
- async run({ sourceCanvas: e, getSource: t, targetFps: i }) {
449
- this.sourceCanvas = e, this.getSource = t, this.setTargetFps(i), this.analysisCanvas = void 0, this.rafId === null && this.processFaceTracking();
450
- }
451
- getModelNode() {
452
- const e = this;
453
- return {
454
- get detectionResults() {
455
- return e.detectionResults;
456
- },
457
- getDetectionResults: this.getDetectionResults.bind(this),
458
- getFace: this.getFace.bind(this),
459
- getRawFaceTrackingData: this.getRawFaceTrackingData.bind(this),
460
- setCamera: (i, r = 0) => {
461
- this.cameras[r] = i;
462
- }
463
- };
464
- }
465
- async getPerformanceData() {
466
- return {
467
- name: this.constructor.name,
468
- processingTime: this.processingTime
469
- };
470
- }
471
- }
472
- const it = (a) => a > 1 ? 1024 : 512;
473
- var P = /* @__PURE__ */ ((a) => (a.ClosedFist = "closed_fist", a.OpenPalm = "open_palm", a.PointingUp = "pointing_up", a.ThumbDown = "thumb_down", a.ThumbUp = "thumb_up", a.Victory = "victory", a.ILoveYou = "i_love_you", a.None = "none", a))(P || {});
474
- const rt = 512, ot = {
475
- Closed_Fist: P.ClosedFist,
476
- Open_Palm: P.OpenPalm,
477
- Pointing_Up: P.PointingUp,
478
- Thumb_Down: P.ThumbDown,
479
- Thumb_Up: P.ThumbUp,
480
- Victory: P.Victory,
481
- ILoveYou: P.ILoveYou,
482
- None: P.None
483
- }, ct = 15;
484
- class ht extends H {
485
- constructor() {
486
- super();
487
- h(this, "landmarker", null);
488
- h(this, "processingTime", null);
489
- h(this, "coordinates");
490
- h(this, "gesture");
491
- h(this, "sourceCanvas");
492
- h(this, "downscaler", new se(rt));
493
- }
494
- async getGestureData() {
495
- if (!this.landmarker || !this.sourceCanvas)
496
- return;
497
- const e = this.downscaler.draw(this.sourceCanvas), t = performance.now(), i = this.landmarker.recognizeForVideo(e, t), r = performance.now();
498
- this.processingTime = r - t;
499
- const c = i.landmarks[0], d = [];
500
- if (c) {
501
- const m = i.gestures[0][0].categoryName;
502
- return c.forEach((u) => {
503
- d.push(te(u));
504
- }), {
505
- coordinates: d,
506
- gesture: ot[m]
507
- };
508
- }
509
- return { coordinates: void 0, gesture: void 0 };
510
- }
511
- async processGestureTracking() {
512
- if (!this.disposed) {
513
- if (this.shouldRunInference()) {
514
- const e = await this.getGestureData();
515
- e && (this.coordinates = e.coordinates, this.gesture = e.gesture);
516
- }
517
- this.disposed || this.paused || (this.rafId = requestAnimationFrame(this.processGestureTracking.bind(this)));
518
- }
519
- }
520
- resume() {
521
- this.paused && (super.resume(), this.processGestureTracking());
522
- }
523
- dispose() {
524
- if (super.dispose(), this.landmarker) {
525
- try {
526
- this.landmarker.close();
527
- } catch {
528
- }
529
- this.landmarker = null;
530
- }
531
- this.sourceCanvas = void 0, this.downscaler.dispose(), this.coordinates = void 0, this.gesture = void 0;
532
- }
533
- async initialize() {
534
- const e = await V.forVisionTasks(
535
- new URL("/assets/xr/wasm", I.assetStorageEndpoint).toString()
536
- ), [t] = await Promise.all([
537
- K(
538
- new URL(
539
- "/assets/xr/models/gesture_tracking.task",
540
- I.assetStorageEndpoint
541
- ).toString()
542
- ),
543
- N(e)
544
- ]), i = await Be.createFromOptions(e, {
545
- baseOptions: {
546
- modelAssetBuffer: t,
547
- delegate: "GPU"
548
- },
549
- runningMode: "VIDEO",
550
- numHands: 1
551
- });
552
- this.landmarker = i;
553
- }
554
- async run({ sourceCanvas: e, targetFps: t }) {
555
- this.sourceCanvas = e, this.setTargetFps(t ?? ct), this.rafId === null && await this.processGestureTracking();
556
- }
557
- getModelNode() {
558
- const e = this;
559
- return {
560
- get coordinates() {
561
- return e.coordinates;
562
- },
563
- get gesture() {
564
- return e.gesture;
565
- }
566
- };
567
- }
568
- async getPerformanceData() {
569
- return {
570
- name: this.constructor.name,
571
- processingTime: this.processingTime
572
- };
573
- }
574
- }
575
- const dt = 512;
576
- class ut extends H {
577
- constructor() {
578
- super();
579
- h(this, "landmarker", null);
580
- h(this, "processingTime", null);
581
- h(this, "hands");
582
- h(this, "coordinates");
583
- h(this, "gesture");
584
- h(this, "handedness");
585
- h(this, "sourceCanvas");
586
- h(this, "downscaler", new se(dt));
587
- }
588
- async getHandData() {
589
- if (!this.landmarker || !this.sourceCanvas)
590
- return;
591
- const e = this.downscaler.draw(this.sourceCanvas), t = performance.now(), i = this.landmarker.detectForVideo(e, t), r = performance.now();
592
- this.processingTime = r - t;
593
- const c = [], d = i.handedness ?? i.handednesses ?? [];
594
- if (i.landmarks.forEach((u, C) => {
595
- var f, v, p;
596
- if (!u || u.length === 0)
597
- return;
598
- const x = u.map(
599
- (k) => te(k)
600
- ), M = (p = (v = (f = d[C]) == null ? void 0 : f[0]) == null ? void 0 : v.categoryName) == null ? void 0 : p.toLowerCase(), F = M === "left" || M === "right" ? M : void 0, l = u[0].z < 0 ? "closed_fist" : "open_palm";
601
- c.push({ coordinates: x, gesture: l, handedness: F });
602
- }), !c.length)
603
- return {
604
- hands: void 0,
605
- coordinates: void 0,
606
- gesture: void 0,
607
- handedness: void 0
608
- };
609
- const m = c[0];
610
- return {
611
- hands: c,
612
- coordinates: m.coordinates,
613
- gesture: m.gesture,
614
- handedness: m.handedness
615
- };
616
- }
617
- async processHandTracking() {
618
- if (!this.disposed) {
619
- if (this.shouldRunInference()) {
620
- const e = await this.getHandData();
621
- e && (this.hands = e.hands, this.coordinates = e.coordinates, this.gesture = e.gesture, this.handedness = e.handedness);
622
- }
623
- this.disposed || this.paused || (this.rafId = requestAnimationFrame(this.processHandTracking.bind(this)));
624
- }
625
- }
626
- resume() {
627
- this.paused && (super.resume(), this.processHandTracking());
628
- }
629
- dispose() {
630
- if (super.dispose(), this.landmarker) {
631
- try {
632
- this.landmarker.close();
633
- } catch {
634
- }
635
- this.landmarker = null;
636
- }
637
- this.sourceCanvas = void 0, this.hands = void 0, this.downscaler.dispose(), this.coordinates = void 0, this.gesture = void 0, this.handedness = void 0;
638
- }
639
- async initialize() {
640
- const e = await V.forVisionTasks(
641
- new URL("/assets/xr/wasm", I.assetStorageEndpoint).toString()
642
- ), [t] = await Promise.all([
643
- K(
644
- new URL("/assets/xr/models/hand_tracking.task", I.assetStorageEndpoint).toString()
645
- ),
646
- N(e)
647
- ]), i = await Ve.createFromOptions(e, {
648
- baseOptions: {
649
- modelAssetBuffer: t,
650
- delegate: "GPU"
651
- },
652
- runningMode: "VIDEO",
653
- numHands: 2
654
- });
655
- this.landmarker = i;
656
- }
657
- async run({ sourceCanvas: e, targetFps: t }) {
658
- this.sourceCanvas = e, this.setTargetFps(t), this.rafId === null && await this.processHandTracking();
659
- }
660
- getModelNode() {
661
- const e = this;
662
- return {
663
- get hands() {
664
- return e.hands;
665
- },
666
- get coordinates() {
667
- return e.coordinates;
668
- },
669
- get gesture() {
670
- return e.gesture;
671
- },
672
- get handedness() {
673
- return e.handedness;
674
- }
675
- };
676
- }
677
- async getPerformanceData() {
678
- return {
679
- name: this.constructor.name,
680
- processingTime: this.processingTime
681
- };
682
- }
683
- }
684
- const lt = 24, gt = 720, mt = [
685
- [255, 255, 255, 255],
686
- // 0: background → green 255, kept
687
- [0, 0, 0, 0]
688
- // 1: person → green 0, discarded
689
- ];
690
- class ft extends H {
691
- constructor() {
692
- super();
693
- h(this, "segmenter", null);
694
- h(this, "processingTime", null);
695
- h(this, "sourceCanvas");
696
- // input source canvas
697
- h(this, "processCanvas");
698
- // downscaled canvas of sourceCanvas for processing
699
- h(this, "filterCanvas");
700
- // post-processing (blur) canvas
701
- // Optional high-resolution input override. The shared session feed canvas is
702
- // sized to the on-screen display layout (often a small, display-fit crop),
703
- // which starves the segmenter of the resolution it needs to capture the whole
704
- // body. When a consumer supplies a native-resolution source here (e.g. the raw
705
- // <video>/<img>), the segmenter runs on THAT instead — letterboxed into the
706
- // process canvas so nothing is cropped. Falls back to `sourceCanvas` when unset.
707
- h(this, "inputSource");
708
- h(this, "inputSourceSize");
709
- // The segmenter's own WebGL2 context. DrawingUtils renders the inverted mask
710
- // into this context on the GPU; we then blit that GL canvas straight into the
711
- // mask canvas with a single `drawImage` — a GPU→GPU transfer, no CPU readback
712
- // and no per-pixel JS loop. (A spike proved `drawImage(glCanvas)` reads the
713
- // full DrawingUtils output correctly; the earlier "reads empty" wall that once
714
- // forced a readPixels path was a false alarm.)
715
- h(this, "glCanvas");
716
- h(this, "drawingUtils");
717
- h(this, "useGpuMaskPath", !1);
718
- // CPU-fallback reused ImageData, allocated on size change only. Used ONLY when
719
- // WebGL2 is unavailable and we must read the single-channel mask back by hand.
720
- h(this, "maskImageData");
721
- h(this, "maskCanvas", null);
722
- h(this, "segmentationMaskTexture");
723
- h(this, "isMaskSetup", !1);
724
- h(this, "isProcessing", !1);
725
- // Live clone of the most recent category mask, kept so getRawSegmentationData()
726
- // can read the single-channel Uint8Array lazily — that readback is paid ONLY
727
- // when a consumer actually asks for raw data. Cloned because the mask returned
728
- // by segmentForVideo is invalidated on the next inference call.
729
- h(this, "latestMask", null);
730
- // Per-frame cache of the read-back array, so repeated getRawSegmentationData()
731
- // calls within one frame don't re-run the GPU→CPU transfer.
732
- h(this, "rawCache", null);
733
- h(this, "quality", "medium");
734
- h(this, "stagingCanvas");
735
- }
736
- getQualityScaleFactor() {
737
- switch (this.quality) {
738
- case "low":
739
- return 0.5;
740
- case "medium":
741
- return 0.75;
742
- case "high":
743
- return 1;
744
- default:
745
- return 0.5;
746
- }
747
- }
748
- /**
749
- * Set (or clear) a high-resolution input override. Pass the raw <video>/<img>
750
- * (or any CanvasImageSource with intrinsic dimensions) to run segmentation on
751
- * native-resolution, uncropped frames instead of the small display-fit session
752
- * feed. Pass `undefined` to revert to the shared feed canvas.
753
- */
754
- setInputSource(e) {
755
- this.inputSource = e, this.inputSourceSize = e ? this.readIntrinsicSize(e) : void 0;
756
- }
757
- readIntrinsicSize(e) {
758
- if (e instanceof HTMLVideoElement)
759
- return e.videoWidth > 0 ? { width: e.videoWidth, height: e.videoHeight } : void 0;
760
- if (e instanceof HTMLImageElement)
761
- return e.naturalWidth > 0 ? { width: e.naturalWidth, height: e.naturalHeight } : void 0;
762
- const t = e.width, i = e.height;
763
- return typeof t == "number" && t > 0 && typeof i == "number" && i > 0 ? { width: t, height: i } : void 0;
764
- }
765
- /**
766
- * Size the process canvas to the override input's aspect ratio, bounded by
767
- * PROCESS_MAX_DIM on the long edge, and keep the GL canvas in sync so the GPU
768
- * mask renders at the same resolution. No-op when there is no override, or when
769
- * the intrinsic size hasn't changed since the last frame.
770
- */
771
- ensureProcessCanvasForInput() {
772
- if (!this.processCanvas || !this.inputSource) return;
773
- const e = this.readIntrinsicSize(this.inputSource);
774
- if (!e) return;
775
- this.inputSourceSize = e;
776
- const t = Math.min(1, gt / Math.max(e.width, e.height)), i = Math.max(1, Math.round(e.width * t)), r = Math.max(1, Math.round(e.height * t));
777
- this.processCanvas.width === i && this.processCanvas.height === r || (this.processCanvas.width = i, this.processCanvas.height = r, this.glCanvas && (this.glCanvas.width = i, this.glCanvas.height = r), this.maskImageData = void 0);
778
- }
779
- async processSegmentation() {
780
- if (this.disposed || !this.isProcessing || !this.maskCanvas || !this.processCanvas)
781
- return;
782
- if (!this.shouldRunInference()) {
783
- if (this.disposed || this.paused) return;
784
- this.rafId = requestAnimationFrame(this.processSegmentation.bind(this));
785
- return;
786
- }
787
- const e = this.inputSource ?? this.sourceCanvas;
788
- if (!this.segmenter || !e) {
789
- if (this.disposed || this.paused) return;
790
- this.rafId = requestAnimationFrame(this.processSegmentation.bind(this));
791
- return;
792
- }
793
- const t = performance.now();
794
- this.ensureProcessCanvasForInput();
795
- const i = this.processCanvas.getContext("2d");
796
- if (i) {
797
- const d = this.processCanvas.width, m = this.processCanvas.height;
798
- if (i.clearRect(0, 0, d, m), this.inputSource && this.inputSourceSize) {
799
- const { width: u, height: C } = this.inputSourceSize, x = Math.min(d / u, m / C), M = u * x, F = C * x;
800
- i.drawImage(this.inputSource, (d - M) / 2, (m - F) / 2, M, F);
801
- } else
802
- i.drawImage(e, 0, 0, d, m);
803
- }
804
- const c = this.segmenter.segmentForVideo(
805
- this.processCanvas,
806
- performance.now()
807
- ).categoryMask;
808
- if (!c) {
809
- if (this.disposed || this.paused) return;
810
- this.rafId = requestAnimationFrame(this.processSegmentation.bind(this));
811
- return;
812
- }
813
- if (this.rawCache = null, this.latestMask && (this.latestMask.close(), this.latestMask = null), this.useGpuMaskPath && this.drawingUtils && this.glCanvas)
814
- this.drawingUtils.drawCategoryMask(c, mt), this.latestMask = c.clone(), c.close(), this.blitGlToMask();
815
- else {
816
- this.latestMask = c.clone();
817
- const d = this.readMaskToImageData(c);
818
- c.close(), d && this.blitImageDataToMask(d);
819
- }
820
- this.segmentationMaskTexture && (this.isMaskSetup || (this.segmentationMaskTexture.format = me, this.segmentationMaskTexture.minFilter = G, this.segmentationMaskTexture.magFilter = G, this.segmentationMaskTexture.generateMipmaps = !1, this.isMaskSetup = !0), this.segmentationMaskTexture.needsUpdate = !0), this.processingTime = performance.now() - t, !(this.disposed || this.paused) && (this.rafId = requestAnimationFrame(this.processSegmentation.bind(this)));
821
- }
822
- /**
823
- * Blit the GPU-rendered mask (already RGBA-inverted by drawCategoryMask)
824
- * straight from the GL canvas into the mask canvas, cover-fitted through the
825
- * soft-edge blur. `drawImage(glCanvas)` is a GPU→GPU transfer — no readPixels,
826
- * no CPU array, no ImageData, no row flip (the 2D canvas presents the WebGL
827
- * canvas right-side-up). This is the zero-readback path.
828
- */
829
- blitGlToMask() {
830
- if (!this.maskCanvas || !this.filterCanvas || !this.glCanvas) return;
831
- const e = this.maskCanvas.getContext("2d"), t = this.filterCanvas.getContext("2d");
832
- !e || !t || (t.filter = "blur(0.5px)", t.clearRect(0, 0, this.filterCanvas.width, this.filterCanvas.height), t.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));
833
- }
834
- /**
835
- * CPU-fallback inverted-alpha ImageData build (only when the GPU path is off).
836
- * The single-channel mask is expanded to RGBA with the person→transparent,
837
- * background→opaque convention (green carries the signal for the alphaMap).
838
- */
839
- readMaskToImageData(e) {
840
- const t = e.getAsUint8Array(), { width: i, height: r } = e;
841
- if (!t || i <= 0 || r <= 0) return null;
842
- (!this.maskImageData || this.maskImageData.width !== i || this.maskImageData.height !== r) && (this.maskImageData = new ImageData(i, r));
843
- const c = this.maskImageData.data;
844
- for (let d = 0; d < t.length; d += 1) {
845
- const m = t[d] === 255 ? 0 : 255;
846
- c[d * 4] = 255, c[d * 4 + 1] = m, c[d * 4 + 2] = 255, c[d * 4 + 3] = m;
847
- }
848
- return this.maskImageData;
849
- }
850
- /**
851
- * CPU-fallback blit: put the inverted-alpha mask ImageData into maskCanvas
852
- * with a soft-edge blur, cover-fitted to the render target. Only used when the
853
- * GPU path is off; the GPU path blits the GL canvas directly (blitGlToMask).
854
- */
855
- blitImageDataToMask(e) {
856
- if (!this.maskCanvas || !this.filterCanvas) return;
857
- const t = this.maskCanvas.getContext("2d"), i = this.filterCanvas.getContext("2d");
858
- if (!t || !i) return;
859
- const r = this.getStagingCanvas(e.width, e.height), c = r.getContext("2d");
860
- c && (c.putImageData(e, 0, 0), i.filter = "blur(0.5px)", i.clearRect(0, 0, this.filterCanvas.width, this.filterCanvas.height), i.drawImage(r, 0, 0, this.filterCanvas.width, this.filterCanvas.height), t.clearRect(0, 0, this.maskCanvas.width, this.maskCanvas.height), t.drawImage(this.filterCanvas, 0, 0, this.maskCanvas.width, this.maskCanvas.height));
861
- }
862
- getStagingCanvas(e, t) {
863
- return this.stagingCanvas || (this.stagingCanvas = document.createElement("canvas")), this.stagingCanvas.width !== e && (this.stagingCanvas.width = e), this.stagingCanvas.height !== t && (this.stagingCanvas.height = t), this.stagingCanvas;
864
- }
865
- resume() {
866
- this.paused && (super.resume(), this.processSegmentation());
867
- }
868
- dispose() {
869
- if (super.dispose(), this.isProcessing = !1, this.latestMask) {
870
- try {
871
- this.latestMask.close();
872
- } catch {
873
- }
874
- this.latestMask = null;
875
- }
876
- if (this.rawCache = null, this.segmenter) {
877
- try {
878
- this.segmenter.close();
879
- } catch {
880
- }
881
- this.segmenter = null;
882
- }
883
- 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;
884
- }
885
- async initialize(e) {
886
- this.quality = (e == null ? void 0 : e.quality) ?? "low";
887
- const t = await V.forVisionTasks(
888
- new URL("/assets/xr/wasm", I.assetStorageEndpoint).toString()
889
- ), [i] = await Promise.all([
890
- K(
891
- new URL("/assets/xr/models/segmentation.tflite", I.assetStorageEndpoint).toString()
892
- ),
893
- N(t)
894
- ]);
895
- this.glCanvas = new OffscreenCanvas(1, 1);
896
- const r = this.glCanvas.getContext("webgl2", {
897
- preserveDrawingBuffer: !0
898
- });
899
- this.segmenter = await Ke.createFromOptions(t, {
900
- baseOptions: {
901
- modelAssetBuffer: i,
902
- delegate: "GPU"
903
- },
904
- ...r ? { canvas: this.glCanvas } : {},
905
- outputCategoryMask: !0,
906
- outputConfidenceMasks: !1,
907
- runningMode: "VIDEO"
908
- }), r ? (this.drawingUtils = new Ne(r), this.useGpuMaskPath = !0) : this.useGpuMaskPath = !1;
909
- }
910
- async run({
911
- sourceCanvas: e,
912
- renderWidth: t,
913
- renderHeight: i,
914
- targetFps: r
915
- }) {
916
- var d;
917
- if (!e)
918
- return;
919
- this.setTargetFps(r ?? lt), this.isProcessing = !1, this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null);
920
- const c = this.getQualityScaleFactor();
921
- this.sourceCanvas = e, this.processCanvas = document.createElement("canvas"), this.processCanvas.width = e.width * c, this.processCanvas.height = e.height * c, 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 = t, this.maskCanvas.height = i, this.filterCanvas = document.createElement("canvas"), this.filterCanvas.width = t, this.filterCanvas.height = i, (d = this.segmentationMaskTexture) == null || d.dispose(), this.segmentationMaskTexture = new fe(this.maskCanvas), this.isMaskSetup = !1, this.rawCache = null, this.isProcessing = !0, this.lastInferenceMs = 0, this.rafId = requestAnimationFrame(this.processSegmentation.bind(this));
922
- }
923
- /**
924
- * Lazily read the single-channel mask back to a Uint8Array. Only invoked when
925
- * a consumer calls getRawSegmentationData(); the default texture path never
926
- * touches it, so apps that only use <VideoBackground> pay no extra readback.
927
- */
928
- getRawSegmentationData() {
929
- if (this.rawCache) return this.rawCache;
930
- if (!this.latestMask) return null;
931
- const e = this.latestMask.getAsUint8Array();
932
- return this.rawCache = {
933
- maskData: e,
934
- width: this.latestMask.width,
935
- height: this.latestMask.height
936
- }, this.rawCache;
937
- }
938
- getModelNode() {
939
- const e = this;
940
- return {
941
- get backgroundSegmentationMask() {
942
- return e.segmentationMaskTexture;
943
- },
944
- getMaskCanvas: () => e.maskCanvas,
945
- getRawSegmentationData: () => e.getRawSegmentationData(),
946
- setInputSource: (t) => e.setInputSource(t ?? void 0)
947
- };
948
- }
949
- async getPerformanceData() {
950
- return {
951
- name: this.constructor.name,
952
- processingTime: this.processingTime
953
- };
954
- }
955
- }
956
- const de = {
957
- [U.BACKGROUND_SEGMENTATION]: ft,
958
- [U.HAND_TRACKER]: ut,
959
- [U.GESTURE_TRACKER]: ht,
960
- [U.FACE_TRACKER]: nt,
961
- [U.BODY_TRACKER]: et
962
- }, pt = async (a) => {
963
- const s = document.createElement("video");
964
- s.srcObject = a, s.muted = !0, s.playsInline = !0, s.autoplay = !0, await new Promise((t) => {
965
- s.onloadedmetadata = () => {
966
- s.play(), t();
967
- };
968
- });
969
- const e = s;
970
- return await new Promise((t) => {
971
- const i = setTimeout(t, 150), r = () => {
972
- clearTimeout(i), t();
973
- };
974
- typeof e.requestVideoFrameCallback == "function" ? e.requestVideoFrameCallback(r) : requestAnimationFrame(() => requestAnimationFrame(() => r()));
975
- }), s;
976
- }, wt = (a) => {
977
- const s = new fe(a);
978
- return s.colorSpace = He, s.format = me, s.minFilter = G, s.magFilter = G, s.generateMipmaps = !1, s.needsUpdate = !0, s;
979
- }, vt = (a, s) => {
980
- const e = a.videoWidth, t = a.videoHeight;
981
- e > 0 && t > 0 && (s.width !== e && (s.width = e), s.height !== t && (s.height = t));
982
- const i = s.getContext("2d", {
983
- colorSpace: "srgb"
984
- });
985
- i.save(), i.scale(-1, 1), i.drawImage(a, -s.width, 0, s.width, s.height), i.restore();
986
- }, St = (a, s, e = 1) => {
987
- const t = s.getContext("2d", {
988
- colorSpace: "srgb"
989
- }), i = s.width / s.height, r = a.width / a.height;
990
- let c, d;
991
- r > i ? (d = s.height, c = a.width * (s.height / a.height)) : (c = s.width, d = a.height * (s.width / a.width));
992
- const m = Number.isFinite(e) && e > 0 ? e : 1;
993
- c *= m, d *= m;
994
- const u = (s.width - c) / 2, C = (s.height - d) / 2;
995
- t.setTransform(1, 0, 0, 1, 0, 0), t.clearRect(0, 0, s.width, s.height), t.drawImage(
996
- a,
997
- 0,
998
- 0,
999
- a.width,
1000
- a.height,
1001
- u,
1002
- C,
1003
- c,
1004
- d
1005
- );
1006
- }, Ct = (a) => {
1007
- switch (a instanceof DOMException ? a.name : "") {
1008
- case "NotAllowedError":
1009
- case "PermissionDeniedError":
1010
- return "permission-denied";
1011
- case "NotReadableError":
1012
- case "TrackStartError":
1013
- return "camera-in-use";
1014
- case "NotFoundError":
1015
- case "DevicesNotFoundError":
1016
- return "no-camera";
1017
- case "NotSupportedError":
1018
- case "SecurityError":
1019
- return "unsupported";
1020
- default:
1021
- return a instanceof TypeError ? "unsupported" : "unknown";
1022
- }
1023
- }, kt = {
1024
- "permission-denied": "Camera access was blocked. Allow camera permissions in your browser, then refresh.",
1025
- "camera-in-use": "Camera is already in use by another app or browser tab. Close it and refresh.",
1026
- "no-camera": "No camera was found on this device.",
1027
- unsupported: "Unable to access camera. Allow camera permissions in your browser, then refresh.",
1028
- unknown: "Unable to access camera. Allow camera permissions in your browser, then refresh."
1029
- }, yt = (a, s, e) => {
1030
- const t = /* @__PURE__ */ new Map();
1031
- let i = !1;
1032
- const r = (l, f) => {
1033
- var v;
1034
- try {
1035
- (v = f.dispose) == null || v.call(f);
1036
- } catch (p) {
1037
- console.warn(`[xr-sdk registry] dispose threw for ${l}`, p);
1038
- }
1039
- };
1040
- return { acquire: async (l, f, v) => {
1041
- let p = t.get(l);
1042
- if (p)
1043
- return p.refs.add(f), p.activeRefs.add(f), p.initPromise;
1044
- const k = s[l];
1045
- if (!k)
1046
- throw new Error(`Invalid model: ${l}`);
1047
- const S = new k(), O = /* @__PURE__ */ new Set([f]), z = /* @__PURE__ */ new Set([f]), D = (async () => {
1048
- await S.initialize(v);
1049
- const _ = t.get(l);
1050
- if (!_ || _.model !== S || _.refs.size === 0)
1051
- return r(l, S), S;
1052
- e && await e(l, S);
1053
- const L = t.get(l);
1054
- return L && L.refs.size > 0 && a.setPipeline((A) => A.set(l, S)), S;
1055
- })();
1056
- return p = { model: S, refs: O, activeRefs: z, initPromise: D, options: v }, t.set(l, p), D.catch(() => {
1057
- t.get(l) === p && (t.delete(l), a.setPipeline((L) => L.delete(l))), r(l, S);
1058
- }), D;
1059
- }, release: (l, f) => {
1060
- const v = t.get(l);
1061
- v && (v.refs.delete(f), v.activeRefs.delete(f) && v.refs.size > 0 && v.activeRefs.size === 0 && v.model.pause(), !(v.refs.size > 0) && (t.delete(l), r(l, v.model), a.setPipeline((p) => p.delete(l))));
1062
- }, setActive: (l, f, v) => {
1063
- const p = t.get(l);
1064
- if (!p || !p.refs.has(f)) return;
1065
- const k = p.activeRefs.size > 0;
1066
- v ? p.activeRefs.add(f) : p.activeRefs.delete(f);
1067
- const S = p.activeRefs.size > 0;
1068
- k !== S && (S && !i ? p.model.resume() : p.model.pause());
1069
- }, suspendAll: () => {
1070
- i = !0;
1071
- for (const l of t.values())
1072
- l.model.pause();
1073
- }, resumeActive: () => {
1074
- i = !1;
1075
- for (const l of t.values())
1076
- l.activeRefs.size > 0 && l.model.resume();
1077
- }, get: (l) => {
1078
- var f;
1079
- return (f = t.get(l)) == null ? void 0 : f.model;
1080
- }, getOptions: (l) => {
1081
- var f;
1082
- return (f = t.get(l)) == null ? void 0 : f.options;
1083
- }, releaseAll: () => {
1084
- for (const l of Array.from(t.keys())) {
1085
- const f = t.get(l);
1086
- f && (f.refs.clear(), t.delete(l), r(l, f.model));
1087
- }
1088
- a.setPipeline((l) => l.clear());
1089
- } };
1090
- }, Mt = {
1091
- lifecycle: "idle",
1092
- ready: !1,
1093
- error: void 0,
1094
- cameraTexture: void 0,
1095
- renderWidth: 0,
1096
- renderHeight: 0,
1097
- source: void 0,
1098
- sourceKind: void 0,
1099
- pipeline: /* @__PURE__ */ new Map()
1100
- }, Tt = () => {
1101
- let a = { ...Mt, pipeline: /* @__PURE__ */ new Map() };
1102
- const s = /* @__PURE__ */ new Set(), e = () => {
1103
- s.forEach((t) => t());
1104
- };
1105
- return {
1106
- getSnapshot: () => a,
1107
- set: (t) => {
1108
- let i = !1;
1109
- for (const r of Object.keys(t))
1110
- if (t[r] !== a[r]) {
1111
- i = !0;
1112
- break;
1113
- }
1114
- i && (a = { ...a, ...t }, e());
1115
- },
1116
- setPipeline: (t) => {
1117
- const i = new Map(a.pipeline);
1118
- return t(i), a = { ...a, pipeline: i }, e(), i;
1119
- },
1120
- subscribe: (t) => (s.add(t), () => {
1121
- s.delete(t);
1122
- })
1123
- };
1124
- }, Rt = ({
1125
- renderHeight: a,
1126
- renderWidth: s,
1127
- videoHeight: e,
1128
- videoWidth: t
1129
- }) => ({
1130
- height: a || e,
1131
- width: s || t
1132
- }), xt = (a) => {
1133
- const s = new Ge({ verbose: !0 }), e = Tt();
1134
- let t = a;
1135
- const i = (n) => {
1136
- var g;
1137
- const o = (g = A.getOptions(n)) == null ? void 0 : g.targetFps;
1138
- return typeof o == "number" ? o : t == null ? void 0 : t.targetFps;
1139
- };
1140
- let r, c, d, m, u, C, x, M, F, l, f, v, p = !1, k = !1, S = 0;
1141
- const O = /* @__PURE__ */ new Set(), z = /* @__PURE__ */ new Set(), D = (n) => {
1142
- const o = e.getSnapshot().cameraTexture;
1143
- o && o.dispose();
1144
- const g = wt(n);
1145
- return e.set({ cameraTexture: g }), g;
1146
- }, _ = async (n, o) => {
1147
- if (O.has(n) || e.getSnapshot().lifecycle !== "running" || !u) return;
1148
- O.add(n);
1149
- const g = S;
1150
- try {
1151
- await o.run({
1152
- sourceCanvas: u,
1153
- renderWidth: e.getSnapshot().renderWidth,
1154
- renderHeight: e.getSnapshot().renderHeight,
1155
- getSource: () => e.getSnapshot().sourceKind,
1156
- targetFps: i(n)
1157
- }), k && (await new Promise((w) => requestAnimationFrame(() => w())), await new Promise((w) => requestAnimationFrame(() => w())), k && S === g && A.suspendAll());
1158
- } catch (w) {
1159
- throw O.delete(n), w;
1160
- }
1161
- }, A = yt(e, de, (n, o) => _(n, o));
1162
- e.subscribe(() => {
1163
- if (e.getSnapshot().lifecycle !== "running") return;
1164
- const n = e.getSnapshot().pipeline;
1165
- for (const [o, g] of n.entries())
1166
- O.has(o) || _(o, g);
1167
- });
1168
- const B = () => {
1169
- if (v !== void 0 && (cancelAnimationFrame(v), v = void 0), c) {
1170
- try {
1171
- c.pause();
1172
- } catch {
1173
- }
1174
- try {
1175
- c.srcObject = null;
1176
- } catch {
1177
- }
1178
- c = void 0;
1179
- }
1180
- if (d) {
1181
- try {
1182
- d.getTracks().forEach((n) => n.stop());
1183
- } catch {
1184
- }
1185
- d = void 0;
1186
- }
1187
- }, W = () => {
1188
- if (p || !c || !m || !u) return;
1189
- const n = window.__xr_debugger_metrics;
1190
- if (n != null && n.trackCameraFrame && n.trackCameraFrame(), (e.getSnapshot().sourceKind ?? "webcam") === "webcam")
1191
- vt(c, m);
1192
- else {
1193
- const w = m.getContext("2d");
1194
- if (!w) return;
1195
- const y = c.videoWidth, R = c.videoHeight;
1196
- m.width !== y && (m.width = y), m.height !== R && (m.height = R), w.setTransform(1, 0, 0, 1, 0, 0), w.clearRect(0, 0, y, R), w.drawImage(c, 0, 0, y, R);
1197
- }
1198
- St(m, u, (t == null ? void 0 : t.cameraZoom) ?? 1.2);
1199
- const g = e.getSnapshot().cameraTexture;
1200
- g && (g.needsUpdate = !0);
1201
- }, ae = () => {
1202
- if (!c || !m || !u) return;
1203
- if (k) {
1204
- W();
1205
- return;
1206
- }
1207
- const n = () => {
1208
- v = requestAnimationFrame(n), W();
1209
- };
1210
- v = requestAnimationFrame(n);
1211
- }, Ce = async (n) => {
1212
- if (n.source === T.WEBCAM)
1213
- try {
1214
- const o = t != null && t.camRes && t.camRes > 0 ? t.camRes : 960;
1215
- return await navigator.mediaDevices.getUserMedia({
1216
- video: {
1217
- facingMode: "user",
1218
- frameRate: { min: 24, ideal: 30, max: 60 },
1219
- width: { ideal: o }
1220
- }
1221
- });
1222
- } catch (o) {
1223
- const g = Ct(o), w = kt[g];
1224
- throw e.set({ error: { error: "PermissionError", message: w, reason: g } }), new b(o instanceof Error ? o.message : "getUserMedia failed");
1225
- }
1226
- return n.stream;
1227
- }, X = async (n) => {
1228
- const o = await Ce(n);
1229
- d = o;
1230
- const g = await pt(o);
1231
- c = g, m = new OffscreenCanvas(g.videoWidth, g.videoHeight);
1232
- const { renderWidth: w, renderHeight: y } = e.getSnapshot(), R = Rt({
1233
- renderWidth: w,
1234
- renderHeight: y,
1235
- videoWidth: g.videoWidth,
1236
- videoHeight: g.videoHeight
1237
- });
1238
- u ? (u.width !== R.width || u.height !== R.height) && (u.width = R.width, u.height = R.height, D(u)) : (u = new OffscreenCanvas(R.width, R.height), D(u));
1239
- const oe = n.source === T.STREAM ? n.static === !0 : !1;
1240
- k = oe, r = n.source === T.WEBCAM ? { source: T.WEBCAM, sourceKind: "webcam" } : {
1241
- source: T.STREAM,
1242
- stream: n.stream,
1243
- static: oe,
1244
- sourceKind: n.sourceKind ?? "webcam"
1245
- }, e.set({
1246
- source: n.source,
1247
- sourceKind: r.sourceKind,
1248
- error: void 0
1249
- });
1250
- }, j = async (n) => {
1251
- const o = n.sourceKind ?? "webcam";
1252
- u = n.canvas;
1253
- const g = D(u);
1254
- e.set({
1255
- cameraTexture: g,
1256
- source: T.CANVAS,
1257
- sourceKind: o,
1258
- renderWidth: u.width,
1259
- renderHeight: u.height,
1260
- error: void 0
1261
- }), r = {
1262
- source: T.CANVAS,
1263
- canvas: n.canvas,
1264
- sourceKind: o
1265
- };
1266
- }, ke = (n, o) => !o || n.source !== o.source ? !1 : n.source === T.STREAM && o.source === T.STREAM ? n.stream === o.stream && (n.sourceKind ?? "webcam") === o.sourceKind : !0, ye = async () => {
1267
- if (!u) return;
1268
- const n = S, o = e.getSnapshot().pipeline;
1269
- for (const [, g] of o.entries())
1270
- g.resume();
1271
- await new Promise((g) => requestAnimationFrame(() => g())), await new Promise((g) => requestAnimationFrame(() => g())), k && S === n && A.suspendAll();
1272
- }, Me = (n, o) => !o || o.source !== T.CANVAS ? !1 : n.canvas === o.canvas && (n.sourceKind ?? "webcam") === o.sourceKind, Te = async (n) => {
1273
- const o = n.source;
1274
- if (o !== T.WEBCAM && o !== T.STREAM)
1275
- throw new b(`Invalid media source: ${String(o)}`);
1276
- if (ke(n, r)) {
1277
- s.log("Media source unchanged, skipping rebind.");
1278
- return;
1279
- }
1280
- S += 1;
1281
- const { lifecycle: g } = e.getSnapshot();
1282
- if (g === "idle" || g === "stopped") {
1283
- await X(n), e.set({ lifecycle: "media-bound" }), s.log("Media source set to:", n.source);
1284
- return;
1285
- }
1286
- if (g === "media-bound") {
1287
- B(), await X(n), s.log("Media source rebound to:", n.source);
1288
- return;
1289
- }
1290
- p = !0, await new Promise((w) => requestAnimationFrame(() => w())), B(), await X(n), p = !1, ae(), k ? await ye() : A.resumeActive(), s.log("Media source swapped to:", n.source);
1291
- }, Re = async (n) => {
1292
- if (Me(n, r)) {
1293
- s.log("Frame source unchanged, skipping rebind.");
1294
- return;
1295
- }
1296
- S += 1;
1297
- const { lifecycle: o } = e.getSnapshot();
1298
- if (o === "idle" || o === "stopped") {
1299
- await j(n), e.set({ lifecycle: "media-bound" }), s.log("Frame source set to canvas.");
1300
- return;
1301
- }
1302
- if (o === "media-bound") {
1303
- B(), await j(n), s.log("Frame source rebound to canvas.");
1304
- return;
1305
- }
1306
- p = !0, await new Promise((g) => requestAnimationFrame(() => g())), B(), await j(n), p = !1, s.log("Frame source swapped to canvas.");
1307
- }, xe = async () => {
1308
- const { lifecycle: n } = e.getSnapshot();
1309
- if (n === "running") return;
1310
- if (n === "idle")
1311
- throw new b("session.start() called before setMediaSource — call setMediaSource first");
1312
- if (!u)
1313
- throw new b("session.start(): media source not bound");
1314
- const o = (r == null ? void 0 : r.source) === T.CANVAS;
1315
- if (!o && (!c || !m))
1316
- throw n === "stopped" ? new b(
1317
- "session.start() called from stopped state without a media source — call setMediaSource first"
1318
- ) : new b("session.start(): media source not bound");
1319
- o || ae(), A.resumeActive(), e.set({ lifecycle: "running" }), await new Promise((w) => requestAnimationFrame(() => w()));
1320
- const g = e.getSnapshot().pipeline;
1321
- for (const [w, y] of g.entries())
1322
- await _(w, y);
1323
- e.set({ ready: !0 }), s.log("XR session started.");
1324
- }, ne = async () => {
1325
- const { lifecycle: n } = e.getSnapshot();
1326
- n === "stopped" || n === "idle" || (B(), A.suspendAll(), e.set({ lifecycle: "stopped", ready: !1 }), s.log("XR session stopped."));
1327
- }, Fe = async () => {
1328
- await ne(), A.releaseAll(), z.clear();
1329
- const n = e.getSnapshot().cameraTexture;
1330
- n && n.dispose(), O.clear(), r = void 0, S += 1, u = void 0, m = void 0, x = void 0, k = !1, e.set({
1331
- lifecycle: "idle",
1332
- cameraTexture: void 0,
1333
- source: void 0
1334
- }), s.log("XR session reset.");
1335
- }, Ae = async (n) => {
1336
- const o = "legacy:registerXRPipeline", g = [];
1337
- await Promise.all(
1338
- n.map(async (w) => {
1339
- const { model: y } = w;
1340
- if (!de[y])
1341
- throw new b(`Invalid model: ${y}`);
1342
- z.has(y) || g.push(y);
1343
- const R = "options" in w ? w.options : void 0;
1344
- await A.acquire(y, o, R);
1345
- })
1346
- ), g.length > 0 && (g.forEach((w) => z.add(w)), s.log("XR pipeline registered."));
1347
- }, be = (n) => {
1348
- const o = A.get(n);
1349
- if (!o)
1350
- throw new b(`Model ${n} is not registered in the pipeline`);
1351
- return o.getModelNode();
1352
- }, ie = async (n, o) => {
1353
- n <= 0 || o <= 0 || (e.set({ renderWidth: n, renderHeight: o }), u && (u.width !== n || u.height !== o) && (u.width = n, u.height = o, D(u), k && W()), s.log(`Source canvas set. Render size: ${n}x${o}`));
1354
- }, Ee = async (n) => {
1355
- var y;
1356
- C = n;
1357
- const o = (y = n.getBoundingClientRect) == null ? void 0 : y.call(n), g = o && o.width > 0 ? Math.round(o.width) : n.clientWidth, w = o && o.height > 0 ? Math.round(o.height) : n.clientHeight;
1358
- await ie(g, w);
1359
- }, Ie = (n) => {
1360
- x = n;
1361
- }, Y = () => C && M && F && l ? C : x, Pe = (n) => {
1362
- M = n.renderer, F = n.scene, l = n.camera, f = n.renderFrame;
1363
- }, re = () => {
1364
- if (!M || !F || !l)
1365
- throw new b(
1366
- "XR frame render requested before the R3F state was bound — make sure <XRScene> is mounted"
1367
- );
1368
- f ? f() : M.render(F, l);
1369
- };
1370
- return {
1371
- store: e,
1372
- registry: A,
1373
- setMediaSource: Te,
1374
- start: xe,
1375
- stop: ne,
1376
- reset: Fe,
1377
- setFrameSource: Re,
1378
- registerXRPipeline: Ae,
1379
- getModelNode: be,
1380
- captureFrame: () => {
1381
- const n = C;
1382
- if (n && Y() === n)
1383
- return re(), n.toDataURL("image/png");
1384
- const o = Y();
1385
- if (o) return o.toDataURL("image/png");
1386
- throw new b(
1387
- "session.captureFrame() called before an XRScene or XRMediaSurface capture target was bound"
1388
- );
1389
- },
1390
- captureStream: (n = 30) => {
1391
- const o = Y();
1392
- if (!(o != null && o.captureStream))
1393
- throw new b(
1394
- "session.captureStream() called before an XRScene or XRMediaSurface capture target was bound"
1395
- );
1396
- return o.captureStream(n);
1397
- },
1398
- getInputFrame: () => u ?? null,
1399
- _setRenderTarget: Ee,
1400
- _setCaptureTarget: Ie,
1401
- _setRenderSize: ie,
1402
- _setR3FState: Pe,
1403
- _renderFrame: re,
1404
- _getVideoElement: () => c,
1405
- _setPerf: (n) => {
1406
- if (t = n, e.getSnapshot().lifecycle !== "running" || !u) return;
1407
- const o = e.getSnapshot().pipeline;
1408
- for (const [g, w] of o.entries())
1409
- w.run({
1410
- sourceCanvas: u,
1411
- renderWidth: e.getSnapshot().renderWidth,
1412
- renderHeight: e.getSnapshot().renderHeight,
1413
- getSource: () => e.getSnapshot().sourceKind,
1414
- targetFps: i(g)
1415
- });
1416
- }
1417
- };
1418
- }, Ft = (a) => {
1419
- const s = ue(a), e = ee(() => xt(s.current), []), t = JSON.stringify(a ?? {});
1420
- return Oe(() => {
1421
- e._setPerf(a);
1422
- }, [e, t]), e;
1423
- }, J = /* @__PURE__ */ new Map(), At = () => ({
1424
- register: (a, s) => {
1425
- s ? J.set(a, s) : J.delete(a);
1426
- },
1427
- resolve: (a) => a ? J.get(a) ?? null : null
1428
- }), pe = At(), we = ge(null), bt = ({ children: a }) => {
1429
- const s = ue(/* @__PURE__ */ new Map()), e = he((r, c) => {
1430
- c ? s.current.set(r, c) : s.current.delete(r);
1431
- }, []), t = he(
1432
- (r) => r ? s.current.get(r) ?? null : null,
1433
- []
1434
- ), i = ee(() => ({ register: e, resolve: t }), [e, t]);
1435
- return Ue(we.Provider, { value: i }, a);
1436
- }, ve = () => le(we) ?? pe, Nt = () => ve().register, Ht = () => ve().resolve;
1437
- pe.register;
1438
- const Se = ge(void 0), qt = () => {
1439
- const a = le(Se);
1440
- if (!a)
1441
- throw new b(
1442
- "XR context can only be used inside XRProvider, did you forget to wrap your app in <XRProvider>?"
1443
- );
1444
- return a;
1445
- }, Gt = ({ children: a, perf: s }) => {
1446
- const e = Ft(s), t = ee(() => ({ session: e }), [e]);
1447
- return /* @__PURE__ */ ce(Se.Provider, { value: t, children: /* @__PURE__ */ ce(bt, { children: a }) });
1448
- };
1449
- export {
1450
- U as X,
1451
- q as a,
1452
- Kt as b,
1453
- T as c,
1454
- Gt as d,
1455
- Ht as e,
1456
- je as f,
1457
- Nt as g,
1458
- I as l,
1459
- te as n,
1460
- Vt as t,
1461
- qt as u
1462
- };