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