@rick427/react-native-liveness 0.2.3 → 0.3.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.
@@ -4,25 +4,20 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { runAtTargetFps, useFrameProcessor } from 'react-native-vision-camera';
5
5
  import { Worklets } from 'react-native-worklets-core';
6
6
  import { useLivenessPlugin } from "./LivenessDetector.js";
7
- import { getFeedback, rollingAverage, scoreFrame } from "./livenessScoring.js";
8
- const WINDOW_SIZE = 20;
9
- // How many frames to decay consecutiveGood by on a bad frame.
10
- // 1 means a single noisy/blink frame only undoes one good frame.
11
- const CONSECUTIVE_DECAY = 1;
7
+ import { CHALLENGE_STEPS } from "./livenessScoring.js";
8
+ const TOTAL_STEPS = CHALLENGE_STEPS.length;
12
9
  const _worklet_11184642299290_init_data = {
13
10
  code: "function useLivenessCameraTs1(){const{plugin,frame,handleFaceDataJS}=this.__closure;const face=plugin.detectLiveness(frame);handleFaceDataJS(face,frame.width);}",
14
11
  location: "/home/runner/work/react-native-liveness/react-native-liveness/src/useLivenessCamera.ts",
15
- sourceMap: "{\"version\":3,\"names\":[\"useLivenessCameraTs1\",\"plugin\",\"frame\",\"handleFaceDataJS\",\"__closure\",\"face\",\"detectLiveness\",\"width\"],\"sources\":[\"/home/runner/work/react-native-liveness/react-native-liveness/src/useLivenessCamera.ts\"],\"mappings\":\"AAyNyB,SAAAA,oBAAMA,CAAA,QAAAC,MAAA,CAAAC,KAAA,CAAAC,gBAAA,OAAAC,SAAA,CAEvB,KAAM,CAAAC,IAAI,CAAGJ,MAAM,CAACK,cAAc,CAACJ,KAAK,CAAC,CACzCC,gBAAgB,CAACE,IAAI,CAAEH,KAAK,CAACK,KAAK,CAAC,CACrC\",\"ignoreList\":[]}"
12
+ sourceMap: "{\"version\":3,\"names\":[\"useLivenessCameraTs1\",\"plugin\",\"frame\",\"handleFaceDataJS\",\"__closure\",\"face\",\"detectLiveness\",\"width\"],\"sources\":[\"/home/runner/work/react-native-liveness/react-native-liveness/src/useLivenessCamera.ts\"],\"mappings\":\"AAkLyB,SAAAA,oBAAMA,CAAA,QAAAC,MAAA,CAAAC,KAAA,CAAAC,gBAAA,OAAAC,SAAA,CAEvB,KAAM,CAAAC,IAAI,CAAGJ,MAAM,CAACK,cAAc,CAACJ,KAAK,CAAC,CACzCC,gBAAgB,CAACE,IAAI,CAAEH,KAAK,CAACK,KAAK,CAAC,CACrC\",\"ignoreList\":[]}"
16
13
  };
