@@ -1243,13 +1243,17 @@ function applyEaseUpdate(varsArg: AstNode, ease: string): void {
12431243 }
12441244}
12451245
1246- function applyUpdatesToCall ( call : TweenCallInfo , updates : Partial < GsapAnimation > ) : void {
1246+ function applyUpdatesToCall (
1247+ call : TweenCallInfo ,
1248+ updates : Partial < GsapAnimation > & { easeEach ?: string } ,
1249+ ) : void {
12471250 if ( updates . properties ) reconcileEditableProperties ( call . varsArg , updates . properties ) ;
12481251 if ( updates . fromProperties && call . method === "fromTo" && call . fromArg ) {
12491252 reconcileEditableProperties ( call . fromArg , updates . fromProperties ) ;
12501253 }
12511254 if ( updates . duration !== undefined ) setVarsKey ( call . varsArg , "duration" , updates . duration ) ;
1252- if ( updates . ease !== undefined ) applyEaseUpdate ( call . varsArg , updates . ease ) ;
1255+ if ( updates . easeEach !== undefined ) applyEaseUpdate ( call . varsArg , updates . easeEach ) ;
1256+ else if ( updates . ease !== undefined ) applyEaseUpdate ( call . varsArg , updates . ease ) ;
12531257 if ( updates . position !== undefined ) {
12541258 const posIdx = call . method === "fromTo" ? 3 : 2 ;
12551259 call . node . arguments [ posIdx ] = parseExpr ( valueToCode ( updates . position ) ) ;
@@ -1282,10 +1286,13 @@ function insertAfterAnchor(parsed: ParsedGsapAst, newStatement: AstNode): void {
12821286function buildTweenStatementCode ( timelineVar : string , anim : Omit < GsapAnimation , "id" > ) : string {
12831287 const selector = JSON . stringify ( anim . targetSelector ) ;
12841288 const props : Record < string , number | string > = { ...anim . properties } ;
1285- // `set` is instantaneous — GSAP ignores duration on it, so don't emit one.
12861289 if ( anim . method !== "set" && anim . duration !== undefined ) props . duration = anim . duration ;
12871290 if ( anim . ease ) props . ease = anim . ease ;
12881291 const entries = Object . entries ( props ) . map ( ( [ k , v ] ) => `${ safeKey ( k ) } : ${ valueToCode ( v ) } ` ) ;
1292+ // immediateRender forces GSAP to apply the set when added to the timeline,
1293+ // not on the first seek — without it, tl.set at position 0 on a paused
1294+ // timeline is invisible until the playhead moves past 0.
1295+ if ( anim . method === "set" ) entries . push ( "immediateRender: true" ) ;
12891296 if ( anim . extras ) {
12901297 for ( const [ k , v ] of Object . entries ( anim . extras ) ) {
12911298 entries . push ( `${ safeKey ( k ) } : ${ valueToCode ( v as number | string ) } ` ) ;
@@ -1308,7 +1315,7 @@ function buildTweenStatementCode(timelineVar: string, anim: Omit<GsapAnimation,
13081315export function updateAnimationInScript (
13091316 script : string ,
13101317 animationId : string ,
1311- updates : Partial < GsapAnimation > ,
1318+ updates : Partial < GsapAnimation > & { easeEach ?: string } ,
13121319) : string {
13131320 let parsed : ParsedGsapAst ;
13141321 try {
@@ -1437,6 +1444,7 @@ export function addAnimationWithKeyframesToScript(
14371444 auto ?: boolean ;
14381445 } > ,
14391446 ease ?: string ,
1447+ easeEach ?: string ,
14401448) : { script : string ; id : string } {
14411449 let parsed : ParsedGsapAst ;
14421450 try {
@@ -1450,7 +1458,7 @@ export function addAnimationWithKeyframesToScript(
14501458 }
14511459
14521460 const selector = JSON . stringify ( targetSelector ) ;
1453- const kfCode = buildKeyframeObjectCode ( keyframes ) ;
1461+ const kfCode = buildKeyframeObjectCode ( keyframes , easeEach ? { easeEach } : undefined ) ;
14541462 const varEntries = [ `keyframes: ${ kfCode } ` , `duration: ${ valueToCode ( duration ) } ` ] ;
14551463 if ( ease ) varEntries . push ( `ease: ${ JSON . stringify ( ease ) } ` ) ;
14561464 const posCode = valueToCode ( position ) ;
@@ -2216,6 +2224,23 @@ export function updateKeyframeInScript(
22162224 const match = findKeyframePropByPct ( kfNode , percentage ) ;
22172225 if ( ! match ) return script ;
22182226
2227+ if ( Object . keys ( properties ) . length === 0 && ease ) {
2228+ // Ease-only update: preserve existing properties, just add/replace ease
2229+ const existing = match . prop . value ;
2230+ if ( existing ?. type === "ObjectExpression" ) {
2231+ const props = ( existing . properties ?? [ ] ) as AstNode [ ] ;
2232+ const easeIdx = props . findIndex (
2233+ ( p : AstNode ) => isObjectProperty ( p ) && propKeyName ( p ) === "ease" ,
2234+ ) ;
2235+ const easeNode = parseExpr ( `({ ease: ${ JSON . stringify ( ease ) } })` ) . properties [ 0 ] ;
2236+ if ( easeIdx >= 0 ) {
2237+ props [ easeIdx ] = easeNode ;
2238+ } else {
2239+ props . push ( easeNode ) ;
2240+ }
2241+ return recast . print ( loc . parsed . ast ) . code ;
2242+ }
2243+ }
22192244 match . prop . value = buildKeyframeValueNode ( properties , ease ) ;
22202245 return recast . print ( loc . parsed . ast ) . code ;
22212246}
0 commit comments