{"_id":"@data_is_null/face-map-expo","_rev":"2-4b5c664769e4849044a6a594d64c00aa","name":"@data_is_null/face-map-expo","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.1":{"name":"@data_is_null/face-map-expo","version":"0.1.1","keywords":["react-native","expo","face-detection","face-mesh","face-landmarks","vision","ml-kit"],"author":{"url":"https://github.com/DataIsNull","name":"Hamid Akhmedov","email":"hamidakhmedovwork@gmail.com"},"license":"MIT","_id":"@data_is_null/face-map-expo@0.1.1","maintainers":[{"name":"data_is_null","email":"hamidakhmedovwork@gmail.com"}],"homepage":"https://github.com/DataIsNull/face-map-expo#readme","bugs":{"url":"https://github.com/DataIsNull/face-map-expo/issues"},"dist":{"shasum":"c7a99b73860dd4225c9fe6a732cb569be327d7da","tarball":"https://registry.npmjs.org/@data_is_null/face-map-expo/-/face-map-expo-0.1.1.tgz","fileCount":33,"integrity":"sha512-J89PuxzhS3oh0oaVgD7IDJtvrC0OeVZkNe8rEKTlw6SzA6ik2BcgsS5bXvuChjCK2Two67+qBEQ1IAK0afE5LQ==","signatures":[{"sig":"MEUCIQCHEXloiAi/j6suCBZ35+u1ntSh8VIgcAzXc7TBa2IreQIgRm5UbSUbDBOj/7BITq/Erj2IcIN8ZOi6KgIUq80X260=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":62027},"main":"build/index.js","types":"build/index.d.ts","gitHead":"df6f78c210c7767b65fa4317ca7f2bc1b23400b3","scripts":{"lint":"expo-module lint","test":"expo-module test","build":"expo-module build","clean":"expo-module clean","prepare":"expo-module prepare","open:ios":"xed example/ios","expo-module":"expo-module","open:android":"open -a \"Android Studio\" example/android","prepublishOnly":"expo-module prepublishOnly"},"_npmUser":{"name":"data_is_null","email":"hamidakhmedovwork@gmail.com"},"repository":{"url":"git+https://github.com/DataIsNull/face-map-expo.git","type":"git"},"_npmVersion":"10.9.2","description":"Expo module for detecting facial landmarks and rendering animated face mesh overlays","directories":{},"_nodeVersion":"23.11.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"expo":"^55.0.24","@types/react":"~19.2.10","react-native":"0.83.6","expo-module-scripts":"^55.0.2","react-native-reanimated":"^4.2.1","@shopify/react-native-skia":"^2.4.18"},"peerDependencies":{"expo":"*","react":"*","react-native":"*","react-native-reanimated":">=3.0.0","@shopify/react-native-skia":">=1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/face-map-expo_0.1.1_1778765008948_0.7969581801586032","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@data_is_null/face-map-expo","version":"0.1.2","description":"Expo module for detecting facial landmarks and rendering animated face mesh overlays","main":"build/index.js","types":"build/index.d.ts","scripts":{"build":"expo-module build","clean":"expo-module clean","lint":"expo-module lint","test":"expo-module test","prepare":"expo-module prepare","prepublishOnly":"expo-module prepublishOnly","expo-module":"expo-module","open:ios":"xed example/ios","open:android":"open -a \"Android Studio\" example/android"},"keywords":["react-native","expo","face-detection","face-mesh","face-landmarks","vision","ml-kit"],"repository":{"type":"git","url":"git+https://github.com/DataIsNull/face-map-expo.git"},"bugs":{"url":"https://github.com/DataIsNull/face-map-expo/issues"},"author":{"name":"Hamid Akhmedov","email":"hamidakhmedovwork@gmail.com","url":"https://github.com/DataIsNull"},"license":"MIT","homepage":"https://github.com/DataIsNull/face-map-expo#readme","dependencies":{},"devDependencies":{"@shopify/react-native-skia":"^2.4.18","@types/react":"~19.2.10","expo-module-scripts":"^55.0.2","expo":"^55.0.24","react-native":"0.83.6","react-native-reanimated":"^4.2.1"},"peerDependencies":{"@shopify/react-native-skia":">=1.0.0","expo":"*","react":"*","react-native":"*","react-native-reanimated":">=3.0.0"},"_id":"@data_is_null/face-map-expo@0.1.2","gitHead":"df6f78c210c7767b65fa4317ca7f2bc1b23400b3","_nodeVersion":"23.11.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-N2MIn5AlOQvBCA1d9iRPNysf9twLfFvlCjPiBudWElIbTXHLMeefK6MDyWUemfMpDPvZ8lcaRdJAUoDCqzxrww==","shasum":"94b40406aa7d9132c3d2aca96faa0e6a641014b5","tarball":"https://registry.npmjs.org/@data_is_null/face-map-expo/-/face-map-expo-0.1.2.tgz","fileCount":33,"unpackedSize":62041,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIG2KIgIhPAHuDoERSVSSHDkjfojnakUtSMcuzOXUxbjrAiEAs5NT8GFEm76G6AN9pckOR5DCXSLwGBPkqytyayKY7ZI="}]},"_npmUser":{"name":"data_is_null","email":"hamidakhmedovwork@gmail.com"},"directories":{},"maintainers":[{"name":"data_is_null","email":"hamidakhmedovwork@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/face-map-expo_0.1.2_1778765167514_0.5529044578349058"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-14T13:23:28.851Z","modified":"2026-05-14T13:26:07.800Z","0.1.1":"2026-05-14T13:23:29.110Z","0.1.2":"2026-05-14T13:26:07.691Z"},"bugs":{"url":"https://github.com/DataIsNull/face-map-expo/issues"},"author":{"name":"Hamid Akhmedov","email":"hamidakhmedovwork@gmail.com","url":"https://github.com/DataIsNull"},"license":"MIT","homepage":"https://github.com/DataIsNull/face-map-expo#readme","keywords":["react-native","expo","face-detection","face-mesh","face-landmarks","vision","ml-kit"],"repository":{"type":"git","url":"git+https://github.com/DataIsNull/face-map-expo.git"},"description":"Expo module for detecting facial landmarks and rendering animated face mesh overlays","maintainers":[{"name":"data_is_null","email":"hamidakhmedovwork@gmail.com"}],"readme":"# face-map-expo\n\nExpo native module that detects facial landmarks on static images and renders animated face mesh overlays.\n\n- **iOS** — Apple Vision framework (`VNDetectFaceLandmarksRequest`)\n- **Android** — Google ML Kit Face Detection (`com.google.mlkit:face-detection`)\n\n## Installation\n\n```bash\nnpx expo install @data_is_null/face-map-expo @shopify/react-native-skia react-native-reanimated react-native-worklets\n```\n\nThis module uses native code. It **does not work in Expo Go** — you need a development build:\n\n```bash\nnpx expo prebuild\nnpx expo run:ios    # or run:android\n```\n\n### iOS\n\nNo additional setup. Uses the built-in Vision framework. Minimum deployment target: iOS 15.1.\n\n### Android\n\nML Kit is bundled automatically via the module's `build.gradle`. No manual dependency setup needed.\n\n## API Reference\n\n### `detectFaceLandmarks(imageUri: string): Promise<FaceMeshResult>`\n\nDetects facial landmarks in an image. Returns normalized coordinates (0..1).\n\n**Parameters:**\n- `imageUri` — Local file URI (`file://...`), content URI (Android), or remote HTTP(S) URL.\n\n**Returns:**\n\n```ts\ntype FacePoint = { x: number; y: number };\n\ntype FaceRegion =\n  | 'faceContour' | 'leftEye' | 'rightEye'\n  | 'leftEyebrow' | 'rightEyebrow' | 'nose'\n  | 'outerLips' | 'innerLips' | 'leftPupil' | 'rightPupil';\n\ntype FaceMeshResult = {\n  points: FacePoint[];                       // flat array of all detected points\n  regions: Record<FaceRegion, FacePoint[]>;  // points grouped by facial region\n  bounds: {                                  // normalized face bounding box\n    x: number;\n    y: number;\n    width: number;\n    height: number;\n  };\n  imageWidth: number;\n  imageHeight: number;\n};\n```\n\n**Error codes** (Promise rejection):\n\n| Code | Meaning |\n|------|---------|\n| `ERR_INVALID_IMAGE` | Could not load or decode the image |\n| `ERR_NO_FACE` | No face detected in the image |\n| `ERR_DETECTION_FAILED` | Detection engine error |\n\n### `useFaceMesh(imageUri: string | undefined)`\n\nReact hook wrapper. Re-runs detection when `imageUri` changes.\n\n```tsx\nconst { result, loading, error } = useFaceMesh(imageUri);\n```\n\n### `<FaceMeshOverlay />`\n\nRenders an animated face mesh overlay using `@shopify/react-native-skia` and `react-native-reanimated`.\n\n```tsx\n<FaceMeshOverlay\n  imageUri={uri}\n  width={300}\n  height={400}\n  animationStyle=\"radialPulse\"\n  dotColor=\"#4A9EFF\"\n  dotSize={2}\n  lineColor=\"rgba(74, 158, 255, 0.5)\"\n  showLines\n/>\n```\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `imageUri` | `string` | **required** | Image URI to detect faces in |\n| `width` | `number` | **required** | Overlay width in pixels |\n| `height` | `number` | **required** | Overlay height in pixels |\n| `animationStyle` | `AnimationStyle` | `'sequentialScan'` | Animation pattern |\n| `duration` | `number` | `2500` | Animation cycle duration (ms) |\n| `dotColor` | `string` | `'#4A9EFF'` | Landmark dot color |\n| `dotSize` | `number` | `2` | Landmark dot radius |\n| `lineColor` | `string` | `'rgba(74, 158, 255, 0.5)'` | Connecting line color |\n| `showLines` | `boolean` | `true` | Draw lines between region points |\n\n**Animation styles:**\n\n| Style | Description |\n|-------|-------------|\n| `sequentialScan` | Top-to-bottom sweep |\n| `radialPulse` | Outward from center |\n| `randomReveal` | Dots pop in randomly |\n| `progressFill` | Left-to-right fill |\n\nEach dot appears with a scale-up animation and a soft glow halo. Lines between region points fade in smoothly. Eye and lip regions draw as closed paths.\n\n## Platform Differences\n\n### Landmark Density\n\n| | iOS (Vision) | Android (ML Kit) |\n|---|---|---|\n| **Total points** | ~70–80 | ~130+ |\n| **Face contour** | Variable-length | 36 fixed points |\n| **Eyes** | Variable-length | 16 points each |\n| **Eyebrows** | Single region | Combined from top + bottom contours |\n| **Nose** | Single region | Combined from bridge + bottom contours |\n| **Lips** | `outerLips` / `innerLips` | Combined from upper/lower top/bottom |\n| **Pupils** | Dedicated region | Single landmark point each |\n\niOS Vision also detects `noseCrest` and `medianLine` regions which are not included in the cross-platform output.\n\n### Coordinate System\n\nBoth platforms normalize coordinates to 0..1 relative to image dimensions. iOS Vision uses bottom-left origin internally (converted to top-left by the module). Android ML Kit uses top-left origin natively.\n\n### Camera Capture\n\nOn iOS, images captured via `expo-camera` CameraView (`takePictureAsync`) produce view snapshots at screen resolution. The module includes a fallback that re-renders these into standard bitmaps for reliable detection. Photos from the system camera (`ImagePicker.launchCameraAsync`) or photo library work without fallback.\n\n## Usage Example\n\n```tsx\nimport { useState } from 'react';\nimport { Image, View, Button, Dimensions } from 'react-native';\nimport * as ImagePicker from 'expo-image-picker';\nimport { FaceMeshOverlay } from 'face-map-expo';\n\nconst W = Dimensions.get('window').width;\n\nexport default function FaceScreen() {\n  const [uri, setUri] = useState<string>();\n  const [size, setSize] = useState({ w: W, h: W });\n\n  const pick = async () => {\n    const r = await ImagePicker.launchCameraAsync({ mediaTypes: ['images'], quality: 1 });\n    if (!r.canceled) {\n      const a = r.assets[0];\n      setUri(a.uri);\n      setSize({ w: W, h: W * (a.height / a.width) });\n    }\n  };\n\n  return (\n    <View style={{ flex: 1 }}>\n      <Button title=\"Take Photo\" onPress={pick} />\n      {uri && (\n        <View style={{ width: size.w, height: size.h }}>\n          <Image source={{ uri }} style={{ width: size.w, height: size.h }} />\n          <FaceMeshOverlay\n            imageUri={uri}\n            width={size.w}\n            height={size.h}\n            animationStyle=\"radialPulse\"\n            showLines\n          />\n        </View>\n      )}\n    </View>\n  );\n}\n```\n\n## Permissions\n\nThe module itself requires no permissions. The example app uses `expo-camera` and `expo-image-picker`:\n\n| Platform | Permission | Purpose |\n|----------|-----------|---------|\n| iOS | `NSCameraUsageDescription` | Camera access |\n| iOS | `NSPhotoLibraryUsageDescription` | Photo library access |\n| Android | `CAMERA` | Camera access |\n| Android | `READ_MEDIA_IMAGES` (API 33+) | Photo library access |\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\ncd example && npm install\n\n# Run example app\ncd example\nnpx expo prebuild --clean\nnpx expo run:ios\n# or\nnpx expo run:android\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}