17
14
  const _worklet_14471027507603_init_data = {
18
15
  code: "function useLivenessCameraTs2(frame){const{runAtTargetFps,_worklet_11184642299290_init_data,plugin,handleFaceDataJS}=this.__closure;runAtTargetFps(20,function useLivenessCameraTs1Factory({_worklet_11184642299290_init_data:_worklet_11184642299290_init_data,plugin:plugin,frame:frame,handleFaceDataJS:handleFaceDataJS}){const _e=[new global.Error(),-4,-27];const useLivenessCameraTs1=function(){const face=plugin.detectLiveness(frame);handleFaceDataJS(face,frame.width);};useLivenessCameraTs1.__closure={plugin:plugin,frame:frame,handleFaceDataJS:handleFaceDataJS};useLivenessCameraTs1.__workletHash=11184642299290;useLivenessCameraTs1.__pluginVersion=\"0.8.3\";useLivenessCameraTs1.__initData=_worklet_11184642299290_init_data;useLivenessCameraTs1.__stackDetails=_e;return useLivenessCameraTs1;}({_worklet_11184642299290_init_data:_worklet_11184642299290_init_data,plugin:plugin,frame:frame,handleFaceDataJS:handleFaceDataJS}));}",
19
16
  location: "/home/runner/work/react-native-liveness/react-native-liveness/src/useLivenessCamera.ts",
20
- sourceMap: "{\"version\":3,\"names\":[\"useLivenessCameraTs2\",\"frame\",\"runAtTargetFps\",\"_worklet_11184642299290_init_data\",\"plugin\",\"handleFaceDataJS\",\"__closure\",\"useLivenessCameraTs1Factory\",\"_e\",\"global\",\"Error\",\"useLivenessCameraTs1\",\"face\",\"detectLiveness\",\"width\",\"__workletHash\",\"__pluginVersion\",\"__initData\",\"__stackDetails\"],\"sources\":[\"/home/runner/work/react-native-liveness/react-native-liveness/src/useLivenessCamera.ts\"],\"mappings\":\"AAqNI,QAAC,CAAAA,oBAAiBA,CAAAC,KAAA,QAAAC,cAAA,CAAAC,iCAAA,CAAAC,MAAA,CAAAC,gBAAA,OAAAC,SAAA,CAIhBJ,cAAc,CAAC,EAAE,CAAE,SAAAK,4BAAA,CAAAJ,iCAAA,CAAAA,iCAAA,CAEJC,MAAM,CAANA,MAAM,CAAgBH,KAAK,CAALA,KAAK,CACxCI,gBAAA,CAAAA,gBAAgB,SAAAG,EAAA,MAAAC,MAAA,CAAAC,KAAA,iBAAAC,oBAAA,SAAAA,CAAA,CAHO,CAEvB,KAAM,CAAAC,IAAI,CAAGR,MAAM,CAACS,cAAc,CAACZ,KAAK,CAAC,CACzCI,gBAAgB,CAACO,IAAI,CAAEX,KAAK,CAACa,KAAK,CAAC,CACrC,CAAC,CAAAH,oBAAA,CAAAL,SAAA,EAFcF,MAAM,CAANA,MAAM,CAAgBH,KAAK,CAALA,KAAK,CACxCI,gBAAA,CAAAA,gBAAgB,EAAAM,oBAAA,CAAAI,aAAA,gBAAAJ,oBAAA,CAAAK,eAAA,SAAAL,oBAAA,CAAAM,UAAA,CAAAd,iCAAA,CAAAQ,oBAAA,CAAAO,cAAA,CAAAV,EAAA,QAAAG,oBAAA,EAHC,EAAAR,iCAAA,CAAAA,iCAAA,CAEJC,MAAM,CAANA,MAAM,CAAgBH,KAAK,CAALA,KAAK,CACxCI,gBAAA,CAAAA,gBAAgB,EACjB,CAAC,CACJ\",\"ignoreList\":[]}"
17
+ sourceMap: "{\"version\":3,\"names\":[\"useLivenessCameraTs2\",\"frame\",\"runAtTargetFps\",\"_worklet_11184642299290_init_data\",\"plugin\",\"handleFaceDataJS\",\"__closure\",\"useLivenessCameraTs1Factory\",\"_e\",\"global\",\"Error\",\"useLivenessCameraTs1\",\"face\",\"detectLiveness\",\"width\",\"__workletHash\",\"__pluginVersion\",\"__initData\",\"__stackDetails\"],\"sources\":[\"/home/runner/work/react-native-liveness/react-native-liveness/src/useLivenessCamera.ts\"],\"mappings\":\"AAgLI,QAAC,CAAAA,oBAAiBA,CAAAC,KAAA,QAAAC,cAAA,CAAAC,iCAAA,CAAAC,MAAA,CAAAC,gBAAA,OAAAC,SAAA,CAEhBJ,cAAc,CAAC,EAAE,CAAE,SAAAK,4BAAA,CAAAJ,iCAAA,CAAAA,iCAAA,CAEJC,MAAM,CAANA,MAAM,CAAgBH,KAAK,CAALA,KAAK,CACxCI,gBAAA,CAAAA,gBAAgB,SAAAG,EAAA,MAAAC,MAAA,CAAAC,KAAA,iBAAAC,oBAAA,SAAAA,CAAA,CAHO,CAEvB,KAAM,CAAAC,IAAI,CAAGR,MAAM,CAACS,cAAc,CAACZ,KAAK,CAAC,CACzCI,gBAAgB,CAACO,IAAI,CAAEX,KAAK,CAACa,KAAK,CAAC,CACrC,CAAC,CAAAH,oBAAA,CAAAL,SAAA,EAFcF,MAAM,CAANA,MAAM,CAAgBH,KAAK,CAALA,KAAK,CACxCI,gBAAA,CAAAA,gBAAgB,EAAAM,oBAAA,CAAAI,aAAA,gBAAAJ,oBAAA,CAAAK,eAAA,SAAAL,oBAAA,CAAAM,UAAA,CAAAd,iCAAA,CAAAQ,oBAAA,CAAAO,cAAA,CAAAV,EAAA,QAAAG,oBAAA,EAHC,EAAAR,iCAAA,CAAAA,iCAAA,CAEJC,MAAM,CAANA,MAAM,CAAgBH,KAAK,CAALA,KAAK,CACxCI,gBAAA,CAAAA,gBAAgB,EACjB,CAAC,CACJ\",\"ignoreList\":[]}"
21
18
  };
