React Native
On React Native, Mimic reads frames from VisionCamera 5 on the camera thread, runs the native face tracker through a Nitro module, and judges gestures on the JS thread. Your component gets a hook and a camera view.
Requirements
Section titled “Requirements”| Version | |
|---|---|
| React Native | 0.79 or later, New Architecture (tested on 0.87) |
react-native-vision-camera |
5.x |
react-native-nitro-modules |
0.37 or later |
react-native-worklets |
0.13 or later |
| iOS / Android | iOS 15+, Android 7 (API 24)+ with a front camera |
Expo works with a development build (expo prebuild), not Expo Go, since Mimic ships native code.
Install
Section titled “Install”Configure access first, then:
npm install @vidrip/mimic-react-native @vidrip/mimic-landmarker @vidrip/mimic-core \ react-native-vision-camera react-native-nitro-modules react-native-workletscd ios && pod install@vidrip/mimic-landmarker is the native module and carries the face model, so there’s nothing to download at runtime.
Camera permission
Section titled “Camera permission”Add a camera usage string to ios/<App>/Info.plist:
<key>NSCameraUsageDescription</key><string>Uses the front camera to read your facial gestures. Nothing leaves your device.</string>and the permission to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />Ask for it at runtime with VisionCamera’s useCameraPermission() before showing the camera.
Bind gestures
Section titled “Bind gestures”import { useCameraPermission } from 'react-native-vision-camera';import { MimicCamera, useMimic } from '@vidrip/mimic-react-native';
export function Game() { const { hasPermission, requestPermission } = useCameraPermission(); const face = useMimic({ on: { 'blink': (e) => { if (e.phase === 'start') fire(); }, 'head.left': (e) => { if (e.phase === 'start') moveLeft(); }, 'smile': (e) => setGrin(e.phase === 'start' ? e.strength : 0), }, });
if (!hasPermission) return <Button title="Allow camera" onPress={requestPermission} />; return ( <> <MimicCamera mimic={face} style={StyleSheet.absoluteFill} /> {!face.profile && <Button title="Calibrate" onPress={() => face.calibrate()} />} </> );}Handlers run on the JS thread. useMimic re-renders only a few times a second (for faceFound, fps and calibration progress), never per frame, so binding gestures doesn’t make your screen re-render at camera rate.
Calibration and profiles
Section titled “Calibration and profiles”face.calibrate() resolves with { profile, status }. While it runs, face.calibration.progress and face.calibration.quality drive your prompt UI. Persist the profile (for example with onProfile) and pass it back as profile to skip calibration next time:
const face = useMimic({ profile: saved, onProfile: (p) => storage.set('mimic', JSON.stringify(p)), on });To make calibration wait until the face is inside your on-screen guide, pass framing: (centre) => boolean; the centre is where the eyes sit in the frame (0 to 1).
Optional features
Section titled “Optional features”blendshapes: trueruns the expression network too. It’s needed foreyes.upandexpression.match, and costs a few milliseconds per frame.gestures: [...]arms only the gestures you use.landmarks: 'always'keeps the full 478-point mesh on every sample, for your own effects. The default sends only the points the gestures need.
- The full React Native API reference.
- The gesture catalog.