Skip to content

feat(lint): flag late fromTo tweens that flash the authored state before starting - #3466

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

feat(lint): flag late fromTo tweens that flash the authored state before starting#3466
miguel-heygen wants to merge 1 commit into
mainfrom
fix/fromto-flash-lint

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

Problem

A tl.fromTo() positioned after the timeline start renders with GSAP's default immediateRender: false. If the target's authored state is visible, the element sits fully rendered from t=0, then jumps to the from-vars when the tween finally starts — a visible flash on every playback and every cold seek.

Real-world casualty: a typewriter composition whose code lines were supposed to type in one at a time. Every line was fully readable from frame 0, then vanished and slid back in when its tween fired. The composition passed all existing gates.

Fix

New lint rule gsap_fromto_flash_before_start in packages/lint. It fires when a fromTo():

  • starts after the timeline start (past a small epsilon, so zero-flash-window tweens at t=0 stay exempt), and
  • targets an element whose authored state is not already hidden, and
  • has state-changing from-vars (non-identity transforms, or opacity/autoAlpha ≠ 1).

Exemptions, each covered by a test:

  • authored hidden state: CSS opacity: 0, a standalone gsap.set(), or a timeline set-to-hidden at the timeline start
  • identity from-vars (tl.fromTo(el, { x: 0 }, ...)) — nothing to jump to
  • explicit immediateRender: true — GSAP applies the from-vars at build time and holds them

The fixHint offers the two real fixes: hide the authored state (CSS opacity: 0 + destination opacity: 1, or a position-0 tl.set), or immediateRender: true.

Testing

  • 8 new tests in packages/lint/src/rules/gsap.test.ts covering each trigger and exemption (170 pass in the file)
  • full packages/lint suite: 517 pass; the 8 failures in hyperframeLinter.test.ts (vi.unstubAllGlobals is not a function) reproduce on main untouched and are unrelated

…ore starting

A timeline fromTo() renders with GSAP's default immediateRender: false.
When its position is after the timeline start and the target's authored
state is visible, the element sits fully rendered from t=0, then jumps
to the from-vars when the tween begins — a visible flash on every
playback and cold seek. In practice this breaks typewriter reveals,
staggered line entrances, and any 'hidden until its beat' element.

New gsap_fromto_flash_before_start rule fires when a fromTo targets a
non-pre-hidden element at a position past the timeline start with
state-changing from-vars. Exemptions:

- authored hidden state (CSS opacity:0, standalone gsap.set, or a
  timeline set-to-hidden at the timeline start)
- identity from-vars (e.g. tl.fromTo(el, { x: 0 }, ...)) — no jump
- immediateRender: true — from-vars hold from load
- tweens at the timeline start (zero flash window)
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