22
19
  export function useLivenessCamera(options) {
23
20
  const {
24
- livenessThreshold,
25
- confirmFrames,
26
21
  countdownFrom,
27
22
  soundEnabled,
28
23
  cameraRef,
@@ -32,24 +27,16 @@ export function useLivenessCamera(options) {
32
27
  } = options;
33
28
  const plugin = useLivenessPlugin();
34
29
 
35
- // Mutable refs — updated every frame, never cause re-renders
36
- const frameScores = useRef([]);
37
- const consecutiveGood = useRef(0);
38
- const frameWidth = useRef(0);
30
+ // ── Step machine refs — mutated every frame, never cause re-renders ────────
31
+ const currentStepIdx = useRef(0);
32
+ const stepFrameCount = useRef(0);
39
33
  const stateRef = useRef('scanning');
40
34
  const isCaptured = useRef(false);
41
-
42
- // Feedback debouncing: only update the displayed text after the same message
43
- // has been stable for FEEDBACK_DEBOUNCE_MS. Prevents rapid flickering when
44
- // ML Kit oscillates between two states on consecutive frames.
45
- const FEEDBACK_DEBOUNCE_MS = 400;
46
- const feedbackTimer = useRef(null);
47
- const pendingFeedback = useRef('Position your face in the circle');
48
35
  const [state, setState] = useState({
49
36
  livenessState: 'scanning',
50
37
  livenessScore: 0,
51
38
  countdown: null,
52
- feedback: 'Position your face in the circle'
39
+ feedback: CHALLENGE_STEPS[0].instruction
53
40
  });
54
41
  const setLivenessState = useCallback(next => {
55
42
  stateRef.current = next;
@@ -59,8 +46,7 @@ export function useLivenessCamera(options) {
59
46
  }));
60
47
  }, []);
61
48
 
62
- // ─── Capture ──────────────────────────────────────────────────────────────
63
-
49
+ // ── Capture ────────────────────────────────────────────────────────────────
64
50
  const capture = useCallback(async () => {
65
51
  if (isCaptured.current || !cameraRef.current) return;
66
52
  isCaptured.current = true;
@@ -70,11 +56,10 @@ export function useLivenessCamera(options) {
70
56
  flash: 'off',
71
57
  enableShutterSound: soundEnabled
72
58
  });
73
- const score = rollingAverage(frameScores.current);
74
59
  setLivenessState('done');
75
60
  onCapture({
76
61
  photo,
77
- livenessScore: score,
62
+ livenessScore: 1,
78
63
  timestamp: Date.now()
79
64
  });
80
65
  } catch (err) {
@@ -83,8 +68,7 @@ export function useLivenessCamera(options) {
83
68
  }
84
69
  }, [cameraRef, onCapture, onError, soundEnabled, setLivenessState]);
85
70
 
