diff --git a/packages/lint/src/rules/gsap.test.ts b/packages/lint/src/rules/gsap.test.ts
index e0866686f7..d6da7ecdfa 100644
--- a/packages/lint/src/rules/gsap.test.ts
+++ b/packages/lint/src/rules/gsap.test.ts
@@ -565,6 +565,31 @@ describe("GSAP rules", () => {
expect(conflicts[0]?.message).toMatch(/x\/scale|scale\/x/);
});
+ it("does not duplicate the CSS transform text when one declaration matches both translate and scale", async () => {
+ const html = `
+
+
+
+
+`;
+ const result = await lintHyperframeHtml(html);
+ const conflict = result.findings.find((f) => f.code === "gsap_css_transform_conflict");
+ expect(conflict).toBeDefined();
+ const doubled = "scale(1.08) translate3d(1.5%, 0, 0) scale(1.08) translate3d(1.5%, 0, 0)";
+ expect(conflict?.message).not.toContain(doubled);
+ expect(conflict?.fixHint).not.toContain(doubled);
+ expect(conflict?.message).toContain("transform: scale(1.08) translate3d(1.5%, 0, 0)");
+ });
+
// --- Inline style transform detection tests ---
it("warns when inline style transform: translateX conflicts with GSAP x", async () => {
diff --git a/packages/lint/src/rules/gsap.ts b/packages/lint/src/rules/gsap.ts
index 3860658eb2..384555e6aa 100644
--- a/packages/lint/src/rules/gsap.ts
+++ b/packages/lint/src/rules/gsap.ts
@@ -1351,7 +1351,7 @@ export const gsapRules: LintRule[] = [
scaleProps.length > 0 ? matchCssTransform(sel, cssScaleSelectors) : undefined;
if (!cssFromTranslate && !cssFromScale) continue;
const existing = conflicts.get(sel) ?? {
- cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(" "),
+ cssTransform: [...new Set([cssFromTranslate, cssFromScale].filter(Boolean))].join(" "),
props: new Set(),
raw: call.raw,
};