@richard.fadiora/liveness-detection 4.3.7 → 4.3.9

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
@@ -1,294 +1,409 @@
1
1
  # Liveness Detection SDK
2
2
 
3
- A cross-framework **liveness detection SDK** that performs randomized user challenges and verifies real-user presence via a backend anti-spoofing API. Works with **React** and **Angular** via framework-specific wrappers while the **core engine is framework-agnostic**.
4
3
 
5
- This version introduces:
6
4
 
7
- - **Headless mode** for fully custom UI
8
- - Robust **challenge sequencing**
9
- - **Configurable thresholds** for `Smile`, `Blink`, and `Turn_Head` challenges
10
- - Sequential challenge execution with **strict timeout handling**
11
- - Pause between steps for user feedback
12
- - Cross-framework integration (React hook & Angular service)
5
+ A cross-framework **liveness detection SDK** that performs randomized user challenges and verifies real-user presence via a backend anti-spoofing API.
6
+ This package provides a **framework-agnostic core** with optimized wrappers for **React ⚛️** and **Angular 🅰️**.
13
7
 
14
- ---
8
+ * * *
9
+
10
+ ## 🚀 Key Features in v4.3.9
11
+
12
+
13
+
14
+ * 📦 **Multi-Entry Support**: Dedicated subpaths for React and Angular to prevent framework leakage.
15
+
16
+ * 🎨 **Prop-Driven Styling**: Fully customizable UI using class name injection (Tailwind/Bootstrap friendly).
17
+
18
+ * 🧠 **Headless Mode**: Access core logic via hooks (React) or services (Angular) for 100% custom UI.
19
+
20
+ * 🅰️ **Standalone Angular Support**: Angular wrapper uses standalone components; no NgModules needed.
21
+
22
+ * 🔒 **Improved Security**: Enhanced challenge sequencing with strict timeout handling and backend frame verification.
23
+
24
+
25
+ * * *
15
26
 
16
27
  ## 📌 Overview
17
28
 
29
+
30
+
18
31
  This SDK strengthens identity verification by combining:
19
32
 
20
- - Randomized challenge-response validation
21
- - Sequential challenge execution
22
- - Strict timeout enforcement
23
- - Backend spoof detection
24
- - Callback-based integration for easy usage
25
- - Headless / fully customizable UI via render props (React)
26
- - Configurable challenge thresholds
33
+ * 🎲 Randomized challenge-response validation
34
+
35
+ * 📋 Sequential challenge execution (Smile, Blink, Turn\_Head, Thumbs\_Up)
36
+
37
+ * 🧠 Real-time MediaPipe face & hand landmark detection
38
+
39
+ * 🛡️ Protection against presentation attacks (photo/video), glare, and replay attacks
40
+
27
41
 
28
- Protects against:
42
+ * * *
29
43
 
30
- - Presentation (photo) attacks
31
- - Screen glare attacks
32
- - Video replay/injection attacks
44
+ ## 📦 Installation & Imports
33
45
 
34
- ---
35
46
 
36
- ## ⚙️ Architecture
37
47
 
38
- ### Core Engine
48
+ `npm install @richard.fadiora/liveness-detection`
39
49
 
40
- - `LivenessEngine` (framework-agnostic)
41
- - Handles:
42
- - Challenge sequence generation
43
- - MediaPipe face & hand model detection
44
- - Challenge validation (`Smile`, `Blink`, `Turn_Head`, `Thumbs_Up`)
45
- - Face cropping
46
- - Detection loop
47
- - Final frame capture and backend verification
48
- - Can be used directly or via React/Angular wrappers
50
+ ### Import Paths
49
51
 
50
- ### Framework Wrappers
52
+ #
51
53
 
