FaceHushOn-device MLiOS, Android, Web
FaceHush: Every face, hushed.
Sharing a photo from a classroom or a party means hiding faces that are not yours to share. FaceHush finds every face, censors all of them, and lets you tap the people who should stay visible. Nothing is uploaded.
No frames, crops, embeddings or thumbnails leave the phone.
- Find every face
- Censor all of them
- Tap who stays visible
The rule that shaped everything
False blur: acceptable. False reveal: a privacy bug.
The failure modes are not symmetric, and that shaped everything. Blurring a face that could have stayed visible is an annoyance. Revealing a face that should have stayed hidden is a privacy failure. Every recognition shortcut had to fail toward blur.
For video, I first tried to make recognition authoritative with person cards you could split and merge. On phone video, same-person and different-person distances overlapped too much for any threshold to be safe. So every face is censored by default, a tap means keep this person visible, and recognition only assists.
The spec invariant reads: a false blur is acceptable, a false reveal is a privacy bug.
Read the decision record, 23 May 2026Why this photo has fourteen faces
A busy-scene memory fix once capped detections at 12 per frame. Review caught what that meant for a crowd.
Capped at 12 detections per frame
13, 14Never tracked, so exported uncensored.
The invariant now
All 14Every valid detection becomes a track and reaches the export censor map. Caps live only where crops are emitted.
The model story
87 MB to 6.8 MB, same 512-d output
- 01
The app was killed during video analysis.
- 02
Swapping ArcFace r50 for the mobile backbone cut the recognition model from 87 MB to 6.8 MB, with the same 512-d output.
- 03
It crashed again. The model was never the problem: every matched frame encoded a JPEG crop and pushed it over the React Native bridge faster than the embedding queue drained.
- 04
The fix bounded the crops.
every other frameat most 3 per track120 per session