react-native-biometric-verifier 0.0.55 → 0.0.57

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/package.json CHANGED
@@ -1,11 +1,8 @@
1
1
  {
2
2
  "name": "react-native-biometric-verifier",
3
- "version": "0.0.55",
3
+ "version": "0.0.57",
4
4
  "description": "A React Native module for biometric verification with face recognition and QR code scanning",
5
5
  "main": "src/index.js",
6
- "private": false,
7
- "license": "JESCON TECHNOLOGIES PVT LMT ,THRISSUR,KERALA",
8
- "author": "PRAFUL DAS M M",
9
6
  "scripts": {
10
7
  "test": "echo \"Error: no test specified\" && exit 1"
11
8
  },
@@ -16,24 +13,15 @@
16
13
  "face-recognition",
17
14
  "qr-code"
18
15
  ],
19
- "repository": {
20
- "type": "git",
21
- "url": "https://github.com/jescon-technologies/react-native-biometric-verifier"
22
- },
23
- "bugs": {
24
- "url": "https://github.com/jescon-technologies/react-native-biometric-verifier/issues"
25
- },
26
- "homepage": "https://github.com/jescon-technologies/react-native-biometric-verifier#readme",
27
- "files": [
28
- "src",
29
- "README.md"
30
- ],
16
+ "author": "PRAFULDAS M M",
17
+ "license": "JESCON TECHNOLOGIES PVT LTD",
31
18
  "peerDependencies": {
32
19
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
33
20
  "react-native": ">=0.60.0",
34
21
  "react-native-vector-icons": "^9.0.0",
35
22
  "react-native-geolocation-service": "^5.0.0",
36
23
  "react-native-image-resizer": "^1.0.0",
24
+ "@react-navigation/native": "^6.0.0",
37
25
  "prop-types": "^15.8.0",
38
26
  "react-native-fs": "^2.20.0"
39
27
  },
