react-native-nitro-pose-exercises 1.1.11 → 1.1.13

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.
@@ -616,53 +616,62 @@ if (!isPostureValid(config.postureFamily, config.visibilityThreshold)) {
616
616
  // Posture Gates
617
617
  // ═══════════════════════════════════════════════════════════
618
618
 
619
- private fun isPostureValid(family: PostureFamily, threshold: Double): Boolean {
620
- if (_landmarks.size < 33) return false
619
+ private fun isPostureValid(family: PostureFamily, threshold: Double): Boolean {
620
+ if (_landmarks.size < 33) return false
621
621
 
622
- val ls = _landmarks[11]; val rs = _landmarks[12]
623
- val lh = _landmarks[23]; val rh = _landmarks[24]
624
- val lk = _landmarks[25]; val rk = _landmarks[26]
625
- val la = _landmarks[27]; val ra = _landmarks[28]
622
+ val ls = _landmarks[11]; val rs = _landmarks[12]
623
+ val lh = _landmarks[23]; val rh = _landmarks[24]
624
+ val lk = _landmarks[25]; val rk = _landmarks[26]
625
+ val la = _landmarks[27]; val ra = _landmarks[28]
626
626
 
627
- val keyVisible = ls.visibility > threshold && rs.visibility > threshold &&
627
+ // Only require torso visible knees and ankles are optional
628
+ val torsoVisible = ls.visibility > threshold && rs.visibility > threshold &&
628
629
  lh.visibility > threshold && rh.visibility > threshold
629
- if (!keyVisible) return false
630
-
631
- val shoulderY = (ls.y + rs.y) / 2
632
- val hipY = (lh.y + rh.y) / 2
633
- val shoulderX = (ls.x + rs.x) / 2
634
- val hipX = (lh.x + rh.x) / 2
635
-
636
- val kneesVisible = lk.visibility > threshold && rk.visibility > threshold
637
- val anklesVisible = la.visibility > threshold && ra.visibility > threshold
638
- val kneeY = if (kneesVisible) (lk.y + rk.y) / 2 else hipY
639
- val ankleY = if (anklesVisible) (la.y + ra.y) / 2 else kneeY
640
-
641
- return when (family) {
642
- PostureFamily.HORIZONTALPRONE, PostureFamily.SUPINE -> {
643
- val ys = listOf(shoulderY, hipY, ankleY)
644
- (ys.max() - ys.min()) < 0.25
645
- }
646
- PostureFamily.STANDINGUPRIGHT -> {
647
- if (!kneesVisible) false
648
- else shoulderY < hipY - 0.08 &&
649
- hipY < kneeY + 0.05 &&
650
- (if (anklesVisible) kneeY < ankleY else true)
651
- }
652
- PostureFamily.SEATED -> {
653
- if (!kneesVisible) false
654
- else shoulderY < hipY - 0.05 && kotlin.math.abs(hipY - kneeY) < 0.20
655
- }
656
- PostureFamily.SIDEPLANK -> {
657
- val ySpread = kotlin.math.abs(shoulderY - hipY)
658
- val shoulderHipDx = kotlin.math.abs(shoulderX - hipX)
659
- ySpread < 0.20 && shoulderHipDx < 0.15
660
- }
661
- PostureFamily.INVERTED -> {
662
- if (!anklesVisible) false
663
- else hipY < shoulderY && hipY < ankleY
664
- }
665
- PostureFamily.NONE -> true
666
- }
630
+ if (!torsoVisible) return false
631
+
632
+ val shoulderY = (ls.y + rs.y) / 2
633
+ val hipY = (lh.y + rh.y) / 2
634
+ val shoulderX = (ls.x + rs.x) / 2
635
+ val hipX = (lh.x + rh.x) / 2
636
+
637
+ val kneesVisible = lk.visibility > threshold && rk.visibility > threshold
638
+ val anklesVisible = la.visibility > threshold && ra.visibility > threshold
639
+ val kneeY = if (kneesVisible) (lk.y + rk.y) / 2 else hipY
640
+ val ankleY = if (anklesVisible) (la.y + ra.y) / 2 else kneeY
641
+
642
+ return when (family) {
643
+ PostureFamily.HORIZONTALPRONE, PostureFamily.SUPINE -> {
644
+ val ys = if (anklesVisible)
645
+ listOf(shoulderY, hipY, ankleY)
646
+ else
647
+ listOf(shoulderY, hipY)
648
+ (ys.max() - ys.min()) < 0.25
649
+ }
650
+ PostureFamily.STANDINGUPRIGHT -> {
651
+ if (kneesVisible) {
652
+ shoulderY < hipY - 0.08 &&
653
+ hipY < kneeY + 0.05 &&
654
+ (if (anklesVisible) kneeY < ankleY else true)
655
+ } else {
656
+ shoulderY < hipY - 0.08
657
+ }
658
+ }
659
+ PostureFamily.SEATED -> {
660
+ if (kneesVisible) {
661
+ shoulderY < hipY - 0.05 && kotlin.math.abs(hipY - kneeY) < 0.20
662
+ } else {
663
+ shoulderY < hipY - 0.05
664
+ }
665
+ }
666
+ PostureFamily.SIDEPLANK -> {
667
+ val ySpread = kotlin.math.abs(shoulderY - hipY)
668
+ val shoulderHipDx = kotlin.math.abs(shoulderX - hipX)
669
+ ySpread < 0.20 && shoulderHipDx < 0.15
670
+ }
671
+ PostureFamily.INVERTED -> {
672
+ if (!anklesVisible) false
673
+ else hipY < shoulderY && hipY < ankleY
674
+ }
675
+ PostureFamily.NONE -> true
667
676
  }
668
677
  }
@@ -345,7 +345,7 @@ private func processExerciseLogic() {
345
345
  // MARK: - Posture Gates
346
346
  // ═══════════════════════════════════════════════════════════
347
347
 
348
- private func isPostureValid(family: PostureFamily, threshold: Double) -> Bool {
348
+ private func isPostureValid(family: PostureFamily, threshold: Double) -> Bool {
349
349
  guard _landmarks.count >= 33 else { return false }
350
350
 
351
351
  let ls = _landmarks[11], rs = _landmarks[12]
@@ -353,38 +353,55 @@ private func isPostureValid(family: PostureFamily, threshold: Double) -> Bool {
353
353
  let lk = _landmarks[25], rk = _landmarks[26]
354
354
  let la = _landmarks[27], ra = _landmarks[28]
355
355
 
356
- let key = [ls, rs, lh, rh]
357
- guard key.allSatisfy({ $0.visibility > 0.3 }) else { return false }
356
+ // Only require torso visible knees and ankles are optional
357
+ let torsoVisible = ls.visibility > threshold && rs.visibility > threshold
358
+ && lh.visibility > threshold && rh.visibility > threshold
359
+ guard torsoVisible else { return false }
358
360
 
359
361
  let shoulderY = (ls.y + rs.y) / 2
360
362
  let hipY = (lh.y + rh.y) / 2
361
363
  let shoulderX = (ls.x + rs.x) / 2
362
364
  let hipX = (lh.x + rh.x) / 2
363
365
 
364
- let kneesVisible = lk.visibility > 0.3 && rk.visibility > 0.3
365
- let anklesVisible = la.visibility > 0.3 && ra.visibility > 0.3
366
+ let kneesVisible = lk.visibility > threshold && rk.visibility > threshold
367
+ let anklesVisible = la.visibility > threshold && ra.visibility > threshold
366
368
  let kneeY = kneesVisible ? (lk.y + rk.y) / 2 : hipY
367
369
  let ankleY = anklesVisible ? (la.y + ra.y) / 2 : kneeY
368
370
 
369
371
  switch family {
370
372
  case .horizontalprone, .supine:
371
- let ys = [shoulderY, hipY, ankleY]
373
+ // Horizontal body torso, plus ankles if visible
374
+ let ys: [Double] = anklesVisible
375
+ ? [shoulderY, hipY, ankleY]
376
+ : [shoulderY, hipY]
372
377
  return ((ys.max() ?? 0) - (ys.min() ?? 0)) < 0.25
373
378
 
374
379
  case .standingupright:
375
- guard kneesVisible else { return false }
376
- return shoulderY < hipY - 0.08 && hipY < kneeY + 0.05 && (anklesVisible ? kneeY < ankleY : true)
380
+ // Torso vertical (shoulders above hips). If knees visible, check chain.
381
+ if kneesVisible {
382
+ return shoulderY < hipY - 0.08
383
+ && hipY < kneeY + 0.05
384
+ && (anklesVisible ? kneeY < ankleY : true)
385
+ } else {
386
+ return shoulderY < hipY - 0.08
387
+ }
377
388
 
378
389
  case .seated:
379
- guard kneesVisible else { return false }
380
- return shoulderY < hipY - 0.05 && Swift.abs(hipY - kneeY) < 0.20
390
+ // Forward-leaning torso. If knees visible, also check hip-knee distance.
391
+ if kneesVisible {
392
+ return shoulderY < hipY - 0.05 && Swift.abs(hipY - kneeY) < 0.20
393
+ } else {
394
+ return shoulderY < hipY - 0.05
395
+ }
381
396
 
382
397
  case .sideplank:
398
+ // Body horizontal, shoulders and hips stacked in x
383
399
  let ySpread = Swift.abs(shoulderY - hipY)
384
400
  let shoulderHipDx = Swift.abs(shoulderX - hipX)
385
401
  return ySpread < 0.20 && shoulderHipDx < 0.15
386
402
 
387
403
  case .inverted:
404
+ // Genuinely needs ankles — hips highest of all three
388
405
  guard anklesVisible else { return false }
389
406
  return hipY < shoulderY && hipY < ankleY
390
407
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-pose-exercises",
3
- "version": "1.1.11",
3
+ "version": "1.1.13",
4
4
  "description": "Real-time on-device exercise tracking for React Native. Rep counting, form validation, and skeleton overlay powered by Apple Vision (iOS) and Google ML Kit (Android) with VisionCamera v5 via Nitro Modules.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -73,6 +73,7 @@
73
73
  "@react-native/eslint-config": "0.85.3",
74
74
  "@react-native/jest-preset": "0.85.3",
75
75
  "@release-it/conventional-changelog": "^10.0.6",
76
+ "@shopify/react-native-skia": "^2.6.4",
76
77
  "@types/react": "^19.2.0",
77
78
  "commitlint": "^20.5.0",
78
79
  "del-cli": "^7.0.0",