From 6498807e1aeafdbe47f7caa9159b988d73a15443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Tue, 19 May 2026 15:32:45 -0400 Subject: [PATCH] fix(core): strip GSAP translate from transform after reapplying manual edits When GSAP animates an element (e.g. scale, opacity), it captures the element's translate into its internal transform matrix (m41/m42). The render reapply script was setting the CSS `translate` property but leaving GSAP's translate baked into `transform`, causing the manual edit offset to be ignored or doubled. Port the same stripGsapTranslateFromTransform logic the studio uses: parse the transform matrix, zero out m41/m42, and remove or rewrite the transform property so the CSS `translate` takes effect cleanly. --- .../helpers/manualEditsRenderScript.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/core/src/studio-api/helpers/manualEditsRenderScript.ts b/packages/core/src/studio-api/helpers/manualEditsRenderScript.ts index e3cc14330..cc4106fa5 100644 --- a/packages/core/src/studio-api/helpers/manualEditsRenderScript.ts +++ b/packages/core/src/studio-api/helpers/manualEditsRenderScript.ts @@ -195,6 +195,27 @@ function studioPositionSeekReapplyRuntime(): void { (tl.totalTime as (t: number, s: boolean) => void)(lastSeekTime, false); }; + const stripGsapTranslateFromTransform = (el: HTMLElement): void => { + const transform = el.style.getPropertyValue("transform"); + if (!transform || transform === "none") return; + const win = el.ownerDocument.defaultView as (Window & typeof globalThis) | null; + const MatrixCtor = (win as unknown as { DOMMatrix?: typeof DOMMatrix })?.DOMMatrix; + if (!MatrixCtor) return; + try { + const m = new MatrixCtor(transform); + if (m.m41 === 0 && m.m42 === 0) return; + m.m41 = 0; + m.m42 = 0; + if (m.is2D && m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1) { + el.style.removeProperty("transform"); + } else { + el.style.setProperty("transform", m.toString()); + } + } catch { + /* non-parseable transform — leave as-is */ + } + }; + const reapplyAll = (): void => { const offsetEls = document.querySelectorAll("[" + PATH_OFFSET_ATTR + '="true"]'); for (let i = 0; i < offsetEls.length; i++) { @@ -211,6 +232,7 @@ function studioPositionSeekReapplyRuntime(): void { "var(" + OFFSET_Y_PROP + ", 0px)", ), ); + stripGsapTranslateFromTransform(el); } } const boxSizeEls = document.querySelectorAll("[" + BOX_SIZE_ATTR + '="true"]');