@healthcloudai/hc-facecapture-connector
v0.5.0
Published
Camera-based face frame capture for React Native — grab a single JPEG still from the device camera. Works on iOS, Android, and Web.
Maintainers
Readme
@healthcloudai/hc-facecapture-connector
Camera-based face frame capture for React Native (Expo). Grab a single JPEG still from the device camera — with a single <FaceCaptureCamera> component that works on iOS, Android, and Web.
import {
FaceCaptureCamera,
} from "@healthcloudai/hc-facecapture-connector";
export default function App() {
return (
<FaceCaptureCamera
onCapture={(result) => {
console.log("Frame:", result.frameBase64);
// → "data:image/jpeg;base64,/9j/4AAQ..."
console.log("Size:", result.width, "×", result.height);
// → 640 × 480
}}
/>
);
}Features
- Zero config — Expo config plugin handles camera permissions
- Single component —
<FaceCaptureCamera>works on iOS, Android, and Web - Headless hook —
useFaceCapture()gives you full control over capture lifecycle - No SDK dependencies — uses CameraX (Android), AVFoundation (iOS), getUserMedia (Web)
- Vendor-free — no Circadify, no MediaPipe, no external SDKs
Installation
npm install @healthcloudai/hc-facecapture-connectorExpo Config Plugin
Add the plugin to your app.json:
{
"expo": {
"plugins": [
"@healthcloudai/hc-facecapture-connector"
]
}
}This automatically:
- Adds camera permissions (iOS + Android)
- Adds
NSCameraUsageDescriptionto Info.plist
After adding the plugin, rebuild your native apps:
npx expo prebuild --clean
npx expo run:ios # or run:androidWeb
Web capture works out of the box — uses getUserMedia + canvas. No extra install needed.
API
Components
<FaceCaptureCamera>
All-in-one face capture component with three screens: idle → camera preview → captured.
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| onCapture | (result: FaceCaptureResult) => void | No | Called on successful frame capture |
| onError | (error: Error) => void | No | Called on fatal error |
| title | string | No | Override the idle screen title |
| subtitle | string | No | Override the idle screen subtitle |
| cameraPosition | "front" \| "back" | No | Which physical lens to use. Default "front". |
| mirror | boolean | No | Horizontally flip the captured JPEG so it matches what the operator saw. Default auto: true for front, false for back. |
The idle screen shows a title, subtitle, and "Open Camera" button. The preview screen shows a live camera feed (mirrored on web for the front lens) with an oval face guide and a capture button. After capture, a success screen with "Retake" and "Done" options appears.
<FaceCapturePreview>
Low-level camera preview. Renders the native viewfinder on iOS/Android, or a <video> element on web.
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| style | StyleProp<ViewStyle> | No | Style for the preview container |
| cameraPosition | "front" \| "back" | No | Which lens to render. Web branch mirrors the preview when "front". Default "front" on native, "back" on web (legacy behavior). |
Hooks
useFaceCapture()
Headless hook for full control.
import { useFaceCapture } from "@healthcloudai/hc-facecapture-connector";
function MyCapture() {
// Pass { cameraPosition, mirror } to choose the lens and flip behavior.
const { start, capture, stop, result, isPreviewing, error } =
useFaceCapture({ cameraPosition: "front" });
const handleCapture = async () => {
await start();
const frame = await capture();
console.log(frame.frameBase64);
await stop();
};
return (
<Button onPress={handleCapture} disabled={isPreviewing}>
Capture Face
</Button>
);
}start() also accepts a per-call override that wins over the hook-time
options: start({ cameraPosition: "back", mirror: false }).
Types
type CameraPosition = "front" | "back";
interface FaceCaptureOptions {
cameraPosition?: CameraPosition; // default "front"
mirror?: boolean; // default auto: front → true, back → false
}
interface FaceCaptureResult {
frameBase64: string; // "data:image/jpeg;base64,..."
width: number;
height: number;
}
interface FaceCaptureError {
code: string;
message: string;
}
interface FaceCaptureAPI {
start: (opts?: FaceCaptureOptions) => Promise<void>;
capture: () => Promise<FaceCaptureResult>;
stop: () => Promise<void>;
isPreviewing: boolean;
result: FaceCaptureResult | null;
error: FaceCaptureError | null;
}Choosing an entry point
This package exposes three layers. Pick the one that matches your app:
| Layer | Use when | What you call |
|-------|----------|---------------|
| 1. All-in-one | Simplest drop-in; one screen owns the camera from idle to capture. | <FaceCaptureCamera /> (renders its own preview + buttons) |
| 2. Headless hook + preview | You want custom UI/overlay but the package still owns the lens. | useFaceCapture() + <FaceCapturePreview /> |
| 3. Primitive | You already have a camera surface (e.g. expo-camera) or must run side-by-side with another camera consumer. | detectFaceInImage(base64Jpeg) — pass your own JPEG, get a boolean |
Why choose Layer 3 in some apps?
A device camera is an exclusive resource on iOS/Android. AVFoundation and
CameraX allow one active capture session at a time, and a few cross-module
flows (e.g. running @healthcloudai/hc-cameravitals-connector and face
back-to-back) can clash if both modules try to own the lens. When your host
app already drives a camera, use Layer 3 and skip this package's preview —
feed the JPEG into detectFaceInImage() instead.
Composition with Camera Vitals
This module is designed to be composed with @healthcloudai/hc-cameravitals-connector for the New Encounter flow:
// 1. Camera vitals (30s Circadify scan)
<CameraVitalsScan apiKey={key} onResult={(vitals) => setVitals(vitals)} />
// 2. Face capture (1s still frame)
// — camera restarts briefly, hold last frame or show overlay
<FaceCaptureCamera onCapture={(frame) => setFaceFrame(frame)} />See the CDC Protect app for the complete integration pattern.
Architecture
FaceCaptureCamera / useFaceCapture()
│
▼
FaceCaptureAdapter (interface)
├── createIOSAdapter() → FaceCaptureModule (AVFoundation)
├── createAndroidAdapter() → FaceCaptureModule (CameraX)
└── createWebAdapter() → getUserMedia + canvasNo external SDKs. No network calls. No API keys.
License
MIT
