mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-03 20:37:30 +00:00
fix(core): scenes stop resetting during playback when the root has no animation of its own (#5693)
This commit is contained in:
@@ -199,6 +199,29 @@ describe("runtime sub-composition placement", () => {
|
||||
expect(window.__player?.getDuration()).toBe(9);
|
||||
});
|
||||
|
||||
it("keeps the scene in one root after a tween first renders, when the root's own timeline is empty", async () => {
|
||||
const runFrames = stubFrames();
|
||||
document.body.innerHTML =
|
||||
`<div data-composition-id="main" data-root="true" data-duration="10">` +
|
||||
`<div id="host" class="clip" data-composition-id="scene" data-start="1" data-duration="9">` +
|
||||
`<div id="s"></div></div></div>`;
|
||||
const scene = gsap
|
||||
.timeline({ paused: true })
|
||||
.fromTo("#s", { x: -100 }, { x: 0, duration: 0.5, ease: "none" }, 0.5)
|
||||
.to({}, { duration: 9 }, 0);
|
||||
const root = gsap.timeline({ paused: true });
|
||||
window.__timelines = { main: root, scene } as unknown as Record<string, RuntimeTimelineLike>;
|
||||
initSandboxRuntimeModular();
|
||||
window.__player?.seek(1.2);
|
||||
const bound = scene.parent;
|
||||
|
||||
window.__player?.seek(3);
|
||||
await runFrames(6);
|
||||
|
||||
expect(scene.parent).toBe(bound);
|
||||
expect(shownX()).toBe(0);
|
||||
});
|
||||
|
||||
it("binds a root timeline that registers after the runtime started on its children", async () => {
|
||||
const runFrames = stubFrames();
|
||||
loadWithoutRootTimeline(`<div id="r"></div>`);
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
import { swallow } from "./diagnostics";
|
||||
import type { RuntimeTimelineLike } from "./types";
|
||||
|
||||
/** A registered timeline's finite duration(); a partial, throwing or non-numeric entry reads as null. */
|
||||
type ChildTimeline = {
|
||||
paused?: () => boolean;
|
||||
startTime?: () => number;
|
||||
totalDuration?: () => number;
|
||||
timeScale?: () => number;
|
||||
};
|
||||
|
||||
const pausedChildEnd = (child: ChildTimeline): number =>
|
||||
child.paused?.() === true
|
||||
? (child.startTime?.() ?? 0) +
|
||||
(child.totalDuration?.() ?? 0) / Math.abs(child.timeScale?.() || 1)
|
||||
: 0;
|
||||
|
||||
/** A timeline's finite length, counting paused child timelines; a partial or throwing entry reads as null. */
|
||||
export function readTimelineDurationSeconds(
|
||||
timeline: Pick<RuntimeTimelineLike, "duration"> | null | undefined,
|
||||
timeline: Pick<RuntimeTimelineLike, "duration" | "getChildren"> | null | undefined,
|
||||
): number | null {
|
||||
try {
|
||||
if (typeof timeline?.duration !== "function") return null;
|
||||
const seconds = Number(timeline.duration());
|
||||
const held: unknown = timeline.getChildren?.(false, false, true);
|
||||
const children = Array.isArray(held) ? (held as ChildTimeline[]) : [];
|
||||
const seconds = Math.max(Number(timeline.duration()), ...children.map(pausedChildEnd));
|
||||
return Number.isFinite(seconds) ? seconds : null;
|
||||
} catch (err) {
|
||||
swallow("runtime.timelineDuration", err);
|
||||
|
||||
Reference in New Issue
Block a user