52
- | Framework | Wrapper | Notes |
53
- |-----------|--------|------|
54
- | React | `useLiveness` hook | Uses `webcamRef` and React state, supports render-prop customization |
55
- | Angular | `LivenessService` | Injectable service, exposes engine state and control methods. Must be imported with "@richard.fadiora/liveness-detection/angular |
54
+ | Target | Import Path |
55
+ | --- | --- |
56
+ | Pure Logic (Core) | @richard.fadiora/liveness-detection |
57
+ | React Wrapper ⚛️ | @richard.fadiora/liveness-detection/react |
58
+ | Angular Wrapper 🅰️ | @richard.fadiora/liveness-detection/angular |
56
59
 
57
- ---
60
+ These entry points ensure framework-specific code stays isolated and bundles remain small.
58
61
 
59
- ## ⚙️ How It Works
62
+ * * *
60
63
 
61
- ### 1️⃣ Challenge Initialization
64
+ ## 🧩 Framework Usage
62
65
 
63
- - Randomly selects **3 challenges** from the pool: `Smile`, `Blink`, `Turn_Head`, `Thumbs_Up`.
64
- - Timer starts immediately (default **60 seconds**, configurable via `duration`).
65
- - Each challenge is verified sequentially, with a brief pause between steps for feedback.
66
- - If the timer expires, the session terminates and no frames are sent to the backend.
66
+ ### 🅰️ Angular Implementation (Standalone)
67
67
 
68
- ### 2️⃣ Challenge Execution
68
+ #
69
69
 
70
- - Real-time validation using webcam input and MediaPipe models.
71
- - Sequential verification ensures **no steps are skipped**.
72
- - Developers can render custom UI via the **render prop** while using the same underlying logic.
73
- - Challenge thresholds are configurable through props:
70
+ The Angular wrapper is now **standalone**. Import it directly into your component’s `imports` array without using a module:
74
71
 
