Fix backward-bending joints in the five legacy motions

Abdominal's pinned hands used elbow -40 as the IK plane hint, drawing
the arms hyperextended (user-reported). Flipping the hint bends the
elbows the natural way while the hands stay on the handles. Same class
of fix for the milder cases: Arm Curl and Shoulder Press elbows and
Calfs knees clamp to -8, Side Plank's raised arm to the -70 ROM cap.
The whole library now passes render.py --strict with zero warnings,
making it a valid verification gate. Fixtures regenerated; 48 tests
green.

Claude-Session: https://claude.ai/code/session_01HJDQQDA9QdP8zByg43H5v3
This commit is contained in:
2026-07-07 13:06:18 -04:00
parent 7c241ec44c
commit bb234c198f
22 changed files with 172 additions and 53 deletions
@@ -79,9 +79,12 @@ struct WorkoutLogListView: View {
Section {
LabeledContent("Started", value: doc.start.formattedRelativeDateTime())
LabeledContent("Status") {
// Emphasize the states that mean the workout amounted to
// something a running or finished one over notStarted.
let emphasized = statusEnum == .inProgress || statusEnum == .completed
Text(statusEnum.displayName)
.fontWeight(statusEnum == .inProgress ? .bold : nil)
.foregroundStyle(statusEnum == .inProgress ? Color.accentColor : Color.secondary)
.fontWeight(emphasized ? .bold : nil)
.foregroundStyle(emphasized ? Color.accentColor : Color.secondary)
}
}
@@ -401,6 +404,17 @@ private struct WorkoutLogRow: View {
private var showsWeight: Bool { loadType == .weight }
/// Compact glanceable summary of the recorded machine settings ("Seat 4 · Back 3")
/// so the values are readable while setting up the machine, without opening the
/// sheet. Nil when nothing is recorded yet the button then reads "Settings".
private var settingsSummary: String? {
guard let settings = log.machineSettings, !settings.isEmpty else { return nil }
let parts = settings
.map { "\($0.name) \($0.value)".trimmingCharacters(in: .whitespaces) }
.filter { !$0.isEmpty }
return parts.isEmpty ? nil : parts.joined(separator: " · ")
}
var body: some View {
HStack(alignment: .top) {
Button {
@@ -443,9 +457,11 @@ private struct WorkoutLogRow: View {
if log.machineSettings != nil
|| ExerciseInfoLibrary.info(for: log.exerciseName)?.isMachineBased == true {
Button(action: onSettingsTap) {
Label("Settings", systemImage: "slider.horizontal.3")
Label(settingsSummary ?? "Settings", systemImage: "slider.horizontal.3")
.font(.footnote.weight(.medium))
.foregroundStyle(Color.accentColor)
.multilineTextAlignment(.trailing)
.lineLimit(2)
}
.buttonStyle(.plain)
}