ugx-face-liveness
v2.0.0
Published
Client-side Angular face-liveness capture using MediaPipe Face Landmarker. The guided flow requires one face to align, turn left, turn right, return to centre, hold still, and then captures a JPEG snapshot plus a short WebM recording.
Readme
UGX Face Liveness v2
Client-side Angular face-liveness capture using MediaPipe Face Landmarker. The guided flow requires one face to align, turn left, turn right, return to centre, hold still, and then captures a JPEG snapshot plus a short WebM recording.
What changed in v2
- Replaced the global
face-api.jsscript and four legacy model downloads with one MediaPipe face-landmarker model. - Runs model inference in a dedicated Web Worker so slow detections do not block buttons, instructions, or camera rendering.
- Limits camera capture to a low-end-friendly 640x480 at 20–24 fps and adapts inference cadence to measured device speed.
- Records only the challenge, after initial alignment, at a controlled bitrate.
- Replaces blink/smile thresholds with an ordered left → right → still challenge.
- Keeps the existing output names and emitted payload values.
This is a fully client-side presentation check. It raises the effort required for simple photo and replay attacks, but no RGB browser-only library can guarantee that every sophisticated spoof or injected camera stream will be rejected.
Compatibility
ugx-face-liveness v2 supports Angular 16–19. It is a breaking release because the old faceDetectionOptions input and blink/smile modes have been removed.
Install
npm install ugx-face-liveness@2Copy the runtime assets
The worker, model, and MediaPipe WebAssembly files are lazy-loaded from /assets/face-liveness by default. Copy the package assets in the consuming application's angular.json build and test targets:
{
"glob": "**/*",
"input": "node_modules/ugx-face-liveness/assets",
"output": "assets/face-liveness"
}For this workspace, the demo uses the source assets instead:
{
"glob": "**/*",
"input": "projects/face-liveness/src/lib/assets",
"output": "assets/face-liveness"
}No external script tag is required.
Usage
import { Component } from '@angular/core';
import { FaceLivenessComponent } from 'ugx-face-liveness';
@Component({
selector: 'app-verification',
standalone: true,
imports: [FaceLivenessComponent],
template: `
<fl-face-liveness
[options]="{ timeoutMs: 25000 }"
(faceDetectionStatusChange)="onFaceStatus($event)"
(errorOccurred)="onError($event)"
(livenessCompleted)="onComplete($event)"
/>
`,
})
export class VerificationComponent {
onFaceStatus(isAligned: boolean): void {}
onError(message: string): void {}
onComplete(result: { snapshot: Blob; video: Blob | null }): void {}
}FaceLivenessModule remains available for NgModule applications.
Options
interface FaceLivenessOptions {
assetBaseUrl?: string; // /assets/face-liveness
detectionIntervalMs?: number; // 140
maxDetectionIntervalMs?: number; // 280
minDetectionConfidence?: number; // 0.55
timeoutMs?: number; // 25000
captureWidth?: number; // 640
captureHeight?: number; // 480
videoBitsPerSecond?: number; // 600000
}The detector automatically increases its interval when inference is slow. Lowering detectionIntervalMs can make the flow less reliable on low-end devices.
Outputs preserved from v1
faceDetectionStatusChange: booleanerrorOccurred: stringlivenessCompleted: { snapshot: Blob; video: Blob | null }
The snapshot is JPEG. The video is WebM VP9 or VP8 where MediaRecorder is available; otherwise video is null.
Local development
npm start
npm run build:lib
npm run test:lib -- --watch=false --browsers=ChromeHeadlessnpm start and npm run build:lib automatically rebuild the generated worker bundle. Use Node.js 20 or 22 LTS.
Model provenance
The included face_landmarker.task is Google's MediaPipe Face Landmarker float16 model bundle. MediaPipe is Apache-2.0 licensed. The model provides 478 three-dimensional facial landmarks; v2 uses those landmarks for face bounds, roll, yaw, ordered movement, and stillness checks.