75
- | Prop Name | Default | Description |
76
- |-----------------------|---------|------------------------------------------|
77
- | `smileThreshold` | 0.20 | Minimum smile width to count as valid |
78
- | `blinkThreshold` | 0.01 | Maximum eye aspect ratio to count as blink |
79
- | `minturnHeadThreshold`| 0.15 | Minimum yaw for right head turn detection |
80
- | `maxturnHeadThreshold`| 0.85 | Maximum yaw for left head turn detection |
72
+ import { Component } from '@angular/core';
73
+ import { LivenessComponent } from '@richard.fadiora/liveness-detection/angular';
74
+
75
+ @Component({
76
+ selector: 'app-verify',
77
+ standalone: true,
78
+ imports: \[LivenessComponent\],
79
+ template: \`
80
+ <LivenessCheck
81
+ \[apiUrl\]="'https://api.yoursite.com/verify'"
82
+ \[containerClass\]="'my-custom-container'"
83
+ \[buttonClass\]="'btn-primary'"
84
+ (onComplete)="handleSuccess($event)"
85
+ (onError)="handleError($event)">
86
+ </LivenessCheck>
87
+ \`
88
+ })
89
+ export class VerifyComponent {
90
+
91
+ handleSuccess(result: any) {
92
+ console.log("Image Captured:", result.image);
93
+ }
94
+
95
+ handleError(error: any) {
96
+ console.error(error.reason);
97
+ }
98
+
99
+ }
81
100
 
82
- ### 3️⃣ Backend Liveness Verification
101
+ ⚠️ **Important Rule:** Standalone components **must not** be declared in an NgModule. Doing so disables standalone behavior and can cause runtime errors.
83
102
 
84
- - Captures **5 frames** from the webcam after all challenges are complete.
85
- - Frames sent to backend API (`apiUrl` prop).
86
- - Backend performs spoof detection, glare detection, and video injection detection.
103
+ * * *
87
104
 
88
- ---
105
+ ### ⚛️ React Implementation
89
106
 
90
- ## ✅ Success & Failure Behavior
107
+ #
91
108
 
92
- ### Success
93
- - UI (or custom component) shows success feedback.
94
- - `onComplete` callback is triggered:
95
- ```js
96
- onComplete({ success: true, image: frame, skinConfidence });
97
- ```
109
+ import { LivenessSDK } from "@richard.fadiora/liveness-detection/react";
110
+
111
+ function App() {
112
+ return (
113
+ <LivenessSDK
114
+ apiUrl\="https://api.yoursite.com/verify"
115
+ classNames\={{ container: "p-4 bg-dark", video: "rounded-lg" }}
116
+ onComplete\={(res) => console.log("Success:", res.image)}
117
+ onError\={(err) => console.error(err.reason)}
118
+ />
119
+ );
120
+ }
98
121
 
99
- ### Failure
100
- - UI shows failure message.
101
- - `onError` callback is triggered:
102
- ```js
103
- onError({ success: false, reason, skinConfidence: null });
104
- ```
105
- - Component resets; user must start a new session.
122
+ * * *
106
123
 
107
- ---
124
+ ## 🎨 Prop-Driven Styling
108
125
 
109
- ## 📦 Props
110
126
 
111
- | Prop Name | Type | Required | Description |
112
- |------------|-----------------------------|----------|-------------|
113
- | `apiUrl` | `string` | Yes | Backend endpoint used for liveness verification |
114
- | `onComplete` | `(result: object) => void` | Yes | Callback fired after verification succeeds |
115
- | `onError` | `(result: object) => void` | Yes | Callback fired after verification fails |
116
- | `duration` | `number` | No | Maximum time for all challenges (default: 60s) |
117
- | `render` | `(sdk: object) => JSX.Element` | No | Optional render prop for full UI customization |
118
- | `classNames` | `object` | No | Optional CSS class names to customize default UI |
119
- | `smileThreshold` | `number` | No | Minimum smile width for Smile challenge |
120
- | `blinkThreshold` | `number` | No | Maximum eye aspect ratio for Blink challenge |
121
- | `minturnHeadThreshold` | `number` | No | Minimum yaw for Turn_Head challenge |
122
- | `maxturnHeadThreshold` | `number` | No | Maximum yaw for Turn_Head challenge |
123
127
 
128
+ | Angular Input | React Prop | Description |
129
+ | --- | --- | --- |
130
+ | `containerClass` | classNames.container | Main wrapper div |
131
+ | `videoClass` | classNames.webcam | The video element |
132
+ | `buttonClass` | classNames.button | The Start button |
133
+ | `timerClass` | classNames.timer | Countdown timer text |
134
+ | `instructionBoxClass` | classNames.challenge | Challenge instruction box |
135
+ | `statusOverlayClass` | classNames.overlay | Overlay during verification |
136
+ | `errorMessageClass` | classNames.error | Wrapper for error messages |
124
137
 
125
- ---
138
+ * * *
139
+ ## Customizing Challenge Labels
126
140
 
127
- ## 🧩 Usage Example
128
141
 
129
- ### Default UI
130
- ```jsx
131
- import { LivenessSDK } from "@richard.fadiora/liveness-detection";
132
142
 
133
- function App() {
134
- return (
135
- <LivenessSDK
136
- apiUrl="https://your-backend-api.com/liveness-check"
137
- onComplete={(result) => console.log("Success:", result)}
138
- onError={(error) => console.log("Failed:", error.reason)}
139
- duration={60}
140
- />
141
- );
142
- }
143
+ You can override the default technical strings (e.g., `Thumbs_Up`) with user-friendly text or different languages using the `challengeMapping` input.
143
144
 
144
- export default App;
145
- ```
146
-
147
- ### Headless / Custom UI
148
- ```jsx
149
- <LivenessSDK
150
- apiUrl="https://your-backend-api.com/liveness-check"
151
- onComplete={handleComplete}
152
- onError={handleError}
153
- render={(sdk) => (
154
- <div>
155
- <video ref={sdk.webcamRef} autoPlay playsInline muted />
156
- <div>Step {sdk.currentStep + 1}: {sdk.sequence[sdk.currentStep]}</div>
157
- <div>Time left: {sdk.timeLeft}s</div>
158
- <button onClick={sdk.start}>Start</button>
159
- </div>
160
- )}
161
- />
162
- ```
163
- ## 📤 Hook Return Values
164
-
165
- The `useLiveness` hook exposes the following values and control functions for managing the liveness detection session.
166
-
167
- | Name | Type | Description |
168
- |-----|------|-------------|
169
- | `webcamRef` | `ref` | React ref attached to the webcam component. Provides access to the live video stream used for face and hand detection as well as frame capture for verification. |
170
- | `status` | `string` | Represents the current state of the liveness session. Possible values include `loading`, `ready`, `capturing`, `verifying`, `success`, `error`, and `expired`. |
171
- | `errorMsg` | `string` | Contains the error message displayed when the liveness verification fails or when the system encounters an issue. |
172
- | `sequence` | `string[]` | The randomized sequence of liveness challenges selected for the current session. Three challenges are chosen from the challenge pool. |
173
- | `currentStep` | `number` | The index of the current challenge being performed within the challenge sequence. |
174
- | `timeLeft` | `number` | Remaining time (in seconds) before the session expires. The timer runs while the system is in the `capturing` state. |
175
- | `isStepTransitioning` | `boolean` | Indicates whether the system is currently transitioning between challenges. Used to briefly pause detection and provide UI feedback after a challenge is completed. |
176
- | `start` | `function` | Starts the liveness challenge session and begins the detection loop. |
177
- | `reset` | `function` | Resets the entire session, including the timer, challenge sequence, step index, and error state. |
178
- | `sendFinalProof` | `function` | Sends captured face frames to the backend verification API to perform the final liveness check. Normally triggered automatically after the last challenge is completed. |
179
-
180
-
181
-
182
-
183
- ---
184
-
185
- ## 🎨 Styling with `classNames`
186
-
187
- You can pass a `classNames` object to override the default UI classes:
188
- ```js
189
- classNames={{
190
- container: "liveness-container",
191
- webcam: "liveness-webcam",
192
- button: "liveness-button",
193
- challenge: "liveness-challenge",
194
- timer: "liveness-timer",
195
- error: "liveness-error",
196
- success: "liveness-success",
197
- }}
198
- ```
199
-
200
- ### CSS Example
201
- ```css
202
- .liveness-container {
203
- text-align: center;
204
- background: #121212;
205
- padding: 24px;
206
- border-radius: 20px;
207
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
208
- color: white;
209
- }
210
- .liveness-webcam {
211
- border-radius: 20px;
212
- border: 2px solid #007bff;
213
- width: 100%;
214
- }
215
- .liveness-button {
216
- padding: 12px 30px;
217
- font-size: 16px;
218
- font-weight: bold;
219
- border-radius: 10px;
220
- background: #28a745;
221
- color: white;
222
- border: none;
223
- cursor: pointer;
224
- margin-top: 10px;
225
- }
226
- .liveness-challenge {
227
- margin: 5px 0;
228
- font-weight: bold;
229
- font-size: 40px;
230
- }
231
- .liveness-timer {
232
- margin: 10px 0;
233
- font-weight: bold;
234
- font-size: 18px;
235
- }
236
- .liveness-error {
237
- color: #ff4d4d;
238
- margin-top: 20px;
145
+ | Technical ID | Default Display |
146
+ | --- | --- |
147
+ | `Smile` | "Smile" |
148
+ | `Blink` | "Blink" |
149
+ | `Turn_Head` | "Turn Head" |
150
+ | `Thumbs_Up` | "Thumbs Up" |
151
+
152
+ **Example: Localization (French)**
153
+
154
+ TypeScript
155
+
156
+ // app.component.ts
157
+ challengeLabels = {
158
+ 'Smile': 'Souriez',
159
+ 'Blink': 'Clignez des yeux',
160
+ 'Turn_Head': 'Tournez la tête',
161
+ 'Thumbs_Up': 'Levez le pouce'
162
+ };
163
+ HTML
164
+
165
+ <LivenessCheck [challengeMapping]="challengeLabels"></LivenessCheck>
166
+
167
+ ###
168
+
169
+ ### 📥 Text & Label Customization
170
+
171
+ ###
172
+
173
+ Customize all user-facing strings to match your app's tone or language.
174
+
175
+ | Input Property | Default Value |
176
+ | --- | --- |
177
+ | `successMessage` | "Verification Successful!" |
178
+ | `errorMessage` | "Verification failed. Please try again." |
179
+ | `startButtonLabel` | "Start Verification" |
180
+ | `retryButtonLabel` | "Try Again" |
181
+
182
+ **Example Usage:**
183
+
184
+ HTML
185
+
186
+ <LivenessCheck
187
+ [successMessage]="'Identity Confirmed!'"
188
+ [errorMessage]="'We couldn\'t verify you. Move to a brighter room.'"
189
+ [startButtonLabel]="'Begin Scan'"
190
+ >
191
+ </LivenessCheck>
192
+
193
+ ## 🔄 State Synchronization
194
+
195
+ ###
196
+
197
+ The `onStateChange` event provides a real-time stream of the SDK's internal engine. This is useful for building custom instruction overlays or logging telemetry.
198
+
199
+ ### The `LivenessState` Object
200
+
201
+ ###
202
+
203
+ When the state changes, the SDK emits an object with the following structure:
204
+
205
+ | Property | Type | Description |
206
+ | --- | --- | --- |
207
+ | `status` | enum | The current phase of the SDK (see Status Flow below). |
208
+ | `sequence` | Challenge[] | The array of 3 randomized challenges (e.g., ['Smile', 'Blink', 'Turn_Head']). |
209
+ | `currentStep` | number | The index (0-2) of the challenge the user is currently performing. |
210
+ | `timeLeft` | number | The countdown timer in seconds before the session expires. |
211
+ | `isStepTransitioning` | boolean | true during the 1.5s pause after a successful challenge. |
212
+ | `errorMsg` | string | Contains the technical error code (e.g., SPOOF_BLUR_DETECTED) when status is 'error'. |
213
+
214
+ * * *
215
+
216
+ ### Implementation: Custom Error Mapping
217
+
218
+ ###
219
+
220
+ You can use the `onStateChange` handler to "intercept" technical error codes and map them to user-friendly instructions in your local UI.
221
+
222
+ **Example: Reactive Instructions**
223
+
224
+ TypeScript
225
+
226
+ // app.component.ts
227
+ handleStateUpdate(state: LivenessState) {
228
+ if (state.status === 'error' && state.errorMsg) {
229
+
230
+ // Pattern matching for specific error prefixes
231
+ switch (true) {
232
+ case state.errorMsg.startsWith('FACE_'):
233
+ this.myLocalStatus = "Center your face in the circle";
234
+ break;
235
+ case state.errorMsg.startsWith('LIGHT_'):
236
+ this.myLocalStatus = "Find a brighter spot";
237
+ break;
238
+ case state.errorMsg.startsWith('TIMEOUT'):
239
+ this.myLocalStatus = "Session expired. Tap retry.";
240
+ break;
241
+ default:
242
+ this.myLocalStatus = state.errorMsg;
243
+ }
244
+ }
245
+ }
246
+ HTML
247
+
248
+ <LivenessCheck
249
+ (onStateChange)="handleStateUpdate($event)"
250
+ [errorMessage]="myLocalStatus">
251
+ </LivenessCheck>
252
+
253
+ * * *
254
+
255
+ ### Why use the State Handler?
256
+
257
+ ###
258
+
259
+ * **Decoupled Logic:** You can keep the SDK's UI simple while handling complex business logic (like analytics or redirecting users) in your main app.
260
+
261
+ * **Dynamic UI:** Change your app's background color, show a progress bar, or trigger haptic feedback based on the `status` transitions.
262
+
263
+ * **Error Interception:** Translate technical backend codes into the specific "voice" of your brand.
264
+
265
+ ## 🚨 Error Reference Guide
266
+
267
+
268
+
269
+ When the SDK emits a `status: 'error'`, the `errorMsg` will contain one of the following technical codes. You can use these to provide contextual hints (e.g., "Too much light") in your UI.
270
+
271
+ | Error Code | Meaning | Recommended User Hint |
272
+ | --- | --- | --- |
273
+ | `SCREEN_REFLECTION_DETECTED` | Excessive glare or light bouncing off the screen. | "Move away from direct light or windows." |
274
+ | `SPOOF_BLUR_DETECTED` | Image is too dark or out of focus. | "Ensure your face is well-lit and clear." |
275
+ | `SCREEN_MOIRE_PATTERN_DETECTED` | Digital pixel patterns detected (indicates a photo/screen). | "Please use your physical device camera." |
276
+ | `STATIC_IMAGE_OR_SCREEN` | Natural micro-movements not detected. | "Blink or move slightly during the scan." |
277
+ | `NO_IMAGE_DATA` | Camera permissions denied or stream interrupted. | "Enable camera access in your settings." |
278
+ | `AI_SPOOF_DETECTION` | Low skin-texture confidence from the AI model. | "Verification failed. Please try again." |
279
+ | `Network Error` | The backend API could not be reached. | "Check your internet connection." |
280
+ | `Liveness Check Failed` | Generic fallback for unspecified validation errors. | "Please try again in a different environment." |
281
+
282
+ * * *
283
+
284
+ ### Pro-Tip: Implementing a User Hint System
285
+
286
+ ##
287
+
288
+ Instead of showing the raw code (which might confuse a non-technical user), use the `onStateChange` handler to map these codes to your friendly "Recommended User Hint" column.
289
+
290
+ TypeScript
291
+
292
+ // Example: Mapping technical codes to friendly messages
293
+ handleStateUpdate(state: LivenessState) {
294
+ const errorMap: Record<string, string> = {
295
+ 'SCREEN_REFLECTION_DETECTED': 'Too much light! Please move to a shaded area.',
296
+ 'SPOOF_BLUR_DETECTED': 'It’s a bit dark. Try increasing your screen brightness.',
297
+ 'NO_IMAGE_DATA': 'We can’t see you! Please check your camera permissions.'
298
+ };
299
+
300
+ if (state.status === 'error') {
301
+ this.friendlyMessage = errorMap[state.errorMsg] || "Something went wrong. Let's try again.";
302
+ }
303
+ }
304
+
305
+ * * *
306
+
307
+ ### 📦 Latest Changes Summary
308
+
309
+ ##
310
+
311
+ * **Zero-CSS Architecture:** All default styles removed; fully styleable via `[ngClass]` inputs.
312
+
313
+ * **Label Mapping:** Added `[challengeMapping]` to allow custom text for "Smile", "Blink", etc.
314
+
315
+ * **State Hook:** New `(onStateChange)` event for advanced lifecycle management.
316
+
317
+ * **Encapsulation:** Set to `ViewEncapsulation.None` for seamless Tailwind and Global CSS integration.
318
+
319
+
320
+ ## ⚙️ Configuration & Thresholds
321
+
322
+
323
+
324
+ | Prop Name | Default | Description |
325
+ | --- | --- | --- |
326
+ | `duration` | 60 | Total session time in seconds |
327
+ | `smileThreshold` | 0.20 | Minimum width for smile detection |
328
+ | `blinkThreshold` | 0.01 | Sensitivity for eye-closure detection |
329
+ | `minturnHeadThreshold` | 0.15 | Minimum yaw for right-turn detection |
330
+ | `maxturnHeadThreshold` | 0.85 | Maximum yaw for left-turn detection |
331
+
332
+ * * *
333
+
334
+ ## ✅ Success & Failure Payload
335
+
336
+ ### onComplete Result
337
+
338
+ #
339
+
340
+ {
341
+ success: true,
342
+ image: string, // Base64 encoded capture frame
343
+ skinConfidence: number // AI model confidence score
239
344
  }
240
- .liveness-success {
241
- color: #4caf50;
242
- margin-top: 20px;
345
+
346
+ ### onError Result
347
+
348
+ #
349
+
350
+ {
351
+ success: false,
352
+ reason: string, // "timeout", "challenge\_failed", "camera\_denied"
243
353
  }
244
- ```
245
354
 
246
- ---
355
+ * * *
356
+
357
+ ## 🛠️ Advanced: Headless Mode
247
358
 
248
- ## ⏳ Timeout Rules
249
359
 
250
- - Maximum session duration: set via `duration` prop (default 60s).
251
- - On timeout: challenge stops, state resets, backend verification is not triggered.
252
360
 
253
- ---
361
+ * **Angular 🅰️**: Inject `LivenessService` to access the `state$` observable.
362
+
363
+ * **React ⚛️**: Use `useLiveness` hook.
364
+
254
365
 
255
- ## 🔐 Security Architecture
366
+ Allows full custom UI while using the detection engine.
256
367
 
257
- - **Client-side**: Randomized challenges, real-time gesture detection
258
- - **Server-side**: Frame-based spoof analysis, glare detection, video injection detection
259
- - **Session control**: Timeout enforcement, manual restart on failure
260
- - Reduces false positives and prevents replay attacks.
368
+ * * *
261
369
 
262
- ---
370
+ ## 🏗️ SDK Architecture
263
371
 
264
- ## 📊 Verification Criteria
265
372
 
266
- - All 3 challenges completed
267
- - All 5 frames successfully sent to backend
268
- - Backend confirms: no spoofing, no glare, human skin texture, no video injection
269
373
 
270
- ---
374
+ Layered design allows the same core detection engine to support multiple frameworks:
271
375
 
272
- ## 🏗️ Integration Notes
376
+ * **core**: `LivenessEngine.ts` handles webcam, landmark detection, challenge sequencing, frame capture, and backend verification
377
+
378
+ * **react**: React components + hooks handle UI and state
379
+
380
+ * **angular**: Standalone components + services handle UI and state
381
+
273
382
 
274
- - Webcam permissions required
275
- - Backend must accept 5 frames in expected format
276
- - `apiUrl` must be reachable and have an endpoint `/v1/verify`
277
- - CORS must be configured properly
383
+ * * *
278
384
 
279
- ---
385
+ ## 🔧 Integration Notes
280
386
 
281
- ## 🚀 Ideal Use Cases
282
387
 
283
- - KYC verification flows
284
- - Identity onboarding
285
- - Account recovery
286
- - Secure login
287
- - Financial / compliance apps
288
388
 
289
- ---
389
+ * **MediaPipe Dependency**: If you see `TS2307: Cannot find module '@mediapipe/tasks-vision'`, run `npm install @mediapipe/tasks-vision`.
390
+
391
+ * **Angular Button Logic**: `[disabled]="!canStart"` — Angular inverts the boolean so button is enabled when `canStart = true`.
392
+
393
+ * **Webcam Permissions**: Required.
394
+
395
+ * **Timeout Rules**: Session resets if challenges aren’t completed within the configured duration.
396
+
397
+ * **Backend**: Accepts multiple frames for final spoof analysis. Endpoint must be `/v1/verify`
398
+
399
+ * **CORS**: Ensure API allows requests from your frontend domain.
400
+
401
+
402
+ * * *
290
403
 
291
404
  ## 👨‍💻 Maintainer
292
405
 
293
- Fadiora Richard.
294
406
 
407
+
408
+ **Fadiora Richard**
409
+ Maintained by **Princeps Credit Systems Limited**