@@ -2964,43 +2964,58 @@ describe("initSandboxRuntimeModular", () => {
29642964 vi . useRealTimers ( ) ;
29652965 } ) ;
29662966
2967- it ( "shows the playhead's frame when a seek-only root binds late during a paused drag" , ( ) => {
2968- const raf = createManualRaf ( ) ;
2969- vi . spyOn ( performance , "now" ) . mockImplementation ( ( ) => raf . now ( ) ) ;
2970- window . requestAnimationFrame = raf . requestAnimationFrame as typeof window . requestAnimationFrame ;
2971- window . cancelAnimationFrame = raf . cancelAnimationFrame as typeof window . cancelAnimationFrame ;
2972- document . body . innerHTML = `
2973- <div data-composition-id="main" data-root="true" data-duration="10" data-width="1920" data-height="1080">
2974- <div id="sibling"></div>
2975- <div id="dragged" data-hf-studio-manual-edit-gesture="tok-1"></div>
2976- </div>
2977- ` ;
2978- window . __hfTimelinesBuilding = true ;
2979- initSandboxRuntimeModular ( ) ;
2980- window . __player ?. seek ( 5 ) ;
2981-
2982- const tl = gsap
2983- . timeline ( { paused : true } )
2984- . to ( "#sibling" , { x : 100 , duration : 10 , ease : "none" } ) ;
2985- const seekOnly : RuntimeTimelineLike = {
2986- play : ( ) => tl . play ( ) ,
2987- pause : ( ) => tl . pause ( ) ,
2988- seek : ( time , suppressEvents ) => tl . seek ( time ?? 0 , suppressEvents ) ,
2989- time : ( ) => tl . time ( ) ,
2990- duration : ( ) => tl . duration ( ) ,
2991- add : ( child , at ) => tl . add ( child as unknown as gsap . core . Timeline , at ) ,
2992- paused : ( paused ) => tl . paused ( paused ) ,
2993- set : ( target , vars , at ) => tl . set ( target , vars , at ) ,
2994- } ;
2995- window . __timelines = { main : seekOnly } ;
2996- window . __hfTimelinesBuilding = false ;
2997- window . dispatchEvent ( new CustomEvent ( "hf-timelines-built" ) ) ;
2998- raf . step ( 16 ) ;
2999- raf . step ( 16 ) ;
2967+ // Discovery no longer re-seeks a bound GSAP root, so binding alone must land it on the playhead.
2968+ it . each ( [
2969+ { root : "seek-only" , declared : ' data-duration="10"' , reported : 10 } ,
2970+ { root : "seek-only" , declared : "" , reported : 0 } ,
2971+ { root : "totalTime" , declared : "" , reported : 0 } ,
2972+ ] ) (
2973+ "shows the playhead's frame when a $root root (duration $reported) binds late during a paused drag" ,
2974+ ( { root, declared, reported } ) => {
2975+ const raf = createManualRaf ( ) ;
2976+ vi . spyOn ( performance , "now" ) . mockImplementation ( ( ) => raf . now ( ) ) ;
2977+ window . requestAnimationFrame =
2978+ raf . requestAnimationFrame as typeof window . requestAnimationFrame ;
2979+ window . cancelAnimationFrame = raf . cancelAnimationFrame as typeof window . cancelAnimationFrame ;
2980+ document . body . innerHTML = `
2981+ <div data-composition-id="main" data-root="true"${ declared } data-width="1920" data-height="1080">
2982+ <div id="sibling"></div>
2983+ <div id="dragged" data-hf-studio-manual-edit-gesture="tok-1"></div>
2984+ </div>
2985+ ` ;
2986+ window . __hfTimelinesBuilding = true ;
2987+ initSandboxRuntimeModular ( ) ;
2988+ window . __player ?. seek ( 5 ) ;
2989+
2990+ const fired = vi . fn ( ) ;
2991+ const tl = gsap
2992+ . timeline ( { paused : true } )
2993+ . to ( "#sibling" , { x : 100 , duration : 10 , ease : "none" } )
2994+ . call ( fired , [ ] , 2 ) ;
2995+ const facade : RuntimeTimelineLike = {
2996+ play : ( ) => tl . play ( ) ,
2997+ pause : ( ) => tl . pause ( ) ,
2998+ seek : ( time , suppressEvents ) => tl . seek ( time ?? 0 , suppressEvents ) ,
2999+ time : ( ) => tl . time ( ) ,
3000+ duration : ( ) => reported ,
3001+ add : ( child , at ) => tl . add ( child as unknown as gsap . core . Timeline , at ) ,
3002+ paused : ( paused ) => tl . paused ( paused ) ,
3003+ set : ( target , vars , at ) => tl . set ( target , vars , at ) ,
3004+ ...( root === "totalTime" && {
3005+ totalTime : ( time , suppressEvents ) => tl . totalTime ( time ?? 0 , suppressEvents ) ,
3006+ } ) ,
3007+ } ;
3008+ window . __timelines = { main : facade } ;
3009+ window . __hfTimelinesBuilding = false ;
3010+ window . dispatchEvent ( new CustomEvent ( "hf-timelines-built" ) ) ;
3011+ raf . step ( 16 ) ;
3012+ raf . step ( 16 ) ;
30003013
3001- expect ( tl . time ( ) ) . toBeCloseTo ( 5 ) ;
3002- expect ( gsap . getProperty ( "#sibling" , "x" ) ) . toBeCloseTo ( 50 ) ;
3003- } ) ;
3014+ expect ( tl . time ( ) ) . toBeCloseTo ( 5 ) ;
3015+ expect ( gsap . getProperty ( "#sibling" , "x" ) ) . toBeCloseTo ( 50 ) ;
3016+ expect ( fired ) . toHaveBeenCalledTimes ( 1 ) ;
3017+ } ,
3018+ ) ;
30043019
30053020 it ( "shows pip video at global start time even when host composition starts late" , ( ) => {
30063021 // Regression: resolveStartForElement used to add the host composition's start on top of
0 commit comments