🏗 System Stack
Everything runs 100% in the browser — no video leaves your device.
MediaPipe FaceMesh — Google WASM, 30fps cap, 468 3D landmarks per face, up to 8 faces.
face-api.js — 4 TensorFlow.js models: TinyFaceDetector (bounding box) · AgeGenderNet (age ±3yr, gender after 10+ readings) · FaceRecognitionNet (128-dim descriptor) · FaceExpressionNet (7-class, async ~1/sec)
Three.js r160 — WebGL live 3D face mesh (898 triangles + back-of-head geometry)
localStorage — face library persisted in browser. Optional Python save_server.py (port 8787) saves photos to disk.
🔄 Per-Frame Pipeline
Every frame: MediaPipe → 468 landmarks → draw mesh overlay on canvas
Every 5th frame: Crop face → 128-dim descriptor → library match (d<0.50=match, d>0.58=new, d<0.35=high confidence) · Age+gender · Skin ITA (forehead+cheeks only, beard-safe) · Ethnicity (7 geometry ratios, ~55–65% accurate) · Hair+shirt colour signature (secondary verification)
Background ~1/sec: Expression analysis — never blocks frame loop
📊 Accuracy Reference
Skin ITA scale: Very Light >55° · Light 41–55° · Intermediate 28–41° · Tan-Brown 10–28° · Brown −30–10° · Dark Brown <−30°
Photos saved only when d<0.35. Open profile → ✕ to remove a photo · 💾 to save current live frame. Hair+shirt colour chips shown as identity markers.
Expressions are running averages since first detection — a brief expression dilutes slowly over time.
⌨ Shortcuts
M Merge selected · Ctrl+Z Undo · Click card to select for merge