Slowly orbit the camera around prop-free form guides
Bodyweight motions (no equipment layer, no hide list) now turn the camera a full revolution every 24 seconds while the motion loops, so the exercise reads from every side; machine exercises keep their authored view, since scene equipment is a view-locked billboard and a hide list describes a single viewpoint. Claude-Session: https://claude.ai/code/session_01LEoff8bXGBS83tK1c55Mf7
This commit is contained in:
@@ -74,6 +74,25 @@ struct ExerciseMotionTests {
|
||||
#expect(hypot(releasedHand.x - 105, releasedHand.y - 152) > 1)
|
||||
}
|
||||
|
||||
/// Prop-free bodyweight motions slowly orbit the camera while looping; motions with
|
||||
/// equipment (view-locked scene shapes) or a hide list keep their authored view.
|
||||
@Test func orbitAppliesOnlyToPropFreeMotions() throws {
|
||||
let birdDog = try #require(FigureAnimation(exerciseName: "Bird Dog"))
|
||||
#expect(birdDog.orbits)
|
||||
// Same loop phase seconds apart: the orbit yaw differs, so the projected head
|
||||
// moves even though the pose is identical.
|
||||
let duration = birdDog.timeline.duration
|
||||
let head0 = birdDog.geometry(at: 0).headCenter
|
||||
let head1 = birdDog.geometry(at: duration * 2).headCenter
|
||||
#expect(hypot(head0.x - head1.x, head0.y - head1.y) > 1)
|
||||
|
||||
let legPress = try #require(FigureAnimation(exerciseName: "Leg Press"))
|
||||
#expect(!legPress.orbits)
|
||||
let fixed0 = legPress.geometry(at: 0).headCenter
|
||||
let fixed1 = legPress.geometry(at: legPress.timeline.duration * 2).headCenter
|
||||
#expect(abs(fixed0.x - fixed1.x) < 1e-9 && abs(fixed0.y - fixed1.y) < 1e-9)
|
||||
}
|
||||
|
||||
/// Every exported motion in the bundle decodes and builds a playable timeline.
|
||||
@Test func allBundledMotionsBuildTimelines() throws {
|
||||
let urls = Bundle.main.urls(forResourcesWithExtension: "json", subdirectory: nil) ?? []
|
||||
|
||||
Reference in New Issue
Block a user