[] = [
const killPattern = new RegExp(`["']#${id}["'][^)]*visibility\\s*:\\s*["']hidden["']`);
const hasKill = killPattern.test(content);
if (!hasKill) {
+ // A tl.set on "#id" is only safe advice when the scene element isn't
+ // itself a clip — otherwise gsap_animates_clip_element errors on that
+ // exact tl.set, since the framework already owns visibility/display on
+ // clip elements. Point at the inner-wrapper pattern instead.
+ const classes = (readAttr(tag.raw, "class") || "").split(/\s+/).filter(Boolean);
+ const isClip = classes.includes("clip");
+ const fixHint = isClip
+ ? `"#${id}" is a clip element — the framework already manages its visibility. ` +
+ "Wrap the scene's content in an inner non-clip , move the exit tween and the hard kill " +
+ '(`tl.set("", { visibility: "hidden" }, )`) onto that wrapper instead.'
+ : `Add \`tl.set("#${id}", { visibility: "hidden" }, )\` after the scene's exit tweens.`;
+
findings.push({
code: "scene_layer_missing_visibility_kill",
severity: "error",
@@ -1021,7 +1045,7 @@ export const gsapRules: LintRule[] = [
message:
`Scene layer "#${id}" exits via opacity tween but has no visibility: hidden hard kill. ` +
"When scrubbing or when tweens conflict, the scene may remain partially visible and overlap the next scene.",
- fixHint: `Add \`tl.set("#${id}", { visibility: "hidden" }, )\` after the scene's exit tweens.`,
+ fixHint,
});
}
}