@vincentt-xr/sdk 2.0.0-alpha.0

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 (159) hide show
  1. package/GROUNDING.md +537 -0
  2. package/LICENSE +7 -0
  3. package/README.md +85 -0
  4. package/dist/DebuggerUI-CEfdddkZ.cjs +1 -0
  5. package/dist/DebuggerUI-Dgop6Q6o.js +269 -0
  6. package/dist/audio/AudioEngine.d.ts +98 -0
  7. package/dist/audio/index.d.ts +34 -0
  8. package/dist/components/AspectRatioContainer/index.d.ts +10 -0
  9. package/dist/components/BodyTracker/index.d.ts +15 -0
  10. package/dist/components/Debugger/DebuggerProvider.d.ts +22 -0
  11. package/dist/components/Debugger/DebuggerUI.d.ts +13 -0
  12. package/dist/components/Debugger/index.d.ts +38 -0
  13. package/dist/components/Debugger/styles.d.ts +19 -0
  14. package/dist/components/FaceMesh/FaceMesh.d.ts +26 -0
  15. package/dist/components/FaceMesh/canonical/CanonicalFaceMeshRenderer.d.ts +34 -0
  16. package/dist/components/FaceMesh/canonical/parseCanonicalFaceModel.d.ts +16 -0
  17. package/dist/components/FaceMesh/canonical/useCanonicalFaceMesh.d.ts +15 -0
  18. package/dist/components/FaceMesh/deform.d.ts +36 -0
  19. package/dist/components/FaceMesh/index.d.ts +6 -0
  20. package/dist/components/FaceMesh/indices.d.ts +1 -0
  21. package/dist/components/FaceMesh/material/blendModes.d.ts +2 -0
  22. package/dist/components/FaceMesh/material/defaults.d.ts +3 -0
  23. package/dist/components/FaceMesh/material/index.d.ts +5 -0
  24. package/dist/components/FaceMesh/material/options.d.ts +25 -0
  25. package/dist/components/FaceMesh/material/support.d.ts +3 -0
  26. package/dist/components/FaceMesh/material/types.d.ts +23 -0
  27. package/dist/components/FaceMesh/uv.d.ts +1 -0
  28. package/dist/components/FaceRetouch/Background.d.ts +16 -0
  29. package/dist/components/FaceRetouch/index.d.ts +6 -0
  30. package/dist/components/FaceRetouch/landmarkMask.d.ts +23 -0
  31. package/dist/components/FaceRetouch/retouchRegions.d.ts +23 -0
  32. package/dist/components/FaceRetouch/useFaceRetouchMask.d.ts +14 -0
  33. package/dist/components/FaceRetouch/useFaceRetouchRegions.d.ts +12 -0
  34. package/dist/components/FaceTracker/BoundingBoxOverlay.d.ts +20 -0
  35. package/dist/components/FaceTracker/index.d.ts +54 -0
  36. package/dist/components/GestureTracker/index.d.ts +31 -0
  37. package/dist/components/GestureTrigger/index.d.ts +3 -0
  38. package/dist/components/HandTracker/index.d.ts +24 -0
  39. package/dist/components/HeadBinding/index.d.ts +31 -0
  40. package/dist/components/HeadBindingOccluder/index.d.ts +36 -0
  41. package/dist/components/HeadOccluder/index.d.ts +13 -0
  42. package/dist/components/Panel/index.d.ts +71 -0
  43. package/dist/components/PerspectiveCamera/index.d.ts +14 -0
  44. package/dist/components/ScreenSpaceUI/ScreenTransform.d.ts +54 -0
  45. package/dist/components/ScreenSpaceUI/context.d.ts +29 -0
  46. package/dist/components/ScreenSpaceUI/index.d.ts +40 -0
  47. package/dist/components/Segmentation/index.d.ts +44 -0
  48. package/dist/components/SpriteAnimation/index.d.ts +52 -0
  49. package/dist/components/TextLabel/index.d.ts +62 -0
  50. package/dist/components/TrackingAnchor/index.d.ts +74 -0
  51. package/dist/components/VideoBackground/index.d.ts +38 -0
  52. package/dist/components/XRCompositor/index.d.ts +5 -0
  53. package/dist/components/XRDebugView/index.d.ts +6 -0
  54. package/dist/components/XRLayer/index.d.ts +6 -0
  55. package/dist/components/XRMediaSurface/index.d.ts +27 -0
  56. package/dist/components/XRProvider/index.d.ts +13 -0
  57. package/dist/components/XRScene/defaults.d.ts +4 -0
  58. package/dist/components/XRScene/index.d.ts +15 -0
  59. package/dist/components/XRViewport/index.d.ts +101 -0
  60. package/dist/components/index.d.ts +26 -0
  61. package/dist/config/index.d.ts +8 -0
  62. package/dist/constants/index.d.ts +25 -0
  63. package/dist/constants/renderLayers.d.ts +25 -0
  64. package/dist/entries/all.d.ts +15 -0
  65. package/dist/entries/core.d.ts +21 -0
  66. package/dist/entries/face-effects.d.ts +19 -0
  67. package/dist/entries/internal.d.ts +16 -0
  68. package/dist/entries/low-level.d.ts +30 -0
  69. package/dist/entries/tracking.d.ts +15 -0
  70. package/dist/face-effects.cjs +252 -0
  71. package/dist/face-effects.js +3542 -0
  72. package/dist/hasFullUnitUVBounds-BGvcFsQM.js +26 -0
  73. package/dist/hasFullUnitUVBounds-p1Dl0ejX.cjs +1 -0
  74. package/dist/hooks/faceResults.d.ts +39 -0
  75. package/dist/hooks/selectors.d.ts +33 -0
  76. package/dist/hooks/useCalibrationFaceTracker.d.ts +23 -0
  77. package/dist/hooks/useDebugger/index.d.ts +25 -0
  78. package/dist/hooks/useDebugger/types.d.ts +20 -0
  79. package/dist/hooks/useFaceBoundingBox.d.ts +11 -0
  80. package/dist/hooks/useFaceResults.d.ts +31 -0
  81. package/dist/hooks/useGestureEdge.d.ts +53 -0
  82. package/dist/hooks/useMediaRecorder.d.ts +40 -0
  83. package/dist/hooks/useTrackerContext.d.ts +35 -0
  84. package/dist/hooks/useXRModel.d.ts +15 -0
  85. package/dist/hooks/useXRSession/constants.d.ts +4 -0
  86. package/dist/hooks/useXRSession/facade.d.ts +39 -0
  87. package/dist/hooks/useXRSession/fns.d.ts +5 -0
  88. package/dist/hooks/useXRSession/index.d.ts +4 -0
  89. package/dist/hooks/useXRSession/registry.d.ts +52 -0
  90. package/dist/hooks/useXRSession/store.d.ts +40 -0
  91. package/dist/index-B5J4gzn2.cjs +1 -0
  92. package/dist/index-BD-JWMjE.js +1991 -0
  93. package/dist/index-BVBVg96G.cjs +1 -0
  94. package/dist/index-CYMj26Ej.js +1331 -0
  95. package/dist/index-DtwHElmG.js +157 -0
  96. package/dist/index-PtFmD6B8.cjs +1 -0
  97. package/dist/internal-DH5d1Xnq.cjs +1 -0
  98. package/dist/internal-KOKJDxCG.js +519 -0
  99. package/dist/internal.cjs +1 -0
  100. package/dist/internal.js +14 -0
  101. package/dist/low-level.cjs +1 -0
  102. package/dist/low-level.js +941 -0
  103. package/dist/main.cjs +1 -0
  104. package/dist/main.js +612 -0
  105. package/dist/models/Base/index.d.ts +25 -0
  106. package/dist/models/Body/index.d.ts +22 -0
  107. package/dist/models/Face/constants.d.ts +2 -0
  108. package/dist/models/Face/index.d.ts +45 -0
  109. package/dist/models/Face/landmarksData.d.ts +2 -0
  110. package/dist/models/Hand/GestureTracking.d.ts +21 -0
  111. package/dist/models/Hand/HandTracking.d.ts +21 -0
  112. package/dist/models/Segmentation/index.d.ts +75 -0
  113. package/dist/models/index.d.ts +5 -0
  114. package/dist/modules/XRClient/index.d.ts +9 -0
  115. package/dist/modules/index.d.ts +1 -0
  116. package/dist/selectors-BHO6TnoC.js +59 -0
  117. package/dist/selectors-Bub0o3qy.cjs +1 -0
  118. package/dist/services/ApiService.d.ts +12 -0
  119. package/dist/services/MetricsCollector/CameraFPSTracker.d.ts +25 -0
  120. package/dist/services/MetricsCollector/MemoryTracker.d.ts +43 -0
  121. package/dist/services/MetricsCollector/RenderTimeTracker.d.ts +10 -0
  122. package/dist/services/MetricsCollector/ResolutionTracker.d.ts +26 -0
  123. package/dist/services/MetricsCollector/index.d.ts +59 -0
  124. package/dist/services/MetricsCollector/types.d.ts +47 -0
  125. package/dist/services/MetricsCollector/utils.d.ts +65 -0
  126. package/dist/texture/computeContainScale.d.ts +25 -0
  127. package/dist/texture/hasFullUnitUVBounds.d.ts +37 -0
  128. package/dist/texture/types.d.ts +20 -0
  129. package/dist/tracking.cjs +1 -0
  130. package/dist/tracking.js +344 -0
  131. package/dist/types/body.d.ts +3 -0
  132. package/dist/types/client.d.ts +3 -0
  133. package/dist/types/common.d.ts +9 -0
  134. package/dist/types/compositor.d.ts +23 -0
  135. package/dist/types/debugger.d.ts +83 -0
  136. package/dist/types/face.d.ts +67 -0
  137. package/dist/types/gesture-tracking.d.ts +15 -0
  138. package/dist/types/hand-tracking.d.ts +5 -0
  139. package/dist/types/headBinding.d.ts +67 -0
  140. package/dist/types/index.d.ts +12 -0
  141. package/dist/types/logger.d.ts +4 -0
  142. package/dist/types/model.d.ts +46 -0
  143. package/dist/types/nodes.d.ts +35 -0
  144. package/dist/types/segmentation.d.ts +31 -0
  145. package/dist/types/session.d.ts +102 -0
  146. package/dist/types/tracking.d.ts +30 -0
  147. package/dist/types/util-types.d.ts +1 -0
  148. package/dist/useFaceResults-cpsSmKKc.js +81 -0
  149. package/dist/useFaceResults-hVUJYSEY.cjs +1 -0
  150. package/dist/utils/calibrationDebug.d.ts +9 -0
  151. package/dist/utils/dataURL.d.ts +6 -0
  152. package/dist/utils/drawMediaCover.d.ts +18 -0
  153. package/dist/utils/errors.d.ts +3 -0
  154. package/dist/utils/fns.d.ts +48 -0
  155. package/dist/utils/headBinding.d.ts +85 -0
  156. package/dist/utils/integrity.d.ts +43 -0
  157. package/dist/utils/landmarkBounds.d.ts +11 -0
  158. package/dist/utils/logger.d.ts +7 -0
  159. package/package.json +113 -0