@@ -24,7 +24,7 @@ const CaptureImageWithoutEdit = React.memo(
24
24
  showCodeScanner = false,
25
25
  isLoading = false,
26
26
  frameProcessorFps = 1,
27
- livenessLevel = 0, // 0 = anti-spoof only, 1 = anti-spoof + blinking
27
+ livenessLevel = 0,
28
28
  antispooflevel,
29
29
  }) => {
30
30
  const cameraRef = useRef(null);
@@ -119,7 +119,6 @@ const CaptureImageWithoutEdit = React.memo(
119
119
  );
120
120
 
121
121
  const onFacesUpdate = useCallback((payload) => {
122
- console.log('qqqqqq',JSON.stringify(payload))
123
122
  if (!isMounted.current) return;
124
123
  try {
125
124
  const { count, progress, antiSpoofState } = payload;
@@ -204,7 +203,7 @@ const CaptureImageWithoutEdit = React.memo(
204
203
  isLoading,
205
204
  isActive: showCamera && cameraInitialized,
206
205
  livenessLevel: livenessLevel,
207
- antispooflevel:antispooflevel,
206
+ antispooflevel,
208
207
  });
209
208
 
210
209
  useEffect(() => {
@@ -436,7 +435,7 @@ const CaptureImageWithoutEdit = React.memo(
436
435
  isActive={showCamera && !isLoading}
437
436
  photo={true}
438
437
  format={format}
439
- codeScanner={showCodeScanner ? codeScanner : undefined}
438
+ codeScanner={showCodeScanner && cameraInitialized ? codeScanner : undefined}
440
439
  enableZoomGesture={false}
441
440
  lowLightBoost={cameraDevice.supportsLowLightBoost}
442
441
  frameProcessor={
@@ -5,30 +5,23 @@ import {
5
5
  Modal,
6
6
  Animated,
7
7
  Easing,
8
- Text,
9
- Image,
10
- Dimensions,
8
+ Text
11
9
  } from "react-native";
10
+ import FastImage from 'react-native-fast-image';
11
+ import { normalize } from "react-native-elements";
12
12
  import { getLoaderGif } from "../utils/getLoaderGif";
13
13
 
14
- const { width, height } = Dimensions.get("window");
15
-
16
- // Helper: convert percentage of screen width to px
17
- const wp = (percent) => (width * percent) / 100;
18
-
19
14
  export default function Loader({
20
15
  state,
21
- overlayColor = "rgba(0,0,0,0.4)",
22
- loaderColor = "lightblue",
23
- size = 12, // % of screen width
24
- gifSource = {
25
- uri: "http://emr.amalaims.org:9393/file/getCommonFile/image/Face.gif",
26
- },
27
- message = "",
16
+ overlayColor = 'rgba(0,0,0,0.4)',
17
+ loaderColor = 'lightblue',
18
+ size = 50,
19
+ gifSource = { uri: "http://emr.amalaims.org:9393/file/getCommonFile/image/Face.gif" },
20
+ message = '',
28
21
  messageStyle = {},
29
- animationType = "fade",
22
+ animationType = 'fade',
30
23
  hasBackground = true,
31
- borderRadius = 4, // %
24
+ borderRadius = 20,
32
25
  shadow = true,
33
26
  imageurl,
34
27
  }) {
@@ -37,29 +30,30 @@ export default function Loader({
37
30
  const [fade] = useState(new Animated.Value(0));
38
31
  const [imageSource, setImageSource] = useState(gifSource);
39
32
 
40
- const error = getLoaderGif(
41
- state.animationState,
42
- state.currentStep,
43
- "http://emr.amalaims.org:9393/",
44
- imageurl
45
- );
33
+ const error = getLoaderGif(state.animationState, state.currentStep, "http://emr.amalaims.org:9393/", imageurl);
46
34
 
35
+ // Reset imageSource whenever gifSource prop changes
47
36
  useEffect(() => {
48
37
  setImageSource(gifSource);
49
38
  }, [gifSource]);
50
39
 
51
40
  const handleImageError = () => {
52
- setImageSource(error);
41
+ try {
42
+ setImageSource(error);
43
+ } catch (err) {
44
+ console.error("Loader image error:", err);
45
+ }
53
46
  };
54
47
 
48
+ // Rotation, pulse, and fade-in animations
55
49
  useEffect(() => {
56
- if (!gifSource) {
50
+ if (!gifSource) { // Only animate if not using a GIF
57
51
  Animated.loop(
58
52
  Animated.timing(rotation, {
59
53
  toValue: 1,
60
54
  duration: 1500,
61
55
  easing: Easing.linear,
62
- useNativeDriver: true,
56
+ useNativeDriver: true
63
57
  })
64
58
  ).start();
65
59
  }
@@ -69,90 +63,80 @@ export default function Loader({
69
63
  Animated.timing(pulse, {
70
64
  toValue: 1.1,
71
65
  duration: 800,
72
- useNativeDriver: true,
66
+ useNativeDriver: true
73
67
  }),
74
68
  Animated.timing(pulse, {
75
69
  toValue: 1,
76
70
  duration: 800,
77
- useNativeDriver: true,
78
- }),
71
+ useNativeDriver: true
72
+ })
79
73
  ])
80
74
  ).start();
81
75
 
82
76
  Animated.timing(fade, {
83
77
  toValue: 1,
84
78
  duration: 300,
85
- useNativeDriver: true,
79
+ useNativeDriver: true
86
80
  }).start();
87
81
  }, []);
88
82
 
89
83
  const spin = rotation.interpolate({
90
84
  inputRange: [0, 1],
91
- outputRange: ["0deg", "360deg"],
85
+ outputRange: ['0deg', '360deg']
92
86
  });
93
87
 
94
- const loaderSize = wp(size);
95
- const borderSize = loaderSize * 0.12;
96
-
97
88
  const loaderContent = gifSource ? (
98
- <Image
99
- style={[
100
- styles.icon,
101
- { width: loaderSize, height: loaderSize },
102
- ]}
89
+ <FastImage
90
+ style={[styles.icon_style, { width: normalize(size), height: normalize(size) }]}
103
91
  source={imageSource}
92
+ resizeMode={FastImage.resizeMode.contain}
104
93
  onError={handleImageError}
105
94
  />
106
95
  ) : (
107
- <Animated.View
108
- style={[
109
- styles.defaultLoader,
96
+ <Animated.View style={[
97
+ styles.defaultLoader,
98
+ {
99
+ borderColor: loaderColor,
100
+ transform: [{ rotate: spin }, { scale: pulse }],
101
+ width: normalize(size),
102
+ height: normalize(size),
103
+ borderWidth: normalize(size / 10)
104
+ }
105
+ ]}>
106
+ <View style={[
107
+ styles.innerCircle,
110
108
  {
111
- width: loaderSize,
112
- height: loaderSize,
113
- borderWidth: borderSize,
114
- borderColor: loaderColor,
115
- transform: [{ rotate: spin }, { scale: pulse }],
116
- },
117
- ]}
118
- >
119
- <View
120
- style={[
121
- styles.innerCircle,
122
- {
123
- width: loaderSize / 2,
124
- height: loaderSize / 2,
125
- backgroundColor: loaderColor,
126
- },
127
- ]}
128
- />
109
+ backgroundColor: loaderColor,
110
+ width: normalize(size / 2),
111
+ height: normalize(size / 2)
112
+ }
113
+ ]} />
129
114
  </Animated.View>
130
115
  );
131
116
 
132
117
  return (
133
118
  <Modal
134
119
  animationType={animationType}
135
- transparent
120
+ transparent={true}
136
121
  visible={state.isLoading}
137
- onRequestClose={() => {}}
122
+ onRequestClose={() => { }}
138
123
  >
139
- <Animated.View
140
- style={[
141
- styles.modalContainer,
142
- { backgroundColor: overlayColor, opacity: fade },
143
- ]}
144
- >
145
- <Animated.View
146
- style={[
147
- styles.loaderContainer,
148
- {
149
- backgroundColor: hasBackground ? "white" : "transparent",
150
- borderRadius: wp(borderRadius),
151
- transform: [{ scale: pulse }],
152
- },
153
- shadow && styles.shadowStyle,
154
- ]}
155
- >
124
+ <Animated.View style={[
125
+ styles.modalContainer,
126
+ {
127
+ backgroundColor: overlayColor,
128
+ opacity: fade
129
+ }
130
+ ]}>
131
+ <Animated.View style={[
132
+ styles.loaderContainer,
133
+ {
134
+ backgroundColor: hasBackground ? 'white' : 'transparent',
135
+ borderRadius: normalize(borderRadius),
136
+ transform: [{ scale: pulse }],
137
+ ...(shadow && styles.shadowStyle)
138
+ }
139
+ ]}>
156
140
  {loaderContent}
157
141
  {message ? (
158
142
  <Text style={[styles.messageText, messageStyle]}>
@@ -168,36 +152,40 @@ export default function Loader({
168
152
  const styles = StyleSheet.create({
169
153
  modalContainer: {
170
154
  flex: 1,
171
- justifyContent: "center",
172
- alignItems: "center",
155
+ justifyContent: 'center',
156
+ alignItems: 'center',
173
157
  },
174
158
  loaderContainer: {
175
- padding: wp(5),
176
- justifyContent: "center",
177
- alignItems: "center",
159
+ padding: normalize(20),
160
+ justifyContent: 'center',
161
+ alignItems: 'center',
178
162
  },
179
- icon: {
180
- resizeMode: "contain",
163
+ icon_style: {
164
+ justifyContent: "center",
165
+ alignItems: "center"
181
166
  },
182
167
  defaultLoader: {
183
- borderRadius: 1000,
184
- justifyContent: "center",
185
- alignItems: "center",
168
+ borderRadius: normalize(100),
169
+ justifyContent: 'center',
170
+ alignItems: 'center',
186
171
  },
187
172
  innerCircle: {
188
- borderRadius: 1000,
173
+ borderRadius: normalize(100),
189
174
  },
190
175
  messageText: {
191
- marginTop: wp(3),
192
- fontSize: wp(3.5),
193
- color: "#555",
194
- textAlign: "center",
176
+ marginTop: normalize(15),
177
+ fontSize: normalize(14),
178
+ color: '#555',
179
+ textAlign: 'center'
195
180
  },
196
181
  shadowStyle: {
197
182
  shadowColor: "#000",
198
- shadowOffset: { width: 0, height: 2 },
183
+ shadowOffset: {
184
+ width: 0,
185
+ height: 2,
186
+ },
199
187
  shadowOpacity: 0.25,
200
188
  shadowRadius: 3.84,
201
189
  elevation: 5,
202
- },
190
+ }
203
191
  });
@@ -1,23 +1,32 @@
1
1
  import React, { useEffect, useRef } from 'react';
2
2
  import { Animated, Text, Platform, StyleSheet } from 'react-native';
3
3
  import Icon from 'react-native-vector-icons/MaterialIcons';
4
+ import PropTypes from 'prop-types';
4
5
  import { Global } from '../utils/Global';
5
6
 
6
- export const Notification = ({ notification = {}, fadeAnim, slideAnim }) => {
7
- const { visible = false, type = 'info', message = '' } = notification;
7
+ export const Notification = ({ notification, fadeAnim, slideAnim }) => {
8
+ if (!notification || typeof notification !== 'object') {
9
+ console.warn('Notification: Invalid or missing notification object');
10
+ return null;
11
+ }
8
12
 
9
- // Animations (must ALWAYS exist)
10
- const scaleAnim = useRef(new Animated.Value(1)).current;
11
- const shakeAnim = useRef(new Animated.Value(0)).current;
13
+ const { visible, type = 'info', message = '' } = notification;
14
+ if (!visible) return null;
12
15
 
16
+ // Icon and color mapping
13
17
  const iconMap = {
14
18
  success: { name: 'check-circle', color: Global.AppTheme.success },
15
19
  error: { name: 'error', color: Global.AppTheme.error },
16
20
  info: { name: 'info', color: Global.AppTheme.info },
17
21
  };
18
22
 
19
- const { name: iconName, color: iconColor } =
20
- iconMap[type] || iconMap.info;
23
+ const { name: iconName, color: iconColor } = iconMap[type] || iconMap.info;
24
+
25
+ // Heartbeat animation (scale in/out)
26
+ const scaleAnim = useRef(new Animated.Value(1)).current;
27
+
28
+ // Shake animation (rotation wiggle)
29
+ const shakeAnim = useRef(new Animated.Value(0)).current;
21
30
 
22
31
  useEffect(() => {
23
32
  const heartbeat = Animated.loop(
@@ -69,20 +78,20 @@ export const Notification = ({ notification = {}, fadeAnim, slideAnim }) => {
69
78
  heartbeat.stop();
70
79
  shake.stop();
71
80
  };
72
- }, [visible, type]);
81
+ }, [visible, type, scaleAnim, shakeAnim]);
73
82
 
74
- const shakeRotate = shakeAnim.interpolate({
83
+ // Shake rotation mapping (small wiggle)
84
+ const shakeInterpolate = shakeAnim.interpolate({
75
85
  inputRange: [-1, 1],
76
86
  outputRange: ['-10deg', '10deg'],
77
87
  });
78
88
 
79
89
  return (
80
90
  <Animated.View
81
- pointerEvents={visible ? 'auto' : 'none'}
82
91
  style={[
83
92
  styles.container,
84
93
  {
85
- opacity: visible ? 1 : 0,
94
+ opacity: fadeAnim instanceof Animated.Value ? fadeAnim : 1,
86
95
  transform: [
87
96
  { translateY: slideAnim instanceof Animated.Value ? slideAnim : 0 },
88
97
  ],
@@ -93,13 +102,12 @@ export const Notification = ({ notification = {}, fadeAnim, slideAnim }) => {
93
102
  style={{
94
103
  transform: [
95
104
  { scale: scaleAnim },
96
- ...(type === 'error' ? [{ rotate: shakeRotate }] : []),
105
+ ...(type === 'error' ? [{ rotate: shakeInterpolate }] : []),
97
106
  ],
98
107
  }}
99
108
  >
100
- <Icon name={iconName} size={50} color={iconColor} />
109
+ <Icon name={iconName} size={50} color={iconColor} style={styles.icon} />
101
110
  </Animated.View>
102
-
103
111
  <Text style={styles.message}>
104
112
  {message || 'No message provided'}
105
113
  </Text>
@@ -134,4 +142,20 @@ const styles = StyleSheet.create({
134
142
  },
135
143
  });
136
144
 
145
+ Notification.propTypes = {
146
+ notification: PropTypes.shape({
147
+ visible: PropTypes.bool.isRequired,
148
+ type: PropTypes.oneOf(['success', 'error', 'info']),
149
+ message: PropTypes.string,
150
+ }),
151
+ fadeAnim: PropTypes.instanceOf(Animated.Value),
152
+ slideAnim: PropTypes.instanceOf(Animated.Value),
153
+ };
154
+
155
+ Notification.defaultProps = {
156
+ notification: { visible: false, type: 'info', message: '' },
157
+ fadeAnim: new Animated.Value(1),
158
+ slideAnim: new Animated.Value(0),
159
+ };
160
+
137
161
  export default Notification;
@@ -38,8 +38,8 @@ export const useFaceDetectionFrameProcessor = ({
38
38
  showCodeScanner = false,
39
39
  isLoading = false,
40
40
  isActive = true,
41
- livenessLevel = 0,
42
- antispooflevel = 7,
41
+ livenessLevel,
42
+ antispooflevel = 0.7,
43
43
  }) => {
44
44
  const { detectFaces } = useFaceDetector({
45
45
  performanceMode: 'fast',
@@ -56,7 +56,7 @@ export const useFaceDetectionFrameProcessor = ({
56
56
  // Initialize anti-spoofing with memoization
57
57
  const initializeAntiSpoof = useCallback(async () => {
58
58
  if (antiSpoofInitialized.current) return true;
59
-
59
+
60
60
  try {
61
61
  const available = isFaceAntiSpoofAvailable?.();
62
62
  if (!available) return false;
@@ -82,10 +82,10 @@ export const useFaceDetectionFrameProcessor = ({
82
82
  Worklets.createSharedValue({
83
83
  // Core timing
84
84
  lastProcessedTime: 0,
85
-
85
+
86
86
  // Face tracking - packed for memory efficiency
87
87
  faceTracking: { lastX: 0, lastY: 0, lastW: 0, lastH: 0, stableCount: 0 },
88
-
88
+
89
89
  // State flags - packed together
90
90
  flags: {
91
91
  captured: false,
@@ -95,14 +95,14 @@ export const useFaceDetectionFrameProcessor = ({
95
95
  isFaceCentered: false,
96
96
  eyeClosed: false,
97
97
  },
98
-
98
+
99
99
  // Liveness state
100
100
  liveness: {
101
101
  level: livenessLevel,
102
102
  step: 0,
103
103
  blinkCount: 0,
104
104
  },
105
-
105
+
106
106
  // Anti-spoof state
107
107
  antiSpoof: {
108
108
  consecutiveLiveFrames: 0,
@@ -110,14 +110,14 @@ export const useFaceDetectionFrameProcessor = ({
110
110
  isLive: false,
111
111
  confidence: 0,
112
112
  },
113
-
113
+
114
114
  // Face centering
115
115
  centering: {
116
116
  centeredFrames: 0,
117
117
  frameWidth: 0,
118
118
  frameHeight: 0,
119
119
  },
120
-
120
+
121
121
  // Performance tracking
122
122
  performance: {
123
123
  batchCounter: 0,
@@ -181,7 +181,7 @@ export const useFaceDetectionFrameProcessor = ({
181
181
  Worklets.createRunOnJS((count, progress, step, isCentered, antiSpoofState) => {
182
182
  const now = Date.now();
183
183
  const callbacks = callbacksRef.current;
184
-
184
+
185
185
  if (now - callbacks.lastFacesEventTime > FACES_EVENT_INTERVAL_MS) {
186
186
  callbacks.lastFacesEventTime = now;
187
187
  onFacesUpdate?.({ count, progress, step, isCentered, antiSpoofState });
@@ -195,7 +195,7 @@ export const useFaceDetectionFrameProcessor = ({
195
195
  Worklets.createRunOnJS((step, extra) => {
196
196
  const now = Date.now();
197
197
  const callbacks = callbacksRef.current;
198
-
198
+
199
199
  if (now - callbacks.lastLivenessEventTime > LIVENESS_EVENT_INTERVAL_MS) {
200
200
  callbacks.lastLivenessEventTime = now;
201
201
  onLivenessUpdate?.(step, extra);
@@ -209,7 +209,7 @@ export const useFaceDetectionFrameProcessor = ({
209
209
  Worklets.createRunOnJS((result) => {
210
210
  const now = Date.now();
211
211
  const callbacks = callbacksRef.current;
212
-
212
+
213
213
  if (now - callbacks.lastAntiSpoofEventTime > ANTI_SPOOF_EVENT_INTERVAL_MS) {
214
214
  callbacks.lastAntiSpoofEventTime = now;
215
215
  onAntiSpoofUpdate?.(result);
@@ -221,7 +221,7 @@ export const useFaceDetectionFrameProcessor = ({
221
221
  // Optimized face centering check - inlined for performance
222
222
  const isFaceCenteredInFrame = Worklets.createRunOnJS((faceBounds, frameWidth, frameHeight) => {
223
223
  'worklet';
224
-
224
+
225
225
  if (!faceBounds || frameWidth === 0 || frameHeight === 0) return false;
226
226
 
227
227
  const faceCenterX = faceBounds.x + faceBounds.width / 2;
@@ -251,10 +251,10 @@ export const useFaceDetectionFrameProcessor = ({
251
251
  const frameProcessor = useFrameProcessor(
252
252
  (frame) => {
253
253
  'worklet';
254
-
254
+
255
255
  // Performance monitoring
256
256
  const processingStart = Date.now();
257
-
257
+
258
258
  const state = sharedState.value;
259
259
  const now = frame?.timestamp ? frame.timestamp / 1e6 : Date.now();
260
260
 
@@ -269,7 +269,7 @@ export const useFaceDetectionFrameProcessor = ({
269
269
  frame.release?.();
270
270
  return;
271
271
  }
272
-
272
+
273
273
  frameProcessingStartTime.current = processingStart;
274
274
 
275
275
  let detected = null;
@@ -293,7 +293,7 @@ export const useFaceDetectionFrameProcessor = ({
293
293
  state.centering.centeredFrames = 0;
294
294
  state.flags.isFaceCentered = false;
295
295
  state.lastProcessedTime = now;
296
-
296
+
297
297
  runOnFaces(0, 0, state.liveness.step, false, {
298
298
  isLive: false,
299
299
  confidence: 0,
@@ -341,8 +341,8 @@ export const useFaceDetectionFrameProcessor = ({
341
341
 
342
342
  // Face centering check
343
343
  const centered = isFaceCenteredInFrame(
344
- bounds,
345
- state.centering.frameWidth,
344
+ bounds,
345
+ state.centering.frameWidth,
346
346
  state.centering.frameHeight
347
347
  );
348
348
 
@@ -434,8 +434,8 @@ export const useFaceDetectionFrameProcessor = ({
434
434
  } else {
435
435
  const dx = Math.abs(x - state.faceTracking.lastX);
436
436
  const dy = Math.abs(y - state.faceTracking.lastY);
437
- newStableCount = (dx < FACE_MOVEMENT_THRESHOLD && dy < FACE_MOVEMENT_THRESHOLD)
438
- ? state.faceTracking.stableCount + 1
437
+ newStableCount = (dx < FACE_MOVEMENT_THRESHOLD && dy < FACE_MOVEMENT_THRESHOLD)
438
+ ? state.faceTracking.stableCount + 1
439
439
  : 1;
440
440
  }
441
441
 
@@ -452,7 +452,7 @@ export const useFaceDetectionFrameProcessor = ({
452
452
  state.performance.batchCounter++;
453
453
 
454
454
  const progress = Math.min(100, (newStableCount / FACE_STABILITY_THRESHOLD) * 100);
455
-
455
+
456
456
  // Batch face updates
457
457
  if (state.performance.batchCounter % BATCH_UPDATE_THRESHOLD === 0) {
458
458
  runOnFaces(1, progress, newLivenessStep, state.flags.isFaceCentered, {
@@ -471,8 +471,8 @@ export const useFaceDetectionFrameProcessor = ({
471
471
  state.antiSpoof.consecutiveLiveFrames >= REQUIRED_CONSECUTIVE_LIVE_FRAMES &&
472
472
  state.flags.isFaceCentered &&
473
473
  (localState.livenessLevel === 0 || (
474
- localState.livenessLevel === 1 &&
475
- newLivenessStep === 2 &&
474
+ localState.livenessLevel === 1 &&
475
+ newLivenessStep === 2 &&
476
476
  newBlinkCount >= REQUIRED_BLINKS
477
477
  ))
478
478
  );
@@ -492,7 +492,7 @@ export const useFaceDetectionFrameProcessor = ({
492
492
  state.flags.hasSingleFace = false;
493
493
  state.centering.centeredFrames = 0;
494
494
  state.flags.isFaceCentered = false;
495
-
495
+
496
496
  runOnFaces(detected.length, 0, state.liveness.step, false, {
497
497
  isLive: false,
498
498
  confidence: 0,
@@ -537,7 +537,7 @@ export const useFaceDetectionFrameProcessor = ({
537
537
 
538
538
  const forceResetCaptureState = useCallback(() => {
539
539
  const current = sharedState.value;
540
-
540
+
541
541
  sharedState.value = {
542
542
  lastProcessedTime: 0,
543
543
  faceTracking: {