@@ -116,7 +116,7 @@ describe("initSandboxRuntimeModular", () => {
116116 window . cancelAnimationFrame = originalCancelAnimationFrame ;
117117 } ) ;
118118
119- it ( "uses the shorter live child timeline when the authored window is longer " , ( ) => {
119+ it ( "keeps authored composition hosts visible when the live child timeline is shorter " , ( ) => {
120120 const root = document . createElement ( "div" ) ;
121121 root . setAttribute ( "data-composition-id" , "main" ) ;
122122 root . setAttribute ( "data-root" , "true" ) ;
@@ -143,6 +143,37 @@ describe("initSandboxRuntimeModular", () => {
143143
144144 player ?. renderSeek ( 9 ) ;
145145
146+ expect ( child . style . visibility ) . toBe ( "visible" ) ;
147+ } ) ;
148+
149+ it ( "uses live child timeline duration when a composition host has no authored duration" , ( ) => {
150+ const root = document . createElement ( "div" ) ;
151+ root . setAttribute ( "data-composition-id" , "main" ) ;
152+ root . setAttribute ( "data-root" , "true" ) ;
153+ root . setAttribute ( "data-start" , "0" ) ;
154+ root . setAttribute ( "data-width" , "1920" ) ;
155+ root . setAttribute ( "data-height" , "1080" ) ;
156+ document . body . appendChild ( root ) ;
157+
158+ const child = document . createElement ( "div" ) ;
159+ child . setAttribute ( "data-composition-id" , "slide-1" ) ;
160+ child . setAttribute ( "data-start" , "0" ) ;
161+ root . appendChild ( child ) ;
162+
163+ window . __timelines = {
164+ main : createMockTimeline ( 20 ) ,
165+ "slide-1" : createMockTimeline ( 8 ) ,
166+ } ;
167+
168+ initSandboxRuntimeModular ( ) ;
169+
170+ const player = window . __player ;
171+ expect ( player ) . toBeDefined ( ) ;
172+
173+ player ?. renderSeek ( 7 ) ;
174+ expect ( child . style . visibility ) . toBe ( "visible" ) ;
175+
176+ player ?. renderSeek ( 9 ) ;
146177 expect ( child . style . visibility ) . toBe ( "hidden" ) ;
147178 } ) ;
148179
@@ -491,7 +522,7 @@ describe("initSandboxRuntimeModular", () => {
491522 } ) ;
492523 } ) ;
493524
494- it ( "does not suppress descendant visibility in render mode (top-level page) " , ( ) => {
525+ it ( "hides timed descendants inside a hidden timed clip in render mode" , ( ) => {
495526 const root = document . createElement ( "div" ) ;
496527 root . setAttribute ( "data-composition-id" , "main" ) ;
497528 root . setAttribute ( "data-root" , "true" ) ;
@@ -507,12 +538,13 @@ describe("initSandboxRuntimeModular", () => {
507538 panel . setAttribute ( "data-duration" , "2" ) ;
508539 root . appendChild ( panel ) ;
509540
510- const headline = document . createElement ( "h1" ) ;
511- headline . className = "headline" ;
512- // Authored child window outlives the parent clip — render keeps legacy behavior.
513- headline . setAttribute ( "data-start" , "0" ) ;
514- headline . setAttribute ( "data-duration" , "8" ) ;
515- panel . appendChild ( headline ) ;
541+ const bottomBand = document . createElement ( "div" ) ;
542+ bottomBand . className = "bottom-band" ;
543+ // Regression shape: a child strip outlives its parent scene. Without
544+ // ancestor suppression it can paint through after the parent has ended.
545+ bottomBand . setAttribute ( "data-start" , "0" ) ;
546+ bottomBand . setAttribute ( "data-duration" , "8" ) ;
547+ panel . appendChild ( bottomBand ) ;
516548
517549 window . __timelines = {
518550 main : createMockTimeline ( 8 ) ,
@@ -526,7 +558,7 @@ describe("initSandboxRuntimeModular", () => {
526558 player ?. seek ( 3 ) ;
527559
528560 expect ( panel . style . visibility ) . toBe ( "hidden" ) ;
529- expect ( headline . style . visibility ) . toBe ( "visible " ) ;
561+ expect ( bottomBand . style . visibility ) . toBe ( "hidden " ) ;
530562 } ) ;
531563
532564 it ( "does not stamp Studio timing on GSAP targets inside authored timed clips" , ( ) => {
0 commit comments