(t: number, opts?: { activateChildren?: boolean })
| 2373 | }; |
| 2374 | |
| 2375 | const seekTimelineAndAdapters = (t: number, opts?: { activateChildren?: boolean }) => { |
| 2376 | const tl = state.capturedTimeline; |
| 2377 | if (tl) { |
| 2378 | // When rendering frame-by-frame (activateChildren=true), ensure all |
| 2379 | // sibling timelines are unpaused before seeking the root. GSAP |
| 2380 | // does not propagate totalTime() to children that are internally |
| 2381 | // paused, which leaves sub-compositions at their initial CSS state |
| 2382 | // (typically opacity:0). This mirrors the activateSiblingTimelines |
| 2383 | // call in player.ts renderSeek and is critical for sub-compositions |
| 2384 | // whose data-start is at or near 0 — they are added to the root |
| 2385 | // while it is paused and may never receive an explicit play(). |
| 2386 | if (opts?.activateChildren) { |
| 2387 | activateSiblingTimelines(tl); |
| 2388 | } |
| 2389 | // #10: when data-duration exceeds the timeline's intrinsic length the |
| 2390 | // engine requests frames past the last tween. Seeking a paused GSAP |
| 2391 | // timeline past its end can revert from()-tweens to their empty initial |
| 2392 | // state, blanking the final poster. Clamp the MASTER seek to the |
| 2393 | // timeline's full extent so it holds the final computed frame instead. |
| 2394 | // Adapters still receive the raw `t` (their media may run longer). |
| 2395 | // totalDuration() includes repeats; Infinity (infinite repeat) → no clamp. |
| 2396 | const tlWithTotal = tl as RuntimeTimelineLike & { totalDuration?: () => number }; |
| 2397 | let tlSeekTime = t; |
| 2398 | if (typeof tlWithTotal.totalDuration === "function") { |
| 2399 | try { |
| 2400 | const total = Number(tlWithTotal.totalDuration()); |
| 2401 | if (Number.isFinite(total) && total > 0 && t > total) { |
| 2402 | tlSeekTime = total; |
| 2403 | } |
| 2404 | } catch (err) { |
| 2405 | swallow("runtime.init.transport.clampDuration", err); |
| 2406 | } |
| 2407 | } |
| 2408 | try { |
| 2409 | if (typeof tl.totalTime === "function") { |
| 2410 | tl.totalTime(tlSeekTime, false); |
| 2411 | } else { |
| 2412 | tl.seek(tlSeekTime, false); |
| 2413 | } |
| 2414 | } catch (err) { |
| 2415 | swallow("runtime.init.transport.seek", err); |
| 2416 | } |
| 2417 | // Sibling timelines (registered in __timelines but not nested under |
| 2418 | // the root) are paused alongside the master. We do NOT seek them to |
| 2419 | // absolute position `t` here — child timelines nested under the root |
| 2420 | // are already propagated via tl.totalTime(), and seeking them again |
| 2421 | // at absolute `t` would clobber their offset-relative position. |
| 2422 | // Play/pause propagation for siblings happens in the player.play() |
| 2423 | // and player.pause() overrides via the adapter layer. |
| 2424 | } else { |
| 2425 | seekStandaloneRegisteredTimelines(t); |
| 2426 | } |
| 2427 | for (const adapter of state.deterministicAdapters) { |
| 2428 | try { |
| 2429 | adapter.seek({ time: t }); |
| 2430 | } catch (err) { |
| 2431 | swallow("runtime.init.transport.adapter", err); |
| 2432 | } |
no test coverage detected