react-native-nitro-pose-exercises 1.1.5 → 1.1.7
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 +192 -159
- package/android/src/main/java/com/margelo/nitro/nitroposeexercises/NitroPoseExercises.kt +121 -4
- package/ios/NitroPoseExercises.swift +128 -11
- package/lib/module/NitroPoseExercises.nitro.js.map +1 -1
- package/lib/module/config/bicep-curl.js +3 -0
- package/lib/module/config/bicep-curl.js.map +1 -1
- package/lib/module/config/boat-pose.js +44 -0
- package/lib/module/config/boat-pose.js.map +1 -0
- package/lib/module/config/bow-pose.js +37 -0
- package/lib/module/config/bow-pose.js.map +1 -0
- package/lib/module/config/bridge-pose.js +37 -0
- package/lib/module/config/bridge-pose.js.map +1 -0
- package/lib/module/config/calf-raise.js +47 -0
- package/lib/module/config/calf-raise.js.map +1 -0
- package/lib/module/config/camel-pose.js +37 -0
- package/lib/module/config/camel-pose.js.map +1 -0
- package/lib/module/config/chair-pose.js +3 -0
- package/lib/module/config/chair-pose.js.map +1 -1
- package/lib/module/config/childs-pose.js +42 -0
- package/lib/module/config/childs-pose.js.map +1 -0
- package/lib/module/config/cobra-pose.js +3 -0
- package/lib/module/config/cobra-pose.js.map +1 -1
- package/lib/module/config/cobra-wings.js +47 -0
- package/lib/module/config/cobra-wings.js.map +1 -0
- package/lib/module/config/dead-lift.js +54 -0
- package/lib/module/config/dead-lift.js.map +1 -0
- package/lib/module/config/downward-dog.js +3 -0
- package/lib/module/config/downward-dog.js.map +1 -1
- package/lib/module/config/extended-side-angle.js +49 -0
- package/lib/module/config/extended-side-angle.js.map +1 -0
- package/lib/module/config/fish-pose.js +37 -0
- package/lib/module/config/fish-pose.js.map +1 -0
- package/lib/module/config/front-raise.js +54 -0
- package/lib/module/config/front-raise.js.map +1 -0
- package/lib/module/config/glute-bridge.js +49 -0
- package/lib/module/config/glute-bridge.js.map +1 -0
- package/lib/module/config/hip-abduction.js +42 -0
- package/lib/module/config/hip-abduction.js.map +1 -0
- package/lib/module/config/knee-raise.js +47 -0
- package/lib/module/config/knee-raise.js.map +1 -0
- package/lib/module/config/lateral-raise.js +54 -0
- package/lib/module/config/lateral-raise.js.map +1 -0
- package/lib/module/config/leg-raise.js +49 -0
- package/lib/module/config/leg-raise.js.map +1 -0
- package/lib/module/config/lunge.js +3 -0
- package/lib/module/config/lunge.js.map +1 -1
- package/lib/module/config/mountain-pose.js +49 -0
- package/lib/module/config/mountain-pose.js.map +1 -0
- package/lib/module/config/overarm-reach.js +47 -0
- package/lib/module/config/overarm-reach.js.map +1 -0
- package/lib/module/config/plank.js +3 -0
- package/lib/module/config/plank.js.map +1 -1
- package/lib/module/config/pull-up.js +47 -0
- package/lib/module/config/pull-up.js.map +1 -0
- package/lib/module/config/pushup.js +4 -0
- package/lib/module/config/pushup.js.map +1 -1
- package/lib/module/config/reverse-warrior.js +49 -0
- package/lib/module/config/reverse-warrior.js.map +1 -0
- package/lib/module/config/shoulder-press.js +3 -0
- package/lib/module/config/shoulder-press.js.map +1 -1
- package/lib/module/config/side-lung.js +54 -0
- package/lib/module/config/side-lung.js.map +1 -0
- package/lib/module/config/side-plank.js +37 -0
- package/lib/module/config/side-plank.js.map +1 -0
- package/lib/module/config/situp.js +3 -0
- package/lib/module/config/situp.js.map +1 -1
- package/lib/module/config/squat.js +3 -0
- package/lib/module/config/squat.js.map +1 -1
- package/lib/module/config/sumo-squat.js +54 -0
- package/lib/module/config/sumo-squat.js.map +1 -0
- package/lib/module/config/tree-pose.js +3 -0
- package/lib/module/config/tree-pose.js.map +1 -1
- package/lib/module/config/triangle-pose.js +49 -0
- package/lib/module/config/triangle-pose.js.map +1 -0
- package/lib/module/config/tricep-dip.js +4 -0
- package/lib/module/config/tricep-dip.js.map +1 -1
- package/lib/module/config/v-up.js +42 -0
- package/lib/module/config/v-up.js.map +1 -0
- package/lib/module/config/wall-sit.js +3 -0
- package/lib/module/config/wall-sit.js.map +1 -1
- package/lib/module/config/warrior-i.js +3 -0
- package/lib/module/config/warrior-i.js.map +1 -1
- package/lib/module/config/warrior-ii.js +3 -0
- package/lib/module/config/warrior-ii.js.map +1 -1
- package/lib/module/config/warrior-iii.js +61 -0
- package/lib/module/config/warrior-iii.js.map +1 -0
- package/lib/module/index.js +31 -3
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NitroPoseExercises.nitro.d.ts +9 -1
- package/lib/typescript/src/NitroPoseExercises.nitro.d.ts.map +1 -1
- package/lib/typescript/src/config/bicep-curl.d.ts.map +1 -1
- package/lib/typescript/src/config/boat-pose.d.ts +3 -0
- package/lib/typescript/src/config/boat-pose.d.ts.map +1 -0
- package/lib/typescript/src/config/bow-pose.d.ts +3 -0
- package/lib/typescript/src/config/bow-pose.d.ts.map +1 -0
- package/lib/typescript/src/config/bridge-pose.d.ts +3 -0
- package/lib/typescript/src/config/bridge-pose.d.ts.map +1 -0
- package/lib/typescript/src/config/calf-raise.d.ts +3 -0
- package/lib/typescript/src/config/calf-raise.d.ts.map +1 -0
- package/lib/typescript/src/config/camel-pose.d.ts +3 -0
- package/lib/typescript/src/config/camel-pose.d.ts.map +1 -0
- package/lib/typescript/src/config/chair-pose.d.ts.map +1 -1
- package/lib/typescript/src/config/childs-pose.d.ts +3 -0
- package/lib/typescript/src/config/childs-pose.d.ts.map +1 -0
- package/lib/typescript/src/config/cobra-pose.d.ts.map +1 -1
- package/lib/typescript/src/config/cobra-wings.d.ts +3 -0
- package/lib/typescript/src/config/cobra-wings.d.ts.map +1 -0
- package/lib/typescript/src/config/dead-lift.d.ts +3 -0
- package/lib/typescript/src/config/dead-lift.d.ts.map +1 -0
- package/lib/typescript/src/config/downward-dog.d.ts.map +1 -1
- package/lib/typescript/src/config/extended-side-angle.d.ts +3 -0
- package/lib/typescript/src/config/extended-side-angle.d.ts.map +1 -0
- package/lib/typescript/src/config/fish-pose.d.ts +3 -0
- package/lib/typescript/src/config/fish-pose.d.ts.map +1 -0
- package/lib/typescript/src/config/front-raise.d.ts +3 -0
- package/lib/typescript/src/config/front-raise.d.ts.map +1 -0
- package/lib/typescript/src/config/glute-bridge.d.ts +3 -0
- package/lib/typescript/src/config/glute-bridge.d.ts.map +1 -0
- package/lib/typescript/src/config/hip-abduction.d.ts +3 -0
- package/lib/typescript/src/config/hip-abduction.d.ts.map +1 -0
- package/lib/typescript/src/config/knee-raise.d.ts +3 -0
- package/lib/typescript/src/config/knee-raise.d.ts.map +1 -0
- package/lib/typescript/src/config/lateral-raise.d.ts +3 -0
- package/lib/typescript/src/config/lateral-raise.d.ts.map +1 -0
- package/lib/typescript/src/config/leg-raise.d.ts +3 -0
- package/lib/typescript/src/config/leg-raise.d.ts.map +1 -0
- package/lib/typescript/src/config/lunge.d.ts.map +1 -1
- package/lib/typescript/src/config/mountain-pose.d.ts +3 -0
- package/lib/typescript/src/config/mountain-pose.d.ts.map +1 -0
- package/lib/typescript/src/config/overarm-reach.d.ts +3 -0
- package/lib/typescript/src/config/overarm-reach.d.ts.map +1 -0
- package/lib/typescript/src/config/plank.d.ts.map +1 -1
- package/lib/typescript/src/config/pull-up.d.ts +3 -0
- package/lib/typescript/src/config/pull-up.d.ts.map +1 -0
- package/lib/typescript/src/config/pushup.d.ts.map +1 -1
- package/lib/typescript/src/config/reverse-warrior.d.ts +3 -0
- package/lib/typescript/src/config/reverse-warrior.d.ts.map +1 -0
- package/lib/typescript/src/config/shoulder-press.d.ts.map +1 -1
- package/lib/typescript/src/config/side-lung.d.ts +3 -0
- package/lib/typescript/src/config/side-lung.d.ts.map +1 -0
- package/lib/typescript/src/config/side-plank.d.ts +3 -0
- package/lib/typescript/src/config/side-plank.d.ts.map +1 -0
- package/lib/typescript/src/config/situp.d.ts.map +1 -1
- package/lib/typescript/src/config/squat.d.ts.map +1 -1
- package/lib/typescript/src/config/sumo-squat.d.ts +3 -0
- package/lib/typescript/src/config/sumo-squat.d.ts.map +1 -0
- package/lib/typescript/src/config/tree-pose.d.ts.map +1 -1
- package/lib/typescript/src/config/triangle-pose.d.ts +3 -0
- package/lib/typescript/src/config/triangle-pose.d.ts.map +1 -0
- package/lib/typescript/src/config/tricep-dip.d.ts.map +1 -1
- package/lib/typescript/src/config/v-up.d.ts +3 -0
- package/lib/typescript/src/config/v-up.d.ts.map +1 -0
- package/lib/typescript/src/config/wall-sit.d.ts.map +1 -1
- package/lib/typescript/src/config/warrior-i.d.ts.map +1 -1
- package/lib/typescript/src/config/warrior-ii.d.ts.map +1 -1
- package/lib/typescript/src/config/warrior-iii.d.ts +3 -0
- package/lib/typescript/src/config/warrior-iii.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +26 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JCameraAngleType.hpp +58 -0
- package/nitrogen/generated/android/c++/JExerciseConfig.hpp +19 -3
- package/nitrogen/generated/android/c++/JHybridNitroPoseExercisesSpec.cpp +47 -0
- package/nitrogen/generated/android/c++/JHybridNitroPoseExercisesSpec.hpp +5 -0
- package/nitrogen/generated/android/c++/JPostureFamily.hpp +73 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroposeexercises/CameraAngleType.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroposeexercises/ExerciseConfig.kt +19 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroposeexercises/HybridNitroPoseExercisesSpec.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroposeexercises/PostureFamily.kt +28 -0
- package/nitrogen/generated/ios/NitroPoseExercises-Swift-Cxx-Bridge.hpp +9 -0
- package/nitrogen/generated/ios/NitroPoseExercises-Swift-Cxx-Umbrella.hpp +6 -0
- package/nitrogen/generated/ios/c++/HybridNitroPoseExercisesSpecSwift.hpp +28 -0
- package/nitrogen/generated/ios/swift/CameraAngleType.swift +40 -0
- package/nitrogen/generated/ios/swift/ExerciseConfig.swift +17 -2
- package/nitrogen/generated/ios/swift/HybridNitroPoseExercisesSpec.swift +3 -0
- package/nitrogen/generated/ios/swift/HybridNitroPoseExercisesSpec_cxx.swift +76 -0
- package/nitrogen/generated/ios/swift/PostureFamily.swift +60 -0
- package/nitrogen/generated/shared/c++/CameraAngleType.hpp +76 -0
- package/nitrogen/generated/shared/c++/ExerciseConfig.hpp +20 -2
- package/nitrogen/generated/shared/c++/HybridNitroPoseExercisesSpec.cpp +5 -0
- package/nitrogen/generated/shared/c++/HybridNitroPoseExercisesSpec.hpp +5 -0
- package/nitrogen/generated/shared/c++/PostureFamily.hpp +96 -0
- package/package.json +1 -1
- package/src/NitroPoseExercises.nitro.ts +19 -0
- package/src/config/bicep-curl.ts +3 -0
- package/src/config/boat-pose.ts +36 -0
- package/src/config/bow-pose.ts +27 -0
- package/src/config/bridge-pose.ts +28 -0
- package/src/config/calf-raise.ts +30 -0
- package/src/config/camel-pose.ts +27 -0
- package/src/config/chair-pose.ts +3 -0
- package/src/config/childs-pose.ts +26 -0
- package/src/config/cobra-pose.ts +3 -0
- package/src/config/cobra-wings.ts +29 -0
- package/src/config/dead-lift.ts +38 -0
- package/src/config/downward-dog.ts +3 -0
- package/src/config/extended-side-angle.ts +36 -0
- package/src/config/fish-pose.ts +28 -0
- package/src/config/front-raise.ts +58 -0
- package/src/config/glute-bridge.ts +36 -0
- package/src/config/hip-abduction.ts +28 -0
- package/src/config/knee-raise.ts +29 -0
- package/src/config/lateral-raise.ts +58 -0
- package/src/config/leg-raise.ts +36 -0
- package/src/config/lunge.ts +3 -0
- package/src/config/mountain-pose.ts +36 -0
- package/src/config/overarm-reach.ts +49 -0
- package/src/config/plank.ts +3 -0
- package/src/config/pull-up.ts +30 -0
- package/src/config/pushup.ts +3 -0
- package/src/config/reverse-warrior.ts +36 -0
- package/src/config/shoulder-press.ts +3 -0
- package/src/config/side-lung.ts +37 -0
- package/src/config/side-plank.ts +28 -0
- package/src/config/situp.ts +3 -0
- package/src/config/squat.ts +3 -0
- package/src/config/sumo-squat.ts +38 -0
- package/src/config/tree-pose.ts +3 -0
- package/src/config/triangle-pose.ts +37 -0
- package/src/config/tricep-dip.ts +3 -0
- package/src/config/v-up.ts +29 -0
- package/src/config/wall-sit.ts +3 -0
- package/src/config/warrior-i.ts +3 -0
- package/src/config/warrior-ii.ts +3 -0
- package/src/config/warrior-iii.ts +45 -0
- package/src/index.tsx +31 -3
|
@@ -26,6 +26,7 @@ class NitroPoseExercises : HybridNitroPoseExercisesSpec() {
|
|
|
26
26
|
private var poseDetector: PoseDetector? = null
|
|
27
27
|
private var isInitialized = false
|
|
28
28
|
|
|
29
|
+
|
|
29
30
|
// ─── Cached Landmarks (ML Kit is async, we cache last result) ──
|
|
30
31
|
private var cachedLandmarks: Array<Landmark> = emptyArray()
|
|
31
32
|
private val landmarkLock = Any()
|
|
@@ -115,6 +116,14 @@ class NitroPoseExercises : HybridNitroPoseExercisesSpec() {
|
|
|
115
116
|
override var onPoseRegained: (() -> Unit)? = null
|
|
116
117
|
override var onSessionComplete: ((result: SessionResult) -> Unit)? = null
|
|
117
118
|
|
|
119
|
+
override var onPostureLost: (() -> Unit)? = null
|
|
120
|
+
override var onPostureRegained: (() -> Unit)? = null
|
|
121
|
+
|
|
122
|
+
// ─── Posture Gate ──────────────────────────────────────────
|
|
123
|
+
private var consecutivePostureFailures: Int = 0
|
|
124
|
+
private val postureFailureThreshold: Int = 10
|
|
125
|
+
private var postureWasLost = false
|
|
126
|
+
|
|
118
127
|
// ─── Hold Tracking ──────────────────────────────────────────
|
|
119
128
|
private var holdStartTime: Long? = null
|
|
120
129
|
|
|
@@ -143,6 +152,12 @@ class NitroPoseExercises : HybridNitroPoseExercisesSpec() {
|
|
|
143
152
|
resetSession()
|
|
144
153
|
}
|
|
145
154
|
|
|
155
|
+
override fun isReady(): Boolean {
|
|
156
|
+
val config = exerciseConfig ?: return false
|
|
157
|
+
if (_landmarks.isEmpty()) return false
|
|
158
|
+
return isPostureValid(config.postureFamily)
|
|
159
|
+
}
|
|
160
|
+
|
|
146
161
|
// ═══════════════════════════════════════════════════════════
|
|
147
162
|
// Exercise Setup
|
|
148
163
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -201,7 +216,10 @@ override fun processFrame(frame: HybridFrameSpec) {
|
|
|
201
216
|
val nativeBuffer = frame.getNativeBuffer()
|
|
202
217
|
val bitmap = FrameHelper.hardwareBufferToBitmap(nativeBuffer.pointer) ?: return
|
|
203
218
|
|
|
204
|
-
|
|
219
|
+
|
|
220
|
+
val rotation = rotationDegreesFromFrame(frame)
|
|
221
|
+
val inputImage = InputImage.fromBitmap(bitmap, rotation)
|
|
222
|
+
|
|
205
223
|
val imageWidth = bitmap.width.toDouble()
|
|
206
224
|
val imageHeight = bitmap.height.toDouble()
|
|
207
225
|
|
|
@@ -270,9 +288,29 @@ override fun processFrame(frame: HybridFrameSpec) {
|
|
|
270
288
|
// Exercise Logic Engine
|
|
271
289
|
// ═══════════════════════════════════════════════════════════
|
|
272
290
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
291
|
+
private fun processExerciseLogic() {
|
|
292
|
+
val config = exerciseConfig ?: return
|
|
293
|
+
if (_landmarks.isEmpty()) return
|
|
294
|
+
|
|
295
|
+
// Posture gate with hysteresis
|
|
296
|
+
if (!isPostureValid(config.postureFamily)) {
|
|
297
|
+
consecutivePostureFailures++
|
|
298
|
+
if (consecutivePostureFailures >= postureFailureThreshold) {
|
|
299
|
+
if (!postureWasLost) {
|
|
300
|
+
postureWasLost = true
|
|
301
|
+
onPostureLost?.invoke()
|
|
302
|
+
}
|
|
303
|
+
_currentPhase = ExercisePhase.UNKNOWN
|
|
304
|
+
phaseHistory.clear()
|
|
305
|
+
}
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
consecutivePostureFailures = 0
|
|
310
|
+
if (postureWasLost) {
|
|
311
|
+
postureWasLost = false
|
|
312
|
+
onPostureRegained?.invoke()
|
|
313
|
+
}
|
|
276
314
|
|
|
277
315
|
val currentAngles = mutableMapOf<String, Double>()
|
|
278
316
|
val angleSnapshots = mutableListOf<AngleSnapshot>()
|
|
@@ -511,6 +549,83 @@ override fun processFrame(frame: HybridFrameSpec) {
|
|
|
511
549
|
onSessionComplete?.invoke(result)
|
|
512
550
|
}
|
|
513
551
|
|
|
552
|
+
// ═══════════════════════════════════════════════════════════
|
|
553
|
+
// Orientation Helpers
|
|
554
|
+
// ═══════════════════════════════════════════════════════════
|
|
555
|
+
|
|
556
|
+
private fun rotationDegreesFromFrame(frame: HybridFrameSpec): Int {
|
|
557
|
+
return when (frame.orientation.name.lowercase()) {
|
|
558
|
+
"up" -> 0
|
|
559
|
+
"right" -> 90
|
|
560
|
+
"down" -> 180
|
|
561
|
+
"left" -> 270
|
|
562
|
+
else -> 0
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// ═══════════════════════════════════════════════════════════
|
|
567
|
+
// Posture Gates
|
|
568
|
+
// ═══════════════════════════════════════════════════════════
|
|
569
|
+
|
|
570
|
+
private func isPostureValid(_ family: String) -> Bool {
|
|
571
|
+
guard _landmarks.count >= 33 else { return false }
|
|
572
|
+
|
|
573
|
+
let visThreshold = exerciseConfig?.visibilityThreshold ?? 0.3
|
|
574
|
+
|
|
575
|
+
if (_landmarks.size < 33) return false
|
|
576
|
+
|
|
577
|
+
val ls = _landmarks[11]; val rs = _landmarks[12]
|
|
578
|
+
val lh = _landmarks[23]; val rh = _landmarks[24]
|
|
579
|
+
val lk = _landmarks[25]; val rk = _landmarks[26]
|
|
580
|
+
val la = _landmarks[27]; val ra = _landmarks[28]
|
|
581
|
+
|
|
582
|
+
val keyVisible = ls.visibility > 0.3 && rs.visibility > 0.3 &&
|
|
583
|
+
lh.visibility > 0.3 && rh.visibility > 0.3
|
|
584
|
+
if (!keyVisible) return false
|
|
585
|
+
|
|
586
|
+
val shoulderY = (ls.y + rs.y) / 2
|
|
587
|
+
val hipY = (lh.y + rh.y) / 2
|
|
588
|
+
val shoulderX = (ls.x + rs.x) / 2
|
|
589
|
+
val hipX = (lh.x + rh.x) / 2
|
|
590
|
+
|
|
591
|
+
val kneesVisible = lk.visibility > 0.3 && rk.visibility > 0.3
|
|
592
|
+
val anklesVisible = la.visibility > 0.3 && ra.visibility > 0.3
|
|
593
|
+
val kneeY = if (kneesVisible) (lk.y + rk.y) / 2 else hipY
|
|
594
|
+
val ankleY = if (anklesVisible) (la.y + ra.y) / 2 else kneeY
|
|
595
|
+
|
|
596
|
+
return when (family) {
|
|
597
|
+
"horizontalProne" -> {
|
|
598
|
+
val ys = listOf(shoulderY, hipY, ankleY)
|
|
599
|
+
(ys.max() - ys.min()) < 0.25
|
|
600
|
+
}
|
|
601
|
+
"standingUpright" -> {
|
|
602
|
+
if (!kneesVisible) false
|
|
603
|
+
else shoulderY < hipY - 0.08 &&
|
|
604
|
+
hipY < kneeY + 0.05 &&
|
|
605
|
+
(if (anklesVisible) kneeY < ankleY else true)
|
|
606
|
+
}
|
|
607
|
+
"seated" -> {
|
|
608
|
+
if (!kneesVisible) false
|
|
609
|
+
else shoulderY < hipY - 0.05 && kotlin.math.abs(hipY - kneeY) < 0.20
|
|
610
|
+
}
|
|
611
|
+
"supine" -> {
|
|
612
|
+
val ys = listOf(shoulderY, hipY, ankleY)
|
|
613
|
+
(ys.max() - ys.min()) < 0.25
|
|
614
|
+
}
|
|
615
|
+
"sidePlank" -> {
|
|
616
|
+
val ySpread = kotlin.math.abs(shoulderY - hipY)
|
|
617
|
+
val shoulderHipDx = kotlin.math.abs(shoulderX - hipX)
|
|
618
|
+
ySpread < 0.20 && shoulderHipDx < 0.15
|
|
619
|
+
}
|
|
620
|
+
"inverted" -> {
|
|
621
|
+
if (!anklesVisible) false
|
|
622
|
+
else hipY < shoulderY && hipY < ankleY
|
|
623
|
+
}
|
|
624
|
+
"none" -> true
|
|
625
|
+
else -> true
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
514
629
|
// ═══════════════════════════════════════════════════════════
|
|
515
630
|
// Countdown
|
|
516
631
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -549,6 +664,8 @@ override fun processFrame(frame: HybridFrameSpec) {
|
|
|
549
664
|
targetReps = 0.0
|
|
550
665
|
countdownSeconds = 0.0
|
|
551
666
|
frameCount = 0
|
|
667
|
+
consecutivePostureFailures = 0
|
|
668
|
+
postureWasLost = false
|
|
552
669
|
synchronized(landmarkLock) {
|
|
553
670
|
cachedLandmarks = emptyArray()
|
|
554
671
|
}
|
|
@@ -70,6 +70,11 @@ class NitroPoseExercises: HybridNitroPoseExercisesSpec {
|
|
|
70
70
|
private var allRepDurations: [Double] = []
|
|
71
71
|
private var allRepFormScores: [Double] = []
|
|
72
72
|
|
|
73
|
+
// ─── Posture Gate ──────────────────────────────────────────
|
|
74
|
+
private var consecutivePostureFailures: Int = 0
|
|
75
|
+
private let postureFailureThreshold: Int = 10 // ~1s at 30fps with throttle=3
|
|
76
|
+
private var postureWasLost = false
|
|
77
|
+
|
|
73
78
|
// ─── Pose Tracking ──────────────────────────────────────────
|
|
74
79
|
private var poseWasLost = false
|
|
75
80
|
|
|
@@ -85,6 +90,8 @@ class NitroPoseExercises: HybridNitroPoseExercisesSpec {
|
|
|
85
90
|
var onPoseLost: (() -> Void)?
|
|
86
91
|
var onPoseRegained: (() -> Void)?
|
|
87
92
|
var onSessionComplete: ((_ result: SessionResult) -> Void)?
|
|
93
|
+
var onPostureLost: (() -> Void)?
|
|
94
|
+
var onPostureRegained: (() -> Void)?
|
|
88
95
|
|
|
89
96
|
// ─── Hold Tracking ──────────────────────────────────────────
|
|
90
97
|
private var holdStartTime: Date?
|
|
@@ -108,6 +115,12 @@ class NitroPoseExercises: HybridNitroPoseExercisesSpec {
|
|
|
108
115
|
resetSession()
|
|
109
116
|
}
|
|
110
117
|
|
|
118
|
+
func isReady() throws -> Bool {
|
|
119
|
+
guard let config = exerciseConfig else { return false }
|
|
120
|
+
guard !_landmarks.isEmpty else { return false }
|
|
121
|
+
return isPostureValid(config.postureFamily)
|
|
122
|
+
}
|
|
123
|
+
|
|
111
124
|
// ═══════════════════════════════════════════════════════════
|
|
112
125
|
// MARK: - Exercise Setup
|
|
113
126
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -151,12 +164,23 @@ class NitroPoseExercises: HybridNitroPoseExercisesSpec {
|
|
|
151
164
|
completeSession()
|
|
152
165
|
}
|
|
153
166
|
|
|
167
|
+
private static func cgOrientation(orientation: CameraOrientation, isMirrored: Bool) -> CGImagePropertyOrientation {
|
|
168
|
+
switch orientation {
|
|
169
|
+
case .up: return isMirrored ? .upMirrored : .up
|
|
170
|
+
case .down: return isMirrored ? .downMirrored : .down
|
|
171
|
+
case .left: return isMirrored ? .leftMirrored : .left
|
|
172
|
+
case .right: return isMirrored ? .rightMirrored : .right
|
|
173
|
+
@unknown default: return .up
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
154
177
|
// ═══════════════════════════════════════════════════════════
|
|
155
178
|
// MARK: - Frame Processing (Apple Vision)
|
|
156
179
|
// ═══════════════════════════════════════════════════════════
|
|
157
180
|
|
|
158
181
|
func processFrame(frame: any HybridFrameSpec) throws {
|
|
159
182
|
guard _status == .active || _status == .countdown else { return }
|
|
183
|
+
|
|
160
184
|
guard isInitialized else { return }
|
|
161
185
|
|
|
162
186
|
// Frame throttle
|
|
@@ -173,9 +197,11 @@ class NitroPoseExercises: HybridNitroPoseExercisesSpec {
|
|
|
173
197
|
// Create Vision request
|
|
174
198
|
let request = VNDetectHumanBodyPoseRequest()
|
|
175
199
|
|
|
176
|
-
|
|
177
|
-
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:])
|
|
200
|
+
print("[PoseExercise] orientation=\(frame.orientation) isMirrored=\(frame.isMirrored) type=\(type(of: frame.orientation))")
|
|
178
201
|
|
|
202
|
+
let cgOrient = Self.cgOrientation(orientation: frame.orientation, isMirrored: frame.isMirrored)
|
|
203
|
+
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: cgOrient, options: [:])
|
|
204
|
+
|
|
179
205
|
do {
|
|
180
206
|
try handler.perform([request])
|
|
181
207
|
|
|
@@ -241,13 +267,37 @@ class NitroPoseExercises: HybridNitroPoseExercisesSpec {
|
|
|
241
267
|
// MARK: - Exercise Logic Engine
|
|
242
268
|
// ═══════════════════════════════════════════════════════════
|
|
243
269
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
270
|
+
private func processExerciseLogic() {
|
|
271
|
+
|
|
272
|
+
guard let config = exerciseConfig else { return }
|
|
273
|
+
guard !_landmarks.isEmpty else { return }
|
|
274
|
+
|
|
275
|
+
// Posture gate with hysteresis
|
|
276
|
+
if !isPostureValid(family: config.postureFamily, threshold: config.visibilityThreshold) {
|
|
277
|
+
consecutivePostureFailures += 1
|
|
278
|
+
if consecutivePostureFailures >= postureFailureThreshold {
|
|
279
|
+
if !postureWasLost {
|
|
280
|
+
postureWasLost = true
|
|
281
|
+
onPostureLost?()
|
|
282
|
+
}
|
|
283
|
+
_currentPhase = .unknown
|
|
284
|
+
phaseHistory = []
|
|
285
|
+
}
|
|
286
|
+
return
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
consecutivePostureFailures = 0
|
|
290
|
+
|
|
291
|
+
if postureWasLost {
|
|
292
|
+
postureWasLost = false
|
|
293
|
+
onPostureRegained?()
|
|
294
|
+
}
|
|
247
295
|
|
|
248
296
|
var currentAngles: [String: Double] = [:]
|
|
249
297
|
var angleSnapshots: [AngleSnapshot] = []
|
|
250
298
|
|
|
299
|
+
let visThreshold = config.visibilityThreshold
|
|
300
|
+
|
|
251
301
|
for angleDef in config.angles {
|
|
252
302
|
let a = Int(angleDef.landmarkA)
|
|
253
303
|
let b = Int(angleDef.landmarkB)
|
|
@@ -255,10 +305,10 @@ class NitroPoseExercises: HybridNitroPoseExercisesSpec {
|
|
|
255
305
|
|
|
256
306
|
guard a < _landmarks.count, b < _landmarks.count, c < _landmarks.count else { continue }
|
|
257
307
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
_landmarks[
|
|
261
|
-
|
|
308
|
+
guard _landmarks[a].visibility > visThreshold,
|
|
309
|
+
_landmarks[b].visibility > visThreshold,
|
|
310
|
+
_landmarks[c].visibility > visThreshold else { continue }
|
|
311
|
+
|
|
262
312
|
|
|
263
313
|
let angle = calculateAngle(
|
|
264
314
|
pointA: _landmarks[a],
|
|
@@ -293,6 +343,71 @@ class NitroPoseExercises: HybridNitroPoseExercisesSpec {
|
|
|
293
343
|
}
|
|
294
344
|
}
|
|
295
345
|
|
|
346
|
+
// ═══════════════════════════════════════════════════════════
|
|
347
|
+
// MARK: - Posture Gates
|
|
348
|
+
// ═══════════════════════════════════════════════════════════
|
|
349
|
+
|
|
350
|
+
private func isPostureValid(_ family: String) -> Bool {
|
|
351
|
+
guard _landmarks.count >= 33 else { return false }
|
|
352
|
+
|
|
353
|
+
let ls = _landmarks[11], rs = _landmarks[12]
|
|
354
|
+
let lh = _landmarks[23], rh = _landmarks[24]
|
|
355
|
+
let lk = _landmarks[25], rk = _landmarks[26]
|
|
356
|
+
let la = _landmarks[27], ra = _landmarks[28]
|
|
357
|
+
|
|
358
|
+
let key = [ls, rs, lh, rh]
|
|
359
|
+
guard key.allSatisfy({ $0.visibility > 0.3 }) else { return false }
|
|
360
|
+
|
|
361
|
+
let shoulderY = (ls.y + rs.y) / 2
|
|
362
|
+
let hipY = (lh.y + rh.y) / 2
|
|
363
|
+
let shoulderX = (ls.x + rs.x) / 2
|
|
364
|
+
let hipX = (lh.x + rh.x) / 2
|
|
365
|
+
|
|
366
|
+
let kneesVisible = lk.visibility > 0.3 && rk.visibility > 0.3
|
|
367
|
+
let anklesVisible = la.visibility > 0.3 && ra.visibility > 0.3
|
|
368
|
+
let kneeY = kneesVisible ? (lk.y + rk.y) / 2 : hipY
|
|
369
|
+
let ankleY = anklesVisible ? (la.y + ra.y) / 2 : kneeY
|
|
370
|
+
|
|
371
|
+
switch family {
|
|
372
|
+
case "horizontalProne":
|
|
373
|
+
let ys = [shoulderY, hipY, ankleY]
|
|
374
|
+
let spread = (ys.max() ?? 0) - (ys.min() ?? 0)
|
|
375
|
+
return spread < 0.25
|
|
376
|
+
|
|
377
|
+
case "standingUpright":
|
|
378
|
+
guard kneesVisible else { return false }
|
|
379
|
+
return shoulderY < hipY - 0.08
|
|
380
|
+
&& hipY < kneeY + 0.05
|
|
381
|
+
&& (anklesVisible ? kneeY < ankleY : true)
|
|
382
|
+
|
|
383
|
+
case "seated":
|
|
384
|
+
guard kneesVisible else { return false }
|
|
385
|
+
return shoulderY < hipY - 0.05
|
|
386
|
+
&& abs(hipY - kneeY) < 0.20
|
|
387
|
+
|
|
388
|
+
case "supine":
|
|
389
|
+
let ys = [shoulderY, hipY, ankleY]
|
|
390
|
+
let spread = (ys.max() ?? 0) - (ys.min() ?? 0)
|
|
391
|
+
return spread < 0.25
|
|
392
|
+
|
|
393
|
+
case "sidePlank":
|
|
394
|
+
let ys = [shoulderY, hipY]
|
|
395
|
+
let ySpread = (ys.max() ?? 0) - (ys.min() ?? 0)
|
|
396
|
+
let shoulderHipDx = abs(shoulderX - hipX)
|
|
397
|
+
return ySpread < 0.20 && shoulderHipDx < 0.15
|
|
398
|
+
|
|
399
|
+
case "inverted":
|
|
400
|
+
guard anklesVisible else { return false }
|
|
401
|
+
return hipY < shoulderY && hipY < ankleY
|
|
402
|
+
|
|
403
|
+
case "none":
|
|
404
|
+
return true
|
|
405
|
+
|
|
406
|
+
default:
|
|
407
|
+
return true
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
296
411
|
// ═══════════════════════════════════════════════════════════
|
|
297
412
|
// MARK: - Angle Calculation
|
|
298
413
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -547,6 +662,8 @@ class NitroPoseExercises: HybridNitroPoseExercisesSpec {
|
|
|
547
662
|
countdownSeconds = 0
|
|
548
663
|
countdownTimer?.invalidate()
|
|
549
664
|
countdownTimer = nil
|
|
550
|
-
frameCount = 0
|
|
665
|
+
frameCount = 0,
|
|
666
|
+
consecutivePostureFailures = 0
|
|
667
|
+
postureWasLost = false
|
|
551
668
|
}
|
|
552
|
-
}
|
|
669
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NitroModules","nitroPoseExercises","createHybridObject"],"sourceRoot":"../../src","sources":["NitroPoseExercises.nitro.ts"],"mappings":";;AAAA,SAA4BA,YAAY,QAAQ,4BAA4B;;AAI5E;;
|
|
1
|
+
{"version":3,"names":["NitroModules","nitroPoseExercises","createHybridObject"],"sourceRoot":"../../src","sources":["NitroPoseExercises.nitro.ts"],"mappings":";;AAAA,SAA4BA,YAAY,QAAQ,4BAA4B;;AAI5E;;AAqBA;;AASA;;AAsCA;;AAmCA;;AA4CA,MAAMC,kBAAkB,GACtBD,YAAY,CAACE,kBAAkB,CAAqB,cAAc,CAAC;AAErE,SAASD,kBAAkB","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["BICEP_CURL_CONFIG","name","type","angles","landmarkA","landmarkB","landmarkC","phases","phase","angleName","minAngle","maxAngle","repSequence","formRules","message","severity","holdDurationMs"],"sourceRoot":"../../../src","sources":["config/bicep-curl.ts"],"mappings":";;AAEA;AACA;AACA;;AAEA,OAAO,MAAMA,iBAAiC,GAAG;EAC/CC,IAAI,EAAE,YAAY;EAClBC,IAAI,EAAE,KAAK;EACXC,MAAM,EAAE,CACN;
|
|
1
|
+
{"version":3,"names":["BICEP_CURL_CONFIG","name","type","postureFamily","visibilityThreshold","cameraAngle","angles","landmarkA","landmarkB","landmarkC","phases","phase","angleName","minAngle","maxAngle","repSequence","formRules","message","severity","holdDurationMs"],"sourceRoot":"../../../src","sources":["config/bicep-curl.ts"],"mappings":";;AAEA;AACA;AACA;;AAEA,OAAO,MAAMA,iBAAiC,GAAG;EAC/CC,IAAI,EAAE,YAAY;EAClBC,IAAI,EAAE,KAAK;EACXC,aAAa,EAAE,iBAAiB;EAChCC,mBAAmB,EAAE,GAAG;EACxBC,WAAW,EAAE,OAAO;EACpBC,MAAM,EAAE,CACN;IACEL,IAAI,EAAE,WAAW;IACjBM,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE,CAAE;EACjB,CAAC,EACD;IACER,IAAI,EAAE,YAAY;IAClBM,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE,CAAE;EACjB,CAAC,EACD;IACER,IAAI,EAAE,cAAc;IACpBM,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE,CAAE;EACjB,CAAC,CACF;EACDC,MAAM,EAAE,CACN;IACEC,KAAK,EAAE,MAAM;IACbC,SAAS,EAAE,WAAW;IACtBC,QAAQ,EAAE,GAAG;IACbC,QAAQ,EAAE;EACZ,CAAC,EACD;IACEH,KAAK,EAAE,IAAI;IACXC,SAAS,EAAE,WAAW;IACtBC,QAAQ,EAAE,EAAE;IACZC,QAAQ,EAAE;EACZ,CAAC,CACF;EACDC,WAAW,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC;EACnCC,SAAS,EAAE,CACT;IACEf,IAAI,EAAE,YAAY;IAClBgB,OAAO,EAAE,uCAAuC;IAChDC,QAAQ,EAAE,SAAS;IACnBN,SAAS,EAAE,cAAc;IACzBC,QAAQ,EAAE,CAAC;IACXC,QAAQ,EAAE;EACZ,CAAC,EACD;IACEb,IAAI,EAAE,UAAU;IAChBgB,OAAO,EAAE,oCAAoC;IAC7CC,QAAQ,EAAE,OAAO;IACjBN,SAAS,EAAE,cAAc;IACzBC,QAAQ,EAAE,CAAC;IACXC,QAAQ,EAAE;EACZ,CAAC,CACF;EACDK,cAAc,EAAE;AAClB,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export const BOAT_POSE_CONFIG = {
|
|
4
|
+
name: 'Boat Pose (Navasana)',
|
|
5
|
+
type: 'hold',
|
|
6
|
+
postureFamily: 'seated',
|
|
7
|
+
visibilityThreshold: 0.3,
|
|
8
|
+
cameraAngle: 'side',
|
|
9
|
+
angles: [{
|
|
10
|
+
name: 'hipFlexion',
|
|
11
|
+
landmarkA: 11,
|
|
12
|
+
landmarkB: 23,
|
|
13
|
+
landmarkC: 25
|
|
14
|
+
}, {
|
|
15
|
+
name: 'kneeAngle',
|
|
16
|
+
landmarkA: 23,
|
|
17
|
+
landmarkB: 25,
|
|
18
|
+
landmarkC: 27
|
|
19
|
+
}],
|
|
20
|
+
phases: [{
|
|
21
|
+
phase: 'hold',
|
|
22
|
+
angleName: 'hipFlexion',
|
|
23
|
+
minAngle: 60,
|
|
24
|
+
maxAngle: 110
|
|
25
|
+
}],
|
|
26
|
+
repSequence: [],
|
|
27
|
+
formRules: [{
|
|
28
|
+
name: 'backRounding',
|
|
29
|
+
message: "Lengthen your spine — don't round your back",
|
|
30
|
+
severity: 'warning',
|
|
31
|
+
angleName: 'hipFlexion',
|
|
32
|
+
minAngle: 60,
|
|
33
|
+
maxAngle: 110
|
|
34
|
+
}, {
|
|
35
|
+
name: 'legsDropping',
|
|
36
|
+
message: 'Keep your legs lifted',
|
|
37
|
+
severity: 'warning',
|
|
38
|
+
angleName: 'kneeAngle',
|
|
39
|
+
minAngle: 150,
|
|
40
|
+
maxAngle: 180
|
|
41
|
+
}],
|
|
42
|
+
holdDurationMs: 30000
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=boat-pose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["BOAT_POSE_CONFIG","name","type","postureFamily","visibilityThreshold","cameraAngle","angles","landmarkA","landmarkB","landmarkC","phases","phase","angleName","minAngle","maxAngle","repSequence","formRules","message","severity","holdDurationMs"],"sourceRoot":"../../../src","sources":["config/boat-pose.ts"],"mappings":";;AAEA,OAAO,MAAMA,gBAAgC,GAAG;EAC9CC,IAAI,EAAE,sBAAsB;EAC5BC,IAAI,EAAE,MAAM;EACZC,aAAa,EAAE,QAAQ;EACvBC,mBAAmB,EAAE,GAAG;EACxBC,WAAW,EAAE,MAAM;EACnBC,MAAM,EAAE,CACN;IAAEL,IAAI,EAAE,YAAY;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,EACnE;IAAER,IAAI,EAAE,WAAW;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,CACnE;EACDC,MAAM,EAAE,CACN;IAAEC,KAAK,EAAE,MAAM;IAAEC,SAAS,EAAE,YAAY;IAAEC,QAAQ,EAAE,EAAE;IAAEC,QAAQ,EAAE;EAAI,CAAC,CACxE;EACDC,WAAW,EAAE,EAAE;EACfC,SAAS,EAAE,CACT;IACEf,IAAI,EAAE,cAAc;IACpBgB,OAAO,EAAE,6CAA6C;IACtDC,QAAQ,EAAE,SAAS;IACnBN,SAAS,EAAE,YAAY;IACvBC,QAAQ,EAAE,EAAE;IACZC,QAAQ,EAAE;EACZ,CAAC,EACD;IACEb,IAAI,EAAE,cAAc;IACpBgB,OAAO,EAAE,uBAAuB;IAChCC,QAAQ,EAAE,SAAS;IACnBN,SAAS,EAAE,WAAW;IACtBC,QAAQ,EAAE,GAAG;IACbC,QAAQ,EAAE;EACZ,CAAC,CACF;EACDK,cAAc,EAAE;AAClB,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export const BOW_POSE_CONFIG = {
|
|
4
|
+
name: 'Bow Pose (Dhanurasana)',
|
|
5
|
+
type: 'hold',
|
|
6
|
+
postureFamily: 'horizontalProne',
|
|
7
|
+
visibilityThreshold: 0.25,
|
|
8
|
+
cameraAngle: 'side',
|
|
9
|
+
angles: [{
|
|
10
|
+
name: 'kneeAngle',
|
|
11
|
+
landmarkA: 23,
|
|
12
|
+
landmarkB: 25,
|
|
13
|
+
landmarkC: 27
|
|
14
|
+
}, {
|
|
15
|
+
name: 'shoulderExtension',
|
|
16
|
+
landmarkA: 23,
|
|
17
|
+
landmarkB: 11,
|
|
18
|
+
landmarkC: 15
|
|
19
|
+
}],
|
|
20
|
+
phases: [{
|
|
21
|
+
phase: 'hold',
|
|
22
|
+
angleName: 'kneeAngle',
|
|
23
|
+
minAngle: 50,
|
|
24
|
+
maxAngle: 100
|
|
25
|
+
}],
|
|
26
|
+
repSequence: [],
|
|
27
|
+
formRules: [{
|
|
28
|
+
name: 'kneesTooWide',
|
|
29
|
+
message: 'Keep your knees hip-width apart',
|
|
30
|
+
severity: 'warning',
|
|
31
|
+
angleName: 'kneeAngle',
|
|
32
|
+
minAngle: 50,
|
|
33
|
+
maxAngle: 100
|
|
34
|
+
}],
|
|
35
|
+
holdDurationMs: 30000
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=bow-pose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["BOW_POSE_CONFIG","name","type","postureFamily","visibilityThreshold","cameraAngle","angles","landmarkA","landmarkB","landmarkC","phases","phase","angleName","minAngle","maxAngle","repSequence","formRules","message","severity","holdDurationMs"],"sourceRoot":"../../../src","sources":["config/bow-pose.ts"],"mappings":";;AACA,OAAO,MAAMA,eAA+B,GAAG;EAC7CC,IAAI,EAAE,wBAAwB;EAC9BC,IAAI,EAAE,MAAM;EACZC,aAAa,EAAE,iBAAiB;EAChCC,mBAAmB,EAAE,IAAI;EACzBC,WAAW,EAAE,MAAM;EACnBC,MAAM,EAAE,CACN;IAAEL,IAAI,EAAE,WAAW;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,EAClE;IAAER,IAAI,EAAE,mBAAmB;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,CAC3E;EACDC,MAAM,EAAE,CACN;IAAEC,KAAK,EAAE,MAAM;IAAEC,SAAS,EAAE,WAAW;IAAEC,QAAQ,EAAE,EAAE;IAAEC,QAAQ,EAAE;EAAI,CAAC,CACvE;EACDC,WAAW,EAAE,EAAE;EACfC,SAAS,EAAE,CACT;IACEf,IAAI,EAAE,cAAc;IACpBgB,OAAO,EAAE,iCAAiC;IAC1CC,QAAQ,EAAE,SAAS;IACnBN,SAAS,EAAE,WAAW;IACtBC,QAAQ,EAAE,EAAE;IACZC,QAAQ,EAAE;EACZ,CAAC,CACF;EACDK,cAAc,EAAE;AAClB,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export const BRIDGE_POSE_CONFIG = {
|
|
4
|
+
name: 'Bridge Pose (Setu Bandhasana)',
|
|
5
|
+
type: 'hold',
|
|
6
|
+
postureFamily: 'supine',
|
|
7
|
+
visibilityThreshold: 0.3,
|
|
8
|
+
cameraAngle: 'side',
|
|
9
|
+
angles: [{
|
|
10
|
+
name: 'hipExtension',
|
|
11
|
+
landmarkA: 11,
|
|
12
|
+
landmarkB: 23,
|
|
13
|
+
landmarkC: 25
|
|
14
|
+
}, {
|
|
15
|
+
name: 'kneeAngle',
|
|
16
|
+
landmarkA: 23,
|
|
17
|
+
landmarkB: 25,
|
|
18
|
+
landmarkC: 27
|
|
19
|
+
}],
|
|
20
|
+
phases: [{
|
|
21
|
+
phase: 'hold',
|
|
22
|
+
angleName: 'kneeAngle',
|
|
23
|
+
minAngle: 80,
|
|
24
|
+
maxAngle: 110
|
|
25
|
+
}],
|
|
26
|
+
repSequence: [],
|
|
27
|
+
formRules: [{
|
|
28
|
+
name: 'hipsLow',
|
|
29
|
+
message: 'Push your hips up higher',
|
|
30
|
+
severity: 'warning',
|
|
31
|
+
angleName: 'hipExtension',
|
|
32
|
+
minAngle: 140,
|
|
33
|
+
maxAngle: 180
|
|
34
|
+
}],
|
|
35
|
+
holdDurationMs: 30000
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=bridge-pose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["BRIDGE_POSE_CONFIG","name","type","postureFamily","visibilityThreshold","cameraAngle","angles","landmarkA","landmarkB","landmarkC","phases","phase","angleName","minAngle","maxAngle","repSequence","formRules","message","severity","holdDurationMs"],"sourceRoot":"../../../src","sources":["config/bridge-pose.ts"],"mappings":";;AAEA,OAAO,MAAMA,kBAAkC,GAAG;EAChDC,IAAI,EAAE,+BAA+B;EACrCC,IAAI,EAAE,MAAM;EACZC,aAAa,EAAE,QAAQ;EACvBC,mBAAmB,EAAE,GAAG;EACxBC,WAAW,EAAE,MAAM;EACnBC,MAAM,EAAE,CACN;IAAEL,IAAI,EAAE,cAAc;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,EACrE;IAAER,IAAI,EAAE,WAAW;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,CACnE;EACDC,MAAM,EAAE,CACN;IAAEC,KAAK,EAAE,MAAM;IAAEC,SAAS,EAAE,WAAW;IAAEC,QAAQ,EAAE,EAAE;IAAEC,QAAQ,EAAE;EAAI,CAAC,CACvE;EACDC,WAAW,EAAE,EAAE;EACfC,SAAS,EAAE,CACT;IACEf,IAAI,EAAE,SAAS;IACfgB,OAAO,EAAE,0BAA0B;IACnCC,QAAQ,EAAE,SAAS;IACnBN,SAAS,EAAE,cAAc;IACzBC,QAAQ,EAAE,GAAG;IACbC,QAAQ,EAAE;EACZ,CAAC,CACF;EACDK,cAAc,EAAE;AAClB,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export const CALF_RAISE_CONFIG = {
|
|
4
|
+
name: 'Calf Raise',
|
|
5
|
+
type: 'rep',
|
|
6
|
+
postureFamily: 'standingUpright',
|
|
7
|
+
visibilityThreshold: 0.2,
|
|
8
|
+
cameraAngle: 'front',
|
|
9
|
+
angles: [{
|
|
10
|
+
name: 'leftAnkle',
|
|
11
|
+
landmarkA: 25,
|
|
12
|
+
landmarkB: 27,
|
|
13
|
+
landmarkC: 31
|
|
14
|
+
}, {
|
|
15
|
+
name: 'rightAnkle',
|
|
16
|
+
landmarkA: 26,
|
|
17
|
+
landmarkB: 28,
|
|
18
|
+
landmarkC: 32
|
|
19
|
+
}, {
|
|
20
|
+
name: 'leftKnee',
|
|
21
|
+
landmarkA: 23,
|
|
22
|
+
landmarkB: 25,
|
|
23
|
+
landmarkC: 27
|
|
24
|
+
}],
|
|
25
|
+
phases: [{
|
|
26
|
+
phase: 'down',
|
|
27
|
+
angleName: 'leftAnkle',
|
|
28
|
+
minAngle: 70,
|
|
29
|
+
maxAngle: 95
|
|
30
|
+
}, {
|
|
31
|
+
phase: 'up',
|
|
32
|
+
angleName: 'leftAnkle',
|
|
33
|
+
minAngle: 110,
|
|
34
|
+
maxAngle: 150
|
|
35
|
+
}],
|
|
36
|
+
repSequence: ['down', 'up', 'down'],
|
|
37
|
+
formRules: [{
|
|
38
|
+
name: 'kneesBending',
|
|
39
|
+
message: 'Keep your legs straight',
|
|
40
|
+
severity: 'warning',
|
|
41
|
+
angleName: 'leftKnee',
|
|
42
|
+
minAngle: 165,
|
|
43
|
+
maxAngle: 180
|
|
44
|
+
}],
|
|
45
|
+
holdDurationMs: 0
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=calf-raise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["CALF_RAISE_CONFIG","name","type","postureFamily","visibilityThreshold","cameraAngle","angles","landmarkA","landmarkB","landmarkC","phases","phase","angleName","minAngle","maxAngle","repSequence","formRules","message","severity","holdDurationMs"],"sourceRoot":"../../../src","sources":["config/calf-raise.ts"],"mappings":";;AAEA,OAAO,MAAMA,iBAAiC,GAAG;EAC/CC,IAAI,EAAE,YAAY;EAClBC,IAAI,EAAE,KAAK;EACXC,aAAa,EAAE,iBAAiB;EAChCC,mBAAmB,EAAE,GAAG;EACxBC,WAAW,EAAE,OAAO;EACpBC,MAAM,EAAE,CACN;IAAEL,IAAI,EAAE,WAAW;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,EAClE;IAAER,IAAI,EAAE,YAAY;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,EACnE;IAAER,IAAI,EAAE,UAAU;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,CAClE;EACDC,MAAM,EAAE,CACN;IAAEC,KAAK,EAAE,MAAM;IAAEC,SAAS,EAAE,WAAW;IAAEC,QAAQ,EAAE,EAAE;IAAEC,QAAQ,EAAE;EAAG,CAAC,EACrE;IAAEH,KAAK,EAAE,IAAI;IAAEC,SAAS,EAAE,WAAW;IAAEC,QAAQ,EAAE,GAAG;IAAEC,QAAQ,EAAE;EAAI,CAAC,CACtE;EACDC,WAAW,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC;EACnCC,SAAS,EAAE,CACT;IACEf,IAAI,EAAE,cAAc;IACpBgB,OAAO,EAAE,yBAAyB;IAClCC,QAAQ,EAAE,SAAS;IACnBN,SAAS,EAAE,UAAU;IACrBC,QAAQ,EAAE,GAAG;IACbC,QAAQ,EAAE;EACZ,CAAC,CACF;EACDK,cAAc,EAAE;AAClB,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export const CAMEL_POSE_CONFIG = {
|
|
4
|
+
name: 'Camel Pose (Ustrasana)',
|
|
5
|
+
type: 'hold',
|
|
6
|
+
postureFamily: 'seated',
|
|
7
|
+
visibilityThreshold: 0.3,
|
|
8
|
+
cameraAngle: 'side',
|
|
9
|
+
angles: [{
|
|
10
|
+
name: 'hipExtension',
|
|
11
|
+
landmarkA: 11,
|
|
12
|
+
landmarkB: 23,
|
|
13
|
+
landmarkC: 25
|
|
14
|
+
}, {
|
|
15
|
+
name: 'kneeAngle',
|
|
16
|
+
landmarkA: 23,
|
|
17
|
+
landmarkB: 25,
|
|
18
|
+
landmarkC: 27
|
|
19
|
+
}],
|
|
20
|
+
phases: [{
|
|
21
|
+
phase: 'hold',
|
|
22
|
+
angleName: 'hipExtension',
|
|
23
|
+
minAngle: 120,
|
|
24
|
+
maxAngle: 165
|
|
25
|
+
}],
|
|
26
|
+
repSequence: [],
|
|
27
|
+
formRules: [{
|
|
28
|
+
name: 'kneesTooWide',
|
|
29
|
+
message: 'Keep knees hip-width apart',
|
|
30
|
+
severity: 'warning',
|
|
31
|
+
angleName: 'kneeAngle',
|
|
32
|
+
minAngle: 80,
|
|
33
|
+
maxAngle: 100
|
|
34
|
+
}],
|
|
35
|
+
holdDurationMs: 30000
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=camel-pose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["CAMEL_POSE_CONFIG","name","type","postureFamily","visibilityThreshold","cameraAngle","angles","landmarkA","landmarkB","landmarkC","phases","phase","angleName","minAngle","maxAngle","repSequence","formRules","message","severity","holdDurationMs"],"sourceRoot":"../../../src","sources":["config/camel-pose.ts"],"mappings":";;AACA,OAAO,MAAMA,iBAAiC,GAAG;EAC/CC,IAAI,EAAE,wBAAwB;EAC9BC,IAAI,EAAE,MAAM;EACZC,aAAa,EAAE,QAAQ;EACvBC,mBAAmB,EAAE,GAAG;EACxBC,WAAW,EAAE,MAAM;EACnBC,MAAM,EAAE,CACN;IAAEL,IAAI,EAAE,cAAc;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,EACrE;IAAER,IAAI,EAAE,WAAW;IAAEM,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE,EAAE;IAAEC,SAAS,EAAE;EAAG,CAAC,CACnE;EACDC,MAAM,EAAE,CACN;IAAEC,KAAK,EAAE,MAAM;IAAEC,SAAS,EAAE,cAAc;IAAEC,QAAQ,EAAE,GAAG;IAAEC,QAAQ,EAAE;EAAI,CAAC,CAC3E;EACDC,WAAW,EAAE,EAAE;EACfC,SAAS,EAAE,CACT;IACEf,IAAI,EAAE,cAAc;IACpBgB,OAAO,EAAE,4BAA4B;IACrCC,QAAQ,EAAE,SAAS;IACnBN,SAAS,EAAE,WAAW;IACtBC,QAAQ,EAAE,EAAE;IACZC,QAAQ,EAAE;EACZ,CAAC,CACF;EACDK,cAAc,EAAE;AAClB,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["CHAIR_POSE_CONFIG","name","type","angles","landmarkA","landmarkB","landmarkC","phases","phase","angleName","minAngle","maxAngle","repSequence","formRules","message","severity","holdDurationMs"],"sourceRoot":"../../../src","sources":["config/chair-pose.ts"],"mappings":";;AAEA;AACA;AACA;AACA;;AAEA,OAAO,MAAMA,iBAAiC,GAAG;EAC/CC,IAAI,EAAE,yBAAyB;EAC/BC,IAAI,EAAE,MAAM;EACZC,MAAM,EAAE,CACN;
|
|
1
|
+
{"version":3,"names":["CHAIR_POSE_CONFIG","name","type","postureFamily","visibilityThreshold","cameraAngle","angles","landmarkA","landmarkB","landmarkC","phases","phase","angleName","minAngle","maxAngle","repSequence","formRules","message","severity","holdDurationMs"],"sourceRoot":"../../../src","sources":["config/chair-pose.ts"],"mappings":";;AAEA;AACA;AACA;AACA;;AAEA,OAAO,MAAMA,iBAAiC,GAAG;EAC/CC,IAAI,EAAE,yBAAyB;EAC/BC,IAAI,EAAE,MAAM;EACZC,aAAa,EAAE,iBAAiB;EAChCC,mBAAmB,EAAE,GAAG;EACxBC,WAAW,EAAE,MAAM;EACnBC,MAAM,EAAE,CACN;IACEL,IAAI,EAAE,UAAU;IAChBM,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE,CAAE;EACjB,CAAC,EACD;IACER,IAAI,EAAE,SAAS;IACfM,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE,CAAE;EACjB,CAAC,EACD;IACER,IAAI,EAAE,SAAS;IACfM,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE;IAAE;IACfC,SAAS,EAAE,EAAE,CAAE;EACjB,CAAC,CACF;EACDC,MAAM,EAAE,CACN;IACEC,KAAK,EAAE,MAAM;IACbC,SAAS,EAAE,UAAU;IACrBC,QAAQ,EAAE,EAAE;IACZC,QAAQ,EAAE;EACZ,CAAC,CACF;EACDC,WAAW,EAAE,EAAE;EACfC,SAAS,EAAE,CACT;IACEf,IAAI,EAAE,kBAAkB;IACxBgB,OAAO,EAAE,mCAAmC;IAC5CC,QAAQ,EAAE,SAAS;IACnBN,SAAS,EAAE,UAAU;IACrBC,QAAQ,EAAE,EAAE;IACZC,QAAQ,EAAE;EACZ,CAAC,EACD;IACEb,IAAI,EAAE,gBAAgB;IACtBgB,OAAO,EAAE,qDAAqD;IAC9DC,QAAQ,EAAE,SAAS;IACnBN,SAAS,EAAE,SAAS;IACpBC,QAAQ,EAAE,EAAE;IACZC,QAAQ,EAAE;EACZ,CAAC,EACD;IACEb,IAAI,EAAE,WAAW;IACjBgB,OAAO,EAAE,6BAA6B;IACtCC,QAAQ,EAAE,MAAM;IAChBN,SAAS,EAAE,SAAS;IACpBC,QAAQ,EAAE,GAAG;IACbC,QAAQ,EAAE;EACZ,CAAC,CACF;EACDK,cAAc,EAAE,KAAK,CAAE;AACzB,CAAC","ignoreList":[]}
|