@swan-admin/swan-web-component 1.0.65 → 1.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/Header-BBS0ksKW.js +32 -0
  2. package/dist/Header-BBS0ksKW.js.map +1 -0
  3. package/dist/Header-CEr0GTzW.js +32 -0
  4. package/dist/Header-CEr0GTzW.js.map +1 -0
  5. package/dist/Header-CWyl1xHS.js +32 -0
  6. package/dist/Header-CWyl1xHS.js.map +1 -0
  7. package/dist/Header-CinjIhJx.js +32 -0
  8. package/dist/Header-CinjIhJx.js.map +1 -0
  9. package/dist/Header-D4sw6doV.js +32 -0
  10. package/dist/Header-D4sw6doV.js.map +1 -0
  11. package/dist/Header-Ddi4-0Tk.js +32 -0
  12. package/dist/Header-Ddi4-0Tk.js.map +1 -0
  13. package/dist/Header-DurZvuvu.js +32 -0
  14. package/dist/Header-DurZvuvu.js.map +1 -0
  15. package/dist/Header-QHsJ-W0o.js +32 -0
  16. package/dist/Header-QHsJ-W0o.js.map +1 -0
  17. package/dist/Header-vfreHFif.js +32 -0
  18. package/dist/Header-vfreHFif.js.map +1 -0
  19. package/dist/Header-wvV2TKA8.js +32 -0
  20. package/dist/Header-wvV2TKA8.js.map +1 -0
  21. package/dist/LoadingScreen-BlArUzy9.js +12 -0
  22. package/dist/LoadingScreen-BlArUzy9.js.map +1 -0
  23. package/dist/LoadingScreen-CL_Uh7jw.js +12 -0
  24. package/dist/LoadingScreen-CL_Uh7jw.js.map +1 -0
  25. package/dist/LoadingScreen-CmttLMLy.js +12 -0
  26. package/dist/LoadingScreen-CmttLMLy.js.map +1 -0
  27. package/dist/LoadingScreen-CsQf8C4V.js +12 -0
  28. package/dist/LoadingScreen-CsQf8C4V.js.map +1 -0
  29. package/dist/LoadingScreen-CsqPjjFQ.js +12 -0
  30. package/dist/LoadingScreen-CsqPjjFQ.js.map +1 -0
  31. package/dist/LoadingScreen-DR13gmXn.js +12 -0
  32. package/dist/LoadingScreen-DR13gmXn.js.map +1 -0
  33. package/dist/LoadingScreen-DTj0QcdY.js +12 -0
  34. package/dist/LoadingScreen-DTj0QcdY.js.map +1 -0
  35. package/dist/LoadingScreen-DkjLcO4p.js +12 -0
  36. package/dist/LoadingScreen-DkjLcO4p.js.map +1 -0
  37. package/dist/LoadingScreen-NZvOIkn7.js +12 -0
  38. package/dist/LoadingScreen-NZvOIkn7.js.map +1 -0
  39. package/dist/LoadingScreen-W5m5KgGq.js +12 -0
  40. package/dist/LoadingScreen-W5m5KgGq.js.map +1 -0
  41. package/dist/arrow-right-9dPfO1-1.js +27 -0
  42. package/dist/arrow-right-9dPfO1-1.js.map +1 -0
  43. package/dist/arrow-right-BDBTHwhp.js +27 -0
  44. package/dist/arrow-right-BDBTHwhp.js.map +1 -0
  45. package/dist/arrow-right-Bo-_bcs-.js +27 -0
  46. package/dist/arrow-right-Bo-_bcs-.js.map +1 -0
  47. package/dist/arrow-right-BqMp5VTz.js +27 -0
  48. package/dist/arrow-right-BqMp5VTz.js.map +1 -0
  49. package/dist/arrow-right-CSJtmJZ9.js +27 -0
  50. package/dist/arrow-right-CSJtmJZ9.js.map +1 -0
  51. package/dist/arrow-right-DWYC9VMJ.js +27 -0
  52. package/dist/arrow-right-DWYC9VMJ.js.map +1 -0
  53. package/dist/arrow-right-DuFCod9Z.js +27 -0
  54. package/dist/arrow-right-DuFCod9Z.js.map +1 -0
  55. package/dist/arrow-right-DuYft9nO.js +27 -0
  56. package/dist/arrow-right-DuYft9nO.js.map +1 -0
  57. package/dist/bodyScan.d.ts +6 -0
  58. package/dist/bodyScan.js +10 -0
  59. package/dist/bodyScan.js.map +1 -0
  60. package/dist/bodyScan.mjs +10 -0
  61. package/dist/bodyScan.mjs.map +1 -0
  62. package/dist/createSvgIcon-7qiG0uLU.js +2 -0
  63. package/dist/createSvgIcon-7qiG0uLU.js.map +1 -0
  64. package/dist/createSvgIcon-B8P8_wCu.js +2 -0
  65. package/dist/createSvgIcon-B8P8_wCu.js.map +1 -0
  66. package/dist/createSvgIcon-BI3z7WiV.js +2 -0
  67. package/dist/createSvgIcon-BI3z7WiV.js.map +1 -0
  68. package/dist/createSvgIcon-BTYDZFK1.js +2 -0
  69. package/dist/createSvgIcon-BTYDZFK1.js.map +1 -0
  70. package/dist/createSvgIcon-CB9vUHUH.js +2 -0
  71. package/dist/createSvgIcon-CB9vUHUH.js.map +1 -0
  72. package/dist/createSvgIcon-CuCbPBPG.js +2 -0
  73. package/dist/createSvgIcon-CuCbPBPG.js.map +1 -0
  74. package/dist/createSvgIcon-CwpzxTx8.js +2 -0
  75. package/dist/createSvgIcon-CwpzxTx8.js.map +1 -0
  76. package/dist/createSvgIcon-CzDhPSaA.js +2 -0
  77. package/dist/createSvgIcon-CzDhPSaA.js.map +1 -0
  78. package/dist/createSvgIcon-Dml8NLBw.js +2 -0
  79. package/dist/createSvgIcon-Dml8NLBw.js.map +1 -0
  80. package/dist/createSvgIcon-iUTUfWQF.js +2 -0
  81. package/dist/createSvgIcon-iUTUfWQF.js.map +1 -0
  82. package/dist/faceScan.d.ts +6 -0
  83. package/dist/faceScan.js +2 -0
  84. package/dist/faceScan.js.map +1 -0
  85. package/dist/faceScan.mjs +2 -0
  86. package/dist/faceScan.mjs.map +1 -0
  87. package/dist/index.css +3 -0
  88. package/dist/index.d.ts +3 -137
  89. package/dist/index.js +78 -974
  90. package/dist/index.js.map +1 -1
  91. package/dist/index.mjs +78 -974
  92. package/dist/index.mjs.map +1 -1
  93. package/dist/{index.d.mts → interfaces-Bn755Jp2.d.ts} +2 -13
  94. package/package.json +116 -66
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faceScan.js","sources":["../src/components/faceScan/FaceScanGuide.tsx","../src/components/faceScan/FaceScanErrorScreen.tsx","../src/customHooks/useFaceScan.ts","../src/components/faceScan/FaceScan.tsx"],"sourcesContent":["\nimport { FaceScanGuideProps } from \"../../types/interfaces\";\nimport Header from \"../Header\";\nimport { GenderType } from \"../../utils/enums\";\nimport { directionMessages, FACE_SCAN_HEADSHOT, glassesOffVideo, maleGlassesOffVideo } from \"../../utils/constants\";\n\n\nfunction FaceScanGuide({\n\tstage,\n\tvideoLoading,\n\tsetVideoLoading,\n\tvideoError,\n\tsetVideoError,\n\tchildren,\n\tgender,\n\tconfig,\n}: FaceScanGuideProps) {\n\tif (stage === -1) {\n\t\treturn (\n\t\t\t<div className=\"text-center p-[16px] w-full h-full\" style={{ background: config?.style?.base?.backgroundColor }}>\n\t\t\t\t<div className=\"w-full\">\n\t\t\t\t\t<Header noTitle resolvedConfig={config} />\n\t\t\t\t\t<h2\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tfontFamily: config?.style?.heading?.headingFontFamily || \"SeriouslyNostalgic Fn\",\n\t\t\t\t\t\t\tfontSize: config?.style?.heading?.headingFontSize || \"32px\",\n\t\t\t\t\t\t\tcolor: config?.style?.heading?.headingColor || \"#000\",\n\t\t\t\t\t\t\tfontWeight: config?.style?.heading?.headingFontWeight || \"normal\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\tMake sure your face is fully visible{\" \"}\n\t\t\t\t\t</h2>\n\t\t\t\t\t{videoLoading && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"mb-4 flex items-center justify-center\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tfontFamily: config?.style?.subheading?.subheadingFontFamily || \"'Inter', sans-serif\",\n\t\t\t\t\t\t\t\tfontSize: config?.style?.subheading?.subheadingFontSize || \"14px\",\n\t\t\t\t\t\t\t\tcolor: config?.style?.subheading?.subheadingColor || \"#4b5563\",\n\t\t\t\t\t\t\t\tfontWeight: config?.style?.subheading?.subheadingFontWeight || \"normal\",\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tLoading video...\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{videoError && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"mb-4 text-red-600\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tfontFamily: config?.style?.subheading?.subheadingFontFamily || \"'Inter', sans-serif\",\n\t\t\t\t\t\t\t\tfontSize: config?.style?.subheading?.subheadingFontSize || \"14px\",\n\t\t\t\t\t\t\t\tcolor: \"#ff0000\",\n\t\t\t\t\t\t\t\tfontWeight: config?.style?.subheading?.subheadingFontWeight || \"normal\",\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tVideo failed to load. Please refresh the page or check your connection.\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{!videoError && (\n\t\t\t\t\t\t<div className={` w-[100px] mx-auto`}>\n\t\t\t\t\t\t\t<video\n\t\t\t\t\t\t\t\tsrc={gender === GenderType.Male ? maleGlassesOffVideo : glassesOffVideo}\n\t\t\t\t\t\t\t\tautoPlay\n\t\t\t\t\t\t\t\tloop\n\t\t\t\t\t\t\t\tcontrols={false}\n\t\t\t\t\t\t\t\tmuted\n\t\t\t\t\t\t\t\tplaysInline\n\t\t\t\t\t\t\t\tclassName=\"h-full w-full object-contain border-none\"\n\t\t\t\t\t\t\t\tonCanPlay={() => setVideoLoading(false)}\n\t\t\t\t\t\t\t\tonLoadStart={() => setVideoLoading(true)}\n\t\t\t\t\t\t\t\tonError={() => setVideoError(true)}\n\t\t\t\t\t\t\t\taria-label=\"Instructional video: Please remove your glasses before starting the scan.\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"text-center p-[16px] w-full h-full\" style={{ background: config?.style?.base?.backgroundColor }}>\n\t\t\t<div className=\"w-full\">\n\t\t\t\t<Header noTitle resolvedConfig={config} />\n\t\t\t\t<h3\n\t\t\t\t\tclassName=\"mb-[0.5rem]\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tfontFamily: config?.style?.heading?.headingFontFamily || \"SeriouslyNostalgic Fn\",\n\t\t\t\t\t\tfontSize: config?.style?.heading?.headingFontSize || \"32px\",\n\t\t\t\t\t\tcolor: config?.style?.heading?.headingColor || \"#000\",\n\t\t\t\t\t\tfontWeight: config?.style?.heading?.headingFontWeight || \"normal\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{directionMessages[stage]}\n\t\t\t\t</h3>\n\t\t\t\t{/* <p>We'll guide you to take 6 selfies </p> */}\n\t\t\t\t<div className=\"max-w-[400px] justify-center gap-1 mx-auto flex items-center\">\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 0 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.forward : FACE_SCAN_HEADSHOT.female.forward} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 1 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.left : FACE_SCAN_HEADSHOT.female.left} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 2 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.right : FACE_SCAN_HEADSHOT.female.right} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 3 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.smile : FACE_SCAN_HEADSHOT.female.smile} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport default FaceScanGuide;\n","import { ArrowRight } from \"lucide-react\";\nimport Header from \"../Header\";\nimport SpecificButton from \"../../atoms/specificButton/SpecificButton\";\n\nfunction FaceScanErrorScreen({ resetScanState, loading, config }: { resetScanState: () => void; loading: boolean; config?: any }) {\n\treturn (\n\t\t<div className=\"fixed top-[0] left-[0] z-[999] flex justify-center items-center w-full h-full\" style={{ background: config?.style?.base?.backgroundColor }}>\n\t\t\t<div className=\"flex flex-col w-full items-center p-[1rem] rounded-lg \">\n\t\t\t\t<Header noTitle resolvedConfig={config} />\n\t\t\t\t<div className=\"flex flex-col items-center w-full\">\n\t\t\t\t\t<h2\n\t\t\t\t\t\tclassName=\"text-xl font-semibold text-gray-800 \"\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tfontFamily: config?.style?.heading?.headingFontFamily || \"SeriouslyNostalgic Fn\",\n\t\t\t\t\t\t\tfontSize: config?.style?.heading?.headingFontSize || \"32px\",\n\t\t\t\t\t\t\tcolor: config?.style?.heading?.headingColor || \"#000\",\n\t\t\t\t\t\t\tfontWeight: config?.style?.heading?.headingFontWeight || \"normal\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\tYour Scan Failed\n\t\t\t\t\t</h2>\n\t\t\t\t\t<p\n\t\t\t\t\t\tclassName=\"mb-[1.5rem]\"\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tfontFamily: config?.style?.subheading?.subheadingFontFamily || \"'Inter', sans-serif\",\n\t\t\t\t\t\t\tfontSize: config?.style?.subheading?.subheadingFontSize || \"14px\",\n\t\t\t\t\t\t\tcolor: config?.style?.subheading?.subheadingColor || \"#4b5563\",\n\t\t\t\t\t\t\tfontWeight: config?.style?.subheading?.subheadingFontWeight || \"normal\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\tPlease click below to reset your scan.\n\t\t\t\t\t</p>\n\t\t\t\t\t<SpecificButton\n\t\t\t\t\t\tdisabled={loading}\n\t\t\t\t\t\tclassName=\"w-full h-[45px] shadow-[0px_1px_2px_0px_#00000040] text-[16px]\"\n\t\t\t\t\t\tbuttonText=\"Reset Scan\"\n\t\t\t\t\t\tpostfixIcon={<ArrowRight />}\n\t\t\t\t\t\tbuttonFunc={() => resetScanState()}\n\t\t\t\t\t\tresolvedConfig={config}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport default FaceScanErrorScreen;\n","import {\n useState,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n RefObject,\n} from \"react\";\nimport * as poseDetection from \"@tensorflow-models/pose-detection\";\nimport \"@tensorflow/tfjs\";\nimport { posthog } from \"posthog-js\";\nimport { ready, setBackend } from \"@tensorflow/tfjs\";\nimport speechService from \"../utils/service/speechService\";\nimport { videoConstraints, voiceOverAssetsPath } from \"../utils/constants\";\n\n/**\n * useFaceScan Hook with PostHog Analytics\n *\n * Analytics Events Tracked:\n * 1. face_scan_pose_detection - Every 4 seconds during scanning\n * - Keypoint scores and positions\n * - Face/body detection metrics\n * - Stage-specific positioning data\n * - Time spent in current stage\n *\n * 2. face_scan_stage_completed - When user successfully completes a stage\n * - Stage transition data\n * - Completion time\n *\n * 3. face_scan_started - When scan sequence begins\n * - Stage information\n * - Start timestamp\n *\n * 4. face_scan_reset - When user resets the scan\n * - Reset reason analysis\n * - Stage where reset occurred\n *\n * This helps identify why users take longer to get detected in pose detection.\n */\n\n// Debounce utility\nfunction debounce(fn: (...args: any) => void, delay: number) {\n let timer: number | NodeJS.Timeout;\n return (...args: any) => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), delay);\n };\n}\n\nlet preloadedDetector: poseDetection.PoseDetector | null = null;\n\nexport const preloadDetector = async () => {\n if (preloadedDetector) return preloadedDetector;\n\n const detector = await poseDetection.createDetector(\n poseDetection.SupportedModels.BlazePose,\n {\n runtime: \"tfjs\",\n modelType: \"full\",\n }\n );\n\n // Dummy video warmup\n const dummyCanvas = document.createElement(\"canvas\");\n dummyCanvas.width = videoConstraints.width;\n dummyCanvas.height = videoConstraints.height;\n const ctx = dummyCanvas.getContext(\"2d\");\n if (ctx) {\n ctx.fillStyle = \"black\";\n ctx.fillRect(0, 0, dummyCanvas.width, dummyCanvas.height);\n }\n try {\n await detector.estimatePoses(dummyCanvas);\n } catch (e) {\n // Expected: empty video stream\n console.log(e, \"at time of preload\");\n }\n\n preloadedDetector = detector;\n return detector;\n};\n\ntype Point = [number, number, number];\n\nfunction useFaceScan({\n faceScanId,\n onValidPose,\n onScanComplete,\n onModelReady,\n onStartRecording,\n shopDomain,\n}: {\n faceScanId: string;\n onValidPose?: () => void;\n onScanComplete?: () => void;\n onModelReady?: () => void;\n onStartRecording: () => void;\n shopDomain: string;\n}) {\n const detectorRef = useRef<poseDetection.PoseDetector | null>(null);\n const [scanStage, setScanStage] = useState(0);\n const [consecutiveValid, setConsecutiveValid] = useState(0);\n const [isModelLoaded, setIsModelLoaded] = useState(false);\n const [isScanningActive, setIsScanningActive] = useState(false);\n const utteranceRef = useRef(null);\n const scanStageRef = useRef(scanStage);\n const consecutiveValidRef = useRef(consecutiveValid);\n const validityBufferRef = useRef<boolean[]>([]);\n const lastSpokenMessageRef = useRef(\"\");\n const lastSpokenTimeRef = useRef(0);\n const voiceEnabledRef = useRef(false);\n const VALIDITY_BUFFER_LENGTH = 10;\n const CONSECUTIVE_VALID_LENGTH = 2;\n const TOTAL_STAGES = 4;\n const POSE_TRACKING_INTERVAL = 4000; // 4 seconds between pose tracking events\n const lastPoseTrackingTimeRef = useRef(0);\n\n // iOS detection\n const isIOS =\n /iPad|iPhone|iPod/.test(navigator.userAgent) ||\n (navigator.platform === \"MacIntel\" && navigator.maxTouchPoints > 1);\n\n const directionMessages = useMemo(\n () => [\n \"Face front\",\n \"Turn head fully left\",\n \"Turn head fully right\",\n \"Smile facing front\",\n ],\n []\n );\n\n // Debounced analytics event\n const debouncedTrackPoseDetection = useMemo(\n () =>\n debounce((payload) => {\n posthog.capture(`${shopDomain}/face_scan_pose_detection`, payload);\n }, 4000),\n [shopDomain]\n );\n\n // Track pose detection performance for analytics\n const trackPoseDetection = useCallback(\n (\n faceKeypoints: Point[],\n bodyKeypoints: Point[],\n stage: number,\n headValid: boolean,\n bodyInvalid: boolean,\n consecutiveValidCount: number\n ) => {\n const now = Date.now();\n\n // Only track every 4 seconds to avoid spam\n if (now - lastPoseTrackingTimeRef.current < POSE_TRACKING_INTERVAL) {\n return;\n }\n\n lastPoseTrackingTimeRef.current = now;\n\n try {\n // Extract key face keypoints for analysis\n const nose = faceKeypoints[0] || [0, 0, 0];\n const leftEye = faceKeypoints[2] || [0, 0, 0];\n const rightEye = faceKeypoints[5] || [0, 0, 0];\n const leftMouth = faceKeypoints[9] || [0, 0, 0];\n const rightMouth = faceKeypoints[10] || [0, 0, 0];\n\n // Calculate key metrics\n const faceKeypointScores = faceKeypoints\n .map((kp: Point) => kp[2])\n .filter((score: number) => score > 0);\n const avgFaceScore =\n faceKeypointScores.length > 0\n ? faceKeypointScores.reduce((a, b) => a + b, 0) /\n faceKeypointScores.length\n : 0;\n\n const bodyKeypointScores = bodyKeypoints\n .map((kp: Point) => kp[2])\n .filter((score: number) => score > 0);\n const avgBodyScore =\n bodyKeypointScores.length > 0\n ? bodyKeypointScores.reduce((a: number, b: number) => a + b, 0) /\n bodyKeypointScores.length\n : 0;\n\n // Calculate face positioning metrics\n const eyeDistance = Math.abs(leftEye[0] - rightEye[0]);\n const noseToRight = nose[0] - rightEye[0];\n const noseToLeft = leftEye[0] - nose[0];\n\n // Determine expected position based on stage\n let expectedPosition = \"frontal\";\n if (stage === 1) expectedPosition = \"left\";\n else if (stage === 2) expectedPosition = \"right\";\n else if (stage === 3) expectedPosition = \"frontal_smile\";\n\n const payload = {\n faceScanId,\n stage,\n timestamp: new Date().toISOString(),\n data: JSON.stringify({\n headValid,\n bodyInvalid,\n consecutiveValid: consecutiveValidCount,\n avgFaceScore: parseFloat(avgFaceScore.toFixed(3)),\n avgBodyScore: parseFloat(avgBodyScore.toFixed(3)),\n faceKeypointsDetected: faceKeypointScores.length,\n bodyKeypointsDetected: bodyKeypointScores.length,\n eyeDistance: parseFloat(eyeDistance.toFixed(2)),\n noseToRightRatio: parseFloat(\n (noseToRight / eyeDistance).toFixed(3)\n ),\n noseToLeftRatio: parseFloat((noseToLeft / eyeDistance).toFixed(3)),\n noseScore: parseFloat(nose[2].toFixed(3)),\n leftEyeScore: parseFloat(leftEye[2].toFixed(3)),\n rightEyeScore: parseFloat(rightEye[2].toFixed(3)),\n leftMouthScore: parseFloat(leftMouth[2].toFixed(3)),\n rightMouthScore: parseFloat(rightMouth[2].toFixed(3)),\n expectedPosition,\n // timeInStage: Math.floor((now - lastPoseTrackingTimeRef.current) / 1000),\n }),\n };\n debouncedTrackPoseDetection(payload);\n } catch (error) {\n console.warn(\"Failed to track pose detection:\", error);\n }\n },\n [faceScanId, debouncedTrackPoseDetection]\n );\n\n // Enable voice commands from user interaction context\n const enableVoiceCommands = () => {\n voiceEnabledRef.current = true; // Set ref immediately\n\n // iOS Safari requires an initial speech synthesis call to enable audio context\n if (isIOS && \"speechSynthesis\" in window) {\n // Create a silent utterance to initialize speech synthesis\n const silentUtterance = new SpeechSynthesisUtterance(\"\");\n silentUtterance.volume = 0; // Set volume to 0 to make it silent\n speechSynthesis.speak(silentUtterance);\n }\n };\n\n // Start scan sequence: first speak direction, then start scanning\n const startScanSequence = () => {\n // Track scan start\n posthog.capture(`${shopDomain}/face_scan_detection_started`, {\n faceScanId,\n stage: scanStageRef.current,\n timestamp: new Date().toISOString(),\n stageName: directionMessages[scanStageRef.current],\n });\n\n // Then start scanning after the voice command finishes\n setTimeout(() => {\n setIsScanningActive(true);\n }, 1500); // Wait for voice command to complete\n };\n\n const isHeadInPosition = (stage: number, keypoints: Point[]) => {\n const nose = 0;\n const leftEye = 2;\n const rightEye = 5;\n const leftMouth = 9;\n const rightMouth = 10;\n\n const minScore = 0.2;\n if (\n keypoints[nose][2] < minScore ||\n keypoints[leftEye][2] < minScore ||\n keypoints[rightEye][2] < minScore\n ) {\n return false;\n }\n\n const eyesToMouthVerticalDistance =\n 0.5 * (keypoints[rightMouth][1] + keypoints[leftMouth][1]) -\n 0.5 * (keypoints[rightEye][1] + keypoints[leftEye][1]);\n\n const faceTiltedness =\n (0.5 * (keypoints[rightMouth][1] + keypoints[leftMouth][1]) -\n keypoints[nose][1]) /\n eyesToMouthVerticalDistance;\n\n const faceIsTilted = faceTiltedness > 0.7 || faceTiltedness < 0.3;\n\n const faceIsVertical =\n Math.abs(keypoints[leftEye][1] - keypoints[rightEye][1]) <\n 0.5 * eyesToMouthVerticalDistance &&\n Math.abs(keypoints[leftMouth][1] - keypoints[rightMouth][1]) <\n 0.5 * eyesToMouthVerticalDistance;\n\n const eyeDistance = keypoints[leftEye][0] - keypoints[rightEye][0];\n const noseToRight = keypoints[nose][0] - keypoints[rightEye][0];\n const noseToLeft = keypoints[leftEye][0] - keypoints[nose][0];\n\n const frontalFace =\n noseToRight > 0.4 * eyeDistance && noseToRight < 0.6 * eyeDistance;\n const fullLeft = noseToRight > 0.85 * eyeDistance;\n const fullRight = noseToLeft > 0.85 * eyeDistance;\n\n switch (stage) {\n case 0:\n return !faceIsTilted && faceIsVertical && frontalFace;\n case 1:\n return !faceIsTilted && faceIsVertical && fullLeft;\n case 2:\n return !faceIsTilted && faceIsVertical && fullRight;\n case 3:\n return !faceIsTilted && faceIsVertical && frontalFace;\n default:\n return false;\n }\n };\n\n const faceScanDetector = async (\n webcamRef: RefObject<HTMLVideoElement | null>,\n canvasRef: RefObject<HTMLCanvasElement | null>\n ) => {\n if (\n !detectorRef.current ||\n !webcamRef.current ||\n !isModelLoaded ||\n !isScanningActive\n )\n return;\n\n try {\n const poses = await detectorRef.current.estimatePoses(webcamRef.current);\n if (poses.length > 0) {\n const faceKeypoints: Point[] = [];\n const bodyKeypoints: Point[] = [];\n poses[0].keypoints.forEach((landmark, idx) => {\n const score = landmark.score ?? 0;\n const point: Point = [landmark.x ?? -1, landmark.y ?? -1, score];\n if (idx <= 10) faceKeypoints.push(point);\n else bodyKeypoints.push(point);\n });\n\n // Optional drawing (invisible canvas)\n if (canvasRef?.current) {\n const ctx = canvasRef.current.getContext(\"2d\");\n const { width, height } = canvasRef.current;\n if (ctx) {\n ctx.clearRect(0, 0, width, height);\n\n const progress = Math.min(\n consecutiveValidRef.current / CONSECUTIVE_VALID_LENGTH,\n 1\n );\n const radius = height * 0.35;\n ctx.beginPath();\n ctx.strokeStyle = \"#00ff00\";\n ctx.lineWidth = 6;\n ctx.arc(\n width / 2,\n height / 2,\n radius + 10,\n -Math.PI / 2,\n -Math.PI / 2 + progress * 2 * Math.PI\n );\n ctx.stroke();\n }\n }\n\n const headValid = isHeadInPosition(scanStageRef.current, faceKeypoints);\n const bodyInvalid =\n bodyKeypoints.slice(2).filter((p) => p[2] > 0.7).length <= 2;\n\n validityBufferRef.current.push(headValid && bodyInvalid);\n if (validityBufferRef.current.length > VALIDITY_BUFFER_LENGTH) {\n validityBufferRef.current.shift();\n }\n\n const validCount = validityBufferRef.current.filter(Boolean).length;\n if (validCount >= 2) {\n const nextValid = consecutiveValidRef.current + 1;\n setConsecutiveValid(nextValid);\n } else {\n setConsecutiveValid(Math.max(0, consecutiveValidRef.current - 1));\n }\n\n // ✅ Pose confirmed\n if (consecutiveValidRef.current >= CONSECUTIVE_VALID_LENGTH) {\n onValidPose?.();\n\n const nextStage = scanStageRef.current + 1;\n setConsecutiveValid(0);\n validityBufferRef.current = [];\n setScanStage(nextStage);\n setIsScanningActive(false); // Stop scanning for next stage\n\n // Play sound effect for stage completion, then next stage instruction (if not final stage)\n (async () => {\n await speechService.playAudio(\n `${voiceOverAssetsPath}face-scan-vos/Sound-effect.mp3`\n );\n // Track stage completion\n posthog.capture(\n `${shopDomain}/face_scan_detection_stage_completed`,\n {\n faceScanId,\n completedStage: scanStageRef.current,\n nextStage,\n timestamp: new Date().toISOString(),\n totalStages: TOTAL_STAGES,\n stageName: directionMessages[scanStageRef.current],\n }\n );\n // Start recording after stage 0 is completed\n if (nextStage === 1 && onStartRecording) {\n onStartRecording();\n }\n if (nextStage >= TOTAL_STAGES) {\n onScanComplete?.();\n } else {\n // Play next stage instruction sound, then start scan sequence\n let nextSound = null;\n switch (nextStage) {\n case 1:\n nextSound = \"Left.mp3\";\n break;\n case 2:\n nextSound = \"Right.mp3\";\n break;\n case 3:\n nextSound = \"Smile.mp3\";\n break;\n default:\n nextSound = null;\n }\n if (nextSound) {\n await speechService.playAudio(\n `${voiceOverAssetsPath}face-scan-vos/${nextSound}`\n );\n }\n startScanSequence();\n }\n })();\n }\n\n // Track pose detection performance for analytics\n trackPoseDetection(\n faceKeypoints,\n bodyKeypoints,\n scanStageRef.current,\n headValid,\n bodyInvalid,\n consecutiveValidRef.current\n );\n }\n } catch (err) {\n console.error(\"Pose detection error:\", err);\n }\n };\n\n const initializeModels = async () => {\n try {\n console.log(\"Initializing TensorFlow...\");\n await setBackend(\"webgl\");\n await ready();\n console.log(\"TensorFlow initialized, loading models...\");\n const detector = await preloadDetector(); // <-- now it waits for preload\n console.log(detector, \"detector\");\n\n detectorRef.current = detector;\n console.log(\"Pose detection model loaded successfully\");\n setIsModelLoaded(true);\n onModelReady?.();\n } catch (err) {\n console.error(\"Error initializing face scan:\", err);\n }\n };\n\n const disposeModelAndTf = async () => {\n try {\n setIsModelLoaded(false);\n if (detectorRef.current) {\n await detectorRef.current.dispose();\n detectorRef.current = null;\n }\n } catch (err) {\n console.error(\"Error disposing resources:\", err);\n } finally {\n setScanStage(0);\n setConsecutiveValid(0);\n scanStageRef.current = 0;\n consecutiveValidRef.current = 0;\n validityBufferRef.current = [];\n }\n };\n\n const resetScan = () => {\n // Track scan reset\n posthog.capture(`${shopDomain}/face_scan_reset`, {\n faceScanId,\n stage: scanStageRef.current,\n timestamp: new Date().toISOString(),\n stageName: directionMessages[scanStageRef.current],\n consecutiveValid: consecutiveValidRef.current,\n });\n\n setScanStage(0);\n setConsecutiveValid(0);\n setIsScanningActive(false);\n scanStageRef.current = 0;\n consecutiveValidRef.current = 0;\n validityBufferRef.current = [];\n lastSpokenMessageRef.current = \"\";\n lastSpokenTimeRef.current = 0;\n voiceEnabledRef.current = false;\n if (utteranceRef.current) {\n speechSynthesis.cancel();\n utteranceRef.current = null;\n }\n };\n\n useEffect(() => {\n // disposeModelAndTf();\n initializeModels();\n return () => {\n disposeModelAndTf();\n };\n }, []);\n\n useEffect(() => {\n scanStageRef.current = scanStage;\n }, [scanStage]);\n\n useEffect(() => {\n consecutiveValidRef.current = consecutiveValid;\n }, [consecutiveValid]);\n\n return {\n faceScanDetector,\n scanStage,\n setScanStage,\n consecutiveValid,\n isModelLoaded,\n resetScan,\n enableVoiceCommands,\n startScanSequence,\n isScanningActive,\n };\n}\n\nexport default useFaceScan;\n","\"use client\"\nimport { useEffect, useRef, useState, useCallback, useMemo } from \"react\";\nimport { ArrowRight } from \"lucide-react\";\nimport { Drawer } from \"@mui/material\";\nimport FaceScanGuide from \"./FaceScanGuide\";\nimport FaceScanErrorScreen from \"./FaceScanErrorScreen\";\nimport posthog from \"posthog-js\";\nimport { FaceScanProps } from \"../../types/interfaces\";\nimport {\n generateUuid,\n handleScanTimeCapture,\n handleWebSocketCapture,\n} from \"../../utils/utils\";\nimport { useLocalConfig } from \"../../config/useLocalConfig\";\nimport {\n posthogPublicHost,\n posthogPublicKey,\n videoConstraints,\n videoTypes,\n voiceOverAssetsPath,\n} from \"../../utils/constants\";\nimport swan from \"../../utils/service/swanService\";\nimport speechService from \"../../utils/service/speechService\";\nimport useFaceScan from \"../../customHooks/useFaceScan\";\nimport SpecificButton from \"../../atoms/specificButton/SpecificButton\";\nimport LoadingScreen from \"../LoadingScreen\";\n\nexport const FaceScan: React.FC<FaceScanProps> = ({\n userDetails,\n onComplete,\n onScanError,\n onRetry,\n config,\n}) => {\n const webcamRef = useRef<HTMLVideoElement | null>(null);\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const recordedBlobsRef = useRef<Blob[] | null>([]);\n const streamRef = useRef<MediaStream | null>(null);\n const [showLoader, setShowLoader] = useState(false);\n const [modelReady, setModelReady] = useState(false);\n const [isScanning, setIsScanning] = useState(false);\n const [showGuideCard, setShowGuideCard] = useState(true);\n const [videoLoading, setVideoLoading] = useState(false);\n const [videoError, setVideoError] = useState(false);\n const [hasError, setHasError] = useState(false);\n const [faceScanId, setFaceScanId] = useState(generateUuid());\n const resolvedConfig = useLocalConfig(config);\n const { email, gender, deviceFocalLength, shopDomain, callbackUrl } =\n userDetails;\n\n console.log(recordedBlobsRef.current, \"recoridng\");\n const supportedTypes = useMemo(\n () => videoTypes.filter((type) => MediaRecorder.isTypeSupported(type)),\n []\n );\n\n const stopRecording = useCallback(() => {\n console.log(\"Stopping recording...\");\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state === \"recording\"\n ) {\n mediaRecorderRef.current.stop();\n }\n mediaRecorderRef.current = null;\n }, []);\n\n const uploadFinalVideo = async () => {\n setShowLoader(true);\n console.log(\"upload final video\");\n if (recordedBlobsRef.current) {\n if (recordedBlobsRef.current.length === 0) {\n console.error(\"No video data recorded\");\n setHasError(true);\n setShowLoader(false);\n\n return;\n }\n\n const videoFile = new File(\n recordedBlobsRef.current,\n `${faceScanId}.webm`,\n {\n type: \"video/webm\",\n }\n );\n const fileSize = videoFile.size;\n const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);\n const estimatedDuration = Math.round(fileSize / 10000);\n const videoData = {\n video_size_mb: parseFloat(fileSizeMB),\n video_size_bytes: fileSize,\n blob_count: recordedBlobsRef.current.length,\n estimated_duration_seconds: estimatedDuration,\n };\n\n const metaData = [\n { gender: gender },\n { face_scan_id: faceScanId },\n {\n focal_length: `${deviceFocalLength}`,\n },\n { customer_store_url: shopDomain },\n { scan_type: \"face_scan\" },\n { callback_url: callbackUrl },\n ];\n console.log(metaData, \"metadata\");\n console.log(videoData);\n\n handleScanTimeCapture({\n eventName: `${shopDomain}/face_scan_meta_data`,\n faceScanId,\n email,\n data: JSON.stringify({ metaData, videoData }),\n });\n\n const uploadStartTime = Date.now();\n handleScanTimeCapture({\n eventName: `${shopDomain}/face_scan_upload_start`,\n faceScanId,\n email,\n startTime: uploadStartTime,\n });\n\n try {\n const res = await swan.fileUpload.faceScanFileUploader({\n file: videoFile,\n objectKey: faceScanId,\n email,\n arrayMetaData: metaData,\n contentType: videoFile.type,\n });\n\n const uploadEndTime = Date.now();\n const uploadDuration = uploadEndTime - uploadStartTime;\n\n handleScanTimeCapture({\n eventName: `${shopDomain}/face_scan_upload_complete`,\n faceScanId,\n email,\n completionTime: uploadEndTime,\n uploadDuration,\n });\n\n console.log(\"✅ Upload successful\", res);\n swan.measurement.handlFaceScaneSocket({\n faceScanId,\n onOpen: () => {\n handleWebSocketCapture({\n eventName: `${shopDomain}/webSocket`,\n faceScanID: faceScanId,\n connection: \"open\",\n type: \"faceScan_recommendation\",\n email,\n });\n console.log(\"websocket connect open\");\n },\n onError: (err) => {\n handleWebSocketCapture({\n eventName: `${shopDomain}/webSocket`,\n faceScanID: faceScanId,\n connection: \"error\",\n type: \"faceScan_recommendation\",\n email,\n });\n onError(err);\n },\n onSuccess: (data) => {\n handleWebSocketCapture({\n eventName: `${shopDomain}/webSocket`,\n faceScanID: faceScanId,\n connection: \"success\",\n type: \"faceScan_recommendation\",\n email,\n });\n onSuccess(data);\n },\n onClose: () => {\n console.log(\"websocket connect close\");\n handleWebSocketCapture({\n eventName: `${shopDomain}/webSocket`,\n faceScanID: faceScanId,\n connection: \"close\",\n type: \"faceScan_recommendation\",\n email,\n });\n },\n });\n } catch (error) {\n onError(error);\n }\n }\n };\n\n const startRecording = useCallback(() => {\n console.log(\"Starting recording for stages 1-3...\");\n const stream = webcamRef.current?.srcObject as MediaStream | null;\n if (!stream) return;\n\n // Create a canvas to normalize orientation\n const videoTrack = stream.getVideoTracks()[0];\n const settings = videoTrack.getSettings();\n const { width = videoConstraints.width, height = videoConstraints.height } =\n settings;\n\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n\n // Always force portrait (swap width/height if landscape)\n if (width > height) {\n canvas.width = height;\n canvas.height = width;\n } else {\n canvas.width = width;\n canvas.height = height;\n }\n\n const videoEl = document.createElement(\"video\");\n videoEl.srcObject = stream;\n videoEl.muted = true;\n videoEl.playsInline = true;\n videoEl.play();\n\n // Draw video frames onto canvas\n const drawFrame = () => {\n // Rotate if camera gives landscape frames\n if (width > height) {\n ctx?.save();\n ctx?.translate(canvas.width, 0);\n ctx?.rotate(Math.PI / 2);\n ctx?.drawImage(videoEl, 0, 0, height, width);\n ctx?.restore();\n } else {\n ctx?.drawImage(videoEl, 0, 0, width, height);\n }\n requestAnimationFrame(drawFrame);\n };\n drawFrame();\n\n // Capture portrait-normalized stream\n const canvasStream = canvas.captureStream(30); // 30fps\n const mediaRecorderOptions =\n supportedTypes.length > 0 ? { mimeType: supportedTypes[0] } : {};\n let mediaRecorder;\n\n try {\n mediaRecorder = new MediaRecorder(canvasStream, mediaRecorderOptions);\n } catch (e) {\n console.error(\"MediaRecorder init failed:\", e);\n setHasError(true);\n setShowLoader(false);\n return;\n }\n\n recordedBlobsRef.current = [];\n mediaRecorder.ondataavailable = (event) => {\n if (event?.data && event.data.size > 0 && recordedBlobsRef.current) {\n recordedBlobsRef.current.push(event.data);\n }\n };\n mediaRecorder.onstop = () => {\n console.log(\n \"Recording stopped, total blobs:\",\n recordedBlobsRef?.current?.length\n );\n uploadFinalVideo();\n };\n\n mediaRecorder.start(100); // 100ms chunks\n mediaRecorderRef.current = mediaRecorder;\n console.log(\"Recording started successfully (portrait normalized)\");\n }, [supportedTypes, uploadFinalVideo]);\n\n const {\n faceScanDetector,\n scanStage,\n setScanStage,\n resetScan,\n isModelLoaded,\n startScanSequence,\n } = useFaceScan({\n faceScanId,\n shopDomain,\n onScanComplete: () => {\n stopRecording();\n },\n onModelReady: () => {\n setModelReady(true);\n },\n onStartRecording: () => {\n console.log(\"Stage 0 completed - starting recording for stages 1-3\");\n startRecording();\n },\n });\n\n const startScan = useCallback(() => {\n if (!isModelLoaded) return;\n setScanStage(0);\n speechService.playAudio(\n `${voiceOverAssetsPath}face-scan-vos/Face-forward.mp3`\n );\n setTimeout(() => {\n setIsScanning(true);\n setTimeout(() => {\n startScanSequence();\n }, 200);\n }, 200);\n }, [setScanStage, setIsScanning, startScanSequence, isModelLoaded]);\n\n const resetScanState = useCallback(() => {\n setIsScanning(false);\n setShowGuideCard(true);\n stopRecording();\n resetScan();\n onRetry?.();\n recordedBlobsRef.current = [];\n if (mediaRecorderRef.current) {\n mediaRecorderRef.current = null;\n }\n setHasError(false);\n setScanStage(-1);\n setFaceScanId(generateUuid());\n if (webcamRef.current && streamRef.current) {\n webcamRef.current.srcObject = streamRef.current;\n console.log(\"Camera stream restored after reset\");\n }\n }, [\n setScanStage,\n setIsScanning,\n setShowGuideCard,\n stopRecording,\n resetScan,\n setFaceScanId,\n ]);\n\n const onError = (data: any) => {\n console.log(data, \"ws error\");\n onScanError?.(data);\n setHasError(true);\n setShowLoader(false);\n setShowGuideCard(false);\n handleScanTimeCapture({\n eventName: `${shopDomain}/faceScan`,\n faceScanId,\n status: \"failed\",\n email,\n data: JSON.stringify(data),\n });\n };\n\n const onSuccess = (data: any) => {\n console.log(data, \"ws success\");\n if (data && data?.resultType === \"intermediate\") {\n handleScanTimeCapture({\n eventName: `${shopDomain}/faceScan_success/intermediate`,\n faceScanId,\n status: \"success\",\n email,\n data: JSON.stringify(data),\n });\n }\n onComplete?.(data);\n };\n\n // Initialize webcam\n useEffect(() => {\n if (navigator.mediaDevices.getUserMedia) {\n navigator.mediaDevices\n .getUserMedia({ video: videoConstraints })\n .then((stream) => {\n streamRef.current = stream;\n if (webcamRef.current) {\n webcamRef.current.srcObject = stream;\n console.log(\"Webcam initialized\");\n }\n })\n .catch((err) => console.error(\"Error accessing webcam:\", err));\n }\n\n // Cleanup function\n return () => {\n if (streamRef.current) {\n streamRef.current.getTracks().forEach((track) => track.stop());\n }\n };\n }, []);\n\n // Face detection interval - only run when scanning is active\n useEffect(() => {\n if (!modelReady || !isScanning) return;\n\n const intervalId = setInterval(() => {\n faceScanDetector(webcamRef, canvasRef);\n }, 500);\n\n // eslint-disable-next-line consistent-return\n return () => clearInterval(intervalId);\n }, [faceScanDetector, modelReady, isScanning]);\n\n const getButtonText = () => {\n if (isScanning) return \"Reset\";\n if (!isModelLoaded) return \"Loading...\";\n return \"Start\";\n };\n\n console.log(\n \"Model ready:\",\n modelReady,\n \"Has error:\",\n hasError,\n \"Is scanning:\",\n isScanning,\n \"showLoader\",\n showLoader\n );\n\n useEffect(() => {\n setScanStage(-1);\n posthog.init(posthogPublicKey, { api_host: posthogPublicHost });\n posthog.capture(\"$pageview\");\n }, []);\n\n return (\n <>\n <audio\n id=\"audioElement\"\n crossOrigin=\"anonymous\"\n preload=\"auto\"\n style={{ position: \"absolute\", zIndex: -99999 }}\n src=\"\"\n />\n\n {showLoader && !hasError && (\n <div\n className=\"fixed z-[9] w-full h-full\"\n style={{ background: resolvedConfig?.style?.base?.primaryColor }}\n >\n {/* <Asset genderType={gender} /> */}\n <LoadingScreen />\n </div>\n )}\n\n {/* Always show camera view */}\n <div\n className=\"h-full flex-col relative w-full flex justify-center items-center text-center rounded-t-[20px]\"\n style={{ background: resolvedConfig?.style?.base?.backgroundColor }}\n >\n <div className=\"flex-1 w-full max-w-md overflow-hidden\">\n <div className=\"w-full h-full\">\n <video\n ref={webcamRef}\n autoPlay\n playsInline\n muted\n width={videoConstraints.width}\n height={videoConstraints.height}\n className=\"w-full h-full object-cover fixed left-0 top-0 z-0\"\n style={{ transform: \"scaleX(-1)\" }}\n />\n <canvas\n ref={canvasRef}\n width={videoConstraints.width}\n height={videoConstraints.height}\n style={{ transform: \"scaleX(-1)\", opacity: \"0\" }}\n />\n </div>\n </div>\n </div>\n\n {/* Error overlay */}\n {!showLoader && hasError && (\n <FaceScanErrorScreen\n loading={showLoader}\n resetScanState={resetScanState}\n config={resolvedConfig}\n />\n )}\n\n {/* Scan guide drawer - only show when scanning */}\n {showGuideCard && !hasError && !showLoader && (\n <Drawer\n open\n className=\"face-scan-small camera-draw\"\n anchor=\"bottom\"\n onClose={(event, reason) => {\n if (reason === \"backdropClick\") {\n return;\n }\n }}\n hideBackdrop\n >\n <FaceScanGuide\n stage={scanStage}\n videoLoading={videoLoading}\n setVideoLoading={setVideoLoading}\n videoError={videoError}\n setVideoError={setVideoError}\n gender={gender}\n config={resolvedConfig}\n >\n <div className=\"flex justify-center w-full p-[1rem]\">\n <SpecificButton\n disabled={showLoader || !isModelLoaded}\n className=\"!w-[60px] !h-[35px] !py-0 !px-0\"\n buttonText={getButtonText()}\n postfixIcon={isScanning ? <ArrowRight /> : \"\"}\n buttonFunc={isScanning ? resetScanState : startScan}\n resolvedConfig={resolvedConfig}\n />\n </div>\n </FaceScanGuide>\n </Drawer>\n )}\n </>\n );\n};\n"],"names":["FaceScanGuide","stage","videoLoading","setVideoLoading","videoError","setVideoError","children","gender","config","_jsxs","className","style","background","base","backgroundColor","_jsx","Header","noTitle","resolvedConfig","fontFamily","heading","headingFontFamily","fontSize","headingFontSize","color","headingColor","fontWeight","headingFontWeight","subheading","subheadingFontFamily","subheadingFontSize","subheadingColor","subheadingFontWeight","src","GenderType","Male","maleGlassesOffVideo","glassesOffVideo","autoPlay","loop","controls","muted","playsInline","onCanPlay","onLoadStart","onError","directionMessages","FACE_SCAN_HEADSHOT","male","forward","female","type","left","right","smile","FaceScanErrorScreen","resetScanState","loading","SpecificButton","disabled","buttonText","postfixIcon","ArrowRight","buttonFunc","preloadedDetector","useFaceScan","faceScanId","onValidPose","onScanComplete","onModelReady","onStartRecording","shopDomain","detectorRef","useRef","scanStage","setScanStage","useState","consecutiveValid","setConsecutiveValid","isModelLoaded","setIsModelLoaded","isScanningActive","setIsScanningActive","utteranceRef","scanStageRef","consecutiveValidRef","validityBufferRef","lastSpokenMessageRef","lastSpokenTimeRef","voiceEnabledRef","lastPoseTrackingTimeRef","isIOS","test","navigator","userAgent","platform","maxTouchPoints","useMemo","debouncedTrackPoseDetection","fn","delay","timer","args","clearTimeout","setTimeout","debounce","payload","posthog","capture","trackPoseDetection","useCallback","faceKeypoints","bodyKeypoints","headValid","bodyInvalid","consecutiveValidCount","now","Date","current","nose","leftEye","rightEye","leftMouth","rightMouth","faceKeypointScores","map","kp","filter","score","avgFaceScore","length","reduce","a","b","bodyKeypointScores","avgBodyScore","eyeDistance","Math","abs","noseToRight","noseToLeft","expectedPosition","timestamp","toISOString","data","JSON","stringify","parseFloat","toFixed","faceKeypointsDetected","bodyKeypointsDetected","noseToRightRatio","noseToLeftRatio","noseScore","leftEyeScore","rightEyeScore","leftMouthScore","rightMouthScore","error","console","warn","startScanSequence","stageName","initializeModels","async","log","setBackend","ready","detector","poseDetection","createDetector","SupportedModels","BlazePose","runtime","modelType","dummyCanvas","document","createElement","width","videoConstraints","height","ctx","getContext","fillStyle","fillRect","estimatePoses","e","preloadDetector","err","useEffect","dispose","disposeModelAndTf","faceScanDetector","webcamRef","canvasRef","poses","keypoints","forEach","landmark","idx","point","x","y","push","clearRect","progress","min","radius","beginPath","strokeStyle","lineWidth","arc","PI","stroke","eyesToMouthVerticalDistance","faceTiltedness","faceIsTilted","faceIsVertical","frontalFace","fullLeft","fullRight","isHeadInPosition","slice","p","shift","Boolean","nextValid","max","nextStage","speechService","playAudio","voiceOverAssetsPath","completedStage","totalStages","nextSound","resetScan","speechSynthesis","cancel","enableVoiceCommands","window","silentUtterance","SpeechSynthesisUtterance","volume","speak","userDetails","onComplete","onScanError","onRetry","mediaRecorderRef","recordedBlobsRef","streamRef","showLoader","setShowLoader","modelReady","setModelReady","isScanning","setIsScanning","showGuideCard","setShowGuideCard","hasError","setHasError","setFaceScanId","generateUuid","useLocalConfig","email","deviceFocalLength","callbackUrl","supportedTypes","videoTypes","MediaRecorder","isTypeSupported","stopRecording","state","stop","uploadFinalVideo","videoFile","File","fileSize","size","fileSizeMB","estimatedDuration","round","videoData","video_size_mb","video_size_bytes","blob_count","estimated_duration_seconds","metaData","face_scan_id","focal_length","customer_store_url","scan_type","callback_url","handleScanTimeCapture","eventName","uploadStartTime","startTime","res","swan","fileUpload","faceScanFileUploader","file","objectKey","arrayMetaData","contentType","uploadEndTime","uploadDuration","completionTime","measurement","handlFaceScaneSocket","onOpen","handleWebSocketCapture","faceScanID","connection","onSuccess","onClose","startRecording","stream","srcObject","settings","getVideoTracks","getSettings","canvas","videoEl","play","drawFrame","save","translate","rotate","drawImage","restore","requestAnimationFrame","canvasStream","captureStream","mediaRecorderOptions","mimeType","mediaRecorder","ondataavailable","event","onstop","start","startScan","status","resultType","mediaDevices","getUserMedia","video","then","catch","getTracks","track","intervalId","setInterval","clearInterval","init","posthogPublicKey","api_host","posthogPublicHost","id","crossOrigin","preload","position","zIndex","primaryColor","LoadingScreen","ref","transform","opacity","Drawer","open","anchor","reason","hideBackdrop"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{jsxs as e,jsx as t,Fragment as a}from"react/jsx-runtime";import{useRef as n,useState as o,useMemo as r,useCallback as c,useEffect as l}from"react";import{ae as s,ay as i,az as d,a9 as u,aA as h,aB as m,S as f,aC as g,aD as p,aE as y,aF as S,aa as b,aG as w,aH as v,aI as x,aJ as F,aK as N}from"./Header-vfreHFif.js";import{A as I}from"./arrow-right-BqMp5VTz.js";import{s as _,L as k,D as M,a as D}from"./LoadingScreen-CmttLMLy.js";import*as z from"@tensorflow-models/pose-detection";import{setBackend as C,ready as P}from"@tensorflow/tfjs";import"react-dom";function T({stage:a,videoLoading:n,setVideoLoading:o,videoError:r,setVideoError:c,children:l,gender:f,config:g}){return-1===a?e("div",{className:"text-center p-[16px] w-full h-full",style:{background:g?.style?.base?.backgroundColor},children:[e("div",{className:"w-full",children:[t(s,{noTitle:!0,resolvedConfig:g}),e("h2",{style:{fontFamily:g?.style?.heading?.headingFontFamily||"SeriouslyNostalgic Fn",fontSize:g?.style?.heading?.headingFontSize||"32px",color:g?.style?.heading?.headingColor||"#000",fontWeight:g?.style?.heading?.headingFontWeight||"normal"},children:["Make sure your face is fully visible"," "]}),n&&t("div",{className:"mb-4 flex items-center justify-center",style:{fontFamily:g?.style?.subheading?.subheadingFontFamily||"'Inter', sans-serif",fontSize:g?.style?.subheading?.subheadingFontSize||"14px",color:g?.style?.subheading?.subheadingColor||"#4b5563",fontWeight:g?.style?.subheading?.subheadingFontWeight||"normal"},children:"Loading video..."}),r&&t("div",{className:"mb-4 text-red-600",style:{fontFamily:g?.style?.subheading?.subheadingFontFamily||"'Inter', sans-serif",fontSize:g?.style?.subheading?.subheadingFontSize||"14px",color:"#ff0000",fontWeight:g?.style?.subheading?.subheadingFontWeight||"normal"},children:"Video failed to load. Please refresh the page or check your connection."}),!r&&t("div",{className:" w-[100px] mx-auto",children:t("video",{src:f===u.Male?i:d,autoPlay:!0,loop:!0,controls:!1,muted:!0,playsInline:!0,className:"h-full w-full object-contain border-none",onCanPlay:()=>o(!1),onLoadStart:()=>o(!0),onError:()=>c(!0),"aria-label":"Instructional video: Please remove your glasses before starting the scan."})})]}),l]}):t("div",{className:"text-center p-[16px] w-full h-full",style:{background:g?.style?.base?.backgroundColor},children:e("div",{className:"w-full",children:[t(s,{noTitle:!0,resolvedConfig:g}),t("h3",{className:"mb-[0.5rem]",style:{fontFamily:g?.style?.heading?.headingFontFamily||"SeriouslyNostalgic Fn",fontSize:g?.style?.heading?.headingFontSize||"32px",color:g?.style?.heading?.headingColor||"#000",fontWeight:g?.style?.heading?.headingFontWeight||"normal"},children:h[a]}),e("div",{className:"max-w-[400px] justify-center gap-1 mx-auto flex items-center",children:[t("div",{className:` w-[120px] overflow-hidden ${0===a?"opacity-100":"opacity-0 hidden"} `,children:t("video",{className:"h-full w-full object-contain border-none",muted:!0,loop:!0,autoPlay:!0,playsInline:!0,children:t("source",{src:f===u.Male?m.male.forward:m.female.forward,type:"video/mp4"})})}),t("div",{className:` w-[120px] overflow-hidden ${1===a?"opacity-100":"opacity-0 hidden"} `,children:t("video",{className:"h-full w-full object-contain border-none",muted:!0,loop:!0,autoPlay:!0,playsInline:!0,children:t("source",{src:f===u.Male?m.male.left:m.female.left,type:"video/mp4"})})}),t("div",{className:` w-[120px] overflow-hidden ${2===a?"opacity-100":"opacity-0 hidden"} `,children:t("video",{className:"h-full w-full object-contain border-none",muted:!0,loop:!0,autoPlay:!0,playsInline:!0,children:t("source",{src:f===u.Male?m.male.right:m.female.right,type:"video/mp4"})})}),t("div",{className:` w-[120px] overflow-hidden ${3===a?"opacity-100":"opacity-0 hidden"} `,children:t("video",{className:"h-full w-full object-contain border-none",muted:!0,loop:!0,autoPlay:!0,playsInline:!0,children:t("source",{src:f===u.Male?m.male.smile:m.female.smile,type:"video/mp4"})})})]})]})})}function $({resetScanState:a,loading:n,config:o}){return t("div",{className:"fixed top-[0] left-[0] z-[999] flex justify-center items-center w-full h-full",style:{background:o?.style?.base?.backgroundColor},children:e("div",{className:"flex flex-col w-full items-center p-[1rem] rounded-lg ",children:[t(s,{noTitle:!0,resolvedConfig:o}),e("div",{className:"flex flex-col items-center w-full",children:[t("h2",{className:"text-xl font-semibold text-gray-800 ",style:{fontFamily:o?.style?.heading?.headingFontFamily||"SeriouslyNostalgic Fn",fontSize:o?.style?.heading?.headingFontSize||"32px",color:o?.style?.heading?.headingColor||"#000",fontWeight:o?.style?.heading?.headingFontWeight||"normal"},children:"Your Scan Failed"}),t("p",{className:"mb-[1.5rem]",style:{fontFamily:o?.style?.subheading?.subheadingFontFamily||"'Inter', sans-serif",fontSize:o?.style?.subheading?.subheadingFontSize||"14px",color:o?.style?.subheading?.subheadingColor||"#4b5563",fontWeight:o?.style?.subheading?.subheadingFontWeight||"normal"},children:"Please click below to reset your scan."}),t(f,{disabled:n,className:"w-full h-[45px] shadow-[0px_1px_2px_0px_#00000040] text-[16px]",buttonText:"Reset Scan",postfixIcon:t(I,{}),buttonFunc:()=>a(),resolvedConfig:o})]})]})})}let j=null;function E({faceScanId:e,onValidPose:t,onScanComplete:a,onModelReady:s,onStartRecording:i,shopDomain:d}){const u=n(null),[h,m]=o(0),[f,S]=o(0),[b,w]=o(!1),[v,x]=o(!1),F=n(null),N=n(h),I=n(f),k=n([]),M=n(""),D=n(0),T=n(!1),$=n(0),E=/iPad|iPhone|iPod/.test(navigator.userAgent)||"MacIntel"===navigator.platform&&navigator.maxTouchPoints>1,R=r(()=>["Face front","Turn head fully left","Turn head fully right","Smile facing front"],[]),L=r(()=>function(e,t){let a;return(...n)=>{a&&clearTimeout(a),a=setTimeout(()=>e(...n),t)}}(e=>{g.capture(`${d}/face_scan_pose_detection`,e)},4e3),[d]),O=c((t,a,n,o,r,c)=>{const l=Date.now();if(!(l-$.current<4e3)){$.current=l;try{const l=t[0]||[0,0,0],s=t[2]||[0,0,0],i=t[5]||[0,0,0],d=t[9]||[0,0,0],u=t[10]||[0,0,0],h=t.map(e=>e[2]).filter(e=>e>0),m=h.length>0?h.reduce((e,t)=>e+t,0)/h.length:0,f=a.map(e=>e[2]).filter(e=>e>0),g=f.length>0?f.reduce((e,t)=>e+t,0)/f.length:0,p=Math.abs(s[0]-i[0]),y=l[0]-i[0],S=s[0]-l[0];let b="frontal";1===n?b="left":2===n?b="right":3===n&&(b="frontal_smile");const w={faceScanId:e,stage:n,timestamp:(new Date).toISOString(),data:JSON.stringify({headValid:o,bodyInvalid:r,consecutiveValid:c,avgFaceScore:parseFloat(m.toFixed(3)),avgBodyScore:parseFloat(g.toFixed(3)),faceKeypointsDetected:h.length,bodyKeypointsDetected:f.length,eyeDistance:parseFloat(p.toFixed(2)),noseToRightRatio:parseFloat((y/p).toFixed(3)),noseToLeftRatio:parseFloat((S/p).toFixed(3)),noseScore:parseFloat(l[2].toFixed(3)),leftEyeScore:parseFloat(s[2].toFixed(3)),rightEyeScore:parseFloat(i[2].toFixed(3)),leftMouthScore:parseFloat(d[2].toFixed(3)),rightMouthScore:parseFloat(u[2].toFixed(3)),expectedPosition:b})};L(w)}catch(e){console.warn("Failed to track pose detection:",e)}}},[e,L]),W=()=>{g.capture(`${d}/face_scan_detection_started`,{faceScanId:e,stage:N.current,timestamp:(new Date).toISOString(),stageName:R[N.current]}),setTimeout(()=>{x(!0)},1500)},V=async()=>{try{console.log("Initializing TensorFlow..."),await C("webgl"),await P(),console.log("TensorFlow initialized, loading models...");const e=await(async()=>{if(j)return j;const e=await z.createDetector(z.SupportedModels.BlazePose,{runtime:"tfjs",modelType:"full"}),t=document.createElement("canvas");t.width=y.width,t.height=y.height;const a=t.getContext("2d");a&&(a.fillStyle="black",a.fillRect(0,0,t.width,t.height));try{await e.estimatePoses(t)}catch(e){console.log(e,"at time of preload")}return j=e,e})();console.log(e,"detector"),u.current=e,console.log("Pose detection model loaded successfully"),w(!0),s?.()}catch(e){console.error("Error initializing face scan:",e)}};return l(()=>(V(),()=>{(async()=>{try{w(!1),u.current&&(await u.current.dispose(),u.current=null)}catch(e){console.error("Error disposing resources:",e)}finally{m(0),S(0),N.current=0,I.current=0,k.current=[]}})()}),[]),l(()=>{N.current=h},[h]),l(()=>{I.current=f},[f]),{faceScanDetector:async(n,o)=>{if(u.current&&n.current&&b&&v)try{const r=await u.current.estimatePoses(n.current);if(r.length>0){const n=[],c=[];if(r[0].keypoints.forEach((e,t)=>{const a=e.score??0,o=[e.x??-1,e.y??-1,a];t<=10?n.push(o):c.push(o)}),o?.current){const e=o.current.getContext("2d"),{width:t,height:a}=o.current;if(e){e.clearRect(0,0,t,a);const n=Math.min(I.current/2,1),o=.35*a;e.beginPath(),e.strokeStyle="#00ff00",e.lineWidth=6,e.arc(t/2,a/2,o+10,-Math.PI/2,-Math.PI/2+2*n*Math.PI),e.stroke()}}const l=((e,t)=>{if(t[0][2]<.2||t[2][2]<.2||t[5][2]<.2)return!1;const a=.5*(t[10][1]+t[9][1])-.5*(t[5][1]+t[2][1]),n=(.5*(t[10][1]+t[9][1])-t[0][1])/a,o=n>.7||n<.3,r=Math.abs(t[2][1]-t[5][1])<.5*a&&Math.abs(t[9][1]-t[10][1])<.5*a,c=t[2][0]-t[5][0],l=t[0][0]-t[5][0],s=l>.4*c&&l<.6*c,i=l>.85*c,d=t[2][0]-t[0][0]>.85*c;switch(e){case 0:case 3:return!o&&r&&s;case 1:return!o&&r&&i;case 2:return!o&&r&&d;default:return!1}})(N.current,n),s=c.slice(2).filter(e=>e[2]>.7).length<=2;k.current.push(l&&s),k.current.length>10&&k.current.shift();if(k.current.filter(Boolean).length>=2){const e=I.current+1;S(e)}else S(Math.max(0,I.current-1));if(I.current>=2){t?.();const n=N.current+1;S(0),k.current=[],m(n),x(!1),(async()=>{if(await _.playAudio(`${p}face-scan-vos/Sound-effect.mp3`),g.capture(`${d}/face_scan_detection_stage_completed`,{faceScanId:e,completedStage:N.current,nextStage:n,timestamp:(new Date).toISOString(),totalStages:4,stageName:R[N.current]}),1===n&&i&&i(),n>=4)a?.();else{let e=null;switch(n){case 1:e="Left.mp3";break;case 2:e="Right.mp3";break;case 3:e="Smile.mp3";break;default:e=null}e&&await _.playAudio(`${p}face-scan-vos/${e}`),W()}})()}O(n,c,N.current,l,s,I.current)}}catch(e){console.error("Pose detection error:",e)}},scanStage:h,setScanStage:m,consecutiveValid:f,isModelLoaded:b,resetScan:()=>{g.capture(`${d}/face_scan_reset`,{faceScanId:e,stage:N.current,timestamp:(new Date).toISOString(),stageName:R[N.current],consecutiveValid:I.current}),m(0),S(0),x(!1),N.current=0,I.current=0,k.current=[],M.current="",D.current=0,T.current=!1,F.current&&(speechSynthesis.cancel(),F.current=null)},enableVoiceCommands:()=>{if(T.current=!0,E&&"speechSynthesis"in window){const e=new SpeechSynthesisUtterance("");e.volume=0,speechSynthesis.speak(e)}},startScanSequence:W,isScanningActive:v}}const R=({userDetails:s,onComplete:i,onScanError:d,onRetry:u,config:h})=>{const m=n(null),z=n(null),C=n(null),P=n([]),j=n(null),[R,L]=o(!1),[O,W]=o(!1),[V,A]=o(!1),[U,B]=o(!0),[J,K]=o(!1),[q,H]=o(!1),[X,G]=o(!1),[Y,Q]=o(S()),Z=b(h),{email:ee,gender:te,deviceFocalLength:ae,shopDomain:ne,callbackUrl:oe}=s;console.log(P.current,"recoridng");const re=r(()=>w.filter(e=>MediaRecorder.isTypeSupported(e)),[]),ce=c(()=>{console.log("Stopping recording..."),C.current&&"recording"===C.current.state&&C.current.stop(),C.current=null},[]),le=async()=>{if(L(!0),console.log("upload final video"),P.current){if(0===P.current.length)return console.error("No video data recorded"),G(!0),void L(!1);const e=new File(P.current,`${Y}.webm`,{type:"video/webm"}),t=e.size,a=(t/1048576).toFixed(2),n=Math.round(t/1e4),o={video_size_mb:parseFloat(a),video_size_bytes:t,blob_count:P.current.length,estimated_duration_seconds:n},r=[{gender:te},{face_scan_id:Y},{focal_length:`${ae}`},{customer_store_url:ne},{scan_type:"face_scan"},{callback_url:oe}];console.log(r,"metadata"),console.log(o),F({eventName:`${ne}/face_scan_meta_data`,faceScanId:Y,email:ee,data:JSON.stringify({metaData:r,videoData:o})});const c=Date.now();F({eventName:`${ne}/face_scan_upload_start`,faceScanId:Y,email:ee,startTime:c});try{const t=await D.fileUpload.faceScanFileUploader({file:e,objectKey:Y,email:ee,arrayMetaData:r,contentType:e.type}),a=Date.now();F({eventName:`${ne}/face_scan_upload_complete`,faceScanId:Y,email:ee,completionTime:a,uploadDuration:a-c}),console.log("✅ Upload successful",t),D.measurement.handlFaceScaneSocket({faceScanId:Y,onOpen:()=>{N({eventName:`${ne}/webSocket`,faceScanID:Y,connection:"open",type:"faceScan_recommendation",email:ee}),console.log("websocket connect open")},onError:e=>{N({eventName:`${ne}/webSocket`,faceScanID:Y,connection:"error",type:"faceScan_recommendation",email:ee}),ye(e)},onSuccess:e=>{N({eventName:`${ne}/webSocket`,faceScanID:Y,connection:"success",type:"faceScan_recommendation",email:ee}),Se(e)},onClose:()=>{console.log("websocket connect close"),N({eventName:`${ne}/webSocket`,faceScanID:Y,connection:"close",type:"faceScan_recommendation",email:ee})}})}catch(e){ye(e)}}},se=c(()=>{console.log("Starting recording for stages 1-3...");const e=m.current?.srcObject;if(!e)return;const t=e.getVideoTracks()[0].getSettings(),{width:a=y.width,height:n=y.height}=t,o=document.createElement("canvas"),r=o.getContext("2d");a>n?(o.width=n,o.height=a):(o.width=a,o.height=n);const c=document.createElement("video");c.srcObject=e,c.muted=!0,c.playsInline=!0,c.play();const l=()=>{a>n?(r?.save(),r?.translate(o.width,0),r?.rotate(Math.PI/2),r?.drawImage(c,0,0,n,a),r?.restore()):r?.drawImage(c,0,0,a,n),requestAnimationFrame(l)};l();const s=o.captureStream(30),i=re.length>0?{mimeType:re[0]}:{};let d;try{d=new MediaRecorder(s,i)}catch(e){return console.error("MediaRecorder init failed:",e),G(!0),void L(!1)}P.current=[],d.ondataavailable=e=>{e?.data&&e.data.size>0&&P.current&&P.current.push(e.data)},d.onstop=()=>{console.log("Recording stopped, total blobs:",P?.current?.length),le()},d.start(100),C.current=d,console.log("Recording started successfully (portrait normalized)")},[re,le]),{faceScanDetector:ie,scanStage:de,setScanStage:ue,resetScan:he,isModelLoaded:me,startScanSequence:fe}=E({faceScanId:Y,shopDomain:ne,onScanComplete:()=>{ce()},onModelReady:()=>{W(!0)},onStartRecording:()=>{console.log("Stage 0 completed - starting recording for stages 1-3"),se()}}),ge=c(()=>{me&&(ue(0),_.playAudio(`${p}face-scan-vos/Face-forward.mp3`),setTimeout(()=>{A(!0),setTimeout(()=>{fe()},200)},200))},[ue,A,fe,me]),pe=c(()=>{A(!1),B(!0),ce(),he(),u?.(),P.current=[],C.current&&(C.current=null),G(!1),ue(-1),Q(S()),m.current&&j.current&&(m.current.srcObject=j.current,console.log("Camera stream restored after reset"))},[ue,A,B,ce,he,Q]),ye=e=>{console.log(e,"ws error"),d?.(e),G(!0),L(!1),B(!1),F({eventName:`${ne}/faceScan`,faceScanId:Y,status:"failed",email:ee,data:JSON.stringify(e)})},Se=e=>{console.log(e,"ws success"),e&&"intermediate"===e?.resultType&&F({eventName:`${ne}/faceScan_success/intermediate`,faceScanId:Y,status:"success",email:ee,data:JSON.stringify(e)}),i?.(e)};l(()=>(navigator.mediaDevices.getUserMedia&&navigator.mediaDevices.getUserMedia({video:y}).then(e=>{j.current=e,m.current&&(m.current.srcObject=e,console.log("Webcam initialized"))}).catch(e=>console.error("Error accessing webcam:",e)),()=>{j.current&&j.current.getTracks().forEach(e=>e.stop())}),[]),l(()=>{if(!O||!V)return;const e=setInterval(()=>{ie(m,z)},500);return()=>clearInterval(e)},[ie,O,V]);return console.log("Model ready:",O,"Has error:",X,"Is scanning:",V,"showLoader",R),l(()=>{ue(-1),g.init(v,{api_host:x}),g.capture("$pageview")},[]),e(a,{children:[t("audio",{id:"audioElement",crossOrigin:"anonymous",preload:"auto",style:{position:"absolute",zIndex:-99999},src:""}),R&&!X&&t("div",{className:"fixed z-[9] w-full h-full",style:{background:Z?.style?.base?.primaryColor},children:t(k,{})}),t("div",{className:"h-full flex-col relative w-full flex justify-center items-center text-center rounded-t-[20px]",style:{background:Z?.style?.base?.backgroundColor},children:t("div",{className:"flex-1 w-full max-w-md overflow-hidden",children:e("div",{className:"w-full h-full",children:[t("video",{ref:m,autoPlay:!0,playsInline:!0,muted:!0,width:y.width,height:y.height,className:"w-full h-full object-cover fixed left-0 top-0 z-0",style:{transform:"scaleX(-1)"}}),t("canvas",{ref:z,width:y.width,height:y.height,style:{transform:"scaleX(-1)",opacity:"0"}})]})})}),!R&&X&&t($,{loading:R,resetScanState:pe,config:Z}),U&&!X&&!R&&t(M,{open:!0,className:"face-scan-small camera-draw",anchor:"bottom",onClose:(e,t)=>{},hideBackdrop:!0,children:t(T,{stage:de,videoLoading:J,setVideoLoading:K,videoError:q,setVideoError:H,gender:te,config:Z,children:t("div",{className:"flex justify-center w-full p-[1rem]",children:t(f,{disabled:R||!me,className:"!w-[60px] !h-[35px] !py-0 !px-0",buttonText:V?"Reset":me?"Start":"Loading...",postfixIcon:V?t(I,{}):"",buttonFunc:V?pe:ge,resolvedConfig:Z})})})})]})};export{R as FaceScan};
2
+ //# sourceMappingURL=faceScan.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faceScan.mjs","sources":["../src/components/faceScan/FaceScanGuide.tsx","../src/components/faceScan/FaceScanErrorScreen.tsx","../src/customHooks/useFaceScan.ts","../src/components/faceScan/FaceScan.tsx"],"sourcesContent":["\nimport { FaceScanGuideProps } from \"../../types/interfaces\";\nimport Header from \"../Header\";\nimport { GenderType } from \"../../utils/enums\";\nimport { directionMessages, FACE_SCAN_HEADSHOT, glassesOffVideo, maleGlassesOffVideo } from \"../../utils/constants\";\n\n\nfunction FaceScanGuide({\n\tstage,\n\tvideoLoading,\n\tsetVideoLoading,\n\tvideoError,\n\tsetVideoError,\n\tchildren,\n\tgender,\n\tconfig,\n}: FaceScanGuideProps) {\n\tif (stage === -1) {\n\t\treturn (\n\t\t\t<div className=\"text-center p-[16px] w-full h-full\" style={{ background: config?.style?.base?.backgroundColor }}>\n\t\t\t\t<div className=\"w-full\">\n\t\t\t\t\t<Header noTitle resolvedConfig={config} />\n\t\t\t\t\t<h2\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tfontFamily: config?.style?.heading?.headingFontFamily || \"SeriouslyNostalgic Fn\",\n\t\t\t\t\t\t\tfontSize: config?.style?.heading?.headingFontSize || \"32px\",\n\t\t\t\t\t\t\tcolor: config?.style?.heading?.headingColor || \"#000\",\n\t\t\t\t\t\t\tfontWeight: config?.style?.heading?.headingFontWeight || \"normal\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\tMake sure your face is fully visible{\" \"}\n\t\t\t\t\t</h2>\n\t\t\t\t\t{videoLoading && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"mb-4 flex items-center justify-center\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tfontFamily: config?.style?.subheading?.subheadingFontFamily || \"'Inter', sans-serif\",\n\t\t\t\t\t\t\t\tfontSize: config?.style?.subheading?.subheadingFontSize || \"14px\",\n\t\t\t\t\t\t\t\tcolor: config?.style?.subheading?.subheadingColor || \"#4b5563\",\n\t\t\t\t\t\t\t\tfontWeight: config?.style?.subheading?.subheadingFontWeight || \"normal\",\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tLoading video...\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{videoError && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"mb-4 text-red-600\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tfontFamily: config?.style?.subheading?.subheadingFontFamily || \"'Inter', sans-serif\",\n\t\t\t\t\t\t\t\tfontSize: config?.style?.subheading?.subheadingFontSize || \"14px\",\n\t\t\t\t\t\t\t\tcolor: \"#ff0000\",\n\t\t\t\t\t\t\t\tfontWeight: config?.style?.subheading?.subheadingFontWeight || \"normal\",\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tVideo failed to load. Please refresh the page or check your connection.\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{!videoError && (\n\t\t\t\t\t\t<div className={` w-[100px] mx-auto`}>\n\t\t\t\t\t\t\t<video\n\t\t\t\t\t\t\t\tsrc={gender === GenderType.Male ? maleGlassesOffVideo : glassesOffVideo}\n\t\t\t\t\t\t\t\tautoPlay\n\t\t\t\t\t\t\t\tloop\n\t\t\t\t\t\t\t\tcontrols={false}\n\t\t\t\t\t\t\t\tmuted\n\t\t\t\t\t\t\t\tplaysInline\n\t\t\t\t\t\t\t\tclassName=\"h-full w-full object-contain border-none\"\n\t\t\t\t\t\t\t\tonCanPlay={() => setVideoLoading(false)}\n\t\t\t\t\t\t\t\tonLoadStart={() => setVideoLoading(true)}\n\t\t\t\t\t\t\t\tonError={() => setVideoError(true)}\n\t\t\t\t\t\t\t\taria-label=\"Instructional video: Please remove your glasses before starting the scan.\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"text-center p-[16px] w-full h-full\" style={{ background: config?.style?.base?.backgroundColor }}>\n\t\t\t<div className=\"w-full\">\n\t\t\t\t<Header noTitle resolvedConfig={config} />\n\t\t\t\t<h3\n\t\t\t\t\tclassName=\"mb-[0.5rem]\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tfontFamily: config?.style?.heading?.headingFontFamily || \"SeriouslyNostalgic Fn\",\n\t\t\t\t\t\tfontSize: config?.style?.heading?.headingFontSize || \"32px\",\n\t\t\t\t\t\tcolor: config?.style?.heading?.headingColor || \"#000\",\n\t\t\t\t\t\tfontWeight: config?.style?.heading?.headingFontWeight || \"normal\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{directionMessages[stage]}\n\t\t\t\t</h3>\n\t\t\t\t{/* <p>We'll guide you to take 6 selfies </p> */}\n\t\t\t\t<div className=\"max-w-[400px] justify-center gap-1 mx-auto flex items-center\">\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 0 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.forward : FACE_SCAN_HEADSHOT.female.forward} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 1 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.left : FACE_SCAN_HEADSHOT.female.left} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 2 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.right : FACE_SCAN_HEADSHOT.female.right} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 3 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.smile : FACE_SCAN_HEADSHOT.female.smile} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport default FaceScanGuide;\n","import { ArrowRight } from \"lucide-react\";\nimport Header from \"../Header\";\nimport SpecificButton from \"../../atoms/specificButton/SpecificButton\";\n\nfunction FaceScanErrorScreen({ resetScanState, loading, config }: { resetScanState: () => void; loading: boolean; config?: any }) {\n\treturn (\n\t\t<div className=\"fixed top-[0] left-[0] z-[999] flex justify-center items-center w-full h-full\" style={{ background: config?.style?.base?.backgroundColor }}>\n\t\t\t<div className=\"flex flex-col w-full items-center p-[1rem] rounded-lg \">\n\t\t\t\t<Header noTitle resolvedConfig={config} />\n\t\t\t\t<div className=\"flex flex-col items-center w-full\">\n\t\t\t\t\t<h2\n\t\t\t\t\t\tclassName=\"text-xl font-semibold text-gray-800 \"\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tfontFamily: config?.style?.heading?.headingFontFamily || \"SeriouslyNostalgic Fn\",\n\t\t\t\t\t\t\tfontSize: config?.style?.heading?.headingFontSize || \"32px\",\n\t\t\t\t\t\t\tcolor: config?.style?.heading?.headingColor || \"#000\",\n\t\t\t\t\t\t\tfontWeight: config?.style?.heading?.headingFontWeight || \"normal\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\tYour Scan Failed\n\t\t\t\t\t</h2>\n\t\t\t\t\t<p\n\t\t\t\t\t\tclassName=\"mb-[1.5rem]\"\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tfontFamily: config?.style?.subheading?.subheadingFontFamily || \"'Inter', sans-serif\",\n\t\t\t\t\t\t\tfontSize: config?.style?.subheading?.subheadingFontSize || \"14px\",\n\t\t\t\t\t\t\tcolor: config?.style?.subheading?.subheadingColor || \"#4b5563\",\n\t\t\t\t\t\t\tfontWeight: config?.style?.subheading?.subheadingFontWeight || \"normal\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\tPlease click below to reset your scan.\n\t\t\t\t\t</p>\n\t\t\t\t\t<SpecificButton\n\t\t\t\t\t\tdisabled={loading}\n\t\t\t\t\t\tclassName=\"w-full h-[45px] shadow-[0px_1px_2px_0px_#00000040] text-[16px]\"\n\t\t\t\t\t\tbuttonText=\"Reset Scan\"\n\t\t\t\t\t\tpostfixIcon={<ArrowRight />}\n\t\t\t\t\t\tbuttonFunc={() => resetScanState()}\n\t\t\t\t\t\tresolvedConfig={config}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport default FaceScanErrorScreen;\n","import {\n useState,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n RefObject,\n} from \"react\";\nimport * as poseDetection from \"@tensorflow-models/pose-detection\";\nimport \"@tensorflow/tfjs\";\nimport { posthog } from \"posthog-js\";\nimport { ready, setBackend } from \"@tensorflow/tfjs\";\nimport speechService from \"../utils/service/speechService\";\nimport { videoConstraints, voiceOverAssetsPath } from \"../utils/constants\";\n\n/**\n * useFaceScan Hook with PostHog Analytics\n *\n * Analytics Events Tracked:\n * 1. face_scan_pose_detection - Every 4 seconds during scanning\n * - Keypoint scores and positions\n * - Face/body detection metrics\n * - Stage-specific positioning data\n * - Time spent in current stage\n *\n * 2. face_scan_stage_completed - When user successfully completes a stage\n * - Stage transition data\n * - Completion time\n *\n * 3. face_scan_started - When scan sequence begins\n * - Stage information\n * - Start timestamp\n *\n * 4. face_scan_reset - When user resets the scan\n * - Reset reason analysis\n * - Stage where reset occurred\n *\n * This helps identify why users take longer to get detected in pose detection.\n */\n\n// Debounce utility\nfunction debounce(fn: (...args: any) => void, delay: number) {\n let timer: number | NodeJS.Timeout;\n return (...args: any) => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), delay);\n };\n}\n\nlet preloadedDetector: poseDetection.PoseDetector | null = null;\n\nexport const preloadDetector = async () => {\n if (preloadedDetector) return preloadedDetector;\n\n const detector = await poseDetection.createDetector(\n poseDetection.SupportedModels.BlazePose,\n {\n runtime: \"tfjs\",\n modelType: \"full\",\n }\n );\n\n // Dummy video warmup\n const dummyCanvas = document.createElement(\"canvas\");\n dummyCanvas.width = videoConstraints.width;\n dummyCanvas.height = videoConstraints.height;\n const ctx = dummyCanvas.getContext(\"2d\");\n if (ctx) {\n ctx.fillStyle = \"black\";\n ctx.fillRect(0, 0, dummyCanvas.width, dummyCanvas.height);\n }\n try {\n await detector.estimatePoses(dummyCanvas);\n } catch (e) {\n // Expected: empty video stream\n console.log(e, \"at time of preload\");\n }\n\n preloadedDetector = detector;\n return detector;\n};\n\ntype Point = [number, number, number];\n\nfunction useFaceScan({\n faceScanId,\n onValidPose,\n onScanComplete,\n onModelReady,\n onStartRecording,\n shopDomain,\n}: {\n faceScanId: string;\n onValidPose?: () => void;\n onScanComplete?: () => void;\n onModelReady?: () => void;\n onStartRecording: () => void;\n shopDomain: string;\n}) {\n const detectorRef = useRef<poseDetection.PoseDetector | null>(null);\n const [scanStage, setScanStage] = useState(0);\n const [consecutiveValid, setConsecutiveValid] = useState(0);\n const [isModelLoaded, setIsModelLoaded] = useState(false);\n const [isScanningActive, setIsScanningActive] = useState(false);\n const utteranceRef = useRef(null);\n const scanStageRef = useRef(scanStage);\n const consecutiveValidRef = useRef(consecutiveValid);\n const validityBufferRef = useRef<boolean[]>([]);\n const lastSpokenMessageRef = useRef(\"\");\n const lastSpokenTimeRef = useRef(0);\n const voiceEnabledRef = useRef(false);\n const VALIDITY_BUFFER_LENGTH = 10;\n const CONSECUTIVE_VALID_LENGTH = 2;\n const TOTAL_STAGES = 4;\n const POSE_TRACKING_INTERVAL = 4000; // 4 seconds between pose tracking events\n const lastPoseTrackingTimeRef = useRef(0);\n\n // iOS detection\n const isIOS =\n /iPad|iPhone|iPod/.test(navigator.userAgent) ||\n (navigator.platform === \"MacIntel\" && navigator.maxTouchPoints > 1);\n\n const directionMessages = useMemo(\n () => [\n \"Face front\",\n \"Turn head fully left\",\n \"Turn head fully right\",\n \"Smile facing front\",\n ],\n []\n );\n\n // Debounced analytics event\n const debouncedTrackPoseDetection = useMemo(\n () =>\n debounce((payload) => {\n posthog.capture(`${shopDomain}/face_scan_pose_detection`, payload);\n }, 4000),\n [shopDomain]\n );\n\n // Track pose detection performance for analytics\n const trackPoseDetection = useCallback(\n (\n faceKeypoints: Point[],\n bodyKeypoints: Point[],\n stage: number,\n headValid: boolean,\n bodyInvalid: boolean,\n consecutiveValidCount: number\n ) => {\n const now = Date.now();\n\n // Only track every 4 seconds to avoid spam\n if (now - lastPoseTrackingTimeRef.current < POSE_TRACKING_INTERVAL) {\n return;\n }\n\n lastPoseTrackingTimeRef.current = now;\n\n try {\n // Extract key face keypoints for analysis\n const nose = faceKeypoints[0] || [0, 0, 0];\n const leftEye = faceKeypoints[2] || [0, 0, 0];\n const rightEye = faceKeypoints[5] || [0, 0, 0];\n const leftMouth = faceKeypoints[9] || [0, 0, 0];\n const rightMouth = faceKeypoints[10] || [0, 0, 0];\n\n // Calculate key metrics\n const faceKeypointScores = faceKeypoints\n .map((kp: Point) => kp[2])\n .filter((score: number) => score > 0);\n const avgFaceScore =\n faceKeypointScores.length > 0\n ? faceKeypointScores.reduce((a, b) => a + b, 0) /\n faceKeypointScores.length\n : 0;\n\n const bodyKeypointScores = bodyKeypoints\n .map((kp: Point) => kp[2])\n .filter((score: number) => score > 0);\n const avgBodyScore =\n bodyKeypointScores.length > 0\n ? bodyKeypointScores.reduce((a: number, b: number) => a + b, 0) /\n bodyKeypointScores.length\n : 0;\n\n // Calculate face positioning metrics\n const eyeDistance = Math.abs(leftEye[0] - rightEye[0]);\n const noseToRight = nose[0] - rightEye[0];\n const noseToLeft = leftEye[0] - nose[0];\n\n // Determine expected position based on stage\n let expectedPosition = \"frontal\";\n if (stage === 1) expectedPosition = \"left\";\n else if (stage === 2) expectedPosition = \"right\";\n else if (stage === 3) expectedPosition = \"frontal_smile\";\n\n const payload = {\n faceScanId,\n stage,\n timestamp: new Date().toISOString(),\n data: JSON.stringify({\n headValid,\n bodyInvalid,\n consecutiveValid: consecutiveValidCount,\n avgFaceScore: parseFloat(avgFaceScore.toFixed(3)),\n avgBodyScore: parseFloat(avgBodyScore.toFixed(3)),\n faceKeypointsDetected: faceKeypointScores.length,\n bodyKeypointsDetected: bodyKeypointScores.length,\n eyeDistance: parseFloat(eyeDistance.toFixed(2)),\n noseToRightRatio: parseFloat(\n (noseToRight / eyeDistance).toFixed(3)\n ),\n noseToLeftRatio: parseFloat((noseToLeft / eyeDistance).toFixed(3)),\n noseScore: parseFloat(nose[2].toFixed(3)),\n leftEyeScore: parseFloat(leftEye[2].toFixed(3)),\n rightEyeScore: parseFloat(rightEye[2].toFixed(3)),\n leftMouthScore: parseFloat(leftMouth[2].toFixed(3)),\n rightMouthScore: parseFloat(rightMouth[2].toFixed(3)),\n expectedPosition,\n // timeInStage: Math.floor((now - lastPoseTrackingTimeRef.current) / 1000),\n }),\n };\n debouncedTrackPoseDetection(payload);\n } catch (error) {\n console.warn(\"Failed to track pose detection:\", error);\n }\n },\n [faceScanId, debouncedTrackPoseDetection]\n );\n\n // Enable voice commands from user interaction context\n const enableVoiceCommands = () => {\n voiceEnabledRef.current = true; // Set ref immediately\n\n // iOS Safari requires an initial speech synthesis call to enable audio context\n if (isIOS && \"speechSynthesis\" in window) {\n // Create a silent utterance to initialize speech synthesis\n const silentUtterance = new SpeechSynthesisUtterance(\"\");\n silentUtterance.volume = 0; // Set volume to 0 to make it silent\n speechSynthesis.speak(silentUtterance);\n }\n };\n\n // Start scan sequence: first speak direction, then start scanning\n const startScanSequence = () => {\n // Track scan start\n posthog.capture(`${shopDomain}/face_scan_detection_started`, {\n faceScanId,\n stage: scanStageRef.current,\n timestamp: new Date().toISOString(),\n stageName: directionMessages[scanStageRef.current],\n });\n\n // Then start scanning after the voice command finishes\n setTimeout(() => {\n setIsScanningActive(true);\n }, 1500); // Wait for voice command to complete\n };\n\n const isHeadInPosition = (stage: number, keypoints: Point[]) => {\n const nose = 0;\n const leftEye = 2;\n const rightEye = 5;\n const leftMouth = 9;\n const rightMouth = 10;\n\n const minScore = 0.2;\n if (\n keypoints[nose][2] < minScore ||\n keypoints[leftEye][2] < minScore ||\n keypoints[rightEye][2] < minScore\n ) {\n return false;\n }\n\n const eyesToMouthVerticalDistance =\n 0.5 * (keypoints[rightMouth][1] + keypoints[leftMouth][1]) -\n 0.5 * (keypoints[rightEye][1] + keypoints[leftEye][1]);\n\n const faceTiltedness =\n (0.5 * (keypoints[rightMouth][1] + keypoints[leftMouth][1]) -\n keypoints[nose][1]) /\n eyesToMouthVerticalDistance;\n\n const faceIsTilted = faceTiltedness > 0.7 || faceTiltedness < 0.3;\n\n const faceIsVertical =\n Math.abs(keypoints[leftEye][1] - keypoints[rightEye][1]) <\n 0.5 * eyesToMouthVerticalDistance &&\n Math.abs(keypoints[leftMouth][1] - keypoints[rightMouth][1]) <\n 0.5 * eyesToMouthVerticalDistance;\n\n const eyeDistance = keypoints[leftEye][0] - keypoints[rightEye][0];\n const noseToRight = keypoints[nose][0] - keypoints[rightEye][0];\n const noseToLeft = keypoints[leftEye][0] - keypoints[nose][0];\n\n const frontalFace =\n noseToRight > 0.4 * eyeDistance && noseToRight < 0.6 * eyeDistance;\n const fullLeft = noseToRight > 0.85 * eyeDistance;\n const fullRight = noseToLeft > 0.85 * eyeDistance;\n\n switch (stage) {\n case 0:\n return !faceIsTilted && faceIsVertical && frontalFace;\n case 1:\n return !faceIsTilted && faceIsVertical && fullLeft;\n case 2:\n return !faceIsTilted && faceIsVertical && fullRight;\n case 3:\n return !faceIsTilted && faceIsVertical && frontalFace;\n default:\n return false;\n }\n };\n\n const faceScanDetector = async (\n webcamRef: RefObject<HTMLVideoElement | null>,\n canvasRef: RefObject<HTMLCanvasElement | null>\n ) => {\n if (\n !detectorRef.current ||\n !webcamRef.current ||\n !isModelLoaded ||\n !isScanningActive\n )\n return;\n\n try {\n const poses = await detectorRef.current.estimatePoses(webcamRef.current);\n if (poses.length > 0) {\n const faceKeypoints: Point[] = [];\n const bodyKeypoints: Point[] = [];\n poses[0].keypoints.forEach((landmark, idx) => {\n const score = landmark.score ?? 0;\n const point: Point = [landmark.x ?? -1, landmark.y ?? -1, score];\n if (idx <= 10) faceKeypoints.push(point);\n else bodyKeypoints.push(point);\n });\n\n // Optional drawing (invisible canvas)\n if (canvasRef?.current) {\n const ctx = canvasRef.current.getContext(\"2d\");\n const { width, height } = canvasRef.current;\n if (ctx) {\n ctx.clearRect(0, 0, width, height);\n\n const progress = Math.min(\n consecutiveValidRef.current / CONSECUTIVE_VALID_LENGTH,\n 1\n );\n const radius = height * 0.35;\n ctx.beginPath();\n ctx.strokeStyle = \"#00ff00\";\n ctx.lineWidth = 6;\n ctx.arc(\n width / 2,\n height / 2,\n radius + 10,\n -Math.PI / 2,\n -Math.PI / 2 + progress * 2 * Math.PI\n );\n ctx.stroke();\n }\n }\n\n const headValid = isHeadInPosition(scanStageRef.current, faceKeypoints);\n const bodyInvalid =\n bodyKeypoints.slice(2).filter((p) => p[2] > 0.7).length <= 2;\n\n validityBufferRef.current.push(headValid && bodyInvalid);\n if (validityBufferRef.current.length > VALIDITY_BUFFER_LENGTH) {\n validityBufferRef.current.shift();\n }\n\n const validCount = validityBufferRef.current.filter(Boolean).length;\n if (validCount >= 2) {\n const nextValid = consecutiveValidRef.current + 1;\n setConsecutiveValid(nextValid);\n } else {\n setConsecutiveValid(Math.max(0, consecutiveValidRef.current - 1));\n }\n\n // ✅ Pose confirmed\n if (consecutiveValidRef.current >= CONSECUTIVE_VALID_LENGTH) {\n onValidPose?.();\n\n const nextStage = scanStageRef.current + 1;\n setConsecutiveValid(0);\n validityBufferRef.current = [];\n setScanStage(nextStage);\n setIsScanningActive(false); // Stop scanning for next stage\n\n // Play sound effect for stage completion, then next stage instruction (if not final stage)\n (async () => {\n await speechService.playAudio(\n `${voiceOverAssetsPath}face-scan-vos/Sound-effect.mp3`\n );\n // Track stage completion\n posthog.capture(\n `${shopDomain}/face_scan_detection_stage_completed`,\n {\n faceScanId,\n completedStage: scanStageRef.current,\n nextStage,\n timestamp: new Date().toISOString(),\n totalStages: TOTAL_STAGES,\n stageName: directionMessages[scanStageRef.current],\n }\n );\n // Start recording after stage 0 is completed\n if (nextStage === 1 && onStartRecording) {\n onStartRecording();\n }\n if (nextStage >= TOTAL_STAGES) {\n onScanComplete?.();\n } else {\n // Play next stage instruction sound, then start scan sequence\n let nextSound = null;\n switch (nextStage) {\n case 1:\n nextSound = \"Left.mp3\";\n break;\n case 2:\n nextSound = \"Right.mp3\";\n break;\n case 3:\n nextSound = \"Smile.mp3\";\n break;\n default:\n nextSound = null;\n }\n if (nextSound) {\n await speechService.playAudio(\n `${voiceOverAssetsPath}face-scan-vos/${nextSound}`\n );\n }\n startScanSequence();\n }\n })();\n }\n\n // Track pose detection performance for analytics\n trackPoseDetection(\n faceKeypoints,\n bodyKeypoints,\n scanStageRef.current,\n headValid,\n bodyInvalid,\n consecutiveValidRef.current\n );\n }\n } catch (err) {\n console.error(\"Pose detection error:\", err);\n }\n };\n\n const initializeModels = async () => {\n try {\n console.log(\"Initializing TensorFlow...\");\n await setBackend(\"webgl\");\n await ready();\n console.log(\"TensorFlow initialized, loading models...\");\n const detector = await preloadDetector(); // <-- now it waits for preload\n console.log(detector, \"detector\");\n\n detectorRef.current = detector;\n console.log(\"Pose detection model loaded successfully\");\n setIsModelLoaded(true);\n onModelReady?.();\n } catch (err) {\n console.error(\"Error initializing face scan:\", err);\n }\n };\n\n const disposeModelAndTf = async () => {\n try {\n setIsModelLoaded(false);\n if (detectorRef.current) {\n await detectorRef.current.dispose();\n detectorRef.current = null;\n }\n } catch (err) {\n console.error(\"Error disposing resources:\", err);\n } finally {\n setScanStage(0);\n setConsecutiveValid(0);\n scanStageRef.current = 0;\n consecutiveValidRef.current = 0;\n validityBufferRef.current = [];\n }\n };\n\n const resetScan = () => {\n // Track scan reset\n posthog.capture(`${shopDomain}/face_scan_reset`, {\n faceScanId,\n stage: scanStageRef.current,\n timestamp: new Date().toISOString(),\n stageName: directionMessages[scanStageRef.current],\n consecutiveValid: consecutiveValidRef.current,\n });\n\n setScanStage(0);\n setConsecutiveValid(0);\n setIsScanningActive(false);\n scanStageRef.current = 0;\n consecutiveValidRef.current = 0;\n validityBufferRef.current = [];\n lastSpokenMessageRef.current = \"\";\n lastSpokenTimeRef.current = 0;\n voiceEnabledRef.current = false;\n if (utteranceRef.current) {\n speechSynthesis.cancel();\n utteranceRef.current = null;\n }\n };\n\n useEffect(() => {\n // disposeModelAndTf();\n initializeModels();\n return () => {\n disposeModelAndTf();\n };\n }, []);\n\n useEffect(() => {\n scanStageRef.current = scanStage;\n }, [scanStage]);\n\n useEffect(() => {\n consecutiveValidRef.current = consecutiveValid;\n }, [consecutiveValid]);\n\n return {\n faceScanDetector,\n scanStage,\n setScanStage,\n consecutiveValid,\n isModelLoaded,\n resetScan,\n enableVoiceCommands,\n startScanSequence,\n isScanningActive,\n };\n}\n\nexport default useFaceScan;\n","\"use client\"\nimport { useEffect, useRef, useState, useCallback, useMemo } from \"react\";\nimport { ArrowRight } from \"lucide-react\";\nimport { Drawer } from \"@mui/material\";\nimport FaceScanGuide from \"./FaceScanGuide\";\nimport FaceScanErrorScreen from \"./FaceScanErrorScreen\";\nimport posthog from \"posthog-js\";\nimport { FaceScanProps } from \"../../types/interfaces\";\nimport {\n generateUuid,\n handleScanTimeCapture,\n handleWebSocketCapture,\n} from \"../../utils/utils\";\nimport { useLocalConfig } from \"../../config/useLocalConfig\";\nimport {\n posthogPublicHost,\n posthogPublicKey,\n videoConstraints,\n videoTypes,\n voiceOverAssetsPath,\n} from \"../../utils/constants\";\nimport swan from \"../../utils/service/swanService\";\nimport speechService from \"../../utils/service/speechService\";\nimport useFaceScan from \"../../customHooks/useFaceScan\";\nimport SpecificButton from \"../../atoms/specificButton/SpecificButton\";\nimport LoadingScreen from \"../LoadingScreen\";\n\nexport const FaceScan: React.FC<FaceScanProps> = ({\n userDetails,\n onComplete,\n onScanError,\n onRetry,\n config,\n}) => {\n const webcamRef = useRef<HTMLVideoElement | null>(null);\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const recordedBlobsRef = useRef<Blob[] | null>([]);\n const streamRef = useRef<MediaStream | null>(null);\n const [showLoader, setShowLoader] = useState(false);\n const [modelReady, setModelReady] = useState(false);\n const [isScanning, setIsScanning] = useState(false);\n const [showGuideCard, setShowGuideCard] = useState(true);\n const [videoLoading, setVideoLoading] = useState(false);\n const [videoError, setVideoError] = useState(false);\n const [hasError, setHasError] = useState(false);\n const [faceScanId, setFaceScanId] = useState(generateUuid());\n const resolvedConfig = useLocalConfig(config);\n const { email, gender, deviceFocalLength, shopDomain, callbackUrl } =\n userDetails;\n\n console.log(recordedBlobsRef.current, \"recoridng\");\n const supportedTypes = useMemo(\n () => videoTypes.filter((type) => MediaRecorder.isTypeSupported(type)),\n []\n );\n\n const stopRecording = useCallback(() => {\n console.log(\"Stopping recording...\");\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state === \"recording\"\n ) {\n mediaRecorderRef.current.stop();\n }\n mediaRecorderRef.current = null;\n }, []);\n\n const uploadFinalVideo = async () => {\n setShowLoader(true);\n console.log(\"upload final video\");\n if (recordedBlobsRef.current) {\n if (recordedBlobsRef.current.length === 0) {\n console.error(\"No video data recorded\");\n setHasError(true);\n setShowLoader(false);\n\n return;\n }\n\n const videoFile = new File(\n recordedBlobsRef.current,\n `${faceScanId}.webm`,\n {\n type: \"video/webm\",\n }\n );\n const fileSize = videoFile.size;\n const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);\n const estimatedDuration = Math.round(fileSize / 10000);\n const videoData = {\n video_size_mb: parseFloat(fileSizeMB),\n video_size_bytes: fileSize,\n blob_count: recordedBlobsRef.current.length,\n estimated_duration_seconds: estimatedDuration,\n };\n\n const metaData = [\n { gender: gender },\n { face_scan_id: faceScanId },\n {\n focal_length: `${deviceFocalLength}`,\n },\n { customer_store_url: shopDomain },\n { scan_type: \"face_scan\" },\n { callback_url: callbackUrl },\n ];\n console.log(metaData, \"metadata\");\n console.log(videoData);\n\n handleScanTimeCapture({\n eventName: `${shopDomain}/face_scan_meta_data`,\n faceScanId,\n email,\n data: JSON.stringify({ metaData, videoData }),\n });\n\n const uploadStartTime = Date.now();\n handleScanTimeCapture({\n eventName: `${shopDomain}/face_scan_upload_start`,\n faceScanId,\n email,\n startTime: uploadStartTime,\n });\n\n try {\n const res = await swan.fileUpload.faceScanFileUploader({\n file: videoFile,\n objectKey: faceScanId,\n email,\n arrayMetaData: metaData,\n contentType: videoFile.type,\n });\n\n const uploadEndTime = Date.now();\n const uploadDuration = uploadEndTime - uploadStartTime;\n\n handleScanTimeCapture({\n eventName: `${shopDomain}/face_scan_upload_complete`,\n faceScanId,\n email,\n completionTime: uploadEndTime,\n uploadDuration,\n });\n\n console.log(\"✅ Upload successful\", res);\n swan.measurement.handlFaceScaneSocket({\n faceScanId,\n onOpen: () => {\n handleWebSocketCapture({\n eventName: `${shopDomain}/webSocket`,\n faceScanID: faceScanId,\n connection: \"open\",\n type: \"faceScan_recommendation\",\n email,\n });\n console.log(\"websocket connect open\");\n },\n onError: (err) => {\n handleWebSocketCapture({\n eventName: `${shopDomain}/webSocket`,\n faceScanID: faceScanId,\n connection: \"error\",\n type: \"faceScan_recommendation\",\n email,\n });\n onError(err);\n },\n onSuccess: (data) => {\n handleWebSocketCapture({\n eventName: `${shopDomain}/webSocket`,\n faceScanID: faceScanId,\n connection: \"success\",\n type: \"faceScan_recommendation\",\n email,\n });\n onSuccess(data);\n },\n onClose: () => {\n console.log(\"websocket connect close\");\n handleWebSocketCapture({\n eventName: `${shopDomain}/webSocket`,\n faceScanID: faceScanId,\n connection: \"close\",\n type: \"faceScan_recommendation\",\n email,\n });\n },\n });\n } catch (error) {\n onError(error);\n }\n }\n };\n\n const startRecording = useCallback(() => {\n console.log(\"Starting recording for stages 1-3...\");\n const stream = webcamRef.current?.srcObject as MediaStream | null;\n if (!stream) return;\n\n // Create a canvas to normalize orientation\n const videoTrack = stream.getVideoTracks()[0];\n const settings = videoTrack.getSettings();\n const { width = videoConstraints.width, height = videoConstraints.height } =\n settings;\n\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n\n // Always force portrait (swap width/height if landscape)\n if (width > height) {\n canvas.width = height;\n canvas.height = width;\n } else {\n canvas.width = width;\n canvas.height = height;\n }\n\n const videoEl = document.createElement(\"video\");\n videoEl.srcObject = stream;\n videoEl.muted = true;\n videoEl.playsInline = true;\n videoEl.play();\n\n // Draw video frames onto canvas\n const drawFrame = () => {\n // Rotate if camera gives landscape frames\n if (width > height) {\n ctx?.save();\n ctx?.translate(canvas.width, 0);\n ctx?.rotate(Math.PI / 2);\n ctx?.drawImage(videoEl, 0, 0, height, width);\n ctx?.restore();\n } else {\n ctx?.drawImage(videoEl, 0, 0, width, height);\n }\n requestAnimationFrame(drawFrame);\n };\n drawFrame();\n\n // Capture portrait-normalized stream\n const canvasStream = canvas.captureStream(30); // 30fps\n const mediaRecorderOptions =\n supportedTypes.length > 0 ? { mimeType: supportedTypes[0] } : {};\n let mediaRecorder;\n\n try {\n mediaRecorder = new MediaRecorder(canvasStream, mediaRecorderOptions);\n } catch (e) {\n console.error(\"MediaRecorder init failed:\", e);\n setHasError(true);\n setShowLoader(false);\n return;\n }\n\n recordedBlobsRef.current = [];\n mediaRecorder.ondataavailable = (event) => {\n if (event?.data && event.data.size > 0 && recordedBlobsRef.current) {\n recordedBlobsRef.current.push(event.data);\n }\n };\n mediaRecorder.onstop = () => {\n console.log(\n \"Recording stopped, total blobs:\",\n recordedBlobsRef?.current?.length\n );\n uploadFinalVideo();\n };\n\n mediaRecorder.start(100); // 100ms chunks\n mediaRecorderRef.current = mediaRecorder;\n console.log(\"Recording started successfully (portrait normalized)\");\n }, [supportedTypes, uploadFinalVideo]);\n\n const {\n faceScanDetector,\n scanStage,\n setScanStage,\n resetScan,\n isModelLoaded,\n startScanSequence,\n } = useFaceScan({\n faceScanId,\n shopDomain,\n onScanComplete: () => {\n stopRecording();\n },\n onModelReady: () => {\n setModelReady(true);\n },\n onStartRecording: () => {\n console.log(\"Stage 0 completed - starting recording for stages 1-3\");\n startRecording();\n },\n });\n\n const startScan = useCallback(() => {\n if (!isModelLoaded) return;\n setScanStage(0);\n speechService.playAudio(\n `${voiceOverAssetsPath}face-scan-vos/Face-forward.mp3`\n );\n setTimeout(() => {\n setIsScanning(true);\n setTimeout(() => {\n startScanSequence();\n }, 200);\n }, 200);\n }, [setScanStage, setIsScanning, startScanSequence, isModelLoaded]);\n\n const resetScanState = useCallback(() => {\n setIsScanning(false);\n setShowGuideCard(true);\n stopRecording();\n resetScan();\n onRetry?.();\n recordedBlobsRef.current = [];\n if (mediaRecorderRef.current) {\n mediaRecorderRef.current = null;\n }\n setHasError(false);\n setScanStage(-1);\n setFaceScanId(generateUuid());\n if (webcamRef.current && streamRef.current) {\n webcamRef.current.srcObject = streamRef.current;\n console.log(\"Camera stream restored after reset\");\n }\n }, [\n setScanStage,\n setIsScanning,\n setShowGuideCard,\n stopRecording,\n resetScan,\n setFaceScanId,\n ]);\n\n const onError = (data: any) => {\n console.log(data, \"ws error\");\n onScanError?.(data);\n setHasError(true);\n setShowLoader(false);\n setShowGuideCard(false);\n handleScanTimeCapture({\n eventName: `${shopDomain}/faceScan`,\n faceScanId,\n status: \"failed\",\n email,\n data: JSON.stringify(data),\n });\n };\n\n const onSuccess = (data: any) => {\n console.log(data, \"ws success\");\n if (data && data?.resultType === \"intermediate\") {\n handleScanTimeCapture({\n eventName: `${shopDomain}/faceScan_success/intermediate`,\n faceScanId,\n status: \"success\",\n email,\n data: JSON.stringify(data),\n });\n }\n onComplete?.(data);\n };\n\n // Initialize webcam\n useEffect(() => {\n if (navigator.mediaDevices.getUserMedia) {\n navigator.mediaDevices\n .getUserMedia({ video: videoConstraints })\n .then((stream) => {\n streamRef.current = stream;\n if (webcamRef.current) {\n webcamRef.current.srcObject = stream;\n console.log(\"Webcam initialized\");\n }\n })\n .catch((err) => console.error(\"Error accessing webcam:\", err));\n }\n\n // Cleanup function\n return () => {\n if (streamRef.current) {\n streamRef.current.getTracks().forEach((track) => track.stop());\n }\n };\n }, []);\n\n // Face detection interval - only run when scanning is active\n useEffect(() => {\n if (!modelReady || !isScanning) return;\n\n const intervalId = setInterval(() => {\n faceScanDetector(webcamRef, canvasRef);\n }, 500);\n\n // eslint-disable-next-line consistent-return\n return () => clearInterval(intervalId);\n }, [faceScanDetector, modelReady, isScanning]);\n\n const getButtonText = () => {\n if (isScanning) return \"Reset\";\n if (!isModelLoaded) return \"Loading...\";\n return \"Start\";\n };\n\n console.log(\n \"Model ready:\",\n modelReady,\n \"Has error:\",\n hasError,\n \"Is scanning:\",\n isScanning,\n \"showLoader\",\n showLoader\n );\n\n useEffect(() => {\n setScanStage(-1);\n posthog.init(posthogPublicKey, { api_host: posthogPublicHost });\n posthog.capture(\"$pageview\");\n }, []);\n\n return (\n <>\n <audio\n id=\"audioElement\"\n crossOrigin=\"anonymous\"\n preload=\"auto\"\n style={{ position: \"absolute\", zIndex: -99999 }}\n src=\"\"\n />\n\n {showLoader && !hasError && (\n <div\n className=\"fixed z-[9] w-full h-full\"\n style={{ background: resolvedConfig?.style?.base?.primaryColor }}\n >\n {/* <Asset genderType={gender} /> */}\n <LoadingScreen />\n </div>\n )}\n\n {/* Always show camera view */}\n <div\n className=\"h-full flex-col relative w-full flex justify-center items-center text-center rounded-t-[20px]\"\n style={{ background: resolvedConfig?.style?.base?.backgroundColor }}\n >\n <div className=\"flex-1 w-full max-w-md overflow-hidden\">\n <div className=\"w-full h-full\">\n <video\n ref={webcamRef}\n autoPlay\n playsInline\n muted\n width={videoConstraints.width}\n height={videoConstraints.height}\n className=\"w-full h-full object-cover fixed left-0 top-0 z-0\"\n style={{ transform: \"scaleX(-1)\" }}\n />\n <canvas\n ref={canvasRef}\n width={videoConstraints.width}\n height={videoConstraints.height}\n style={{ transform: \"scaleX(-1)\", opacity: \"0\" }}\n />\n </div>\n </div>\n </div>\n\n {/* Error overlay */}\n {!showLoader && hasError && (\n <FaceScanErrorScreen\n loading={showLoader}\n resetScanState={resetScanState}\n config={resolvedConfig}\n />\n )}\n\n {/* Scan guide drawer - only show when scanning */}\n {showGuideCard && !hasError && !showLoader && (\n <Drawer\n open\n className=\"face-scan-small camera-draw\"\n anchor=\"bottom\"\n onClose={(event, reason) => {\n if (reason === \"backdropClick\") {\n return;\n }\n }}\n hideBackdrop\n >\n <FaceScanGuide\n stage={scanStage}\n videoLoading={videoLoading}\n setVideoLoading={setVideoLoading}\n videoError={videoError}\n setVideoError={setVideoError}\n gender={gender}\n config={resolvedConfig}\n >\n <div className=\"flex justify-center w-full p-[1rem]\">\n <SpecificButton\n disabled={showLoader || !isModelLoaded}\n className=\"!w-[60px] !h-[35px] !py-0 !px-0\"\n buttonText={getButtonText()}\n postfixIcon={isScanning ? <ArrowRight /> : \"\"}\n buttonFunc={isScanning ? resetScanState : startScan}\n resolvedConfig={resolvedConfig}\n />\n </div>\n </FaceScanGuide>\n </Drawer>\n )}\n </>\n );\n};\n"],"names":["FaceScanGuide","stage","videoLoading","setVideoLoading","videoError","setVideoError","children","gender","config","_jsxs","className","style","background","base","backgroundColor","_jsx","Header","noTitle","resolvedConfig","fontFamily","heading","headingFontFamily","fontSize","headingFontSize","color","headingColor","fontWeight","headingFontWeight","subheading","subheadingFontFamily","subheadingFontSize","subheadingColor","subheadingFontWeight","src","GenderType","Male","maleGlassesOffVideo","glassesOffVideo","autoPlay","loop","controls","muted","playsInline","onCanPlay","onLoadStart","onError","directionMessages","FACE_SCAN_HEADSHOT","male","forward","female","type","left","right","smile","FaceScanErrorScreen","resetScanState","loading","SpecificButton","disabled","buttonText","postfixIcon","ArrowRight","buttonFunc","preloadedDetector","useFaceScan","faceScanId","onValidPose","onScanComplete","onModelReady","onStartRecording","shopDomain","detectorRef","useRef","scanStage","setScanStage","useState","consecutiveValid","setConsecutiveValid","isModelLoaded","setIsModelLoaded","isScanningActive","setIsScanningActive","utteranceRef","scanStageRef","consecutiveValidRef","validityBufferRef","lastSpokenMessageRef","lastSpokenTimeRef","voiceEnabledRef","lastPoseTrackingTimeRef","isIOS","test","navigator","userAgent","platform","maxTouchPoints","useMemo","debouncedTrackPoseDetection","fn","delay","timer","args","clearTimeout","setTimeout","debounce","payload","posthog","capture","trackPoseDetection","useCallback","faceKeypoints","bodyKeypoints","headValid","bodyInvalid","consecutiveValidCount","now","Date","current","nose","leftEye","rightEye","leftMouth","rightMouth","faceKeypointScores","map","kp","filter","score","avgFaceScore","length","reduce","a","b","bodyKeypointScores","avgBodyScore","eyeDistance","Math","abs","noseToRight","noseToLeft","expectedPosition","timestamp","toISOString","data","JSON","stringify","parseFloat","toFixed","faceKeypointsDetected","bodyKeypointsDetected","noseToRightRatio","noseToLeftRatio","noseScore","leftEyeScore","rightEyeScore","leftMouthScore","rightMouthScore","error","console","warn","startScanSequence","stageName","initializeModels","async","log","setBackend","ready","detector","poseDetection","createDetector","SupportedModels","BlazePose","runtime","modelType","dummyCanvas","document","createElement","width","videoConstraints","height","ctx","getContext","fillStyle","fillRect","estimatePoses","e","preloadDetector","err","useEffect","dispose","disposeModelAndTf","faceScanDetector","webcamRef","canvasRef","poses","keypoints","forEach","landmark","idx","point","x","y","push","clearRect","progress","min","radius","beginPath","strokeStyle","lineWidth","arc","PI","stroke","eyesToMouthVerticalDistance","faceTiltedness","faceIsTilted","faceIsVertical","frontalFace","fullLeft","fullRight","isHeadInPosition","slice","p","shift","Boolean","nextValid","max","nextStage","speechService","playAudio","voiceOverAssetsPath","completedStage","totalStages","nextSound","resetScan","speechSynthesis","cancel","enableVoiceCommands","window","silentUtterance","SpeechSynthesisUtterance","volume","speak","FaceScan","userDetails","onComplete","onScanError","onRetry","mediaRecorderRef","recordedBlobsRef","streamRef","showLoader","setShowLoader","modelReady","setModelReady","isScanning","setIsScanning","showGuideCard","setShowGuideCard","hasError","setHasError","setFaceScanId","generateUuid","useLocalConfig","email","deviceFocalLength","callbackUrl","supportedTypes","videoTypes","MediaRecorder","isTypeSupported","stopRecording","state","stop","uploadFinalVideo","videoFile","File","fileSize","size","fileSizeMB","estimatedDuration","round","videoData","video_size_mb","video_size_bytes","blob_count","estimated_duration_seconds","metaData","face_scan_id","focal_length","customer_store_url","scan_type","callback_url","handleScanTimeCapture","eventName","uploadStartTime","startTime","res","swan","fileUpload","faceScanFileUploader","file","objectKey","arrayMetaData","contentType","uploadEndTime","completionTime","uploadDuration","measurement","handlFaceScaneSocket","onOpen","handleWebSocketCapture","faceScanID","connection","onSuccess","onClose","startRecording","stream","srcObject","settings","getVideoTracks","getSettings","canvas","videoEl","play","drawFrame","save","translate","rotate","drawImage","restore","requestAnimationFrame","canvasStream","captureStream","mediaRecorderOptions","mimeType","mediaRecorder","ondataavailable","event","onstop","start","startScan","status","resultType","mediaDevices","getUserMedia","video","then","catch","getTracks","track","intervalId","setInterval","clearInterval","init","posthogPublicKey","api_host","posthogPublicHost","id","crossOrigin","preload","position","zIndex","primaryColor","LoadingScreen","ref","transform","opacity","Drawer","open","anchor","reason","hideBackdrop"],"mappings":"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"}
package/dist/index.css ADDED
@@ -0,0 +1,3 @@
1
+ .vjs-svg-icon{fill:currentColor;background-position:50%;background-repeat:no-repeat;display:inline-block;height:1.8em;width:1.8em}.vjs-svg-icon:before{content:none!important}.vjs-control:focus .vjs-svg-icon,.vjs-svg-icon:hover{filter:drop-shadow(0 0 .25em #fff)}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-modal-dialog,.vjs-button>.vjs-icon-placeholder:before,.vjs-modal-dialog .vjs-modal-dialog-content{height:100%;left:0;position:absolute;top:0;width:100%}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.vjs-button>.vjs-icon-placeholder:before{text-align:center}@font-face{font-family:VideoJS;font-style:normal;font-weight:400;src:url(data:application/font-woff;charset=utf-8;base64,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) format("woff")}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-play-control .vjs-icon-placeholder,.vjs-icon-play{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-play-control .vjs-icon-placeholder:before,.vjs-icon-play:before{content:"\f101"}.vjs-icon-play-circle{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-play-circle:before{content:"\f102"}.video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder,.vjs-icon-pause{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder:before,.vjs-icon-pause:before{content:"\f103"}.video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder,.vjs-icon-volume-mute{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder:before,.vjs-icon-volume-mute:before{content:"\f104"}.video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder,.vjs-icon-volume-low{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder:before,.vjs-icon-volume-low:before{content:"\f105"}.video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder,.vjs-icon-volume-mid{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder:before,.vjs-icon-volume-mid:before{content:"\f106"}.video-js .vjs-mute-control .vjs-icon-placeholder,.vjs-icon-volume-high{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-mute-control .vjs-icon-placeholder:before,.vjs-icon-volume-high:before{content:"\f107"}.video-js .vjs-fullscreen-control .vjs-icon-placeholder,.vjs-icon-fullscreen-enter{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-fullscreen-control .vjs-icon-placeholder:before,.vjs-icon-fullscreen-enter:before{content:"\f108"}.video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder,.vjs-icon-fullscreen-exit{font-family:VideoJS;font-style:normal;font-weight:400}.video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder:before,.vjs-icon-fullscreen-exit:before{content:"\f109"}.vjs-icon-spinner{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-spinner:before{content:"\f10a"}.video-js .vjs-subs-caps-button .vjs-icon-placeholder,.video-js .vjs-subtitles-button .vjs-icon-placeholder,.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder,.vjs-icon-subtitles{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js .vjs-subtitles-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder:before,.vjs-icon-subtitles:before{content:"\f10b"}.video-js .vjs-captions-button .vjs-icon-placeholder,.video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder,.vjs-icon-captions{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-captions-button .vjs-icon-placeholder:before,.video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder:before,.vjs-icon-captions:before{content:"\f10c"}.vjs-icon-hd{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-hd:before{content:"\f10d"}.video-js .vjs-chapters-button .vjs-icon-placeholder,.vjs-icon-chapters{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-chapters-button .vjs-icon-placeholder:before,.vjs-icon-chapters:before{content:"\f10e"}.vjs-icon-downloading{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-downloading:before{content:"\f10f"}.vjs-icon-file-download{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-file-download:before{content:"\f110"}.vjs-icon-file-download-done{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-file-download-done:before{content:"\f111"}.vjs-icon-file-download-off{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-file-download-off:before{content:"\f112"}.vjs-icon-share{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-share:before{content:"\f113"}.vjs-icon-cog{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-cog:before{content:"\f114"}.vjs-icon-square{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-square:before{content:"\f115"}.video-js .vjs-play-progress,.video-js .vjs-volume-level,.vjs-icon-circle,.vjs-seek-to-live-control .vjs-icon-placeholder{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-play-progress:before,.video-js .vjs-volume-level:before,.vjs-icon-circle:before,.vjs-seek-to-live-control .vjs-icon-placeholder:before{content:"\f116"}.vjs-icon-circle-outline{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-circle-outline:before{content:"\f117"}.vjs-icon-circle-inner-circle{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-circle-inner-circle:before{content:"\f118"}.video-js .vjs-control.vjs-close-button .vjs-icon-placeholder,.vjs-icon-cancel{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-control.vjs-close-button .vjs-icon-placeholder:before,.vjs-icon-cancel:before{content:"\f119"}.vjs-icon-repeat{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-repeat:before{content:"\f11a"}.video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder,.vjs-icon-replay{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder:before,.vjs-icon-replay:before{content:"\f11b"}.video-js .vjs-skip-backward-5 .vjs-icon-placeholder,.vjs-icon-replay-5{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-skip-backward-5 .vjs-icon-placeholder:before,.vjs-icon-replay-5:before{content:"\f11c"}.video-js .vjs-skip-backward-10 .vjs-icon-placeholder,.vjs-icon-replay-10{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-skip-backward-10 .vjs-icon-placeholder:before,.vjs-icon-replay-10:before{content:"\f11d"}.video-js .vjs-skip-backward-30 .vjs-icon-placeholder,.vjs-icon-replay-30{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-skip-backward-30 .vjs-icon-placeholder:before,.vjs-icon-replay-30:before{content:"\f11e"}.video-js .vjs-skip-forward-5 .vjs-icon-placeholder,.vjs-icon-forward-5{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-skip-forward-5 .vjs-icon-placeholder:before,.vjs-icon-forward-5:before{content:"\f11f"}.video-js .vjs-skip-forward-10 .vjs-icon-placeholder,.vjs-icon-forward-10{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-skip-forward-10 .vjs-icon-placeholder:before,.vjs-icon-forward-10:before{content:"\f120"}.video-js .vjs-skip-forward-30 .vjs-icon-placeholder,.vjs-icon-forward-30{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-skip-forward-30 .vjs-icon-placeholder:before,.vjs-icon-forward-30:before{content:"\f121"}.video-js .vjs-audio-button .vjs-icon-placeholder,.vjs-icon-audio{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-audio-button .vjs-icon-placeholder:before,.vjs-icon-audio:before{content:"\f122"}.vjs-icon-next-item{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-next-item:before{content:"\f123"}.vjs-icon-previous-item{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-previous-item:before{content:"\f124"}.vjs-icon-shuffle{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-shuffle:before{content:"\f125"}.vjs-icon-cast{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-cast:before{content:"\f126"}.video-js .vjs-picture-in-picture-control .vjs-icon-placeholder,.vjs-icon-picture-in-picture-enter{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-picture-in-picture-control .vjs-icon-placeholder:before,.vjs-icon-picture-in-picture-enter:before{content:"\f127"}.video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder,.vjs-icon-picture-in-picture-exit{font-family:VideoJS;font-style:normal;font-weight:400}.video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder:before,.vjs-icon-picture-in-picture-exit:before{content:"\f128"}.vjs-icon-facebook{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-facebook:before{content:"\f129"}.vjs-icon-linkedin{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-linkedin:before{content:"\f12a"}.vjs-icon-twitter{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-twitter:before{content:"\f12b"}.vjs-icon-tumblr{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-tumblr:before{content:"\f12c"}.vjs-icon-pinterest{font-family:VideoJS;font-style:normal;font-weight:400}.vjs-icon-pinterest:before{content:"\f12d"}.video-js .vjs-descriptions-button .vjs-icon-placeholder,.vjs-icon-audio-description{font-family:VideoJS;font-style:normal;font-weight:400}.video-js .vjs-descriptions-button .vjs-icon-placeholder:before,.vjs-icon-audio-description:before{content:"\f12e"}.video-js{background-color:#000;box-sizing:border-box;color:#fff;display:inline-block;font-family:Arial,Helvetica,sans-serif;font-size:10px;font-style:normal;font-weight:400;line-height:1;padding:0;position:relative;vertical-align:top;word-break:normal}.video-js:-moz-full-screen{position:absolute}.video-js:-webkit-full-screen{height:100%!important;width:100%!important}.video-js[tabindex="-1"]{outline:none}.video-js *,.video-js :after,.video-js :before{box-sizing:inherit}.video-js ul{font-family:inherit;font-size:inherit;line-height:inherit;list-style-position:outside;margin:0}.video-js.vjs-1-1,.video-js.vjs-16-9,.video-js.vjs-4-3,.video-js.vjs-9-16,.video-js.vjs-fluid{max-width:100%;width:100%}.video-js.vjs-1-1:not(.vjs-audio-only-mode),.video-js.vjs-16-9:not(.vjs-audio-only-mode),.video-js.vjs-4-3:not(.vjs-audio-only-mode),.video-js.vjs-9-16:not(.vjs-audio-only-mode),.video-js.vjs-fluid:not(.vjs-audio-only-mode){height:0}.video-js.vjs-16-9:not(.vjs-audio-only-mode){padding-top:56.25%}.video-js.vjs-4-3:not(.vjs-audio-only-mode){padding-top:75%}.video-js.vjs-9-16:not(.vjs-audio-only-mode){padding-top:177.7777777778%}.video-js.vjs-1-1:not(.vjs-audio-only-mode){padding-top:100%}.video-js .vjs-tech,.video-js.vjs-fill:not(.vjs-audio-only-mode){height:100%;width:100%}.video-js .vjs-tech{left:0;position:absolute;top:0}.video-js.vjs-audio-only-mode .vjs-tech{display:none}body.vjs-full-window,body.vjs-pip-window{height:100%;margin:0;padding:0}.vjs-full-window .video-js.vjs-fullscreen,body.vjs-pip-window .video-js{bottom:0;left:0;overflow:hidden;position:fixed;right:0;top:0;z-index:1000}.video-js.vjs-fullscreen:not(.vjs-ios-native-fs),body.vjs-pip-window .video-js{display:block;height:100%!important;padding-top:0!important;width:100%!important}.video-js.vjs-fullscreen.vjs-user-inactive{cursor:none}.vjs-pip-container .vjs-pip-text{background-color:rgba(0,0,0,.7);bottom:10%;font-size:2em;padding:.5em;position:absolute;text-align:center;width:100%}.vjs-layout-small.vjs-pip-container .vjs-pip-text,.vjs-layout-tiny.vjs-pip-container .vjs-pip-text,.vjs-layout-x-small.vjs-pip-container .vjs-pip-text{bottom:0;font-size:1.4em}.vjs-hidden{display:none!important}.vjs-disabled{cursor:default;opacity:.5}.video-js .vjs-offscreen{height:1px;left:-9999px;position:absolute;top:0;width:1px}.vjs-lock-showing{display:block!important;opacity:1!important;visibility:visible!important}.vjs-no-js{background-color:#000;color:#fff;font-family:Arial,Helvetica,sans-serif;font-size:18px;height:150px;margin:0 auto;padding:20px;text-align:center;width:300px}.vjs-no-js a,.vjs-no-js a:visited{color:#66a8cc}.video-js .vjs-big-play-button{background-color:#2b333f;background-color:rgba(43,51,63,.7);border:.06666em solid #fff;border-radius:.3em;cursor:pointer;display:block;font-size:3em;height:1.63332em;left:50%;line-height:1.5em;margin-left:-1.5em;margin-top:-.81666em;opacity:1;padding:0;position:absolute;top:50%;transition:all .4s;width:3em}.vjs-big-play-button .vjs-svg-icon{height:1em;left:50%;line-height:1;position:absolute;top:50%;transform:translate(-50%,-50%);width:1em}.video-js .vjs-big-play-button:focus,.video-js:hover .vjs-big-play-button{background-color:#73859f;background-color:rgba(115,133,159,.5);border-color:#fff;transition:all 0s}.vjs-controls-disabled .vjs-big-play-button,.vjs-error .vjs-big-play-button,.vjs-has-started .vjs-big-play-button,.vjs-using-native-controls .vjs-big-play-button{display:none}.vjs-has-started.vjs-paused.vjs-show-big-play-button-on-pause:not(.vjs-seeking,.vjs-scrubbing,.vjs-error) .vjs-big-play-button{display:block}.video-js button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:none;color:inherit;display:inline-block;font-size:inherit;line-height:inherit;text-decoration:none;text-transform:none;transition:none}.video-js.vjs-spatial-navigation-enabled .vjs-button:focus{box-shadow:none;outline:.0625em solid #fff}.vjs-control .vjs-button{height:100%;width:100%}.video-js .vjs-control.vjs-close-button{cursor:pointer;height:3em;position:absolute;right:0;top:.5em;z-index:2}.video-js .vjs-modal-dialog{background:rgba(0,0,0,.8);background:linear-gradient(180deg,rgba(0,0,0,.8),hsla(0,0%,100%,0));overflow:auto}.video-js .vjs-modal-dialog>*{box-sizing:border-box}.vjs-modal-dialog .vjs-modal-dialog-content{font-size:1.2em;line-height:1.5;padding:20px 24px;z-index:1}.vjs-menu-button{cursor:pointer}.vjs-menu-button.vjs-disabled{cursor:default}.vjs-workinghover .vjs-menu-button.vjs-disabled:hover .vjs-menu{display:none}.vjs-menu .vjs-menu-content{display:block;font-family:Arial,Helvetica,sans-serif;margin:0;overflow:auto;padding:0}.vjs-menu .vjs-menu-content>*{box-sizing:border-box}.vjs-scrubbing .vjs-control.vjs-menu-button:hover .vjs-menu{display:none}.vjs-menu li{display:flex;font-size:1.2em;justify-content:center;line-height:1.4em;list-style:none;margin:0;padding:.2em 0;text-align:center;text-transform:lowercase}.js-focus-visible .vjs-menu li.vjs-menu-item:hover,.vjs-menu li.vjs-menu-item:focus,.vjs-menu li.vjs-menu-item:hover{background-color:#73859f;background-color:rgba(115,133,159,.5)}.js-focus-visible .vjs-menu li.vjs-selected:hover,.vjs-menu li.vjs-selected,.vjs-menu li.vjs-selected:focus,.vjs-menu li.vjs-selected:hover{background-color:#fff;color:#2b333f}.js-focus-visible .vjs-menu li.vjs-selected:hover .vjs-svg-icon,.vjs-menu li.vjs-selected .vjs-svg-icon,.vjs-menu li.vjs-selected:focus .vjs-svg-icon,.vjs-menu li.vjs-selected:hover .vjs-svg-icon{fill:#000}.js-focus-visible .vjs-menu :not(.vjs-selected):focus:not(.focus-visible),.video-js .vjs-menu :not(.vjs-selected):focus:not(:focus-visible){background:none}.vjs-menu li.vjs-menu-title{cursor:default;font-size:1em;font-weight:700;line-height:2em;margin:0 0 .3em;padding:0;text-align:center;text-transform:uppercase}.vjs-menu-button-popup .vjs-menu{border-top-color:rgba(43,51,63,.7);bottom:0;display:none;height:0;left:-3em;margin-bottom:1.5em;position:absolute;width:10em}.vjs-pip-window .vjs-menu-button-popup .vjs-menu{left:unset;right:1em}.vjs-menu-button-popup .vjs-menu .vjs-menu-content{background-color:#2b333f;background-color:rgba(43,51,63,.7);bottom:1.5em;max-height:15em;position:absolute;width:100%}.vjs-layout-tiny .vjs-menu-button-popup .vjs-menu .vjs-menu-content,.vjs-layout-x-small .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:5em}.vjs-layout-small .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:10em}.vjs-layout-medium .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:14em}.vjs-layout-huge .vjs-menu-button-popup .vjs-menu .vjs-menu-content,.vjs-layout-large .vjs-menu-button-popup .vjs-menu .vjs-menu-content,.vjs-layout-x-large .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:25em}.vjs-menu-button-popup .vjs-menu.vjs-lock-showing,.vjs-workinghover .vjs-menu-button-popup.vjs-hover .vjs-menu{display:block}.video-js .vjs-menu-button-inline{overflow:hidden;transition:all .4s}.video-js .vjs-menu-button-inline:before{width:2.222222222em}.video-js .vjs-menu-button-inline.vjs-slider-active,.video-js .vjs-menu-button-inline:focus,.video-js .vjs-menu-button-inline:hover{width:12em}.vjs-menu-button-inline .vjs-menu{height:100%;left:4em;margin:0;opacity:0;padding:0;position:absolute;top:0;transition:all .4s;width:auto}.vjs-menu-button-inline.vjs-slider-active .vjs-menu,.vjs-menu-button-inline:focus .vjs-menu,.vjs-menu-button-inline:hover .vjs-menu{display:block;opacity:1}.vjs-menu-button-inline .vjs-menu-content{height:100%;margin:0;overflow:hidden;width:auto}.video-js .vjs-control-bar{background-color:#2b333f;background-color:rgba(43,51,63,.7);bottom:0;display:none;height:3em;left:0;position:absolute;right:0;width:100%}.video-js.vjs-spatial-navigation-enabled .vjs-control-bar{gap:1px}.video-js:not(.vjs-controls-disabled,.vjs-using-native-controls,.vjs-error) .vjs-control-bar.vjs-lock-showing{display:flex!important}.vjs-audio-only-mode .vjs-control-bar,.vjs-has-started .vjs-control-bar{display:flex;opacity:1;transition:visibility .1s,opacity .1s;visibility:visible}.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar{opacity:0;pointer-events:none;transition:visibility 1s,opacity 1s;visibility:visible}.vjs-controls-disabled .vjs-control-bar,.vjs-error .vjs-control-bar,.vjs-using-native-controls .vjs-control-bar{display:none!important}.vjs-audio-only-mode.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar,.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar{opacity:1;pointer-events:auto;visibility:visible}.video-js .vjs-control{flex:none;height:100%;margin:0;padding:0;position:relative;text-align:center;width:4em}.video-js .vjs-control.vjs-visible-text{padding-left:1em;padding-right:1em;width:auto}.vjs-button>.vjs-icon-placeholder:before{font-size:1.8em;line-height:1.67}.vjs-button>.vjs-icon-placeholder{display:block}.vjs-button>.vjs-svg-icon{display:inline-block}.video-js .vjs-control:focus,.video-js .vjs-control:focus:before,.video-js .vjs-control:hover:before{text-shadow:0 0 1em #fff}.video-js :not(.vjs-visible-text)>.vjs-control-text{clip:rect(0 0 0 0);border:0;height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.video-js .vjs-custom-control-spacer{display:none}.video-js .vjs-progress-control{align-items:center;cursor:pointer;display:flex;flex:auto;min-width:4em;touch-action:none}.video-js .vjs-progress-control.disabled{cursor:default}.vjs-live .vjs-progress-control{display:none}.vjs-liveui .vjs-progress-control{align-items:center;display:flex}.video-js .vjs-progress-holder{flex:auto;height:.3em;transition:all .2s}.video-js .vjs-progress-control .vjs-progress-holder{margin:0 10px}.video-js .vjs-progress-control:hover .vjs-progress-holder,.video-js.vjs-scrubbing.vjs-touch-enabled .vjs-progress-control .vjs-progress-holder{font-size:1.6666666667em}.video-js .vjs-progress-control:hover .vjs-progress-holder.disabled{font-size:1em}.video-js .vjs-progress-holder .vjs-load-progress,.video-js .vjs-progress-holder .vjs-load-progress div,.video-js .vjs-progress-holder .vjs-play-progress{display:block;height:100%;margin:0;padding:0;position:absolute;width:0}.video-js .vjs-play-progress{background-color:#fff}.video-js .vjs-play-progress:before{font-size:.9em;line-height:.35em;position:absolute;right:-.5em;z-index:1}.vjs-svg-icons-enabled .vjs-play-progress:before{content:none!important}.vjs-play-progress .vjs-svg-icon{height:.9em;line-height:.15em;pointer-events:none;position:absolute;right:-.4em;top:-.35em;width:.9em;z-index:1}.video-js .vjs-load-progress{background:rgba(115,133,159,.5)}.video-js .vjs-load-progress div{background:rgba(115,133,159,.75)}.video-js .vjs-time-tooltip{background-color:#fff;background-color:hsla(0,0%,100%,.8);border-radius:.3em;color:#000;float:right;font-family:Arial,Helvetica,sans-serif;font-size:1em;padding:6px 8px 8px;pointer-events:none;position:absolute;top:-3.4em;visibility:hidden;z-index:1}.video-js .vjs-progress-holder:focus .vjs-time-tooltip{display:none}.video-js .vjs-progress-control:hover .vjs-progress-holder:focus .vjs-time-tooltip,.video-js .vjs-progress-control:hover .vjs-time-tooltip,.video-js.vjs-scrubbing.vjs-touch-enabled .vjs-progress-control .vjs-time-tooltip{display:block;font-size:.6em;visibility:visible}.video-js .vjs-progress-control.disabled:hover .vjs-time-tooltip{font-size:1em}.video-js .vjs-progress-control .vjs-mouse-display{background-color:#000;display:none;height:100%;position:absolute;width:1px;z-index:1}.video-js .vjs-progress-control:hover .vjs-mouse-display,.video-js.vjs-scrubbing.vjs-touch-enabled .vjs-progress-control .vjs-mouse-display{display:block}.video-js.vjs-touch-enabled:not(.vjs-scrubbing) .vjs-progress-control .vjs-mouse-display,.video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display{opacity:0;transition:visibility 1s,opacity 1s;visibility:hidden}.vjs-mouse-display .vjs-time-tooltip{background-color:#000;background-color:rgba(0,0,0,.8);color:#fff}.video-js .vjs-slider{-webkit-touch-callout:none;background-color:#73859f;background-color:rgba(115,133,159,.5);cursor:pointer;margin:0 .45em;padding:0;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none}.video-js .vjs-slider.disabled{cursor:default}.video-js .vjs-slider:focus{box-shadow:0 0 1em #fff;text-shadow:0 0 1em #fff}.video-js.vjs-spatial-navigation-enabled .vjs-slider:focus{outline:.0625em solid #fff}.video-js .vjs-mute-control{cursor:pointer;flex:none}.video-js .vjs-volume-control{cursor:pointer;display:flex;margin-right:1em}.video-js .vjs-volume-control.vjs-volume-horizontal{width:5em}.video-js .vjs-volume-panel .vjs-volume-control{height:1px;margin-left:-1px;opacity:0;visibility:visible;width:1px}.video-js .vjs-volume-panel{transition:width 1s}.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active,.video-js .vjs-volume-panel .vjs-volume-control:active,.video-js .vjs-volume-panel.vjs-hover .vjs-mute-control~.vjs-volume-control,.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control,.video-js .vjs-volume-panel:active .vjs-volume-control,.video-js .vjs-volume-panel:focus .vjs-volume-control{opacity:1;position:relative;transition:visibility .1s,opacity .1s,height .1s,width .1s,left 0s,top 0s;visibility:visible}.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-horizontal,.video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-horizontal,.video-js .vjs-volume-panel.vjs-hover .vjs-mute-control~.vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-horizontal{height:3em;margin-right:0;width:5em}.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-vertical,.video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-vertical,.video-js .vjs-volume-panel.vjs-hover .vjs-mute-control~.vjs-volume-control.vjs-volume-vertical,.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control.vjs-volume-vertical,.video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-vertical,.video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-vertical{left:-3.5em;transition:left 0s}.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js .vjs-volume-panel.vjs-volume-panel-horizontal:active{transition:width .1s;width:10em}.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-mute-toggle-only{width:4em}.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical{height:8em;left:-3000em;transition:visibility 1s,opacity 1s,height 1s 1s,width 1s 1s,left 1s 1s,top 1s 1s;width:3em}.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal{transition:visibility 1s,opacity 1s,height 1s 1s,width 1s,left 1s 1s,top 1s 1s}.video-js .vjs-volume-panel{display:flex}.video-js .vjs-volume-bar{margin:1.35em .45em}.vjs-volume-bar.vjs-slider-horizontal{height:.3em;width:5em}.vjs-volume-bar.vjs-slider-vertical{height:5em;margin:1.35em auto;width:.3em}.video-js .vjs-volume-level{background-color:#fff;bottom:0;left:0;position:absolute}.video-js .vjs-volume-level:before{font-size:.9em;position:absolute;z-index:1}.vjs-slider-vertical .vjs-volume-level{width:.3em}.vjs-slider-vertical .vjs-volume-level:before{left:-.3em;top:-.5em;z-index:1}.vjs-svg-icons-enabled .vjs-volume-level:before{content:none}.vjs-volume-level .vjs-svg-icon{height:.9em;pointer-events:none;position:absolute;width:.9em;z-index:1}.vjs-slider-horizontal .vjs-volume-level{height:.3em}.vjs-slider-horizontal .vjs-volume-level:before{line-height:.35em;right:-.5em}.vjs-slider-horizontal .vjs-volume-level .vjs-svg-icon{right:-.3em;transform:translateY(-50%)}.vjs-slider-vertical .vjs-volume-level .vjs-svg-icon{top:-.55em;transform:translateX(-50%)}.video-js .vjs-volume-panel.vjs-volume-panel-vertical{width:4em}.vjs-volume-bar.vjs-slider-vertical .vjs-volume-level{height:100%}.vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level{width:100%}.video-js .vjs-volume-vertical{background-color:#2b333f;background-color:rgba(43,51,63,.7);bottom:8em;height:8em;width:3em}.video-js .vjs-volume-horizontal .vjs-menu{left:-2em}.video-js .vjs-volume-tooltip{background-color:#fff;background-color:hsla(0,0%,100%,.8);border-radius:.3em;color:#000;float:right;font-family:Arial,Helvetica,sans-serif;font-size:1em;padding:6px 8px 8px;pointer-events:none;position:absolute;top:-3.4em;visibility:hidden;z-index:1}.video-js .vjs-volume-control:hover .vjs-progress-holder:focus .vjs-volume-tooltip,.video-js .vjs-volume-control:hover .vjs-volume-tooltip{display:block;font-size:1em;visibility:visible}.video-js .vjs-volume-vertical:hover .vjs-progress-holder:focus .vjs-volume-tooltip,.video-js .vjs-volume-vertical:hover .vjs-volume-tooltip{left:1em;top:-12px}.video-js .vjs-volume-control.disabled:hover .vjs-volume-tooltip{font-size:1em}.video-js .vjs-volume-control .vjs-mouse-display{background-color:#000;display:none;height:1px;position:absolute;width:100%;z-index:1}.video-js .vjs-volume-horizontal .vjs-mouse-display{height:100%;width:1px}.video-js .vjs-volume-control:hover .vjs-mouse-display{display:block}.video-js.vjs-user-inactive .vjs-volume-control .vjs-mouse-display{opacity:0;transition:visibility 1s,opacity 1s;visibility:hidden}.vjs-mouse-display .vjs-volume-tooltip{background-color:#000;background-color:rgba(0,0,0,.8);color:#fff}.vjs-poster{bottom:0;cursor:pointer;display:inline-block;height:100%;left:0;margin:0;padding:0;position:absolute;right:0;top:0;vertical-align:middle}.vjs-has-started .vjs-poster,.vjs-using-native-controls .vjs-poster{display:none}.vjs-audio.vjs-has-started .vjs-poster,.vjs-has-started.vjs-audio-poster-mode .vjs-poster,.vjs-pip-container.vjs-has-started .vjs-poster{display:block}.vjs-poster img{height:100%;-o-object-fit:contain;object-fit:contain;width:100%}.video-js .vjs-live-control{align-items:flex-start;display:flex;flex:auto;font-size:1em;line-height:3em}.video-js.vjs-liveui .vjs-live-control,.video-js:not(.vjs-live) .vjs-live-control{display:none}.video-js .vjs-seek-to-live-control{align-items:center;cursor:pointer;display:inline-flex;flex:none;font-size:1em;height:100%;line-height:3em;min-width:4em;padding-left:.5em;padding-right:.5em;width:auto}.video-js.vjs-live:not(.vjs-liveui) .vjs-seek-to-live-control,.video-js:not(.vjs-live) .vjs-seek-to-live-control{display:none}.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge{cursor:auto}.vjs-seek-to-live-control .vjs-icon-placeholder{color:#888;margin-right:.5em}.vjs-svg-icons-enabled .vjs-seek-to-live-control{line-height:0}.vjs-seek-to-live-control .vjs-svg-icon{fill:#888;height:1em;pointer-events:none;width:1em}.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-icon-placeholder{color:red}.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-svg-icon{fill:red}.video-js .vjs-time-control{flex:none;font-size:1em;line-height:3em;min-width:2em;padding-left:1em;padding-right:1em;width:auto}.video-js .vjs-current-time,.video-js .vjs-duration,.vjs-live .vjs-time-control,.vjs-live .vjs-time-divider{display:none}.vjs-time-divider{display:none;line-height:3em}.vjs-normalise-time-controls:not(.vjs-live) .vjs-time-control{display:flex}.video-js .vjs-play-control{cursor:pointer}.video-js .vjs-play-control .vjs-icon-placeholder{flex:none}.vjs-text-track-display{bottom:3em;left:0;pointer-events:none;position:absolute;right:0;top:0}.vjs-error .vjs-text-track-display{display:none}.video-js.vjs-controls-disabled .vjs-text-track-display,.video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display{bottom:1em}.video-js .vjs-text-track{font-size:1.4em;margin-bottom:.1em;text-align:center}.vjs-subtitles{color:#fff}.vjs-captions{color:#fc6}.vjs-tt-cue{display:block}video::-webkit-media-text-track-display{transform:translateY(-3em)}.video-js.vjs-controls-disabled video::-webkit-media-text-track-display,.video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display{transform:translateY(-1.5em)}.video-js.vjs-force-center-align-cues .vjs-text-track-cue{text-align:center!important;width:80%!important}@supports not (inset:10px){.video-js .vjs-text-track-display>div{bottom:0;left:0;right:0;top:0}}.video-js .vjs-picture-in-picture-control{cursor:pointer;flex:none}.video-js.vjs-audio-only-mode .vjs-picture-in-picture-control,.vjs-pip-window .vjs-picture-in-picture-control{display:none}.video-js .vjs-fullscreen-control{cursor:pointer;flex:none}.video-js.vjs-audio-only-mode .vjs-fullscreen-control,.vjs-pip-window .vjs-fullscreen-control{display:none}.vjs-playback-rate .vjs-playback-rate-value,.vjs-playback-rate>.vjs-menu-button{height:100%;left:0;position:absolute;top:0;width:100%}.vjs-playback-rate .vjs-playback-rate-value{font-size:1.5em;line-height:2;pointer-events:none;text-align:center}.vjs-playback-rate .vjs-menu{left:0;width:4em}.vjs-error .vjs-error-display .vjs-modal-dialog-content{font-size:1.4em;text-align:center}.vjs-loading-spinner{background-clip:padding-box;border:.6em solid rgba(43,51,63,.7);border-radius:50%;box-sizing:border-box;display:none;height:5em;left:50%;opacity:.85;position:absolute;text-align:left;top:50%;transform:translate(-50%,-50%);visibility:hidden;width:5em}.vjs-seeking .vjs-loading-spinner,.vjs-waiting .vjs-loading-spinner{align-items:center;animation:vjs-spinner-show 0s linear .3s forwards;display:flex;justify-content:center}.vjs-error .vjs-loading-spinner{display:none}.vjs-loading-spinner:after,.vjs-loading-spinner:before{border:inherit;border-color:#fff transparent transparent;border-radius:inherit;box-sizing:inherit;content:"";height:inherit;opacity:1;position:absolute;width:inherit}.vjs-seeking .vjs-loading-spinner:after,.vjs-seeking .vjs-loading-spinner:before,.vjs-waiting .vjs-loading-spinner:after,.vjs-waiting .vjs-loading-spinner:before{animation:vjs-spinner-spin 1.1s cubic-bezier(.6,.2,0,.8) infinite,vjs-spinner-fade 1.1s linear infinite}.vjs-seeking .vjs-loading-spinner:before,.vjs-waiting .vjs-loading-spinner:before{border-top-color:#fff}.vjs-seeking .vjs-loading-spinner:after,.vjs-waiting .vjs-loading-spinner:after{animation-delay:.44s;border-top-color:#fff}@keyframes vjs-spinner-show{to{visibility:visible}}@keyframes vjs-spinner-spin{to{transform:rotate(1turn)}}@keyframes vjs-spinner-fade{0%{border-top-color:#73859f}20%{border-top-color:#73859f}35%{border-top-color:#fff}60%{border-top-color:#73859f}to{border-top-color:#73859f}}.video-js.vjs-audio-only-mode .vjs-captions-button{display:none}.vjs-chapters-button .vjs-menu ul{width:24em}.video-js.vjs-audio-only-mode .vjs-descriptions-button{display:none}.vjs-subs-caps-button+.vjs-menu .vjs-captions-menu-item .vjs-svg-icon{height:1.5em;width:1.5em}.video-js .vjs-subs-caps-button+.vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder{display:inline-block;margin-bottom:-.1em;vertical-align:middle}.video-js .vjs-subs-caps-button+.vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before{content:"\f10c";font-family:VideoJS;font-size:1.5em;line-height:inherit}.video-js.vjs-audio-only-mode .vjs-subs-caps-button{display:none}.video-js .vjs-audio-button+.vjs-menu .vjs-descriptions-menu-item .vjs-menu-item-text .vjs-icon-placeholder,.video-js .vjs-audio-button+.vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder{display:inline-block;margin-bottom:-.1em;vertical-align:middle}.video-js .vjs-audio-button+.vjs-menu .vjs-descriptions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before,.video-js .vjs-audio-button+.vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before{content:" \f12e";font-family:VideoJS;font-size:1.5em;line-height:inherit}.video-js.vjs-layout-small .vjs-current-time,.video-js.vjs-layout-small .vjs-duration,.video-js.vjs-layout-small .vjs-playback-rate,.video-js.vjs-layout-small .vjs-remaining-time,.video-js.vjs-layout-small .vjs-time-divider,.video-js.vjs-layout-small .vjs-volume-control,.video-js.vjs-layout-tiny .vjs-current-time,.video-js.vjs-layout-tiny .vjs-duration,.video-js.vjs-layout-tiny .vjs-playback-rate,.video-js.vjs-layout-tiny .vjs-remaining-time,.video-js.vjs-layout-tiny .vjs-time-divider,.video-js.vjs-layout-tiny .vjs-volume-control,.video-js.vjs-layout-x-small .vjs-current-time,.video-js.vjs-layout-x-small .vjs-duration,.video-js.vjs-layout-x-small .vjs-playback-rate,.video-js.vjs-layout-x-small .vjs-remaining-time,.video-js.vjs-layout-x-small .vjs-time-divider,.video-js.vjs-layout-x-small .vjs-volume-control{display:none}.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal:active,.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal:hover,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal:active,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal:hover,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal:active,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal:hover{width:auto}.video-js.vjs-layout-tiny .vjs-progress-control,.video-js.vjs-layout-x-small .vjs-progress-control{display:none}.video-js.vjs-layout-x-small .vjs-custom-control-spacer{display:block;flex:auto}.vjs-modal-dialog.vjs-text-track-settings{background-color:#2b333f;background-color:rgba(43,51,63,.75);color:#fff;height:70%}.vjs-spatial-navigation-enabled .vjs-modal-dialog.vjs-text-track-settings{height:80%}.vjs-error .vjs-text-track-settings{display:none}.vjs-text-track-settings .vjs-modal-dialog-content{display:table}.vjs-text-track-settings .vjs-track-settings-colors,.vjs-text-track-settings .vjs-track-settings-controls,.vjs-text-track-settings .vjs-track-settings-font{display:table-cell}.vjs-text-track-settings .vjs-track-settings-controls{text-align:right;vertical-align:bottom}@supports (display:grid){.vjs-text-track-settings .vjs-modal-dialog-content{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr;padding:20px 24px 0}.vjs-track-settings-controls .vjs-default-button{margin-bottom:20px}.vjs-text-track-settings .vjs-track-settings-controls{grid-column:1/-1}.vjs-layout-small .vjs-text-track-settings .vjs-modal-dialog-content,.vjs-layout-tiny .vjs-text-track-settings .vjs-modal-dialog-content,.vjs-layout-x-small .vjs-text-track-settings .vjs-modal-dialog-content{grid-template-columns:1fr}}.vjs-text-track-settings select{font-size:inherit}.vjs-track-setting>select{margin-bottom:.5em;margin-right:1em}.vjs-text-track-settings fieldset{border:none;margin:10px}.vjs-text-track-settings fieldset span{display:inline-block;padding:0 .6em .8em}.vjs-text-track-settings fieldset span>select{max-width:7.3em}.vjs-text-track-settings legend{color:#fff;font-size:1.2em;font-weight:700}.vjs-text-track-settings .vjs-label{margin:0 .5em .5em 0}.vjs-track-settings-controls button:active,.vjs-track-settings-controls button:focus{background-image:linear-gradient(0deg,#fff 88%,#73859f);outline-style:solid;outline-width:medium}.vjs-track-settings-controls button:hover{color:rgba(43,51,63,.75)}.vjs-track-settings-controls button{background-color:#fff;background-image:linear-gradient(-180deg,#fff 88%,#73859f);border-radius:2px;color:#2b333f;cursor:pointer}.vjs-track-settings-controls .vjs-default-button{margin-right:1em}.vjs-title-bar{background:rgba(0,0,0,.9);background:linear-gradient(180deg,rgba(0,0,0,.9),rgba(0,0,0,.7) 60%,transparent);font-size:1.2em;line-height:1.5;padding:.666em 1.333em 4em;pointer-events:none;position:absolute;top:0;transition:opacity .1s;width:100%}.vjs-error .vjs-title-bar{display:none}.vjs-title-bar-description,.vjs-title-bar-title{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vjs-title-bar-title{font-weight:700;margin-bottom:.333em}.vjs-playing.vjs-user-inactive .vjs-title-bar{opacity:0;transition:opacity 1s}.video-js .vjs-skip-backward-10,.video-js .vjs-skip-backward-30,.video-js .vjs-skip-backward-5,.video-js .vjs-skip-forward-10,.video-js .vjs-skip-forward-30,.video-js .vjs-skip-forward-5{cursor:pointer}.video-js .vjs-transient-button{align-items:center;background-color:rgba(50,50,50,.5);cursor:pointer;display:flex;height:3em;justify-content:center;opacity:1;position:absolute;transition:opacity 1s}.video-js:not(.vjs-has-started) .vjs-transient-button{display:none}.video-js.not-hover .vjs-transient-button:not(.force-display),.video-js.vjs-user-inactive .vjs-transient-button:not(.force-display){opacity:0}.video-js .vjs-transient-button span{padding:0 .5em}.video-js .vjs-transient-button.vjs-left{left:1em}.video-js .vjs-transient-button.vjs-right{right:1em}.video-js .vjs-transient-button.vjs-top{top:1em}.video-js .vjs-transient-button.vjs-near-top{top:4em}.video-js .vjs-transient-button.vjs-bottom{bottom:4em}.video-js .vjs-transient-button:hover{background-color:rgba(50,50,50,.9)}@media print{.video-js>:not(.vjs-tech):not(.vjs-poster){visibility:hidden}}.vjs-resize-manager{border:none;height:100%;left:0;position:absolute;top:0;width:100%;z-index:-1000}.js-focus-visible .video-js :focus:not(.focus-visible){outline:none}.video-js :focus:not(:focus-visible){outline:none}
2
+
3
+ /*! tailwindcss v4.1.17 | MIT License | https://tailwindcss.com */@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap");@import url("https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");@font-face{font-display:swap;font-family:SeriouslyNostalgic Fn;font-style:normal;font-weight:400;src:url(fonts/SeriouslyNostalgicFn-SemiCond.eot);src:url(fonts/SeriouslyNostalgicFn-SemiCond.eot?#iefix) format("embedded-opentype"),url(fonts/SeriouslyNostalgicFn-SemiCond.woff2) format("woff2"),url(fonts/SeriouslyNostalgicFn-SemiCond.woff) format("woff"),url(fonts/SeriouslyNostalgicFn-SemiCond.ttf) format("truetype"),url(fonts/SeriouslyNostalgicFn-SemiCond.svg#SeriouslyNostalgicFn-SemiCond) format("svg")}@font-face{font-display:swap;font-family:SeriouslyNostalgic Fn;font-style:italic;font-weight:400;src:url(fonts/SeriouslyNostalgicFnIt-SmCn.eot);src:url(fonts/SeriouslyNostalgicFnIt-SmCn.eot?#iefix) format("embedded-opentype"),url(fonts/SeriouslyNostalgicFnIt-SmCn.woff2) format("woff2"),url(fonts/SeriouslyNostalgicFnIt-SmCn.woff) format("woff"),url(fonts/SeriouslyNostalgicFnIt-SmCn.ttf) format("truetype"),url(fonts/SeriouslyNostalgicFnIt-SmCn.svg#SeriouslyNostalgicFnIt-SmCn) format("svg")}@font-face{font-display:swap;font-family:Switzer;font-style:normal;font-weight:400;src:url(fonts/Switzer-Regular.eot);src:url(fonts/Switzer-Regular.eot?#iefix) format("embedded-opentype"),url(fonts/Switzer-Regular.woff2) format("woff2"),url(fonts/Switzer-Regular.woff) format("woff"),url(fonts/Switzer-Regular.ttf) format("truetype"),url(fonts/Switzer-Regular.svg#Switzer-Regular) format("svg")}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.top-\[\.5rem\]{top:.5rem}.top-\[0\]{top:0}.top-\[1rem\]{top:1rem}.top-\[8px\]{top:8px}.top-\[20px\]{top:20px}.top-\[60px\]{top:60px}.right-\[8px\]{right:8px}.right-\[20px\]{right:20px}.bottom-\[0\]{bottom:0}.bottom-\[1rem\]{bottom:1rem}.bottom-\[2rem\]{bottom:2rem}.bottom-\[5rem\]{bottom:5rem}.bottom-\[8rem\]{bottom:8rem}.bottom-\[30px\]{bottom:30px}.left-\[0\]{left:0}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-\[0\]{z-index:0}.z-\[9\]{z-index:9}.z-\[99\]{z-index:99}.z-\[999\]{z-index:999}.mx-auto{margin-inline:auto}.my-\[0\.5rem\]{margin-block:.5rem}.my-\[1\.5rem\]{margin-block:1.5rem}.mt-\[\.5rem\]{margin-top:.5rem}.mt-\[\.25rem\]{margin-top:.25rem}.mt-\[\.75rem\]{margin-top:.75rem}.mt-\[0\.2rem\]{margin-top:.2rem}.mt-\[0\.5rem\]{margin-top:.5rem}.mt-\[1rem\]{margin-top:1rem}.mt-\[3\.5rem\]{margin-top:3.5rem}.mb-\[\.5rem\]{margin-bottom:.5rem}.mb-\[\.25rem\]{margin-bottom:.25rem}.mb-\[\.75rem\]{margin-bottom:.75rem}.mb-\[0\.5rem\]{margin-bottom:.5rem}.mb-\[1\.5rem\]{margin-bottom:1.5rem}.mb-\[1\.25rem\]{margin-bottom:1.25rem}.mb-\[1rem\]{margin-bottom:1rem}.mb-\[2rem\]{margin-bottom:2rem}.flex{display:flex}.hidden{display:none}.table{display:table}.aspect-\[2\/1\.4\]{aspect-ratio:2/1.4}.\!h-\[35px\]{height:35px!important}.\!h-\[40px\]{height:40px!important}.h-\[\.375rem\]{height:.375rem}.h-\[1rem\]{height:1rem}.h-\[3px\]{height:3px}.h-\[3rem\]{height:3rem}.h-\[4rem\]{height:4rem}.h-\[6rem\]{height:6rem}.h-\[20px\]{height:20px}.h-\[40px\]{height:40px}.h-\[45px\]{height:45px}.h-\[100vh\]{height:100vh}.h-\[var\(--real-vh\)\]{height:var(--real-vh)}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[calc\(100vh-450px\)\]{max-height:calc(100vh - 450px)}.min-h-\[33px\]{min-height:33px}.min-h-\[40px\]{min-height:40px}.\!w-\[60px\]{width:60px!important}.\!w-\[180px\]{width:180px!important}.w-\[1px\]{width:1px}.w-\[1rem\]{width:1rem}.w-\[3rem\]{width:3rem}.w-\[4rem\]{width:4rem}.w-\[6rem\]{width:6rem}.w-\[12rem\]{width:12rem}.w-\[20px\]{width:20px}.w-\[30px\]{width:30px}.w-\[50px\]{width:50px}.w-\[100px\]{width:100px}.w-\[120px\]{width:120px}.w-\[180px\]{width:180px}.w-full{width:100%}.w-screen{width:100vw}.max-w-\[20rem\]{max-width:20rem}.max-w-\[28rem\]{max-width:28rem}.max-w-\[280px\]{max-width:280px}.max-w-\[400px\]{max-width:400px}.min-w-\[120px\]{min-width:120px}.flex-1{flex:1}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-\[0\.5rem\],.gap-\[\.5rem\]{gap:.5rem}.gap-\[1rem\]{gap:1rem}.gap-\[4px\]{gap:4px}.gap-\[5px\]{gap:5px}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded-\[\.375rem\]{border-radius:.375rem}.rounded-\[4px\]{border-radius:4px}.rounded-\[20px\]{border-radius:20px}.rounded-\[9999px\]{border-radius:9999px}.rounded-t-\[20px\]{border-top-left-radius:20px;border-top-right-radius:20px}.rounded-t-\[30px\]{border-top-left-radius:30px;border-top-right-radius:30px}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-none{--tw-border-style:none;border-style:none}.border-\[\#fff\]{border-color:#fff}.\!bg-\[\#ffffff\]{background-color:#fff!important}.bg-\[\#1b1b1b\]{background-color:#1b1b1b}.bg-\[\#8B5CF6\]{background-color:#8b5cf6}.bg-\[\#fff\]\/10{background-color:color-mix(in oklab,#fff 10%,transparent)}.bg-\[\#fff\]\/20{background-color:color-mix(in oklab,#fff 20%,transparent)}.bg-\[\#fff\]\/30{background-color:color-mix(in oklab,#fff 30%,transparent)}.bg-\[\#fff\]\/70{background-color:color-mix(in oklab,#fff 70%,transparent)}.bg-\[\#fff\]\/80{background-color:color-mix(in oklab,#fff 80%,transparent)}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-\[1\.5rem\]{padding:1.5rem}.p-\[1rem\]{padding:1rem}.p-\[15px\]{padding:15px}.p-\[16px\]{padding:16px}.px-\[\.75rem\]{padding-inline:.75rem}.px-\[1rem\]{padding-inline:1rem}.px-\[15px\]{padding-inline:15px}.\!py-\[0\]{padding-block:0!important}.py-\[1rem\]{padding-block:1rem}.py-\[6px\]{padding-block:6px}.pt-\[\.5rem\]{padding-top:.5rem}.pt-\[1\.5rem\]{padding-top:1.5rem}.pt-\[1rem\]{padding-top:1rem}.pt-\[15px\]{padding-top:15px}.\!pr-\[10px\]{padding-right:10px!important}.pr-\[2\.5rem\]{padding-right:2.5rem}.pb-\[\.5rem\]{padding-bottom:.5rem}.pl-\[1rem\]{padding-left:1rem}.text-center{text-align:center}.text-left{text-align:left}.text-\[\.75rem\]{font-size:.75rem}.text-\[1\.5rem\]{font-size:1.5rem}.text-\[3rem\]{font-size:3rem}.text-\[14px\]{font-size:14px}.text-\[16px\]{font-size:16px}.text-\[32px\]{font-size:32px}.leading-none{--tw-leading:1;line-height:1}.\!text-\[\#000000\]{color:#000!important}.text-\[\#000\]\/70{color:color-mix(in oklab,#000 70%,transparent)}.text-\[\#fff\]{color:#fff}.text-\[\#fff\]\/40{color:color-mix(in oklab,#fff 40%,transparent)}.text-\[\#fff\]\/70{color:color-mix(in oklab,#fff 70%,transparent)}.\!opacity-50{opacity:50%!important}.opacity-0{opacity:0}.opacity-50{opacity:50%}.opacity-100{opacity:100%}.\!shadow-none{--tw-shadow:0 0 #0000!important;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)!important}.shadow-\[0_0_8px_rgba\(139\,92\,246\,0\.8\)\]{--tw-shadow:0 0 8px var(--tw-shadow-color,rgba(139,92,246,.8))}.shadow-\[0_0_8px_rgba\(139\,92\,246\,0\.8\)\],.shadow-\[0_1px_1px_rgba\(0\,0\,0\,0\.251\)\]{box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_1px_1px_rgba\(0\,0\,0\,0\.251\)\]{--tw-shadow:0 1px 1px var(--tw-shadow-color,rgba(0,0,0,.251))}.shadow-\[0px_1px_2px_0px_\#00000040\]{--tw-shadow:0px 1px 2px 0px var(--tw-shadow-color,#00000040)}.ring,.shadow-\[0px_1px_2px_0px_\#00000040\]{box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-duration:var(--tw-duration,0s);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,ease)}.transition-all{transition-duration:var(--tw-duration,0s);transition-property:all;transition-timing-function:var(--tw-ease,ease)}.duration-200{--tw-duration:200ms;transition-duration:.2s}.duration-300{--tw-duration:300ms;transition-duration:.3s}.\!outline-none{--tw-outline-style:none!important;outline-style:none!important}.outline-none{--tw-outline-style:none;outline-style:none}.file\:border-0{&::file-selector-button{border-style:var(--tw-border-style);border-width:0}}.file\:bg-transparent{&::file-selector-button{background-color:transparent}}.focus\:ring-1{&:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.focus\:outline-none{&:focus{--tw-outline-style:none;outline-style:none}}.focus-visible\:ring-2{&:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.focus-visible\:ring-offset-2{&:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}}.focus-visible\:outline-none{&:focus-visible{--tw-outline-style:none;outline-style:none}}.disabled\:cursor-not-allowed{&:disabled{cursor:not-allowed}}.disabled\:shadow-none{&:disabled{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.\[\&_svg\]\:size-\[16px\]{& svg{height:16px;width:16px}}.\[\&_svg\]\:shrink-0{& svg{flex-shrink:0}}.\[\&_video\]\:rounded-t-\[20px\]{& video{border-top-left-radius:20px;border-top-right-radius:20px}}#root,body,html{-webkit-font-smoothing:antialiased;height:100%;overscroll-behavior:none;overscroll-behavior-y:none;text-rendering:optimizeLegibility;width:100%}*{box-sizing:border-box}h1,h2,h3,h4,p{line-height:1.5;margin:0;padding:0}.camera-drawer .MuiPaper-root{background-color:transparent!important;box-shadow:0 0 0!important;height:80%}.vjs-poster{background-size:cover}.video-js.vjs-paused .vjs-big-play-button{display:none!important}.vjs-poster{background-color:#fff;background-position:center 20px;background-size:90%}.video-js.vjs-paused .vjs-big-play-button{align-items:center;background-color:#fff;border:1px solid #d9d9d9!important;border-radius:100%;bottom:50%;display:flex;height:50px;left:50%;top:auto;transform:translate(-50%,-135%);width:50px}.video-js.vjs-paused .vjs-icon-placeholder{color:#d9d9d9!important;font-size:50px}.camera-drawer .MuiModal-backdrop{backdrop-filter:blur(10px);pointer-events:none}.camera-drawer .MuiModal-backdrop,.video-js{background-color:transparent!important}.vjs-fluid:not(.vjs-audio-only-mode){min-height:85vh}input::-webkit-inner-spin-button,input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.camera-drawer.face-scan-small .MuiModal-backdrop{backdrop-filter:blur(0)}.face-scan-small .MuiPaper-root{border-top-left-radius:30px;border-top-right-radius:30px;height:315px}.confirm-modal .MuiPaper-root{background-color:#fff;border-radius:10px;padding:20px 10px}.confirm-modal{pointer-events:none}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@layer properties{@supports ((-webkit-hyphens:none) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,::backdrop,:after,:before{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial}}}