MCPcopy Create free account
hub / github.com/heygen-com/hyperframes / resolveRootTimelineFromDocument

Function resolveRootTimelineFromDocument

packages/core/src/runtime/init.ts:738–1128  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

736 };
737
738 const resolveRootTimelineFromDocument = (): TimelineResolution => {
739 const timelines = (window.__timelines ?? {}) as Record<string, RuntimeTimelineLike | undefined>;
740 // DX fallback (#6): when the root timeline cannot be resolved by id but
741 // EXACTLY ONE usable timeline is registered, bind it rather than silently
742 // rendering the frozen t=0 DOM. Safe because with a single registered
743 // timeline there is no ambiguity about which one is the composition's
744 // root. Multiple registered → ambiguous, so we still return null and let
745 // the loud warning fire.
746 const resolveSoleTimelineFallback = (reason: string): TimelineResolution => {
747 const usable = Object.entries(timelines).filter(
748 (entry): entry is [string, RuntimeTimelineLike] =>
749 !!entry[1] && typeof entry[1].play === "function" && typeof entry[1].pause === "function",
750 );
751 if (usable.length !== 1) return { timeline: null };
752 const [soleId, soleTimeline] = usable[0];
753 return {
754 timeline: soleTimeline,
755 selectedTimelineIds: [soleId],
756 selectedDurationSeconds: getTimelineDurationSeconds(soleTimeline),
757 diagnostics: {
758 code: "root_timeline_sole_registered_fallback",
759 details: { reason, soleTimelineId: soleId },
760 },
761 };
762 };
763 const startResolver = createRuntimeStartTimeResolver({
764 timelineRegistry: timelines,
765 includeAuthoredTimingAttrs: true,
766 });
767 const mediaDurationFloorSeconds = resolveMediaDurationFloorSeconds();
768 const authoredCompositionDurationFloorSeconds =
769 resolveAuthoredCompositionDurationFloorSeconds();
770 const durationFloorSeconds =
771 Math.max(mediaDurationFloorSeconds ?? 0, authoredCompositionDurationFloorSeconds ?? 0) ||
772 null;
773 const minCandidateDurationSeconds = resolveMinCandidateDurationSeconds(durationFloorSeconds);
774 const resolveCompositionStartSeconds = (compositionId: string): number => {
775 const node = document.querySelector(
776 `[data-composition-id="${CSS.escape(compositionId)}"]`,
777 ) as Element | null;
778 if (!node) return 0;
779 return startResolver.resolveStartForElement(node, 0);
780 };
781 const createCompositeTimelineFromCandidates = (
782 candidates: Array<{
783 compositionId: string;
784 timeline: RuntimeTimelineLike;
785 durationSeconds: number;
786 }>,
787 ): RuntimeTimelineLike | null => {
788 const gsapApi = window.gsap;
789 if (!gsapApi || typeof gsapApi.timeline !== "function") return null;
790 const compositeTimeline = gsapApi.timeline({ paused: true }) as RuntimeTimelineLike;
791 for (const candidate of candidates) {
792 compositeTimeline.add(
793 candidate.timeline,
794 resolveCompositionStartSeconds(candidate.compositionId),
795 );

Callers 2

Tested by

no test coverage detected