@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 +115 -32
- package/lib/module/LivenessCamera.js +276 -27
- package/lib/module/LivenessCamera.js.map +1 -1
- package/lib/module/LivenessDetector.js +27 -7
- package/lib/module/LivenessDetector.js.map +1 -1
- package/lib/module/useLivenessCamera.js +67 -12
- package/lib/module/useLivenessCamera.js.map +1 -1
- package/lib/typescript/src/LivenessCamera.d.ts.map +1 -1
- package/package.json +6 -2
- package/src/LivenessCamera.tsx +214 -26
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
|
-
-
|
|
20
|
-
-
|
|
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
|
-
-
|
|
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
|
|
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
|
-
|
|
59
|
-
|
|
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
|
|
68
|
+
> **Already have both plugins?** Just confirm both lines are present — order matters, Reanimated must come after worklets-core.
|
|
65
69
|
|
|
66
|
-
After updating
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
184
|
+
#### `LivenessCamera` props
|
|
119
185
|
|
|
120
186
|
| Prop | Type | Default | Description |
|
|
121
187
|
|---|---|---|---|
|
|
122
|
-
| `onCapture` | `(result: CaptureResult) => void` | **required** | Fired after photo is
|
|
123
|
-
| `onLivenessConfirmed` | `() => void` | — | Fired the moment liveness is confirmed, before
|
|
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
|
|
127
|
-
| `confirmFrames` | `number` | `
|
|
128
|
-
| `soundEnabled` | `boolean` | `true` | Play
|
|
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
|
-
|
|
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
|
|
151
|
-
| Head pose | 30% | Yaw < ±
|
|
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
|
|
243
|
+
Camera (60 fps preview)
|
|
162
244
|
↓ [worklet thread — Vision Camera frame processor]
|
|
163
|
-
Native plugin (Swift / Kotlin)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
↓ [
|
|
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()
|
|
250
|
+
→ scoreFrame() — soft-edge signals, weighted sum
|
|
169
251
|
→ rolling 20-frame window
|
|
170
|
-
→
|
|
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
|
-
|
|
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
|
-
//
|
|
12
|
-
|
|
17
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
18
|
+
const DEFAULT_FONT = 'Baloo-Medium';
|
|
13
19
|
const CIRCLE_DIAMETER_RATIO = 0.82;
|
|
14
20
|
const STROKE_WIDTH = 3;
|
|
15
|
-
|
|
16
|
-
const
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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__*/
|
|
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
|
|
83
|
-
const opacity = useRef(new
|
|
326
|
+
const scale = useRef(new RNAnimated.Value(0)).current;
|
|
327
|
+
const opacity = useRef(new RNAnimated.Value(0)).current;
|
|
84
328
|
useEffect(() => {
|
|
85
|
-
|
|
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
|
-
}),
|
|
334
|
+
}), RNAnimated.spring(scale, {
|
|
91
335
|
toValue: 1.0,
|
|
92
336
|
stiffness: 150,
|
|
93
337
|
damping: 8,
|
|
94
338
|
useNativeDriver: true
|
|
95
|
-
})]),
|
|
339
|
+
})]), RNAnimated.timing(opacity, {
|
|
96
340
|
toValue: 1,
|
|
97
341
|
duration: 150,
|
|
98
342
|
useNativeDriver: true
|
|
99
343
|
})]).start();
|
|
100
344
|
return () => {
|
|
101
|
-
|
|
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(
|
|
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":";;AAAA,SAASA,WAAW,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AAChE,SAASC,QAAQ,EAAEC,UAAU,EAAEC,IAAI,EAAEC,IAAI,QAAQ,cAAc;AAC/D,SACEC,MAAM,EACNC,eAAe,EACfC,eAAe,EACfC,mBAAmB,QACd,4BAA4B;AACnC,SAASC,MAAM,EAAEC,IAAI,EAAEC,GAAG,QAAQ,kBAAkB;AACpD,SAASC,iBAAiB,QAAQ,wBAAqB;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAGxD,MAAMC,YAAY,GAAG,cAAc;;AAEnC;AACA;AACA,MAAMC,qBAAqB,GAAG,IAAI;AAClC,MAAMC,YAAY,GAAG,CAAC;AACtB;AACA,MAAMC,CAAC,GAAG,MAAM;;AAEhB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,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;AACA;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,GAAGP,CAAC,IAAIK,EAAE,GAAGE,CAAC,GAAGP,CAAC,IAAIM,EAAE,GAAGC,CAAC,IAAIF,EAAE,IAAIC,EAAE,GAAGC,CAAC,EAAE,EACnE,KAAKF,EAAE,GAAGE,CAAC,GAAGP,CAAC,IAAIM,EAAE,GAAGC,CAAC,IAAIF,EAAE,GAAGE,CAAC,IAAID,EAAE,GAAGC,CAAC,GAAGP,CAAC,IAAIK,EAAE,GAAGE,CAAC,IAAID,EAAE,EAAE,EACnE,KAAKD,EAAE,GAAGE,CAAC,IAAID,EAAE,GAAGC,CAAC,GAAGP,CAAC,IAAIK,EAAE,GAAGE,CAAC,GAAGP,CAAC,IAAIM,EAAE,GAAGC,CAAC,IAAIF,EAAE,IAAIC,EAAE,GAAGC,CAAC,EAAE,EACnE,KAAKF,EAAE,GAAGE,CAAC,GAAGP,CAAC,IAAIM,EAAE,GAAGC,CAAC,IAAIF,EAAE,GAAGE,CAAC,IAAID,EAAE,GAAGC,CAAC,GAAGP,CAAC,IAAIK,EAAE,GAAGE,CAAC,IAAID,EAAE,EAAE,EACnE,GAAG,CACJ,CAACE,IAAI,CAAC,GAAG,CAAC;AACb;AAEA,SAASC,aAAaA,CAAC;EACrBC,KAAK;EACLC,MAAM;EACNT,KAAK;EACLC;AAMF,CAAC,EAAE;EACD,IAAIO,KAAK,KAAK,CAAC,IAAIC,MAAM,KAAK,CAAC,EAAE,OAAO,IAAI;EAE5C,MAAMN,EAAE,GAAGK,KAAK,GAAG,CAAC;EACpB,MAAMJ,EAAE,GAAGK,MAAM,GAAG,IAAI;EACxB,MAAMJ,CAAC,GAAIG,KAAK,GAAGZ,qBAAqB,GAAI,CAAC;EAC7C,MAAMc,KAAK,GAAGX,cAAc,CAACC,KAAK,EAAEC,KAAK,CAAC;EAE1C,MAAMU,MAAM,GAAG,QAAQH,KAAK,IAAIC,MAAM,OAAOP,UAAU,CAACC,EAAE,EAAEC,EAAE,EAAEC,CAAC,CAAC,EAAE;EAEpE,oBACEX,KAAA,CAACL,GAAG;IAACuB,KAAK,EAAEhC,UAAU,CAACiC,YAAa;IAACL,KAAK,EAAEA,KAAM;IAACC,MAAM,EAAEA,MAAO;IAAAK,QAAA,gBAChEtB,IAAA,CAACJ,IAAI;MAAC2B,CAAC,EAAEJ,MAAO;MAACK,IAAI,EAAC,kBAAkB;MAACC,QAAQ,EAAC;IAAS,CAAE,CAAC,eAC9DzB,IAAA,CAACL,MAAM;MACLgB,EAAE,EAAEA,EAAG;MACPC,EAAE,EAAEA,EAAG;MACPC,CAAC,EAAEA,CAAE;MACLW,IAAI,EAAC,MAAM;MACXE,MAAM,EAAER,KAAM;MACdS,WAAW,EAAEtB;IAAa,CAC3B,CAAC;EAAA,CACC,CAAC;AAEV;AAEA,SAASuB,eAAeA,CAAC;EACvBC,KAAK;EACLC;AAIF,CAAC,EAAE;EACD,MAAMC,KAAK,GAAG9C,MAAM,CAAC,IAAIE,QAAQ,CAAC6C,KAAK,CAAC,CAAC,CAAC,CAAC,CAACC,OAAO;EACnD,MAAMC,OAAO,GAAGjD,MAAM,CAAC,IAAIE,QAAQ,CAAC6C,KAAK,CAAC,CAAC,CAAC,CAAC,CAACC,OAAO;EAErDjD,SAAS,CAAC,MAAM;IACdG,QAAQ,CAACgD,QAAQ,CAAC,CAChBhD,QAAQ,CAACiD,QAAQ,CAAC,CAChBjD,QAAQ,CAACkD,MAAM,CAACN,KAAK,EAAE;MACrBO,OAAO,EAAE,GAAG;MACZC,SAAS,EAAE,GAAG;MACdC,OAAO,EAAE,CAAC;MACVC,eAAe,EAAE;IACnB,CAAC,CAAC,EACFtD,QAAQ,CAACkD,MAAM,CAACN,KAAK,EAAE;MACrBO,OAAO,EAAE,GAAG;MACZC,SAAS,EAAE,GAAG;MACdC,OAAO,EAAE,CAAC;MACVC,eAAe,EAAE;IACnB,CAAC,CAAC,CACH,CAAC,EACFtD,QAAQ,CAACuD,MAAM,CAACR,OAAO,EAAE;MACvBI,OAAO,EAAE,CAAC;MACVK,QAAQ,EAAE,GAAG;MACbF,eAAe,EAAE;IACnB,CAAC,CAAC,CACH,CAAC,CAACG,KAAK,CAAC,CAAC;IAEV,OAAO,MAAM;MACXzD,QAAQ,CAACuD,MAAM,CAACR,OAAO,EAAE;QACvBI,OAAO,EAAE,CAAC;QACVK,QAAQ,EAAE,GAAG;QACbF,eAAe,EAAE;MACnB,CAAC,CAAC,CAACG,KAAK,CAAC,CAAC;IACZ,CAAC;EACH,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;;EAER,oBACE5C,IAAA,CAACb,QAAQ,CAACG,IAAI;IACZ8B,KAAK,EAAE,CAACyB,MAAM,CAACC,eAAe,EAAE;MAAEZ,OAAO;MAAEa,SAAS,EAAE,CAAC;QAAEhB;MAAM,CAAC;IAAE,CAAC,CAAE;IAAAT,QAAA,eAErEtB,IAAA,CAACX,IAAI;MAAC+B,KAAK,EAAE,CAACyB,MAAM,CAACG,aAAa,EAAE;QAAElB;MAAW,CAAC,CAAE;MAAAR,QAAA,EAAEO;IAAK,CAAO;EAAC,CACtD,CAAC;AAEpB;AAEA,OAAO,SAASoB,cAAcA,CAAC;EAC7BC,SAAS;EACTC,mBAAmB;EACnBC,OAAO;EACPC,aAAa,GAAG,CAAC;EACjBC,iBAAiB,GAAG,IAAI;EACxBC,aAAa,GAAG,EAAE;EAClBC,YAAY,GAAG,IAAI;EACnB1B,UAAU,GAAG3B,YAAY;EACzBiB;AACmB,CAAC,EAAE;EACtB,MAAM;IAAEqC,aAAa;IAAEC;EAAkB,CAAC,GAAGhE,mBAAmB,CAAC,CAAC;EAClE,MAAMiE,MAAM,GAAGnE,eAAe,CAAC,OAAO,CAAC;EACvC,MAAMoE,MAAM,GAAGnE,eAAe,CAACkE,MAAM,EAAE,CAAC;IAAEE,GAAG,EAAE;EAAG,CAAC,CAAC,CAAC;EACrD,MAAMA,GAAG,GAAGC,IAAI,CAACC,GAAG,CAACH,MAAM,EAAEI,MAAM,IAAI,EAAE,EAAE,EAAE,CAAC;EAC9C,MAAMC,SAAS,GAAGhF,MAAM,CAAS,IAAI,CAAC;EACtC,MAAM,CAACiF,aAAa,EAAEC,gBAAgB,CAAC,GAAGjF,QAAQ,CAAC;IAAE8B,KAAK,EAAE,CAAC;IAAEC,MAAM,EAAE;EAAE,CAAC,CAAC;EAE3E,MAAM;IAAEmD,cAAc;IAAEC,aAAa;IAAEC,aAAa;IAAEC,SAAS;IAAEC;EAAS,CAAC,GACzE1E,iBAAiB,CAAC;IAChBwD,iBAAiB;IACjBC,aAAa;IACbF,aAAa;IACbG,YAAY;IACZS,SAAS;IACTf,SAAS;IACTC,mBAAmB;IACnBC;EACF,CAAC,CAAC;EAEJ,MAAMqB,YAAY,GAAG1F,WAAW,CAC7B2F,CAAiE,IAAK;IACrE,MAAM;MAAE1D,KAAK;MAAEC;IAAO,CAAC,GAAGyD,CAAC,CAACC,WAAW,CAACC,MAAM;IAC9CT,gBAAgB,CAAC;MAAEnD,KAAK;MAAEC;IAAO,CAAC,CAAC;EACrC,CAAC,EACD,EACF,CAAC;EAEDjC,SAAS,CAAC,MAAM;IACd,IAAI,CAACyE,aAAa,EAAE;MAClBC,iBAAiB,CAAC,CAAC,CAACmB,KAAK,CAAC,MAAM;QAC9BzB,OAAO,GAAG,IAAI0B,KAAK,CAAC,0BAA0B,CAAC,CAAC;MAClD,CAAC,CAAC;IACJ;EACF,CAAC,EAAE,CAACrB,aAAa,EAAEC,iBAAiB,EAAEN,OAAO,CAAC,CAAC;EAE/C,IAAI,CAACK,aAAa,EAAE;IAClB,oBACEzD,IAAA,CAACV,IAAI;MAAC8B,KAAK,EAAE,CAACyB,MAAM,CAACkC,IAAI,EAAE3D,KAAK,EAAEyB,MAAM,CAACmC,QAAQ,CAAE;MAAA1D,QAAA,eACjDtB,IAAA,CAACX,IAAI;QAAC+B,KAAK,EAAE,CAACyB,MAAM,CAACoC,cAAc,EAAE;UAAEnD;QAAW,CAAC,CAAE;QAAAR,QAAA,EAAC;MAEtD,CAAM;IAAC,CACH,CAAC;EAEX;EAEA,IAAI,CAACqC,MAAM,EAAE;IACX,oBACE3D,IAAA,CAACV,IAAI;MAAC8B,KAAK,EAAE,CAACyB,MAAM,CAACkC,IAAI,EAAE3D,KAAK,EAAEyB,MAAM,CAACmC,QAAQ,CAAE;MAAA1D,QAAA,eACjDtB,IAAA,CAACX,IAAI;QAAC+B,KAAK,EAAE,CAACyB,MAAM,CAACoC,cAAc,EAAE;UAAEnD;QAAW,CAAC,CAAE;QAAAR,QAAA,EAAC;MAEtD,CAAM;IAAC,CACH,CAAC;EAEX;EAEA,oBACEpB,KAAA,CAACZ,IAAI;IAAC8B,KAAK,EAAE,CAACyB,MAAM,CAACkC,IAAI,EAAE3D,KAAK,CAAE;IAAC8D,QAAQ,EAAET,YAAa;IAAAnD,QAAA,gBACxDtB,IAAA,CAACT,MAAM;MACL4F,GAAG,EAAElB,SAAU;MACf7C,KAAK,EAAEhC,UAAU,CAACiC,YAAa;MAC/BsC,MAAM,EAAEA,MAAO;MACfyB,QAAQ,EAAEf,aAAa,KAAK,MAAM,IAAIA,aAAa,KAAK,OAAQ;MAChED,cAAc,EAAEA,cAAe;MAC/BiB,KAAK;MACLC,WAAW,EAAC,KAAK;MACjB1B,MAAM,EAAEA,MAAO;MACfC,GAAG,EAAEA;IAAI,CACV,CAAC,eACF7D,IAAA,CAACe,aAAa;MACZC,KAAK,EAAEkD,aAAa,CAAClD,KAAM;MAC3BC,MAAM,EAAEiD,aAAa,CAACjD,MAAO;MAC7BT,KAAK,EAAE6D,aAAc;MACrB5D,KAAK,EAAE6D;IAAc,CACtB,CAAC,EACDD,aAAa,KAAK,MAAM,iBACvBrE,IAAA,CAACV,IAAI;MAAC8B,KAAK,EAAEyB,MAAM,CAAC0C,iBAAkB;MAAAjE,QAAA,eACpCtB,IAAA,CAACX,IAAI;QAAC+B,KAAK,EAAE,CAACyB,MAAM,CAAC2C,YAAY,EAAE;UAAE1D;QAAW,CAAC,CAAE;QAAAR,QAAA,EAAEkD;MAAQ,CAAO;IAAC,CACjE,CACP,EACAH,aAAa,KAAK,WAAW,IAAIE,SAAS,KAAK,IAAI,iBAClDvE,IAAA,CAACV,IAAI;MAAC8B,KAAK,EAAEyB,MAAM,CAAC4C,kBAAmB;MAAAnE,QAAA,eACrCtB,IAAA,CAAC4B,eAAe;QAEdC,KAAK,EAAE0C,SAAU;QACjBzC,UAAU,EAAEA;MAAW,GAFlByC,SAGN;IAAC,CACE,CACP,EACAF,aAAa,KAAK,WAAW,iBAC5BrE,IAAA,CAACV,IAAI;MAAC8B,KAAK,EAAEyB,MAAM,CAAC6C,YAAa;MAACC,aAAa,EAAC;IAAM,CAAE,CACzD;EAAA,CACG,CAAC;AAEX;AAEA,MAAM9C,MAAM,GAAGzD,UAAU,CAACwG,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/D,KAAK,EAAE,MAAM;IACbgF,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;IACZtE,KAAK,EAAE,MAAM;IACbgF,QAAQ,EAAE,EAAE;IACZC,SAAS,EAAE,QAAQ;IACnBM,eAAe,EAAE,iBAAiB;IAClCC,gBAAgB,EAAE;MAAE1F,KAAK,EAAE,CAAC;MAAEC,MAAM,EAAE;IAAE,CAAC;IACzC0F,gBAAgB,EAAE;EACpB,CAAC;EACDlB,kBAAkB,EAAE;IAClB,GAAGrG,UAAU,CAACwH,kBAAkB;IAChCZ,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE;EACd,CAAC;EACDnD,eAAe,EAAE;IACf9B,KAAK,EAAE,EAAE;IACTC,MAAM,EAAE,EAAE;IACV4F,YAAY,EAAE,EAAE;IAChBf,eAAe,EAAE,wBAAwB;IACzCgB,WAAW,EAAE,CAAC;IACdC,WAAW,EAAE,MAAM;IACnBf,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE;EACd,CAAC;EACDjD,aAAa,EAAE;IACb9B,KAAK,EAAE,MAAM;IACbgF,QAAQ,EAAE,EAAE;IACZc,UAAU,EAAE;EACd,CAAC;EACDtB,YAAY,EAAE;IACZ,GAAGtG,UAAU,CAACwH,kBAAkB;IAChCd,eAAe,EAAE,MAAM;IACvB5D,OAAO,EAAE;EACX;AACF,CAAC,CAAC","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":"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","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:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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;
|
|
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(
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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":";;AAAA,SAASA,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AAEzE,SAASC,cAAc,EAAEC,iBAAiB,QAAQ,4BAA4B;AAC9E,SAASC,QAAQ,QAAQ,4BAA4B;AACrD,SAASC,iBAAiB,QAAQ,uBAAoB;AACtD,SAASC,WAAW,EAAEC,cAAc,EAAEC,UAAU,QAAQ,sBAAmB;AAQ3E,MAAMC,WAAW,GAAG,EAAE;AACtB;AACA;AACA,MAAMC,iBAAiB,GAAG,CAAC;
|
|
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":"
|
|
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
|
|
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
|
[
|
package/src/LivenessCamera.tsx
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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
|
-
//
|
|
16
|
-
|
|
39
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
40
|
+
const DEFAULT_FONT = 'Baloo-Medium';
|
|
17
41
|
const CIRCLE_DIAMETER_RATIO = 0.82;
|
|
18
42
|
const STROKE_WIDTH = 3;
|
|
19
|
-
|
|
20
|
-
const
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
103
|
-
const opacity = useRef(new
|
|
287
|
+
const scale = useRef(new RNAnimated.Value(0)).current;
|
|
288
|
+
const opacity = useRef(new RNAnimated.Value(0)).current;
|
|
104
289
|
|
|
105
290
|
useEffect(() => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
<
|
|
323
|
+
<RNAnimated.View
|
|
139
324
|
style={[styles.countdownBubble, { opacity, transform: [{ scale }] }]}
|
|
140
325
|
>
|
|
141
326
|
<Text style={[styles.countdownText, { fontFamily }]}>{value}</Text>
|
|
142
|
-
</
|
|
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,
|