@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.
- package/GROUNDING.md +1109 -13
- package/dist/{DebuggerUI-BjOMr8q_.js → DebuggerUI-C-ldiozL.js} +1 -1
- package/dist/{DebuggerUI-B6bP6P9r.cjs → DebuggerUI-CWX5EtQv.cjs} +1 -1
- package/dist/FaceMeshRenderer-BEEXZwS6.cjs +158 -0
- package/dist/FaceMeshRenderer-UuH5sTXG.js +1322 -0
- package/dist/FaceRetouch-C7h7x9kd.js +683 -0
- package/dist/FaceRetouch-DqftT26Y.cjs +134 -0
- package/dist/GLTFLoader-C5q63sKO.js +1633 -0
- package/dist/GLTFLoader-Cb_CRwmG.cjs +1 -0
- package/dist/SegmentationOverlay-DQuW3dsc.js +133 -0
- package/dist/SegmentationOverlay-aWVod8Kl.cjs +1 -0
- package/dist/assets/cache.d.ts +99 -0
- package/dist/assets/estimate.d.ts +11 -0
- package/dist/assets/index.d.ts +7 -0
- package/dist/assets/loaders.d.ts +28 -0
- package/dist/assets/react.d.ts +33 -0
- package/dist/calibration/calibration.d.ts +70 -0
- package/dist/calibration/index.d.ts +6 -0
- package/dist/calibration/storage.d.ts +13 -0
- package/dist/calibration/types.d.ts +53 -0
- package/dist/calibration/useXRCalibration.d.ts +46 -0
- package/dist/camera/CameraPermissionGate.d.ts +26 -0
- package/dist/camera/devices.d.ts +26 -0
- package/dist/camera/index.d.ts +8 -0
- package/dist/camera/permission.d.ts +86 -0
- package/dist/camera/useCameraPermission.d.ts +35 -0
- package/dist/capabilities/detect.d.ts +45 -0
- package/dist/capabilities/index.d.ts +5 -0
- package/dist/capabilities/types.d.ts +120 -0
- package/dist/capabilities/useXRCapabilities.d.ts +18 -0
- package/dist/compat/environment.d.ts +5 -0
- package/dist/compat/index.d.ts +4 -0
- package/dist/compat/run.d.ts +18 -0
- package/dist/compat/scenarios.d.ts +10 -0
- package/dist/compat/types.d.ts +101 -0
- package/dist/components/BodyTracker/index.d.ts +9 -0
- package/dist/components/FaceMesh/canonical/CanonicalFaceMeshRenderer.d.ts +33 -3
- package/dist/components/FaceMesh/canonical/parseCanonicalFaceModel.d.ts +12 -0
- package/dist/components/FaceMesh/canonical/shaders.d.ts +1 -1
- package/dist/components/FaceMesh/index.d.ts +1 -1
- package/dist/components/GestureListener/index.d.ts +11 -0
- package/dist/components/HandTracker/index.d.ts +10 -0
- package/dist/components/HolisticTracker/index.d.ts +69 -0
- package/dist/components/HolisticTracker/settings.d.ts +58 -0
- package/dist/components/HolisticTracker/signals.d.ts +49 -0
- package/dist/components/IrisEffect/IrisMaterial.d.ts +73 -0
- package/dist/components/IrisEffect/index.d.ts +51 -0
- package/dist/components/IrisEffect/settings.d.ts +117 -0
- package/dist/components/LipEffect/LipEffect.d.ts +7 -1
- package/dist/components/LipEffect/LipEffectMaterial.d.ts +43 -7
- package/dist/components/LipEffect/LipEffects.d.ts +9 -0
- package/dist/components/LipEffect/defaults.d.ts +27 -4
- package/dist/components/LipEffect/index.d.ts +11 -3
- package/dist/components/LipEffect/settings.d.ts +271 -0
- package/dist/components/LipEffect/types.d.ts +56 -9
- package/dist/components/LipEffect/useLipDesignTextures.d.ts +11 -0
- package/dist/components/LipEffect/uvGuide.d.ts +59 -0
- package/dist/components/PersonCutout/index.d.ts +50 -0
- package/dist/components/PersonCutout/personCutout.d.ts +16 -0
- package/dist/components/ScreenImage/components/ScreenImageBody.d.ts +1 -1
- package/dist/components/ScreenImage/index.d.ts +3 -1
- package/dist/components/ScreenImage/materials/ScreenImageBlendMaterial.d.ts +1 -1
- package/dist/components/ScreenImage/materials/ScreenImageMaskMaterial.d.ts +11 -0
- package/dist/components/ScreenImage/source.d.ts +6 -0
- package/dist/components/ScreenImage/types.d.ts +18 -0
- package/dist/components/SegmentationOverlay/SegmentationOverlay.d.ts +37 -0
- package/dist/components/SegmentationOverlay/SegmentationOverlayMaterial.d.ts +31 -0
- package/dist/components/SegmentationOverlay/index.d.ts +9 -0
- package/dist/components/SegmentationOverlay/maskTexture.d.ts +23 -0
- package/dist/components/SegmentationOverlay/providers.d.ts +72 -0
- package/dist/components/SegmentationOverlay/settings.d.ts +65 -0
- package/dist/components/XRProvider/index.d.ts +16 -2
- package/dist/components/XRViewport/hooks/useViewportExternalFaces.d.ts +1 -1
- package/dist/components/XRViewport/hooks/useViewportMediaSource.d.ts +1 -1
- package/dist/components/XRViewport/hooks/useViewportPipeline.d.ts +1 -1
- package/dist/components/index.d.ts +3 -0
- package/dist/constants/index.d.ts +4 -1
- package/dist/contexts-CO0sd4JQ.cjs +1 -0
- package/dist/{contexts-ByhzppYl.js → contexts-FzlnnMYD.js} +252 -246
- package/dist/coordinates/feed.d.ts +52 -0
- package/dist/coordinates/index.d.ts +5 -0
- package/dist/coordinates/spaces.d.ts +49 -0
- package/dist/coordinates/viewport.d.ts +22 -0
- package/dist/coordinates/world.d.ts +15 -0
- package/dist/debug-ui/gesture-settings/index.d.ts +14 -0
- package/dist/debug-ui/holistic-tracker-settings/index.d.ts +16 -0
- package/dist/debug-ui/index.d.ts +14 -0
- package/dist/debug-ui/iris-effect-settings/index.d.ts +12 -0
- package/dist/debug-ui/lip-effect-settings/index.d.ts +15 -0
- package/dist/debug-ui/media-source.cjs +1 -1
- package/dist/debug-ui/media-source.js +1 -1
- package/dist/debug-ui/product-hotspots/index.d.ts +24 -0
- package/dist/debug-ui/segmentation-overlay-settings/index.d.ts +12 -0
- package/dist/debug-ui/xr-diagnostics/index.d.ts +25 -0
- package/dist/debug-ui.cjs +3 -3
- package/dist/debug-ui.js +2057 -1687
- package/dist/detector-K8aej4MB.js +59 -0
- package/dist/detector-ijypGtse.cjs +1 -0
- package/dist/entries/core.d.ts +18 -1
- package/dist/entries/face-effects.d.ts +11 -3
- package/dist/entries/low-level.d.ts +22 -3
- package/dist/entries/product.d.ts +11 -0
- package/dist/entries/tracking.d.ts +24 -1
- package/dist/face-effects.cjs +155 -1
- package/dist/face-effects.js +1134 -2197
- package/dist/gestures/definitions.d.ts +85 -0
- package/dist/gestures/detector.d.ts +87 -0
- package/dist/gestures/index.d.ts +8 -0
- package/dist/gestures/measures.d.ts +101 -0
- package/dist/gestures/settings.d.ts +49 -0
- package/dist/{getFaceInfo-C4QpCQIY.js → getFaceInfo-BkZfaQs-.js} +5 -5
- package/dist/{getFaceInfo-fA1bFBub.cjs → getFaceInfo-ahPxQFGu.cjs} +1 -1
- package/dist/hooks/selectors.d.ts +68 -1
- package/dist/hooks/useCalibrationFaceTracker.d.ts +1 -1
- package/dist/hooks/useFaceInfo.d.ts +13 -1
- package/dist/hooks/useFaceInfos.d.ts +1 -1
- package/dist/hooks/useGesture.d.ts +32 -0
- package/dist/hooks/useIrisTracking.d.ts +45 -0
- package/dist/hooks/useXRDiagnostics.d.ts +81 -0
- package/dist/hooks/useXRModel.d.ts +7 -0
- package/dist/hooks/useXRSession/facade.d.ts +42 -2
- package/dist/hooks/useXRSession/index.d.ts +2 -2
- package/dist/hooks/useXRSession/reason.d.ts +3 -1
- package/dist/hooks/useXRSession/registry.d.ts +14 -0
- package/dist/hooks/useXRSession/store.d.ts +52 -3
- package/dist/index--RgGzZ6X.cjs +47 -0
- package/dist/{index-VJ0SJwmG.js → index-CHVbH0hz.js} +4 -4
- package/dist/index-CeVkgsag.cjs +1 -0
- package/dist/index-CnGox6Xr.js +3054 -0
- package/dist/{index-ByoNj0QP.js → index-CsUdQ-pn.js} +113 -111
- package/dist/{index-BjmTe9eM.cjs → index-DKBAh6hV.cjs} +1 -1
- package/dist/index-DsZwTfG0.cjs +1 -0
- package/dist/index-Dw6tj2Mi.js +144 -0
- package/dist/index-OCPjOaeP.cjs +1 -0
- package/dist/{index-DXT3WccE.js → index-s9pF4zkG.js} +1065 -1101
- package/dist/internal-BYza1h8_.cjs +1 -0
- package/dist/{internal-Dmk1cTXq.js → internal-vsfNQycj.js} +15 -16
- package/dist/internal.cjs +1 -1
- package/dist/internal.js +2 -2
- package/dist/iris/compute.d.ts +25 -0
- package/dist/iris/index.d.ts +4 -0
- package/dist/iris/lead.d.ts +19 -0
- package/dist/iris/types.d.ts +87 -0
- package/dist/landmarkMask-CbTFzBYG.js +224 -0
- package/dist/landmarkMask-u7es2k4X.cjs +1 -0
- package/dist/low-level.cjs +1 -1
- package/dist/low-level.js +1085 -634
- package/dist/main.cjs +1 -1
- package/dist/main.js +1519 -465
- package/dist/measures-9dQPdw96.js +154 -0
- package/dist/measures-KfJzpvod.cjs +1 -0
- package/dist/models/Base/index.d.ts +49 -0
- package/dist/models/Body/index.d.ts +1 -1
- package/dist/models/Face/index.d.ts +1 -1
- package/dist/models/Hand/GestureTracking.d.ts +1 -1
- package/dist/models/Hand/HandTracking.d.ts +1 -1
- package/dist/models/Holistic/index.d.ts +49 -0
- package/dist/models/Holistic/result.d.ts +68 -0
- package/dist/models/SemanticSegmentation/index.d.ts +31 -0
- package/dist/models/SemanticSegmentation/presets.d.ts +28 -0
- package/dist/models/index.d.ts +2 -0
- package/dist/product/ProductDimensions.d.ts +16 -0
- package/dist/product/ProductHotspot.d.ts +16 -0
- package/dist/product/ProductViewer.d.ts +9 -0
- package/dist/product/details.d.ts +53 -0
- package/dist/product/index.d.ts +14 -0
- package/dist/product/loadModelViewer.d.ts +4 -0
- package/dist/product/types.d.ts +71 -0
- package/dist/product/useProductAr.d.ts +37 -0
- package/dist/product/useProductDetails.d.ts +60 -0
- package/dist/product.cjs +1 -0
- package/dist/product.js +414 -0
- package/dist/providers-C0Dlhh9Z.js +365 -0
- package/dist/providers-YNwkmNeK.cjs +62 -0
- package/dist/quality/XRQualityController.d.ts +25 -0
- package/dist/quality/controller.d.ts +33 -0
- package/dist/quality/index.d.ts +6 -0
- package/dist/quality/types.d.ts +100 -0
- package/dist/quality/useXRQuality.d.ts +28 -0
- package/dist/{renderGroups-KZk6eRiY.js → renderGroups-CN1cGFUo.js} +1 -1
- package/dist/{renderGroups-80H3DpTl.cjs → renderGroups-O4KmaMl9.cjs} +1 -1
- package/dist/renderPasses-Cg-zqmEz.cjs +21 -0
- package/dist/renderPasses-NnKZVfBy.js +1460 -0
- package/dist/scene-object.cjs +1 -1
- package/dist/scene-object.js +2 -2
- package/dist/screenTransform-BenfCtZt.js +44 -0
- package/dist/screenTransform-BiXdpVf0.cjs +1 -0
- package/dist/segmentation-9PhSvc-R.cjs +1 -0
- package/dist/segmentation-CeOTKemr.js +5 -0
- package/dist/segmentation2d/faceMemory.d.ts +28 -0
- package/dist/segmentation2d/faceRegions.d.ts +24 -0
- package/dist/segmentation2d/index.d.ts +9 -0
- package/dist/segmentation2d/maskUv.d.ts +23 -0
- package/dist/segmentation2d/rasterize.d.ts +14 -0
- package/dist/segmentation2d/types.d.ts +46 -0
- package/dist/selectors-C5G1PMYL.js +195 -0
- package/dist/selectors-Du_PsVnW.cjs +1 -0
- package/dist/{session-CpkiK5YA.cjs → session-BBr0yN8h.cjs} +7 -7
- package/dist/{session-DLFN_VII.js → session-Cy0m7l7-.js} +76 -76
- package/dist/settings-DRR7-snV.cjs +1 -0
- package/dist/settings-aQk845NJ.js +73 -0
- package/dist/subjects/index.d.ts +2 -0
- package/dist/subjects/select.d.ts +62 -0
- package/dist/subjects/types.d.ts +55 -0
- package/dist/tracking-config/apply.d.ts +57 -0
- package/dist/tracking-config/index.d.ts +7 -0
- package/dist/tracking-config/resolve.d.ts +25 -0
- package/dist/tracking-config/storage.d.ts +8 -0
- package/dist/tracking-config/types.d.ts +106 -0
- package/dist/tracking-config/useXRTrackingConfig.d.ts +38 -0
- package/dist/tracking.cjs +1 -1
- package/dist/tracking.js +1056 -383
- package/dist/types/compositor.d.ts +21 -0
- package/dist/types/holistic.d.ts +121 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/model.d.ts +22 -2
- package/dist/types/nodes.d.ts +27 -2
- package/dist/types/segmentation.d.ts +19 -0
- package/dist/types/session.d.ts +41 -3
- package/dist/useFaceInfo-Blf7FCu3.js +303 -0
- package/dist/useFaceInfo-C5mO8NQY.cjs +1 -0
- package/dist/useXRCapabilities-B1R2ghy-.cjs +1 -0
- package/dist/useXRCapabilities-C68v__wB.js +30 -0
- package/dist/utils/fns.d.ts +6 -3
- package/dist/utils/integrity.d.ts +4 -1
- package/dist/utils/updateThrottle.d.ts +2 -0
- package/dist/utils/useStableUniforms.d.ts +18 -0
- package/docs/api/adaptive-quality.mdx +104 -0
- package/docs/api/asset-lifecycle.mdx +78 -0
- package/docs/api/camera-permission.mdx +142 -0
- package/docs/api/coordinate-spaces.mdx +165 -0
- package/docs/api/cross-camera.mdx +88 -0
- package/docs/api/diagnostics-calibration.mdx +97 -0
- package/docs/api/face-effects.mdx +6 -0
- package/docs/api/face-mesh.mdx +4 -2
- package/docs/api/gestures.mdx +173 -0
- package/docs/api/holistic-tracker.mdx +159 -0
- package/docs/api/iris-tracking.mdx +242 -0
- package/docs/api/multi-subject.mdx +95 -0
- package/docs/api/person-cutout.mdx +136 -0
- package/docs/api/product-ar.mdx +111 -0
- package/docs/api/product-details.mdx +78 -0
- package/docs/api/screen-space-coordinates.mdx +4 -1
- package/docs/api/segmentation-overlay.mdx +301 -0
- package/docs/api/session-lifecycle.mdx +136 -0
- package/docs/api/trackers.mdx +5 -0
- package/docs/api/tracking-config.mdx +108 -0
- package/docs/docs.json +23 -1
- package/docs/examples/lip-shaders.mdx +224 -0
- package/docs/guides/lip-effect-textures.mdx +292 -0
- package/docs/guides/lip-uv-template.png +0 -0
- package/docs/guides/lip-uv-template.svg +1 -0
- package/package.json +13 -1
- package/dist/FaceMeshRenderer-C5l6VLdO.cjs +0 -155
- package/dist/FaceMeshRenderer-wjAHrJzP.js +0 -1270
- package/dist/FaceRetouch-BkJzoA79.cjs +0 -134
- package/dist/FaceRetouch-DwbKQJAN.js +0 -551
- package/dist/contexts-Dr62It_K.cjs +0 -1
- package/dist/index-9dlAQAhy.js +0 -1462
- package/dist/index-BpEf2BBb.cjs +0 -1
- package/dist/index-CyUUurQT.cjs +0 -1
- package/dist/index-DCiMbxC3.cjs +0 -1
- package/dist/index-DpI-qo5X.cjs +0 -17
- package/dist/index-DyVF4vEW.js +0 -111
- package/dist/internal-Cq-TEQ5Y.cjs +0 -1
- package/dist/renderLayers-lDtL0_43.cjs +0 -1
- package/dist/renderLayers-zrK2pv5O.js +0 -13
- package/dist/renderPasses-BOoBSr8z.cjs +0 -21
- package/dist/renderPasses-BcquyVtu.js +0 -1500
- package/dist/selectors-B8H97CKA.js +0 -59
- package/dist/selectors-CZLKT2Iv.cjs +0 -1
- package/dist/useFaceInfo-BJ8-_MOs.cjs +0 -1
- package/dist/useFaceInfo-Dk426LTu.js +0 -62
- package/dist/useFaceResults-CtetsO9M.js +0 -19
- 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
|
+
};
|