( script: string, animationId: string, resolvedFromValues?: Record<string, number | string>, setDuration = 1, )
| 2544 | * the "to" state for `from()` tweens (the values the DOM would resolve to). |
| 2545 | */ |
| 2546 | export function convertToKeyframesInScript( |
| 2547 | script: string, |
| 2548 | animationId: string, |
| 2549 | resolvedFromValues?: Record<string, number | string>, |
| 2550 | setDuration = 1, |
| 2551 | ): string { |
| 2552 | let loc = locateAnimationWithFallback(script, animationId); |
| 2553 | if (!loc) return script; |
| 2554 | |
| 2555 | const anim = loc.target.animation; |
| 2556 | if (anim.keyframes) return script; |
| 2557 | |
| 2558 | const { fromProps, toProps } = resolveConversionProps(anim, resolvedFromValues); |
| 2559 | const varsArg = loc.target.call.varsArg; |
| 2560 | const originalEase = anim.ease; |
| 2561 | |
| 2562 | stripEditableAndEase(varsArg); |
| 2563 | insertKeyframesProp(varsArg, fromProps, toProps, originalEase || undefined); |
| 2564 | |
| 2565 | if (originalEase) { |
| 2566 | setVarsKey(varsArg, "ease", "none"); |
| 2567 | } |
| 2568 | |
| 2569 | // For from() or fromTo(), convert to to() |
| 2570 | if (anim.method === "from" || anim.method === "fromTo") { |
| 2571 | loc.target.call.node.callee.property.name = "to"; |
| 2572 | if (anim.method === "fromTo") loc.target.call.node.arguments.splice(1, 1); |
| 2573 | } |
| 2574 | |
| 2575 | // A static `set` becomes an animatable `to`: flip the method, drop the |
| 2576 | // immediateRender hold marker, and give it a real duration so the keyframes |
| 2577 | // span time. This is what makes a static 3D transform keyframeable. |
| 2578 | if (anim.method === "set") { |
| 2579 | // A GLOBAL `gsap.set(...)` is off-timeline; flipping only the method would |
| 2580 | // emit `gsap.to(...)`, which fires once at load and is NOT on the paused |
| 2581 | // master timeline (the engine can't seek/render it). Re-root it onto the |
| 2582 | // timeline var and add the position arg (a gsap.set has none) so the |
| 2583 | // converted tween is seekable. A `tl.set` already has the right object. |
| 2584 | const calleeObj = loc.target.call.node.callee.object; |
| 2585 | if (anim.global && calleeObj?.type === "Identifier") { |
| 2586 | calleeObj.name = loc.parsed.timelineVar; |
| 2587 | if (loc.target.call.node.arguments.length < 3) { |
| 2588 | loc.target.call.node.arguments.push(parseExpr("0")); |
| 2589 | } |
| 2590 | } |
| 2591 | loc.target.call.node.callee.property.name = "to"; |
| 2592 | removeVarsKey(varsArg, "immediateRender"); |
| 2593 | setVarsKey(varsArg, "duration", Math.max(0.001, setDuration)); |
| 2594 | } |
| 2595 | |
| 2596 | return recast.print(loc.parsed.ast).code; |
| 2597 | } |
| 2598 | |
| 2599 | /** |
| 2600 | * Remove all keyframes from a tween, collapsing to a flat tween with the |
no test coverage detected