Skip to content

fix(core): name the selector when a scoped GSAP target matches nothing - #5839

Merged
jrusso1020 merged 1 commit into
heygen-com:mainfrom
serdarucel:fix/gsap-missing-target-selector
Oct 24, 2026
Merged

jrusso1020 merged 1 commit into
heygen-com:mainfrom
serdarucel:fix/gsap-missing-target-selector

Conversation

@serdarucel

Copy link
Copy Markdown
Contributor

What

When a GSAP selector inside a sub-composition matches nothing, the hyperframes check warning now names the selector:

⚠ console_warning: GSAP target [data-part="reco-title"] not found. https://gsap.com

instead of GSAP target not found. https://gsap.com.

Why

The empty name makes the warning not actionable: in a composition with several tweens there is no way to tell which target missed (request 1 in #5687).

Related work

Refs #5687. This covers request 1 only (selector text in the message); the --strict escalation and a dedicated rule code (requests 2 and 3) are not part of this PR.

How

__hfResolveGsapTarget in packages/core/src/compiler/compositionScoping.ts turns a string (or array of strings) into the in-scope elements before GSAP sees it. GSAP 3.15 builds the warning as "GSAP target " + targets + " not found" (gsap-core.js, Tween constructor), so an empty array prints as an empty string.

When the resolved list is empty, the resolver still returns an empty array (nothing outside the composition gets targeted), but that array's toString() returns the authored target. The non-empty path is unchanged.

The two GSAP target not found lines that follow the named one come from GSAP itself (the fromTo from-state set on the already-empty _targets). A root composition with the same fromTo and no scoping prints the same three lines, so after this change a sub-composition matches root behavior.

Test plan

Reproduction project: root index.html + one sub-composition (compositions/reco.html) with tl.fromTo('[data-part="reco-title"]', ...) against an element that only has class="reco-title". Ran npx tsx src/cli.ts check <proj> --no-contrast from packages/cli on Windows 11.

Before (main e9181d0):

Runtime
  ⚠ console_warning: GSAP target  not found. https://gsap.com
  ⚠ console_warning: GSAP target  not found. https://gsap.com
  ⚠ console_warning: GSAP target  not found. https://gsap.com

After:

Runtime
  ⚠ console_warning: GSAP target [data-part="reco-title"] not found. https://gsap.com
  ⚠ console_warning: GSAP target  not found. https://gsap.com
  ⚠ console_warning: GSAP target  not found. https://gsap.com

Same fromTo in a root composition (no scoping), for comparison: the same three lines as After.

  • Unit tests added/updated: new test in compositionScoping.test.ts. The resolved target is empty, String(target) is the selector, and a matching element in another composition is not targeted. The test fails on main and passes with the change. npx vitest run src/compiler/compositionScoping.test.ts: 79 passed.
  • Manual testing performed (reproduction above)
  • Documentation updated (if applicable): not applicable
  • Comments follow CONTRIBUTING.md "Comments"

npx vitest run src/compiler in packages/core: 564 passed, 2 failed. The 2 failures are the htmlBundler.test.ts symlink tests (EPERM: operation not permitted, symlink, Windows without symlink privilege), and they fail the same way on main. oxlint, oxfmt --check, bun run typecheck (core), node scripts/check-comment-citations.mjs and node scripts/comment-ratchet.mjs are clean.

@miguel-heygen miguel-heygen 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.

Thank you for this, and welcome. This is a careful first change: small, well scoped to request 1 of the issue, and the write up explains the two trailing warnings instead of hiding them.

I verified the mechanism against the GSAP source rather than the screenshots, because the fix leans on how the library builds that string. In 3.15 the Tween constructor concatenates the original argument into the warning, not the parsed target list, so the overridden toString on the array you hand in is genuinely the one that prints. I also traced what happens to that array afterwards: it goes through the library's own toArray, which flattens into a fresh array, so the tag cannot escape into the scoped utils.toArray result or into author code. I replayed the resolver under node with an always empty query to confirm the named selector, the comma joined array form, the unchanged empty case and the untouched non empty path. The scoping invariant holds: the list is still empty, so nothing outside the composition is ever targeted.

Two notes for later, neither blocking. The fix rests on a library internal that no test here pins, since the new test uses a stub, so a future GSAP upgrade could quietly take the selector back out of the warning with everything still green. If the check output ever becomes something people script against, one test driving the real library through the wrapper would be worth having. And the override makes toString an own enumerable property of the array, which is contained today because the value never leaves the resolver's call sites; defineProperty would take that edge off for one more line.

On checks: only the mergeability and WIP jobs have run at this head, so the repo suite has not actually been exercised here. The branch is also a few hundred commits behind main, so please pull main in and let a full run happen before it merges.

@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.

Reviewed at 71d55882. Approving, on top of Miguel's approval at this head. On main, when a scoped selector matches nothing, __hfResolveGsapTarget returns an empty array or NodeList. GSAP builds its warning by string concatenation, so it prints GSAP target not found. The fix only touches that empty case. It still returns an empty array, so nothing outside the composition is targeted, and the array's toString() returns the authored selector. The non-empty path returns the same value as before.

The new test checks the three things that matter: the target is empty, String(target) is the selector, and a matching element in another composition isn't picked up. It fails on main, where String([]) is empty.

Need: yes, request 1 of #5687 · Size: ok · Reuse: nothing to reuse · Simpler: already minimal

— Rames

@jrusso1020

Copy link
Copy Markdown
Collaborator

Thanks, @serdarucel. This one is approved, and it'll go into the merge queue once these are sorted:

Once it's green and signed, we'll queue it at your new head. If you push code changes beyond a rebase, we'll take another look first.

— Rames

@serdarucel
serdarucel force-pushed the fix/gsap-missing-target-selector branch from 71d5588 to a084bee Compare October 24, 2026 09:05
@serdarucel

Copy link
Copy Markdown
Contributor Author

Thanks! Rebased on main and signed the commit; no code changes. The timeline viewport gate failure was the thumbnailRenders ceiling (14 -> 13), which main has already lowered.

@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.

Re-approving at the new head. I diffed this PR's own patch against the head I approved and it is identical, so this is a rebase and re-sign.

@jrusso1020

Copy link
Copy Markdown
Collaborator

Thanks, @serdarucel. CI at a084beee fails on both Linux and Windows in packages/core/src/compiler/pageBuild.golden.test.ts, in the 'preview' and 'render' pages of the repeated-scenes project. That golden snapshot embeds the runtime's __hfResolveGsapTarget, and this PR's empty-match change shows up as a snapshot mismatch. It's an expected diff, but the golden needs updating: run bunx vitest run src/compiler/pageBuild.golden.test.ts -u in packages/core, check that the only change is the resolver block, and push. I'll re-approve once CI is green.

— Rames

A sub-composition resolves GSAP selectors to a list of in-scope elements.
When that list is empty, GSAP's "target not found" warning stringified it
as an empty name, so check reported `GSAP target  not found` with no hint
of which selector missed. Keep the empty list but give it the authored
selector as its text, matching what GSAP prints in a root composition.

Refs heygen-com#5687
@serdarucel
serdarucel force-pushed the fix/gsap-missing-target-selector branch from a084bee to b3e911f Compare October 24, 2026 16:49
@serdarucel

Copy link
Copy Markdown
Contributor Author

Thanks! Updated both goldens with bunx vitest run src/compiler/pageBuild.golden.test.ts -u. The only change in pageBuild.preview.html and pageBuild.render.html is the __hfResolveGsapTarget block (three hunks per file, one per mount). Amended into the same signed commit; golden and compositionScoping tests pass locally (83/83).

@miguel-heygen miguel-heygen 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.

Thanks for updating the goldens. I compared this head against the one I approved: the resolver and its test are unchanged. Each golden changes only in the __hfResolveGsapTarget block, one hunk per mount, which is the expected snapshot diff.

CI is fully green here on both Linux and Windows. My two earlier notes (a test that drives the real GSAP warning through the wrapper, and defineProperty for the toString override) are still optional follow-ups, not blockers.

Verdict: APPROVE
Reasoning: The only change since the approved head is the expected golden update, and every check passes at this head.

@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.

Only adds the regenerated pageBuild golden snapshots, which match the source change. Re-approving at the new head.

@jrusso1020
jrusso1020 added this pull request to the merge queue Oct 24, 2026
Merged via the queue into heygen-com:main with commit e26d330 Oct 24, 2026
79 checks passed
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