Skip to content

fix(lint): stop scene-exit hard-kill rules from contradicting gsap_animates_clip_element#1846

Merged
miguel-heygen merged 1 commit into
mainfrom
fix/gsap-clip-hardkill-fixhint
Jul 3, 2026
Merged

fix(lint): stop scene-exit hard-kill rules from contradicting gsap_animates_clip_element#1846
miguel-heygen merged 1 commit into
mainfrom
fix/gsap-clip-hardkill-fixhint

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

Root-caused from two independent post-release feedback reports of the same lint contradiction.

The contradiction

scene_layer_missing_visibility_kill and gsap_exit_missing_hard_kill tell you to add tl.set(selector, { visibility: "hidden" }, t) on an exiting scene element. When that element is also class="clip", the exact tl.set they recommend is then flagged by gsap_animates_clip_element ("the framework manages clip visibility via visibility — do not animate these properties on clip elements"). Two users hit this independently:

"the linter both requires visibility:hidden on clip elements and forbids GSAP from animating visibility on clip elements."

"'scene_layer_missing_visibility_kill' lint rule tells you to add tl.set(...) on the exiting scene layer, but if that layer is also class='clip', the 'gsap_animates_clip_element' rule then errors on the same visibility set. [...] Would help if the first rule's fix hint mentioned the inner-wrapper pattern for clip scenes."

That second report describes exactly the workaround this fix teaches: wrap the scene's content in an inner non-clip <div> and move the exit tween + hard kill onto that wrapper.

Fix

Both rules now detect when the flagged/exiting selector is a clip element and, only in that case, point the fixHint at the inner-wrapper pattern instead of a tl.set on the clip element itself:

  • gsap_exit_missing_hard_kill reuses the clipIds/clipClasses maps already built in its enclosing rule.
  • scene_layer_missing_visibility_kill (a separate, older id-pattern rule) checks the flagged tag's class list directly, since it doesn't share that closure.

Non-clip targets are unaffected — identical fix hint as before.

Tests

Two new cases in gsap.test.ts (one per rule) asserting the fix hint mentions the inner-wrapper pattern and does NOT suggest a tl.set on the clip selector. All 67 existing + new tests in the suite pass.

…imates_clip_element

Two independent post-release feedback reports of the same contradiction:
scene_layer_missing_visibility_kill / gsap_exit_missing_hard_kill tell you to
add `tl.set(selector, { visibility: "hidden" }, t)` on an exiting scene
element, but when that element is also class="clip", the exact tl.set they
recommend is then flagged by gsap_animates_clip_element (the framework
already owns visibility/display on clip elements). One report worked around
it by wrapping the scene's content in an inner non-clip div and asked that
the fix hint mention that pattern.

Both rules now detect when the exiting/flagged selector is a clip element
(scene_layer_missing_visibility_kill checks the tag's class list directly;
gsap_exit_missing_hard_kill reuses the clipIds/clipClasses maps already built
in its enclosing rule) and, only in that case, point at the inner-wrapper
pattern instead of a tl.set on the clip element itself. Non-clip targets are
unaffected — same fix hint as before.
@miguel-heygen miguel-heygen marked this pull request as ready for review July 2, 2026 22:48

@james-russo-rames-d-jusso james-russo-rames-d-jusso left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at d9aacd3092 (batch review, Group C lint quality; layering on Magi's own vetting).
Note: bot-authored (Magi via miguel-heygen); COMMENT-quality — stamp routing per protocol.

Summary — reroutes the fixHint copy of gsap_exit_missing_hard_kill and scene_layer_missing_visibility_kill to the inner-wrapper pattern when the exiting/flagged selector is itself a clip element. Resolves the contradiction against gsap_animates_clip_element (which errors on tl.set(clip, { visibility })).

Verified

  • Detection unchanged, only hint copy changes. The hasHardKill check and the finding emission run before the branch; if the author DID add a hard kill, both rules still exit early. Non-clip targets get the original hint verbatim. No false negatives introduced.
  • Symmetric fix across two structurally-different rules. gsap_exit_missing_hard_kill reuses the clipIds / clipClasses maps already built in its enclosing closure (packages/lint/src/rules/gsap.ts:521-538). scene_layer_missing_visibility_kill is a separate top-level rule with no closure access, so it reads class attr on the flagged tag directly. Both routes converge on class="clip" — the same signal gsap_animates_clip_element uses at :678-680. Consistent.
  • Scene-inside-clip nesting: <div class="clip"><div id="scene1"...> — scene1 isn't itself clip, isClip=false, gets the plain hint tl.set("#scene1", ...). Since scene1 isn't a clip element, gsap_animates_clip_element won't fire on it. No contradiction. Correct.
  • Two tests, one per rule, assert (a) hint mentions "clip element" and "inner", (b) hint does NOT contain the direct tl.set on the clip selector. Targeted at both parts of the contradiction.

Nits

  • 🟡 The inner-wrapper hint template still emits the numeric boundary time (boundary.toFixed(2)) even though the actual selector is a placeholder ("<inner-selector>"). Author needs to substitute two things; the timing is still a useful reference number. Fine as-is.
  • 🟡 The hint text is duplicated between the two rules ("is a clip element — the framework already manages its visibility. Wrap the scene's content in an inner non-clip <div>..."). If a third rule joins this contradiction someday, worth pulling into a shared helper. Not for this PR.

Questions

  • ↩️ Is there any consumer (a build step, docs generator, telemetry) that dedupes findings by exact fixHint string? If yes, the divergence between clip-case and non-clip-case hints for the same code would produce two hint-buckets in whatever dashboard reads them. Probably not — but worth a git grep 'fixHint' if you have downstream aggregation.

— Rames D Jusso

@jrusso1020 jrusso1020 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE — verified CI green (0 fail / 0 pending) + no open CR at this head. Non-author stamp clearing the review gate on the Magi self-initiated draft-pass batch, which James greenlit and RDJ batch-cleared: both security holds re-verified at R2 (#1866 chrome-shell reclaim-race closed via the reclaim-gate + mtime recheck; #1845 Windows npx shell-injection closed — no cmd.exe, node <npx-cli.js> with pure argv), zero drift on the other nine, all green.

Merge via Magi's normal path (no admin-merge). Ordering note: the skills-manifest triple-conflict on #1877 / #1862 / #1845 (all bump hyperframes-media.hash) needs sequential rebase + regen at merge time; the rest land in any order.

Rames Jusso

@miguel-heygen miguel-heygen merged commit c7b34d5 into main Jul 3, 2026
39 checks passed
@miguel-heygen miguel-heygen deleted the fix/gsap-clip-hardkill-fixhint branch July 3, 2026 00:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants