diff --git a/packages/lint/src/rules/gsap.test.ts b/packages/lint/src/rules/gsap.test.ts
index e9b46325a..5b280df17 100644
--- a/packages/lint/src/rules/gsap.test.ts
+++ b/packages/lint/src/rules/gsap.test.ts
@@ -1315,4 +1315,204 @@ describe("GSAP rules", () => {
const finding = result.findings.find((f) => f.code === "scene_layer_missing_visibility_kill");
expect(finding).toBeUndefined();
});
+
+ it("gsap_non_transform_motion: errors on layout-prop tweens (left/marginLeft) and roundProps", async () => {
+ const html = `
+
+
+
+`;
+ const result = await lintHyperframeHtml(html);
+ const findings = result.findings.filter((f) => f.code === "gsap_non_transform_motion");
+ expect(findings).toHaveLength(3);
+ expect(findings.every((f) => f.severity === "error")).toBe(true);
+ });
+
+ it("gsap_non_transform_motion: does NOT fire on transform x/y", async () => {
+ const html = `
+
+
+
+`;
+ const result = await lintHyperframeHtml(html);
+ const finding = result.findings.find((f) => f.code === "gsap_non_transform_motion");
+ expect(finding).toBeUndefined();
+ });
+
+ it("gsap_non_transform_motion: does NOT fire on tl.set() (instantaneous, no stutter)", async () => {
+ const html = `
+
+
+
+`;
+ const result = await lintHyperframeHtml(html);
+ const finding = result.findings.find((f) => f.code === "gsap_non_transform_motion");
+ expect(finding).toBeUndefined();
+ });
+
+ it("gsap_non_transform_motion: one tween with both a layout prop AND roundProps reports once", async () => {
+ const html = `
+
+
+
+`;
+ const result = await lintHyperframeHtml(html);
+ const findings = result.findings.filter((f) => f.code === "gsap_non_transform_motion");
+ expect(findings).toHaveLength(1);
+ });
+
+ it("gsap_non_transform_motion: catches standalone gsap.to() animating a layout prop", async () => {
+ const html = `
+
+
+
+`;
+ const result = await lintHyperframeHtml(html);
+ const finding = result.findings.find(
+ (f) => f.code === "gsap_non_transform_motion" && f.selector === "#a",
+ );
+ expect(finding).toBeDefined();
+ });
+
+ it("gsap_non_transform_motion: does NOT fire on html-in-canvas elements (