@rick427/react-native-liveness 0.1.9 → 0.2.1

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
@@ -16,10 +16,13 @@ The library scores each camera frame against a set of liveness signals (face siz
16
16
 
17
17
  - Real-time passive liveness detection (no gestures required)
18
18
  - On-device ML — works fully offline (ML Kit)
19
- - Face guide oval with live feedback hints
20
- - Animated countdown (React Native built-in `Animated`)
19
+ - Circle guide with animated scanner — sweeping scan line, rotating corner brackets, confidence progress arc
20
+ - Score-driven border colour: white yellow → green
21
+ - Built-in modal via `LivenessCameraModal` — one import, zero wiring
22
+ - Configurable animation type, close button style, and font
21
23
  - Auto photo capture via Vision Camera's `takePhoto()`
22
- - Optional shutter sound
24
+ - 60 fps preview, ML Kit capped at 20 fps via `runAtTargetFps`
25
+ - Optional shutter sound (respects silent mode)
23
26
  - Fully typed TypeScript API
24
27
 
25
28
  ---
@@ -41,29 +44,30 @@ Install these if you don't already have them:
41
44
  | `react-native-vision-camera` | `>= 4.0.0` |
42
45
  | `react-native-svg` | `>= 13.0.0` |
43
46
  | `react-native-worklets-core` | `>= 1.0.0` |
47
+ | `react-native-reanimated` | `>= 4.0.0` |
44
48
 
45
49
  ```sh
46
- npm install react-native-vision-camera react-native-svg react-native-worklets-core
50
+ npm install react-native-vision-camera react-native-svg react-native-worklets-core react-native-reanimated
47
51
  ```
48
52
 
49
53
  ### Configure worklets Babel plugin
50
54
 
51
- The library uses Vision Camera frame processors which run in a worklet context. Add the appropriate plugin to your `babel.config.js` depending on which package you have installed:
55
+ The library uses Vision Camera frame processors which run in a worklet context. Add the appropriate plugin to your `babel.config.js`:
52
56
 
53
57
  ```js
54
58
  // babel.config.js
55
59
  module.exports = {
56
60
  presets: ['module:@react-native/babel-preset'], // or 'babel-preset-expo'
57
61
  plugins: [
58
- ['react-native-worklets-core/plugin'], // if using react-native-worklets-core
59
- // ['react-native-worklets/plugin'], // if using react-native-worklets
62
+ 'react-native-worklets-core/plugin', // frame processor worklets
63
+ 'react-native-reanimated/plugin', // SVG animations (must come last)
60
64
  ],
61
65
  };
62
66
  ```
63
67
 
64
- > **Already have worklets configured?** Just confirm the relevant plugin line is present — no further changes needed.
68
+ > **Already have both plugins?** Just confirm both lines are present — order matters, Reanimated must come after worklets-core.
65
69
 
66
- After updating the Babel config, clear the Metro cache:
70
+ After updating Babel config, clear the Metro cache:
67
71
 
68
72
  ```sh
69
73
  npx react-native start --reset-cache
@@ -86,22 +90,84 @@ Add `NSCameraUsageDescription` to your `Info.plist`:
86
90
 
87
91
  ### Android
88
92
 
89
- The ML Kit dependency is included in `build.gradle` automatically. No extra steps needed.
93
+ ML Kit and all native dependencies are included automatically via `build.gradle`. No extra steps needed.
90
94
 
91
95
  ---
92
96
 
93
97
  ## Usage
94
98
 
95
- ### Drop-in component
99
+ There are two ways to use the library depending on how much control you need.
100
+
101
+ ---
102
+
103
+ ### Option 1 — `LivenessCameraModal` (recommended)
104
+
105
+ The easiest integration. Pass `visible` / `onClose` and you're done — the modal, close button, and full-screen layout are all handled for you.
96
106
 
97
107
  ```tsx
98
- import { LivenessCamera } from '@rick427/react-native-liveness';
108
+ import { useState } from 'react';
109
+ import { LivenessCameraModal } from '@rick427/react-native-liveness';
99
110
  import type { CaptureResult } from '@rick427/react-native-liveness';
100
111
 
101
112
  export default function VerificationScreen() {
113
+ const [showLiveness, setShowLiveness] = useState(false);
114
+
102
115
  const handleCapture = (result: CaptureResult) => {
103
116
  console.log('Photo path:', result.photo.path);
104
117
  console.log('Liveness score:', result.livenessScore); // 0.0 – 1.0
118
+ setShowLiveness(false);
119
+ };
120
+
121
+ return (
122
+ <>
123
+ {/* Trigger however you like */}
124
+ <Button title="Verify Identity" onPress={() => setShowLiveness(true)} />
125
+
126
+ <LivenessCameraModal
127
+ visible={showLiveness}
128
+ onClose={() => setShowLiveness(false)}
129
+ onCapture={handleCapture}
130
+ onLivenessConfirmed={() => console.log('Live face confirmed!')}
131
+ onError={(err) => console.error(err)}
132
+ />
133
+ </>
134
+ );
135
+ }
136
+ ```
137
+
138
+ #### `LivenessCameraModal` props
139
+
140
+ | Prop | Type | Default | Description |
141
+ |---|---|---|---|
142
+ | `visible` | `boolean` | **required** | Controls modal visibility. |
143
+ | `onClose` | `() => void` | **required** | Called when the × button is pressed or Android back is fired. |
144
+ | `onCapture` | `(result: CaptureResult) => void` | **required** | Fired after photo is captured. |
145
+ | `animationType` | `'slide' \| 'fade' \| 'none'` | `'slide'` | Modal entrance/exit animation. |
146
+ | `closeButtonStyle` | `ViewStyle` | — | Override the close button container style (position, size, colours). |
147
+ | `closeButtonIconColor` | `string` | `'#fff'` | Colour of the × icon. |
148
+ | `closeButtonIconSize` | `number` | `18` | Size of the × icon in dp. |
149
+ | `onLivenessConfirmed` | `() => void` | — | Fired the moment liveness is confirmed, before countdown. |
150
+ | `onError` | `(err: Error) => void` | — | Fired on unrecoverable errors. |
151
+ | `countdownFrom` | `number` | `3` | Countdown start value. |
152
+ | `livenessThreshold` | `number` | `0.75` | Score (0–1) required to confirm liveness. |
153
+ | `confirmFrames` | `number` | `10` | Consecutive high-score frames required (~500 ms at 20 fps). |
154
+ | `soundEnabled` | `boolean` | `true` | Play native shutter sound on capture. |
155
+ | `fontFamily` | `string` | `'Baloo-Medium'` | Font applied to all text inside the component. |
156
+
157
+ ---
158
+
159
+ ### Option 2 — `LivenessCamera` (embedded)
160
+
161
+ Use this when you want full layout control — embed the camera directly inside your own screen or custom modal.
162
+
163
+ ```tsx
164
+ import { LivenessCamera } from '@rick427/react-native-liveness';
165
+ import type { CaptureResult } from '@rick427/react-native-liveness';
166
+
167
+ export default function VerificationScreen() {
168
+ const handleCapture = (result: CaptureResult) => {
169
+ console.log('Photo path:', result.photo.path);
170
+ console.log('Liveness score:', result.livenessScore);
105
171
  };
106
172
 
107
173
  return (
@@ -115,20 +181,23 @@ export default function VerificationScreen() {
115
181
  }
116
182
  ```
117
183
 
118
- ### Props
184
+ #### `LivenessCamera` props
119
185
 
120
186
  | Prop | Type | Default | Description |
121
187
  |---|---|---|---|
122
- | `onCapture` | `(result: CaptureResult) => void` | **required** | Fired after photo is taken. |
123
- | `onLivenessConfirmed` | `() => void` | — | Fired the moment liveness is confirmed, before the countdown. |
188
+ | `onCapture` | `(result: CaptureResult) => void` | **required** | Fired after photo is captured. |
189
+ | `onLivenessConfirmed` | `() => void` | — | Fired the moment liveness is confirmed, before countdown. |
124
190
  | `onError` | `(err: Error) => void` | — | Fired on unrecoverable errors. |
125
191
  | `countdownFrom` | `number` | `3` | Countdown start value. |
126
- | `livenessThreshold` | `number` | `0.75` | Score (0–1) required per frame to be considered live. |
127
- | `confirmFrames` | `number` | `15` | Consecutive high-score frames required (~500 ms at 30 fps). |
128
- | `soundEnabled` | `boolean` | `true` | Play the native system shutter sound on capture. Respects silent mode. |
192
+ | `livenessThreshold` | `number` | `0.75` | Score (0–1) required to confirm liveness. |
193
+ | `confirmFrames` | `number` | `10` | Consecutive high-score frames required (~500 ms at 20 fps). |
194
+ | `soundEnabled` | `boolean` | `true` | Play native shutter sound on capture. |
195
+ | `fontFamily` | `string` | `'Baloo-Medium'` | Font applied to all text inside the component. |
129
196
  | `style` | `ViewStyle` | — | Style for the root container. |
130
197
 
131
- ### CaptureResult
198
+ ---
199
+
200
+ ### `CaptureResult`
132
201
 
133
202
  ```ts
134
203
  type CaptureResult = {
@@ -140,34 +209,48 @@ type CaptureResult = {
140
209
 
141
210
  ---
142
211
 
212
+ ## Scanner animation
213
+
214
+ The circle guide layers three animations built entirely with `Animated` + `react-native-svg` — no extra dependencies.
215
+
216
+ | Layer | Behaviour |
217
+ |---|---|
218
+ | **Dim base ring** | Always visible; gives a positioning target before any progress starts. |
219
+ | **Sweep scan line** | A gradient bar ping-pongs top → bottom inside the circle (1.8 s/leg). Fades out on confirm. |
220
+ | **Rotating brackets** | Four corner arcs rotate slowly (1 rev / 6 s), suggesting the circle boundary during scanning. Freeze in place on confirm. |
221
+ | **Progress arc** | The circle border draws itself in clockwise from 12 o'clock as `livenessScore / livenessThreshold` builds. White → yellow → green. |
222
+
223
+ ---
224
+
143
225
  ## How liveness scoring works
144
226
 
145
- Each camera frame is scored across four signals:
227
+ Each camera frame is scored across four signals at up to **20 fps** (ML Kit is throttled via `runAtTargetFps` while the preview renders at 60 fps):
146
228
 
147
229
  | Signal | Weight | Detail |
148
230
  |---|---|---|
149
- | Face detected | 20% | ML Kit found a face in the frame |
150
- | Face size | 20% | Face width is 20%–65% of the frame (not too far, not too close) |
151
- | Head pose | 30% | Yaw < ±20° and pitch < ±20° from frontal |
152
- | Eyes open | 30% | Average of left/right eye open probability from ML Kit |
231
+ | Face detected | 20% | ML Kit found a face in the frame. |
232
+ | Face size | 20% | Face width is 15–80% of the frame. Soft-edge scoring at boundaries. |
233
+ | Head pose | 30% | Yaw < ±25° and pitch < ±25° from frontal. Soft decay outside range. |
234
+ | Eyes open | 30% | Average of left/right eye open probability from ML Kit. |
153
235
 
154
- A rolling window of the last 20 frame scores is maintained. Liveness is confirmed once `confirmFrames` consecutive frames all score above `livenessThreshold`.
236
+ A rolling window of the last 20 frame scores is maintained. Liveness is confirmed once `confirmFrames` consecutive frames all score above `livenessThreshold`. Bad frames **decay** the streak by 2 instead of resetting it, making detection resilient to momentary noise.
155
237
 
156
238
  ---
157
239
 
158
240
  ## Architecture
159
241
 
160
242
  ```
161
- Camera frame (30fps)
243
+ Camera (60 fps preview)
162
244
  ↓ [worklet thread — Vision Camera frame processor]
163
- Native plugin (Swift / Kotlin)
164
- → ML Kit Face Detection
165
- → { bounds, yawAngle, pitchAngle, leftEyeOpenProbability, … }
166
- ↓ [runOnJS → JS thread]
245
+ runAtTargetFps(20) → Native plugin (Swift / Kotlin)
246
+ → ML Kit Face Detection
247
+ → { bounds, yawAngle, pitchAngle, leftEyeOpenProbability, … }
248
+ ↓ [Worklets.createRunOnJS → JS thread, ~20×/sec]
167
249
  useLivenessCamera hook
168
- → scoreFrame() per frame
250
+ → scoreFrame() soft-edge signals, weighted sum
169
251
  → rolling 20-frame window
170
- 15 consecutive frames > threshold liveness confirmed
252
+ consecutiveGood++ on pass, decay -2 on fail
253
+ → 10 consecutive frames > threshold → liveness confirmed
171
254
 
172
255
  Countdown 3 → 2 → 1 (React Native Animated)
173
256
 
@@ -1,25 +1,32 @@
1
1
  "use strict";
2
2
 
3
3
  import { useCallback, useEffect, useRef, useState } from 'react';
4
- import { Animated, StyleSheet, Text, View } from 'react-native';
4
+ import { Animated as RNAnimated, StyleSheet, Text, View } from 'react-native';
5
+ import Animated, { cancelAnimation, Easing, useAnimatedProps, useSharedValue, withRepeat, withSequence, withTiming } from 'react-native-reanimated';
5
6
  import { Camera, useCameraDevice, useCameraFormat, useCameraPermission } from 'react-native-vision-camera';
6
- import { Circle, Path, Svg } from 'react-native-svg';
7
+ import { Circle, ClipPath, Defs, G, LinearGradient, Path, Rect, Stop, Svg } from 'react-native-svg';
7
8
  import { useLivenessCamera } from "./useLivenessCamera.js";
8
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
- const DEFAULT_FONT = 'Baloo-Medium';
10
+ // ─── Animated SVG components (Reanimated) ────────────────────────────────────
11
+ // createAnimatedComponent from react-native-reanimated properly drives SVG
12
+ // presentation attributes (strokeDashoffset, y, rotation) on the UI thread.
13
+ const AnimatedCircle = Animated.createAnimatedComponent(Circle);
14
+ const AnimatedG = Animated.createAnimatedComponent(G);
15
+ const AnimatedRect = Animated.createAnimatedComponent(Rect);
10
16
 
11
- // Circle diameter = 82 % of container width — large enough to fit any face
12
- // comfortably without the user needing to fiddle with distance.
17
+ // ─── Constants ────────────────────────────────────────────────────────────────
18
+ const DEFAULT_FONT = 'Baloo-Medium';
13
19
  const CIRCLE_DIAMETER_RATIO = 0.82;
14
20
  const STROKE_WIDTH = 3;
15
- // Cubic bezier approximation constant for a smooth circle path
16
- const K = 0.5523;
21
+ const K = 0.5523; // cubic bezier ellipse approximation
22
+ const SCAN_LINE_HEIGHT = 44; // px — height of the sweep bar
23
+ const BRACKET_SPAN_DEG = 44; // degrees each corner bracket spans
24
+ const BRACKET_STROKE = STROKE_WIDTH + 1;
17
25
 
26
+ // ─── Colour helper ────────────────────────────────────────────────────────────
18
27
  /**
19
- * Returns the stroke colour for the circle guide.
20
- *
21
28
  * ● White – no face / scanning (score < 0.4)
22
- * ● Yellow – face detected, confidence building (0.4 ≤ score < threshold)
29
+ * ● Yellow – face detected, confidence building
23
30
  * ● Green – liveness confirmed / countdown / capture
24
31
  * ● Red – error
25
32
  */
@@ -37,68 +44,305 @@ function getCircleColor(state, score) {
37
44
  }
38
45
  }
39
46
 
40
- /**
41
- * Returns an SVG path string tracing a circle at (cx, cy) with radius r
42
- * using cubic bezier curves. Used inside a compound path with
43
- * fillRule="evenodd" to punch a transparent hole through the dark scrim.
44
- */
47
+ // ─── SVG path helpers ─────────────────────────────────────────────────────────
48
+ /** Cubic bezier circle path used inside compound evenodd scrim. */
45
49
  function circlePath(cx, cy, r) {
46
50
  return [`M ${cx + r} ${cy}`, `C ${cx + r} ${cy - r * K} ${cx + r * K} ${cy - r} ${cx} ${cy - r}`, `C ${cx - r * K} ${cy - r} ${cx - r} ${cy - r * K} ${cx - r} ${cy}`, `C ${cx - r} ${cy + r * K} ${cx - r * K} ${cy + r} ${cx} ${cy + r}`, `C ${cx + r * K} ${cy + r} ${cx + r} ${cy + r * K} ${cx + r} ${cy}`, 'Z'].join(' ');
47
51
  }
52
+
53
+ /** One corner bracket arc centred at `centerDeg`, spanning `spanDeg`. */
54
+ function bracketArcPath(cx, cy, r, centerDeg, spanDeg) {
55
+ const toRad = d => d * Math.PI / 180;
56
+ const a1 = toRad(centerDeg - spanDeg / 2);
57
+ const a2 = toRad(centerDeg + spanDeg / 2);
58
+ const x1 = cx + r * Math.cos(a1);
59
+ const y1 = cy + r * Math.sin(a1);
60
+ const x2 = cx + r * Math.cos(a2);
61
+ const y2 = cy + r * Math.sin(a2);
62
+ return `M ${x1} ${y1} A ${r} ${r} 0 0 1 ${x2} ${y2}`;
63
+ }
64
+
65
+ // ─── CircleOverlay ────────────────────────────────────────────────────────────
66
+ const _worklet_15111972513221_init_data = {
67
+ code: "function LivenessCameraTsx1(){const{cy,r,scanProgress,SCAN_LINE_HEIGHT,scanOpacity}=this.__closure;return{y:cy-r+2+scanProgress.value*(2*r-SCAN_LINE_HEIGHT-4),opacity:scanOpacity.value};}",
68
+ location: "/home/runner/work/react-native-liveness/react-native-liveness/src/LivenessCamera.tsx",
69
+ sourceMap: "{\"version\":3,\"names\":[\"LivenessCameraTsx1\",\"cy\",\"r\",\"scanProgress\",\"SCAN_LINE_HEIGHT\",\"scanOpacity\",\"__closure\",\"y\",\"value\",\"opacity\"],\"sources\":[\"/home/runner/work/react-native-liveness/react-native-liveness/src/LivenessCamera.tsx\"],\"mappings\":\"AAmII,SAAAA,mBAAA,QAAAC,EAAA,CAAAC,CAAA,CAAAC,YAAA,CAAAC,gBAAA,CAAAC,WAAA,OAAAC,SAAA,OAAO,CAELC,CAAC,CAAEN,EAAE,CAAGC,CAAC,CAAG,CAAC,CAAGC,YAAY,CAACK,KAAK,EAAI,CAAC,CAAGN,CAAC,CAAGE,gBAAgB,CAAG,CAAC,CAAC,CACnEK,OAAO,CAAEJ,WAAW,CAACG,KACvB,CAAC\",\"ignoreList\":[]}"
70
+ };
71
+ const _worklet_14693916078586_init_data = {
72
+ code: "function LivenessCameraTsx2(){const{bracketRot,cx,cy}=this.__closure;return{rotation:bracketRot.value%360,originX:cx,originY:cy};}",
73
+ location: "/home/runner/work/react-native-liveness/react-native-liveness/src/LivenessCamera.tsx",
74
+ sourceMap: "{\"version\":3,\"names\":[\"LivenessCameraTsx2\",\"bracketRot\",\"cx\",\"cy\",\"__closure\",\"rotation\",\"value\",\"originX\",\"originY\"],\"sources\":[\"/home/runner/work/react-native-liveness/react-native-liveness/src/LivenessCamera.tsx\"],\"mappings\":\"AA4II,SAAAA,mBAAA,QAAAC,UAAA,CAAAC,EAAA,CAAAC,EAAA,OAAAC,SAAA,OAAO,CAELC,QAAQ,CAAEJ,UAAU,CAACK,KAAK,CAAG,GAAG,CAChCC,OAAO,CAAEL,EAAE,CACXM,OAAO,CAAEL,EACX,CAAC\",\"ignoreList\":[]}"
75
+ };
76
+ const _worklet_1688522500078_init_data = {
77
+ code: "function LivenessCameraTsx3(){const{circumference,livenessProgress,livenessThreshold}=this.__closure;return{strokeDashoffset:circumference-livenessProgress.value/livenessThreshold*circumference};}",
78
+ location: "/home/runner/work/react-native-liveness/react-native-liveness/src/LivenessCamera.tsx",
79
+ sourceMap: "{\"version\":3,\"names\":[\"LivenessCameraTsx3\",\"circumference\",\"livenessProgress\",\"livenessThreshold\",\"__closure\",\"strokeDashoffset\",\"value\"],\"sources\":[\"/home/runner/work/react-native-liveness/react-native-liveness/src/LivenessCamera.tsx\"],\"mappings\":\"AAsJI,SAAAA,mBAAA,QAAAC,aAAA,CAAAC,gBAAA,CAAAC,iBAAA,OAAAC,SAAA,OAAO,CACLC,gBAAgB,CACdJ,aAAa,CACZC,gBAAgB,CAACI,KAAK,CAAGH,iBAAiB,CAAIF,aACnD,CAAC\",\"ignoreList\":[]}"
80
+ };
48
81
  function CircleOverlay({
49
82
  width,
50
83
  height,
51
84
  state,
52
- score
85
+ score,
86
+ livenessThreshold
53
87
  }) {
54
- if (width === 0 || height === 0) return null;
88
+ // ── Shared values all hooks before any early return ─────────────────────
89
+ // scanProgress 0=top 1=bottom, ping-pongs continuously
90
+ const scanProgress = useSharedValue(0);
91
+ const scanOpacity = useSharedValue(1);
92
+ // bracketRot drives the slow bracket rotation in degrees
93
+ const bracketRot = useSharedValue(0);
94
+ // livenessProgress tracks smoothed score for the arc
95
+ const livenessProgress = useSharedValue(0);
96
+
97
+ // ── Geometry — computed before useAnimatedProps (safe when 0) ─────────────
55
98
  const cx = width / 2;
56
99
  const cy = height * 0.42;
57
100
  const r = width * CIRCLE_DIAMETER_RATIO / 2;
101
+ const circumference = 2 * Math.PI * r;
58
102
  const color = getCircleColor(state, score);
103
+
104
+ // ── Animated props — UI-thread worklets, deps rebuilt when geometry changes
105
+ const scanAnimProps = useAnimatedProps(function LivenessCameraTsx1Factory({
106
+ _worklet_15111972513221_init_data,
107
+ cy,
108
+ r,
109
+ scanProgress,
110
+ SCAN_LINE_HEIGHT,
111
+ scanOpacity
112
+ }) {
113
+ const _e = [new global.Error(), -6, -27];
114
+ const LivenessCameraTsx1 = () => ({
115
+ // Map 0→1 progress onto the pixel range inside the circle
116
+ y: cy - r + 2 + scanProgress.value * (2 * r - SCAN_LINE_HEIGHT - 4),
117
+ opacity: scanOpacity.value
118
+ });
119
+ LivenessCameraTsx1.__closure = {
120
+ cy,
121
+ r,
122
+ scanProgress,
123
+ SCAN_LINE_HEIGHT,
124
+ scanOpacity
125
+ };
126
+ LivenessCameraTsx1.__workletHash = 15111972513221;
127
+ LivenessCameraTsx1.__pluginVersion = "0.8.3";
128
+ LivenessCameraTsx1.__initData = _worklet_15111972513221_init_data;
129
+ LivenessCameraTsx1.__stackDetails = _e;
130
+ return LivenessCameraTsx1;
131
+ }({
132
+ _worklet_15111972513221_init_data,
133
+ cy,
134
+ r,
135
+ scanProgress,
136
+ SCAN_LINE_HEIGHT,
137
+ scanOpacity
138
+ }), [cy, r]);
139
+ const bracketAnimProps = useAnimatedProps(function LivenessCameraTsx2Factory({
140
+ _worklet_14693916078586_init_data,
141
+ bracketRot,
142
+ cx,
143
+ cy
144
+ }) {
145
+ const _e = [new global.Error(), -4, -27];
146
+ const LivenessCameraTsx2 = () => ({
147
+ // react-native-svg accepts numeric rotation + origin instead of a string
148
+ rotation: bracketRot.value % 360,
149
+ originX: cx,
150
+ originY: cy
151
+ });
152
+ LivenessCameraTsx2.__closure = {
153
+ bracketRot,
154
+ cx,
155
+ cy
156
+ };
157
+ LivenessCameraTsx2.__workletHash = 14693916078586;
158
+ LivenessCameraTsx2.__pluginVersion = "0.8.3";
159
+ LivenessCameraTsx2.__initData = _worklet_14693916078586_init_data;
160
+ LivenessCameraTsx2.__stackDetails = _e;
161
+ return LivenessCameraTsx2;
162
+ }({
163
+ _worklet_14693916078586_init_data,
164
+ bracketRot,
165
+ cx,
166
+ cy
167
+ }), [cx, cy]);
168
+ const progressAnimProps = useAnimatedProps(function LivenessCameraTsx3Factory({
169
+ _worklet_1688522500078_init_data,
170
+ circumference,
171
+ livenessProgress,
172
+ livenessThreshold
173
+ }) {
174
+ const _e = [new global.Error(), -4, -27];
175
+ const LivenessCameraTsx3 = () => ({
176
+ strokeDashoffset: circumference - livenessProgress.value / livenessThreshold * circumference
177
+ });
178
+ LivenessCameraTsx3.__closure = {
179
+ circumference,
180
+ livenessProgress,
181
+ livenessThreshold
182
+ };
183
+ LivenessCameraTsx3.__workletHash = 1688522500078;
184
+ LivenessCameraTsx3.__pluginVersion = "0.8.3";
185
+ LivenessCameraTsx3.__initData = _worklet_1688522500078_init_data;
186
+ LivenessCameraTsx3.__stackDetails = _e;
187
+ return LivenessCameraTsx3;
188
+ }({
189
+ _worklet_1688522500078_init_data,
190
+ circumference,
191
+ livenessProgress,
192
+ livenessThreshold
193
+ }), [circumference, livenessThreshold]);
194
+
195
+ // ── Start scan line + bracket rotation on mount ───────────────────────────
196
+ useEffect(() => {
197
+ scanProgress.value = withRepeat(withSequence(withTiming(1, {
198
+ duration: 1800,
199
+ easing: Easing.linear
200
+ }), withTiming(0, {
201
+ duration: 1800,
202
+ easing: Easing.linear
203
+ })), -1, false);
204
+ bracketRot.value = withRepeat(withTiming(360, {
205
+ duration: 6000,
206
+ easing: Easing.linear
207
+ }), -1, false);
208
+ return () => {
209
+ cancelAnimation(scanProgress);
210
+ cancelAnimation(bracketRot);
211
+ };
212
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
213
+
214
+ // ── On liveness confirmed: freeze brackets, fade scan line out ────────────
215
+ useEffect(() => {
216
+ if (state !== 'scanning') {
217
+ cancelAnimation(scanProgress);
218
+ cancelAnimation(bracketRot);
219
+ scanOpacity.value = withTiming(0, {
220
+ duration: 350
221
+ });
222
+ }
223
+ }, [state]); // eslint-disable-line react-hooks/exhaustive-deps
224
+
225
+ // ── Drive progress arc from live score ────────────────────────────────────
226
+ useEffect(() => {
227
+ livenessProgress.value = withTiming(Math.min(score, livenessThreshold), {
228
+ duration: 180
229
+ });
230
+ }, [score, livenessThreshold]); // eslint-disable-line react-hooks/exhaustive-deps
231
+
232
+ // ── Guard — render nothing until dimensions are known ─────────────────────
233
+ if (width === 0 || height === 0) return null;
234
+
235
+ // Scrim: full-screen rect with transparent circle cutout (evenodd rule)
59
236
  const scrimD = `M0 0H${width}V${height}H0Z ${circlePath(cx, cy, r)}`;
237
+
238
+ // 4 corner brackets at NE / SE / SW / NW diagonal positions
239
+ const bracketD = [45, 135, 225, 315].map(deg => bracketArcPath(cx, cy, r, deg, BRACKET_SPAN_DEG)).join(' ');
60
240
  return /*#__PURE__*/_jsxs(Svg, {
61
241
  style: StyleSheet.absoluteFill,
62
242
  width: width,
63
243
  height: height,
64
- children: [/*#__PURE__*/_jsx(Path, {
244
+ children: [/*#__PURE__*/_jsxs(Defs, {
245
+ children: [/*#__PURE__*/_jsx(ClipPath, {
246
+ id: "liveness-circle-clip",
247
+ children: /*#__PURE__*/_jsx(Circle, {
248
+ cx: cx,
249
+ cy: cy,
250
+ r: r
251
+ })
252
+ }), /*#__PURE__*/_jsxs(LinearGradient, {
253
+ id: "scan-gradient",
254
+ x1: "0",
255
+ y1: "0",
256
+ x2: "0",
257
+ y2: "1",
258
+ children: [/*#__PURE__*/_jsx(Stop, {
259
+ offset: "0",
260
+ stopColor: "#fff",
261
+ stopOpacity: "0"
262
+ }), /*#__PURE__*/_jsx(Stop, {
263
+ offset: "0.25",
264
+ stopColor: "#fff",
265
+ stopOpacity: "0.65"
266
+ }), /*#__PURE__*/_jsx(Stop, {
267
+ offset: "0.75",
268
+ stopColor: "#fff",
269
+ stopOpacity: "0.65"
270
+ }), /*#__PURE__*/_jsx(Stop, {
271
+ offset: "1",
272
+ stopColor: "#fff",
273
+ stopOpacity: "0"
274
+ })]
275
+ })]
276
+ }), /*#__PURE__*/_jsx(Path, {
65
277
  d: scrimD,
66
278
  fill: "rgba(0,0,0,0.55)",
67
279
  fillRule: "evenodd"
68
280
  }), /*#__PURE__*/_jsx(Circle, {
281
+ cx: cx,
282
+ cy: cy,
283
+ r: r,
284
+ fill: "none",
285
+ stroke: "rgba(255,255,255,0.18)",
286
+ strokeWidth: 1
287
+ }), /*#__PURE__*/_jsx(G, {
288
+ clipPath: "url(#liveness-circle-clip)",
289
+ children: /*#__PURE__*/_jsx(AnimatedRect, {
290
+ x: cx - r,
291
+ width: r * 2,
292
+ height: SCAN_LINE_HEIGHT,
293
+ fill: "url(#scan-gradient)",
294
+ animatedProps: scanAnimProps
295
+ })
296
+ }), /*#__PURE__*/_jsx(AnimatedG, {
297
+ animatedProps: bracketAnimProps,
298
+ children: /*#__PURE__*/_jsx(Path, {
299
+ d: bracketD,
300
+ fill: "none",
301
+ stroke: color,
302
+ strokeWidth: BRACKET_STROKE,
303
+ strokeLinecap: "round",
304
+ opacity: 0.85
305
+ })
306
+ }), /*#__PURE__*/_jsx(AnimatedCircle, {
69
307
  cx: cx,
70
308
  cy: cy,
71
309
  r: r,
72
310
  fill: "none",
73
311
  stroke: color,
74
- strokeWidth: STROKE_WIDTH
312
+ strokeWidth: STROKE_WIDTH,
313
+ strokeDasharray: circumference,
314
+ strokeLinecap: "round",
315
+ transform: `rotate(-90, ${cx}, ${cy})`,
316
+ animatedProps: progressAnimProps
75
317
  })]
76
318
  });
77
319
  }
320
+
321
+ // ─── CountdownBubble ──────────────────────────────────────────────────────────
78
322
  function CountdownBubble({
79
323
  value,
80
324
  fontFamily
81
325
  }) {
82
- const scale = useRef(new Animated.Value(0)).current;
83
- const opacity = useRef(new Animated.Value(0)).current;
326
+ const scale = useRef(new RNAnimated.Value(0)).current;
327
+ const opacity = useRef(new RNAnimated.Value(0)).current;
84
328
  useEffect(() => {
85
- Animated.parallel([Animated.sequence([Animated.spring(scale, {
329
+ RNAnimated.parallel([RNAnimated.sequence([RNAnimated.spring(scale, {
86
330
  toValue: 1.2,
87
331
  stiffness: 200,
88
332
  damping: 6,
89
333
  useNativeDriver: true
90
- }), Animated.spring(scale, {
334
+ }), RNAnimated.spring(scale, {
91
335
  toValue: 1.0,
92
336
  stiffness: 150,
93
337
  damping: 8,
94
338
  useNativeDriver: true
95
- })]), Animated.timing(opacity, {
339
+ })]), RNAnimated.timing(opacity, {
96
340
  toValue: 1,
97
341
  duration: 150,
98
342
  useNativeDriver: true
99
343
  })]).start();
100
344
  return () => {
101
- Animated.timing(opacity, {
345
+ RNAnimated.timing(opacity, {
102
346
  toValue: 0,
103
347
  duration: 200,
104
348
  useNativeDriver: true
@@ -106,7 +350,7 @@ function CountdownBubble({
106
350
  };
107
351
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
108
352
 
109
- return /*#__PURE__*/_jsx(Animated.View, {
353
+ return /*#__PURE__*/_jsx(RNAnimated.View, {
110
354
  style: [styles.countdownBubble, {
111
355
  opacity,
112
356
  transform: [{
@@ -121,6 +365,8 @@ function CountdownBubble({
121
365
  })
122
366
  });
123
367
  }
368
+
369
+ // ─── LivenessCamera ───────────────────────────────────────────────────────────
124
370
  export function LivenessCamera({
125
371
  onCapture,
126
372
  onLivenessConfirmed,
@@ -218,7 +464,8 @@ export function LivenessCamera({
218
464
  width: containerSize.width,
219
465
  height: containerSize.height,
220
466
  state: livenessState,
221
- score: livenessScore
467
+ score: livenessScore,
468
+ livenessThreshold: livenessThreshold
222
469
  }), livenessState !== 'done' && /*#__PURE__*/_jsx(View, {
223
470
  style: styles.feedbackContainer,
224
471
  children: /*#__PURE__*/_jsx(Text, {
@@ -239,6 +486,8 @@ export function LivenessCamera({
239
486
  })]
240
487
  });
241
488
  }
489
+
490
+ // ─── Styles ───────────────────────────────────────────────────────────────────
242
491
  const styles = StyleSheet.create({
243
492
  root: {
244
493
  flex: 1,
@@ -1 +1 @@
1
- {"version":3,"names":["useCallback","useEffect","useRef","useState","Animated","StyleSheet","Text","View","Camera","useCameraDevice","useCameraFormat","useCameraPermission","Circle","Path","Svg","useLivenessCamera","jsx","_jsx","jsxs","_jsxs","DEFAULT_FONT","CIRCLE_DIAMETER_RATIO","STROKE_WIDTH","K","getCircleColor","state","score","circlePath","cx","cy","r","join","CircleOverlay","width","height","color","scrimD","style","absoluteFill","children","d","fill","fillRule","stroke","strokeWidth","CountdownBubble","value","fontFamily","scale","Value","current","opacity","parallel","sequence","spring","toValue","stiffness","damping","useNativeDriver","timing","duration","start","styles","countdownBubble","transform","countdownText","LivenessCamera","onCapture","onLivenessConfirmed","onError","countdownFrom","livenessThreshold","confirmFrames","soundEnabled","hasPermission","requestPermission","device","format","fps","Math","min","maxFps","cameraRef","containerSize","setContainerSize","frameProcessor","livenessState","livenessScore","countdown","feedback","handleLayout","e","nativeEvent","layout","catch","Error","root","centered","permissionText","onLayout","ref","isActive","photo","pixelFormat","feedbackContainer","feedbackText","countdownContainer","captureFlash","pointerEvents","create","flex","backgroundColor","overflow","justifyContent","alignItems","fontSize","textAlign","paddingHorizontal","position","bottom","left","right","textShadowColor","textShadowOffset","textShadowRadius","absoluteFillObject","borderRadius","borderWidth","borderColor","lineHeight"],"sourceRoot":"../../src","sources":["LivenessCamera.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["useCallback","useEffect","useRef","useState","Animated","RNAnimated","StyleSheet","Text","View","cancelAnimation","Easing","useAnimatedProps","useSharedValue","withRepeat","withSequence","withTiming","Camera","useCameraDevice","useCameraFormat","useCameraPermission","Circle","ClipPath","Defs","G","LinearGradient","Path","Rect","Stop","Svg","useLivenessCamera","jsx","_jsx","jsxs","_jsxs","AnimatedCircle","createAnimatedComponent","AnimatedG","AnimatedRect","DEFAULT_FONT","CIRCLE_DIAMETER_RATIO","STROKE_WIDTH","K","SCAN_LINE_HEIGHT","BRACKET_SPAN_DEG","BRACKET_STROKE","getCircleColor","state","score","circlePath","cx","cy","r","join","bracketArcPath","centerDeg","spanDeg","toRad","d","Math","PI","a1","a2","x1","cos","y1","sin","x2","y2","_worklet_15111972513221_init_data","code","location","sourceMap","_worklet_14693916078586_init_data","_worklet_1688522500078_init_data","CircleOverlay","width","height","livenessThreshold","scanProgress","scanOpacity","bracketRot","livenessProgress","circumference","color","scanAnimProps","LivenessCameraTsx1Factory","_e","global","Error","LivenessCameraTsx1","y","value","opacity","__closure","__workletHash","__pluginVersion","__initData","__stackDetails","bracketAnimProps","LivenessCameraTsx2Factory","LivenessCameraTsx2","rotation","originX","originY","progressAnimProps","LivenessCameraTsx3Factory","LivenessCameraTsx3","strokeDashoffset","duration","easing","linear","min","scrimD","bracketD","map","deg","style","absoluteFill","children","id","offset","stopColor","stopOpacity","fill","fillRule","stroke","strokeWidth","clipPath","x","animatedProps","strokeLinecap","strokeDasharray","transform","CountdownBubble","fontFamily","scale","Value","current","parallel","sequence","spring","toValue","stiffness","damping","useNativeDriver","timing","start","styles","countdownBubble","countdownText","LivenessCamera","onCapture","onLivenessConfirmed","onError","countdownFrom","confirmFrames","soundEnabled","hasPermission","requestPermission","device","format","fps","maxFps","cameraRef","containerSize","setContainerSize","frameProcessor","livenessState","livenessScore","countdown","feedback","handleLayout","e","nativeEvent","layout","catch","root","centered","permissionText","onLayout","ref","isActive","photo","pixelFormat","feedbackContainer","feedbackText","countdownContainer","captureFlash","pointerEvents","create","flex","backgroundColor","overflow","justifyContent","alignItems","fontSize","textAlign","paddingHorizontal","position","bottom","left","right","textShadowColor","textShadowOffset","textShadowRadius","absoluteFillObject","borderRadius","borderWidth","borderColor","lineHeight"],"sourceRoot":"../../src","sources":["LivenessCamera.tsx"],"mappings":";;AAAA,SAASA,WAAW,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AAChE,SAASC,QAAQ,IAAIC,UAAU,EAAEC,UAAU,EAAEC,IAAI,EAAEC,IAAI,QAAQ,cAAc;AAC7E,OAAOJ,QAAQ,IACbK,eAAe,EACfC,MAAM,EACNC,gBAAgB,EAChBC,cAAc,EACdC,UAAU,EACVC,YAAY,EACZC,UAAU,QACL,yBAAyB;AAChC,SACEC,MAAM,EACNC,eAAe,EACfC,eAAe,EACfC,mBAAmB,QACd,4BAA4B;AACnC,SACEC,MAAM,EACNC,QAAQ,EACRC,IAAI,EACJC,CAAC,EACDC,cAAc,EACdC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,GAAG,QACE,kBAAkB;AACzB,SAASC,iBAAiB,QAAQ,wBAAqB;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAGxD;AACA;AACA;AACA,MAAMC,cAAc,GAAG9B,QAAQ,CAAC+B,uBAAuB,CAACf,MAAM,CAAC;AAC/D,MAAMgB,SAAS,GAAGhC,QAAQ,CAAC+B,uBAAuB,CAACZ,CAAC,CAAC;AACrD,MAAMc,YAAY,GAAGjC,QAAQ,CAAC+B,uBAAuB,CAACT,IAAI,CAAC;;AAE3D;AACA,MAAMY,YAAY,GAAG,cAAc;AACnC,MAAMC,qBAAqB,GAAG,IAAI;AAClC,MAAMC,YAAY,GAAG,CAAC;AACtB,MAAMC,CAAC,GAAG,MAAM,CAAC,CAAC;AAClB,MAAMC,gBAAgB,GAAG,EAAE,CAAC,CAAC;AAC7B,MAAMC,gBAAgB,GAAG,EAAE,CAAC,CAAC;AAC7B,MAAMC,cAAc,GAAGJ,YAAY,GAAG,CAAC;;AAEvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASK,cAAcA,CAACC,KAAoB,EAAEC,KAAa,EAAU;EACnE,QAAQD,KAAK;IACX,KAAK,OAAO;MACV,OAAO,SAAS;IAClB,KAAK,WAAW;IAChB,KAAK,WAAW;IAChB,KAAK,WAAW;IAChB,KAAK,MAAM;MACT,OAAO,SAAS;IAClB;MACE,OAAOC,KAAK,IAAI,GAAG,GAAG,SAAS,GAAG,SAAS;EAC/C;AACF;;AAEA;AACA;AACA,SAASC,UAAUA,CAACC,EAAU,EAAEC,EAAU,EAAEC,CAAS,EAAU;EAC7D,OAAO,CACL,KAAKF,EAAE,GAAGE,CAAC,IAAID,EAAE,EAAE,EACnB,KAAKD,EAAE,GAAGE,CAAC,IAAID,EAAE,GAAGC,CAAC,GAAGV,CAAC,IAAIQ,EAAE,GAAGE,CAAC,GAAGV,CAAC,IAAIS,EAAE,GAAGC,CAAC,IAAIF,EAAE,IAAIC,EAAE,GAAGC,CAAC,EAAE,EACnE,KAAKF,EAAE,GAAGE,CAAC,GAAGV,CAAC,IAAIS,EAAE,GAAGC,CAAC,IAAIF,EAAE,GAAGE,CAAC,IAAID,EAAE,GAAGC,CAAC,GAAGV,CAAC,IAAIQ,EAAE,GAAGE,CAAC,IAAID,EAAE,EAAE,EACnE,KAAKD,EAAE,GAAGE,CAAC,IAAID,EAAE,GAAGC,CAAC,GAAGV,CAAC,IAAIQ,EAAE,GAAGE,CAAC,GAAGV,CAAC,IAAIS,EAAE,GAAGC,CAAC,IAAIF,EAAE,IAAIC,EAAE,GAAGC,CAAC,EAAE,EACnE,KAAKF,EAAE,GAAGE,CAAC,GAAGV,CAAC,IAAIS,EAAE,GAAGC,CAAC,IAAIF,EAAE,GAAGE,CAAC,IAAID,EAAE,GAAGC,CAAC,GAAGV,CAAC,IAAIQ,EAAE,GAAGE,CAAC,IAAID,EAAE,EAAE,EACnE,GAAG,CACJ,CAACE,IAAI,CAAC,GAAG,CAAC;AACb;;AAEA;AACA,SAASC,cAAcA,CACrBJ,EAAU,EACVC,EAAU,EACVC,CAAS,EACTG,SAAiB,EACjBC,OAAe,EACP;EACR,MAAMC,KAAK,GAAIC,CAAS,IAAMA,CAAC,GAAGC,IAAI,CAACC,EAAE,GAAI,GAAG;EAChD,MAAMC,EAAE,GAAGJ,KAAK,CAACF,SAAS,GAAGC,OAAO,GAAG,CAAC,CAAC;EACzC,MAAMM,EAAE,GAAGL,KAAK,CAACF,SAAS,GAAGC,OAAO,GAAG,CAAC,CAAC;EACzC,MAAMO,EAAE,GAAGb,EAAE,GAAGE,CAAC,GAAGO,IAAI,CAACK,GAAG,CAACH,EAAE,CAAC;EAChC,MAAMI,EAAE,GAAGd,EAAE,GAAGC,CAAC,GAAGO,IAAI,CAACO,GAAG,CAACL,EAAE,CAAC;EAChC,MAAMM,EAAE,GAAGjB,EAAE,GAAGE,CAAC,GAAGO,IAAI,CAACK,GAAG,CAACF,EAAE,CAAC;EAChC,MAAMM,EAAE,GAAGjB,EAAE,GAAGC,CAAC,GAAGO,IAAI,CAACO,GAAG,CAACJ,EAAE,CAAC;EAChC,OAAO,KAAKC,EAAE,IAAIE,EAAE,MAAMb,CAAC,IAAIA,CAAC,UAAUe,EAAE,IAAIC,EAAE,EAAE;AACtD;;AAEA;AAAA,MAAAC,iCAAA;EAAAC,IAAA;EAAAC,QAAA;EAAAC,SAAA;AAAA;AAAA,MAAAC,iCAAA;EAAAH,IAAA;EAAAC,QAAA;EAAAC,SAAA;AAAA;AAAA,MAAAE,gCAAA;EAAAJ,IAAA;EAAAC,QAAA;EAAAC,SAAA;AAAA;AACA,SAASG,aAAaA,CAAC;EACrBC,KAAK;EACLC,MAAM;EACN9B,KAAK;EACLC,KAAK;EACL8B;AAOF,CAAC,EAAE;EACD;EACA;EACA,MAAMC,YAAY,GAAGlE,cAAc,CAAC,CAAC,CAAC;EACtC,MAAMmE,WAAW,GAAGnE,cAAc,CAAC,CAAC,CAAC;EACrC;EACA,MAAMoE,UAAU,GAAGpE,cAAc,CAAC,CAAC,CAAC;EACpC;EACA,MAAMqE,gBAAgB,GAAGrE,cAAc,CAAC,CAAC,CAAC;;EAE1C;EACA,MAAMqC,EAAE,GAAG0B,KAAK,GAAG,CAAC;EACpB,MAAMzB,EAAE,GAAG0B,MAAM,GAAG,IAAI;EACxB,MAAMzB,CAAC,GAAIwB,KAAK,GAAGpC,qBAAqB,GAAI,CAAC;EAC7C,MAAM2C,aAAa,GAAG,CAAC,GAAGxB,IAAI,CAACC,EAAE,GAAGR,CAAC;EACrC,MAAMgC,KAAK,GAAGtC,cAAc,CAACC,KAAK,EAAEC,KAAK,CAAC;;EAE1C;EACA,MAAMqC,aAAa,GAAGzE,gBAAgB,CACpC,SAAA0E,0BAAA;IAAAjB,iCAAA;IAEKlB,EAAE;IAAGC,CAAC;IAAO2B,YAAY;IAAkBpC,gBAAgB;IACrDqC;EAAW;IAAA,MAAAO,EAAA,QAAAC,MAAA,CAAAC,KAAA;IAAA,MAAAC,kBAAA,GAHtBA,CAAA,MAAO;MACL;MACAC,CAAC,EAAExC,EAAE,GAAGC,CAAC,GAAG,CAAC,GAAG2B,YAAY,CAACa,KAAK,IAAI,CAAC,GAAGxC,CAAC,GAAGT,gBAAgB,GAAG,CAAC,CAAC;MACnEkD,OAAO,EAAEb,WAAW,CAACY;IACvB,CAAC,CAAC;IAAAF,kBAAA,CAAAI,SAAA;MAFG3C,EAAE;MAAGC,CAAC;MAAO2B,YAAY;MAAkBpC,gBAAgB;MACrDqC;IAAW;IAAAU,kBAAA,CAAAK,aAAA;IAAAL,kBAAA,CAAAM,eAAA;IAAAN,kBAAA,CAAAO,UAAA,GAAA5B,iCAAA;IAAAqB,kBAAA,CAAAQ,cAAA,GAAAX,EAAA;IAAA,OAAAG,kBAAA;EAAA,CAHtB;IAAArB,iCAAA;IAEKlB,EAAE;IAAGC,CAAC;IAAO2B,YAAY;IAAkBpC,gBAAgB;IACrDqC;EAAW,IAEtB,CAAC7B,EAAE,EAAEC,CAAC,CACR,CAAC;EAED,MAAM+C,gBAAgB,GAAGvF,gBAAgB,CACvC,SAAAwF,0BAAA;IAAA3B,iCAAA;IAEYQ,UAAU;IACX/B,EAAE;IACFC;EAAE;IAAA,MAAAoC,EAAA,QAAAC,MAAA,CAAAC,KAAA;IAAA,MAAAY,kBAAA,GAJbA,CAAA,MAAO;MACL;MACAC,QAAQ,EAAErB,UAAU,CAACW,KAAK,GAAG,GAAG;MAChCW,OAAO,EAAErD,EAAE;MACXsD,OAAO,EAAErD;IACX,CAAC,CAAC;IAAAkD,kBAAA,CAAAP,SAAA;MAHUb,UAAU;MACX/B,EAAE;MACFC;IAAE;IAAAkD,kBAAA,CAAAN,aAAA;IAAAM,kBAAA,CAAAL,eAAA;IAAAK,kBAAA,CAAAJ,UAAA,GAAAxB,iCAAA;IAAA4B,kBAAA,CAAAH,cAAA,GAAAX,EAAA;IAAA,OAAAc,kBAAA;EAAA,CAJb;IAAA5B,iCAAA;IAEYQ,UAAU;IACX/B,EAAE;IACFC;EAAE,IAEb,CAACD,EAAE,EAAEC,EAAE,CACT,CAAC;EAED,MAAMsD,iBAAiB,GAAG7F,gBAAgB,CACxC,SAAA8F,0BAAA;IAAAhC,gCAAA;IAEIS,aAAa;IACZD,gBAAgB;IAASJ;EAAiB;IAAA,MAAAS,EAAA,QAAAC,MAAA,CAAAC,KAAA;IAAA,MAAAkB,kBAAA,GAH/CA,CAAA,MAAO;MACLC,gBAAgB,EACdzB,aAAa,GACZD,gBAAgB,CAACU,KAAK,GAAGd,iBAAiB,GAAIK;IACnD,CAAC,CAAC;IAAAwB,kBAAA,CAAAb,SAAA;MAFEX,aAAa;MACZD,gBAAgB;MAASJ;IAAiB;IAAA6B,kBAAA,CAAAZ,aAAA;IAAAY,kBAAA,CAAAX,eAAA;IAAAW,kBAAA,CAAAV,UAAA,GAAAvB,gCAAA;IAAAiC,kBAAA,CAAAT,cAAA,GAAAX,EAAA;IAAA,OAAAoB,kBAAA;EAAA,CAH/C;IAAAjC,gCAAA;IAEIS,aAAa;IACZD,gBAAgB;IAASJ;EAAiB,IAE/C,CAACK,aAAa,EAAEL,iBAAiB,CACnC,CAAC;;EAED;EACA5E,SAAS,CAAC,MAAM;IACd6E,YAAY,CAACa,KAAK,GAAG9E,UAAU,CAC7BC,YAAY,CACVC,UAAU,CAAC,CAAC,EAAE;MAAE6F,QAAQ,EAAE,IAAI;MAAEC,MAAM,EAAEnG,MAAM,CAACoG;IAAO,CAAC,CAAC,EACxD/F,UAAU,CAAC,CAAC,EAAE;MAAE6F,QAAQ,EAAE,IAAI;MAAEC,MAAM,EAAEnG,MAAM,CAACoG;IAAO,CAAC,CACzD,CAAC,EACD,CAAC,CAAC,EACF,KACF,CAAC;IACD9B,UAAU,CAACW,KAAK,GAAG9E,UAAU,CAC3BE,UAAU,CAAC,GAAG,EAAE;MAAE6F,QAAQ,EAAE,IAAI;MAAEC,MAAM,EAAEnG,MAAM,CAACoG;IAAO,CAAC,CAAC,EAC1D,CAAC,CAAC,EACF,KACF,CAAC;IACD,OAAO,MAAM;MACXrG,eAAe,CAACqE,YAAY,CAAC;MAC7BrE,eAAe,CAACuE,UAAU,CAAC;IAC7B,CAAC;EACH,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;;EAER;EACA/E,SAAS,CAAC,MAAM;IACd,IAAI6C,KAAK,KAAK,UAAU,EAAE;MACxBrC,eAAe,CAACqE,YAAY,CAAC;MAC7BrE,eAAe,CAACuE,UAAU,CAAC;MAC3BD,WAAW,CAACY,KAAK,GAAG5E,UAAU,CAAC,CAAC,EAAE;QAAE6F,QAAQ,EAAE;MAAI,CAAC,CAAC;IACtD;EACF,CAAC,EAAE,CAAC9D,KAAK,CAAC,CAAC,CAAC,CAAC;;EAEb;EACA7C,SAAS,CAAC,MAAM;IACdgF,gBAAgB,CAACU,KAAK,GAAG5E,UAAU,CAAC2C,IAAI,CAACqD,GAAG,CAAChE,KAAK,EAAE8B,iBAAiB,CAAC,EAAE;MACtE+B,QAAQ,EAAE;IACZ,CAAC,CAAC;EACJ,CAAC,EAAE,CAAC7D,KAAK,EAAE8B,iBAAiB,CAAC,CAAC,CAAC,CAAC;;EAEhC;EACA,IAAIF,KAAK,KAAK,CAAC,IAAIC,MAAM,KAAK,CAAC,EAAE,OAAO,IAAI;;EAE5C;EACA,MAAMoC,MAAM,GAAG,QAAQrC,KAAK,IAAIC,MAAM,OAAO5B,UAAU,CAACC,EAAE,EAAEC,EAAE,EAAEC,CAAC,CAAC,EAAE;;EAEpE;EACA,MAAM8D,QAAQ,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CACjCC,GAAG,CAAEC,GAAG,IAAK9D,cAAc,CAACJ,EAAE,EAAEC,EAAE,EAAEC,CAAC,EAAEgE,GAAG,EAAExE,gBAAgB,CAAC,CAAC,CAC9DS,IAAI,CAAC,GAAG,CAAC;EAEZ,oBACEnB,KAAA,CAACL,GAAG;IAACwF,KAAK,EAAE9G,UAAU,CAAC+G,YAAa;IAAC1C,KAAK,EAAEA,KAAM;IAACC,MAAM,EAAEA,MAAO;IAAA0C,QAAA,gBAEhErF,KAAA,CAACX,IAAI;MAAAgG,QAAA,gBAEHvF,IAAA,CAACV,QAAQ;QAACkG,EAAE,EAAC,sBAAsB;QAAAD,QAAA,eACjCvF,IAAA,CAACX,MAAM;UAAC6B,EAAE,EAAEA,EAAG;UAACC,EAAE,EAAEA,EAAG;UAACC,CAAC,EAAEA;QAAE,CAAE;MAAC,CACxB,CAAC,eAGXlB,KAAA,CAACT,cAAc;QAAC+F,EAAE,EAAC,eAAe;QAACzD,EAAE,EAAC,GAAG;QAACE,EAAE,EAAC,GAAG;QAACE,EAAE,EAAC,GAAG;QAACC,EAAE,EAAC,GAAG;QAAAmD,QAAA,gBAC5DvF,IAAA,CAACJ,IAAI;UAAC6F,MAAM,EAAC,GAAG;UAACC,SAAS,EAAC,MAAM;UAACC,WAAW,EAAC;QAAG,CAAE,CAAC,eACpD3F,IAAA,CAACJ,IAAI;UAAC6F,MAAM,EAAC,MAAM;UAACC,SAAS,EAAC,MAAM;UAACC,WAAW,EAAC;QAAM,CAAE,CAAC,eAC1D3F,IAAA,CAACJ,IAAI;UAAC6F,MAAM,EAAC,MAAM;UAACC,SAAS,EAAC,MAAM;UAACC,WAAW,EAAC;QAAM,CAAE,CAAC,eAC1D3F,IAAA,CAACJ,IAAI;UAAC6F,MAAM,EAAC,GAAG;UAACC,SAAS,EAAC,MAAM;UAACC,WAAW,EAAC;QAAG,CAAE,CAAC;MAAA,CACtC,CAAC;IAAA,CACb,CAAC,eAGP3F,IAAA,CAACN,IAAI;MAACgC,CAAC,EAAEuD,MAAO;MAACW,IAAI,EAAC,kBAAkB;MAACC,QAAQ,EAAC;IAAS,CAAE,CAAC,eAG9D7F,IAAA,CAACX,MAAM;MACL6B,EAAE,EAAEA,EAAG;MACPC,EAAE,EAAEA,EAAG;MACPC,CAAC,EAAEA,CAAE;MACLwE,IAAI,EAAC,MAAM;MACXE,MAAM,EAAC,wBAAwB;MAC/BC,WAAW,EAAE;IAAE,CAChB,CAAC,eAGF/F,IAAA,CAACR,CAAC;MAACwG,QAAQ,EAAC,4BAA4B;MAAAT,QAAA,eACtCvF,IAAA,CAACM,YAAY;QACX2F,CAAC,EAAE/E,EAAE,GAAGE,CAAE;QACVwB,KAAK,EAAExB,CAAC,GAAG,CAAE;QACbyB,MAAM,EAAElC,gBAAiB;QACzBiF,IAAI,EAAC,qBAAqB;QAC1BM,aAAa,EAAE7C;MAAc,CAC9B;IAAC,CACD,CAAC,eAGJrD,IAAA,CAACK,SAAS;MAAC6F,aAAa,EAAE/B,gBAAiB;MAAAoB,QAAA,eACzCvF,IAAA,CAACN,IAAI;QACHgC,CAAC,EAAEwD,QAAS;QACZU,IAAI,EAAC,MAAM;QACXE,MAAM,EAAE1C,KAAM;QACd2C,WAAW,EAAElF,cAAe;QAC5BsF,aAAa,EAAC,OAAO;QACrBtC,OAAO,EAAE;MAAK,CACf;IAAC,CACO,CAAC,eAIZ7D,IAAA,CAACG,cAAc;MACbe,EAAE,EAAEA,EAAG;MACPC,EAAE,EAAEA,EAAG;MACPC,CAAC,EAAEA,CAAE;MACLwE,IAAI,EAAC,MAAM;MACXE,MAAM,EAAE1C,KAAM;MACd2C,WAAW,EAAEtF,YAAa;MAC1B2F,eAAe,EAAEjD,aAAc;MAC/BgD,aAAa,EAAC,OAAO;MACrBE,SAAS,EAAE,eAAenF,EAAE,KAAKC,EAAE,GAAI;MACvC+E,aAAa,EAAEzB;IAAkB,CAClC,CAAC;EAAA,CACC,CAAC;AAEV;;AAEA;AACA,SAAS6B,eAAeA,CAAC;EACvB1C,KAAK;EACL2C;AAIF,CAAC,EAAE;EACD,MAAMC,KAAK,GAAGrI,MAAM,CAAC,IAAIG,UAAU,CAACmI,KAAK,CAAC,CAAC,CAAC,CAAC,CAACC,OAAO;EACrD,MAAM7C,OAAO,GAAG1F,MAAM,CAAC,IAAIG,UAAU,CAACmI,KAAK,CAAC,CAAC,CAAC,CAAC,CAACC,OAAO;EAEvDxI,SAAS,CAAC,MAAM;IACdI,UAAU,CAACqI,QAAQ,CAAC,CAClBrI,UAAU,CAACsI,QAAQ,CAAC,CAClBtI,UAAU,CAACuI,MAAM,CAACL,KAAK,EAAE;MACvBM,OAAO,EAAE,GAAG;MACZC,SAAS,EAAE,GAAG;MACdC,OAAO,EAAE,CAAC;MACVC,eAAe,EAAE;IACnB,CAAC,CAAC,EACF3I,UAAU,CAACuI,MAAM,CAACL,KAAK,EAAE;MACvBM,OAAO,EAAE,GAAG;MACZC,SAAS,EAAE,GAAG;MACdC,OAAO,EAAE,CAAC;MACVC,eAAe,EAAE;IACnB,CAAC,CAAC,CACH,CAAC,EACF3I,UAAU,CAAC4I,MAAM,CAACrD,OAAO,EAAE;MACzBiD,OAAO,EAAE,CAAC;MACVjC,QAAQ,EAAE,GAAG;MACboC,eAAe,EAAE;IACnB,CAAC,CAAC,CACH,CAAC,CAACE,KAAK,CAAC,CAAC;IAEV,OAAO,MAAM;MACX7I,UAAU,CAAC4I,MAAM,CAACrD,OAAO,EAAE;QACzBiD,OAAO,EAAE,CAAC;QACVjC,QAAQ,EAAE,GAAG;QACboC,eAAe,EAAE;MACnB,CAAC,CAAC,CAACE,KAAK,CAAC,CAAC;IACZ,CAAC;EACH,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;;EAER,oBACEnH,IAAA,CAAC1B,UAAU,CAACG,IAAI;IACd4G,KAAK,EAAE,CAAC+B,MAAM,CAACC,eAAe,EAAE;MAAExD,OAAO;MAAEwC,SAAS,EAAE,CAAC;QAAEG;MAAM,CAAC;IAAE,CAAC,CAAE;IAAAjB,QAAA,eAErEvF,IAAA,CAACxB,IAAI;MAAC6G,KAAK,EAAE,CAAC+B,MAAM,CAACE,aAAa,EAAE;QAAEf;MAAW,CAAC,CAAE;MAAAhB,QAAA,EAAE3B;IAAK,CAAO;EAAC,CACpD,CAAC;AAEtB;;AAEA;AACA,OAAO,SAAS2D,cAAcA,CAAC;EAC7BC,SAAS;EACTC,mBAAmB;EACnBC,OAAO;EACPC,aAAa,GAAG,CAAC;EACjB7E,iBAAiB,GAAG,IAAI;EACxB8E,aAAa,GAAG,EAAE;EAClBC,YAAY,GAAG,IAAI;EACnBtB,UAAU,GAAGhG,YAAY;EACzB8E;AACmB,CAAC,EAAE;EACtB,MAAM;IAAEyC,aAAa;IAAEC;EAAkB,CAAC,GAAG3I,mBAAmB,CAAC,CAAC;EAClE,MAAM4I,MAAM,GAAG9I,eAAe,CAAC,OAAO,CAAC;EACvC,MAAM+I,MAAM,GAAG9I,eAAe,CAAC6I,MAAM,EAAE,CAAC;IAAEE,GAAG,EAAE;EAAG,CAAC,CAAC,CAAC;EACrD,MAAMA,GAAG,GAAGvG,IAAI,CAACqD,GAAG,CAACiD,MAAM,EAAEE,MAAM,IAAI,EAAE,EAAE,EAAE,CAAC;EAC9C,MAAMC,SAAS,GAAGjK,MAAM,CAAS,IAAI,CAAC;EACtC,MAAM,CAACkK,aAAa,EAAEC,gBAAgB,CAAC,GAAGlK,QAAQ,CAAC;IAAEwE,KAAK,EAAE,CAAC;IAAEC,MAAM,EAAE;EAAE,CAAC,CAAC;EAE3E,MAAM;IAAE0F,cAAc;IAAEC,aAAa;IAAEC,aAAa;IAAEC,SAAS;IAAEC;EAAS,CAAC,GACzE7I,iBAAiB,CAAC;IAChBgD,iBAAiB;IACjB8E,aAAa;IACbD,aAAa;IACbE,YAAY;IACZO,SAAS;IACTZ,SAAS;IACTC,mBAAmB;IACnBC;EACF,CAAC,CAAC;EAEJ,MAAMkB,YAAY,GAAG3K,WAAW,CAC7B4K,CAAiE,IAAK;IACrE,MAAM;MAAEjG,KAAK;MAAEC;IAAO,CAAC,GAAGgG,CAAC,CAACC,WAAW,CAACC,MAAM;IAC9CT,gBAAgB,CAAC;MAAE1F,KAAK;MAAEC;IAAO,CAAC,CAAC;EACrC,CAAC,EACD,EACF,CAAC;EAED3E,SAAS,CAAC,MAAM;IACd,IAAI,CAAC4J,aAAa,EAAE;MAClBC,iBAAiB,CAAC,CAAC,CAACiB,KAAK,CAAC,MAAM;QAC9BtB,OAAO,GAAG,IAAIjE,KAAK,CAAC,0BAA0B,CAAC,CAAC;MAClD,CAAC,CAAC;IACJ;EACF,CAAC,EAAE,CAACqE,aAAa,EAAEC,iBAAiB,EAAEL,OAAO,CAAC,CAAC;EAE/C,IAAI,CAACI,aAAa,EAAE;IAClB,oBACE9H,IAAA,CAACvB,IAAI;MAAC4G,KAAK,EAAE,CAAC+B,MAAM,CAAC6B,IAAI,EAAE5D,KAAK,EAAE+B,MAAM,CAAC8B,QAAQ,CAAE;MAAA3D,QAAA,eACjDvF,IAAA,CAACxB,IAAI;QAAC6G,KAAK,EAAE,CAAC+B,MAAM,CAAC+B,cAAc,EAAE;UAAE5C;QAAW,CAAC,CAAE;QAAAhB,QAAA,EAAC;MAEtD,CAAM;IAAC,CACH,CAAC;EAEX;EAEA,IAAI,CAACyC,MAAM,EAAE;IACX,oBACEhI,IAAA,CAACvB,IAAI;MAAC4G,KAAK,EAAE,CAAC+B,MAAM,CAAC6B,IAAI,EAAE5D,KAAK,EAAE+B,MAAM,CAAC8B,QAAQ,CAAE;MAAA3D,QAAA,eACjDvF,IAAA,CAACxB,IAAI;QAAC6G,KAAK,EAAE,CAAC+B,MAAM,CAAC+B,cAAc,EAAE;UAAE5C;QAAW,CAAC,CAAE;QAAAhB,QAAA,EAAC;MAEtD,CAAM;IAAC,CACH,CAAC;EAEX;EAEA,oBACErF,KAAA,CAACzB,IAAI;IAAC4G,KAAK,EAAE,CAAC+B,MAAM,CAAC6B,IAAI,EAAE5D,KAAK,CAAE;IAAC+D,QAAQ,EAAER,YAAa;IAAArD,QAAA,gBACxDvF,IAAA,CAACf,MAAM;MACLoK,GAAG,EAAEjB,SAAU;MACf/C,KAAK,EAAE9G,UAAU,CAAC+G,YAAa;MAC/B0C,MAAM,EAAEA,MAAO;MACfsB,QAAQ,EAAEd,aAAa,KAAK,MAAM,IAAIA,aAAa,KAAK,OAAQ;MAChED,cAAc,EAAEA,cAAe;MAC/BgB,KAAK;MACLC,WAAW,EAAC,KAAK;MACjBvB,MAAM,EAAEA,MAAO;MACfC,GAAG,EAAEA;IAAI,CACV,CAAC,eACFlI,IAAA,CAAC2C,aAAa;MACZC,KAAK,EAAEyF,aAAa,CAACzF,KAAM;MAC3BC,MAAM,EAAEwF,aAAa,CAACxF,MAAO;MAC7B9B,KAAK,EAAEyH,aAAc;MACrBxH,KAAK,EAAEyH,aAAc;MACrB3F,iBAAiB,EAAEA;IAAkB,CACtC,CAAC,EACD0F,aAAa,KAAK,MAAM,iBACvBxI,IAAA,CAACvB,IAAI;MAAC4G,KAAK,EAAE+B,MAAM,CAACqC,iBAAkB;MAAAlE,QAAA,eACpCvF,IAAA,CAACxB,IAAI;QAAC6G,KAAK,EAAE,CAAC+B,MAAM,CAACsC,YAAY,EAAE;UAAEnD;QAAW,CAAC,CAAE;QAAAhB,QAAA,EAAEoD;MAAQ,CAAO;IAAC,CACjE,CACP,EACAH,aAAa,KAAK,WAAW,IAAIE,SAAS,KAAK,IAAI,iBAClD1I,IAAA,CAACvB,IAAI;MAAC4G,KAAK,EAAE+B,MAAM,CAACuC,kBAAmB;MAAApE,QAAA,eACrCvF,IAAA,CAACsG,eAAe;QAEd1C,KAAK,EAAE8E,SAAU;QACjBnC,UAAU,EAAEA;MAAW,GAFlBmC,SAGN;IAAC,CACE,CACP,EACAF,aAAa,KAAK,WAAW,iBAC5BxI,IAAA,CAACvB,IAAI;MAAC4G,KAAK,EAAE+B,MAAM,CAACwC,YAAa;MAACC,aAAa,EAAC;IAAM,CAAE,CACzD;EAAA,CACG,CAAC;AAEX;;AAEA;AACA,MAAMzC,MAAM,GAAG7I,UAAU,CAACuL,MAAM,CAAC;EAC/Bb,IAAI,EAAE;IACJc,IAAI,EAAE,CAAC;IACPC,eAAe,EAAE,MAAM;IACvBC,QAAQ,EAAE;EACZ,CAAC;EACDf,QAAQ,EAAE;IACRgB,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE;EACd,CAAC;EACDhB,cAAc,EAAE;IACd/F,KAAK,EAAE,MAAM;IACbgH,QAAQ,EAAE,EAAE;IACZC,SAAS,EAAE,QAAQ;IACnBC,iBAAiB,EAAE;EACrB,CAAC;EACDb,iBAAiB,EAAE;IACjBc,QAAQ,EAAE,UAAU;IACpBC,MAAM,EAAE,KAAK;IACbC,IAAI,EAAE,CAAC;IACPC,KAAK,EAAE,CAAC;IACRP,UAAU,EAAE,QAAQ;IACpBG,iBAAiB,EAAE;EACrB,CAAC;EACDZ,YAAY,EAAE;IACZtG,KAAK,EAAE,MAAM;IACbgH,QAAQ,EAAE,EAAE;IACZC,SAAS,EAAE,QAAQ;IACnBM,eAAe,EAAE,iBAAiB;IAClCC,gBAAgB,EAAE;MAAEhI,KAAK,EAAE,CAAC;MAAEC,MAAM,EAAE;IAAE,CAAC;IACzCgI,gBAAgB,EAAE;EACpB,CAAC;EACDlB,kBAAkB,EAAE;IAClB,GAAGpL,UAAU,CAACuM,kBAAkB;IAChCZ,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE;EACd,CAAC;EACD9C,eAAe,EAAE;IACfzE,KAAK,EAAE,EAAE;IACTC,MAAM,EAAE,EAAE;IACVkI,YAAY,EAAE,EAAE;IAChBf,eAAe,EAAE,wBAAwB;IACzCgB,WAAW,EAAE,CAAC;IACdC,WAAW,EAAE,MAAM;IACnBf,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE;EACd,CAAC;EACD7C,aAAa,EAAE;IACblE,KAAK,EAAE,MAAM;IACbgH,QAAQ,EAAE,EAAE;IACZc,UAAU,EAAE;EACd,CAAC;EACDtB,YAAY,EAAE;IACZ,GAAGrL,UAAU,CAACuM,kBAAkB;IAChCd,eAAe,EAAE,MAAM;IACvBnG,OAAO,EAAE;EACX;AACF,CAAC,CAAC","ignoreList":[]}
@@ -2,19 +2,39 @@
2
2
 
3
3
  import { useMemo } from 'react';
4
4
  import { VisionCameraProxy } from 'react-native-vision-camera';
5
+ const _worklet_4012480599600_init_data = {
6
+ code: "function LivenessDetectorTs1(frame){const{plugin}=this.__closure;const result=plugin.call(frame);return result;}",
7
+ location: "/home/runner/work/react-native-liveness/react-native-liveness/src/LivenessDetector.ts",
8
+ sourceMap: "{\"version\":3,\"names\":[\"LivenessDetectorTs1\",\"frame\",\"plugin\",\"__closure\",\"result\",\"call\"],\"sources\":[\"/home/runner/work/react-native-liveness/react-native-liveness/src/LivenessDetector.ts\"],\"mappings\":\"AAsBoB,QAAC,CAAAA,mBAAkCA,CAAAC,KAAA,QAAAC,MAAA,OAAAC,SAAA,CAEjD,KAAM,CAAAC,MAAM,CAAGF,MAAM,CAACG,IAAI,CAACJ,KAAK,CAAC,CAEjC,MAAO,CAAAG,MAAM,CACf\",\"ignoreList\":[]}"
9
+ };
5
10
  function createPlugin() {
6
11
  const plugin = VisionCameraProxy.initFrameProcessorPlugin('detectLiveness', {});
7
12
  if (!plugin) {
8
13
  throw new Error('[LivenessCamera] Frame Processor Plugin "detectLiveness" not found. ' + 'Make sure the native module is linked correctly.');
9
14
  }
10
15
  return {
11
- detectLiveness: frame => {
12
- 'worklet';
13
-
14
- const result = plugin.call(frame);
15
- // plugin.call returns a loosely-typed BasicParameterType — cast via unknown
16
- return result;
17
- }
16
+ detectLiveness: function LivenessDetectorTs1Factory({
17
+ _worklet_4012480599600_init_data,
18
+ plugin
19
+ }) {
20
+ const _e = [new global.Error(), -2, -27];
21
+ const LivenessDetectorTs1 = function (frame) {
22
+ const result = plugin.call(frame);
23
+ // plugin.call returns a loosely-typed BasicParameterType — cast via unknown
24
+ return result;
25
+ };
26
+ LivenessDetectorTs1.__closure = {
27
+ plugin
28
+ };
29
+ LivenessDetectorTs1.__workletHash = 4012480599600;
30
+ LivenessDetectorTs1.__pluginVersion = "0.8.3";
31
+ LivenessDetectorTs1.__initData = _worklet_4012480599600_init_data;
32
+ LivenessDetectorTs1.__stackDetails = _e;
33
+ return LivenessDetectorTs1;
34
+ }({
35
+ _worklet_4012480599600_init_data,
36
+ plugin
37
+ })
18
38
  };
19
39
  }
20
40
  export function useLivenessPlugin() {
@@ -1 +1 @@
1
- {"version":3,"names":["useMemo","VisionCameraProxy","createPlugin","plugin","initFrameProcessorPlugin","Error","detectLiveness","frame","result","call","useLivenessPlugin"],"sourceRoot":"../../src","sources":["LivenessDetector.ts"],"mappings":";;AAAA,SAASA,OAAO,QAAQ,OAAO;AAC/B,SAASC,iBAAiB,QAAoB,4BAA4B;AAO1E,SAASC,YAAYA,CAAA,EAAmB;EACtC,MAAMC,MAAM,GAAGF,iBAAiB,CAACG,wBAAwB,CACvD,gBAAgB,EAChB,CAAC,CACH,CAAC;EAED,IAAI,CAACD,MAAM,EAAE;IACX,MAAM,IAAIE,KAAK,CACb,sEAAsE,GACpE,kDACJ,CAAC;EACH;EAEA,OAAO;IACLC,cAAc,EAAGC,KAAY,IAAsB;MACjD,SAAS;;MACT,MAAMC,MAAM,GAAGL,MAAM,CAACM,IAAI,CAACF,KAAK,CAAC;MACjC;MACA,OAAOC,MAAM;IACf;EACF,CAAC;AACH;AAEA,OAAO,SAASE,iBAAiBA,CAAA,EAAmB;EAClD,OAAOV,OAAO,CAAC,MAAME,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC;AAC1C","ignoreList":[]}
1
+ {"version":3,"names":["useMemo","VisionCameraProxy","_worklet_4012480599600_init_data","code","location","sourceMap","createPlugin","plugin","initFrameProcessorPlugin","Error","detectLiveness","LivenessDetectorTs1Factory","_e","global","LivenessDetectorTs1","frame","result","call","__closure","__workletHash","__pluginVersion","__initData","__stackDetails","useLivenessPlugin"],"sourceRoot":"../../src","sources":["LivenessDetector.ts"],"mappings":";;AAAA,SAASA,OAAO,QAAQ,OAAO;AAC/B,SAASC,iBAAiB,QAAoB,4BAA4B;AAAC,MAAAC,gCAAA;EAAAC,IAAA;EAAAC,QAAA;EAAAC,SAAA;AAAA;AAO3E,SAASC,YAAYA,CAAA,EAAmB;EACtC,MAAMC,MAAM,GAAGN,iBAAiB,CAACO,wBAAwB,CACvD,gBAAgB,EAChB,CAAC,CACH,CAAC;EAED,IAAI,CAACD,MAAM,EAAE;IACX,MAAM,IAAIE,KAAK,CACb,sEAAsE,GACpE,kDACJ,CAAC;EACH;EAEA,OAAO;IACLC,cAAc,EAAE,SAAAC,2BAAA;MAAAT,gCAAA;MAECK;IAAM;MAAA,MAAAK,EAAA,QAAAC,MAAA,CAAAJ,KAAA;MAAA,MAAAK,mBAAA,YAAAA,CAFNC,KAAY,EAAsB;QAEjD,MAAMC,MAAM,GAAGT,MAAM,CAACU,IAAI,CAACF,KAAK,CAAC;QACjC;QACA,OAAOC,MAAM;MACf,CAAC;MAAAF,mBAAA,CAAAI,SAAA;QAHgBX;MAAM;MAAAO,mBAAA,CAAAK,aAAA;MAAAL,mBAAA,CAAAM,eAAA;MAAAN,mBAAA,CAAAO,UAAA,GAAAnB,gCAAA;MAAAY,mBAAA,CAAAQ,cAAA,GAAAV,EAAA;MAAA,OAAAE,mBAAA;IAAA,CAFP;MAAAZ,gCAAA;MAECK;IAAM;EAIzB,CAAC;AACH;AAEA,OAAO,SAASgB,iBAAiBA,CAAA,EAAmB;EAClD,OAAOvB,OAAO,CAAC,MAAMM,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC;AAC1C","ignoreList":[]}
@@ -9,6 +9,16 @@ const WINDOW_SIZE = 20;
9
9
  // How many frames to decay consecutiveGood by on a bad frame.
10
10
  // Decay (not hard reset) means one noisy frame won't erase all progress.
11
11
  const CONSECUTIVE_DECAY = 2;
12
+ const _worklet_11184642299290_init_data = {
13
+ code: "function useLivenessCameraTs1(){const{plugin,frame,handleFaceDataJS}=this.__closure;const face=plugin.detectLiveness(frame);handleFaceDataJS(face,frame.width);}",
14
+ 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\":\"AAuNyB,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
+ };
17
+ const _worklet_14471027507603_init_data = {
18
+ 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
+ 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\":\"AAmNI,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\":[]}"
21
+ };
12
22
  export function useLivenessCamera(options) {
13
23
  const {
14
24
  livenessThreshold,
@@ -168,18 +178,63 @@ export function useLivenessCamera(options) {
168
178
  // ─── Frame processor ──────────────────────────────────────────────────────
169
179
 
170
180
  const handleFaceDataJS = useMemo(() => Worklets.createRunOnJS(handleFaceData), [handleFaceData]);
171
- const frameProcessor = useFrameProcessor(frame => {
172
- 'worklet';
173
-
174
- // Camera preview renders at full fps (60). ML Kit only needs ~20fps —
175
- // running it on every frame would block the render thread unnecessarily.
176
- runAtTargetFps(20, () => {
177
- 'worklet';
178
-
179
- const face = plugin.detectLiveness(frame);
180
- handleFaceDataJS(face, frame.width);
181
- });
182
- }, [plugin, handleFaceDataJS]);
181
+ const frameProcessor = useFrameProcessor(function useLivenessCameraTs2Factory({
182
+ _worklet_14471027507603_init_data,
183
+ runAtTargetFps,
184
+ _worklet_11184642299290_init_data,
185
+ plugin,
186
+ handleFaceDataJS
187
+ }) {
188
+ const _e = [new global.Error(), -5, -27];
189
+ const useLivenessCameraTs2 = function (frame) {
190
+ // Camera preview renders at full fps (60). ML Kit only needs ~20fps —
191
+ // running it on every frame would block the render thread unnecessarily.
192
+ runAtTargetFps(20, function useLivenessCameraTs1Factory({
193
+ _worklet_11184642299290_init_data,
194
+ plugin,
195
+ frame,
196
+ handleFaceDataJS
197
+ }) {
198
+ const _e = [new global.Error(), -4, -27];
199
+ const useLivenessCameraTs1 = function () {
200
+ const face = plugin.detectLiveness(frame);
201
+ handleFaceDataJS(face, frame.width);
202
+ };
203
+ useLivenessCameraTs1.__closure = {
204
+ plugin,
205
+ frame,
206
+ handleFaceDataJS
207
+ };
208
+ useLivenessCameraTs1.__workletHash = 11184642299290;
209
+ useLivenessCameraTs1.__pluginVersion = "0.8.3";
210
+ useLivenessCameraTs1.__initData = _worklet_11184642299290_init_data;
211
+ useLivenessCameraTs1.__stackDetails = _e;
212
+ return useLivenessCameraTs1;
213
+ }({
214
+ _worklet_11184642299290_init_data,
215
+ plugin,
216
+ frame,
217
+ handleFaceDataJS
218
+ }));
219
+ };
220
+ useLivenessCameraTs2.__closure = {
221
+ runAtTargetFps,
222
+ _worklet_11184642299290_init_data,
223
+ plugin,
224
+ handleFaceDataJS
225
+ };
226
+ useLivenessCameraTs2.__workletHash = 14471027507603;
227
+ useLivenessCameraTs2.__pluginVersion = "0.8.3";
228
+ useLivenessCameraTs2.__initData = _worklet_14471027507603_init_data;
229
+ useLivenessCameraTs2.__stackDetails = _e;
230
+ return useLivenessCameraTs2;
231
+ }({
232
+ _worklet_14471027507603_init_data,
233
+ runAtTargetFps,
234
+ _worklet_11184642299290_init_data,
235
+ plugin,
236
+ handleFaceDataJS
237
+ }), [plugin, handleFaceDataJS]);
183
238
  useEffect(() => {
184
239
  return () => {
185
240
  frameScores.current = [];
@@ -1 +1 @@
1
- {"version":3,"names":["useCallback","useEffect","useMemo","useRef","useState","runAtTargetFps","useFrameProcessor","Worklets","useLivenessPlugin","getFeedback","rollingAverage","scoreFrame","WINDOW_SIZE","CONSECUTIVE_DECAY","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","frame","detectLiveness"],"sourceRoot":"../../src","sources":["useLivenessCamera.ts"],"mappings":"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","ignoreList":[]}
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 +1 @@
1
- {"version":3,"file":"LivenessCamera.d.ts","sourceRoot":"","sources":["../../../src/LivenessCamera.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,mBAAmB,EAAiB,MAAM,SAAS,CAAC;AAuIlE,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,mBAAmB,EACnB,OAAO,EACP,aAAiB,EACjB,iBAAwB,EACxB,aAAkB,EAClB,YAAmB,EACnB,UAAyB,EACzB,KAAK,GACN,EAAE,mBAAmB,2CA8FrB"}
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,aAAkB,EAClB,YAAmB,EACnB,UAAyB,EACzB,KAAK,GACN,EAAE,mBAAmB,2CA+FrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rick427/react-native-liveness",
3
- "version": "0.1.9",
3
+ "version": "0.2.1",
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",
@@ -75,8 +75,10 @@
75
75
  "react": "19.2.0",
76
76
  "react-native": "0.83.6",
77
77
  "react-native-builder-bob": "^0.41.0",
78
+ "react-native-reanimated": "^4.3.0",
78
79
  "react-native-svg": "^15.0.0",
79
80
  "react-native-vision-camera": "^4.0.0",
81
+ "react-native-worklets": "0.8.x",
80
82
  "react-native-worklets-core": "^1.3.3",
81
83
  "turbo": "^2.8.21",
82
84
  "typescript": "^6.0.2"
@@ -84,6 +86,7 @@
84
86
  "peerDependencies": {
85
87
  "react": "*",
86
88
  "react-native": "*",
89
+ "react-native-reanimated": ">=4.0.0",
87
90
  "react-native-svg": ">=13.0.0",
88
91
  "react-native-vision-camera": ">=4.0.0",
89
92
  "react-native-worklets-core": ">=1.0.0"
@@ -99,7 +102,8 @@
99
102
  [
100
103
  "module",
101
104
  {
102
- "esm": true
105
+ "esm": true,
106
+ "configFile": true
103
107
  }
104
108
  ],
105
109
  [
@@ -1,29 +1,54 @@
1
1
  import { useCallback, useEffect, useRef, useState } from 'react';
2
- import { Animated, StyleSheet, Text, View } from 'react-native';
2
+ import { Animated as RNAnimated, StyleSheet, Text, View } from 'react-native';
3
+ import Animated, {
4
+ cancelAnimation,
5
+ Easing,
6
+ useAnimatedProps,
7
+ useSharedValue,
8
+ withRepeat,
9
+ withSequence,
10
+ withTiming,
11
+ } from 'react-native-reanimated';
3
12
  import {
4
13
  Camera,
5
14
  useCameraDevice,
6
15
  useCameraFormat,
7
16
  useCameraPermission,
8
17
  } from 'react-native-vision-camera';
9
- import { Circle, Path, Svg } from 'react-native-svg';
18
+ import {
19
+ Circle,
20
+ ClipPath,
21
+ Defs,
22
+ G,
23
+ LinearGradient,
24
+ Path,
25
+ Rect,
26
+ Stop,
27
+ Svg,
28
+ } from 'react-native-svg';
10
29
  import { useLivenessCamera } from './useLivenessCamera';
11
30
  import type { LivenessCameraProps, LivenessState } from './types';
12
31
 
13
- const DEFAULT_FONT = 'Baloo-Medium';
32
+ // ─── Animated SVG components (Reanimated) ────────────────────────────────────
33
+ // createAnimatedComponent from react-native-reanimated properly drives SVG
34
+ // presentation attributes (strokeDashoffset, y, rotation) on the UI thread.
35
+ const AnimatedCircle = Animated.createAnimatedComponent(Circle);
36
+ const AnimatedG = Animated.createAnimatedComponent(G);
37
+ const AnimatedRect = Animated.createAnimatedComponent(Rect);
14
38
 
15
- // Circle diameter = 82 % of container width — large enough to fit any face
16
- // comfortably without the user needing to fiddle with distance.
39
+ // ─── Constants ────────────────────────────────────────────────────────────────
40
+ const DEFAULT_FONT = 'Baloo-Medium';
17
41
  const CIRCLE_DIAMETER_RATIO = 0.82;
18
42
  const STROKE_WIDTH = 3;
19
- // Cubic bezier approximation constant for a smooth circle path
20
- const K = 0.5523;
43
+ const K = 0.5523; // cubic bezier ellipse approximation
44
+ const SCAN_LINE_HEIGHT = 44; // px — height of the sweep bar
45
+ const BRACKET_SPAN_DEG = 44; // degrees each corner bracket spans
46
+ const BRACKET_STROKE = STROKE_WIDTH + 1;
21
47
 
48
+ // ─── Colour helper ────────────────────────────────────────────────────────────
22
49
  /**
23
- * Returns the stroke colour for the circle guide.
24
- *
25
50
  * ● White – no face / scanning (score < 0.4)
26
- * ● Yellow – face detected, confidence building (0.4 ≤ score < threshold)
51
+ * ● Yellow – face detected, confidence building
27
52
  * ● Green – liveness confirmed / countdown / capture
28
53
  * ● Red – error
29
54
  */
@@ -41,11 +66,8 @@ function getCircleColor(state: LivenessState, score: number): string {
41
66
  }
42
67
  }
43
68
 
44
- /**
45
- * Returns an SVG path string tracing a circle at (cx, cy) with radius r
46
- * using cubic bezier curves. Used inside a compound path with
47
- * fillRule="evenodd" to punch a transparent hole through the dark scrim.
48
- */
69
+ // ─── SVG path helpers ─────────────────────────────────────────────────────────
70
+ /** Cubic bezier circle path used inside compound evenodd scrim. */
49
71
  function circlePath(cx: number, cy: number, r: number): string {
50
72
  return [
51
73
  `M ${cx + r} ${cy}`,
@@ -57,41 +79,204 @@ function circlePath(cx: number, cy: number, r: number): string {
57
79
  ].join(' ');
58
80
  }
59
81
 
82
+ /** One corner bracket arc centred at `centerDeg`, spanning `spanDeg`. */
83
+ function bracketArcPath(
84
+ cx: number,
85
+ cy: number,
86
+ r: number,
87
+ centerDeg: number,
88
+ spanDeg: number
89
+ ): string {
90
+ const toRad = (d: number) => (d * Math.PI) / 180;
91
+ const a1 = toRad(centerDeg - spanDeg / 2);
92
+ const a2 = toRad(centerDeg + spanDeg / 2);
93
+ const x1 = cx + r * Math.cos(a1);
94
+ const y1 = cy + r * Math.sin(a1);
95
+ const x2 = cx + r * Math.cos(a2);
96
+ const y2 = cy + r * Math.sin(a2);
97
+ return `M ${x1} ${y1} A ${r} ${r} 0 0 1 ${x2} ${y2}`;
98
+ }
99
+
100
+ // ─── CircleOverlay ────────────────────────────────────────────────────────────
60
101
  function CircleOverlay({
61
102
  width,
62
103
  height,
63
104
  state,
64
105
  score,
106
+ livenessThreshold,
65
107
  }: {
66
108
  width: number;
67
109
  height: number;
68
110
  state: LivenessState;
69
111
  score: number;
112
+ livenessThreshold: number;
70
113
  }) {
71
- if (width === 0 || height === 0) return null;
114
+ // ── Shared values all hooks before any early return ─────────────────────
115
+ // scanProgress 0=top 1=bottom, ping-pongs continuously
116
+ const scanProgress = useSharedValue(0);
117
+ const scanOpacity = useSharedValue(1);
118
+ // bracketRot drives the slow bracket rotation in degrees
119
+ const bracketRot = useSharedValue(0);
120
+ // livenessProgress tracks smoothed score for the arc
121
+ const livenessProgress = useSharedValue(0);
72
122
 
123
+ // ── Geometry — computed before useAnimatedProps (safe when 0) ─────────────
73
124
  const cx = width / 2;
74
125
  const cy = height * 0.42;
75
126
  const r = (width * CIRCLE_DIAMETER_RATIO) / 2;
127
+ const circumference = 2 * Math.PI * r;
76
128
  const color = getCircleColor(state, score);
77
129
 
130
+ // ── Animated props — UI-thread worklets, deps rebuilt when geometry changes
131
+ const scanAnimProps = useAnimatedProps(
132
+ () => ({
133
+ // Map 0→1 progress onto the pixel range inside the circle
134
+ y: cy - r + 2 + scanProgress.value * (2 * r - SCAN_LINE_HEIGHT - 4),
135
+ opacity: scanOpacity.value,
136
+ }),
137
+ [cy, r]
138
+ );
139
+
140
+ const bracketAnimProps = useAnimatedProps(
141
+ () => ({
142
+ // react-native-svg accepts numeric rotation + origin instead of a string
143
+ rotation: bracketRot.value % 360,
144
+ originX: cx,
145
+ originY: cy,
146
+ }),
147
+ [cx, cy]
148
+ );
149
+
150
+ const progressAnimProps = useAnimatedProps(
151
+ () => ({
152
+ strokeDashoffset:
153
+ circumference -
154
+ (livenessProgress.value / livenessThreshold) * circumference,
155
+ }),
156
+ [circumference, livenessThreshold]
157
+ );
158
+
159
+ // ── Start scan line + bracket rotation on mount ───────────────────────────
160
+ useEffect(() => {
161
+ scanProgress.value = withRepeat(
162
+ withSequence(
163
+ withTiming(1, { duration: 1800, easing: Easing.linear }),
164
+ withTiming(0, { duration: 1800, easing: Easing.linear })
165
+ ),
166
+ -1,
167
+ false
168
+ );
169
+ bracketRot.value = withRepeat(
170
+ withTiming(360, { duration: 6000, easing: Easing.linear }),
171
+ -1,
172
+ false
173
+ );
174
+ return () => {
175
+ cancelAnimation(scanProgress);
176
+ cancelAnimation(bracketRot);
177
+ };
178
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
179
+
180
+ // ── On liveness confirmed: freeze brackets, fade scan line out ────────────
181
+ useEffect(() => {
182
+ if (state !== 'scanning') {
183
+ cancelAnimation(scanProgress);
184
+ cancelAnimation(bracketRot);
185
+ scanOpacity.value = withTiming(0, { duration: 350 });
186
+ }
187
+ }, [state]); // eslint-disable-line react-hooks/exhaustive-deps
188
+
189
+ // ── Drive progress arc from live score ────────────────────────────────────
190
+ useEffect(() => {
191
+ livenessProgress.value = withTiming(Math.min(score, livenessThreshold), {
192
+ duration: 180,
193
+ });
194
+ }, [score, livenessThreshold]); // eslint-disable-line react-hooks/exhaustive-deps
195
+
196
+ // ── Guard — render nothing until dimensions are known ─────────────────────
197
+ if (width === 0 || height === 0) return null;
198
+
199
+ // Scrim: full-screen rect with transparent circle cutout (evenodd rule)
78
200
  const scrimD = `M0 0H${width}V${height}H0Z ${circlePath(cx, cy, r)}`;
79
201
 
202
+ // 4 corner brackets at NE / SE / SW / NW diagonal positions
203
+ const bracketD = [45, 135, 225, 315]
204
+ .map((deg) => bracketArcPath(cx, cy, r, deg, BRACKET_SPAN_DEG))
205
+ .join(' ');
206
+
80
207
  return (
81
208
  <Svg style={StyleSheet.absoluteFill} width={width} height={height}>
209
+ {/* ── Definitions ─────────────────────────────────────────────────── */}
210
+ <Defs>
211
+ {/* Clip path: restrict scan line to circle area */}
212
+ <ClipPath id="liveness-circle-clip">
213
+ <Circle cx={cx} cy={cy} r={r} />
214
+ </ClipPath>
215
+
216
+ {/* Vertical gradient for the scan bar — fades at top and bottom */}
217
+ <LinearGradient id="scan-gradient" x1="0" y1="0" x2="0" y2="1">
218
+ <Stop offset="0" stopColor="#fff" stopOpacity="0" />
219
+ <Stop offset="0.25" stopColor="#fff" stopOpacity="0.65" />
220
+ <Stop offset="0.75" stopColor="#fff" stopOpacity="0.65" />
221
+ <Stop offset="1" stopColor="#fff" stopOpacity="0" />
222
+ </LinearGradient>
223
+ </Defs>
224
+
225
+ {/* ── Dark scrim with transparent circle cutout ────────────────────── */}
82
226
  <Path d={scrimD} fill="rgba(0,0,0,0.55)" fillRule="evenodd" />
227
+
228
+ {/* ── Dim base ring — always shows the circle boundary ─────────────── */}
83
229
  <Circle
230
+ cx={cx}
231
+ cy={cy}
232
+ r={r}
233
+ fill="none"
234
+ stroke="rgba(255,255,255,0.18)"
235
+ strokeWidth={1}
236
+ />
237
+
238
+ {/* ── Scan line — sweeps top → bottom, clipped to circle ───────────── */}
239
+ <G clipPath="url(#liveness-circle-clip)">
240
+ <AnimatedRect
241
+ x={cx - r}
242
+ width={r * 2}
243
+ height={SCAN_LINE_HEIGHT}
244
+ fill="url(#scan-gradient)"
245
+ animatedProps={scanAnimProps}
246
+ />
247
+ </G>
248
+
249
+ {/* ── Rotating corner brackets ─────────────────────────────────────── */}
250
+ <AnimatedG animatedProps={bracketAnimProps}>
251
+ <Path
252
+ d={bracketD}
253
+ fill="none"
254
+ stroke={color}
255
+ strokeWidth={BRACKET_STROKE}
256
+ strokeLinecap="round"
257
+ opacity={0.85}
258
+ />
259
+ </AnimatedG>
260
+
261
+ {/* ── Progress arc — draws in as liveness confidence builds ────────── */}
262
+ {/* transform rotates -90° so arc starts at 12 o'clock, goes clockwise */}
263
+ <AnimatedCircle
84
264
  cx={cx}
85
265
  cy={cy}
86
266
  r={r}
87
267
  fill="none"
88
268
  stroke={color}
89
269
  strokeWidth={STROKE_WIDTH}
270
+ strokeDasharray={circumference}
271
+ strokeLinecap="round"
272
+ transform={`rotate(-90, ${cx}, ${cy})`}
273
+ animatedProps={progressAnimProps}
90
274
  />
91
275
  </Svg>
92
276
  );
93
277
  }
94
278
 
279
+ // ─── CountdownBubble ──────────────────────────────────────────────────────────
95
280
  function CountdownBubble({
96
281
  value,
97
282
  fontFamily,
@@ -99,26 +284,26 @@ function CountdownBubble({
99
284
  value: number;
100
285
  fontFamily: string;
101
286
  }) {
102
- const scale = useRef(new Animated.Value(0)).current;
103
- const opacity = useRef(new Animated.Value(0)).current;
287
+ const scale = useRef(new RNAnimated.Value(0)).current;
288
+ const opacity = useRef(new RNAnimated.Value(0)).current;
104
289
 
105
290
  useEffect(() => {
106
- Animated.parallel([
107
- Animated.sequence([
108
- Animated.spring(scale, {
291
+ RNAnimated.parallel([
292
+ RNAnimated.sequence([
293
+ RNAnimated.spring(scale, {
109
294
  toValue: 1.2,
110
295
  stiffness: 200,
111
296
  damping: 6,
112
297
  useNativeDriver: true,
113
298
  }),
114
- Animated.spring(scale, {
299
+ RNAnimated.spring(scale, {
115
300
  toValue: 1.0,
116
301
  stiffness: 150,
117
302
  damping: 8,
118
303
  useNativeDriver: true,
119
304
  }),
120
305
  ]),
121
- Animated.timing(opacity, {
306
+ RNAnimated.timing(opacity, {
122
307
  toValue: 1,
123
308
  duration: 150,
124
309
  useNativeDriver: true,
@@ -126,7 +311,7 @@ function CountdownBubble({
126
311
  ]).start();
127
312
 
128
313
  return () => {
129
- Animated.timing(opacity, {
314
+ RNAnimated.timing(opacity, {
130
315
  toValue: 0,
131
316
  duration: 200,
132
317
  useNativeDriver: true,
@@ -135,14 +320,15 @@ function CountdownBubble({
135
320
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
136
321
 
137
322
  return (
138
- <Animated.View
323
+ <RNAnimated.View
139
324
  style={[styles.countdownBubble, { opacity, transform: [{ scale }] }]}
140
325
  >
141
326
  <Text style={[styles.countdownText, { fontFamily }]}>{value}</Text>
142
- </Animated.View>
327
+ </RNAnimated.View>
143
328
  );
144
329
  }
145
330
 
331
+ // ─── LivenessCamera ───────────────────────────────────────────────────────────
146
332
  export function LivenessCamera({
147
333
  onCapture,
148
334
  onLivenessConfirmed,
@@ -227,6 +413,7 @@ export function LivenessCamera({
227
413
  height={containerSize.height}
228
414
  state={livenessState}
229
415
  score={livenessScore}
416
+ livenessThreshold={livenessThreshold}
230
417
  />
231
418
  {livenessState !== 'done' && (
232
419
  <View style={styles.feedbackContainer}>
@@ -249,6 +436,7 @@ export function LivenessCamera({
249
436
  );
250
437
  }
251
438
 
439
+ // ─── Styles ───────────────────────────────────────────────────────────────────
252
440
  const styles = StyleSheet.create({
253
441
  root: {
254
442
  flex: 1,