mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-03 12:17:03 +00:00
* fix(inspector): live queries see every composition, wherever the playhead is The Studio preview parks scenes away from the playhead, so a live inspect, timeline or element-map query answered missing for every element in a parked composition. Each live query now holds every scene mounted under its own holder, then hands the scene window back. __hfHoldScenes keeps holds per holder, so the inspector letting go never drops a scene Studio holds. * fix(inspector): isolate concurrent live query scene holds
107 lines
3.7 KiB
TypeScript
107 lines
3.7 KiB
TypeScript
import type {
|
|
TimelineEvent,
|
|
TimelineRequest,
|
|
TimelineRuntimeResult,
|
|
} from "../../core/src/runtime/timelineInspection";
|
|
import type { RuntimeQuery, RuntimeResponse } from "./types";
|
|
|
|
export interface PageRunner {
|
|
run<A, R>(fn: (arg: A) => R, arg: A): Promise<R>;
|
|
}
|
|
|
|
export interface PageTimeline extends TimelineRuntimeResult {
|
|
following: TimelineEvent[];
|
|
generation: string | null;
|
|
duration?: number;
|
|
}
|
|
|
|
export interface PageRuntimeResponse extends RuntimeResponse {
|
|
generation: string | null;
|
|
}
|
|
|
|
type InspectedWindow = Window & {
|
|
__hfInspection?: {
|
|
query(query: RuntimeQuery): RuntimeResponse;
|
|
timeline(request: TimelineRequest): TimelineRuntimeResult;
|
|
};
|
|
__hfLiveInspection?: { generation: string; project: string };
|
|
__hfHoldScenes?: (names: string[], holder?: string) => Promise<void>;
|
|
__player?: {
|
|
renderSeek(time: number, options: { exact: boolean }): void;
|
|
getTime(): number;
|
|
getDuration(): number;
|
|
};
|
|
};
|
|
|
|
export interface PlayerState {
|
|
time: number | undefined;
|
|
duration: number | undefined;
|
|
}
|
|
|
|
export function seekPage(time: number): void {
|
|
const player = (window as InspectedWindow).__player;
|
|
if (!player) throw new Error("player_unavailable");
|
|
player.renderSeek(time, { exact: true });
|
|
}
|
|
|
|
export function playerStatePage(): PlayerState {
|
|
const player = (window as InspectedWindow).__player;
|
|
return { time: player?.getTime(), duration: player?.getDuration() };
|
|
}
|
|
|
|
export function queryPage(query: RuntimeQuery): PageRuntimeResponse {
|
|
const inspected = window as InspectedWindow;
|
|
const inspection = inspected.__hfInspection;
|
|
if (!inspection) throw new Error("inspector_unavailable");
|
|
return {
|
|
generation: inspected.__hfLiveInspection?.generation ?? null,
|
|
...inspection.query(query),
|
|
};
|
|
}
|
|
|
|
export function timelinePage(request: TimelineRequest): PageTimeline {
|
|
const inspected = window as InspectedWindow;
|
|
const inspection = inspected.__hfInspection;
|
|
if (!inspection) throw new Error("inspector_unavailable");
|
|
const result = inspection.timeline(request);
|
|
const following: TimelineEvent[] = [];
|
|
const generation = inspected.__hfLiveInspection?.generation ?? null;
|
|
const duration = inspected.__player?.getDuration();
|
|
if (request.boundary === undefined) return { ...result, following, generation, duration };
|
|
const boundary = request.boundary;
|
|
const schedule = inspection.timeline({ ...request, boundary: undefined });
|
|
for (const crossing of result.events) {
|
|
if (crossing.kind !== "animation" || crossing.relation !== "crosses") continue;
|
|
for (const target of crossing.targets) {
|
|
const next = schedule.events
|
|
.filter(
|
|
(event) =>
|
|
event.kind === "animation" &&
|
|
event.start > boundary &&
|
|
event.targets.some((t) => t.ref === target.ref) &&
|
|
event.properties.some((p) => crossing.properties.includes(p)),
|
|
)
|
|
.sort((a, b) => a.start - b.start)[0];
|
|
if (next && !following.includes(next)) following.push(next);
|
|
}
|
|
}
|
|
return { ...result, following, generation, duration };
|
|
}
|
|
|
|
export function liveGenerationPage(): string | null {
|
|
return (window as InspectedWindow).__hfLiveInspection?.generation ?? null;
|
|
}
|
|
|
|
export async function holdEveryScenePage(holder: string): Promise<string[]> {
|
|
const hold = (window as InspectedWindow).__hfHoldScenes;
|
|
if (!hold) return [];
|
|
const sceneOf = (el: Element) => el.getAttribute("data-hf-scene") ?? "";
|
|
const names = new Set(Array.from(document.querySelectorAll("[data-hf-scene]"), sceneOf));
|
|
await hold([...names], holder);
|
|
return Array.from(document.querySelectorAll("[data-hf-parked-scene]"), sceneOf);
|
|
}
|
|
|
|
export async function releaseEveryScenePage(holder: string): Promise<void> {
|
|
await (window as InspectedWindow).__hfHoldScenes?.([], holder);
|
|
}
|