@pose-tracker/react-native-pose-estimation-light 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -2
- package/lib/PoseTrackerProvider.js +3 -0
- package/lib/backends/webview/WebViewPoseBackend.d.ts +1 -1
- package/lib/backends/webview/onlineRuntime.d.ts +14 -4
- package/lib/backends/webview/onlineRuntime.js +22 -4
- package/lib/backends/webview/poseHtml.d.ts +12 -4
- package/lib/backends/webview/poseHtml.js +15 -6
- package/lib/backends/webview/poseRuntimeSource.js +2 -2
- package/lib/camera/WebViewPoseView.d.ts +12 -0
- package/lib/camera/WebViewPoseView.js +29 -0
- package/lib/client.d.ts +13 -2
- package/lib/client.js +9 -1
- package/lib/engine/types.d.ts +5 -0
- package/lib/events/classicMessage.d.ts +2 -2
- package/lib/events/classicMessage.js +4 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.js +4 -2
- package/lib/models/poseModels.d.ts +8 -6
- package/lib/models/poseModels.js +9 -8
- package/lib/sdkVersion.d.ts +1 -1
- package/lib/sdkVersion.js +1 -1
- package/lib/types/events.d.ts +37 -2
- package/lib/types/features.d.ts +2 -2
- package/lib/types/features.js +8 -9
- package/package.json +1 -1
- package/src/PoseTrackerProvider.tsx +3 -0
- package/src/backends/webview/WebViewPoseBackend.ts +1 -1
- package/src/backends/webview/onlineRuntime.ts +36 -5
- package/src/backends/webview/poseHtml.ts +23 -6
- package/src/camera/WebViewPoseView.tsx +43 -0
- package/src/client.ts +25 -5
- package/src/engine/types.ts +5 -0
- package/src/events/classicMessage.ts +7 -2
- package/src/index.ts +3 -0
- package/src/models/poseModels.ts +14 -11
- package/src/sdkVersion.ts +1 -1
- package/src/types/events.ts +35 -0
- package/src/types/features.ts +8 -9
|
@@ -178,6 +178,8 @@ function WebViewPoseView(props) {
|
|
|
178
178
|
// injected via __PT_SET_SKELETON (avoids remounting on uuid fetch).
|
|
179
179
|
skeletonDef: props.skeletonDef ?? null,
|
|
180
180
|
capturePriority: client.getQualityState().capturePriority,
|
|
181
|
+
sourceType: props.source ?? 'camera',
|
|
182
|
+
sourceUrl: props.sourceUri,
|
|
181
183
|
});
|
|
182
184
|
}, [
|
|
183
185
|
facingMode,
|
|
@@ -188,6 +190,8 @@ function WebViewPoseView(props) {
|
|
|
188
190
|
coldStart,
|
|
189
191
|
loadingText,
|
|
190
192
|
props.skeletonDef,
|
|
193
|
+
props.source,
|
|
194
|
+
props.sourceUri,
|
|
191
195
|
]);
|
|
192
196
|
// Apply custom skeleton (uuid fetch or prop) without remounting the page.
|
|
193
197
|
(0, react_1.useEffect)(() => {
|
|
@@ -210,6 +214,31 @@ function WebViewPoseView(props) {
|
|
|
210
214
|
const payload = JSON.stringify(loadingText);
|
|
211
215
|
webRef.current?.injectJavaScript?.(`window.__PT_SET_LOADING_TEXT && window.__PT_SET_LOADING_TEXT(${payload}); true;`);
|
|
212
216
|
}, [isWebViewBackend, html, loadingText]);
|
|
217
|
+
// Live source switches after first HTML boot (CFG already has initial source).
|
|
218
|
+
const lastSourceHtmlRef = (0, react_1.useRef)(null);
|
|
219
|
+
(0, react_1.useEffect)(() => {
|
|
220
|
+
if (!isWebViewBackend || !html)
|
|
221
|
+
return;
|
|
222
|
+
if (lastSourceHtmlRef.current !== html) {
|
|
223
|
+
lastSourceHtmlRef.current = html;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const type = props.source ?? 'camera';
|
|
227
|
+
const payload = JSON.stringify({
|
|
228
|
+
type,
|
|
229
|
+
url: props.sourceUri ?? null,
|
|
230
|
+
base64: props.sourceBase64 ?? null,
|
|
231
|
+
mime: props.sourceMime ?? null,
|
|
232
|
+
});
|
|
233
|
+
webRef.current?.injectJavaScript?.(`window.__PT_SET_SOURCE && window.__PT_SET_SOURCE(${payload}); true;`);
|
|
234
|
+
}, [
|
|
235
|
+
isWebViewBackend,
|
|
236
|
+
html,
|
|
237
|
+
props.source,
|
|
238
|
+
props.sourceUri,
|
|
239
|
+
props.sourceBase64,
|
|
240
|
+
props.sourceMime,
|
|
241
|
+
]);
|
|
213
242
|
(0, react_1.useEffect)(() => {
|
|
214
243
|
if (!(backend instanceof WebViewPoseBackend_1.WebViewPoseBackend)) {
|
|
215
244
|
return;
|
package/lib/client.d.ts
CHANGED
|
@@ -60,8 +60,8 @@ export interface PoseTrackerClientOptions extends ConfigureOptions {
|
|
|
60
60
|
usageTracker?: UsageTracker;
|
|
61
61
|
/**
|
|
62
62
|
* Docs API `model` query parity (`movenet` default, `blazepose`, …).
|
|
63
|
-
* BlazePose
|
|
64
|
-
*
|
|
63
|
+
* BlazePose loads via CDN pose-detection in the WebView (heavier than
|
|
64
|
+
* MoveNet). Ignored when {@link modelUrl} is set.
|
|
65
65
|
*/
|
|
66
66
|
model?: PoseModelAlias;
|
|
67
67
|
/**
|
|
@@ -102,6 +102,12 @@ export interface PoseTrackerClientOptions extends ConfigureOptions {
|
|
|
102
102
|
* triaging Android GPU issues in the field.
|
|
103
103
|
*/
|
|
104
104
|
onDiagnostic?: (message: string) => void;
|
|
105
|
+
/**
|
|
106
|
+
* When true, exercise sessions request `engine_debug` snapshots from the
|
|
107
|
+
* remote engine (bundle ≥ 1.2.4). Overridable per call via
|
|
108
|
+
* `startExercise(id, { debug: true|false })`.
|
|
109
|
+
*/
|
|
110
|
+
debugEngine?: boolean;
|
|
105
111
|
}
|
|
106
112
|
/**
|
|
107
113
|
* Per-session options for {@link PoseTrackerClient.startExercise} — the SDK
|
|
@@ -118,6 +124,11 @@ export interface StartExerciseOptions {
|
|
|
118
124
|
userHeightCm?: number;
|
|
119
125
|
/** Device pitch in degrees — jump exercises compensate camera tilt. */
|
|
120
126
|
devicePitchDeg?: number;
|
|
127
|
+
/**
|
|
128
|
+
* Request throttled `engine_debug` events for this session (movement FSM
|
|
129
|
+
* QA). Defaults to {@link PoseTrackerClientOptions.debugEngine}.
|
|
130
|
+
*/
|
|
131
|
+
debug?: boolean;
|
|
121
132
|
}
|
|
122
133
|
export declare class PoseTrackerClient {
|
|
123
134
|
private status;
|
package/lib/client.js
CHANGED
|
@@ -398,7 +398,7 @@ class PoseTrackerClient {
|
|
|
398
398
|
tfjsVersion: this.options.tfjsVersion,
|
|
399
399
|
});
|
|
400
400
|
this.options.onDiagnostic?.(`[posetracker-light] pose-runtime online version=${parts.version} ` +
|
|
401
|
-
`modelId=${parts.modelId} modelUrl=${parts.modelUrl}`);
|
|
401
|
+
`modelId=${parts.modelId} modelKind=${parts.modelKind} modelUrl=${parts.modelUrl}`);
|
|
402
402
|
return parts;
|
|
403
403
|
}
|
|
404
404
|
/**
|
|
@@ -818,17 +818,21 @@ class PoseTrackerClient {
|
|
|
818
818
|
this.stopExercise();
|
|
819
819
|
this.currentExerciseId = exerciseId;
|
|
820
820
|
this.keypointsSuppressionLogged = false;
|
|
821
|
+
const debug = options.debug ?? this.options.debugEngine === true;
|
|
821
822
|
this.session = this.engine.createSession({
|
|
822
823
|
exercise,
|
|
823
824
|
locale: this.options.locale ?? 'en',
|
|
824
825
|
difficulty: options.difficulty,
|
|
825
826
|
minGrade: this.features.minGrade ?? undefined,
|
|
827
|
+
debug,
|
|
826
828
|
features: {
|
|
827
829
|
angles: this.features.angles,
|
|
828
830
|
recommendations: this.features.recommendations,
|
|
829
831
|
progression: this.features.progression,
|
|
830
832
|
},
|
|
831
833
|
}, (event) => this.emitFromSession(event));
|
|
834
|
+
this.options.onDiagnostic?.(`[posetracker] startExercise id=${exercise.id} difficulty=${options.difficulty ?? 'medium'} ` +
|
|
835
|
+
`debug=${debug} engine=${this.engine.version} minGrade=${this.features.minGrade ?? 'off'}`);
|
|
832
836
|
}
|
|
833
837
|
/** Custom engine session (jump_analysis / air_time_jump). */
|
|
834
838
|
startCustomExercise(custom, options) {
|
|
@@ -1032,6 +1036,10 @@ class PoseTrackerClient {
|
|
|
1032
1036
|
return;
|
|
1033
1037
|
}
|
|
1034
1038
|
const classic = (0, classicMessage_1.toClassicNativeMessage)(event);
|
|
1039
|
+
if (classic == null) {
|
|
1040
|
+
// SDK-only events (e.g. engine_debug) have no classic equivalent.
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1035
1043
|
this.messageListeners.forEach((l) => {
|
|
1036
1044
|
try {
|
|
1037
1045
|
l(classic);
|
package/lib/engine/types.d.ts
CHANGED
|
@@ -36,6 +36,11 @@ export interface EngineSessionOptions {
|
|
|
36
36
|
minGrade?: MinGrade;
|
|
37
37
|
/** Emission flags — engines older than 1.1.0 ignore them (client re-filters). */
|
|
38
38
|
features?: EngineSessionFeatures;
|
|
39
|
+
/**
|
|
40
|
+
* When true, the engine emits throttled `engine_debug` events (movement
|
|
41
|
+
* FSM snapshot). Requires engine bundle ≥ 1.2.4. Ignored by older engines.
|
|
42
|
+
*/
|
|
43
|
+
debug?: boolean;
|
|
39
44
|
}
|
|
40
45
|
export interface EngineSession {
|
|
41
46
|
/** Feed one estimated pose; the session emits events through the sink. */
|
|
@@ -26,6 +26,6 @@ export declare function anglesToClassicTree(angles: AngleValue[]): {
|
|
|
26
26
|
/**
|
|
27
27
|
* Map a typed SDK event to a classic PoseTracker `sendDataToNative` payload.
|
|
28
28
|
* Returns null for SDK-only events that have no classic equivalent and should
|
|
29
|
-
* not be mirrored (
|
|
29
|
+
* not be mirrored (e.g. `engine_debug` QA snapshots).
|
|
30
30
|
*/
|
|
31
|
-
export declare function toClassicNativeMessage(event: PoseTrackerEvent): ClassicNativeMessage;
|
|
31
|
+
export declare function toClassicNativeMessage(event: PoseTrackerEvent): ClassicNativeMessage | null;
|
|
@@ -49,7 +49,7 @@ function anglesToClassicTree(angles) {
|
|
|
49
49
|
/**
|
|
50
50
|
* Map a typed SDK event to a classic PoseTracker `sendDataToNative` payload.
|
|
51
51
|
* Returns null for SDK-only events that have no classic equivalent and should
|
|
52
|
-
* not be mirrored (
|
|
52
|
+
* not be mirrored (e.g. `engine_debug` QA snapshots).
|
|
53
53
|
*/
|
|
54
54
|
function toClassicNativeMessage(event) {
|
|
55
55
|
switch (event.type) {
|
|
@@ -236,6 +236,9 @@ function toClassicNativeMessage(event) {
|
|
|
236
236
|
totalParts: event.totalParts,
|
|
237
237
|
timestampMs: event.timestampMs,
|
|
238
238
|
};
|
|
239
|
+
case 'engine_debug':
|
|
240
|
+
// SDK-only QA stream — no classic WebView equivalent; skip onMessage.
|
|
241
|
+
return null;
|
|
239
242
|
default: {
|
|
240
243
|
const _exhaustive = event;
|
|
241
244
|
return { type: 'unknown', event: _exhaustive };
|
package/lib/index.d.ts
CHANGED
|
@@ -19,10 +19,10 @@ export { UsageTracker, TrackError } from './api/track';
|
|
|
19
19
|
export type { TrackRequest, TrackResponse, UsageTrackerOptions } from './api/track';
|
|
20
20
|
export { RuntimeCache } from './runtime/RuntimeCache';
|
|
21
21
|
export type { PoseRuntimeParts, RuntimeCacheOptions, RuntimeCacheProgress, } from './runtime/RuntimeCache';
|
|
22
|
-
export { getOnlineRuntimeParts, getOnlineRuntimeVersion, defaultOnlineRuntimeUrls, ONLINE_TFJS_VERSION, } from './backends/webview/onlineRuntime';
|
|
22
|
+
export { getOnlineRuntimeParts, getOnlineRuntimeVersion, defaultOnlineRuntimeUrls, defaultPoseDetectionCdnUrl, ONLINE_TFJS_VERSION, ONLINE_POSE_DETECTION_VERSION, } from './backends/webview/onlineRuntime';
|
|
23
23
|
export type { GetOnlineRuntimeOptions, OnlineRuntimeParts, OnlineRuntimeUrls, } from './backends/webview/onlineRuntime';
|
|
24
24
|
export { DEFAULT_MOVENET_LIGHTNING_URL, originFromModelUrl, resolvePoseModel, } from './models/poseModels';
|
|
25
|
-
export type { PoseModelAlias, ResolvePoseModelOptions, ResolvedPoseModel, } from './models/poseModels';
|
|
25
|
+
export type { PoseModelAlias, PoseModelKind, ResolvePoseModelOptions, ResolvedPoseModel, } from './models/poseModels';
|
|
26
26
|
export { PoseTrackerClient } from './client';
|
|
27
27
|
export type { PoseTrackerClientOptions, PreferredBackend, StartExerciseOptions } from './client';
|
|
28
28
|
export type { ColdStartMode, PreloadOptions } from './types/preload';
|
package/lib/index.js
CHANGED
|
@@ -28,8 +28,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
28
28
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
29
29
|
};
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
-
exports.
|
|
32
|
-
exports.resolveFeatures = exports.shouldShowWatermark = exports.isPaidPlan = exports.freeBlockedFeatures = exports.featureNotSupportedMessage = exports.COMBINED_REFERENCE_EXERCISE_MESSAGE = exports.INVALID_TOKEN_MESSAGE = exports.FREE_PLAN_FEATURES_MESSAGE = exports.DEFAULT_FEATURES = exports.RuntimeGuard = exports.scoreDeviceCapability = exports.profileFromScore = exports.isMaliRenderer = exports.ENABLE_MALI_HARD_CAP = exports.CAPTURE_CONSTRAINT_MODE = exports.ANDROID_SOFT_CAP_PROFILE = exports.ANDROID_PREPROCESS_PATH = exports.ANDROID_PERF_DEBUG = exports.ANDROID_MIN_TARGET_FPS = exports.ANDROID_INFER_FRAME_SKIP = exports.profileFromWarmupMedianMs = exports.nextLowerQualityProfile = exports.minMedianMsForMinTarget = exports.lowerQualityProfile = exports.isQualityProfileId = exports.getQualityProfile = exports.getMinTargetFps = exports.getIdealFpsRange = exports.getCriticalFpsThreshold = exports.estimatedFpsFromMedianMs = exports.currentQualityPlatform = exports.TARGET_MEDIAN_MS = exports.TARGET_FPS = exports.QUALITY_PROFILES = exports.QUALITY_LADDER = exports.MIN_TARGET_FPS_IOS = exports.MIN_TARGET_FPS_DEFAULT = exports.MIN_TARGET_FPS_ANDROID = exports.QUALITY_SETTLE_MS = exports.LOW_FPS_STREAK_BEFORE_DOWNGRADE = exports.IDEAL_FPS_RANGE_IOS = exports.IDEAL_FPS_RANGE_ANDROID = exports.CRITICAL_FPS_THRESHOLD = exports.AdaptiveQualityController = exports.toClassicNativeMessage = void 0;
|
|
31
|
+
exports.logAccelerationReport = exports.defaultDiagnosticLogger = exports.createNativeFileStore = exports.createMemoryFileStore = exports.createBlobUtilFileStore = exports.createRnfsFileStore = exports.createExpoFileStore = exports.EngineLoader = exports.isExpoGo = exports.PoseCameraView = exports.VISION_JOINT_TO_SDK = exports.poseFromVisionPluginResult = exports.VISION_BODY_POSE_PLUGIN_NAME = exports.isVisionPoseCameraAvailable = exports.isVisionBackendAvailable = exports.VisionUnavailableError = exports.VisionPoseBackend = exports.POSETRACKER_LOGO_DATA_URL = exports.POSE_HTML_BUILD = exports.DEFAULT_LOADING_TEXT = exports.buildPoseHtml = exports.WebViewPoseView = exports.isWebViewPoseBackend = exports.WebViewPoseBackend = exports.usePoseTracker = exports.PoseTrackerProvider = exports.SkeletonFetchError = exports.fetchSkeletonDefinition = exports.DEFAULT_SKELETON_DEFINITION = exports.PoseTrackerClient = exports.resolvePoseModel = exports.originFromModelUrl = exports.DEFAULT_MOVENET_LIGHTNING_URL = exports.ONLINE_POSE_DETECTION_VERSION = exports.ONLINE_TFJS_VERSION = exports.defaultPoseDetectionCdnUrl = exports.defaultOnlineRuntimeUrls = exports.getOnlineRuntimeVersion = exports.getOnlineRuntimeParts = exports.RuntimeCache = exports.TrackError = exports.UsageTracker = exports.resolveExerciseName = exports.findExerciseByIdOrAlias = exports.EXERCISE_ALIASES = exports.SDK_VERSION = exports.SDK_NAME = exports.DEFAULT_BASE_URL = exports.ConfigureError = exports.configure = void 0;
|
|
32
|
+
exports.resolveFeatures = exports.shouldShowWatermark = exports.isPaidPlan = exports.freeBlockedFeatures = exports.featureNotSupportedMessage = exports.COMBINED_REFERENCE_EXERCISE_MESSAGE = exports.INVALID_TOKEN_MESSAGE = exports.FREE_PLAN_FEATURES_MESSAGE = exports.DEFAULT_FEATURES = exports.RuntimeGuard = exports.scoreDeviceCapability = exports.profileFromScore = exports.isMaliRenderer = exports.ENABLE_MALI_HARD_CAP = exports.CAPTURE_CONSTRAINT_MODE = exports.ANDROID_SOFT_CAP_PROFILE = exports.ANDROID_PREPROCESS_PATH = exports.ANDROID_PERF_DEBUG = exports.ANDROID_MIN_TARGET_FPS = exports.ANDROID_INFER_FRAME_SKIP = exports.profileFromWarmupMedianMs = exports.nextLowerQualityProfile = exports.minMedianMsForMinTarget = exports.lowerQualityProfile = exports.isQualityProfileId = exports.getQualityProfile = exports.getMinTargetFps = exports.getIdealFpsRange = exports.getCriticalFpsThreshold = exports.estimatedFpsFromMedianMs = exports.currentQualityPlatform = exports.TARGET_MEDIAN_MS = exports.TARGET_FPS = exports.QUALITY_PROFILES = exports.QUALITY_LADDER = exports.MIN_TARGET_FPS_IOS = exports.MIN_TARGET_FPS_DEFAULT = exports.MIN_TARGET_FPS_ANDROID = exports.QUALITY_SETTLE_MS = exports.LOW_FPS_STREAK_BEFORE_DOWNGRADE = exports.IDEAL_FPS_RANGE_IOS = exports.IDEAL_FPS_RANGE_ANDROID = exports.CRITICAL_FPS_THRESHOLD = exports.AdaptiveQualityController = exports.toClassicNativeMessage = exports.logPlatformBanner = exports.logFrameStats = void 0;
|
|
33
33
|
// Handshake + usage tracking
|
|
34
34
|
var configure_1 = require("./api/configure");
|
|
35
35
|
Object.defineProperty(exports, "configure", { enumerable: true, get: function () { return configure_1.configure; } });
|
|
@@ -51,7 +51,9 @@ var onlineRuntime_1 = require("./backends/webview/onlineRuntime");
|
|
|
51
51
|
Object.defineProperty(exports, "getOnlineRuntimeParts", { enumerable: true, get: function () { return onlineRuntime_1.getOnlineRuntimeParts; } });
|
|
52
52
|
Object.defineProperty(exports, "getOnlineRuntimeVersion", { enumerable: true, get: function () { return onlineRuntime_1.getOnlineRuntimeVersion; } });
|
|
53
53
|
Object.defineProperty(exports, "defaultOnlineRuntimeUrls", { enumerable: true, get: function () { return onlineRuntime_1.defaultOnlineRuntimeUrls; } });
|
|
54
|
+
Object.defineProperty(exports, "defaultPoseDetectionCdnUrl", { enumerable: true, get: function () { return onlineRuntime_1.defaultPoseDetectionCdnUrl; } });
|
|
54
55
|
Object.defineProperty(exports, "ONLINE_TFJS_VERSION", { enumerable: true, get: function () { return onlineRuntime_1.ONLINE_TFJS_VERSION; } });
|
|
56
|
+
Object.defineProperty(exports, "ONLINE_POSE_DETECTION_VERSION", { enumerable: true, get: function () { return onlineRuntime_1.ONLINE_POSE_DETECTION_VERSION; } });
|
|
55
57
|
var poseModels_1 = require("./models/poseModels");
|
|
56
58
|
Object.defineProperty(exports, "DEFAULT_MOVENET_LIGHTNING_URL", { enumerable: true, get: function () { return poseModels_1.DEFAULT_MOVENET_LIGHTNING_URL; } });
|
|
57
59
|
Object.defineProperty(exports, "originFromModelUrl", { enumerable: true, get: function () { return poseModels_1.originFromModelUrl; } });
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* MoveNet SinglePose Lightning hosted at app.posetracker.com (same URL as
|
|
6
6
|
* `usePoseDetection` / tracking WebView `modelUrl`).
|
|
7
7
|
*
|
|
8
|
-
* BlazePose
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* BlazePose loads via CDN `@tensorflow-models/pose-detection` inside the
|
|
9
|
+
* WebView (no graph `modelUrl`). Pass a TF.js `modelUrl` for any custom
|
|
10
|
+
* graph model.
|
|
11
11
|
*/
|
|
12
12
|
/** Production MoveNet SinglePose Lightning topology (Front default). */
|
|
13
13
|
export declare const DEFAULT_MOVENET_LIGHTNING_URL = "https://app.posetracker.com/scripts/tmp_model_to_remove.json";
|
|
@@ -22,16 +22,18 @@ export interface ResolvePoseModelOptions {
|
|
|
22
22
|
/** Explicit TF.js graph-model topology URL (weights resolve as siblings). */
|
|
23
23
|
modelUrl?: string;
|
|
24
24
|
}
|
|
25
|
+
export type PoseModelKind = 'movenet-graph' | 'blazepose' | 'custom-graph' | 'unsupported';
|
|
25
26
|
export interface ResolvedPoseModel {
|
|
26
27
|
/** Stable id reported in diagnostics / track params. */
|
|
27
28
|
modelId: string;
|
|
28
|
-
|
|
29
|
+
kind: PoseModelKind;
|
|
30
|
+
/** TF.js `loadGraphModel` URL when kind is movenet-graph or custom-graph. */
|
|
29
31
|
modelUrl: string | null;
|
|
30
|
-
/** Human-readable reason when
|
|
32
|
+
/** Human-readable reason when kind is unsupported. */
|
|
31
33
|
unsupportedReason?: string;
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
34
|
-
* Resolve which
|
|
36
|
+
* Resolve which online pose model the light WebView should run.
|
|
35
37
|
* Default: MoveNet SinglePose Lightning (product URL).
|
|
36
38
|
*/
|
|
37
39
|
export declare function resolvePoseModel(options?: ResolvePoseModelOptions): ResolvedPoseModel;
|
package/lib/models/poseModels.js
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* MoveNet SinglePose Lightning hosted at app.posetracker.com (same URL as
|
|
7
7
|
* `usePoseDetection` / tracking WebView `modelUrl`).
|
|
8
8
|
*
|
|
9
|
-
* BlazePose
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* BlazePose loads via CDN `@tensorflow-models/pose-detection` inside the
|
|
10
|
+
* WebView (no graph `modelUrl`). Pass a TF.js `modelUrl` for any custom
|
|
11
|
+
* graph model.
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
14
|
exports.DEFAULT_MOVENET_LIGHTNING_URL = void 0;
|
|
@@ -17,7 +17,7 @@ exports.originFromModelUrl = originFromModelUrl;
|
|
|
17
17
|
/** Production MoveNet SinglePose Lightning topology (Front default). */
|
|
18
18
|
exports.DEFAULT_MOVENET_LIGHTNING_URL = 'https://app.posetracker.com/scripts/tmp_model_to_remove.json';
|
|
19
19
|
/**
|
|
20
|
-
* Resolve which
|
|
20
|
+
* Resolve which online pose model the light WebView should run.
|
|
21
21
|
* Default: MoveNet SinglePose Lightning (product URL).
|
|
22
22
|
*/
|
|
23
23
|
function resolvePoseModel(options = {}) {
|
|
@@ -28,27 +28,28 @@ function resolvePoseModel(options = {}) {
|
|
|
28
28
|
const alias = typeof options.model === 'string' && options.model.trim().length > 0
|
|
29
29
|
? options.model.trim()
|
|
30
30
|
: 'custom';
|
|
31
|
-
return { modelId: alias, modelUrl: explicit };
|
|
31
|
+
return { modelId: alias, kind: 'custom-graph', modelUrl: explicit };
|
|
32
32
|
}
|
|
33
33
|
const key = (options.model ?? 'movenet').trim().toLowerCase();
|
|
34
34
|
if (key === 'movenet' || key === 'movenet-singlepose-lightning' || key === 'lightning') {
|
|
35
35
|
return {
|
|
36
36
|
modelId: 'movenet-singlepose-lightning',
|
|
37
|
+
kind: 'movenet-graph',
|
|
37
38
|
modelUrl: exports.DEFAULT_MOVENET_LIGHTNING_URL,
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
if (key === 'blazepose') {
|
|
41
42
|
return {
|
|
42
43
|
modelId: 'blazepose',
|
|
44
|
+
kind: 'blazepose',
|
|
43
45
|
modelUrl: null,
|
|
44
|
-
unsupportedReason: 'BlazePose is not wired in the light RN WebView yet (needs MediaPipe). ' +
|
|
45
|
-
'Use model="movenet" or pass a TF.js graph modelUrl.',
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
return {
|
|
49
49
|
modelId: key,
|
|
50
|
+
kind: 'unsupported',
|
|
50
51
|
modelUrl: null,
|
|
51
|
-
unsupportedReason: `Unknown model "${options.model}". Use "movenet" (default) or pass modelUrl.`,
|
|
52
|
+
unsupportedReason: `Unknown model "${options.model}". Use "movenet" (default), "blazepose", or pass modelUrl.`,
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
55
|
/** Origin used as WebView `baseUrl` so model fetches are same-origin when possible. */
|
package/lib/sdkVersion.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** AUTO-GENERATED by scripts/sync-sdk-version.mjs — do not edit. */
|
|
2
|
-
export declare const SDK_VERSION = "0.1
|
|
2
|
+
export declare const SDK_VERSION = "0.2.1";
|
package/lib/sdkVersion.js
CHANGED
package/lib/types/events.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export type PoseTrackerStatus = 'idle' | 'configuring' | 'downloading' | 'warmin
|
|
|
23
23
|
* restarting the camera pipeline, via `configure()` or a preload retry.
|
|
24
24
|
*/
|
|
25
25
|
export type PoseTrackerMode = 'keypoints-only' | 'full-engine';
|
|
26
|
-
export type InitializationStep = 'configuring' | 'downloading' | 'warming' | 'accessing_webcam' | 'loading_pose_model' | 'ready';
|
|
26
|
+
export type InitializationStep = 'configuring' | 'downloading' | 'warming' | 'accessing_webcam' | 'loading_media' | 'loading_pose_model' | 'ready';
|
|
27
27
|
export interface InitializationEvent {
|
|
28
28
|
type: 'initialization';
|
|
29
29
|
/**
|
|
@@ -154,6 +154,40 @@ export interface ProgressionEvent {
|
|
|
154
154
|
value: number;
|
|
155
155
|
timestampMs: number;
|
|
156
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Throttled movement / rep-FSM snapshot for QA (engine ≥ 1.2.4).
|
|
159
|
+
* Enable via `PoseTrackerClientOptions.debugEngine` or `startExercise(..., { debug: true })`.
|
|
160
|
+
*/
|
|
161
|
+
export interface EngineDebugEvent {
|
|
162
|
+
type: 'engine_debug';
|
|
163
|
+
exerciseId: string;
|
|
164
|
+
engineVersion: string;
|
|
165
|
+
ready: boolean;
|
|
166
|
+
postureHint: string;
|
|
167
|
+
direction?: string;
|
|
168
|
+
missingKeypoints: string[];
|
|
169
|
+
stepIndex: number;
|
|
170
|
+
stepCount: number;
|
|
171
|
+
stepPosition: number | null;
|
|
172
|
+
stepProgression: number;
|
|
173
|
+
progression: number;
|
|
174
|
+
/** Raw FSM rep count (before minGrade gate). */
|
|
175
|
+
rawCount: number;
|
|
176
|
+
/** Public counter after minGrade gate. */
|
|
177
|
+
publicCount: number;
|
|
178
|
+
difficulty: string;
|
|
179
|
+
minGrade: MinGrade | null;
|
|
180
|
+
pointOfView: 'low' | 'up';
|
|
181
|
+
computeError?: string;
|
|
182
|
+
lastSkipReason: string | null;
|
|
183
|
+
posesProcessed: number;
|
|
184
|
+
visibleKeypoints: number;
|
|
185
|
+
knees: {
|
|
186
|
+
left: number | null;
|
|
187
|
+
right: number | null;
|
|
188
|
+
};
|
|
189
|
+
timestampMs: number;
|
|
190
|
+
}
|
|
157
191
|
export interface RecommendationsEvent {
|
|
158
192
|
type: 'recommendations';
|
|
159
193
|
/** Localized form advice strings. */
|
|
@@ -309,7 +343,7 @@ export interface RuntimeDownloadProgressEvent {
|
|
|
309
343
|
partBytes: number;
|
|
310
344
|
timestampMs: number;
|
|
311
345
|
}
|
|
312
|
-
export type PoseTrackerEvent = InitializationEvent | ErrorEvent | WarningEvent | RuntimeDownloadProgressEvent | KeypointsEvent | AnglesEvent | CounterEvent | PostureEvent | ProgressionEvent | RecommendationsEvent | FormScoreEvent | ExerciseSummaryEvent | JumpCalibrationEvent | JumpStartedEvent | JumpHeightEvent | JumpDiscardedEvent | JumpResultEvent | JumpSummaryEvent | QualityChangedEvent | PerformanceWarningEvent;
|
|
346
|
+
export type PoseTrackerEvent = InitializationEvent | ErrorEvent | WarningEvent | RuntimeDownloadProgressEvent | KeypointsEvent | AnglesEvent | CounterEvent | PostureEvent | ProgressionEvent | EngineDebugEvent | RecommendationsEvent | FormScoreEvent | ExerciseSummaryEvent | JumpCalibrationEvent | JumpStartedEvent | JumpHeightEvent | JumpDiscardedEvent | JumpResultEvent | JumpSummaryEvent | QualityChangedEvent | PerformanceWarningEvent;
|
|
313
347
|
export type PoseTrackerEventType = PoseTrackerEvent['type'];
|
|
314
348
|
export type PoseTrackerEventListener = (event: PoseTrackerEvent) => void;
|
|
315
349
|
/**
|
|
@@ -325,6 +359,7 @@ export interface PoseTrackerCallbacks {
|
|
|
325
359
|
onCounter?: (event: CounterEvent) => void;
|
|
326
360
|
onPosture?: (event: PostureEvent) => void;
|
|
327
361
|
onProgression?: (event: ProgressionEvent) => void;
|
|
362
|
+
onEngineDebug?: (event: EngineDebugEvent) => void;
|
|
328
363
|
onRecommendations?: (event: RecommendationsEvent) => void;
|
|
329
364
|
onFormScore?: (event: FormScoreEvent) => void;
|
|
330
365
|
onExerciseSummary?: (event: ExerciseSummaryEvent) => void;
|
package/lib/types/features.d.ts
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
* - `keypoints` DURING an exercise session requires a paid plan too
|
|
12
12
|
* (free may stream keypoints only in pose-only mode, i.e. no exercise).
|
|
13
13
|
* - `blazepose` / `poseEngine` / `mediapipeModel` / `poseBackend` /
|
|
14
|
-
* `runInWorker` are NOT
|
|
15
|
-
*
|
|
14
|
+
* `runInWorker` are NOT feature flags here — select BlazePose with
|
|
15
|
+
* `options.model = 'blazepose'` instead of `{ features: { blazepose: true } }`.
|
|
16
16
|
*/
|
|
17
17
|
import type { MinGrade } from './events';
|
|
18
18
|
export interface PoseTrackerFeatures {
|
package/lib/types/features.js
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
* - `keypoints` DURING an exercise session requires a paid plan too
|
|
13
13
|
* (free may stream keypoints only in pose-only mode, i.e. no exercise).
|
|
14
14
|
* - `blazepose` / `poseEngine` / `mediapipeModel` / `poseBackend` /
|
|
15
|
-
* `runInWorker` are NOT
|
|
16
|
-
*
|
|
15
|
+
* `runInWorker` are NOT feature flags here — select BlazePose with
|
|
16
|
+
* `options.model = 'blazepose'` instead of `{ features: { blazepose: true } }`.
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.COMBINED_REFERENCE_EXERCISE_MESSAGE = exports.INVALID_TOKEN_MESSAGE = exports.FREE_PLAN_FEATURES_MESSAGE = exports.DEFAULT_FEATURES = void 0;
|
|
@@ -38,12 +38,12 @@ const KNOWN_FEATURE_KEYS = new Set([
|
|
|
38
38
|
'minGrade',
|
|
39
39
|
]);
|
|
40
40
|
/**
|
|
41
|
-
* WebView params that
|
|
42
|
-
*
|
|
43
|
-
*
|
|
41
|
+
* WebView params that are NOT feature flags in this SDK.
|
|
42
|
+
* Note: `options.model = 'blazepose'` is supported on light; passing
|
|
43
|
+
* `{ blazepose: true }` inside `features` is rejected (WebView query parity).
|
|
44
44
|
*/
|
|
45
45
|
const UNSUPPORTED_FEATURE_HINTS = {
|
|
46
|
-
blazepose: 'BlazePose',
|
|
46
|
+
blazepose: 'BlazePose as a features flag (use options.model = "blazepose" instead)',
|
|
47
47
|
poseEngine: 'pose engine selection (MediaPipe/PoseLandmarker)',
|
|
48
48
|
mediapipeModel: 'MediaPipe model selection',
|
|
49
49
|
poseBackend: 'pose backend selection',
|
|
@@ -62,9 +62,8 @@ exports.COMBINED_REFERENCE_EXERCISE_MESSAGE = 'You cannot combine reference & ex
|
|
|
62
62
|
/** SDK-specific: the requested WebView feature does not exist in this SDK. */
|
|
63
63
|
function featureNotSupportedMessage(key) {
|
|
64
64
|
const hint = UNSUPPORTED_FEATURE_HINTS[key] ?? `'${key}'`;
|
|
65
|
-
return (`The '${key}' option (${hint}) is not available
|
|
66
|
-
'
|
|
67
|
-
'Remove the option, or use the PoseTracker WebView product if you need it. ' +
|
|
65
|
+
return (`The '${key}' option (${hint}) is not available as a features flag. ` +
|
|
66
|
+
'Remove the option, or use options.model / modelUrl for model selection. ' +
|
|
68
67
|
'(visit: https://posetracker.gitbook.io/posetracker-api/tracking-endpoint)');
|
|
69
68
|
}
|
|
70
69
|
// ---------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pose-tracker/react-native-pose-estimation-light",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Human pose estimation SDK for React Native (light / online) — MoveNet Lightning via CDN + model URL each session, no bundled weights. iOS & Android (Expo Go). Optional API-key exercise engine.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -281,6 +281,9 @@ export function usePoseTracker(callbacks: PoseTrackerCallbacks = {}): PoseTracke
|
|
|
281
281
|
case 'progression':
|
|
282
282
|
cb.onProgression?.(event);
|
|
283
283
|
break;
|
|
284
|
+
case 'engine_debug':
|
|
285
|
+
cb.onEngineDebug?.(event);
|
|
286
|
+
break;
|
|
284
287
|
case 'recommendations':
|
|
285
288
|
cb.onRecommendations?.(event);
|
|
286
289
|
break;
|
|
@@ -86,7 +86,7 @@ export type WebViewPoseMessage =
|
|
|
86
86
|
type: 'initialization';
|
|
87
87
|
message: string;
|
|
88
88
|
ready?: boolean;
|
|
89
|
-
step?: 'accessing_webcam' | 'loading_pose_model' | 'ready';
|
|
89
|
+
step?: 'accessing_webcam' | 'loading_media' | 'loading_pose_model' | 'ready';
|
|
90
90
|
}
|
|
91
91
|
| { type: 'warning'; message: string; code?: string }
|
|
92
92
|
| { type: 'diag'; message: string }
|
|
@@ -5,22 +5,29 @@
|
|
|
5
5
|
* TF.js + WASM backends load from a CDN; MoveNet (or a custom graph model)
|
|
6
6
|
* loads from a URL on every WebView boot — same idea as the historical
|
|
7
7
|
* PoseTracker Front tracking page.
|
|
8
|
+
*
|
|
9
|
+
* BlazePose: appends `@tensorflow-models/pose-detection` CDN after TF.js
|
|
10
|
+
* (no graph `modelUrl`); the page runtime calls `createDetector`.
|
|
8
11
|
*/
|
|
9
12
|
|
|
10
13
|
import { POSE_RUNTIME_JS, POSE_RUNTIME_VERSION } from './poseRuntimeSource';
|
|
11
14
|
import {
|
|
12
15
|
resolvePoseModel,
|
|
13
16
|
type PoseModelAlias,
|
|
17
|
+
type PoseModelKind,
|
|
14
18
|
type ResolvedPoseModel,
|
|
15
19
|
} from '../../models/poseModels';
|
|
16
20
|
|
|
17
21
|
/** TF.js version pinned for CDN scripts (matches offline SDK build). */
|
|
18
22
|
export const ONLINE_TFJS_VERSION = '4.22.0';
|
|
19
23
|
|
|
24
|
+
/** pose-detection UMD pin (BlazePose). */
|
|
25
|
+
export const ONLINE_POSE_DETECTION_VERSION = '2.1.3';
|
|
26
|
+
|
|
20
27
|
const JSDELIVR = 'https://cdn.jsdelivr.net/npm';
|
|
21
28
|
|
|
22
29
|
export interface OnlineRuntimeUrls {
|
|
23
|
-
/** Ordered <script src> list (core → converter → webgl → wasm). */
|
|
30
|
+
/** Ordered <script src> list (core → converter → webgl → wasm [→ pose-detection]). */
|
|
24
31
|
tfjsScriptUrls: string[];
|
|
25
32
|
/** Directory passed to `tf.wasm.setWasmPaths`. */
|
|
26
33
|
tfjsWasmPath: string;
|
|
@@ -30,7 +37,9 @@ export interface OnlineRuntimeParts {
|
|
|
30
37
|
version: string;
|
|
31
38
|
delivery: 'online';
|
|
32
39
|
modelId: string;
|
|
33
|
-
|
|
40
|
+
/** Graph kinds only; null for BlazePose. */
|
|
41
|
+
modelUrl: string | null;
|
|
42
|
+
modelKind: Exclude<PoseModelKind, 'unsupported'>;
|
|
34
43
|
tfjsScriptUrls: string[];
|
|
35
44
|
tfjsWasmPath: string;
|
|
36
45
|
/** Thin page runtime shipped in the package (~50 KB). */
|
|
@@ -47,6 +56,8 @@ export interface GetOnlineRuntimeOptions {
|
|
|
47
56
|
tfjsCdnBase?: string;
|
|
48
57
|
/** Override TF.js version segment in CDN URLs. */
|
|
49
58
|
tfjsVersion?: string;
|
|
59
|
+
/** Override pose-detection version (BlazePose CDN). */
|
|
60
|
+
poseDetectionVersion?: string;
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
export function defaultOnlineRuntimeUrls(
|
|
@@ -65,25 +76,45 @@ export function defaultOnlineRuntimeUrls(
|
|
|
65
76
|
};
|
|
66
77
|
}
|
|
67
78
|
|
|
79
|
+
export function defaultPoseDetectionCdnUrl(
|
|
80
|
+
cdnBase: string = JSDELIVR,
|
|
81
|
+
version: string = ONLINE_POSE_DETECTION_VERSION,
|
|
82
|
+
): string {
|
|
83
|
+
const base = cdnBase.replace(/\/$/, '');
|
|
84
|
+
return `${base}/@tensorflow-models/pose-detection@${version}/dist/pose-detection.min.js`;
|
|
85
|
+
}
|
|
86
|
+
|
|
68
87
|
/**
|
|
69
88
|
* Build the online runtime descriptor used by {@link buildPoseHtml}.
|
|
70
|
-
* Throws when the selected model cannot be loaded
|
|
89
|
+
* Throws when the selected model cannot be loaded.
|
|
71
90
|
*/
|
|
72
91
|
export function getOnlineRuntimeParts(options: GetOnlineRuntimeOptions = {}): OnlineRuntimeParts {
|
|
73
92
|
const resolved: ResolvedPoseModel = resolvePoseModel({
|
|
74
93
|
model: options.model,
|
|
75
94
|
modelUrl: options.modelUrl,
|
|
76
95
|
});
|
|
77
|
-
if (
|
|
96
|
+
if (resolved.kind === 'unsupported') {
|
|
78
97
|
throw new Error(resolved.unsupportedReason ?? `Model "${resolved.modelId}" is unavailable.`);
|
|
79
98
|
}
|
|
99
|
+
if (resolved.kind !== 'blazepose' && !resolved.modelUrl) {
|
|
100
|
+
throw new Error(resolved.unsupportedReason ?? `Model "${resolved.modelId}" is unavailable.`);
|
|
101
|
+
}
|
|
102
|
+
|
|
80
103
|
const urls = defaultOnlineRuntimeUrls(options.tfjsCdnBase, options.tfjsVersion);
|
|
104
|
+
const scriptUrls = [...urls.tfjsScriptUrls];
|
|
105
|
+
if (resolved.kind === 'blazepose') {
|
|
106
|
+
scriptUrls.push(
|
|
107
|
+
defaultPoseDetectionCdnUrl(options.tfjsCdnBase, options.poseDetectionVersion),
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
81
111
|
return {
|
|
82
112
|
version: POSE_RUNTIME_VERSION,
|
|
83
113
|
delivery: 'online',
|
|
84
114
|
modelId: resolved.modelId,
|
|
85
115
|
modelUrl: resolved.modelUrl,
|
|
86
|
-
|
|
116
|
+
modelKind: resolved.kind,
|
|
117
|
+
tfjsScriptUrls: scriptUrls,
|
|
87
118
|
tfjsWasmPath: urls.tfjsWasmPath,
|
|
88
119
|
runtimeJs: POSE_RUNTIME_JS,
|
|
89
120
|
};
|