seg-cam 1.0.2 → 1.1.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.
package/README.md CHANGED
@@ -88,6 +88,8 @@ export function CameraApp() {
88
88
  | `onSegmentedImage`| `(images: ImageBitmap[], bboxes?: BoundingBox[]) => void`| - | Throttled (500ms). Returns individual bitmaps and bounding boxes of detected objects (tlbr format). |
89
89
  | `bodyPixArchitecture`| `'MobileNetV1' \| 'ResNet50'` | `'MobileNetV1'` | Performance vs Accuracy trade-off. |
90
90
  | `verbose` | `boolean` | `false` | Enable detailed console logging. |
91
+ | `className` | `string` | - | Optional CSS class for the canvas element. |
92
+ | `style` | `React.CSSProperties` | - | Optional inline styles for the canvas. Use `transform: 'scaleX(-1)'` for selfie-mode mirroring. |
91
93
 
92
94
  ### `DetectionStats` Type
93
95
 
@@ -100,6 +102,20 @@ interface DetectionStats {
100
102
  }
101
103
  ```
102
104
 
105
+ ### `BoundingBox` Type
106
+
107
+ The `BoundingBox` provides the location of a detected object in **pixel coordinates** relative to the original unmirrored video frame.
108
+
109
+ ```typescript
110
+ interface BoundingBox {
111
+ top: number; // Y-coordinate of the top edge
112
+ left: number; // X-coordinate of the left edge
113
+ bottom: number; // Y-coordinate of the bottom edge
114
+ right: number; // X-coordinate of the right edge
115
+ }
116
+ ```
117
+ Note: The format is `[top, left, bottom, right]`. Dimensions can be calculated as `height = bottom - top` and `width = right - left`.
118
+
103
119
  ### `JerseyDetectorHandle` (Inverted Ref)
104
120
 
105
121
  You can use a `ref` on the `JerseyDetector` component to access its internal state imperatively:
@@ -135,6 +151,12 @@ const currentStats = detectorRef.current?.stats;
135
151
  - `'mask_with_image'`: Draws the overlay on top of the existing canvas (may trail if not cleared externally).
136
152
  - `'none'`: Skips bitmap generation entirely. Use this if you only need `onSegmentedImage` or stats, improving performance.
137
153
  - **`threshold`**: (`number`, 0.0-1.0, Default `0.5`) The minimum confidence required for a person pixel to be considered valid.
154
+ - **Mirroring**: Passing `style={{ transform: 'scaleX(-1)' }}` will:
155
+ - Mirror the UI display of the mask/composite using CSS.
156
+ - Automatically tell the worker to mirror the pixels in the internal mask bitmap (for UI display).
157
+ - **Does NOT mirror** the individual `onSegmentedImage` snapshots (kept unmirrored for classification).
158
+ - Keep `capture()` oriented correctly (unmirrored) by automatically un-flipping the mask before export.
159
+ - Keep `bboxes` in original, unmirrored coordinates.
138
160
 
139
161
  ## Performance Tips
140
162
 
package/dist/index.d.mts CHANGED
@@ -66,6 +66,7 @@ type WorkerConfig = {
66
66
  targetPartId?: number;
67
67
  imagesToReturn?: ImagesToReturn;
68
68
  minDetectionArea?: number;
69
+ mirror?: boolean;
69
70
  };
70
71
  type BoundingBox = {
71
72
  top: number;
@@ -147,6 +148,8 @@ interface JerseyDetectorProps {
147
148
  imagesToReturn?: ImagesToReturn;
148
149
  minDetectionArea?: number;
149
150
  workerUrl?: string;
151
+ className?: string;
152
+ style?: React.CSSProperties;
150
153
  }
151
154
  declare const JerseyDetector: react.ForwardRefExoticComponent<JerseyDetectorProps & react.RefAttributes<JerseyDetectorHandle>>;
152
155
 
package/dist/index.d.ts CHANGED
@@ -66,6 +66,7 @@ type WorkerConfig = {
66
66
  targetPartId?: number;
67
67
  imagesToReturn?: ImagesToReturn;
68
68
  minDetectionArea?: number;
69
+ mirror?: boolean;
69
70
  };
70
71
  type BoundingBox = {
71
72
  top: number;
@@ -147,6 +148,8 @@ interface JerseyDetectorProps {
147
148
  imagesToReturn?: ImagesToReturn;
148
149
  minDetectionArea?: number;
149
150
  workerUrl?: string;
151
+ className?: string;
152
+ style?: React.CSSProperties;
150
153
  }
151
154
  declare const JerseyDetector: react.ForwardRefExoticComponent<JerseyDetectorProps & react.RefAttributes<JerseyDetectorHandle>>;
152
155
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var ke=Object.create;var z=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var Re=Object.getPrototypeOf,ve=Object.prototype.hasOwnProperty;var _e=(e,o)=>{for(var c in o)z(e,c,{get:o[c],enumerable:!0})},fe=(e,o,c,h)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of we(o))!ve.call(e,s)&&s!==c&&z(e,s,{get:()=>o[s],enumerable:!(h=be(o,s))||h.enumerable});return e};var Me=(e,o,c)=>(c=e!=null?ke(Re(e)):{},fe(o||!e||!e.__esModule?z(c,"default",{value:e,enumerable:!0}):c,e)),Ce=e=>fe(z({},"__esModule",{value:!0}),e);var S=(e,o,c)=>new Promise((h,s)=>{var O=d=>{try{k(c.next(d))}catch(b){s(b)}},D=d=>{try{k(c.throw(d))}catch(b){s(b)}},k=d=>d.done?h(d.value):Promise.resolve(d.value).then(O,D);k((c=c.apply(e,o)).next())});var Se={};_e(Se,{DEFAULT_CONFIG:()=>l,JerseyDetector:()=>ne,useJerseyWorker:()=>Q});module.exports=Ce(Se);var n=require("react");var p=require("react");var g=null,C=!1,V=null,re=0,te=null,E=new Map,We=0,K=new Map;function Q(e,o){let c=(0,p.useRef)(!1),[h,s]=(0,p.useState)(!1),[O,D]=(0,p.useState)(null),k=(0,p.useRef)(!0),d=(0,p.useRef)(!1),b=(0,p.useRef)(`instance_${Math.random().toString(36).substr(2,9)}`),B=(0,p.useRef)(0);(0,p.useEffect)(()=>{var _;if(!e)return;k.current=!0,B.current++;let v=B.current,W=b.current,A=(_=K.get(W))!=null?_:0;return v>A&&(re++,K.set(W,v)),S(null,null,function*(){var y;if(!g||!xe(te,e)){g&&(g.terminate(),g=null,C=!1,console.log("[v0 useJerseyWorker] Worker terminated because of change in config"));try{d.current=(y=e.verbose)!=null?y:d.current;let f=o||"/jersey-detector-worker.js";g=new Worker(f),te=e,C=!1,V=null,s(!1),D(null),g.onmessage=m=>{let a=m.data;switch(a.type){case"ready":C=!0,s(!0),d.current&&console.log("[v0 useJerseyWorker] Worker Ready",{device:a.device,dtype:a.dtype,config:a.config});break;case"loading_progress":d.current&&console.log(`[v0 useJerseyWorker] Loaded ${a.progress}% of ${a.file}`);break;case"debug":d.current&&console.log(a.debug_message);break;case"error":let P=a.error_message||"Unknown worker error";console.error("[v0 useJerseyWorker] Worker sent error message:",P),C=!1,V=P,s(!1),D(P);break;case"detect_response":if(a.requestId&&E.has(a.requestId)){let I=E.get(a.requestId);I&&(I.resolve(a),E.delete(a.requestId))}else if(E.size>0){let I=E.entries().next();if(!I.done){let[x,L]=I.value;L.resolve(a),E.delete(x)}}break}},g.onerror=m=>{let a=m.message||"Worker initialization error";console.error("[useJerseyWorker] Worker error:",a),C=!1,V=a,s(!1),D(a)},g.postMessage({type:"init",config:e})}catch(f){let m=(f==null?void 0:f.message)||String(f);console.error("[useJerseyWorker] Failed to create worker:",m),s(!1),D(m)}}else s(C),D(V)}),()=>{k.current=!1;let y=b.current,f=K.get(y),m=B.current;f===m&&(re--,K.delete(y),re<=0&&g&&(g.terminate(),g=null,C=!1,V=null,te=null,E.clear()))}},[]);let j=(0,p.useCallback)((v,W,A=.5)=>S(null,null,function*(){if(!g||!C)throw new Error("Worker not ready");if(c.current)return null;let w=`req_${++We}_${Date.now()}`;return new Promise((_,y)=>{E.set(w,{resolve:_,reject:y});try{c.current=!0,g.postMessage({type:"detect",requestId:w,dimensions:W,bitmap:v,threshold:A},[v])}catch(f){E.delete(w);let m=`Failed to send detect: ${f==null?void 0:f.message}`;y(new Error(m))}finally{c.current=!1}setTimeout(()=>{E.has(w)&&(E.delete(w),y(new Error("Detection timeout")))},1e4)})}),[h]);return{isReady:h,workerReady:h,lastError:O,detect:j}}function xe(e,o){return e?JSON.stringify(e)===JSON.stringify(o):!1}var l={TASK:"image-segmentation",MODEL:"BodyPix",BODYPIX_ARCHITECTURE:"MobileNetV1",BODYPIX_MULTIPLIER:.75,BODYPIX_QUANT_BYTES:2,BODYPIX_STRIDE:16,MULTI_SEGMENTATION:!0,SEGMENT_BODY_PARTS:!0,BACKGROUND_SHADE:0,SHIRT_SHADE:170,DETECTION_THRESHOLD:.5,TARGET_PART_ID:12,IMAGES_TO_RETURN:"mask",VERBOSE:!1,MIN_DETECTION_AREA:1e4};var me=Me(require("p-limit"));var ge=require("react/jsx-runtime"),ne=(0,n.forwardRef)(({videoRef:e,onWorkerReady:o,onWorkerError:c,onStatsUpdate:h,onSegmentedImage:s,task:O=l.TASK,model:D=l.MODEL,verbose:k=l.VERBOSE,bodyPixArchitecture:d=l.BODYPIX_ARCHITECTURE,bodyPixMultiplier:b=l.BODYPIX_MULTIPLIER,bodyPixQuantBytes:B=l.BODYPIX_QUANT_BYTES,bodyPixStride:j=l.BODYPIX_STRIDE,multiSegmentation:v=l.MULTI_SEGMENTATION,segmentBodyParts:W=l.SEGMENT_BODY_PARTS,backgroundShade:A=l.BACKGROUND_SHADE,shirtShade:w=l.SHIRT_SHADE,threshold:_=l.DETECTION_THRESHOLD,targetPartId:y=l.TARGET_PART_ID,imagesToReturn:f=l.IMAGES_TO_RETURN,minDetectionArea:m=l.MIN_DETECTION_AREA,workerUrl:a},P)=>{let I=(0,n.useRef)(null),x=(0,n.useRef)(null),L=(0,n.useRef)(!1),Y=(0,n.useRef)([]),pe=(0,n.useRef)(null),U=(0,n.useRef)(!1),q=(0,n.useRef)(void 0);q.current=c;let Z=(0,n.useRef)({jerseyCount:0,confidence:0,fps:0,processingTime:0}),oe=(0,n.useRef)(0),ye=500,se=5,ie=(0,n.useMemo)(()=>(0,me.default)(se),[]),ee=(0,n.useMemo)(()=>({task:O,model:D,verbose:k,bodyPixArchitecture:d,bodyPixMultiplier:b,bodyPixQuantBytes:B,bodyPixStride:j,multiSegmentation:v,segmentBodyParts:W,backgroundShade:A,shirtShade:w,threshold:_,targetPartId:y,imagesToReturn:f,minDetectionArea:m}),[O,D,k,d,b,B,j,v,W,A,w,_,y,f,m]),he=()=>{var r,i;return{width:((r=e.current)==null?void 0:r.videoWidth)||0,height:((i=e.current)==null?void 0:i.videoHeight)||0}},{isReady:N,workerReady:M,lastError:G,detect:Te}=Q(ee,a);(0,n.useEffect)(()=>{M&&console.log("[JerseyDetector] Worker Ready with config:",ee),o==null||o(M)},[M,o,ee]),(0,n.useEffect)(()=>{var r;G&&(U.current=!0,(r=q.current)==null||r.call(q,G))},[G]);let Ee=(0,n.useCallback)((r,i)=>{if(ie.activeCount>=se){r.forEach(t=>{var u;return(u=t==null?void 0:t.close)==null?void 0:u.call(t)}),console.warn("[JerseyDetector] Dropped new segmented images \u2014 max 5 classifications running");return}ie(()=>S(null,null,function*(){try{s==null||s(r,i)}catch(t){console.error("[JerseyDetector] Classification error:",t)}finally{r.forEach(t=>{var u;return(u=t==null?void 0:t.close)==null?void 0:u.call(t)})}}))},[s]),De=()=>S(null,null,function*(){var H,ae,ce;let r=e.current,i=I.current;if(U.current||!N||!M||!r||!i||L.current||r.readyState<2||r.paused||r.ended||r.videoWidth===0||r.videoHeight===0)return;let t=i.getContext("2d");if(!t||i.width<=0||i.height<=0)return;let u=null,R=null;try{L.current=!0;let F=r.videoWidth,X=r.videoHeight;pe.current={width:F,height:X},u=yield createImageBitmap(r);let Ie=he(),T=yield Te(u,Ie,_);if((T==null?void 0:T.type)==="detect_response"){if(f!=="none"&&((i.width!==F||i.height!==X)&&(i.width=F,i.height=X),t.clearRect(0,0,F,X),T.bitmap)){let J=T.bitmap;t.drawImage(J,0,0),console.log(`[JerseyDetector] Bitmap created with dims ${J.width}x${J.height}`),J.close()}Y.current.push(Date.now()),Y.current=Y.current.filter(J=>Date.now()-J<1e3);let $={jerseyCount:((H=T.stats)==null?void 0:H.jerseyCount)||0,confidence:((ae=T.stats)==null?void 0:ae.confidence)||0,fps:Y.current.length,processingTime:((ce=T.stats)==null?void 0:ce.processingTime)||0},ue=Z.current;Z.current=$;let le=Date.now(),de=le-oe.current>ye||$.jerseyCount!==ue.jerseyCount||$.confidence!==ue.confidence;de&&h&&(h($),oe.current=le),de&&T.segmentedImages&&s&&Ee(T.segmentedImages,T.bboxes)}}catch(F){U.current=!0}finally{u==null||u.close(),L.current=!1}});return(0,n.useImperativeHandle)(P,()=>({get isReady(){return N},get lastError(){return G},get stats(){return Z.current},capture:(r="image/jpeg",i=.92)=>{let t=e.current,u=I.current;if(!t||t.videoWidth<=0||t.videoHeight<=0)throw new Error("Video not ready for capture");let R=document.createElement("canvas");R.width=t.videoWidth,R.height=t.videoHeight;let H=R.getContext("2d");if(!H)throw new Error("Failed to get context for capture canvas");return H.drawImage(t,0,0,R.width,R.height),u&&u.width>0&&u.height>0?H.drawImage(u,0,0,R.width,R.height):console.warn("[capture] Mask canvas not available \u2014 returning raw video frame"),R.toDataURL(r,i)}}),[N,G,M]),(0,n.useEffect)(()=>{if(!M||!N||U.current)return;let r=e.current,i=I.current;if(!r||!i||r.videoWidth===0||r.videoHeight===0){let u=setTimeout(()=>{x.current=requestAnimationFrame(()=>{})},100);return()=>clearTimeout(u)}(i.width!==r.videoWidth||i.height!==r.videoHeight)&&(i.width=r.videoWidth,i.height=r.videoHeight);let t=()=>S(null,null,function*(){!M||!N||U.current||(yield De(),x.current=requestAnimationFrame(t))});return x.current=requestAnimationFrame(t),()=>{x.current&&cancelAnimationFrame(x.current)}},[M,N]),(0,ge.jsx)("canvas",{ref:I,className:"absolute inset-0 pointer-events-none",style:{zIndex:10,width:"100%",height:"100%"}})});ne.displayName="JerseyDetector";0&&(module.exports={DEFAULT_CONFIG,JerseyDetector,useJerseyWorker});
1
+ "use strict";var Me=Object.create;var V=Object.defineProperty;var Ce=Object.getOwnPropertyDescriptor;var We=Object.getOwnPropertyNames,ge=Object.getOwnPropertySymbols,Se=Object.getPrototypeOf,he=Object.prototype.hasOwnProperty,xe=Object.prototype.propertyIsEnumerable;var pe=(e,r,t)=>r in e?V(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t,ye=(e,r)=>{for(var t in r||(r={}))he.call(r,t)&&pe(e,t,r[t]);if(ge)for(var t of ge(r))xe.call(r,t)&&pe(e,t,r[t]);return e};var Oe=(e,r)=>{for(var t in r)V(e,t,{get:r[t],enumerable:!0})},Te=(e,r,t,E)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of We(r))!he.call(e,i)&&i!==t&&V(e,i,{get:()=>r[i],enumerable:!(E=Ce(r,i))||E.enumerable});return e};var Be=(e,r,t)=>(t=e!=null?Me(Se(e)):{},Te(r||!e||!e.__esModule?V(t,"default",{value:e,enumerable:!0}):t,e)),Ne=e=>Te(V({},"__esModule",{value:!0}),e);var x=(e,r,t)=>new Promise((E,i)=>{var O=f=>{try{w(t.next(f))}catch(R){i(R)}},b=f=>{try{w(t.throw(f))}catch(R){i(R)}},w=f=>f.done?E(f.value):Promise.resolve(f.value).then(O,b);w((t=t.apply(e,r)).next())});var Je={};Oe(Je,{DEFAULT_CONFIG:()=>d,JerseyDetector:()=>ie,useJerseyWorker:()=>ee});module.exports=Ne(Je);var s=require("react");var h=require("react");var p=null,W=!1,j=null,oe=0,se=null,k=new Map,Ae=0,Z=new Map;function ee(e,r){let t=(0,h.useRef)(!1),[E,i]=(0,h.useState)(!1),[O,b]=(0,h.useState)(null),w=(0,h.useRef)(!0),f=(0,h.useRef)(!1),R=(0,h.useRef)(`instance_${Math.random().toString(36).substr(2,9)}`),B=(0,h.useRef)(0);(0,h.useEffect)(()=>{var M;if(!e)return;w.current=!0,B.current++;let _=B.current,S=R.current,N=(M=Z.get(S))!=null?M:0;return _>N&&(oe++,Z.set(S,_)),x(null,null,function*(){var y;if(!p||!He(se,e)){p&&(p.terminate(),p=null,W=!1,console.log("[v0 useJerseyWorker] Worker terminated because of change in config"));try{f.current=(y=e.verbose)!=null?y:f.current;let m=r||"/jersey-detector-worker.js";p=new Worker(m),se=e,W=!1,j=null,i(!1),b(null),p.onmessage=g=>{let c=g.data;switch(c.type){case"ready":W=!0,i(!0),f.current&&console.log("[v0 useJerseyWorker] Worker Ready",{device:c.device,dtype:c.dtype,config:c.config});break;case"loading_progress":f.current&&console.log(`[v0 useJerseyWorker] Loaded ${c.progress}% of ${c.file}`);break;case"debug":f.current&&console.log(c.debug_message);break;case"error":let P=c.error_message||"Unknown worker error";console.error("[v0 useJerseyWorker] Worker sent error message:",P),W=!1,j=P,i(!1),b(P);break;case"detect_response":if(c.requestId&&k.has(c.requestId)){let l=k.get(c.requestId);l&&(l.resolve(c),k.delete(c.requestId))}else if(k.size>0){let l=k.entries().next();if(!l.done){let[re,A]=l.value;A.resolve(c),k.delete(re)}}break}},p.onerror=g=>{let c=g.message||"Worker initialization error";console.error("[useJerseyWorker] Worker error:",c),W=!1,j=c,i(!1),b(c)},p.postMessage({type:"init",config:e})}catch(m){let g=(m==null?void 0:m.message)||String(m);console.error("[useJerseyWorker] Failed to create worker:",g),i(!1),b(g)}}else i(W),b(j)}),()=>{w.current=!1;let y=R.current,m=Z.get(y),g=B.current;m===g&&(oe--,Z.delete(y),oe<=0&&p&&(p.terminate(),p=null,W=!1,j=null,se=null,k.clear()))}},[]);let Y=(0,h.useCallback)((_,S,N=.5)=>x(null,null,function*(){if(!p||!W)throw new Error("Worker not ready");if(t.current)return null;let v=`req_${++Ae}_${Date.now()}`;return new Promise((M,y)=>{k.set(v,{resolve:M,reject:y});try{t.current=!0,p.postMessage({type:"detect",requestId:v,dimensions:S,bitmap:_,threshold:N},[_])}catch(m){k.delete(v);let g=`Failed to send detect: ${m==null?void 0:m.message}`;y(new Error(g))}finally{t.current=!1}setTimeout(()=>{k.has(v)&&(k.delete(v),y(new Error("Detection timeout")))},1e4)})}),[E]);return{isReady:E,workerReady:E,lastError:O,detect:Y}}function He(e,r){return e?JSON.stringify(e)===JSON.stringify(r):!1}var d={TASK:"image-segmentation",MODEL:"BodyPix",BODYPIX_ARCHITECTURE:"MobileNetV1",BODYPIX_MULTIPLIER:.75,BODYPIX_QUANT_BYTES:2,BODYPIX_STRIDE:16,MULTI_SEGMENTATION:!0,SEGMENT_BODY_PARTS:!0,BACKGROUND_SHADE:0,SHIRT_SHADE:170,DETECTION_THRESHOLD:.5,TARGET_PART_ID:12,IMAGES_TO_RETURN:"mask",VERBOSE:!1,MIN_DETECTION_AREA:1e4};var Ee=Be(require("p-limit"));var De=require("react/jsx-runtime"),ie=(0,s.forwardRef)(({videoRef:e,onWorkerReady:r,onWorkerError:t,onStatsUpdate:E,onSegmentedImage:i,task:O=d.TASK,model:b=d.MODEL,verbose:w=d.VERBOSE,bodyPixArchitecture:f=d.BODYPIX_ARCHITECTURE,bodyPixMultiplier:R=d.BODYPIX_MULTIPLIER,bodyPixQuantBytes:B=d.BODYPIX_QUANT_BYTES,bodyPixStride:Y=d.BODYPIX_STRIDE,multiSegmentation:_=d.MULTI_SEGMENTATION,segmentBodyParts:S=d.SEGMENT_BODY_PARTS,backgroundShade:N=d.BACKGROUND_SHADE,shirtShade:v=d.SHIRT_SHADE,threshold:M=d.DETECTION_THRESHOLD,targetPartId:y=d.TARGET_PART_ID,imagesToReturn:m=d.IMAGES_TO_RETURN,minDetectionArea:g=d.MIN_DETECTION_AREA,workerUrl:c,className:P,style:l},re)=>{let A=(0,s.useRef)(null),L=(0,s.useRef)(null),te=(0,s.useRef)(!1),q=(0,s.useRef)([]),Ie=(0,s.useRef)(null),U=(0,s.useRef)(!1),X=(0,s.useRef)(void 0);X.current=t;let ne=(0,s.useRef)({jerseyCount:0,confidence:0,fps:0,processingTime:0}),ae=(0,s.useRef)(0),ke=500,ce=5,ue=(0,s.useMemo)(()=>(0,Ee.default)(ce),[]),$=(0,s.useMemo)(()=>({task:O,model:b,verbose:w,bodyPixArchitecture:f,bodyPixMultiplier:R,bodyPixQuantBytes:B,bodyPixStride:Y,multiSegmentation:_,segmentBodyParts:S,backgroundShade:N,shirtShade:v,threshold:M,targetPartId:y,imagesToReturn:m,minDetectionArea:g,mirror:(l==null?void 0:l.transform)==="scaleX(-1)"||typeof(l==null?void 0:l.transform)=="string"&&l.transform.includes("scaleX(-1)")}),[O,b,w,f,R,B,Y,_,S,N,v,M,y,m,g,l==null?void 0:l.transform]),be=()=>{var n,a;return{width:((n=e.current)==null?void 0:n.videoWidth)||0,height:((a=e.current)==null?void 0:a.videoHeight)||0}},{isReady:H,workerReady:C,lastError:G,detect:we}=ee($,c);(0,s.useEffect)(()=>{C&&console.log("[JerseyDetector] Worker Ready with config:",$),r==null||r(C)},[C,r,$]),(0,s.useEffect)(()=>{var n;G&&(U.current=!0,(n=X.current)==null||n.call(X,G))},[G]);let Re=(0,s.useCallback)((n,a)=>{if(ue.activeCount>=ce){n.forEach(o=>{var u;return(u=o==null?void 0:o.close)==null?void 0:u.call(o)}),console.warn("[JerseyDetector] Dropped new segmented images \u2014 max 5 classifications running");return}ue(()=>x(null,null,function*(){try{i==null||i(n,a)}catch(o){console.error("[JerseyDetector] Classification error:",o)}finally{n.forEach(o=>{var u;return(u=o==null?void 0:o.close)==null?void 0:u.call(o)})}}))},[i]),ve=()=>x(null,null,function*(){var D,z,le;let n=e.current,a=A.current;if(U.current||!H||!C||!n||!a||te.current||n.readyState<2||n.paused||n.ended||n.videoWidth===0||n.videoHeight===0)return;let o=a.getContext("2d");if(!o||a.width<=0||a.height<=0)return;let u=null,T=null;try{te.current=!0;let F=n.videoWidth,K=n.videoHeight;Ie.current={width:F,height:K},u=yield createImageBitmap(n);let _e=be(),I=yield we(u,_e,M);if((I==null?void 0:I.type)==="detect_response"){if(m!=="none"&&((a.width!==F||a.height!==K)&&(a.width=F,a.height=K),o.clearRect(0,0,F,K),I.bitmap)){let J=I.bitmap;o.drawImage(J,0,0),console.log(`[JerseyDetector] Bitmap created with dims ${J.width}x${J.height}`),J.close()}q.current.push(Date.now()),q.current=q.current.filter(J=>Date.now()-J<1e3);let Q={jerseyCount:((D=I.stats)==null?void 0:D.jerseyCount)||0,confidence:((z=I.stats)==null?void 0:z.confidence)||0,fps:q.current.length,processingTime:((le=I.stats)==null?void 0:le.processingTime)||0},de=ne.current;ne.current=Q;let fe=Date.now(),me=fe-ae.current>ke||Q.jerseyCount!==de.jerseyCount||Q.confidence!==de.confidence;me&&E&&(E(Q),ae.current=fe),me&&I.segmentedImages&&i&&Re(I.segmentedImages,I.bboxes)}}catch(F){U.current=!0}finally{u==null||u.close(),te.current=!1}});return(0,s.useImperativeHandle)(re,()=>({get isReady(){return H},get lastError(){return G},get stats(){return ne.current},capture:(n="image/jpeg",a=.92)=>{let o=e.current,u=A.current;if(!o||o.videoWidth<=0||o.videoHeight<=0)throw new Error("Video not ready for capture");let T=document.createElement("canvas");T.width=o.videoWidth,T.height=o.videoHeight;let D=T.getContext("2d");if(!D)throw new Error("Failed to get context for capture canvas");let z=$.mirror;return D.drawImage(o,0,0,T.width,T.height),u&&u.width>0&&u.height>0?z?(D.save(),D.translate(T.width,0),D.scale(-1,1),D.drawImage(u,0,0,T.width,T.height),D.restore()):D.drawImage(u,0,0,T.width,T.height):console.warn("[capture] Mask canvas not available \u2014 returning raw video frame"),T.toDataURL(n,a)}}),[H,G,C]),(0,s.useEffect)(()=>{if(!C||!H||U.current)return;let n=e.current,a=A.current;if(!n||!a||n.videoWidth===0||n.videoHeight===0){let u=setTimeout(()=>{L.current=requestAnimationFrame(()=>{})},100);return()=>clearTimeout(u)}(a.width!==n.videoWidth||a.height!==n.videoHeight)&&(a.width=n.videoWidth,a.height=n.videoHeight);let o=()=>x(null,null,function*(){!C||!H||U.current||(yield ve(),L.current=requestAnimationFrame(o))});return L.current=requestAnimationFrame(o),()=>{L.current&&cancelAnimationFrame(L.current)}},[C,H]),(0,De.jsx)("canvas",{ref:A,className:`absolute inset-0 pointer-events-none ${P||""}`,style:ye({zIndex:10,width:"100%",height:"100%"},l)})});ie.displayName="JerseyDetector";0&&(module.exports={DEFAULT_CONFIG,JerseyDetector,useJerseyWorker});
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- var x=(s,p,y)=>new Promise((w,u)=>{var S=i=>{try{E(y.next(i))}catch(D){u(D)}},h=i=>{try{E(y.throw(i))}catch(D){u(D)}},E=i=>i.done?w(i.value):Promise.resolve(i.value).then(S,h);E((y=y.apply(s,p)).next())});import{forwardRef as Re,useImperativeHandle as ve,useRef as b,useEffect as te,useMemo as fe,useCallback as _e}from"react";import{useEffect as Ie,useState as de,useCallback as ke,useRef as F}from"react";var d=null,M=!1,V=null,Z=0,ee=null,g=new Map,be=0,z=new Map;function re(s,p){let y=F(!1),[w,u]=de(!1),[S,h]=de(null),E=F(!0),i=F(!1),D=F(`instance_${Math.random().toString(36).substr(2,9)}`),O=F(0);Ie(()=>{var v;if(!s)return;E.current=!0,O.current++;let R=O.current,C=D.current,B=(v=z.get(C))!=null?v:0;return R>B&&(Z++,z.set(C,R)),x(null,null,function*(){var f;if(!d||!we(ee,s)){d&&(d.terminate(),d=null,M=!1,console.log("[v0 useJerseyWorker] Worker terminated because of change in config"));try{i.current=(f=s.verbose)!=null?f:i.current;let a=p||"/jersey-detector-worker.js";d=new Worker(a),ee=s,M=!1,V=null,u(!1),h(null),d.onmessage=l=>{let n=l.data;switch(n.type){case"ready":M=!0,u(!0),i.current&&console.log("[v0 useJerseyWorker] Worker Ready",{device:n.device,dtype:n.dtype,config:n.config});break;case"loading_progress":i.current&&console.log(`[v0 useJerseyWorker] Loaded ${n.progress}% of ${n.file}`);break;case"debug":i.current&&console.log(n.debug_message);break;case"error":let J=n.error_message||"Unknown worker error";console.error("[v0 useJerseyWorker] Worker sent error message:",J),M=!1,V=J,u(!1),h(J);break;case"detect_response":if(n.requestId&&g.has(n.requestId)){let T=g.get(n.requestId);T&&(T.resolve(n),g.delete(n.requestId))}else if(g.size>0){let T=g.entries().next();if(!T.done){let[W,P]=T.value;P.resolve(n),g.delete(W)}}break}},d.onerror=l=>{let n=l.message||"Worker initialization error";console.error("[useJerseyWorker] Worker error:",n),M=!1,V=n,u(!1),h(n)},d.postMessage({type:"init",config:s})}catch(a){let l=(a==null?void 0:a.message)||String(a);console.error("[useJerseyWorker] Failed to create worker:",l),u(!1),h(l)}}else u(M),h(V)}),()=>{E.current=!1;let f=D.current,a=z.get(f),l=O.current;a===l&&(Z--,z.delete(f),Z<=0&&d&&(d.terminate(),d=null,M=!1,V=null,ee=null,g.clear()))}},[]);let j=ke((R,C,B=.5)=>x(null,null,function*(){if(!d||!M)throw new Error("Worker not ready");if(y.current)return null;let I=`req_${++be}_${Date.now()}`;return new Promise((v,f)=>{g.set(I,{resolve:v,reject:f});try{y.current=!0,d.postMessage({type:"detect",requestId:I,dimensions:C,bitmap:R,threshold:B},[R])}catch(a){g.delete(I);let l=`Failed to send detect: ${a==null?void 0:a.message}`;f(new Error(l))}finally{y.current=!1}setTimeout(()=>{g.has(I)&&(g.delete(I),f(new Error("Detection timeout")))},1e4)})}),[w]);return{isReady:w,workerReady:w,lastError:S,detect:j}}function we(s,p){return s?JSON.stringify(s)===JSON.stringify(p):!1}var c={TASK:"image-segmentation",MODEL:"BodyPix",BODYPIX_ARCHITECTURE:"MobileNetV1",BODYPIX_MULTIPLIER:.75,BODYPIX_QUANT_BYTES:2,BODYPIX_STRIDE:16,MULTI_SEGMENTATION:!0,SEGMENT_BODY_PARTS:!0,BACKGROUND_SHADE:0,SHIRT_SHADE:170,DETECTION_THRESHOLD:.5,TARGET_PART_ID:12,IMAGES_TO_RETURN:"mask",VERBOSE:!1,MIN_DETECTION_AREA:1e4};import Me from"p-limit";import{jsx as Ce}from"react/jsx-runtime";var me=Re(({videoRef:s,onWorkerReady:p,onWorkerError:y,onStatsUpdate:w,onSegmentedImage:u,task:S=c.TASK,model:h=c.MODEL,verbose:E=c.VERBOSE,bodyPixArchitecture:i=c.BODYPIX_ARCHITECTURE,bodyPixMultiplier:D=c.BODYPIX_MULTIPLIER,bodyPixQuantBytes:O=c.BODYPIX_QUANT_BYTES,bodyPixStride:j=c.BODYPIX_STRIDE,multiSegmentation:R=c.MULTI_SEGMENTATION,segmentBodyParts:C=c.SEGMENT_BODY_PARTS,backgroundShade:B=c.BACKGROUND_SHADE,shirtShade:I=c.SHIRT_SHADE,threshold:v=c.DETECTION_THRESHOLD,targetPartId:f=c.TARGET_PART_ID,imagesToReturn:a=c.IMAGES_TO_RETURN,minDetectionArea:l=c.MIN_DETECTION_AREA,workerUrl:n},J)=>{let T=b(null),W=b(null),P=b(!1),Y=b([]),ge=b(null),L=b(!1),q=b(void 0);q.current=y;let K=b({jerseyCount:0,confidence:0,fps:0,processingTime:0}),ne=b(0),pe=500,oe=5,se=fe(()=>Me(oe),[]),Q=fe(()=>({task:S,model:h,verbose:E,bodyPixArchitecture:i,bodyPixMultiplier:D,bodyPixQuantBytes:O,bodyPixStride:j,multiSegmentation:R,segmentBodyParts:C,backgroundShade:B,shirtShade:I,threshold:v,targetPartId:f,imagesToReturn:a,minDetectionArea:l}),[S,h,E,i,D,O,j,R,C,B,I,v,f,a,l]),ye=()=>{var e,t;return{width:((e=s.current)==null?void 0:e.videoWidth)||0,height:((t=s.current)==null?void 0:t.videoHeight)||0}},{isReady:A,workerReady:_,lastError:U,detect:he}=re(Q,n);te(()=>{_&&console.log("[JerseyDetector] Worker Ready with config:",Q),p==null||p(_)},[_,p,Q]),te(()=>{var e;U&&(L.current=!0,(e=q.current)==null||e.call(q,U))},[U]);let Te=_e((e,t)=>{if(se.activeCount>=oe){e.forEach(r=>{var o;return(o=r==null?void 0:r.close)==null?void 0:o.call(r)}),console.warn("[JerseyDetector] Dropped new segmented images \u2014 max 5 classifications running");return}se(()=>x(null,null,function*(){try{u==null||u(e,t)}catch(r){console.error("[JerseyDetector] Classification error:",r)}finally{e.forEach(r=>{var o;return(o=r==null?void 0:r.close)==null?void 0:o.call(r)})}}))},[u]),Ee=()=>x(null,null,function*(){var N,ie,ae;let e=s.current,t=T.current;if(L.current||!A||!_||!e||!t||P.current||e.readyState<2||e.paused||e.ended||e.videoWidth===0||e.videoHeight===0)return;let r=t.getContext("2d");if(!r||t.width<=0||t.height<=0)return;let o=null,k=null;try{P.current=!0;let G=e.videoWidth,X=e.videoHeight;ge.current={width:G,height:X},o=yield createImageBitmap(e);let De=ye(),m=yield he(o,De,v);if((m==null?void 0:m.type)==="detect_response"){if(a!=="none"&&((t.width!==G||t.height!==X)&&(t.width=G,t.height=X),r.clearRect(0,0,G,X),m.bitmap)){let H=m.bitmap;r.drawImage(H,0,0),console.log(`[JerseyDetector] Bitmap created with dims ${H.width}x${H.height}`),H.close()}Y.current.push(Date.now()),Y.current=Y.current.filter(H=>Date.now()-H<1e3);let $={jerseyCount:((N=m.stats)==null?void 0:N.jerseyCount)||0,confidence:((ie=m.stats)==null?void 0:ie.confidence)||0,fps:Y.current.length,processingTime:((ae=m.stats)==null?void 0:ae.processingTime)||0},ce=K.current;K.current=$;let ue=Date.now(),le=ue-ne.current>pe||$.jerseyCount!==ce.jerseyCount||$.confidence!==ce.confidence;le&&w&&(w($),ne.current=ue),le&&m.segmentedImages&&u&&Te(m.segmentedImages,m.bboxes)}}catch(G){L.current=!0}finally{o==null||o.close(),P.current=!1}});return ve(J,()=>({get isReady(){return A},get lastError(){return U},get stats(){return K.current},capture:(e="image/jpeg",t=.92)=>{let r=s.current,o=T.current;if(!r||r.videoWidth<=0||r.videoHeight<=0)throw new Error("Video not ready for capture");let k=document.createElement("canvas");k.width=r.videoWidth,k.height=r.videoHeight;let N=k.getContext("2d");if(!N)throw new Error("Failed to get context for capture canvas");return N.drawImage(r,0,0,k.width,k.height),o&&o.width>0&&o.height>0?N.drawImage(o,0,0,k.width,k.height):console.warn("[capture] Mask canvas not available \u2014 returning raw video frame"),k.toDataURL(e,t)}}),[A,U,_]),te(()=>{if(!_||!A||L.current)return;let e=s.current,t=T.current;if(!e||!t||e.videoWidth===0||e.videoHeight===0){let o=setTimeout(()=>{W.current=requestAnimationFrame(()=>{})},100);return()=>clearTimeout(o)}(t.width!==e.videoWidth||t.height!==e.videoHeight)&&(t.width=e.videoWidth,t.height=e.videoHeight);let r=()=>x(null,null,function*(){!_||!A||L.current||(yield Ee(),W.current=requestAnimationFrame(r))});return W.current=requestAnimationFrame(r),()=>{W.current&&cancelAnimationFrame(W.current)}},[_,A]),Ce("canvas",{ref:T,className:"absolute inset-0 pointer-events-none",style:{zIndex:10,width:"100%",height:"100%"}})});me.displayName="JerseyDetector";export{c as DEFAULT_CONFIG,me as JerseyDetector,re as useJerseyWorker};
1
+ var ve=Object.defineProperty;var me=Object.getOwnPropertySymbols;var _e=Object.prototype.hasOwnProperty,Me=Object.prototype.propertyIsEnumerable;var ge=(t,n,o)=>n in t?ve(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,pe=(t,n)=>{for(var o in n||(n={}))_e.call(n,o)&&ge(t,o,n[o]);if(me)for(var o of me(n))Me.call(n,o)&&ge(t,o,n[o]);return t};var S=(t,n,o)=>new Promise((R,f)=>{var x=u=>{try{I(o.next(u))}catch(k){f(k)}},D=u=>{try{I(o.throw(u))}catch(k){f(k)}},I=u=>u.done?R(u.value):Promise.resolve(u.value).then(x,D);I((o=o.apply(t,n)).next())});import{forwardRef as Oe,useImperativeHandle as Be,useRef as w,useEffect as se,useMemo as ye,useCallback as Ne}from"react";import{useEffect as Ce,useState as he,useCallback as We,useRef as F}from"react";var g=null,C=!1,V=null,te=0,ne=null,E=new Map,Se=0,Q=new Map;function oe(t,n){let o=F(!1),[R,f]=he(!1),[x,D]=he(null),I=F(!0),u=F(!1),k=F(`instance_${Math.random().toString(36).substr(2,9)}`),O=F(0);Ce(()=>{var _;if(!t)return;I.current=!0,O.current++;let v=O.current,W=k.current,B=(_=Q.get(W))!=null?_:0;return v>B&&(te++,Q.set(W,v)),S(null,null,function*(){var p;if(!g||!xe(ne,t)){g&&(g.terminate(),g=null,C=!1,console.log("[v0 useJerseyWorker] Worker terminated because of change in config"));try{u.current=(p=t.verbose)!=null?p:u.current;let l=n||"/jersey-detector-worker.js";g=new Worker(l),ne=t,C=!1,V=null,f(!1),D(null),g.onmessage=m=>{let i=m.data;switch(i.type){case"ready":C=!0,f(!0),u.current&&console.log("[v0 useJerseyWorker] Worker Ready",{device:i.device,dtype:i.dtype,config:i.config});break;case"loading_progress":u.current&&console.log(`[v0 useJerseyWorker] Loaded ${i.progress}% of ${i.file}`);break;case"debug":u.current&&console.log(i.debug_message);break;case"error":let J=i.error_message||"Unknown worker error";console.error("[v0 useJerseyWorker] Worker sent error message:",J),C=!1,V=J,f(!1),D(J);break;case"detect_response":if(i.requestId&&E.has(i.requestId)){let c=E.get(i.requestId);c&&(c.resolve(i),E.delete(i.requestId))}else if(E.size>0){let c=E.entries().next();if(!c.done){let[Z,N]=c.value;N.resolve(i),E.delete(Z)}}break}},g.onerror=m=>{let i=m.message||"Worker initialization error";console.error("[useJerseyWorker] Worker error:",i),C=!1,V=i,f(!1),D(i)},g.postMessage({type:"init",config:t})}catch(l){let m=(l==null?void 0:l.message)||String(l);console.error("[useJerseyWorker] Failed to create worker:",m),f(!1),D(m)}}else f(C),D(V)}),()=>{I.current=!1;let p=k.current,l=Q.get(p),m=O.current;l===m&&(te--,Q.delete(p),te<=0&&g&&(g.terminate(),g=null,C=!1,V=null,ne=null,E.clear()))}},[]);let j=We((v,W,B=.5)=>S(null,null,function*(){if(!g||!C)throw new Error("Worker not ready");if(o.current)return null;let b=`req_${++Se}_${Date.now()}`;return new Promise((_,p)=>{E.set(b,{resolve:_,reject:p});try{o.current=!0,g.postMessage({type:"detect",requestId:b,dimensions:W,bitmap:v,threshold:B},[v])}catch(l){E.delete(b);let m=`Failed to send detect: ${l==null?void 0:l.message}`;p(new Error(m))}finally{o.current=!1}setTimeout(()=>{E.has(b)&&(E.delete(b),p(new Error("Detection timeout")))},1e4)})}),[R]);return{isReady:R,workerReady:R,lastError:x,detect:j}}function xe(t,n){return t?JSON.stringify(t)===JSON.stringify(n):!1}var d={TASK:"image-segmentation",MODEL:"BodyPix",BODYPIX_ARCHITECTURE:"MobileNetV1",BODYPIX_MULTIPLIER:.75,BODYPIX_QUANT_BYTES:2,BODYPIX_STRIDE:16,MULTI_SEGMENTATION:!0,SEGMENT_BODY_PARTS:!0,BACKGROUND_SHADE:0,SHIRT_SHADE:170,DETECTION_THRESHOLD:.5,TARGET_PART_ID:12,IMAGES_TO_RETURN:"mask",VERBOSE:!1,MIN_DETECTION_AREA:1e4};import Ae from"p-limit";import{jsx as He}from"react/jsx-runtime";var Te=Oe(({videoRef:t,onWorkerReady:n,onWorkerError:o,onStatsUpdate:R,onSegmentedImage:f,task:x=d.TASK,model:D=d.MODEL,verbose:I=d.VERBOSE,bodyPixArchitecture:u=d.BODYPIX_ARCHITECTURE,bodyPixMultiplier:k=d.BODYPIX_MULTIPLIER,bodyPixQuantBytes:O=d.BODYPIX_QUANT_BYTES,bodyPixStride:j=d.BODYPIX_STRIDE,multiSegmentation:v=d.MULTI_SEGMENTATION,segmentBodyParts:W=d.SEGMENT_BODY_PARTS,backgroundShade:B=d.BACKGROUND_SHADE,shirtShade:b=d.SHIRT_SHADE,threshold:_=d.DETECTION_THRESHOLD,targetPartId:p=d.TARGET_PART_ID,imagesToReturn:l=d.IMAGES_TO_RETURN,minDetectionArea:m=d.MIN_DETECTION_AREA,workerUrl:i,className:J,style:c},Z)=>{let N=w(null),P=w(null),ee=w(!1),Y=w([]),Ee=w(null),L=w(!1),q=w(void 0);q.current=o;let re=w({jerseyCount:0,confidence:0,fps:0,processingTime:0}),ie=w(0),De=500,ae=5,ce=ye(()=>Ae(ae),[]),X=ye(()=>({task:x,model:D,verbose:I,bodyPixArchitecture:u,bodyPixMultiplier:k,bodyPixQuantBytes:O,bodyPixStride:j,multiSegmentation:v,segmentBodyParts:W,backgroundShade:B,shirtShade:b,threshold:_,targetPartId:p,imagesToReturn:l,minDetectionArea:m,mirror:(c==null?void 0:c.transform)==="scaleX(-1)"||typeof(c==null?void 0:c.transform)=="string"&&c.transform.includes("scaleX(-1)")}),[x,D,I,u,k,O,j,v,W,B,b,_,p,l,m,c==null?void 0:c.transform]),Ie=()=>{var e,s;return{width:((e=t.current)==null?void 0:e.videoWidth)||0,height:((s=t.current)==null?void 0:s.videoHeight)||0}},{isReady:A,workerReady:M,lastError:U,detect:ke}=oe(X,i);se(()=>{M&&console.log("[JerseyDetector] Worker Ready with config:",X),n==null||n(M)},[M,n,X]),se(()=>{var e;U&&(L.current=!0,(e=q.current)==null||e.call(q,U))},[U]);let be=Ne((e,s)=>{if(ce.activeCount>=ae){e.forEach(r=>{var a;return(a=r==null?void 0:r.close)==null?void 0:a.call(r)}),console.warn("[JerseyDetector] Dropped new segmented images \u2014 max 5 classifications running");return}ce(()=>S(null,null,function*(){try{f==null||f(e,s)}catch(r){console.error("[JerseyDetector] Classification error:",r)}finally{e.forEach(r=>{var a;return(a=r==null?void 0:r.close)==null?void 0:a.call(r)})}}))},[f]),we=()=>S(null,null,function*(){var y,$,ue;let e=t.current,s=N.current;if(L.current||!A||!M||!e||!s||ee.current||e.readyState<2||e.paused||e.ended||e.videoWidth===0||e.videoHeight===0)return;let r=s.getContext("2d");if(!r||s.width<=0||s.height<=0)return;let a=null,h=null;try{ee.current=!0;let G=e.videoWidth,z=e.videoHeight;Ee.current={width:G,height:z},a=yield createImageBitmap(e);let Re=Ie(),T=yield ke(a,Re,_);if((T==null?void 0:T.type)==="detect_response"){if(l!=="none"&&((s.width!==G||s.height!==z)&&(s.width=G,s.height=z),r.clearRect(0,0,G,z),T.bitmap)){let H=T.bitmap;r.drawImage(H,0,0),console.log(`[JerseyDetector] Bitmap created with dims ${H.width}x${H.height}`),H.close()}Y.current.push(Date.now()),Y.current=Y.current.filter(H=>Date.now()-H<1e3);let K={jerseyCount:((y=T.stats)==null?void 0:y.jerseyCount)||0,confidence:(($=T.stats)==null?void 0:$.confidence)||0,fps:Y.current.length,processingTime:((ue=T.stats)==null?void 0:ue.processingTime)||0},le=re.current;re.current=K;let de=Date.now(),fe=de-ie.current>De||K.jerseyCount!==le.jerseyCount||K.confidence!==le.confidence;fe&&R&&(R(K),ie.current=de),fe&&T.segmentedImages&&f&&be(T.segmentedImages,T.bboxes)}}catch(G){L.current=!0}finally{a==null||a.close(),ee.current=!1}});return Be(Z,()=>({get isReady(){return A},get lastError(){return U},get stats(){return re.current},capture:(e="image/jpeg",s=.92)=>{let r=t.current,a=N.current;if(!r||r.videoWidth<=0||r.videoHeight<=0)throw new Error("Video not ready for capture");let h=document.createElement("canvas");h.width=r.videoWidth,h.height=r.videoHeight;let y=h.getContext("2d");if(!y)throw new Error("Failed to get context for capture canvas");let $=X.mirror;return y.drawImage(r,0,0,h.width,h.height),a&&a.width>0&&a.height>0?$?(y.save(),y.translate(h.width,0),y.scale(-1,1),y.drawImage(a,0,0,h.width,h.height),y.restore()):y.drawImage(a,0,0,h.width,h.height):console.warn("[capture] Mask canvas not available \u2014 returning raw video frame"),h.toDataURL(e,s)}}),[A,U,M]),se(()=>{if(!M||!A||L.current)return;let e=t.current,s=N.current;if(!e||!s||e.videoWidth===0||e.videoHeight===0){let a=setTimeout(()=>{P.current=requestAnimationFrame(()=>{})},100);return()=>clearTimeout(a)}(s.width!==e.videoWidth||s.height!==e.videoHeight)&&(s.width=e.videoWidth,s.height=e.videoHeight);let r=()=>S(null,null,function*(){!M||!A||L.current||(yield we(),P.current=requestAnimationFrame(r))});return P.current=requestAnimationFrame(r),()=>{P.current&&cancelAnimationFrame(P.current)}},[M,A]),He("canvas",{ref:N,className:`absolute inset-0 pointer-events-none ${J||""}`,style:pe({zIndex:10,width:"100%",height:"100%"},c)})});Te.displayName="JerseyDetector";export{d as DEFAULT_CONFIG,Te as JerseyDetector,oe as useJerseyWorker};