From 30969c6c90a0c75934d212a42fa7360eaf9f8791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Mon, 25 May 2026 19:16:17 -0400 Subject: [PATCH 1/2] fix(studio): use declared dimensions for overlay scale during GSAP playback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When GSAP applies transforms (scale, translate) to the root composition element during playback, rootRect.width/height from getBoundingClientRect() changes to reflect the transformed size. The overlay scale calculation (rootScaleX/Y = iframeRect / rootRect) then produces wrong values, causing overlays to appear at incorrect positions during animated playback — especially visible during scroll animations (y transform) and entrance animations (scale transform). Fix: use the composition's declared data-width/data-height attributes for scale calculation. These are the canonical dimensions that don't change with GSAP transforms. Falls back to rootRect dimensions when the attributes aren't present (non-composition elements). --- .../src/components/editor/domEditOverlayGeometry.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/studio/src/components/editor/domEditOverlayGeometry.ts b/packages/studio/src/components/editor/domEditOverlayGeometry.ts index 647c92174..56620788d 100644 --- a/packages/studio/src/components/editor/domEditOverlayGeometry.ts +++ b/packages/studio/src/components/editor/domEditOverlayGeometry.ts @@ -92,9 +92,16 @@ export function toOverlayRect( const root = doc?.querySelector("[data-composition-id]") ?? doc?.documentElement ?? null; const rootRect = root?.getBoundingClientRect(); - const rootWidth = rootRect?.width; - const rootHeight = rootRect?.height; - if (!rootWidth || !rootHeight) return null; + // Use the composition's declared dimensions (data-width/data-height) for scale + // calculation instead of rootRect.width/height. When GSAP applies transforms + // (scale, translate) to the root element, rootRect dimensions change but the + // composition's canonical size stays the same. Using rootRect causes overlay + // misalignment during animated playback. + const declaredWidth = readPositiveDimension(root?.getAttribute("data-width") ?? null); + const declaredHeight = readPositiveDimension(root?.getAttribute("data-height") ?? null); + const rootWidth = declaredWidth ?? rootRect?.width; + const rootHeight = declaredHeight ?? rootRect?.height; + if (!rootWidth || !rootHeight || !rootRect) return null; const elementRect = element.getBoundingClientRect(); const rootScaleX = iframeRect.width / rootWidth; From 45e03ab92ec71fa10eaeaf801974f12ef7130bec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Mon, 25 May 2026 23:40:27 +0000 Subject: [PATCH 2/2] fix(studio): remove rootRect subtraction from overlay position formula elementRect.left/top from getBoundingClientRect() already reflects GSAP transforms in viewport coordinates. Subtracting rootRect.left/top cancels the transform, pinning overlays to the un-animated layout position. Use elementRect directly so overlays track elements during scroll (y: -500) and entrance (scale: 0.95) animations. --- .../studio/src/components/editor/domEditOverlayGeometry.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/studio/src/components/editor/domEditOverlayGeometry.ts b/packages/studio/src/components/editor/domEditOverlayGeometry.ts index 56620788d..bfebd852b 100644 --- a/packages/studio/src/components/editor/domEditOverlayGeometry.ts +++ b/packages/studio/src/components/editor/domEditOverlayGeometry.ts @@ -118,8 +118,8 @@ export function toOverlayRect( }); return { - left: iframeRect.left - overlayRect.left + (elementRect.left - rootRect.left) * rootScaleX, - top: iframeRect.top - overlayRect.top + (elementRect.top - rootRect.top) * rootScaleY, + left: iframeRect.left - overlayRect.left + elementRect.left * rootScaleX, + top: iframeRect.top - overlayRect.top + elementRect.top * rootScaleY, width: elementRect.width * rootScaleX, height: elementRect.height * rootScaleY, editScaleX: editScale.scaleX,