package/dist/main.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";var Y=Object.defineProperty;var K=(s,e,t)=>e in s?Y(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var E=(s,e,t)=>K(s,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react"),A=require("./index-PtFmD6B8.cjs"),W=require("./index-BVBVg96G.cjs"),f=require("react/jsx-runtime"),I=require("@react-three/fiber"),O=require("three"),N=require("./selectors-Bub0o3qy.cjs"),J=require("@react-three/drei");function Q(s){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(s){for(const t in s)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(s,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>s[t]})}}return e.default=s,Object.freeze(e)}const H=Q(O),q=9,B=16,ee=({children:s})=>{const[e,t]=u.useState({width:0,height:0});return u.useEffect(()=>{const n=()=>{const i=document.documentElement.clientWidth,c=document.documentElement.clientHeight,o=i/c,a=q/B;let r,d;o>a?(d=c,r=d*q/B):(r=i,d=r*B/q),t({width:r,height:d})};return n(),window.addEventListener("resize",n),()=>window.removeEventListener("resize",n)},[]),f.jsx("div",{style:{width:"100vw",height:`${window.innerHeight}px`,display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"#0d0d0d"},children:f.jsx("div",{style:{width:e.width,height:e.height,position:"relative"},children:s})})},te="rgba(20,40,110,0.88)",se=24,ne=512;function re({color:s=te,borderColor:e,borderWidth:t=0,borderRadius:n=se,resolution:i=ne,aspect:c=1,opacity:o=1,name:a,overlay:r=!0,position:d,rotation:M,scale:g,visible:l}){const x=u.useRef(null),T=u.useRef(null),S=u.useMemo(()=>ie({width:Math.round(i*Math.max(c,.05)),height:Math.round(i),color:s,borderColor:e,borderWidth:t,borderRadius:n}),[s,e,t,n,i,c]);u.useEffect(()=>()=>{S.dispose()},[S]);const y=u.useRef(null),b=u.useRef(o);return b.current!==o&&(b.current=o,y.current=null,T.current&&(T.current.opacity=o)),u.useEffect(()=>{const h=x.current;if(h)return h.userData.setOpacity=P=>{y.current=P,T.current&&(T.current.opacity=P)},()=>{delete h.userData.setOpacity}},[]),f.jsxs("mesh",{ref:x,name:a,position:d,rotation:M,scale:g,visible:l,children:[f.jsx("planeGeometry",{args:[1,1]}),f.jsx("meshBasicMaterial",{ref:T,map:S,transparent:!0,opacity:o,depthTest:!r,depthWrite:!r})]})}function ie(s){const{width:e,height:t,color:n,borderColor:i,borderWidth:c,borderRadius:o}=s,a=typeof OffscreenCanvas<"u"?new OffscreenCanvas(e,t):(()=>{const g=document.createElement("canvas");return g.width=e,g.height=t,g})(),r=a.getContext("2d");r.clearRect(0,0,e,t);const d=Math.min(o,Math.min(e,t)/2);r.beginPath(),r.moveTo(d,0),r.lineTo(e-d,0),r.quadraticCurveTo(e,0,e,d),r.lineTo(e,t-d),r.quadraticCurveTo(e,t,e-d,t),r.lineTo(d,t),r.quadraticCurveTo(0,t,0,t-d),r.lineTo(0,d),r.quadraticCurveTo(0,0,d,0),r.closePath(),r.fillStyle=n,r.fill(),i&&c>0&&(r.lineWidth=c,r.strokeStyle=i,r.stroke());const M=new H.CanvasTexture(a);return M.needsUpdate=!0,M}const oe=({children:s,depth:e=0})=>{const{camera:t,size:n}=I.useThree(),i=u.useMemo(()=>{if(!(t instanceof O.PerspectiveCamera))return{width:10,height:10};const c=Math.abs(t.position.z-e),o=t.fov*Math.PI/180,a=2*Math.tan(o/2)*c;return{width:a*(n.width/n.height),height:a}},[t,n,e]);return f.jsx(W.ScreenSpaceContext.Provider,{value:i,children:f.jsx("group",{position:[0,0,e],children:s})})};function Z(s,e){return!Number.isFinite(s)||!Number.isFinite(e)||s<=0||e<=0?[1,1,1]:Math.abs(s-e)<1e-6?[1,1,1]:s>e?[e/s,1,1]:[1,s/e,1]}const ae={left:-1,right:1,top:1,bottom:-1},ce=(s,e,t)=>{const n=s%e,i=Math.floor(s/e);return{x:n/e,y:(t-1-i)/t}},ue=({sheet:s,contentAspect:e,renderOrder:t,name:n})=>{const i=J.useTexture(s.url),c=u.useRef(0),o=u.useRef(-1),a=W.useScreenRectAspect(),[r,d]=e!=null?Z(a,e):[1,1];return I.useFrame((M,g)=>{i.wrapS=O.RepeatWrapping,i.wrapT=O.RepeatWrapping,i.magFilter=O.LinearFilter,i.minFilter=O.LinearFilter,i.generateMipmaps=!1,i.repeat.set(1/s.cols,1/s.rows),c.current+=g;const l=Math.floor(c.current*s.fps)%s.frames;if(l===o.current)return;o.current=l;const{x,y:T}=ce(l,s.cols,s.rows);i.offset.set(x,T)}),f.jsxs("mesh",{name:n,renderOrder:t,scale:[r,d,1],children:[f.jsx("planeGeometry",{args:[1,1]}),f.jsx("meshBasicMaterial",{map:i,transparent:!0,toneMapped:!1,depthWrite:!1})]})},le=({sheet:s,anchors:e=ae,contentAspect:t,renderOrder:n=10,name:i="spriteAnimation"})=>f.jsx(u.Suspense,{fallback:null,children:f.jsx(W.ScreenTransform,{anchors:e,children:f.jsx(ue,{sheet:s,contentAspect:t,renderOrder:n,name:i})})}),de={color:"#ffffff",fontWeight:"bold",fontFamily:"Arial, sans-serif",fontSize:48,bgColor:"rgba(20,40,110,0.88)",borderWidth:0,borderRadius:24,padding:32,aspect:2.5,resolution:512,opacity:1};function fe(s){const e={...de,...s},{text:t,color:n,fontWeight:i,fontFamily:c,fontSize:o,bgColor:a,borderColor:r,borderWidth:d,borderRadius:M,padding:g,aspect:l,resolution:x,opacity:T,name:S,overlay:y=!0,position:b,rotation:h,scale:P,visible:z}=e,[D,U]=u.useState(null),[_,F]=u.useState(null),p=u.useRef(t);p.current!==t&&(p.current=t,D!==null&&U(null));const v=u.useRef(a);v.current!==a&&(v.current=a,_!==null&&F(null));const m=u.useRef(null),C=D??t,k=_??a,j=u.useMemo(()=>he({text:C,color:n,fontWeight:i,fontFamily:c,fontSize:o,bgColor:k,borderColor:r,borderWidth:d,borderRadius:M,padding:g,height:x,width:Math.round(x*Math.max(l,.1))}),[C,n,i,c,o,k,r,d,M,g,l,x]);return u.useEffect(()=>{const R=m.current;if(R)return R.userData.setText=L=>U(L),R.userData.setBgColor=L=>F(L),()=>{delete R.userData.setText,delete R.userData.setBgColor}},[]),u.useEffect(()=>()=>{j.dispose()},[j]),f.jsxs("mesh",{ref:m,name:S,position:b,rotation:h,scale:P,visible:z,children:[f.jsx("planeGeometry",{args:[1,1]}),f.jsx("meshBasicMaterial",{map:j,transparent:!0,opacity:T,depthTest:!y,depthWrite:!y})]})}function he(s){const{width:e,height:t,text:n,color:i,fontFamily:c,fontWeight:o,padding:a}=s;let{fontSize:r,bgColor:d}=s,M;const g=typeof OffscreenCanvas<"u"?new OffscreenCanvas(e,t):(()=>{const h=document.createElement("canvas");return h.width=e,h.height=t,h})(),l=g.getContext("2d");if(l.clearRect(0,0,e,t),d!=="transparent"){const h=Math.min(s.borderRadius,Math.min(e,t)/2);l.beginPath(),l.moveTo(h,0),l.lineTo(e-h,0),l.quadraticCurveTo(e,0,e,h),l.lineTo(e,t-h),l.quadraticCurveTo(e,t,e-h,t),l.lineTo(h,t),l.quadraticCurveTo(0,t,0,t-h),l.lineTo(0,h),l.quadraticCurveTo(0,0,h,0),l.closePath(),l.fillStyle=d,l.fill(),s.borderColor&&s.borderWidth>0&&(l.lineWidth=s.borderWidth,l.strokeStyle=s.borderColor,l.stroke())}l.fillStyle=i,l.textAlign="center",l.textBaseline="middle";const x=e-a*2;let T=X(l,n,x,o,r,c);const S=Math.max(1,Math.floor((t-a*2)/(r*1.3)));T.length>S&&(r=Math.max(12,Math.round(r*.75)),T=X(l,n,x,o,r,c)),l.font=`${o} ${r}px ${c}`;const y=r*1.3,b=t/2-(T.length-1)*y/2;for(let h=0;h<T.length;h++)l.fillText(T[h],e/2,b+h*y);return M=new H.CanvasTexture(g),M.needsUpdate=!0,M}function X(s,e,t,n,i,c){s.font=`${n} ${i}px ${c}`;const o=e.split(" "),a=[];let r="";for(const d of o){const M=r?`${r} ${d}`:d;s.measureText(M).width>t&&r?(a.push(r),r=d):r=M}return r&&a.push(r),a}const pe=({segmentationMask:s,segmentation:e,invert:t=!1,customBackground:n,renderOrder:i=A.RENDER_LAYERS.BACKGROUND})=>{const{camera:c,size:o}=I.useThree(),a=N.useXRCameraTexture(),r=N.useXRModelNode(A.XRModel.BACKGROUND_SEGMENTATION),d=e?r==null?void 0:r.backgroundSegmentationMask:void 0,M=u.useRef(!1);u.useEffect(()=>{if(!e){M.current=!1;return}r===null&&!M.current&&(console.warn(`[VideoBackground] segmentation="${e}" set but no matching <Segmentation> component is mounted; rendering unmasked.`),M.current=!0)},[e,r]);const g=e?d:s,l=u.useMemo(()=>{if(!(c instanceof O.PerspectiveCamera))return[10,10];const S=(c.position.z||5)- -1,y=c.fov*Math.PI/180,b=2*Math.tan(y/2)*S;return[b*(o.width/o.height),b]},[c,o]);return a?f.jsx("group",{position:[0,0,-1],children:t?f.jsxs(f.Fragment,{children:[f.jsxs("mesh",{position:[0,0,-.01],renderOrder:i-1,children:[f.jsx("planeGeometry",{args:l}),f.jsx("meshBasicMaterial",{map:a,depthTest:!1,depthWrite:!1,toneMapped:!1})]}),n&&g&&f.jsxs("mesh",{position:[0,0,0],renderOrder:i,children:[f.jsx("planeGeometry",{args:l}),f.jsx("meshBasicMaterial",{map:typeof n=="string"?void 0:n,color:typeof n=="string"?n:void 0,alphaMap:g,transparent:!1,alphaTest:.5,depthTest:!1,depthWrite:!1,toneMapped:!1},"inverted-mask")]})]}):f.jsxs(f.Fragment,{children:[n&&g&&f.jsxs("mesh",{position:[0,0,-.01],renderOrder:i-1,children:[f.jsx("planeGeometry",{args:l}),f.jsx("meshBasicMaterial",{map:typeof n=="string"?void 0:n,color:typeof n=="string"?n:void 0,depthTest:!1,depthWrite:!1,toneMapped:!1})]}),f.jsxs("mesh",{position:[0,0,0],renderOrder:i,children:[f.jsx("planeGeometry",{args:l}),f.jsx("meshBasicMaterial",{map:a,alphaMap:g,transparent:!1,alphaTest:g?.5:void 0,depthTest:!1,depthWrite:!1,toneMapped:!1},g?"with-mask":"no-mask")]})]})}):null},me=["video/mp4","video/webm;codecs=vp9","video/webm;codecs=vp8","video/webm"];function ge(s={}){const{audio:e=!1,mimeType:t,bitsPerSecond:n,onData:i,onStop:c,passThroughStream:o}=s,a=u.useRef(null),r=u.useRef(null),d=u.useRef([]),[M,g]=u.useState(!1),[l,x]=u.useState(!1),[T,S]=u.useState(null),[y,b]=u.useState(null),h=u.useCallback(()=>{var v;const p=[t,...me].filter(Boolean);for(const m of p)if((v=MediaRecorder.isTypeSupported)!=null&&v.call(MediaRecorder,m))return m},[t]),P=u.useCallback(async p=>{const v=new MediaStream;if(p.getTracks().forEach(m=>v.addTrack(m)),e){let m;if(e instanceof MediaStream)m=e;else{const C=typeof e=="object"?{audio:e}:{audio:!0,video:!1};m=await navigator.mediaDevices.getUserMedia(C)}m.getAudioTracks().forEach(C=>v.addTrack(C))}if(!v.getTracks().length)throw new Error("No tracks available in combined stream.");return r.current=v,v},[e]),z=u.useCallback(async(p,v)=>{try{let m;o?(m=p,r.current=m):m=await P(p);const C=h(),k={};C&&(k.mimeType=C),n&&(k.bitsPerSecond=n);const j=new MediaRecorder(m,k);j.ondataavailable=R=>{var L;((L=R.data)==null?void 0:L.size)>0&&(d.current.push(R.data),i==null||i(R.data))},j.onstop=()=>{const R=new Blob(d.current,{type:C??"video/webm"});S(R),c==null||c(R),d.current=[]},a.current=j,j.start(v),g(!0),x(!1)}catch(m){console.error("start(stream) failed",m),b(m instanceof Error?m:new Error(String(m)))}},[P,h,n,i,c,o]),D=u.useCallback(()=>{const p=a.current;p&&p.state!=="inactive"&&p.stop(),g(!1),x(!1)},[]),U=u.useCallback(()=>{const p=a.current;(p==null?void 0:p.state)==="recording"&&(p.pause(),x(!0))},[]),_=u.useCallback(()=>{const p=a.current;(p==null?void 0:p.state)==="paused"&&(p.resume(),x(!1))},[]),F=u.useCallback(()=>{var p,v;try{(p=a.current)==null||p.stop(),a.current=null,(v=r.current)==null||v.getTracks().forEach(m=>m.stop()),r.current=null,S(null),g(!1),x(!1),d.current=[],b(null)}catch(m){console.error("clear failed",m)}},[]);return u.useEffect(()=>()=>F(),[]),{start:z,stop:D,pause:U,resume:_,clear:F,isRecording:M,isPaused:l,recordedBlob:T,error:y,getActiveStream:()=>r.current}}const Me=(s,e)=>{const t=s.split(","),n=t[0].match(/:(.*?);/),i=n?n[1]:"application/octet-stream",c=atob(t[t.length-1]);let o=c.length;const a=new Uint8Array(o);for(;o--;)a[o]=c.charCodeAt(o);return new File([a],e,{type:i})},xe=4,Te=50,ve=5e3,$=s=>new Promise(e=>{if(s.readyState>=4){e();return}let t=!1;const n=()=>{t||(t=!0,e())};s.addEventListener("canplaythrough",n,{once:!0}),s.addEventListener("error",n,{once:!0}),setTimeout(n,ve)}),G=(s,e)=>{const t=document.createElement("audio");return t.src=s,t.loop=e,t.preload="auto",t.setAttribute("playsinline",""),t.setAttribute("webkit-playsinline",""),t.load(),t},Se=s=>{s.muted=!0,s.play().then(()=>{s.pause(),s.currentTime=0,s.muted=!1}).catch(()=>{s.muted=!1})};class V{constructor(e={}){E(this,"sfxPoolSize");E(this,"coalesceMs");E(this,"muted",!0);E(this,"listeners",new Set);E(this,"music",null);E(this,"musicWanted",null);E(this,"pools",new Map);E(this,"lastPlayed",new Map);E(this,"ready",new Map);this.sfxPoolSize=e.sfxPoolSize??xe,this.coalesceMs=e.coalesceMs??Te}prefetchMusic(e,t=.4){this.musicWanted={url:e,volume:t};const n=`music:${e}`,i=this.ready.get(n);if(i)return i;this.music=G(e,!0),this.music.volume=t;const c=$(this.music);return this.ready.set(n,c),c}registerSound(e,t=1){const n=this.ready.get(e);if(n)return n;const i=[];for(let o=0;o<this.sfxPoolSize;o+=1){const a=G(e,!1);a.volume=t,a.addEventListener("ended",()=>{a.currentTime=0}),i.push(a)}this.pools.set(e,{els:i,next:0,volume:t});const c=$(i[0]);return this.ready.set(e,c),c}onMuteChange(e){return this.listeners.add(e),e(this.muted),()=>this.listeners.delete(e)}isMuted(){return this.muted}setMuted(e){e!==this.muted&&(this.muted=e,this.muted||this.pools.forEach(t=>t.els.forEach(Se)),this.applyMusic(),this.listeners.forEach(t=>t(this.muted)))}toggleMuted(){this.setMuted(!this.muted)}playOneShot(e,t){if(this.muted)return;const n=this.pools.get(e);if(!n)return;const i=performance.now();if(i-(this.lastPlayed.get(e)??-1/0)<this.coalesceMs)return;this.lastPlayed.set(e,i);const c=n.els.length;let o;for(let a=0;a<c;a+=1){const r=n.els[(n.next+a)%c];if(r.paused){o=r,n.next=(n.next+a+1)%c;break}}o||(o=n.els[n.next],n.next=(n.next+1)%c),o.muted=!1,o.volume=t??n.volume,o.currentTime!==0&&(o.currentTime=0),o.play().catch(()=>{})}startMusic(e,t=.4){this.musicWanted={url:e,volume:t},this.applyMusic()}stopMusic(){this.musicWanted=null,this.music&&(this.music.pause(),this.music.currentTime=0)}applyMusic(){!this.music||!this.musicWanted||(this.music.volume=this.musicWanted.volume,!this.muted&&this.music.paused&&this.music.play().catch(()=>{}),this.muted&&!this.music.paused&&this.music.pause())}}const w=new V,ye=(s,e)=>w.prefetchMusic(s,e),be=(s,e)=>w.registerSound(s,e),Re=(s,e)=>w.startMusic(s,e),we=()=>w.stopMusic(),Ce=(s,e)=>w.playOneShot(s,e),Ee=s=>w.setMuted(s),je=()=>w.toggleMuted(),Pe=()=>w.isMuted(),Oe=s=>w.onMuteChange(s),ke=()=>{const[s,e]=u.useState(w.isMuted());return u.useEffect(()=>w.onMuteChange(e),[]),s};exports.XRMediaSource=A.XRMediaSource;exports.XRModel=A.XRModel;exports.XRProvider=A.XRProvider;exports.ScreenTransform=W.ScreenTransform;exports.XRScene=W.XRScene;exports.useScreenRectAspect=W.useScreenRectAspect;exports.AspectRatioContainer=ee;exports.AudioEngine=V;exports.Panel=re;exports.ScreenSpaceUI=oe;exports.SpriteAnimation=le;exports.TextLabel=fe;exports.VideoBackground=pe;exports.audio=w;exports.computeContainScale=Z;exports.dataURLtoFile=Me;exports.isMuted=Pe;exports.onMuteChange=Oe;exports.playOneShot=Ce;exports.prefetchMusic=ye;exports.registerSound=be;exports.setMuted=Ee;exports.startMusic=Re;exports.stopMusic=we;exports.toggleMuted=je;exports.useMediaRecorder=ge;exports.useMuted=ke;
package/dist/main.js ADDED
@@ -0,0 +1,612 @@
1
+ var Q = Object.defineProperty;
2
+ var ee = (r, e, t) => e in r ? Q(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
3
+ var R = (r, e, t) => ee(r, typeof e != "symbol" ? e + "" : e, t);
4
+ import { useState as W, useEffect as k, useRef as y, useMemo as I, Suspense as te, useCallback as F } from "react";
5
+ import { X as re, R as ne } from "./index-CYMj26Ej.js";
6
+ import { b as rt, a as nt } from "./index-CYMj26Ej.js";
7
+ import { S as se, a as ie, u as oe } from "./index-DtwHElmG.js";
8
+ import { X as it } from "./index-DtwHElmG.js";
9
+ import { jsx as p, jsxs as P, Fragment as X } from "react/jsx-runtime";
10
+ import { useThree as Y, useFrame as ae } from "@react-three/fiber";
11
+ import * as K from "three";
12
+ import { PerspectiveCamera as J, RepeatWrapping as q, LinearFilter as H } from "three";
13
+ import { u as ce, a as le } from "./selectors-BHO6TnoC.js";
14
+ import { useTexture as ue } from "@react-three/drei";
15
+ const $ = 9, G = 16, Ae = ({ children: r }) => {
16
+ const [e, t] = W({ width: 0, height: 0 });
17
+ return k(() => {
18
+ const n = () => {
19
+ const i = document.documentElement.clientWidth, c = document.documentElement.clientHeight, o = i / c, a = $ / G;
20
+ let s, u;
21
+ o > a ? (u = c, s = u * $ / G) : (s = i, u = s * G / $), t({ width: s, height: u });
22
+ };
23
+ return n(), window.addEventListener("resize", n), () => window.removeEventListener("resize", n);
24
+ }, []), /* @__PURE__ */ p(
25
+ "div",
26
+ {
27
+ style: {
28
+ width: "100vw",
29
+ height: `${window.innerHeight}px`,
30
+ display: "flex",
31
+ alignItems: "center",
32
+ justifyContent: "center",
33
+ backgroundColor: "#0d0d0d"
34
+ },
35
+ children: /* @__PURE__ */ p("div", { style: { width: e.width, height: e.height, position: "relative" }, children: r })
36
+ }
37
+ );
38
+ }, de = "rgba(20,40,110,0.88)", he = 24, fe = 512;
39
+ function _e({
40
+ color: r = de,
41
+ borderColor: e,
42
+ borderWidth: t = 0,
43
+ borderRadius: n = he,
44
+ resolution: i = fe,
45
+ aspect: c = 1,
46
+ opacity: o = 1,
47
+ name: a,
48
+ overlay: s = !0,
49
+ position: u,
50
+ rotation: g,
51
+ scale: m,
52
+ visible: l
53
+ }) {
54
+ const M = y(null), v = y(null), w = I(() => me({
55
+ width: Math.round(i * Math.max(c, 0.05)),
56
+ height: Math.round(i),
57
+ color: r,
58
+ borderColor: e,
59
+ borderWidth: t,
60
+ borderRadius: n
61
+ }), [r, e, t, n, i, c]);
62
+ k(() => () => {
63
+ w.dispose();
64
+ }, [w]);
65
+ const b = y(null), S = y(o);
66
+ return S.current !== o && (S.current = o, b.current = null, v.current && (v.current.opacity = o)), k(() => {
67
+ const d = M.current;
68
+ if (d)
69
+ return d.userData.setOpacity = (L) => {
70
+ b.current = L, v.current && (v.current.opacity = L);
71
+ }, () => {
72
+ delete d.userData.setOpacity;
73
+ };
74
+ }, []), /* @__PURE__ */ P(
75
+ "mesh",
76
+ {
77
+ ref: M,
78
+ name: a,
79
+ position: u,
80
+ rotation: g,
81
+ scale: m,
82
+ visible: l,
83
+ children: [
84
+ /* @__PURE__ */ p("planeGeometry", { args: [1, 1] }),
85
+ /* @__PURE__ */ p(
86
+ "meshBasicMaterial",
87
+ {
88
+ ref: v,
89
+ map: w,
90
+ transparent: !0,
91
+ opacity: o,
92
+ depthTest: !s,
93
+ depthWrite: !s
94
+ }
95
+ )
96
+ ]
97
+ }
98
+ );
99
+ }
100
+ function me(r) {
101
+ const { width: e, height: t, color: n, borderColor: i, borderWidth: c, borderRadius: o } = r, a = typeof OffscreenCanvas < "u" ? new OffscreenCanvas(e, t) : (() => {
102
+ const m = document.createElement("canvas");
103
+ return m.width = e, m.height = t, m;
104
+ })(), s = a.getContext("2d");
105
+ s.clearRect(0, 0, e, t);
106
+ const u = Math.min(o, Math.min(e, t) / 2);
107
+ s.beginPath(), s.moveTo(u, 0), s.lineTo(e - u, 0), s.quadraticCurveTo(e, 0, e, u), s.lineTo(e, t - u), s.quadraticCurveTo(e, t, e - u, t), s.lineTo(u, t), s.quadraticCurveTo(0, t, 0, t - u), s.lineTo(0, u), s.quadraticCurveTo(0, 0, u, 0), s.closePath(), s.fillStyle = n, s.fill(), i && c > 0 && (s.lineWidth = c, s.strokeStyle = i, s.stroke());
108
+ const g = new K.CanvasTexture(a);
109
+ return g.needsUpdate = !0, g;
110
+ }
111
+ const ze = ({ children: r, depth: e = 0 }) => {
112
+ const { camera: t, size: n } = Y(), i = I(() => {
113
+ if (!(t instanceof J))
114
+ return { width: 10, height: 10 };
115
+ const c = Math.abs(t.position.z - e), o = t.fov * Math.PI / 180, a = 2 * Math.tan(o / 2) * c;
116
+ return { width: a * (n.width / n.height), height: a };
117
+ }, [t, n, e]);
118
+ return /* @__PURE__ */ p(se.Provider, { value: i, children: /* @__PURE__ */ p("group", { position: [0, 0, e], children: r }) });
119
+ };
120
+ function pe(r, e) {
121
+ return !Number.isFinite(r) || !Number.isFinite(e) || r <= 0 || e <= 0 ? [1, 1, 1] : Math.abs(r - e) < 1e-6 ? [1, 1, 1] : r > e ? [e / r, 1, 1] : [1, r / e, 1];
122
+ }
123
+ const ge = { left: -1, right: 1, top: 1, bottom: -1 }, Me = (r, e, t) => {
124
+ const n = r % e, i = Math.floor(r / e);
125
+ return { x: n / e, y: (t - 1 - i) / t };
126
+ }, ve = ({
127
+ sheet: r,
128
+ contentAspect: e,
129
+ renderOrder: t,
130
+ name: n
131
+ }) => {
132
+ const i = ue(r.url), c = y(0), o = y(-1), a = oe(), [s, u] = e != null ? pe(a, e) : [1, 1];
133
+ return ae((g, m) => {
134
+ i.wrapS = q, i.wrapT = q, i.magFilter = H, i.minFilter = H, i.generateMipmaps = !1, i.repeat.set(1 / r.cols, 1 / r.rows), c.current += m;
135
+ const l = Math.floor(c.current * r.fps) % r.frames;
136
+ if (l === o.current) return;
137
+ o.current = l;
138
+ const { x: M, y: v } = Me(l, r.cols, r.rows);
139
+ i.offset.set(M, v);
140
+ }), /* @__PURE__ */ P("mesh", { name: n, renderOrder: t, scale: [s, u, 1], children: [
141
+ /* @__PURE__ */ p("planeGeometry", { args: [1, 1] }),
142
+ /* @__PURE__ */ p("meshBasicMaterial", { map: i, transparent: !0, toneMapped: !1, depthWrite: !1 })
143
+ ] });
144
+ }, Be = ({
145
+ sheet: r,
146
+ anchors: e = ge,
147
+ contentAspect: t,
148
+ renderOrder: n = 10,
149
+ name: i = "spriteAnimation"
150
+ }) => /* @__PURE__ */ p(te, { fallback: null, children: /* @__PURE__ */ p(ie, { anchors: e, children: /* @__PURE__ */ p(ve, { sheet: r, contentAspect: t, renderOrder: n, name: i }) }) }), Te = {
151
+ color: "#ffffff",
152
+ fontWeight: "bold",
153
+ fontFamily: "Arial, sans-serif",
154
+ fontSize: 48,
155
+ bgColor: "rgba(20,40,110,0.88)",
156
+ borderWidth: 0,
157
+ borderRadius: 24,
158
+ padding: 32,
159
+ aspect: 2.5,
160
+ resolution: 512,
161
+ opacity: 1
162
+ };
163
+ function Ie(r) {
164
+ const e = { ...Te, ...r }, {
165
+ text: t,
166
+ color: n,
167
+ fontWeight: i,
168
+ fontFamily: c,
169
+ fontSize: o,
170
+ bgColor: a,
171
+ borderColor: s,
172
+ borderWidth: u,
173
+ borderRadius: g,
174
+ padding: m,
175
+ aspect: l,
176
+ resolution: M,
177
+ opacity: v,
178
+ name: w,
179
+ overlay: b = !0,
180
+ position: S,
181
+ rotation: d,
182
+ scale: L,
183
+ visible: N
184
+ } = e, [_, z] = W(null), [B, A] = W(null), h = y(t);
185
+ h.current !== t && (h.current = t, _ !== null && z(null));
186
+ const T = y(a);
187
+ T.current !== a && (T.current = a, B !== null && A(null));
188
+ const f = y(null), E = _ ?? t, D = B ?? a, O = I(
189
+ () => ye({
190
+ text: E,
191
+ color: n,
192
+ fontWeight: i,
193
+ fontFamily: c,
194
+ fontSize: o,
195
+ bgColor: D,
196
+ borderColor: s,
197
+ borderWidth: u,
198
+ borderRadius: g,
199
+ padding: m,
200
+ height: M,
201
+ width: Math.round(M * Math.max(l, 0.1))
202
+ }),
203
+ [
204
+ E,
205
+ n,
206
+ i,
207
+ c,
208
+ o,
209
+ D,
210
+ s,
211
+ u,
212
+ g,
213
+ m,
214
+ l,
215
+ M
216
+ ]
217
+ );
218
+ return k(() => {
219
+ const x = f.current;
220
+ if (x)
221
+ return x.userData.setText = (U) => z(U), x.userData.setBgColor = (U) => A(U), () => {
222
+ delete x.userData.setText, delete x.userData.setBgColor;
223
+ };
224
+ }, []), k(() => () => {
225
+ O.dispose();
226
+ }, [O]), /* @__PURE__ */ P(
227
+ "mesh",
228
+ {
229
+ ref: f,
230
+ name: w,
231
+ position: S,
232
+ rotation: d,
233
+ scale: L,
234
+ visible: N,
235
+ children: [
236
+ /* @__PURE__ */ p("planeGeometry", { args: [1, 1] }),
237
+ /* @__PURE__ */ p(
238
+ "meshBasicMaterial",
239
+ {
240
+ map: O,
241
+ transparent: !0,
242
+ opacity: v,
243
+ depthTest: !b,
244
+ depthWrite: !b
245
+ }
246
+ )
247
+ ]
248
+ }
249
+ );
250
+ }
251
+ function ye(r) {
252
+ const { width: e, height: t, text: n, color: i, fontFamily: c, fontWeight: o, padding: a } = r;
253
+ let { fontSize: s, bgColor: u } = r, g;
254
+ const m = typeof OffscreenCanvas < "u" ? new OffscreenCanvas(e, t) : (() => {
255
+ const d = document.createElement("canvas");
256
+ return d.width = e, d.height = t, d;
257
+ })(), l = m.getContext("2d");
258
+ if (l.clearRect(0, 0, e, t), u !== "transparent") {
259
+ const d = Math.min(r.borderRadius, Math.min(e, t) / 2);
260
+ l.beginPath(), l.moveTo(d, 0), l.lineTo(e - d, 0), l.quadraticCurveTo(e, 0, e, d), l.lineTo(e, t - d), l.quadraticCurveTo(e, t, e - d, t), l.lineTo(d, t), l.quadraticCurveTo(0, t, 0, t - d), l.lineTo(0, d), l.quadraticCurveTo(0, 0, d, 0), l.closePath(), l.fillStyle = u, l.fill(), r.borderColor && r.borderWidth > 0 && (l.lineWidth = r.borderWidth, l.strokeStyle = r.borderColor, l.stroke());
261
+ }
262
+ l.fillStyle = i, l.textAlign = "center", l.textBaseline = "middle";
263
+ const M = e - a * 2;
264
+ let v = Z(l, n, M, o, s, c);
265
+ const w = Math.max(1, Math.floor((t - a * 2) / (s * 1.3)));
266
+ v.length > w && (s = Math.max(12, Math.round(s * 0.75)), v = Z(l, n, M, o, s, c)), l.font = `${o} ${s}px ${c}`;
267
+ const b = s * 1.3, S = t / 2 - (v.length - 1) * b / 2;
268
+ for (let d = 0; d < v.length; d++)
269
+ l.fillText(v[d], e / 2, S + d * b);
270
+ return g = new K.CanvasTexture(m), g.needsUpdate = !0, g;
271
+ }
272
+ function Z(r, e, t, n, i, c) {
273
+ r.font = `${n} ${i}px ${c}`;
274
+ const o = e.split(" "), a = [];
275
+ let s = "";
276
+ for (const u of o) {
277
+ const g = s ? `${s} ${u}` : u;
278
+ r.measureText(g).width > t && s ? (a.push(s), s = u) : s = g;
279
+ }
280
+ return s && a.push(s), a;
281
+ }
282
+ const Ne = ({
283
+ segmentationMask: r,
284
+ segmentation: e,
285
+ invert: t = !1,
286
+ customBackground: n,
287
+ renderOrder: i = ne.BACKGROUND
288
+ }) => {
289
+ const { camera: c, size: o } = Y(), a = ce(), s = le(re.BACKGROUND_SEGMENTATION), u = e ? s == null ? void 0 : s.backgroundSegmentationMask : void 0, g = y(!1);
290
+ k(() => {
291
+ if (!e) {
292
+ g.current = !1;
293
+ return;
294
+ }
295
+ s === null && !g.current && (console.warn(
296
+ `[VideoBackground] segmentation="${e}" set but no matching <Segmentation> component is mounted; rendering unmasked.`
297
+ ), g.current = !0);
298
+ }, [e, s]);
299
+ const m = e ? u : r, l = I(() => {
300
+ if (!(c instanceof J))
301
+ return [10, 10];
302
+ const w = (c.position.z || 5) - -1, b = c.fov * Math.PI / 180, S = 2 * Math.tan(b / 2) * w;
303
+ return [S * (o.width / o.height), S];
304
+ }, [c, o]);
305
+ return a ? /* @__PURE__ */ p("group", { position: [0, 0, -1], children: t ? /* @__PURE__ */ P(X, { children: [
306
+ /* @__PURE__ */ P("mesh", { position: [0, 0, -0.01], renderOrder: i - 1, children: [
307
+ /* @__PURE__ */ p("planeGeometry", { args: l }),
308
+ /* @__PURE__ */ p(
309
+ "meshBasicMaterial",
310
+ {
311
+ map: a,
312
+ depthTest: !1,
313
+ depthWrite: !1,
314
+ toneMapped: !1
315
+ }
316
+ )
317
+ ] }),
318
+ n && m && /* @__PURE__ */ P("mesh", { position: [0, 0, 0], renderOrder: i, children: [
319
+ /* @__PURE__ */ p("planeGeometry", { args: l }),
320
+ /* @__PURE__ */ p(
321
+ "meshBasicMaterial",
322
+ {
323
+ map: typeof n == "string" ? void 0 : n,
324
+ color: typeof n == "string" ? n : void 0,
325
+ alphaMap: m,
326
+ transparent: !1,
327
+ alphaTest: 0.5,
328
+ depthTest: !1,
329
+ depthWrite: !1,
330
+ toneMapped: !1
331
+ },
332
+ "inverted-mask"
333
+ )
334
+ ] })
335
+ ] }) : /* @__PURE__ */ P(X, { children: [
336
+ n && m && /* @__PURE__ */ P("mesh", { position: [0, 0, -0.01], renderOrder: i - 1, children: [
337
+ /* @__PURE__ */ p("planeGeometry", { args: l }),
338
+ /* @__PURE__ */ p(
339
+ "meshBasicMaterial",
340
+ {
341
+ map: typeof n == "string" ? void 0 : n,
342
+ color: typeof n == "string" ? n : void 0,
343
+ depthTest: !1,
344
+ depthWrite: !1,
345
+ toneMapped: !1
346
+ }
347
+ )
348
+ ] }),
349
+ /* @__PURE__ */ P("mesh", { position: [0, 0, 0], renderOrder: i, children: [
350
+ /* @__PURE__ */ p("planeGeometry", { args: l }),
351
+ /* @__PURE__ */ p(
352
+ "meshBasicMaterial",
353
+ {
354
+ map: a,
355
+ alphaMap: m,
356
+ transparent: !1,
357
+ alphaTest: m ? 0.5 : void 0,
358
+ depthTest: !1,
359
+ depthWrite: !1,
360
+ toneMapped: !1
361
+ },
362
+ m ? "with-mask" : "no-mask"
363
+ )
364
+ ] })
365
+ ] }) }) : null;
366
+ }, we = [
367
+ "video/mp4",
368
+ "video/webm;codecs=vp9",
369
+ "video/webm;codecs=vp8",
370
+ "video/webm"
371
+ ];
372
+ function $e(r = {}) {
373
+ const { audio: e = !1, mimeType: t, bitsPerSecond: n, onData: i, onStop: c, passThroughStream: o } = r, a = y(null), s = y(null), u = y([]), [g, m] = W(!1), [l, M] = W(!1), [v, w] = W(null), [b, S] = W(null), d = F(() => {
374
+ var T;
375
+ const h = [t, ...we].filter(Boolean);
376
+ for (const f of h)
377
+ if ((T = MediaRecorder.isTypeSupported) != null && T.call(MediaRecorder, f)) return f;
378
+ }, [t]), L = F(
379
+ async (h) => {
380
+ const T = new MediaStream();
381
+ if (h.getTracks().forEach((f) => T.addTrack(f)), e) {
382
+ let f;
383
+ if (e instanceof MediaStream)
384
+ f = e;
385
+ else {
386
+ const E = typeof e == "object" ? { audio: e } : { audio: !0, video: !1 };
387
+ f = await navigator.mediaDevices.getUserMedia(E);
388
+ }
389
+ f.getAudioTracks().forEach((E) => T.addTrack(E));
390
+ }
391
+ if (!T.getTracks().length)
392
+ throw new Error("No tracks available in combined stream.");
393
+ return s.current = T, T;
394
+ },
395
+ [e]
396
+ ), N = F(
397
+ async (h, T) => {
398
+ try {
399
+ let f;
400
+ o ? (f = h, s.current = f) : f = await L(h);
401
+ const E = d(), D = {};
402
+ E && (D.mimeType = E), n && (D.bitsPerSecond = n);
403
+ const O = new MediaRecorder(f, D);
404
+ O.ondataavailable = (x) => {
405
+ var U;
406
+ ((U = x.data) == null ? void 0 : U.size) > 0 && (u.current.push(x.data), i == null || i(x.data));
407
+ }, O.onstop = () => {
408
+ const x = new Blob(u.current, {
409
+ type: E ?? "video/webm"
410
+ });
411
+ w(x), c == null || c(x), u.current = [];
412
+ }, a.current = O, O.start(T), m(!0), M(!1);
413
+ } catch (f) {
414
+ console.error("start(stream) failed", f), S(f instanceof Error ? f : new Error(String(f)));
415
+ }
416
+ },
417
+ [L, d, n, i, c, o]
418
+ ), _ = F(() => {
419
+ const h = a.current;
420
+ h && h.state !== "inactive" && h.stop(), m(!1), M(!1);
421
+ }, []), z = F(() => {
422
+ const h = a.current;
423
+ (h == null ? void 0 : h.state) === "recording" && (h.pause(), M(!0));
424
+ }, []), B = F(() => {
425
+ const h = a.current;
426
+ (h == null ? void 0 : h.state) === "paused" && (h.resume(), M(!1));
427
+ }, []), A = F(() => {
428
+ var h, T;
429
+ try {
430
+ (h = a.current) == null || h.stop(), a.current = null, (T = s.current) == null || T.getTracks().forEach((f) => f.stop()), s.current = null, w(null), m(!1), M(!1), u.current = [], S(null);
431
+ } catch (f) {
432
+ console.error("clear failed", f);
433
+ }
434
+ }, []);
435
+ return k(() => () => A(), []), {
436
+ start: N,
437
+ stop: _,
438
+ pause: z,
439
+ resume: B,
440
+ clear: A,
441
+ isRecording: g,
442
+ isPaused: l,
443
+ recordedBlob: v,
444
+ error: b,
445
+ getActiveStream: () => s.current
446
+ };
447
+ }
448
+ const Ge = (r, e) => {
449
+ const t = r.split(","), n = t[0].match(/:(.*?);/), i = n ? n[1] : "application/octet-stream", c = atob(t[t.length - 1]);
450
+ let o = c.length;
451
+ const a = new Uint8Array(o);
452
+ for (; o--; )
453
+ a[o] = c.charCodeAt(o);
454
+ return new File([a], e, { type: i });
455
+ }, be = 4, Se = 50, xe = 5e3, j = (r) => new Promise((e) => {
456
+ if (r.readyState >= 4) {
457
+ e();
458
+ return;
459
+ }
460
+ let t = !1;
461
+ const n = () => {
462
+ t || (t = !0, e());
463
+ };
464
+ r.addEventListener("canplaythrough", n, { once: !0 }), r.addEventListener("error", n, { once: !0 }), setTimeout(n, xe);
465
+ }), V = (r, e) => {
466
+ const t = document.createElement("audio");
467
+ return t.src = r, t.loop = e, t.preload = "auto", t.setAttribute("playsinline", ""), t.setAttribute("webkit-playsinline", ""), t.load(), t;
468
+ }, Ce = (r) => {
469
+ r.muted = !0, r.play().then(() => {
470
+ r.pause(), r.currentTime = 0, r.muted = !1;
471
+ }).catch(() => {
472
+ r.muted = !1;
473
+ });
474
+ };
475
+ class Ee {
476
+ constructor(e = {}) {
477
+ R(this, "sfxPoolSize");
478
+ R(this, "coalesceMs");
479
+ R(this, "muted", !0);
480
+ R(this, "listeners", /* @__PURE__ */ new Set());
481
+ R(this, "music", null);
482
+ R(this, "musicWanted", null);
483
+ R(this, "pools", /* @__PURE__ */ new Map());
484
+ /** Last play time per SFX URL, for the coalesce window. */
485
+ R(this, "lastPlayed", /* @__PURE__ */ new Map());
486
+ /** Readiness promises so a loading gate can await decode/buffer. */
487
+ R(this, "ready", /* @__PURE__ */ new Map());
488
+ this.sfxPoolSize = e.sfxPoolSize ?? be, this.coalesceMs = e.coalesceMs ?? Se;
489
+ }
490
+ /**
491
+ * Create + buffer the looping music element. Await in the loading gate so the
492
+ * unmute tap is instant. Idempotent per URL (re-requesting the same track is
493
+ * a no-op that returns the in-flight promise).
494
+ */
495
+ prefetchMusic(e, t = 0.4) {
496
+ this.musicWanted = { url: e, volume: t };
497
+ const n = `music:${e}`, i = this.ready.get(n);
498
+ if (i) return i;
499
+ this.music = V(e, !0), this.music.volume = t;
500
+ const c = j(this.music);
501
+ return this.ready.set(n, c), c;
502
+ }
503
+ /**
504
+ * Create + buffer an SFX voice pool (round-robin so overlapping plays don't
505
+ * cut each other off). Returns a promise that resolves when the first element
506
+ * buffers. Idempotent per URL.
507
+ */
508
+ registerSound(e, t = 1) {
509
+ const n = this.ready.get(e);
510
+ if (n) return n;
511
+ const i = [];
512
+ for (let o = 0; o < this.sfxPoolSize; o += 1) {
513
+ const a = V(e, !1);
514
+ a.volume = t, a.addEventListener("ended", () => {
515
+ a.currentTime = 0;
516
+ }), i.push(a);
517
+ }
518
+ this.pools.set(e, { els: i, next: 0, volume: t });
519
+ const c = j(i[0]);
520
+ return this.ready.set(e, c), c;
521
+ }
522
+ /** Subscribe to mute-state changes (for a toggle UI). Fires immediately with
523
+ * the current state. Returns an unsubscribe. */
524
+ onMuteChange(e) {
525
+ return this.listeners.add(e), e(this.muted), () => this.listeners.delete(e);
526
+ }
527
+ isMuted() {
528
+ return this.muted;
529
+ }
530
+ /**
531
+ * Toggle sound. The first unmute is a real user gesture that unlocks every
532
+ * preloaded element (iOS gates media playback on a gesture): touch each SFX
533
+ * element with a muted play/pause so later `playOneShot` calls are allowed,
534
+ * then start the music. All elements are already buffered, so this is instant.
535
+ */
536
+ setMuted(e) {
537
+ e !== this.muted && (this.muted = e, this.muted || this.pools.forEach((t) => t.els.forEach(Ce)), this.applyMusic(), this.listeners.forEach((t) => t(this.muted)));
538
+ }
539
+ toggleMuted() {
540
+ this.setMuted(!this.muted);
541
+ }
542
+ /**
543
+ * Play a preloaded SFX; no-op while muted. Cycles the voice pool so
544
+ * overlapping plays don't cut each other off, coalesces a rapid repeat of the
545
+ * same sound into one play, and does NO synchronous `currentTime` seek on a
546
+ * ready element (the pool rewinds on `ended`, off the hot path).
547
+ */
548
+ playOneShot(e, t) {
549
+ if (this.muted) return;
550
+ const n = this.pools.get(e);
551
+ if (!n) return;
552
+ const i = performance.now();
553
+ if (i - (this.lastPlayed.get(e) ?? -1 / 0) < this.coalesceMs) return;
554
+ this.lastPlayed.set(e, i);
555
+ const c = n.els.length;
556
+ let o;
557
+ for (let a = 0; a < c; a += 1) {
558
+ const s = n.els[(n.next + a) % c];
559
+ if (s.paused) {
560
+ o = s, n.next = (n.next + a + 1) % c;
561
+ break;
562
+ }
563
+ }
564
+ o || (o = n.els[n.next], n.next = (n.next + 1) % c), o.muted = !1, o.volume = t ?? n.volume, o.currentTime !== 0 && (o.currentTime = 0), o.play().catch(() => {
565
+ });
566
+ }
567
+ /** Request the looping background track (buffer it with prefetchMusic, which
568
+ * a loading gate awaits). Remembered while muted; starts on unmute. */
569
+ startMusic(e, t = 0.4) {
570
+ this.musicWanted = { url: e, volume: t }, this.applyMusic();
571
+ }
572
+ stopMusic() {
573
+ this.musicWanted = null, this.music && (this.music.pause(), this.music.currentTime = 0);
574
+ }
575
+ applyMusic() {
576
+ !this.music || !this.musicWanted || (this.music.volume = this.musicWanted.volume, !this.muted && this.music.paused && this.music.play().catch(() => {
577
+ }), this.muted && !this.music.paused && this.music.pause());
578
+ }
579
+ }
580
+ const C = new Ee(), Xe = (r, e) => C.prefetchMusic(r, e), qe = (r, e) => C.registerSound(r, e), He = (r, e) => C.startMusic(r, e), Ze = () => C.stopMusic(), je = (r, e) => C.playOneShot(r, e), Ve = (r) => C.setMuted(r), Ye = () => C.toggleMuted(), Ke = () => C.isMuted(), Je = (r) => C.onMuteChange(r), Qe = () => {
581
+ const [r, e] = W(C.isMuted());
582
+ return k(() => C.onMuteChange(e), []), r;
583
+ };
584
+ export {
585
+ Ae as AspectRatioContainer,
586
+ Ee as AudioEngine,
587
+ _e as Panel,
588
+ ze as ScreenSpaceUI,
589
+ ie as ScreenTransform,
590
+ Be as SpriteAnimation,
591
+ Ie as TextLabel,
592
+ Ne as VideoBackground,
593
+ rt as XRMediaSource,
594
+ re as XRModel,
595
+ nt as XRProvider,
596
+ it as XRScene,
597
+ C as audio,
598
+ pe as computeContainScale,
599
+ Ge as dataURLtoFile,
600
+ Ke as isMuted,
601
+ Je as onMuteChange,
602
+ je as playOneShot,
603
+ Xe as prefetchMusic,
604
+ qe as registerSound,
605
+ Ve as setMuted,
606
+ He as startMusic,
607
+ Ze as stopMusic,
608
+ Ye as toggleMuted,
609
+ $e as useMediaRecorder,
610
+ Qe as useMuted,
611
+ oe as useScreenRectAspect
612
+ };
@@ -0,0 +1,25 @@
1
+ import { RunModelParams } from '../../types';
2
+ import { PerformanceData } from '../../types/common';
3
+ export declare class BaseXRModel {
4
+ protected disposed: boolean;
5
+ protected paused: boolean;
6
+ protected rafId: number | null;
7
+ protected targetFrameIntervalMs: number;
8
+ protected lastInferenceMs: number;
9
+ /** Set the per-frame inference cap. fps <= 0 (or undefined) → uncapped. */
10
+ protected setTargetFps(fps: number | undefined): void;
11
+ /**
12
+ * True if enough time has elapsed to run inference this frame (and records
13
+ * the timestamp). Always true when uncapped. Call once per RAF tick, right
14
+ * before the detect call; skip the detect (but keep rescheduling RAF) when
15
+ * it returns false.
16
+ */
17
+ protected shouldRunInference(): boolean;
18
+ initialize(_options?: Record<string, unknown>): Promise<void>;
19
+ run(_params?: RunModelParams): Promise<void>;
20
+ getModelNode(): {};
21
+ getPerformanceData(): Promise<PerformanceData>;
22
+ pause(): void;
23
+ resume(): void;
24
+ dispose(): void;
25
+ }
@@ -0,0 +1,22 @@
1
+ import { RunModelParams } from '../../types';
2
+ import { BodyModelOptions } from '../../types/body';
3
+ import { PerformanceData } from '../../types/common';
4
+ import { XRModelNodeBodyTracking } from '../../types/nodes';
5
+ import { BaseXRModel } from '../Base';
6
+ export declare class BodyTrackingModel extends BaseXRModel {
7
+ private landmarker;
8
+ private processingTime;
9
+ private coordinates;
10
+ private sourceCanvas;
11
+ private readonly downscaler;
12
+ constructor();
13
+ private getBodyData;
14
+ private processBodyTracking;
15
+ resume(): void;
16
+ dispose(): void;
17
+ private getLandmarks2D;
18
+ initialize(options?: BodyModelOptions): Promise<void>;
19
+ run({ sourceCanvas }: RunModelParams): Promise<void>;
20
+ getModelNode(): XRModelNodeBodyTracking;
21
+ getPerformanceData(): Promise<PerformanceData>;
22
+ }