From 268488d93df1101101f56268c55742f3b7e08b43 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Fri, 28 Nov 2025 01:27:57 +0100 Subject: [PATCH] fix: Clamp leader rotation limits to prevent extreme angles and add a safety check for inverted limits. --- frontend/src/desktop/CardPhysics.ts | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/frontend/src/desktop/CardPhysics.ts b/frontend/src/desktop/CardPhysics.ts index 134b225..edc9ad1 100644 --- a/frontend/src/desktop/CardPhysics.ts +++ b/frontend/src/desktop/CardPhysics.ts @@ -137,8 +137,19 @@ export class CardPhysics { this.updateMassScale(); // Constrain leader limits to ensure follower stays within [-5, 5] - this.minLimit = Math.max(this.minLimit, -this.ROTATION_LIMIT - offset); - this.maxLimit = Math.min(this.maxLimit, this.ROTATION_LIMIT - offset); + // But clamp the result to never exceed the global limits [-5, 5] + // This prevents the leader from being forced into extreme angles by far-away followers + const calculatedMin = -this.ROTATION_LIMIT - offset; + const calculatedMax = this.ROTATION_LIMIT - offset; + + this.minLimit = Math.max(this.minLimit, Math.min(this.ROTATION_LIMIT, Math.max(-this.ROTATION_LIMIT, calculatedMin))); + this.maxLimit = Math.min(this.maxLimit, Math.max(-this.ROTATION_LIMIT, Math.min(this.ROTATION_LIMIT, calculatedMax))); + + // Safety: If limits invert (min > max), prioritize keeping leader near 0 + if (this.minLimit > this.maxLimit) { + this.minLimit = -this.ROTATION_LIMIT; + this.maxLimit = this.ROTATION_LIMIT; + } } removeFollower(card: LayoutCard) { @@ -172,9 +183,19 @@ export class CardPhysics { // Re-apply limits const offset = f.offsetRotation; - this.minLimit = Math.max(this.minLimit, -this.ROTATION_LIMIT - offset); - this.maxLimit = Math.min(this.maxLimit, this.ROTATION_LIMIT - offset); + const calculatedMin = -this.ROTATION_LIMIT - offset; + const calculatedMax = this.ROTATION_LIMIT - offset; + + this.minLimit = Math.max(this.minLimit, Math.min(this.ROTATION_LIMIT, Math.max(-this.ROTATION_LIMIT, calculatedMin))); + this.maxLimit = Math.min(this.maxLimit, Math.max(-this.ROTATION_LIMIT, Math.min(this.ROTATION_LIMIT, calculatedMax))); } + + // Safety check + if (this.minLimit > this.maxLimit) { + this.minLimit = -this.ROTATION_LIMIT; + this.maxLimit = this.ROTATION_LIMIT; + } + this.updateMassScale(); }