86
- // ─── Countdown ────────────────────────────────────────────────────────────
87
-
71
+ // ── Countdown ──────────────────────────────────────────────────────────────
88
72
  const startCountdown = useCallback(() => {
89
73
  setLivenessState('countdown');
90
74
  let tick = countdownFrom;
@@ -111,13 +95,10 @@ export function useLivenessCamera(options) {
111
95
  return () => clearInterval(interval);
112
96
  }, [capture, countdownFrom, setLivenessState]);
113
97
 
114
- // ─── Per-frame face handler (runs on JS thread, called from worklet) ──────
115
-
98
+ // ── Per-frame face handler (runs on JS thread, called from worklet) ────────
116
99
  const handleFaceData = useCallback((face, width) => {
117
- if (stateRef.current === 'capturing' || stateRef.current === 'done' || stateRef.current === 'error') {
118
- return;
119
- }
120
- frameWidth.current = width;
100
+ const s = stateRef.current;
101
+ if (s === 'confirmed' || s === 'countdown' || s === 'capturing' || s === 'done' || s === 'error') return;
121
102
  const safeFace = face ?? {
122
103
  detected: false,
123
104
  bounds: {
@@ -133,55 +114,51 @@ export function useLivenessCamera(options) {
133
114
  rightEyeOpenProbability: -1,
134
115
  smilingProbability: -1
135
116
  };
136
- const {
137
- total
138
- } = scoreFrame(safeFace, width);
139
- frameScores.current.push(total);
140
- if (frameScores.current.length > WINDOW_SIZE) {
141
- frameScores.current.shift();
142
- }
143
- const avgScore = rollingAverage(frameScores.current);
117
+ const step = CHALLENGE_STEPS[currentStepIdx.current];
118
+ const stepMet = step.check(safeFace, width);
144
119
 
145
- // Decay on bad frames instead of hard reset — one noisy ML Kit result
146
- // won't wipe out progress the user has already built up.
147
- if (total >= livenessThreshold) {
148
- consecutiveGood.current += 1;
120
+ // Advance or gently decay the frame counter
121
+ if (stepMet) {
122
+ stepFrameCount.current += 1;
149
123
  } else {
150
- consecutiveGood.current = Math.max(0, consecutiveGood.current - CONSECUTIVE_DECAY);
124
+ stepFrameCount.current = Math.max(0, stepFrameCount.current - 1);
151
125
  }
152
126
 
153
- // Consecutive-frames gate only. The avgScore is displayed on the arc but
154
- // not used as a confirmation gate — the rolling window starts empty so
155
- // early frames (before the face was positioned) drag the average down and
156
- // would prevent confirmation even when the face is clearly live.
157
- const isLive = consecutiveGood.current >= confirmFrames;
158
-
159
- // Debounce the feedback text: only apply a new message after it has been
160
- // stable for FEEDBACK_DEBOUNCE_MS, preventing rapid label flickering.
161
- const newFeedback = getFeedback(safeFace, width, isLive);
162
- if (newFeedback !== pendingFeedback.current) {
163
- pendingFeedback.current = newFeedback;
164
- if (feedbackTimer.current) clearTimeout(feedbackTimer.current);
165
- feedbackTimer.current = setTimeout(() => {
127
+ // Step complete?
128
+ if (stepFrameCount.current >= step.framesRequired) {
129
+ stepFrameCount.current = 0;
130
+ const nextIdx = currentStepIdx.current + 1;
131
+ if (nextIdx >= TOTAL_STEPS) {
132
+ // All challenges done — confirm liveness
166
133
  setState(prev => ({
167
134
  ...prev,
168
- feedback: pendingFeedback.current
135
+ livenessScore: 1,
136
+ feedback: 'Liveness confirmed'
169
137
  }));
170
- }, FEEDBACK_DEBOUNCE_MS);
138
+ setLivenessState('confirmed');
139
+ onLivenessConfirmed?.();
140
+ startCountdown();
141
+ } else {
142
+ // Advance to next challenge
143
+ currentStepIdx.current = nextIdx;
144
+ setState(prev => ({
145
+ ...prev,
146
+ livenessScore: nextIdx / TOTAL_STEPS,
147
+ feedback: CHALLENGE_STEPS[nextIdx].instruction
148
+ }));
149
+ }
150
+ return;
171
151
  }
152
+
153
+ // Smooth arc progress within the current step
154
+ const progress = (currentStepIdx.current + stepFrameCount.current / step.framesRequired) / TOTAL_STEPS;
172
155
  setState(prev => ({
173
156
  ...prev,
174
- livenessScore: avgScore
157
+ livenessScore: progress
175
158
  }));
176
- if (isLive && stateRef.current === 'scanning') {
177
- setLivenessState('confirmed');
178
- onLivenessConfirmed?.();
179
- startCountdown();
180
- }
181
- }, [confirmFrames, livenessThreshold, onLivenessConfirmed, setLivenessState, startCountdown]);
182
-
183
- // ─── Frame processor ──────────────────────────────────────────────────────
159
+ }, [onLivenessConfirmed, setLivenessState, startCountdown]);
184
160
 
161
+ // ── Frame processor ────────────────────────────────────────────────────────
185
162
  const handleFaceDataJS = useMemo(() => Worklets.createRunOnJS(handleFaceData), [handleFaceData]);
186
163
  const frameProcessor = useFrameProcessor(function useLivenessCameraTs2Factory({
187
164
  _worklet_14471027507603_init_data,
@@ -192,8 +169,6 @@ export function useLivenessCamera(options) {
192
169
  }) {
193
170
  const _e = [new global.Error(), -5, -27];
194
171
  const useLivenessCameraTs2 = function (frame) {
195
- // Camera preview renders at full fps (60). ML Kit only needs ~20fps —
196
- // running it on every frame would block the render thread unnecessarily.
197
172
  runAtTargetFps(20, function useLivenessCameraTs1Factory({
198
173
  _worklet_11184642299290_init_data,
199
174
  plugin,
@@ -242,10 +217,9 @@ export function useLivenessCamera(options) {
242
217
  }), [plugin, handleFaceDataJS]);
243
218
  useEffect(() => {
244
219
  return () => {
245
- frameScores.current = [];
246
- consecutiveGood.current = 0;
220
+ currentStepIdx.current = 0;
221
+ stepFrameCount.current = 0;
247
222
  isCaptured.current = false;
248
- if (feedbackTimer.current) clearTimeout(feedbackTimer.current);
249
223
  };
250
224
  }, []);
251
225
  return {
@@ -1 +1 @@
1
- {"version":3,"names":["useCallback","useEffect","useMemo","useRef","useState","runAtTargetFps","useFrameProcessor","Worklets","useLivenessPlugin","getFeedback","rollingAverage","scoreFrame","WINDOW_SIZE","CONSECUTIVE_DECAY","_worklet_11184642299290_init_data","code","location","sourceMap","_worklet_14471027507603_init_data","useLivenessCamera","options","livenessThreshold","confirmFrames","countdownFrom","soundEnabled","cameraRef","onCapture","onLivenessConfirmed","onError","plugin","frameScores","consecutiveGood","frameWidth","stateRef","isCaptured","FEEDBACK_DEBOUNCE_MS","feedbackTimer","pendingFeedback","state","setState","livenessState","livenessScore","countdown","feedback","setLivenessState","next","current","prev","capture","photo","takePhoto","flash","enableShutterSound","score","timestamp","Date","now","err","Error","String","startCountdown","tick","interval","setInterval","clearInterval","handleFaceData","face","width","safeFace","detected","bounds","x","y","height","yawAngle","pitchAngle","rollAngle","leftEyeOpenProbability","rightEyeOpenProbability","smilingProbability","total","push","length","shift","avgScore","Math","max","isLive","newFeedback","clearTimeout","setTimeout","handleFaceDataJS","createRunOnJS","frameProcessor","useLivenessCameraTs2Factory","_e","global","useLivenessCameraTs2","frame","useLivenessCameraTs1Factory","useLivenessCameraTs1","detectLiveness","__closure","__workletHash","__pluginVersion","__initData","__stackDetails"],"sourceRoot":"../../src","sources":["useLivenessCamera.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["useCallback","useEffect","useMemo","useRef","useState","runAtTargetFps","useFrameProcessor","Worklets","useLivenessPlugin","CHALLENGE_STEPS","TOTAL_STEPS","length","_worklet_11184642299290_init_data","code","location","sourceMap","_worklet_14471027507603_init_data","useLivenessCamera","options","countdownFrom","soundEnabled","cameraRef","onCapture","onLivenessConfirmed","onError","plugin","currentStepIdx","stepFrameCount","stateRef","isCaptured","state","setState","livenessState","livenessScore","countdown","feedback","instruction","setLivenessState","next","current","prev","capture","photo","takePhoto","flash","enableShutterSound","timestamp","Date","now","err","Error","String","startCountdown","tick","interval","setInterval","clearInterval","handleFaceData","face","width","s","safeFace","detected","bounds","x","y","height","yawAngle","pitchAngle","rollAngle","leftEyeOpenProbability","rightEyeOpenProbability","smilingProbability","step","stepMet","check","Math","max","framesRequired","nextIdx","progress","handleFaceDataJS","createRunOnJS","frameProcessor","useLivenessCameraTs2Factory","_e","global","useLivenessCameraTs2","frame","useLivenessCameraTs1Factory","useLivenessCameraTs1","detectLiveness","__closure","__workletHash","__pluginVersion","__initData","__stackDetails"],"sourceRoot":"../../src","sources":["useLivenessCamera.ts"],"mappings":"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","ignoreList":[]}
@@ -1,3 +1,3 @@
1
1
  import type { LivenessCameraProps } from './types';
2
- export declare function LivenessCamera({ onCapture, onLivenessConfirmed, onError, countdownFrom, livenessThreshold, confirmFrames, soundEnabled, fontFamily, style, }: LivenessCameraProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function LivenessCamera({ onCapture, onLivenessConfirmed, onError, countdownFrom, soundEnabled, fontFamily, style, }: LivenessCameraProps): import("react/jsx-runtime").JSX.Element;
3
3
  //# sourceMappingURL=LivenessCamera.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LivenessCamera.d.ts","sourceRoot":"","sources":["../../../src/LivenessCamera.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,mBAAmB,EAAiB,MAAM,SAAS,CAAC;AA8SlE,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,mBAAmB,EACnB,OAAO,EACP,aAAiB,EACjB,iBAAwB,EACxB,aAAiB,EACjB,YAAmB,EACnB,UAAyB,EACzB,KAAK,GACN,EAAE,mBAAmB,2CA+FrB"}
1
+ {"version":3,"file":"LivenessCamera.d.ts","sourceRoot":"","sources":["../../../src/LivenessCamera.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,mBAAmB,EAAiB,MAAM,SAAS,CAAC;AAySlE,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,mBAAmB,EACnB,OAAO,EACP,aAAiB,EACjB,YAAmB,EACnB,UAAyB,EACzB,KAAK,GACN,EAAE,mBAAmB,2CA4FrB"}
@@ -11,5 +11,5 @@ import type { LivenessCameraModalProps } from './types';
11
11
  * />
12
12
  * ```
13
13
  */
14
- export declare function LivenessCameraModal({ visible, onClose, animationType, closeButtonStyle, closeButtonIconColor, closeButtonIconSize, onCapture, onLivenessConfirmed, onError, countdownFrom, livenessThreshold, confirmFrames, soundEnabled, fontFamily, }: LivenessCameraModalProps): import("react/jsx-runtime").JSX.Element;
14
+ export declare function LivenessCameraModal({ visible, onClose, animationType, closeButtonStyle, closeButtonIconColor, closeButtonIconSize, onCapture, onLivenessConfirmed, onError, countdownFrom, soundEnabled, fontFamily, }: LivenessCameraModalProps): import("react/jsx-runtime").JSX.Element;
15
15
  //# sourceMappingURL=LivenessCameraModal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LivenessCameraModal.d.ts","sourceRoot":"","sources":["../../../src/LivenessCameraModal.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAwBxD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,OAAO,EACP,aAAuB,EACvB,gBAAgB,EAChB,oBAA6B,EAC7B,mBAAwB,EAExB,SAAS,EACT,mBAAmB,EACnB,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,UAAU,GACX,EAAE,wBAAwB,2CAqC1B"}
1
+ {"version":3,"file":"LivenessCameraModal.d.ts","sourceRoot":"","sources":["../../../src/LivenessCameraModal.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAwBxD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,OAAO,EACP,aAAuB,EACvB,gBAAgB,EAChB,oBAA6B,EAC7B,mBAAwB,EAExB,SAAS,EACT,mBAAmB,EACnB,OAAO,EACP,aAAa,EACb,YAAY,EACZ,UAAU,GACX,EAAE,wBAAwB,2CAmC1B"}
@@ -1,11 +1,16 @@
1
1
  import type { FaceData, FeedbackMessage } from './types';
2
- export type FrameScore = {
3
- total: number;
4
- faceSize: number;
5
- headPose: number;
6
- eyesOpen: number;
2
+ export type ChallengeStep = {
3
+ /** Text shown to the user while this step is active. */
4
+ instruction: FeedbackMessage;
5
+ /** How many consecutive ML Kit frames must pass the check to complete the step. */
6
+ framesRequired: number;
7
+ /** Returns true when the face satisfies this step's condition. */
8
+ check: (face: FaceData, frameWidth: number) => boolean;
7
9
  };
8
- export declare function scoreFrame(face: FaceData, frameWidth: number): FrameScore;
9
- export declare function rollingAverage(scores: number[]): number;
10
- export declare function getFeedback(face: FaceData, frameWidth: number, livenessConfirmed: boolean): FeedbackMessage;
10
+ /**
11
+ * Sequential liveness challenges.
12
+ * Each step completes when `framesRequired` consecutive frames pass `check`.
13
+ * The progress arc fills 1/N per step, then turns green at the end.
14
+ */
15
+ export declare const CHALLENGE_STEPS: readonly ChallengeStep[];
11
16
  //# sourceMappingURL=livenessScoring.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"livenessScoring.d.ts","sourceRoot":"","sources":["../../../src/livenessScoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAkBzD,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,CAsDzE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAGvD;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,QAAQ,EACd,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,OAAO,GACzB,eAAe,CAmBjB"}
1
+ {"version":3,"file":"livenessScoring.d.ts","sourceRoot":"","sources":["../../../src/livenessScoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAOzD,MAAM,MAAM,aAAa,GAAG;IAC1B,wDAAwD;IACxD,WAAW,EAAE,eAAe,CAAC;IAC7B,mFAAmF;IACnF,cAAc,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,KAAK,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;CACxD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAuC1C,CAAC"}
@@ -16,9 +16,10 @@ export type FaceData = {
16
16
  smilingProbability: number;
17
17
  };
18
18
  export type LivenessState = 'idle' | 'scanning' | 'confirmed' | 'countdown' | 'capturing' | 'done' | 'error';
19
- export type FeedbackMessage = 'Position your face in the circle' | 'Move closer' | 'Move farther away' | 'Look straight ahead' | 'Hold still...' | 'Stay still' | 'Open your eyes' | 'Liveness confirmed' | '';
19
+ export type FeedbackMessage = 'Position your face in the circle' | 'Turn your head slightly' | 'Now look straight ahead' | 'Now blink' | 'Liveness confirmed' | '';
20
20
  export type CaptureResult = {
21
21
  photo: PhotoFile;
22
+ /** Always 1.0 — all challenges were passed before capture. */
22
23
  livenessScore: number;
23
24
  timestamp: number;
24
25
  };
@@ -39,15 +40,6 @@ export type LivenessCameraProps = {
39
40
  * Countdown start value. Defaults to 3.
40
41
  */
41
42
  countdownFrom?: number;
42
- /**
43
- * Score (0–1) required to confirm liveness. Defaults to 0.75.
44
- */
45
- livenessThreshold?: number;
46
- /**
47
- * Number of consecutive high-score frames required before liveness is
48
- * confirmed. Defaults to 10 (~500ms at 20fps).
49
- */
50
- confirmFrames?: number;
51
43
  /**
52
44
  * Style applied to the root container.
53
45
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QACN,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,uBAAuB,EAAE,MAAM,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,UAAU,GACV,WAAW,GACX,WAAW,GACX,WAAW,GACX,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,MAAM,eAAe,GACvB,kCAAkC,GAClC,aAAa,GACb,mBAAmB,GACnB,qBAAqB,GACrB,eAAe,GACf,YAAY,GACZ,gBAAgB,GAChB,oBAAoB,GACpB,EAAE,CAAC;AAEP,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC;;OAEG;IACH,SAAS,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAE3C;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IAEjC;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,GAAG;IAC1E;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC,eAAe,CAAC,CAAC;IAE5C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAE7B;;OAEG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QACN,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,uBAAuB,EAAE,MAAM,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,UAAU,GACV,WAAW,GACX,WAAW,GACX,WAAW,GACX,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,MAAM,eAAe,GACvB,kCAAkC,GAClC,yBAAyB,GACzB,yBAAyB,GACzB,WAAW,GACX,oBAAoB,GACpB,EAAE,CAAC;AAEP,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC;;OAEG;IACH,SAAS,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAE3C;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IAEjC;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,GAAG;IAC1E;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC,eAAe,CAAC,CAAC;IAE5C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAE7B;;OAEG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC"}
@@ -1,8 +1,6 @@
1
1
  import type { Camera } from 'react-native-vision-camera';
2
2
  import type { CaptureResult, FeedbackMessage, LivenessState } from './types';
3
3
  type Options = {
4
- livenessThreshold: number;
5
- confirmFrames: number;
6
4
  countdownFrom: number;
7
5
  soundEnabled: boolean;
8
6
  cameraRef: React.RefObject<Camera | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"useLivenessCamera.d.ts","sourceRoot":"","sources":["../../../src/useLivenessCamera.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAS,MAAM,4BAA4B,CAAC;AAKhE,OAAO,KAAK,EACV,aAAa,EAEb,eAAe,EACf,aAAa,EACd,MAAM,SAAS,CAAC;AAOjB,KAAK,OAAO,GAAG;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,SAAS,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,CAAC;AASF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO;;;;;;EA8MjD"}
1
+ {"version":3,"file":"useLivenessCamera.d.ts","sourceRoot":"","sources":["../../../src/useLivenessCamera.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAS,MAAM,4BAA4B,CAAC;AAKhE,OAAO,KAAK,EACV,aAAa,EAEb,eAAe,EACf,aAAa,EACd,MAAM,SAAS,CAAC;AAIjB,KAAK,OAAO,GAAG;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,SAAS,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,CAAC;AAUF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO;;;;;;EA0KjD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rick427/react-native-liveness",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "description": "Liveness detection library for React Native using Vision Camera v4 and ML Kit",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -47,9 +47,9 @@ const BRACKET_STROKE = STROKE_WIDTH + 1;
47
47
 
48
48
  // ─── Colour helper ────────────────────────────────────────────────────────────
49
49
  /**
50
- * ● White – no face / scanning (score < 0.4)
51
- * ● Yellow – face detected, confidence building
52
- * ● Green – liveness confirmed / countdown / capture
50
+ * ● White – no face yet (arc at 0)
51
+ * ● Yellow – challenge in progress (arc filling)
52
+ * ● Green – all challenges passed (confirmed / countdown / capture)
53
53
  * ● Red – error
54
54
  */
55
55
  function getCircleColor(state: LivenessState, score: number): string {
@@ -62,7 +62,7 @@ function getCircleColor(state: LivenessState, score: number): string {
62
62
  case 'done':
63
63
  return '#4CAF50';
64
64
  default:
65
- return score >= 0.4 ? '#FFD60A' : '#FFFFFF';
65
+ return score > 0.02 ? '#FFD60A' : '#FFFFFF';
66
66
  }
67
67
  }
68
68
 
@@ -103,13 +103,11 @@ function CircleOverlay({
103
103
  height,
104
104
  state,
105
105
  score,
106
- livenessThreshold,
107
106
  }: {
108
107
  width: number;
109
108
  height: number;
110
109
  state: LivenessState;
111
110
  score: number;
112
- livenessThreshold: number;
113
111
  }) {
114
112
  // ── Shared values — all hooks before any early return ─────────────────────
115
113
  // scanProgress 0=top 1=bottom, ping-pongs continuously
@@ -147,13 +145,12 @@ function CircleOverlay({
147
145
  [cx, cy]
148
146
  );
149
147
 
148
+ // score is already 0–1 challenge progress — arc fills directly
150
149
  const progressAnimProps = useAnimatedProps(
151
150
  () => ({
152
- strokeDashoffset:
153
- circumference -
154
- (livenessProgress.value / livenessThreshold) * circumference,
151
+ strokeDashoffset: circumference * (1 - livenessProgress.value),
155
152
  }),
156
- [circumference, livenessThreshold]
153
+ [circumference]
157
154
  );
158
155
 
159
156
  // ── Start scan line + bracket rotation on mount ───────────────────────────
@@ -186,12 +183,10 @@ function CircleOverlay({
186
183
  }
187
184
  }, [state]); // eslint-disable-line react-hooks/exhaustive-deps
188
185
 
189
- // ── Drive progress arc from live score ────────────────────────────────────
186
+ // ── Drive progress arc from challenge progress (0–1) ─────────────────────
190
187
  useEffect(() => {
191
- livenessProgress.value = withTiming(Math.min(score, livenessThreshold), {
192
- duration: 180,
193
- });
194
- }, [score, livenessThreshold]); // eslint-disable-line react-hooks/exhaustive-deps
188
+ livenessProgress.value = withTiming(score, { duration: 220 });
189
+ }, [score]); // eslint-disable-line react-hooks/exhaustive-deps
195
190
 
196
191
  // ── Guard — render nothing until dimensions are known ─────────────────────
197
192
  if (width === 0 || height === 0) return null;
@@ -334,8 +329,6 @@ export function LivenessCamera({
334
329
  onLivenessConfirmed,
335
330
  onError,
336
331
  countdownFrom = 3,
337
- livenessThreshold = 0.65,
338
- confirmFrames = 7,
339
332
  soundEnabled = true,
340
333
  fontFamily = DEFAULT_FONT,
341
334
  style,
@@ -349,8 +342,6 @@ export function LivenessCamera({
349
342
 
350
343
  const { frameProcessor, livenessState, livenessScore, countdown, feedback } =
351
344
  useLivenessCamera({
352
- livenessThreshold,
353
- confirmFrames,
354
345
  countdownFrom,
355
346
  soundEnabled,
356
347
  cameraRef,
@@ -413,7 +404,6 @@ export function LivenessCamera({
413
404
  height={containerSize.height}
414
405
  state={livenessState}
415
406
  score={livenessScore}
416
- livenessThreshold={livenessThreshold}
417
407
  />
418
408
  {livenessState !== 'done' && (
419
409
  <View style={styles.feedbackContainer}>
@@ -49,8 +49,6 @@ export function LivenessCameraModal({
49
49
  onLivenessConfirmed,
50
50
  onError,
51
51
  countdownFrom,
52
- livenessThreshold,
53
- confirmFrames,
54
52
  soundEnabled,
55
53
  fontFamily,
56
54
  }: LivenessCameraModalProps) {
@@ -73,8 +71,6 @@ export function LivenessCameraModal({
73
71
  onLivenessConfirmed={onLivenessConfirmed}
74
72
  onError={onError}
75
73
  countdownFrom={countdownFrom}
76
- livenessThreshold={livenessThreshold}
77
- confirmFrames={confirmFrames}
78
74
  soundEnabled={soundEnabled}
79
75
  fontFamily={fontFamily}
80
76
  />