Skip to content

feat(lint): warn on repeated tl.fromTo() on one selector without a tl.set baseline [P2]#2075

Open
miguel-heygen wants to merge 1 commit into
mainfrom
fix/lint-fromto-without-baseline
Open

feat(lint): warn on repeated tl.fromTo() on one selector without a tl.set baseline [P2]#2075
miguel-heygen wants to merge 1 commit into
mainfrom
fix/lint-fromto-without-baseline

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Bug

tl.fromTo(SELECTOR, { from }, { to }, laterTime) applies its from values
to the DOM at authoring time (GSAP's immediateRender), regardless of the
tween's timeline position. When the same string-literal selector gets 2+
tl.fromTo() calls with no earlier tl.set() baseline, the last-authored
from becomes the element's resting state for any seek before the first
tween actually runs, e.g. a z-index:999 overlay rendered solid black across
~40% of the timeline. hyperframes lint/validate/inspect all pass clean
today for this pattern.

Fix

New warning-severity rule: gsap_repeated_fromto_without_baseline, extending
the existing GSAP static analysis in packages/lint/src/rules/gsap.ts.

Per script/timeline: groups fromTo GSAP windows by target selector; for any
selector with 2+ fromTo calls, checks for a tl.set/gsap.set baseline on
that exact selector (before or at the first fromTo). If no baseline exists,
fires one finding per offending selector with a fixHint suggesting
tl.set(selector, { ...safe resting values... }, 0).

False-positive guards

This repo has a real history of GSAP false positives, so the rule is
conservative:

  • Byte-identical string-literal selector matching only, no normalization or
    token/substring matching.
  • Selectors the parser can't statically resolve (dynamic/variable selectors)
    never fire.
  • A single fromTo call on a selector never fires.
  • Two fromTo calls on different selectors never fire together.
  • Any tl.set/gsap.set on the exact same literal selector suppresses the
    finding.

Tests

Added 4 tests to packages/lint/src/rules/gsap.test.ts:

  • warns when repeated tl.fromTo calls target one selector without a
    tl.set baseline
  • does not warn when repeated tl.fromTo calls have an earlier tl.set
    baseline
  • does not warn for a single tl.fromTo call on a selector
  • does not warn when tl.fromTo calls target different selectors

bunx vitest run packages/lint/src/rules/gsap.test.ts: 86 passed.
bunx oxlint / bunx oxfmt --check: clean.

….set baseline

GSAP applies a fromTo()'s `from` vars to the DOM at authoring time regardless
of timeline position. When the SAME string-literal selector gets 2+ fromTo()
calls with no earlier tl.set()/gsap.set() baseline, the LAST-authored `from`
value becomes the resting state for any seek before the first tween, e.g. a
z-index:999 overlay rendered solid black across ~40% of the timeline while
lint/validate/inspect passed clean.

New rule gsap_repeated_fromto_without_baseline extends the existing gsap
static analysis: warns (not errors) when a byte-identical string-literal
selector has 2+ fromTo windows and no set() baseline for it. Conservative to
avoid the repo's history of gsap false positives: literal selectors only,
skipped when any set targets the same literal, skipped for dynamic selectors.
@miguel-heygen miguel-heygen force-pushed the fix/lint-fromto-without-baseline branch from b679d2c to f6bf77f Compare July 8, 2026 20:37
@miguel-heygen miguel-heygen marked this pull request as ready for review July 8, 2026 21:40
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.

1 participant