mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 14:50:02 +00:00
Merge pull request #918 from heygen-com/refactor/unify-subcomp-inlining
fix: hold external sub-compositions in render mode + regenerate baseline
This commit is contained in:
@@ -7,15 +7,12 @@ import {
|
|||||||
parseHTMLContent,
|
parseHTMLContent,
|
||||||
stripEmbeddedRuntimeScripts,
|
stripEmbeddedRuntimeScripts,
|
||||||
} from "./htmlDocument";
|
} from "./htmlDocument";
|
||||||
import {
|
// rewriteSubCompPaths functions are used by inlineSubCompositions (shared module)
|
||||||
rewriteAssetPaths,
|
|
||||||
rewriteCssAssetUrls,
|
|
||||||
rewriteInlineStyleAssetUrls,
|
|
||||||
} from "./rewriteSubCompPaths";
|
|
||||||
import { scopeCssToComposition, wrapScopedCompositionScript } from "./compositionScoping";
|
import { scopeCssToComposition, wrapScopedCompositionScript } from "./compositionScoping";
|
||||||
import { validateHyperframeHtmlContract } from "./staticGuard";
|
import { validateHyperframeHtmlContract } from "./staticGuard";
|
||||||
import { getHyperframeRuntimeScript } from "../generated/runtime-inline";
|
import { getHyperframeRuntimeScript } from "../generated/runtime-inline";
|
||||||
import { readDeclaredDefaults } from "../runtime/getVariables";
|
import { readDeclaredDefaults } from "../runtime/getVariables";
|
||||||
|
import { inlineSubCompositions } from "./inlineSubCompositions";
|
||||||
|
|
||||||
/** Resolve a relative path within projectDir, rejecting traversal outside it. */
|
/** Resolve a relative path within projectDir, rejecting traversal outside it. */
|
||||||
function safePath(projectDir: string, relativePath: string): string | null {
|
function safePath(projectDir: string, relativePath: string): string | null {
|
||||||
@@ -581,144 +578,36 @@ export async function bundleToSingleHtml(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline sub-compositions
|
// Inline sub-compositions (via shared function)
|
||||||
const compStyleChunks: string[] = [];
|
|
||||||
const compScriptChunks: string[] = [];
|
|
||||||
const compExternalScriptSrcs: string[] = [];
|
|
||||||
const compVariablesByComp: Record<string, Record<string, unknown>> = {};
|
|
||||||
const trackedCompositionHosts = getBundledTrackedCompositionHosts(document);
|
const trackedCompositionHosts = getBundledTrackedCompositionHosts(document);
|
||||||
const hostIdentityByElement = assignBundledRuntimeCompositionIds(trackedCompositionHosts);
|
const hostIdentityByElement = assignBundledRuntimeCompositionIds(trackedCompositionHosts);
|
||||||
const subCompositionHosts = trackedCompositionHosts.filter((host) =>
|
const subCompositionHosts = trackedCompositionHosts.filter((host) =>
|
||||||
host.hasAttribute("data-composition-src"),
|
host.hasAttribute("data-composition-src"),
|
||||||
);
|
);
|
||||||
for (const hostEl of subCompositionHosts) {
|
const subCompResult = inlineSubCompositions(document, subCompositionHosts, {
|
||||||
const src = hostEl.getAttribute("data-composition-src");
|
resolveHtml: (srcPath: string) => {
|
||||||
if (!src || !isRelativeUrl(src)) continue;
|
if (!isRelativeUrl(srcPath)) return null;
|
||||||
const compPath = safePath(projectDir, src);
|
const compPath = safePath(projectDir, srcPath);
|
||||||
const compHtml = compPath ? safeReadFile(compPath) : null;
|
return compPath ? safeReadFile(compPath) : null;
|
||||||
if (compHtml == null) {
|
},
|
||||||
console.warn(`[Bundler] Composition file not found: ${src}`);
|
parseHtml: parseHTMLContent,
|
||||||
continue;
|
hostIdentityMap: hostIdentityByElement,
|
||||||
}
|
rewriteInlineStyles: true,
|
||||||
|
flattenInnerRoot: prepareFlattenedInnerRoot,
|
||||||
const compDoc = parseHTMLContent(compHtml);
|
readVariableDefaults: readDeclaredDefaults,
|
||||||
const hostIdentity = hostIdentityByElement.get(hostEl);
|
parseHostVariables: parseHostVariableValues,
|
||||||
const compId = hostIdentity?.authoredCompositionId || null;
|
buildScopeSelector: (compId: string) => cssAttributeSelector("data-composition-id", compId),
|
||||||
const runtimeCompId = hostIdentity?.runtimeCompositionId || compId || "";
|
scriptErrorLabel: "[HyperFrames] composition script error:",
|
||||||
const contentRoot = compDoc.querySelector("template");
|
onMissingComposition: (srcPath: string) => {
|
||||||
const contentHtml = contentRoot ? contentRoot.innerHTML || "" : compDoc.body.innerHTML || "";
|
console.warn(`[Bundler] Composition file not found: ${srcPath}`);
|
||||||
const contentDoc = parseHTMLContent(contentHtml);
|
},
|
||||||
const innerRoot = compId
|
});
|
||||||
? contentDoc.querySelector(`[data-composition-id="${compId}"]`)
|
const compStyleChunks: string[] = [...subCompResult.styles];
|
||||||
: contentDoc.querySelector("[data-composition-id]");
|
const compScriptChunks: string[] = [...subCompResult.scripts];
|
||||||
const inferredCompId = innerRoot?.getAttribute("data-composition-id")?.trim() || "";
|
const compExternalScriptSrcs: string[] = [...subCompResult.externalScriptSrcs];
|
||||||
const authoredRootId = innerRoot?.getAttribute("id")?.trim() || null;
|
const compVariablesByComp: Record<string, Record<string, unknown>> = {
|
||||||
const scopeCompId = compId || inferredCompId;
|
...subCompResult.variablesByComp,
|
||||||
const runtimeScope = runtimeCompId
|
};
|
||||||
? cssAttributeSelector("data-composition-id", runtimeCompId)
|
|
||||||
: "";
|
|
||||||
const mergedVariables = runtimeCompId
|
|
||||||
? {
|
|
||||||
...readDeclaredDefaults(compDoc.documentElement),
|
|
||||||
...parseHostVariableValues(hostEl),
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
if (runtimeCompId && Object.keys(mergedVariables).length > 0) {
|
|
||||||
compVariablesByComp[runtimeCompId] = mergedVariables;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When a sub-composition is a full HTML document (no <template>), styles
|
|
||||||
// and scripts in <head> are not part of contentDoc (which only has body
|
|
||||||
// content). Extract them so backgrounds, positioning, fonts, and library
|
|
||||||
// scripts (e.g. GSAP CDN) are not silently dropped.
|
|
||||||
if (!contentRoot && compDoc.head) {
|
|
||||||
for (const s of [...compDoc.head.querySelectorAll("style")]) {
|
|
||||||
const css = rewriteCssAssetUrls(s.textContent || "", src);
|
|
||||||
compStyleChunks.push(
|
|
||||||
scopeCompId ? scopeCssToComposition(css, scopeCompId, runtimeScope, authoredRootId) : css,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
for (const s of [...compDoc.head.querySelectorAll("script")]) {
|
|
||||||
const externalSrc = (s.getAttribute("src") || "").trim();
|
|
||||||
if (externalSrc && !compExternalScriptSrcs.includes(externalSrc)) {
|
|
||||||
compExternalScriptSrcs.push(externalSrc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const s of [...contentDoc.querySelectorAll("style")]) {
|
|
||||||
const css = rewriteCssAssetUrls(s.textContent || "", src);
|
|
||||||
compStyleChunks.push(
|
|
||||||
scopeCompId ? scopeCssToComposition(css, scopeCompId, runtimeScope, authoredRootId) : css,
|
|
||||||
);
|
|
||||||
s.remove();
|
|
||||||
}
|
|
||||||
for (const s of [...contentDoc.querySelectorAll("script")]) {
|
|
||||||
const externalSrc = (s.getAttribute("src") || "").trim();
|
|
||||||
if (externalSrc) {
|
|
||||||
// External CDN/remote script — collect for deduped injection into the document.
|
|
||||||
// Do NOT try to inline the content (external scripts have no innerHTML).
|
|
||||||
if (!compExternalScriptSrcs.includes(externalSrc)) {
|
|
||||||
compExternalScriptSrcs.push(externalSrc);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
compScriptChunks.push(
|
|
||||||
scopeCompId
|
|
||||||
? wrapScopedCompositionScript(
|
|
||||||
s.textContent || "",
|
|
||||||
scopeCompId,
|
|
||||||
"[HyperFrames] composition script error:",
|
|
||||||
runtimeScope,
|
|
||||||
runtimeCompId || scopeCompId,
|
|
||||||
authoredRootId,
|
|
||||||
)
|
|
||||||
: `(function(){ try { ${s.textContent || ""} } catch (_err) { console.error('[HyperFrames] composition script error:', _err); } })();`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
s.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rewrite relative asset paths before inlining so ../foo.svg from
|
|
||||||
// compositions/ resolves correctly when the content moves to root.
|
|
||||||
const assetEls = innerRoot
|
|
||||||
? innerRoot.querySelectorAll("[src], [href]")
|
|
||||||
: contentDoc.querySelectorAll("[src], [href]");
|
|
||||||
rewriteAssetPaths(
|
|
||||||
assetEls,
|
|
||||||
src,
|
|
||||||
(el: Element, attr: string) => el.getAttribute(attr),
|
|
||||||
(el: Element, attr: string, val: string) => {
|
|
||||||
el.setAttribute(attr, val);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const styledEls = innerRoot
|
|
||||||
? innerRoot.querySelectorAll("[style]")
|
|
||||||
: contentDoc.querySelectorAll("[style]");
|
|
||||||
rewriteInlineStyleAssetUrls(
|
|
||||||
styledEls,
|
|
||||||
src,
|
|
||||||
(el: Element) => el.getAttribute("style"),
|
|
||||||
(el: Element, val: string) => {
|
|
||||||
el.setAttribute("style", val);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (innerRoot) {
|
|
||||||
const innerW = innerRoot.getAttribute("data-width");
|
|
||||||
const innerH = innerRoot.getAttribute("data-height");
|
|
||||||
if (innerW && !hostEl.getAttribute("data-width")) hostEl.setAttribute("data-width", innerW);
|
|
||||||
if (innerH && !hostEl.getAttribute("data-height")) hostEl.setAttribute("data-height", innerH);
|
|
||||||
innerRoot.setAttribute("data-composition-file", src);
|
|
||||||
for (const child of [...innerRoot.querySelectorAll("style, script")]) child.remove();
|
|
||||||
const preparedInnerRoot = prepareFlattenedInnerRoot(innerRoot);
|
|
||||||
hostEl.innerHTML = preparedInnerRoot.outerHTML || "";
|
|
||||||
} else {
|
|
||||||
for (const child of [...contentDoc.querySelectorAll("style, script")]) child.remove();
|
|
||||||
hostEl.innerHTML = contentDoc.body.innerHTML || "";
|
|
||||||
}
|
|
||||||
hostEl.setAttribute("data-composition-file", src);
|
|
||||||
hostEl.removeAttribute("data-composition-src");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inline template compositions: inject <template id="X-template"> content into
|
// Inline template compositions: inject <template id="X-template"> content into
|
||||||
// matching empty host elements with data-composition-id="X" (no data-composition-src)
|
// matching empty host elements with data-composition-id="X" (no data-composition-src)
|
||||||
|
|||||||
@@ -34,3 +34,10 @@ export {
|
|||||||
|
|
||||||
// Composition isolation helpers
|
// Composition isolation helpers
|
||||||
export { scopeCssToComposition, wrapScopedCompositionScript } from "./compositionScoping";
|
export { scopeCssToComposition, wrapScopedCompositionScript } from "./compositionScoping";
|
||||||
|
|
||||||
|
// Sub-composition inlining (shared between bundler and producer)
|
||||||
|
export {
|
||||||
|
inlineSubCompositions,
|
||||||
|
type InlineSubCompositionsOptions,
|
||||||
|
type InlineSubCompositionsResult,
|
||||||
|
} from "./inlineSubCompositions";
|
||||||
|
|||||||
@@ -0,0 +1,323 @@
|
|||||||
|
/**
|
||||||
|
* Shared sub-composition inlining logic.
|
||||||
|
*
|
||||||
|
* Both the core bundler (preview) and the producer compiler (render) need to
|
||||||
|
* inline sub-composition HTML referenced via `data-composition-src`. This
|
||||||
|
* module is the single source of truth for that transformation, eliminating
|
||||||
|
* divergence that previously caused bugs (e.g. producer not setting
|
||||||
|
* `data-composition-file`).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
rewriteAssetPaths,
|
||||||
|
rewriteCssAssetUrls,
|
||||||
|
rewriteInlineStyleAssetUrls,
|
||||||
|
} from "./rewriteSubCompPaths";
|
||||||
|
import { scopeCssToComposition, wrapScopedCompositionScript } from "./compositionScoping";
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public interface
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export interface InlineSubCompositionsOptions {
|
||||||
|
/**
|
||||||
|
* Resolve the HTML content for a sub-composition given its `data-composition-src` value.
|
||||||
|
* Return `null` when the file cannot be found.
|
||||||
|
*/
|
||||||
|
resolveHtml: (srcPath: string) => string | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an HTML string into a Document. The returned object must expose
|
||||||
|
* standard DOM APIs (querySelector, querySelectorAll, body, head, etc.).
|
||||||
|
* Both linkedom's `parseHTML(...).document` and the core bundler's
|
||||||
|
* `parseHTMLContent(...)` satisfy this contract.
|
||||||
|
*/
|
||||||
|
parseHtml: (html: string) => Document;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identity map produced by `assignBundledRuntimeCompositionIds`.
|
||||||
|
* When provided, authoredCompositionId and runtimeCompositionId are read
|
||||||
|
* from this map instead of from the host element's attributes directly.
|
||||||
|
* The bundler uses this; the producer can omit it.
|
||||||
|
*/
|
||||||
|
hostIdentityMap?: Map<
|
||||||
|
Element,
|
||||||
|
{ authoredCompositionId: string | null; runtimeCompositionId: string | null }
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When true, rewrite `url(...)` references in inline `style` attributes
|
||||||
|
* on sub-composition elements. The bundler enables this; the producer
|
||||||
|
* can skip it.
|
||||||
|
*/
|
||||||
|
rewriteInlineStyles?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the inner root element before injecting it into the host.
|
||||||
|
* The bundler's `prepareFlattenedInnerRoot` clones the element, strips
|
||||||
|
* timing attributes, and adds `data-hf-inner-root`. When omitted, the
|
||||||
|
* inner root's outerHTML is injected as-is.
|
||||||
|
*/
|
||||||
|
flattenInnerRoot?: (innerRoot: Element) => Element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read declared variable defaults from a sub-composition's `<html>` element.
|
||||||
|
* The bundler passes `readDeclaredDefaults`; the producer can omit this.
|
||||||
|
*/
|
||||||
|
readVariableDefaults?: (docElement: Element) => Record<string, unknown>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse host-level variable overrides from `data-variable-values`.
|
||||||
|
* The bundler passes `parseHostVariableValues`; the producer can omit this.
|
||||||
|
*/
|
||||||
|
parseHostVariables?: (host: Element) => Record<string, unknown>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a CSS attribute selector for scoping, e.g.
|
||||||
|
* `[data-composition-id="my-comp"]`. Defaults to a simple implementation
|
||||||
|
* when not provided. The bundler passes `cssAttributeSelector` which
|
||||||
|
* handles escaping.
|
||||||
|
*/
|
||||||
|
buildScopeSelector?: (compId: string) => string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error label prefix used in wrapped composition scripts.
|
||||||
|
* Defaults to `"[HyperFrames] composition script error:"`.
|
||||||
|
*/
|
||||||
|
scriptErrorLabel?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a warning when a composition file cannot be resolved.
|
||||||
|
* Defaults to `console.warn`.
|
||||||
|
*/
|
||||||
|
onMissingComposition?: (srcPath: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InlineSubCompositionsResult {
|
||||||
|
styles: string[];
|
||||||
|
scripts: string[];
|
||||||
|
externalScriptSrcs: string[];
|
||||||
|
variablesByComp: Record<string, Record<string, unknown>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Default helpers
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function defaultBuildScopeSelector(compId: string): string {
|
||||||
|
const escaped = compId.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
||||||
|
return `[data-composition-id="${escaped}"]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Core implementation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inline sub-compositions into a document. For each host element in `hosts`:
|
||||||
|
*
|
||||||
|
* 1. Resolve the sub-composition HTML via `options.resolveHtml`
|
||||||
|
* 2. Parse it, find `<template>` or `<body>` content
|
||||||
|
* 3. Find the inner `[data-composition-id]` root
|
||||||
|
* 4. Extract `<style>` elements, scope CSS, collect them
|
||||||
|
* 5. Extract `<script>` elements, wrap inline scripts, collect them
|
||||||
|
* 6. Collect external script `src` URLs for deduplication
|
||||||
|
* 7. Rewrite asset paths (and optionally inline-style asset URLs)
|
||||||
|
* 8. Copy dimension attrs from inner root to host if missing
|
||||||
|
* 9. Set `data-composition-file` on host
|
||||||
|
* 10. Remove `data-composition-src` from host
|
||||||
|
* 11. Inject the content into the host element
|
||||||
|
*/
|
||||||
|
export function inlineSubCompositions(
|
||||||
|
document: Document,
|
||||||
|
hosts: Element[],
|
||||||
|
options: InlineSubCompositionsOptions,
|
||||||
|
): InlineSubCompositionsResult {
|
||||||
|
const {
|
||||||
|
resolveHtml,
|
||||||
|
parseHtml,
|
||||||
|
hostIdentityMap,
|
||||||
|
rewriteInlineStyles = false,
|
||||||
|
flattenInnerRoot,
|
||||||
|
readVariableDefaults,
|
||||||
|
parseHostVariables,
|
||||||
|
buildScopeSelector = defaultBuildScopeSelector,
|
||||||
|
scriptErrorLabel = "[HyperFrames] composition script error:",
|
||||||
|
onMissingComposition,
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const styles: string[] = [];
|
||||||
|
const scripts: string[] = [];
|
||||||
|
const externalScriptSrcs: string[] = [];
|
||||||
|
const variablesByComp: Record<string, Record<string, unknown>> = {};
|
||||||
|
|
||||||
|
for (const hostEl of hosts) {
|
||||||
|
const src = hostEl.getAttribute("data-composition-src");
|
||||||
|
if (!src) continue;
|
||||||
|
|
||||||
|
const compHtml = resolveHtml(src);
|
||||||
|
if (compHtml == null) {
|
||||||
|
if (onMissingComposition) {
|
||||||
|
onMissingComposition(src);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const compDoc = parseHtml(compHtml);
|
||||||
|
|
||||||
|
// Determine composition IDs
|
||||||
|
let compId: string | null;
|
||||||
|
let runtimeCompId: string;
|
||||||
|
if (hostIdentityMap) {
|
||||||
|
const identity = hostIdentityMap.get(hostEl);
|
||||||
|
compId = identity?.authoredCompositionId || null;
|
||||||
|
runtimeCompId = identity?.runtimeCompositionId || compId || "";
|
||||||
|
} else {
|
||||||
|
compId = hostEl.getAttribute("data-composition-id") || null;
|
||||||
|
runtimeCompId = compId || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find content: prefer <template>, fall back to <body>
|
||||||
|
const contentRoot = compDoc.querySelector("template");
|
||||||
|
const contentHtml = contentRoot ? contentRoot.innerHTML || "" : compDoc.body?.innerHTML || "";
|
||||||
|
const contentDoc = parseHtml(contentHtml);
|
||||||
|
|
||||||
|
// Find the inner composition root
|
||||||
|
const innerRoot = compId
|
||||||
|
? contentDoc.querySelector(`[data-composition-id="${compId}"]`)
|
||||||
|
: contentDoc.querySelector("[data-composition-id]");
|
||||||
|
const inferredCompId = innerRoot?.getAttribute("data-composition-id")?.trim() || "";
|
||||||
|
const authoredRootId = innerRoot?.getAttribute("id")?.trim() || null;
|
||||||
|
const scopeCompId = compId || inferredCompId;
|
||||||
|
const runtimeScope = runtimeCompId ? buildScopeSelector(runtimeCompId) : "";
|
||||||
|
|
||||||
|
// Variable merging (bundler feature)
|
||||||
|
if (readVariableDefaults && parseHostVariables && runtimeCompId) {
|
||||||
|
const mergedVariables = {
|
||||||
|
...readVariableDefaults(compDoc.documentElement),
|
||||||
|
...parseHostVariables(hostEl),
|
||||||
|
};
|
||||||
|
if (Object.keys(mergedVariables).length > 0) {
|
||||||
|
variablesByComp[runtimeCompId] = mergedVariables;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When a sub-composition is a full HTML document (no <template>), styles
|
||||||
|
// and scripts in <head> are not part of contentDoc (which only has body
|
||||||
|
// content). Extract them so backgrounds, positioning, fonts, and library
|
||||||
|
// scripts (e.g. GSAP CDN) are not silently dropped.
|
||||||
|
if (!contentRoot && compDoc.head) {
|
||||||
|
for (const s of [...compDoc.head.querySelectorAll("style")]) {
|
||||||
|
const css = rewriteCssAssetUrls(s.textContent || "", src);
|
||||||
|
styles.push(
|
||||||
|
scopeCompId
|
||||||
|
? scopeCssToComposition(css, scopeCompId, runtimeScope || undefined, authoredRootId)
|
||||||
|
: css,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (const s of [...compDoc.head.querySelectorAll("script")]) {
|
||||||
|
const externalSrc = (s.getAttribute("src") || "").trim();
|
||||||
|
if (externalSrc && !externalScriptSrcs.includes(externalSrc)) {
|
||||||
|
externalScriptSrcs.push(externalSrc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract styles from content
|
||||||
|
for (const s of [...contentDoc.querySelectorAll("style")]) {
|
||||||
|
const css = rewriteCssAssetUrls(s.textContent || "", src);
|
||||||
|
styles.push(
|
||||||
|
scopeCompId
|
||||||
|
? scopeCssToComposition(css, scopeCompId, runtimeScope || undefined, authoredRootId)
|
||||||
|
: css,
|
||||||
|
);
|
||||||
|
s.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract scripts from content
|
||||||
|
for (const s of [...contentDoc.querySelectorAll("script")]) {
|
||||||
|
const externalSrc = (s.getAttribute("src") || "").trim();
|
||||||
|
if (externalSrc) {
|
||||||
|
if (!externalScriptSrcs.includes(externalSrc)) {
|
||||||
|
externalScriptSrcs.push(externalSrc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scripts.push(
|
||||||
|
scopeCompId
|
||||||
|
? wrapScopedCompositionScript(
|
||||||
|
s.textContent || "",
|
||||||
|
scopeCompId,
|
||||||
|
scriptErrorLabel,
|
||||||
|
runtimeScope || undefined,
|
||||||
|
runtimeCompId || scopeCompId,
|
||||||
|
authoredRootId,
|
||||||
|
)
|
||||||
|
: `(function(){ try { ${s.textContent || ""} } catch (_err) { console.error(${JSON.stringify(scriptErrorLabel)}, _err); } })();`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
s.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewrite relative asset paths before inlining so ../foo.svg from
|
||||||
|
// compositions/ resolves correctly when the content moves to root.
|
||||||
|
const assetEls = innerRoot
|
||||||
|
? innerRoot.querySelectorAll("[src], [href]")
|
||||||
|
: contentDoc.querySelectorAll("[src], [href]");
|
||||||
|
rewriteAssetPaths(
|
||||||
|
assetEls,
|
||||||
|
src,
|
||||||
|
(el: Element, attr: string) => el.getAttribute(attr),
|
||||||
|
(el: Element, attr: string, val: string) => {
|
||||||
|
el.setAttribute(attr, val);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rewriteInlineStyles) {
|
||||||
|
const styledEls = innerRoot
|
||||||
|
? innerRoot.querySelectorAll("[style]")
|
||||||
|
: contentDoc.querySelectorAll("[style]");
|
||||||
|
rewriteInlineStyleAssetUrls(
|
||||||
|
styledEls,
|
||||||
|
src,
|
||||||
|
(el: Element) => el.getAttribute("style"),
|
||||||
|
(el: Element, val: string) => {
|
||||||
|
el.setAttribute("style", val);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy dimension attributes from inner root to host if missing
|
||||||
|
if (innerRoot) {
|
||||||
|
const innerW = innerRoot.getAttribute("data-width");
|
||||||
|
const innerH = innerRoot.getAttribute("data-height");
|
||||||
|
if (innerW && !hostEl.getAttribute("data-width")) hostEl.setAttribute("data-width", innerW);
|
||||||
|
if (innerH && !hostEl.getAttribute("data-height")) {
|
||||||
|
hostEl.setAttribute("data-height", innerH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject content into the host element
|
||||||
|
if (innerRoot) {
|
||||||
|
innerRoot.setAttribute("data-composition-file", src);
|
||||||
|
for (const child of [...innerRoot.querySelectorAll("style, script")]) child.remove();
|
||||||
|
if (flattenInnerRoot) {
|
||||||
|
const prepared = flattenInnerRoot(innerRoot);
|
||||||
|
hostEl.innerHTML = prepared.outerHTML || "";
|
||||||
|
} else {
|
||||||
|
hostEl.innerHTML = compId ? innerRoot.innerHTML || "" : innerRoot.outerHTML || "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const child of [...contentDoc.querySelectorAll("style, script")]) child.remove();
|
||||||
|
// linkedom fragment parsing: when content is `<div data-composition-id="X">...</div>`,
|
||||||
|
// the div becomes documentElement and body is empty. Fall back to documentElement.outerHTML
|
||||||
|
// to preserve the composition wrapper.
|
||||||
|
const bodyHtml = contentDoc.body?.innerHTML || "";
|
||||||
|
hostEl.innerHTML = bodyHtml || contentDoc.documentElement?.outerHTML || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
hostEl.setAttribute("data-composition-file", src);
|
||||||
|
hostEl.removeAttribute("data-composition-src");
|
||||||
|
}
|
||||||
|
|
||||||
|
return { styles, scripts, externalScriptSrcs, variablesByComp };
|
||||||
|
}
|
||||||
@@ -20,10 +20,8 @@ import {
|
|||||||
shouldClampMediaDuration,
|
shouldClampMediaDuration,
|
||||||
type ResolvedDuration,
|
type ResolvedDuration,
|
||||||
type UnresolvedElement,
|
type UnresolvedElement,
|
||||||
rewriteAssetPaths,
|
|
||||||
rewriteCssAssetUrls,
|
|
||||||
} from "@hyperframes/core";
|
} from "@hyperframes/core";
|
||||||
import { scopeCssToComposition, wrapScopedCompositionScript } from "@hyperframes/core/compiler";
|
import { inlineSubCompositions as inlineSubCompositionsShared } from "@hyperframes/core/compiler";
|
||||||
import { extractMediaMetadata, extractAudioMetadata } from "../utils/ffprobe.js";
|
import { extractMediaMetadata, extractAudioMetadata } from "../utils/ffprobe.js";
|
||||||
import { isPathInside, toExternalAssetKey } from "../utils/paths.js";
|
import { isPathInside, toExternalAssetKey } from "../utils/paths.js";
|
||||||
import {
|
import {
|
||||||
@@ -543,13 +541,11 @@ function coalesceHeadStylesAndBodyScripts(html: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inline sub-composition HTML into the main document, mirroring what the
|
* Inline sub-composition HTML into the main document using the shared
|
||||||
* bundler's step 6 does. For each host element with `data-composition-src`:
|
* inlining logic from @hyperframes/core. This wrapper handles the
|
||||||
* - Resolve the composition HTML from the pre-compiled map or disk
|
* producer-specific concerns: parsing HTML via linkedom, resolving
|
||||||
* - Extract <template> (or <body>) content
|
* compositions from the pre-compiled map or disk, and setting explicit
|
||||||
* - Move composition <style> to <head>, <script> to end of <body>
|
* pixel dimensions on host elements for headless rendering.
|
||||||
* - Replace host innerHTML with composition children
|
|
||||||
* - Remove data-composition-src so the runtime skips async fetching
|
|
||||||
*/
|
*/
|
||||||
function inlineSubCompositions(
|
function inlineSubCompositions(
|
||||||
html: string,
|
html: string,
|
||||||
@@ -559,142 +555,33 @@ function inlineSubCompositions(
|
|||||||
const { document } = parseHTML(html);
|
const { document } = parseHTML(html);
|
||||||
const head = document.querySelector("head");
|
const head = document.querySelector("head");
|
||||||
const body = document.querySelector("body");
|
const body = document.querySelector("body");
|
||||||
const hosts = document.querySelectorAll("[data-composition-src]");
|
const hosts = Array.from(document.querySelectorAll("[data-composition-src]"));
|
||||||
|
|
||||||
if (!hosts.length) return html;
|
if (!hosts.length) return html;
|
||||||
|
|
||||||
const collectedStyles: string[] = [];
|
const result = inlineSubCompositionsShared(
|
||||||
const collectedScripts: string[] = [];
|
document as unknown as Document,
|
||||||
const collectedExternalScriptSrcs: string[] = [];
|
hosts as unknown as Element[],
|
||||||
|
{
|
||||||
|
resolveHtml: (srcPath: string) => {
|
||||||
|
let compHtml = subCompositions.get(srcPath) || null;
|
||||||
|
if (!compHtml) {
|
||||||
|
const filePath = resolve(projectDir, srcPath);
|
||||||
|
if (existsSync(filePath)) {
|
||||||
|
compHtml = readFileSync(filePath, "utf-8");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return compHtml;
|
||||||
|
},
|
||||||
|
parseHtml: (htmlStr: string) => parseHTML(htmlStr).document as unknown as Document,
|
||||||
|
scriptErrorLabel: "[Compiler] Composition script failed",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Producer-specific: set explicit pixel dimensions on host elements so
|
||||||
|
// children using width/height: 100% resolve correctly. The runtime does
|
||||||
|
// this automatically but compiled HTML needs it inline.
|
||||||
for (const host of hosts) {
|
for (const host of hosts) {
|
||||||
const srcPath = host.getAttribute("data-composition-src");
|
|
||||||
if (!srcPath) continue;
|
|
||||||
|
|
||||||
let compHtml = subCompositions.get(srcPath) || null;
|
|
||||||
if (!compHtml) {
|
|
||||||
const filePath = resolve(projectDir, srcPath);
|
|
||||||
if (existsSync(filePath)) {
|
|
||||||
compHtml = readFileSync(filePath, "utf-8");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!compHtml) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const compDoc = parseHTML(compHtml).document;
|
|
||||||
const compId = host.getAttribute("data-composition-id");
|
|
||||||
|
|
||||||
const templateEl = compDoc.querySelector("template");
|
|
||||||
const bodyEl = compDoc.querySelector("body");
|
|
||||||
const contentHtml = templateEl
|
|
||||||
? templateEl.innerHTML || ""
|
|
||||||
: bodyEl
|
|
||||||
? bodyEl.innerHTML || ""
|
|
||||||
: compDoc.toString();
|
|
||||||
|
|
||||||
const contentDoc = parseHTML(contentHtml).document;
|
|
||||||
|
|
||||||
const innerRoot = compId
|
|
||||||
? contentDoc.querySelector(`[data-composition-id="${compId}"]`)
|
|
||||||
: contentDoc.querySelector("[data-composition-id]");
|
|
||||||
const inferredCompId = innerRoot?.getAttribute("data-composition-id")?.trim() || null;
|
|
||||||
|
|
||||||
// When a sub-composition is a full HTML document (no <template>), styles
|
|
||||||
// and scripts in <head> are not part of contentDoc (which only has body
|
|
||||||
// content). Extract them separately so backgrounds, positioning, fonts,
|
|
||||||
// and library scripts (e.g. GSAP CDN) are not silently dropped.
|
|
||||||
if (!templateEl) {
|
|
||||||
const compHead = compDoc.querySelector("head");
|
|
||||||
if (compHead) {
|
|
||||||
for (const styleEl of compHead.querySelectorAll("style")) {
|
|
||||||
const css = rewriteCssAssetUrls(styleEl.textContent || "", srcPath);
|
|
||||||
const scopeId = compId || inferredCompId;
|
|
||||||
if (scopeId && css.trim()) {
|
|
||||||
collectedStyles.push(scopeCssToComposition(css, scopeId));
|
|
||||||
} else {
|
|
||||||
collectedStyles.push(css);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const scriptEl of compHead.querySelectorAll("script")) {
|
|
||||||
const src = (scriptEl.getAttribute("src") || "").trim();
|
|
||||||
if (src && !collectedExternalScriptSrcs.includes(src)) {
|
|
||||||
collectedExternalScriptSrcs.push(src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const styleEl of contentDoc.querySelectorAll("style")) {
|
|
||||||
const css = rewriteCssAssetUrls(styleEl.textContent || "", srcPath);
|
|
||||||
const scopeId = compId || inferredCompId;
|
|
||||||
if (scopeId && css.trim()) {
|
|
||||||
// Scope sub-composition styles to their composition ID to prevent
|
|
||||||
// CSS class collisions when multiple compositions use the same
|
|
||||||
// class names (e.g. ".content"). This matches preview behavior
|
|
||||||
// where each composition's styles are naturally scoped.
|
|
||||||
collectedStyles.push(scopeCssToComposition(css, scopeId));
|
|
||||||
} else {
|
|
||||||
collectedStyles.push(css);
|
|
||||||
}
|
|
||||||
styleEl.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const scriptEl of contentDoc.querySelectorAll("script")) {
|
|
||||||
const src = (scriptEl.getAttribute("src") || "").trim();
|
|
||||||
if (src) {
|
|
||||||
// External CDN/remote script — collect for deduped injection into the
|
|
||||||
// parent document, mirroring the bundler's hoisting behavior.
|
|
||||||
if (!collectedExternalScriptSrcs.includes(src)) {
|
|
||||||
collectedExternalScriptSrcs.push(src);
|
|
||||||
}
|
|
||||||
scriptEl.remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const content = (scriptEl.textContent || "").trim();
|
|
||||||
if (content) {
|
|
||||||
const scriptMountCompId = compId || inferredCompId || "";
|
|
||||||
collectedScripts.push(
|
|
||||||
scriptMountCompId
|
|
||||||
? wrapScopedCompositionScript(
|
|
||||||
content,
|
|
||||||
scriptMountCompId,
|
|
||||||
"[Compiler] Composition script failed",
|
|
||||||
)
|
|
||||||
: `(function(){ try { ${content} } catch (_err) { console.error("[Compiler] Composition script failed", _err); } })()`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
scriptEl.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rewrite relative asset paths before inlining so ../foo.svg from
|
|
||||||
// compositions/ resolves correctly when the content moves to root.
|
|
||||||
const rewriteTarget = innerRoot || contentDoc;
|
|
||||||
rewriteAssetPaths(
|
|
||||||
rewriteTarget.querySelectorAll("[src], [href]"),
|
|
||||||
srcPath,
|
|
||||||
(el, attr) => (el.getAttribute(attr) || "").trim(),
|
|
||||||
(el, attr, val) => el.setAttribute(attr, val),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (innerRoot) {
|
|
||||||
const innerW = innerRoot.getAttribute("data-width");
|
|
||||||
const innerH = innerRoot.getAttribute("data-height");
|
|
||||||
if (innerW && !host.getAttribute("data-width")) host.setAttribute("data-width", innerW);
|
|
||||||
if (innerH && !host.getAttribute("data-height")) host.setAttribute("data-height", innerH);
|
|
||||||
innerRoot.querySelectorAll("style, script").forEach((el) => el.remove());
|
|
||||||
host.innerHTML = compId ? innerRoot.innerHTML || "" : innerRoot.outerHTML || "";
|
|
||||||
} else {
|
|
||||||
contentDoc.querySelectorAll("style, script").forEach((el) => el.remove());
|
|
||||||
host.innerHTML = contentDoc.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
host.setAttribute("data-composition-file", srcPath);
|
|
||||||
host.removeAttribute("data-composition-src");
|
|
||||||
|
|
||||||
// Set explicit pixel dimensions on the host element so children using
|
|
||||||
// width/height: 100% resolve correctly. The runtime does this
|
|
||||||
// automatically but compiled HTML needs it inline.
|
|
||||||
const hostW = host.getAttribute("data-width");
|
const hostW = host.getAttribute("data-width");
|
||||||
const hostH = host.getAttribute("data-height");
|
const hostH = host.getAttribute("data-height");
|
||||||
if (hostW && hostH) {
|
if (hostW && hostH) {
|
||||||
@@ -713,22 +600,23 @@ function inlineSubCompositions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectedStyles.length && head) {
|
// Append collected styles to <head>
|
||||||
|
if (result.styles.length && head) {
|
||||||
const styleEl = document.createElement("style");
|
const styleEl = document.createElement("style");
|
||||||
styleEl.textContent = collectedStyles.join("\n\n");
|
styleEl.textContent = result.styles.join("\n\n");
|
||||||
head.appendChild(styleEl);
|
head.appendChild(styleEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject external CDN scripts before inline scripts so plugins (e.g.
|
// Inject external CDN scripts before inline scripts so plugins (e.g.
|
||||||
// TextPlugin, ScrollTrigger) are registered before composition code runs.
|
// TextPlugin, ScrollTrigger) are registered before composition code runs.
|
||||||
// Deduplicate against scripts already present in the document.
|
// Deduplicate against scripts already present in the document.
|
||||||
if (collectedExternalScriptSrcs.length && body) {
|
if (result.externalScriptSrcs.length && body) {
|
||||||
const existingScriptSrcs = new Set(
|
const existingScriptSrcs = new Set(
|
||||||
Array.from(document.querySelectorAll("script[src]")).map((el) =>
|
Array.from(document.querySelectorAll("script[src]")).map((el: Element) =>
|
||||||
(el.getAttribute("src") || "").trim(),
|
(el.getAttribute("src") || "").trim(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
for (const src of collectedExternalScriptSrcs) {
|
for (const src of result.externalScriptSrcs) {
|
||||||
if (!existingScriptSrcs.has(src)) {
|
if (!existingScriptSrcs.has(src)) {
|
||||||
const scriptEl = document.createElement("script");
|
const scriptEl = document.createElement("script");
|
||||||
scriptEl.setAttribute("src", src);
|
scriptEl.setAttribute("src", src);
|
||||||
@@ -738,9 +626,10 @@ function inlineSubCompositions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectedScripts.length && body) {
|
// Append collected inline scripts to <body>
|
||||||
|
if (result.scripts.length && body) {
|
||||||
const scriptEl = document.createElement("script");
|
const scriptEl = document.createElement("script");
|
||||||
scriptEl.textContent = collectedScripts.join("\n;\n");
|
scriptEl.textContent = result.scripts.join("\n;\n");
|
||||||
body.appendChild(scriptEl);
|
body.appendChild(scriptEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:324369f32516e8408fd11bf3e1644d3fc25a024cea3f2483a932621c4e264293
|
oid sha256:6b1a1f0e54d8196829e1dd6d4a0ef128747f98a76c50755bbb8150b792ee5b64
|
||||||
size 450917
|
size 689794
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:936aff6bdaf542f3fa6311288e056def65bfdba420ed9577243e203da954fb7e
|
oid sha256:d7a67603547c49da6f75e967afbdc5f849aed3323658ae0ad4d45fc5dfad2eeb
|
||||||
size 18979575
|
size 22330971
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f5e7d82a72a22b19ecda914727c0bb45453e213865f7d44ba88bd328053eded7
|
oid sha256:fa7e5d324d183f9edbab0a428954428fa204dc53dd08615237d7994cdb265998
|
||||||
size 7614486
|
size 12322028
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:701ec3b1ece40ca89d8b1836b10f8a02f2ed5c442f99c059c62dd86fa66003b5
|
oid sha256:abe913663b03ac7ea0d47427e38fc26b0afde872a91444636a7299c1168fc2ee
|
||||||
size 10757091
|
size 17106658
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:d260f106a6ad907a2b4d07b78e8e8d4b286eea3f8650be9d8a6b4674c194e64c
|
oid sha256:5bc77b1c42ebaf496bcff565bd334bd67ae1e2fc44f685d1d41c840a57f810df
|
||||||
size 6114459
|
size 15232127
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:798f6756d8c07f5b0a44f7c861fcf051c6a043f03ec13e71249bd5ae8175d98a
|
oid sha256:20f1d8f5824520f55369794c6674717c230f5ceacc05222f06080bd555ccc1f7
|
||||||
size 3900890
|
size 7198724
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:ed6c28c61ca54c7b45229eb7fe6222ab5aef34cd2132a285d7a4e164319127b9
|
oid sha256:f1c6af0c1460f17cfe8c28b1813d2d28807c3c848ea313c49b2f54f498ffb3bd
|
||||||
size 6704037
|
size 11365418
|
||||||
|
|||||||
@@ -358,7 +358,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Compositions -->
|
<!-- Compositions -->
|
||||||
<div style="width:1920px;height:1080px" id="intro-comp" data-composition-id="intro" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="100">
|
<div style="width:1920px;height:1080px" data-composition-file="compositions/intro.html" id="intro-comp" data-composition-id="intro" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="100">
|
||||||
<div class="intro-container">
|
<div class="intro-container">
|
||||||
<h1 class="title">EDITOR AGENT</h1>
|
<h1 class="title">EDITOR AGENT</h1>
|
||||||
</div>
|
</div>
|
||||||
@@ -367,14 +367,14 @@
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div style="width:1920px;height:1080px" id="captions-comp" data-composition-id="captions" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="200">
|
<div style="width:1920px;height:1080px" data-composition-file="compositions/captions.html" id="captions-comp" data-composition-id="captions" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="200">
|
||||||
<div id="captions-container"></div>
|
<div id="captions-container"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div style="width:1920px;height:1080px" id="stats-comp" data-composition-id="stats" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="150">
|
<div style="width:1920px;height:1080px" data-composition-file="compositions/stats.html" id="stats-comp" data-composition-id="stats" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="150">
|
||||||
<div id="stats-container">
|
<div id="stats-container">
|
||||||
<!-- Moment 1: 47% NEED MOTION GRAPHICS -->
|
<!-- Moment 1: 47% NEED MOTION GRAPHICS -->
|
||||||
<div id="moment-1" class="moment" style="opacity: 0; transform: scale(0) rotate(8deg)">
|
<div id="moment-1" class="moment" style="opacity: 0; transform: scale(0) rotate(8deg)">
|
||||||
@@ -476,20 +476,87 @@ window.__timelines = window.__timelines || {};
|
|||||||
var __hfCompId = "intro";
|
var __hfCompId = "intro";
|
||||||
var __hfTimelineCompId = "intro";
|
var __hfTimelineCompId = "intro";
|
||||||
var __hfErrorLabel = "[Compiler] Composition script failed";
|
var __hfErrorLabel = "[Compiler] Composition script failed";
|
||||||
|
var __hfAuthoredRootId = "intro-comp";
|
||||||
|
var __hfAuthoredRootAttr = "data-hf-authored-id";
|
||||||
var __hfEscapeAttr = function(value) {
|
var __hfEscapeAttr = function(value) {
|
||||||
return (value + "").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
return (value + "").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
||||||
};
|
};
|
||||||
var __hfRootSelector = null || (__hfCompId
|
var __hfRootSelector = "[data-composition-id=\"intro\"]" || (__hfCompId
|
||||||
? '[data-composition-id="' + __hfEscapeAttr(__hfCompId) + '"]'
|
? '[data-composition-id="' + __hfEscapeAttr(__hfCompId) + '"]'
|
||||||
: "");
|
: "");
|
||||||
var __hfRoot = null;
|
var __hfRoot = null;
|
||||||
var __hfRootSelectorPattern = "\\[\\s*data-composition-id\\s*=\\s*(?:\"intro\"|'intro')\\s*\\]";
|
var __hfRootSelectorPattern = "\\[\\s*data-composition-id\\s*=\\s*(?:\"intro\"|'intro')\\s*\\]";
|
||||||
var __hfTimingSelectorPattern = "\\s*\\[\\s*data-(?:start|duration)\\s*=\\s*(?:\"[^\"]*\"|'[^']*')\\s*\\]";
|
var __hfTimingSelectorPattern = "\\s*\\[\\s*data-(?:start|duration)\\s*=\\s*(?:\"[^\"]*\"|'[^']*')\\s*\\]";
|
||||||
|
var __hfAuthoredRootIdForms = ["intro-comp"];
|
||||||
|
var __hfAuthoredRootSelector = __hfAuthoredRootId
|
||||||
|
? "[" + __hfAuthoredRootAttr + '="' + __hfEscapeAttr(__hfAuthoredRootId) + '"]'
|
||||||
|
: "";
|
||||||
|
var __hfIsSelectorNameChar = function(char) {
|
||||||
|
return !!char && /[\w-]/.test(char);
|
||||||
|
};
|
||||||
|
var __hfReplaceAuthoredRootIdSelectors = function(selector) {
|
||||||
|
if (!__hfAuthoredRootSelector || !__hfAuthoredRootIdForms.length || typeof selector !== "string") {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
var result = "";
|
||||||
|
var bracketDepth = 0;
|
||||||
|
var quote = null;
|
||||||
|
for (var index = 0; index < selector.length; index += 1) {
|
||||||
|
var char = selector[index];
|
||||||
|
var previousChar = index > 0 ? selector[index - 1] : "";
|
||||||
|
if (quote) {
|
||||||
|
result += char;
|
||||||
|
if (char === quote && previousChar !== "\\") {
|
||||||
|
quote = null;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === '"' || char === "'") {
|
||||||
|
quote = char;
|
||||||
|
result += char;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === "[") {
|
||||||
|
bracketDepth += 1;
|
||||||
|
result += char;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === "]") {
|
||||||
|
bracketDepth = Math.max(0, bracketDepth - 1);
|
||||||
|
result += char;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === "#" && bracketDepth === 0) {
|
||||||
|
var matchedForm = null;
|
||||||
|
for (var formIndex = 0; formIndex < __hfAuthoredRootIdForms.length; formIndex += 1) {
|
||||||
|
var form = __hfAuthoredRootIdForms[formIndex];
|
||||||
|
if (selector.slice(index + 1, index + 1 + form.length) === form) {
|
||||||
|
matchedForm = form;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matchedForm) {
|
||||||
|
var nextChar = selector[index + 1 + matchedForm.length];
|
||||||
|
if (!__hfIsSelectorNameChar(nextChar)) {
|
||||||
|
result += __hfAuthoredRootSelector;
|
||||||
|
index += matchedForm.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += char;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
var __hfNormalizeSelector = function(selector) {
|
var __hfNormalizeSelector = function(selector) {
|
||||||
if (!__hfCompId || typeof selector !== "string") return selector;
|
if (!__hfCompId || typeof selector !== "string") return selector;
|
||||||
return selector
|
var normalized = selector
|
||||||
.replace(new RegExp(__hfRootSelectorPattern + '(?:' + __hfTimingSelectorPattern + ')+', 'g'), __hfRootSelector)
|
.replace(new RegExp(__hfRootSelectorPattern + '(?:' + __hfTimingSelectorPattern + ')+', 'g'), __hfRootSelector)
|
||||||
.replace(new RegExp('(?:' + __hfTimingSelectorPattern + ')+' + __hfRootSelectorPattern, 'g'), __hfRootSelector);
|
.replace(new RegExp('(?:' + __hfTimingSelectorPattern + ')+' + __hfRootSelectorPattern, 'g'), __hfRootSelector);
|
||||||
|
if (__hfAuthoredRootSelector) {
|
||||||
|
normalized = __hfReplaceAuthoredRootIdSelectors(normalized);
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
};
|
};
|
||||||
var __hfFindRoot = function() {
|
var __hfFindRoot = function() {
|
||||||
if (!__hfRoot && __hfRootSelector) {
|
if (!__hfRoot && __hfRootSelector) {
|
||||||
@@ -520,8 +587,15 @@ window.__timelines = window.__timelines || {};
|
|||||||
var root = __hfFindRoot();
|
var root = __hfFindRoot();
|
||||||
if (!root) return found || null;
|
if (!root) return found || null;
|
||||||
var idValue = id + "";
|
var idValue = id + "";
|
||||||
|
if (__hfAuthoredRootId && __hfAuthoredRootId === idValue && root.getAttribute && root.getAttribute(__hfAuthoredRootAttr) === idValue) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
if (root.id === idValue) return root;
|
if (root.id === idValue) return root;
|
||||||
if (typeof root.querySelector !== "function") return null;
|
if (typeof root.querySelector !== "function") return null;
|
||||||
|
try {
|
||||||
|
var authoredRootMatch = root.querySelector('[' + __hfAuthoredRootAttr + '="' + __hfEscapeAttr(idValue) + '"]');
|
||||||
|
if (authoredRootMatch) return authoredRootMatch;
|
||||||
|
} catch {}
|
||||||
if (typeof CSS !== "undefined" && CSS && typeof CSS.escape === "function") {
|
if (typeof CSS !== "undefined" && CSS && typeof CSS.escape === "function") {
|
||||||
try {
|
try {
|
||||||
return root.querySelector("#" + CSS.escape(idValue)) || null;
|
return root.querySelector("#" + CSS.escape(idValue)) || null;
|
||||||
@@ -638,7 +712,12 @@ window.__timelines = window.__timelines || {};
|
|||||||
var root = baseEl || __hfFindRoot();
|
var root = baseEl || __hfFindRoot();
|
||||||
return function(selector) {
|
return function(selector) {
|
||||||
if (!root || typeof selector !== "string") return [];
|
if (!root || typeof selector !== "string") return [];
|
||||||
return Array.prototype.slice.call(root.querySelectorAll(selector));
|
return Array.prototype.filter.call(
|
||||||
|
window.document.querySelectorAll(__hfNormalizeSelector(selector)),
|
||||||
|
function(node) {
|
||||||
|
return node === root || (typeof root.contains === "function" && root.contains(node));
|
||||||
|
},
|
||||||
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -657,14 +736,15 @@ window.__timelines = window.__timelines || {};
|
|||||||
: Object.assign({}, __hfBaseHyperframes, {
|
: Object.assign({}, __hfBaseHyperframes, {
|
||||||
getVariables: function() {
|
getVariables: function() {
|
||||||
var byComp = window.__hfVariablesByComp;
|
var byComp = window.__hfVariablesByComp;
|
||||||
var scoped = byComp && __hfCompId ? byComp[__hfCompId] : null;
|
var scoped = byComp && __hfTimelineCompId ? byComp[__hfTimelineCompId] : null;
|
||||||
return scoped ? Object.assign({}, scoped) : {};
|
return scoped ? Object.assign({}, scoped) : {};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
var __hfRun = function() {
|
var __hfRun = function() {
|
||||||
try {
|
try {
|
||||||
(function(document, gsap, window, __hyperframes) {
|
(function(document, gsap, window, __hyperframes) {
|
||||||
(function () {
|
|
||||||
|
(function () {
|
||||||
const tl = gsap.timeline({ paused: true });
|
const tl = gsap.timeline({ paused: true });
|
||||||
|
|
||||||
// --- INTRO SEQUENCE ---
|
// --- INTRO SEQUENCE ---
|
||||||
@@ -725,6 +805,7 @@ window.__timelines = window.__timelines || {};
|
|||||||
|
|
||||||
window.__timelines["intro"] = tl;
|
window.__timelines["intro"] = tl;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
}).call(window, __hfScopedDocument, __hfScopedGsap, __hfScopedWindow, __hfScopedHyperframes);
|
}).call(window, __hfScopedDocument, __hfScopedGsap, __hfScopedWindow, __hfScopedHyperframes);
|
||||||
} catch (_err) {
|
} catch (_err) {
|
||||||
console.error(__hfErrorLabel, __hfCompId, _err);
|
console.error(__hfErrorLabel, __hfCompId, _err);
|
||||||
@@ -738,20 +819,87 @@ window.__timelines = window.__timelines || {};
|
|||||||
var __hfCompId = "captions";
|
var __hfCompId = "captions";
|
||||||
var __hfTimelineCompId = "captions";
|
var __hfTimelineCompId = "captions";
|
||||||
var __hfErrorLabel = "[Compiler] Composition script failed";
|
var __hfErrorLabel = "[Compiler] Composition script failed";
|
||||||
|
var __hfAuthoredRootId = null;
|
||||||
|
var __hfAuthoredRootAttr = "data-hf-authored-id";
|
||||||
var __hfEscapeAttr = function(value) {
|
var __hfEscapeAttr = function(value) {
|
||||||
return (value + "").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
return (value + "").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
||||||
};
|
};
|
||||||
var __hfRootSelector = null || (__hfCompId
|
var __hfRootSelector = "[data-composition-id=\"captions\"]" || (__hfCompId
|
||||||
? '[data-composition-id="' + __hfEscapeAttr(__hfCompId) + '"]'
|
? '[data-composition-id="' + __hfEscapeAttr(__hfCompId) + '"]'
|
||||||
: "");
|
: "");
|
||||||
var __hfRoot = null;
|
var __hfRoot = null;
|
||||||
var __hfRootSelectorPattern = "\\[\\s*data-composition-id\\s*=\\s*(?:\"captions\"|'captions')\\s*\\]";
|
var __hfRootSelectorPattern = "\\[\\s*data-composition-id\\s*=\\s*(?:\"captions\"|'captions')\\s*\\]";
|
||||||
var __hfTimingSelectorPattern = "\\s*\\[\\s*data-(?:start|duration)\\s*=\\s*(?:\"[^\"]*\"|'[^']*')\\s*\\]";
|
var __hfTimingSelectorPattern = "\\s*\\[\\s*data-(?:start|duration)\\s*=\\s*(?:\"[^\"]*\"|'[^']*')\\s*\\]";
|
||||||
|
var __hfAuthoredRootIdForms = [];
|
||||||
|
var __hfAuthoredRootSelector = __hfAuthoredRootId
|
||||||
|
? "[" + __hfAuthoredRootAttr + '="' + __hfEscapeAttr(__hfAuthoredRootId) + '"]'
|
||||||
|
: "";
|
||||||
|
var __hfIsSelectorNameChar = function(char) {
|
||||||
|
return !!char && /[\w-]/.test(char);
|
||||||
|
};
|
||||||
|
var __hfReplaceAuthoredRootIdSelectors = function(selector) {
|
||||||
|
if (!__hfAuthoredRootSelector || !__hfAuthoredRootIdForms.length || typeof selector !== "string") {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
var result = "";
|
||||||
|
var bracketDepth = 0;
|
||||||
|
var quote = null;
|
||||||
|
for (var index = 0; index < selector.length; index += 1) {
|
||||||
|
var char = selector[index];
|
||||||
|
var previousChar = index > 0 ? selector[index - 1] : "";
|
||||||
|
if (quote) {
|
||||||
|
result += char;
|
||||||
|
if (char === quote && previousChar !== "\\") {
|
||||||
|
quote = null;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === '"' || char === "'") {
|
||||||
|
quote = char;
|
||||||
|
result += char;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === "[") {
|
||||||
|
bracketDepth += 1;
|
||||||
|
result += char;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === "]") {
|
||||||
|
bracketDepth = Math.max(0, bracketDepth - 1);
|
||||||
|
result += char;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === "#" && bracketDepth === 0) {
|
||||||
|
var matchedForm = null;
|
||||||
|
for (var formIndex = 0; formIndex < __hfAuthoredRootIdForms.length; formIndex += 1) {
|
||||||
|
var form = __hfAuthoredRootIdForms[formIndex];
|
||||||
|
if (selector.slice(index + 1, index + 1 + form.length) === form) {
|
||||||
|
matchedForm = form;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matchedForm) {
|
||||||
|
var nextChar = selector[index + 1 + matchedForm.length];
|
||||||
|
if (!__hfIsSelectorNameChar(nextChar)) {
|
||||||
|
result += __hfAuthoredRootSelector;
|
||||||
|
index += matchedForm.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += char;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
var __hfNormalizeSelector = function(selector) {
|
var __hfNormalizeSelector = function(selector) {
|
||||||
if (!__hfCompId || typeof selector !== "string") return selector;
|
if (!__hfCompId || typeof selector !== "string") return selector;
|
||||||
return selector
|
var normalized = selector
|
||||||
.replace(new RegExp(__hfRootSelectorPattern + '(?:' + __hfTimingSelectorPattern + ')+', 'g'), __hfRootSelector)
|
.replace(new RegExp(__hfRootSelectorPattern + '(?:' + __hfTimingSelectorPattern + ')+', 'g'), __hfRootSelector)
|
||||||
.replace(new RegExp('(?:' + __hfTimingSelectorPattern + ')+' + __hfRootSelectorPattern, 'g'), __hfRootSelector);
|
.replace(new RegExp('(?:' + __hfTimingSelectorPattern + ')+' + __hfRootSelectorPattern, 'g'), __hfRootSelector);
|
||||||
|
if (__hfAuthoredRootSelector) {
|
||||||
|
normalized = __hfReplaceAuthoredRootIdSelectors(normalized);
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
};
|
};
|
||||||
var __hfFindRoot = function() {
|
var __hfFindRoot = function() {
|
||||||
if (!__hfRoot && __hfRootSelector) {
|
if (!__hfRoot && __hfRootSelector) {
|
||||||
@@ -782,8 +930,15 @@ window.__timelines = window.__timelines || {};
|
|||||||
var root = __hfFindRoot();
|
var root = __hfFindRoot();
|
||||||
if (!root) return found || null;
|
if (!root) return found || null;
|
||||||
var idValue = id + "";
|
var idValue = id + "";
|
||||||
|
if (__hfAuthoredRootId && __hfAuthoredRootId === idValue && root.getAttribute && root.getAttribute(__hfAuthoredRootAttr) === idValue) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
if (root.id === idValue) return root;
|
if (root.id === idValue) return root;
|
||||||
if (typeof root.querySelector !== "function") return null;
|
if (typeof root.querySelector !== "function") return null;
|
||||||
|
try {
|
||||||
|
var authoredRootMatch = root.querySelector('[' + __hfAuthoredRootAttr + '="' + __hfEscapeAttr(idValue) + '"]');
|
||||||
|
if (authoredRootMatch) return authoredRootMatch;
|
||||||
|
} catch {}
|
||||||
if (typeof CSS !== "undefined" && CSS && typeof CSS.escape === "function") {
|
if (typeof CSS !== "undefined" && CSS && typeof CSS.escape === "function") {
|
||||||
try {
|
try {
|
||||||
return root.querySelector("#" + CSS.escape(idValue)) || null;
|
return root.querySelector("#" + CSS.escape(idValue)) || null;
|
||||||
@@ -900,7 +1055,12 @@ window.__timelines = window.__timelines || {};
|
|||||||
var root = baseEl || __hfFindRoot();
|
var root = baseEl || __hfFindRoot();
|
||||||
return function(selector) {
|
return function(selector) {
|
||||||
if (!root || typeof selector !== "string") return [];
|
if (!root || typeof selector !== "string") return [];
|
||||||
return Array.prototype.slice.call(root.querySelectorAll(selector));
|
return Array.prototype.filter.call(
|
||||||
|
window.document.querySelectorAll(__hfNormalizeSelector(selector)),
|
||||||
|
function(node) {
|
||||||
|
return node === root || (typeof root.contains === "function" && root.contains(node));
|
||||||
|
},
|
||||||
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -919,14 +1079,15 @@ window.__timelines = window.__timelines || {};
|
|||||||
: Object.assign({}, __hfBaseHyperframes, {
|
: Object.assign({}, __hfBaseHyperframes, {
|
||||||
getVariables: function() {
|
getVariables: function() {
|
||||||
var byComp = window.__hfVariablesByComp;
|
var byComp = window.__hfVariablesByComp;
|
||||||
var scoped = byComp && __hfCompId ? byComp[__hfCompId] : null;
|
var scoped = byComp && __hfTimelineCompId ? byComp[__hfTimelineCompId] : null;
|
||||||
return scoped ? Object.assign({}, scoped) : {};
|
return scoped ? Object.assign({}, scoped) : {};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
var __hfRun = function() {
|
var __hfRun = function() {
|
||||||
try {
|
try {
|
||||||
(function(document, gsap, window, __hyperframes) {
|
(function(document, gsap, window, __hyperframes) {
|
||||||
(function () {
|
|
||||||
|
(function () {
|
||||||
const TRANSCRIPT = [
|
const TRANSCRIPT = [
|
||||||
{ text: "We", start: 0.119, end: 0.259 },
|
{ text: "We", start: 0.119, end: 0.259 },
|
||||||
{ text: "asked", start: 0.319, end: 0.479 },
|
{ text: "asked", start: 0.319, end: 0.479 },
|
||||||
@@ -1038,6 +1199,7 @@ window.__timelines = window.__timelines || {};
|
|||||||
|
|
||||||
window.__timelines["captions"] = tl;
|
window.__timelines["captions"] = tl;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
}).call(window, __hfScopedDocument, __hfScopedGsap, __hfScopedWindow, __hfScopedHyperframes);
|
}).call(window, __hfScopedDocument, __hfScopedGsap, __hfScopedWindow, __hfScopedHyperframes);
|
||||||
} catch (_err) {
|
} catch (_err) {
|
||||||
console.error(__hfErrorLabel, __hfCompId, _err);
|
console.error(__hfErrorLabel, __hfCompId, _err);
|
||||||
@@ -1051,20 +1213,87 @@ window.__timelines = window.__timelines || {};
|
|||||||
var __hfCompId = "stats";
|
var __hfCompId = "stats";
|
||||||
var __hfTimelineCompId = "stats";
|
var __hfTimelineCompId = "stats";
|
||||||
var __hfErrorLabel = "[Compiler] Composition script failed";
|
var __hfErrorLabel = "[Compiler] Composition script failed";
|
||||||
|
var __hfAuthoredRootId = null;
|
||||||
|
var __hfAuthoredRootAttr = "data-hf-authored-id";
|
||||||
var __hfEscapeAttr = function(value) {
|
var __hfEscapeAttr = function(value) {
|
||||||
return (value + "").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
return (value + "").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
||||||
};
|
};
|
||||||
var __hfRootSelector = null || (__hfCompId
|
var __hfRootSelector = "[data-composition-id=\"stats\"]" || (__hfCompId
|
||||||
? '[data-composition-id="' + __hfEscapeAttr(__hfCompId) + '"]'
|
? '[data-composition-id="' + __hfEscapeAttr(__hfCompId) + '"]'
|
||||||
: "");
|
: "");
|
||||||
var __hfRoot = null;
|
var __hfRoot = null;
|
||||||
var __hfRootSelectorPattern = "\\[\\s*data-composition-id\\s*=\\s*(?:\"stats\"|'stats')\\s*\\]";
|
var __hfRootSelectorPattern = "\\[\\s*data-composition-id\\s*=\\s*(?:\"stats\"|'stats')\\s*\\]";
|
||||||
var __hfTimingSelectorPattern = "\\s*\\[\\s*data-(?:start|duration)\\s*=\\s*(?:\"[^\"]*\"|'[^']*')\\s*\\]";
|
var __hfTimingSelectorPattern = "\\s*\\[\\s*data-(?:start|duration)\\s*=\\s*(?:\"[^\"]*\"|'[^']*')\\s*\\]";
|
||||||
|
var __hfAuthoredRootIdForms = [];
|
||||||
|
var __hfAuthoredRootSelector = __hfAuthoredRootId
|
||||||
|
? "[" + __hfAuthoredRootAttr + '="' + __hfEscapeAttr(__hfAuthoredRootId) + '"]'
|
||||||
|
: "";
|
||||||
|
var __hfIsSelectorNameChar = function(char) {
|
||||||
|
return !!char && /[\w-]/.test(char);
|
||||||
|
};
|
||||||
|
var __hfReplaceAuthoredRootIdSelectors = function(selector) {
|
||||||
|
if (!__hfAuthoredRootSelector || !__hfAuthoredRootIdForms.length || typeof selector !== "string") {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
var result = "";
|
||||||
|
var bracketDepth = 0;
|
||||||
|
var quote = null;
|
||||||
|
for (var index = 0; index < selector.length; index += 1) {
|
||||||
|
var char = selector[index];
|
||||||
|
var previousChar = index > 0 ? selector[index - 1] : "";
|
||||||
|
if (quote) {
|
||||||
|
result += char;
|
||||||
|
if (char === quote && previousChar !== "\\") {
|
||||||
|
quote = null;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === '"' || char === "'") {
|
||||||
|
quote = char;
|
||||||
|
result += char;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === "[") {
|
||||||
|
bracketDepth += 1;
|
||||||
|
result += char;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === "]") {
|
||||||
|
bracketDepth = Math.max(0, bracketDepth - 1);
|
||||||
|
result += char;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char === "#" && bracketDepth === 0) {
|
||||||
|
var matchedForm = null;
|
||||||
|
for (var formIndex = 0; formIndex < __hfAuthoredRootIdForms.length; formIndex += 1) {
|
||||||
|
var form = __hfAuthoredRootIdForms[formIndex];
|
||||||
|
if (selector.slice(index + 1, index + 1 + form.length) === form) {
|
||||||
|
matchedForm = form;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matchedForm) {
|
||||||
|
var nextChar = selector[index + 1 + matchedForm.length];
|
||||||
|
if (!__hfIsSelectorNameChar(nextChar)) {
|
||||||
|
result += __hfAuthoredRootSelector;
|
||||||
|
index += matchedForm.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += char;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
var __hfNormalizeSelector = function(selector) {
|
var __hfNormalizeSelector = function(selector) {
|
||||||
if (!__hfCompId || typeof selector !== "string") return selector;
|
if (!__hfCompId || typeof selector !== "string") return selector;
|
||||||
return selector
|
var normalized = selector
|
||||||
.replace(new RegExp(__hfRootSelectorPattern + '(?:' + __hfTimingSelectorPattern + ')+', 'g'), __hfRootSelector)
|
.replace(new RegExp(__hfRootSelectorPattern + '(?:' + __hfTimingSelectorPattern + ')+', 'g'), __hfRootSelector)
|
||||||
.replace(new RegExp('(?:' + __hfTimingSelectorPattern + ')+' + __hfRootSelectorPattern, 'g'), __hfRootSelector);
|
.replace(new RegExp('(?:' + __hfTimingSelectorPattern + ')+' + __hfRootSelectorPattern, 'g'), __hfRootSelector);
|
||||||
|
if (__hfAuthoredRootSelector) {
|
||||||
|
normalized = __hfReplaceAuthoredRootIdSelectors(normalized);
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
};
|
};
|
||||||
var __hfFindRoot = function() {
|
var __hfFindRoot = function() {
|
||||||
if (!__hfRoot && __hfRootSelector) {
|
if (!__hfRoot && __hfRootSelector) {
|
||||||
@@ -1095,8 +1324,15 @@ window.__timelines = window.__timelines || {};
|
|||||||
var root = __hfFindRoot();
|
var root = __hfFindRoot();
|
||||||
if (!root) return found || null;
|
if (!root) return found || null;
|
||||||
var idValue = id + "";
|
var idValue = id + "";
|
||||||
|
if (__hfAuthoredRootId && __hfAuthoredRootId === idValue && root.getAttribute && root.getAttribute(__hfAuthoredRootAttr) === idValue) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
if (root.id === idValue) return root;
|
if (root.id === idValue) return root;
|
||||||
if (typeof root.querySelector !== "function") return null;
|
if (typeof root.querySelector !== "function") return null;
|
||||||
|
try {
|
||||||
|
var authoredRootMatch = root.querySelector('[' + __hfAuthoredRootAttr + '="' + __hfEscapeAttr(idValue) + '"]');
|
||||||
|
if (authoredRootMatch) return authoredRootMatch;
|
||||||
|
} catch {}
|
||||||
if (typeof CSS !== "undefined" && CSS && typeof CSS.escape === "function") {
|
if (typeof CSS !== "undefined" && CSS && typeof CSS.escape === "function") {
|
||||||
try {
|
try {
|
||||||
return root.querySelector("#" + CSS.escape(idValue)) || null;
|
return root.querySelector("#" + CSS.escape(idValue)) || null;
|
||||||
@@ -1213,7 +1449,12 @@ window.__timelines = window.__timelines || {};
|
|||||||
var root = baseEl || __hfFindRoot();
|
var root = baseEl || __hfFindRoot();
|
||||||
return function(selector) {
|
return function(selector) {
|
||||||
if (!root || typeof selector !== "string") return [];
|
if (!root || typeof selector !== "string") return [];
|
||||||
return Array.prototype.slice.call(root.querySelectorAll(selector));
|
return Array.prototype.filter.call(
|
||||||
|
window.document.querySelectorAll(__hfNormalizeSelector(selector)),
|
||||||
|
function(node) {
|
||||||
|
return node === root || (typeof root.contains === "function" && root.contains(node));
|
||||||
|
},
|
||||||
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1232,14 +1473,15 @@ window.__timelines = window.__timelines || {};
|
|||||||
: Object.assign({}, __hfBaseHyperframes, {
|
: Object.assign({}, __hfBaseHyperframes, {
|
||||||
getVariables: function() {
|
getVariables: function() {
|
||||||
var byComp = window.__hfVariablesByComp;
|
var byComp = window.__hfVariablesByComp;
|
||||||
var scoped = byComp && __hfCompId ? byComp[__hfCompId] : null;
|
var scoped = byComp && __hfTimelineCompId ? byComp[__hfTimelineCompId] : null;
|
||||||
return scoped ? Object.assign({}, scoped) : {};
|
return scoped ? Object.assign({}, scoped) : {};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
var __hfRun = function() {
|
var __hfRun = function() {
|
||||||
try {
|
try {
|
||||||
(function(document, gsap, window, __hyperframes) {
|
(function(document, gsap, window, __hyperframes) {
|
||||||
(function () {
|
|
||||||
|
(function () {
|
||||||
const TRANSCRIPT = [
|
const TRANSCRIPT = [
|
||||||
{ text: "We", start: 0.119, end: 0.259 },
|
{ text: "We", start: 0.119, end: 0.259 },
|
||||||
{ text: "asked", start: 0.319, end: 0.479 },
|
{ text: "asked", start: 0.319, end: 0.479 },
|
||||||
@@ -1404,6 +1646,7 @@ window.__timelines = window.__timelines || {};
|
|||||||
|
|
||||||
window.__timelines["stats"] = tl;
|
window.__timelines["stats"] = tl;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
}).call(window, __hfScopedDocument, __hfScopedGsap, __hfScopedWindow, __hfScopedHyperframes);
|
}).call(window, __hfScopedDocument, __hfScopedGsap, __hfScopedWindow, __hfScopedHyperframes);
|
||||||
} catch (_err) {
|
} catch (_err) {
|
||||||
console.error(__hfErrorLabel, __hfCompId, _err);
|
console.error(__hfErrorLabel, __hfCompId, _err);
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:a256872dd11c18a5cbb776d105af04f13432264c5c0689fa79c6ca697c86cf6b
|
oid sha256:1c5c34878cfe63ce79e60fe792c018e7b0b481ca59bd9c0dec558ed5e7cbb341
|
||||||
size 13478856
|
size 13503597
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4a1ac6cb0517b8224364833754981228f1138848e4f70715065f64f939ab4253
|
oid sha256:d2ca0d92ccf9740ad67c4ea46f50f65c3e3cefac88a07a171bd0fdcaf865efe0
|
||||||
size 7277596
|
size 13513666
|
||||||
|
|||||||
Reference in New Issue
Block a user