Functions
Everything the package exports besides the <PoseCamera> component, on one page. The component has pages of its own: props, ref methods and events.
import {
detectOnImage, detectOnVideo, exportPose,
useCameraPermission, getCameraPermission, requestCameraPermission,
validateTriggers, assertValidTriggers,
landmark, landmarkInto, createLandmark, worldLandmark, visibilityOf, isVisible, hasLandmark,
isJointName, isAngleJointName,
setLogLevel, addLogListener,
PoseConfigError,
} from 'react-native-pose-detection';| Function | Returns | What it does |
|---|---|---|
detectOnImage(uri, options?) | Promise<PoseFrame[]> | Landmarks from a photo |
detectOnVideo(uri, options?) | VideoTask | Landmarks from a video, sampled, cancellable |
exportPose(uri, options?) | ExportTask | A copy of a photo or video with the skeleton painted in |
useCameraPermission(options?) | UseCameraPermission | The camera permission as React state, asked for on mount |
getCameraPermission() | Promise<CameraPermission> | Reads the permission, never prompts |
requestCameraPermission() | Promise<CameraPermission> | Prompts when the system still will |
validateTriggers(triggers) | ValidationIssue[] | Checks trigger configs without rendering |
assertValidTriggers(triggers) | void | The same check, throwing PoseConfigError |
landmark(frame, joint) | Landmark | One joint out of a PoseFrame |
landmarkInto(frame, joint, out) | out | The same, allocation-free |
createLandmark() | MutableLandmark | A reusable target for landmarkInto |
worldLandmark(frame, joint) | Landmark | null | One joint in meters, hip-centered |
visibilityOf(frame, joint) | number | One joint's visibility, 0 when absent |
isVisible(frame, joint, minVisibility?) | boolean | Visibility at or above minVisibility, 0.5 by default |
hasLandmark(frame, joint) | boolean | Whether the frame carries the joint: data.landmarks on, and kept by data.select |
isJointName(value) | boolean | Type guard for the 33 JointNames |
isAngleJointName(value) | boolean | Type guard for the 12 joints that have an angle |
setLogLevel(config) | void | Turns the diagnostic channel on, up or off |
addLogListener(listener) | Subscription | Log entries, batched |
PoseConfigError is the one error class, and the package's constants close the page.
Files
The same detector, no camera. The photos and video files guide has the full story: what each option costs, where exports land, cancelling, and backgrounding.
detectOnImage
detectOnImage(uri: string, options?: StaticOptions): Promise<PoseFrame[]>One PoseFrame per pose found, the largest body first. uri is a local file, a content:// URI on Android, or an http(s) URL, fetched whole before it is decoded.
| Option | Default |
|---|---|
maxPoses | 1, up to 5 |
minConfidence | 0.5 at maxPoses: 1, 0.3 above it; 0.1 to 1 |
angles | true, all twelve; or a list of AngleJointNames |
worldLandmarks | false |
select | all 33 joints |
Rejects with IMAGE_DECODE_FAILED, MODEL_NOT_FOUND or DETECTION_FAILED. See landmarks from an image.
A bad option is a PoseConfigError instead, as it is on the camera: a number that is not finite, or a select or angles joint that data would refuse. detectOnImage() rejects with it, and detectOnVideo() and exportPose() throw it from the call itself, before a task exists.
detectOnVideo
detectOnVideo(uri: string, options?: VideoOptions): VideoTask
type VideoTask = {
readonly frames: Promise<PoseFrame[]>;
cancel(): void; // frames then resolves with what was decoded so far
};VideoOptions is everything detectOnImage takes, plus:
| Option | Default |
|---|---|
fps | 10, samples a second, not the video's own rate |
startMs / endMs | the whole clip |
smoothing | 'auto': off for one pose, on for several |
onProgress | (progress: number) => void, 0 to 1 |
Each frame's timestamp is its position in the video in milliseconds. Rejects with VIDEO_DECODE_FAILED, MODEL_NOT_FOUND or DETECTION_FAILED, and resolves rather than rejects after cancel(). See landmarks from a video.
exportPose
exportPose(uri: string, options?: ExportOptions): ExportTask
type ExportTask = {
readonly result: Promise<ExportResult>;
cancel(): void;
};
type ExportResult = {
readonly uri: string; // file:// inside your app's sandbox
readonly width: number;
readonly height: number;
readonly durationMs: number; // 0 for a photo
readonly frameCount: number; // 1 for a photo
readonly posesFound: number; // a photo: poses painted; a video: frames with one
};Paints the skeleton into a copy of a photo or a video with the renderer the live camera uses. The options are overlay, maxPoses, minConfidence (0.1 to 1), fps, maxSize, directory, fileName, quality (0.1 to 1) and onProgress; their defaults are in export options. Rejects with EXPORT_CANCELLED after cancel(), which stops a video export, or any export still queued behind another, but not a photo export already running, and EXPORT_FAILED when the file cannot be read, painted or written. A cancelled or failed export deletes its own partial file and leaves any earlier export under the same name as it was. See painting a copy.
Camera permission
Nothing else in the package prompts: <PoseCamera> reports PERMISSION_DENIED and stops, so when to ask stays your decision. The camera permission reference explains the four states and why blocked is not denied.
type CameraPermission = {
readonly status: 'granted' | 'denied' | 'blocked' | 'undetermined';
readonly granted: boolean;
readonly canAskAgain: boolean; // false and not granted: send the user to Linking.openSettings()
};useCameraPermission
useCameraPermission(options?: { ask?: boolean }): UseCameraPermissionThe permission as React state, asked for on mount unless ask is false. It adds pending, request() and error to CameraPermission. error is set when reading or asking fails, which means an incomplete install: an app built without the native module, an Expo Go session for instance, or an Android app with no Expo permissions manager. request() never rejects: a failure resolves with undetermined and sets error. See camera permission.
getCameraPermission
getCameraPermission(): Promise<CameraPermission>Reads the current status. Never prompts, so it is safe anywhere.
requestCameraPermission
requestCameraPermission(): Promise<CameraPermission>Prompts when the system still will, and resolves with the outcome either way: at once, without a dialog, when the status is already granted or blocked. On Android, an app whose Expo modules are not fully installed has no permissions manager to ask, and this rejects with PERMISSIONS_UNAVAILABLE.
Triggers
<PoseCamera> checks its triggers during render and throws on a bad one, so these are only needed for configs you build at runtime and want to check first. The rules are in the trigger schema.
validateTriggers
validateTriggers(triggers: readonly Trigger[]): ValidationIssue[]
type ValidationIssue = { path: string; message: string }; // path: 'triggers[0].enter.angle'Every problem found, not just the first. Empty when the config is fine.
assertValidTriggers
assertValidTriggers(triggers: readonly Trigger[]): voidThrows PoseConfigError listing every problem, which is what <PoseCamera> does.
Reading a frame
A PoseFrame holds its landmarks in one Float32Array. These read a joint out of it without copying or parsing anything, and account for data.select:
const knee = landmark(frame, 'leftKnee'); // { x, y, z, visibility }
if (isVisible(frame, 'leftWrist')) { /* trust its coordinates */ }landmark, landmarkInto and worldLandmark throw PoseConfigError for a joint data.select left out, and the first two also for a frame sent with data.landmarks off; hasLandmark and visibilityOf let you branch instead. The allocation of each, and the buffer layout underneath, are in types → accessors.
Joint names
isJointName(value: unknown): value is JointName
isAngleJointName(value: unknown): value is AngleJointNameType guards for values that arrive as plain strings, from storage or a server. The 33 names are in types, and the twelve that have an angle under AngleJointName.
Diagnostics
A log channel that is off by default and costs nothing until you turn it on. Entries always reach Logcat on Android and os.Logger on iOS; the functions below bring them into JavaScript. See the log channel.
setLogLevel
setLogLevel(config: LogLevel | Partial<Record<LogCategory, LogLevel>>): void
// LogLevel: 'off' | 'error' | 'warn' | 'info' | 'debug' | 'trace'
// LogCategory: 'camera' | 'detector' | 'engine' | 'triggers' | 'calibration' | 'overlay'Sets the level for the whole app, or per category with a map. Throws PoseConfigError on an unknown level or category, because a level that silently failed to apply looks like the bug you were trying to find. A camera's logLevel prop raises it while that camera is mounted, and is checked the same way during render.
addLogListener
addLogListener(listener: (entries: readonly LogEntry[]) => void): Subscription
type LogEntry = {
readonly level: 'error' | 'warn' | 'info' | 'debug' | 'trace';
readonly category: LogCategory;
readonly message: string;
readonly timestamp: number; // the clock PoseFrame.timestamp uses
readonly data?: Readonly<Record<string, number | string | boolean>>;
};Entries arrive in batches about every 250 ms, with or without a camera on screen, so a photo detection or an export can be watched too. The native stream runs only while a listener is attached, or a camera with an onLog prop is mounted. Call remove() on the returned subscription to stop; the same function added twice needs two.
When more than 256 entries pile up between two batches, the oldest are dropped, and the next batch opens with a warn entry whose data.droppedCount is how many.
Errors
class PoseConfigError extends Error {
readonly issues: readonly ValidationIssue[];
}Thrown for a configuration mistake:
- a bad trigger, or a bad
dataconfig: an unknownmode, or aselectoranglesjoint that does not exist or has no angle - a numeric prop or file option that is not a finite number, and the same joint mistakes in the file functions'
selectandangles - an unknown log level or category, from
setLogLevel()or thelogLevelprop - a landmark read the frame cannot answer: a joint
data.selectexcluded, or any joint withdata.landmarksoff
Out-of-range prop and file-option numbers are clamped natively rather than thrown; trigger bounds are range-checked and throw. It carries every problem it found on issues.
Runtime failures are not thrown: they arrive as onError codes on the camera and as rejections with a code from the file functions, all listed in error codes.
Constants
| Constant | Value |
|---|---|
JOINT_NAMES | the 33 JointNames, in landmark order |
JOINT_INDEX | JointName → landmark index |
LANDMARK_COUNT | 33 |
ANGLE_JOINT_NAMES | the 12 AngleJointNames |
ANGLE_JOINTS | each angle joint's [proximal, vertex, distal] triple |
POSE_CONNECTIONS | the 35 skeleton bones as [JointName, JointName] pairs |
POSE_CONNECTION_INDICES | the same bones as index pairs |
CONNECTION_COUNT | 35 |
LANDMARK_STRIDE | 4 floats per landmark |
LANDMARK_OFFSET | { x: 0, y: 1, z: 2, visibility: 3 } |
FULL_FRAME_FLOAT_COUNT | 132, floats in an unselected frame |
FULL_FRAME_BYTE_LENGTH | 528, bytes in an unselected frame |
ERROR_CODES | every ErrorCode |
LOG_LEVELS | every LogLevel |
LOG_CATEGORIES | every LogCategory |
Every type is exported too: types covers PoseFrame and the wire format, and each page above names the types its functions take.