From e8cf3b9bf325b18dde97c7acc96053ccc78f1c7e Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Thu, 5 Mar 2026 20:59:19 +0000 Subject: [PATCH 1/2] Restore rotate loop spin semantics while preserving reverse --- api/animate.js | 29 ++++++++++++++++++++--------- tests/animate.test.js | 26 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/api/animate.js b/api/animate.js index d0ba89ed..5356f6dd 100644 --- a/api/animate.js +++ b/api/animate.js @@ -168,18 +168,25 @@ export const flockAnimate = { "rotation", fps, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, - loop || reverse - ? BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE + reverse + ? BABYLON.Animation.ANIMATIONLOOPMODE_YOYO + : loop + ? BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE : BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT, ); - const rotateKeys = [ + const rotateKeys = loop + ? [ + { frame: 0, value: startRotation }, + { frame: frames, value: targetRotation }, + ] + : [ { frame: 0, value: startRotation }, { frame: frames, value: targetRotation }, - ]; - if (reverse || loop) { - rotateKeys.push({ frame: frames * 2, value: startRotation }); - } + ...(reverse + ? [{ frame: frames * 2, value: startRotation }] + : []), + ]; rotateAnimation.setKeys(rotateKeys); if (easing !== "Linear") { @@ -205,13 +212,17 @@ export const flockAnimate = { mesh, [rotateAnimation], 0, - reverse || loop ? frames * 2 : frames, + reverse && !loop ? frames * 2 : frames, loop, ); animatable.onAnimationEndObservable.add(() => { flock.scene.onAfterAnimationsObservable.remove(syncObserver); - if (!reverse) mesh.rotation = targetRotation.clone(); + if (reverse) { + mesh.rotation = startRotation.clone(); + } else { + mesh.rotation = targetRotation.clone(); + } resolve(); }); }); diff --git a/tests/animate.test.js b/tests/animate.test.js index 8c191444..35813308 100644 --- a/tests/animate.test.js +++ b/tests/animate.test.js @@ -211,6 +211,32 @@ export function runAnimateTests(flock) { expect(actualDuration).to.be.at.least(180); // Allow some tolerance expect(actualDuration).to.be.at.most(300); }); + + it("should return to the start rotation when reverse is true", async function () { + const boxId = "rotateAnimReverse"; + await flock.createBox(boxId, { + width: 1, + height: 1, + depth: 1, + position: [0, 0, 0], + }); + boxIds.push(boxId); + + const mesh = flock.scene.getMeshByName(boxId); + expect(mesh).to.exist; + + const initialRotation = mesh.rotation.clone(); + + await flock.rotateAnim(boxId, { + y: 90, + duration: 0.1, + reverse: true, + }); + + expect(mesh.rotation.x).to.be.closeTo(initialRotation.x, 0.01); + expect(mesh.rotation.y).to.be.closeTo(initialRotation.y, 0.01); + expect(mesh.rotation.z).to.be.closeTo(initialRotation.z, 0.01); + }); }); describe("animateProperty function", function () { From f5642e640db4ae1c0d21034795a4d2a59df6fcd4 Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Thu, 5 Mar 2026 21:08:58 +0000 Subject: [PATCH 2/2] Fix reverse+loop rotateAnim timing --- api/animate.js | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/api/animate.js b/api/animate.js index 5356f6dd..e0403200 100644 --- a/api/animate.js +++ b/api/animate.js @@ -168,25 +168,16 @@ export const flockAnimate = { "rotation", fps, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, - reverse - ? BABYLON.Animation.ANIMATIONLOOPMODE_YOYO - : loop - ? BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE + loop + ? BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE : BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT, ); - const rotateKeys = loop - ? [ - { frame: 0, value: startRotation }, - { frame: frames, value: targetRotation }, - ] - : [ + const rotateKeys = [ { frame: 0, value: startRotation }, { frame: frames, value: targetRotation }, - ...(reverse - ? [{ frame: frames * 2, value: startRotation }] - : []), - ]; + ...(reverse ? [{ frame: frames * 2, value: startRotation }] : []), + ]; rotateAnimation.setKeys(rotateKeys); if (easing !== "Linear") { @@ -212,7 +203,7 @@ export const flockAnimate = { mesh, [rotateAnimation], 0, - reverse && !loop ? frames * 2 : frames, + reverse ? frames * 2 : frames, loop, );