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.
This commit is contained in:
Miguel Ángel
2026-05-19 15:45:51 -04:00
parent 8fd5bf8f51
commit 6498807e1a
@@ -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"]');