Skip to content

Studio: resizing after a drag inserts tl.set before the timeline declaration (TDZ ReferenceError) #4518

Description

@Harlan66

Describe the bug

After an element has been dragged in Studio (which writes a global gsap.set("#el", { x, y }) above the timeline declaration, per #2099), resizing it writes tl.set("#el", { width, height }, 0) also above the declaration. const tl is then referenced in its temporal dead zone, the composition script throws, and every animation in the composition stops working.

Cause: findInsertionPoint in packages/parsers/src/gsapWriterAcorn.ts anchors new tl.* statements after the last located GSAP call. When the only located call is a global hold, that position is before const tl = gsap.timeline(...). addLabelToScript and addAnimationWithKeyframesToScript share the same insertion point.

Minimal reproduction

<div id="root" data-composition-id="main" data-start="0" data-duration="2" data-width="1920" data-height="1080">
  <div id="box" class="clip" data-start="0" data-duration="2" data-track-index="1"
       style="position:absolute; left:100px; top:100px; width:400px; height:300px; background:tomato"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script>
  window.__timelines = window.__timelines || {};
  const tl = gsap.timeline({ paused: true });
  window.__timelines["main"] = tl;
</script>

Or directly against the writer:

const s1 = addAnimationToScript(script, { targetSelector: "#box", method: "set", position: 0, properties: { x: 53, y: 157 }, global: true }).script;
const s2 = addAnimationToScript(s1, { targetSelector: "#box", method: "set", position: 0, properties: { width: 512, height: 670 } }).script;
// s2: gsap.set(...); tl.set(...); const tl = gsap.timeline(...)

Steps to reproduce

  1. npx hyperframes preview on the composition above.
  2. Drag #box on the canvas (a global gsap.set is written above the timeline).
  3. Resize #box with a corner handle.

Expected behavior

tl.set("#box", { width, height }, 0) is inserted after const tl = gsap.timeline(...).

Actual behavior

gsap.set("#box", { x: 53, y: 157 });
tl.set("#box", { width: 512, height: 670 }, 0);
const tl = gsap.timeline({ paused: true });

→ ReferenceError: Cannot access 'tl' before initialization; the composition script aborts. Workaround: put any tl.* call (e.g. tl.set({}, {}, 0);) right after the declaration so there is a located call to anchor on.

Environment

hyperframes CLI 0.8.77 (also reproduced on main @ 0985b45), macOS, Chrome.

Additional context

Fix PR to follow. The legacy recast writer in gsapParser.ts (insertAfterAnchor) has the same shape, but its write path is retired, so the PR leaves it alone.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions