Skip to content

Commit 84d807c

Browse files
committed
fix(studio): counter-rotate drag offset for css-rotated elements
CSS compose order is translate → rotate → transform. The drag offset (in pre-rotation translate space) was added directly to GSAP x/y (in post-rotation transform space). Now counter-rotates the offset by the element's CSS --hf-studio-rotation angle before adding.
1 parent f901ad1 commit 84d807c

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

packages/studio/src/hooks/gsapRuntimeBridge.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,18 @@ async function commitGsapPositionFromDrag(
173173
gsapPos: { x: number; y: number },
174174
callbacks: GsapDragCommitCallbacks,
175175
): Promise<void> {
176-
const newX = Math.round(gsapPos.x + studioOffset.x);
177-
const newY = Math.round(gsapPos.y + studioOffset.y);
176+
// CSS composition: translate → rotate → transform. The studioOffset is in
177+
// pre-rotation space (CSS translate), but GSAP x/y are in post-CSS-rotate
178+
// space (CSS transform). Counter-rotate the offset to match GSAP's frame.
179+
const rotStyle = selection.element.style.getPropertyValue("--hf-studio-rotation");
180+
const rotDeg = Number.parseFloat(rotStyle) || 0;
181+
const rad = (-rotDeg * Math.PI) / 180;
182+
const cos = Math.cos(rad);
183+
const sin = Math.sin(rad);
184+
const adjX = studioOffset.x * cos - studioOffset.y * sin;
185+
const adjY = studioOffset.x * sin + studioOffset.y * cos;
186+
const newX = Math.round(gsapPos.x + adjX);
187+
const newY = Math.round(gsapPos.y + adjY);
178188
const clearOffset = () => clearStudioPathOffset(selection.element);
179189

180190
if (anim.keyframes) {

0 commit comments

Comments
 (0)