@@ -413,6 +413,176 @@ describe("initSandboxRuntimeModular", () => {
413413 expect ( sceneB . style . visibility ) . toBe ( "visible" ) ;
414414 } ) ;
415415
416+ it ( "hides GSAP tween targets inside a hidden timed clip (issue #1387)" , ( ) => {
417+ const root = document . createElement ( "div" ) ;
418+ root . setAttribute ( "data-composition-id" , "main" ) ;
419+ root . setAttribute ( "data-root" , "true" ) ;
420+ root . setAttribute ( "data-start" , "0" ) ;
421+ root . setAttribute ( "data-duration" , "8" ) ;
422+ root . setAttribute ( "data-width" , "1920" ) ;
423+ root . setAttribute ( "data-height" , "1080" ) ;
424+ document . body . appendChild ( root ) ;
425+
426+ const captionOne = document . createElement ( "div" ) ;
427+ captionOne . id = "t01" ;
428+ captionOne . setAttribute ( "data-start" , "0" ) ;
429+ captionOne . setAttribute ( "data-duration" , "4" ) ;
430+ root . appendChild ( captionOne ) ;
431+
432+ const lineOne = document . createElement ( "div" ) ;
433+ lineOne . className = "line" ;
434+ // Studio stamps full-duration pseudo-clips on GSAP tween targets.
435+ lineOne . setAttribute ( "data-start" , "0" ) ;
436+ lineOne . setAttribute ( "data-duration" , "8" ) ;
437+ captionOne . appendChild ( lineOne ) ;
438+
439+ const captionTwo = document . createElement ( "div" ) ;
440+ captionTwo . id = "t02" ;
441+ captionTwo . setAttribute ( "data-start" , "4" ) ;
442+ captionTwo . setAttribute ( "data-duration" , "4" ) ;
443+ root . appendChild ( captionTwo ) ;
444+
445+ const lineTwo = document . createElement ( "div" ) ;
446+ lineTwo . className = "line" ;
447+ lineTwo . setAttribute ( "data-start" , "0" ) ;
448+ lineTwo . setAttribute ( "data-duration" , "8" ) ;
449+ captionTwo . appendChild ( lineTwo ) ;
450+
451+ window . __timelines = {
452+ main : createMockTimeline ( 8 ) ,
453+ } ;
454+
455+ initSandboxRuntimeModular ( ) ;
456+
457+ const player = window . __player ;
458+ expect ( player ) . toBeDefined ( ) ;
459+
460+ player ?. seek ( 1 ) ;
461+
462+ expect ( captionOne . style . visibility ) . toBe ( "visible" ) ;
463+ expect ( lineOne . style . visibility ) . toBe ( "visible" ) ;
464+ expect ( captionTwo . style . visibility ) . toBe ( "hidden" ) ;
465+ expect ( lineTwo . style . visibility ) . toBe ( "hidden" ) ;
466+
467+ player ?. seek ( 5 ) ;
468+
469+ expect ( captionOne . style . visibility ) . toBe ( "hidden" ) ;
470+ expect ( lineOne . style . visibility ) . toBe ( "hidden" ) ;
471+ expect ( captionTwo . style . visibility ) . toBe ( "visible" ) ;
472+ expect ( lineTwo . style . visibility ) . toBe ( "visible" ) ;
473+ } ) ;
474+
475+ it ( "does not stamp Studio timing on GSAP targets inside authored timed clips" , ( ) => {
476+ const originalParent = window . parent ;
477+ Object . defineProperty ( window , "parent" , {
478+ configurable : true ,
479+ value : { } ,
480+ } ) ;
481+
482+ try {
483+ const root = document . createElement ( "div" ) ;
484+ root . setAttribute ( "data-composition-id" , "main" ) ;
485+ root . setAttribute ( "data-root" , "true" ) ;
486+ root . setAttribute ( "data-start" , "0" ) ;
487+ root . setAttribute ( "data-duration" , "8" ) ;
488+ root . setAttribute ( "data-width" , "1920" ) ;
489+ root . setAttribute ( "data-height" , "1080" ) ;
490+ document . body . appendChild ( root ) ;
491+
492+ const caption = document . createElement ( "div" ) ;
493+ caption . id = "t01" ;
494+ caption . setAttribute ( "data-start" , "0" ) ;
495+ caption . setAttribute ( "data-duration" , "4" ) ;
496+ root . appendChild ( caption ) ;
497+
498+ const line = document . createElement ( "div" ) ;
499+ line . className = "line" ;
500+ caption . appendChild ( line ) ;
501+
502+ const tweenTarget = {
503+ targets : ( ) => [ line ] ,
504+ } ;
505+ const timeline = createMockTimeline ( 8 ) as RuntimeTimelineLike & {
506+ getChildren : ( nested ?: boolean ) => Array < { targets : ( ) => Element [ ] } > ;
507+ } ;
508+ timeline . getChildren = ( ) => [ tweenTarget ] ;
509+
510+ window . __timelines = {
511+ main : timeline ,
512+ } ;
513+
514+ initSandboxRuntimeModular ( ) ;
515+
516+ expect ( line . hasAttribute ( "data-start" ) ) . toBe ( false ) ;
517+ expect ( line . hasAttribute ( "data-duration" ) ) . toBe ( false ) ;
518+ } finally {
519+ Object . defineProperty ( window , "parent" , {
520+ configurable : true ,
521+ value : originalParent ,
522+ } ) ;
523+ }
524+ } ) ;
525+
526+ it ( "hides tween targets inside inactive multi-panel beats (niemmo panel stack)" , ( ) => {
527+ const root = document . createElement ( "div" ) ;
528+ root . setAttribute ( "data-composition-id" , "niemmo-launch-50" ) ;
529+ root . setAttribute ( "data-root" , "true" ) ;
530+ root . setAttribute ( "data-start" , "0" ) ;
531+ root . setAttribute ( "data-duration" , "50" ) ;
532+ root . setAttribute ( "data-width" , "1280" ) ;
533+ root . setAttribute ( "data-height" , "720" ) ;
534+ document . body . appendChild ( root ) ;
535+
536+ const panelA = document . createElement ( "div" ) ;
537+ panelA . className = "panel clip" ;
538+ panelA . setAttribute ( "data-composition-id" , "cold-open" ) ;
539+ panelA . setAttribute ( "data-start" , "0" ) ;
540+ panelA . setAttribute ( "data-duration" , "2" ) ;
541+ root . appendChild ( panelA ) ;
542+
543+ const headlineA = document . createElement ( "h1" ) ;
544+ headlineA . className = "co-headline" ;
545+ headlineA . setAttribute ( "data-start" , "0" ) ;
546+ headlineA . setAttribute ( "data-duration" , "50" ) ;
547+ panelA . appendChild ( headlineA ) ;
548+
549+ const panelB = document . createElement ( "div" ) ;
550+ panelB . className = "panel clip" ;
551+ panelB . setAttribute ( "data-composition-id" , "problem-dev-beat" ) ;
552+ panelB . setAttribute ( "data-start" , "2" ) ;
553+ panelB . setAttribute ( "data-duration" , "2.5" ) ;
554+ root . appendChild ( panelB ) ;
555+
556+ const headlineB = document . createElement ( "h1" ) ;
557+ headlineB . className = "pb-headline" ;
558+ headlineB . setAttribute ( "data-start" , "0" ) ;
559+ headlineB . setAttribute ( "data-duration" , "50" ) ;
560+ panelB . appendChild ( headlineB ) ;
561+
562+ window . __timelines = {
563+ "niemmo-launch-50" : createMockTimeline ( 50 ) ,
564+ } ;
565+
566+ initSandboxRuntimeModular ( ) ;
567+
568+ const player = window . __player ;
569+ expect ( player ) . toBeDefined ( ) ;
570+
571+ player ?. seek ( 1 ) ;
572+
573+ expect ( panelA . style . visibility ) . toBe ( "visible" ) ;
574+ expect ( headlineA . style . visibility ) . toBe ( "visible" ) ;
575+ expect ( panelB . style . visibility ) . toBe ( "hidden" ) ;
576+ expect ( headlineB . style . visibility ) . toBe ( "hidden" ) ;
577+
578+ player ?. seek ( 3 ) ;
579+
580+ expect ( panelA . style . visibility ) . toBe ( "hidden" ) ;
581+ expect ( headlineA . style . visibility ) . toBe ( "hidden" ) ;
582+ expect ( panelB . style . visibility ) . toBe ( "visible" ) ;
583+ expect ( headlineB . style . visibility ) . toBe ( "visible" ) ;
584+ } ) ;
585+
416586 it ( "clamps nested media to the authored host window on seek" , ( ) => {
417587 const root = document . createElement ( "div" ) ;
418588 root . setAttribute ( "data-composition-id" , "main" ) ;
0 commit comments