TypeScript, type-safe, opinionated port of Python's Uniface: A comprehensive library for face detection, recognition, landmark analysis, age, and gender detection.

Demos:
The code pattern is highly inspired by Uniface, however we do not offer model variations. We stick to predetermined opinionated models and functionality to achieve a minimum footprint.
onnxruntime-webCustomization will be added as we go along. Feel free to open an issue for feature requests.
bun add ppu-uniface
or
npm install ppu-uniface
It is recommended to do warmup initialize first to download all the models needed to run for the first time.
import { Uniface } from "ppu-uniface";
const uniface = new Uniface();
await uniface.initialize();
const image1 = await Bun.file("path/to/image1.jpg").arrayBuffer();
const image2 = await Bun.file("path/to/image2.jpg").arrayBuffer();
const result = await uniface.verify(image1, image2);
console.log(result);
await uniface.destroy();
const result = await uniface.verify(image1, image2, { compact: true });
// Returns: { multipleFaces, spoofing, verified, similarity }
const result = await uniface.verify(image1, image2, { compact: false });
// Returns: { detection, recognition, verification }
// Override detection threshold for both faces in verification
const result = await uniface.verify(image1, image2, {
compact: true,
detection: {
threshold: { confidence: 0.5 },
},
});
// Override verification threshold for this specific verification call
const result = await uniface.verify(image1, image2, {
compact: true,
threshold: 0.85, // Falls back to model-level threshold (0.7) if not provided
});
// Or with direct embedding comparison
const verification = await uniface.verifyEmbedding(
face1.embedding,
face2.embedding,
0.85 // Optional threshold override
);
const detection = await uniface.detect(imageBuffer);
console.log(detection);
// Returns: { box, confidence, landmarks, multipleFaces }
// Override confidence threshold for this detection call
const detection = await uniface.detect(imageBuffer, {
threshold: { confidence: 0.5 },
});
// Override both thresholds
const detection = await uniface.detect(imageBuffer, {
threshold: {
confidence: 0.8,
nonMaximumSuppression: 0.3,
},
});
const recognition = await uniface.recognize(imageBuffer);
console.log(recognition.embedding);
// Returns: { embedding: Float32Array(512) }
const face1 = await uniface.recognize(image1);
const face2 = await uniface.recognize(image2);
const verification = await uniface.verifyEmbedding(
face1.embedding,
face2.embedding
);
console.log(verification);
// Returns: { similarity, verified, threshold }
import { LoggerConfig } from "ppu-uniface";
LoggerConfig.verbose = true;
import {
RetinaNetDetection,
FaceNet512Recognition,
CosineVerification,
alignAndCropFace,
} from "ppu-uniface";
const detector = new RetinaNetDetection();
await detector.initialize();
const recognizer = new FaceNet512Recognition();
await recognizer.initialize();
const verifier = new CosineVerification();
const detection = await detector.detect(imageBuffer);
if (detection) {
const alignedFace = await alignAndCropFace(imageBuffer, detection);
const embedding = await recognizer.recognize(alignedFace);
console.log(embedding);
}
await detector.destroy();
await recognizer.destroy();
ppu-uniface runs entirely in the browser using onnxruntime-web. No server required.
npm install ppu-uniface onnxruntime-web
import { Uniface } from "ppu-uniface/web";
const uniface = new Uniface();
await uniface.initialize();
// Use with an image ArrayBuffer (from fetch, FileReader, canvas, etc.)
const detection = await uniface.detect(imageArrayBuffer);
const recognition = await uniface.recognize(imageArrayBuffer);
const verification = await uniface.verify(image1, image2);
const spoofing = await uniface.spoofingAnalysisWithDetection(imageArrayBuffer);
await uniface.destroy();
<script type="importmap">
{
"imports": {
"onnxruntime-web": "https://cdn.jsdelivr.net/npm/[email protected]/dist/ort.all.bundle.min.mjs",
"onnxruntime-common": "https://cdn.jsdelivr.net/npm/[email protected]/dist/ort-common.min.mjs",
"ppu-ocv/web": "https://cdn.jsdelivr.net/npm/ppu-ocv@2/index.web.js",
"ppu-uniface/web": "https://cdn.jsdelivr.net/npm/ppu-uniface@3/web/index.js"
}
}
</script>
<script type="module">
import { Uniface } from "ppu-uniface/web";
const uniface = new Uniface();
await uniface.initialize();
// ... use uniface methods
</script>
Note: First initialization downloads ONNX models (~100MB total). Subsequent loads use browser cache.
You can customize the models by passing options to the Uniface constructor or individual model constructors.
DetectionModelOptions)Model-level options configured during initialization:
| Option | Type | Default | Description |
|---|---|---|---|
threshold.confidence |
number |
0.7 |
Minimum confidence score for face detection |
threshold.nonMaximumSuppression |
number |
0.4 |
IoU threshold for non-maximum suppression |
topK.preNonMaximumSuppression |
number |
5000 |
Maximum detections before NMS |
topK.postNonMaxiumSuppression |
number |
750 |
Maximum detections after NMS |
size.input |
[number, number] |
[320, 320] |
Input dimensions [height, width] |
DetectOptions)Override detection thresholds on a per-call basis (available for detect(), verify(), verifyWithDetections(), and spoofingAnalysisWithDetection()):
| Option | Type | Default | Description |
|---|---|---|---|
threshold.confidence |
number |
Model-level or 0.7 |
Minimum confidence score for face detection |
threshold.nonMaximumSuppression |
number |
Model-level or 0.4 |
IoU threshold for non-maximum suppression |
RecognitionModelOptions)| Option | Type | Default | Description |
|---|---|---|---|
size.input |
[number, number, number, number] |
[1, 160, 160, 3] |
Input tensor shape [batch, height, width, channels] |
size.output |
[number, number] |
[1, 512] |
Output tensor shape [batch, embedding_size] |
VerificationModelOptions)| Option | Type | Default | Description |
|---|---|---|---|
threshold |
number |
0.7 |
Similarity threshold for verification |
VerificationModelOptions)| Option | Type | Default | Description |
|---|---|---|---|
threshold |
number |
0.5 |
Similarity threshold for verification |
enable |
boolean |
true |
Enable the anti-spoofing analysis |
const uniface = new Uniface({
detection: {
threshold: {
confidence: 0.9,
},
size: {
input: [640, 640],
},
},
verification: {
threshold: 0.8,
},
});
UnifaceMain service class for face detection, recognition, and verification.
initialize(): Promise<void> - Initializes all modelsdetect(image: ArrayBuffer | Canvas, options?: DetectOptions): Promise<DetectionResult | null> - Detects face in image with optional threshold overridesrecognize(image: ArrayBuffer | Canvas): Promise<RecognitionResult> - Generates face embeddingverify(image1, image2, options?: UnifaceVerifyOptions): Promise<UnifaceFullResult | UnifaceCompactResult> - Verifies if two images contain the same person (supports detection and verification threshold overrides via options.detection and options.threshold)verifyWithDetections(input1, input2, options?: UnifaceVerifyOptions): Promise<UnifaceFullResult | UnifaceCompactResult> - Verifies with pre-computed detections (supports detection and verification threshold overrides via options.detection and options.threshold)verifyEmbedding(embedding1, embedding2, threshold?: number): Promise<VerificationResult> - Compares two embeddings directly with optional threshold overridespoofingAnalysisWithDetection(image: ArrayBuffer | Canvas, options?: DetectOptions): Promise<SpoofingResult | null> - Analyzes spoofing with automatic detection and optional threshold overridesdestroy(): Promise<void> - Releases all model resourcesDetectOptions{
threshold?: {
confidence?: number; // Default: 0.7
nonMaximumSuppression?: number; // Default: 0.4
};
}
DetectionResult{
box: { x: number; y: number; width: number; height: number };
confidence: number;
landmarks: number[][]; // 5 points: left eye, right eye, nose, left mouth, right mouth
multipleFaces: boolean;
}
RecognitionResult{
embedding: Float32Array; // 512-dimensional vector
}
VerificationResult{
similarity: number; // 0-1
verified: boolean;
threshold: number; // Default: 0.7
}
UnifaceVerifyOptions{
compact: boolean; // Default: true
detection?: DetectOptions; // Optional detection threshold overrides
threshold?: number; // Optional verification threshold override (falls back to model-level threshold, default: 0.7)
}
UnifaceCompactResult{
multipleFaces: {
face1: boolean | null;
face2: boolean | null;
}
spoofing: {
face1: boolean | null;
face2: boolean | null;
}
verified: boolean;
similarity: number;
}
UnifaceFullResult{
detection: {
face1: DetectionResult | null;
face2: DetectionResult | null;
}
recognition: {
face1: RecognitionResult;
face2: RecognitionResult;
}
spoofing: {
face1: SpoofingResult | null;
face2: SpoofingResult | null;
}
verification: VerificationResult;
}
The library automatically downloads and caches the following models on first use:
Models are cached in ~/.cache/ppu-uniface/ for faster subsequent loads.
bun run benchmark
Feel free to compare it to Deepface.
bun test
The library includes comprehensive unit tests covering:
Typical performance on modern hardware:
onnxruntime-node - ONNX model inferenceppu-ocv - Computer vision utilitiesonnxruntime-web - ONNX model inference (WASM)ppu-ocv/web - Computer vision utilities (browser build)Contributions are welcome! Please feel free to submit a Pull Request.
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)MIT