mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 07:19:52 +00:00
fix(lint): drop false media_in_subcomposition rule (#2765)
The media_in_subcomposition rule blanket-errored every <video>/<audio>
inside a sub-composition, claiming nested media is "never seeked/decoded
and renders blank/black". This is false: the runtime discovers media with
a flat document.querySelectorAll("video, audio"), resolves each element's
host composition via closest("[data-composition-id]"), and rebases its
local data-start by the accumulated absolute start of every ancestor
composition (packages/core/src/runtime/{media,startResolver}.ts). Media
seeks and decodes at any nesting depth, verified end to end through the
producer render path.
- Remove the rule and flip its test to assert nested media is NOT flagged.
- Drop the now-dead media_in_subcomposition clause from the registry
components test.
- Drop the equivalent pre-render guard from the faceless-explainer and
pr-to-video assemble scripts.
- Correct the reference docs (hyperframes-core SKILL, data-attributes,
variables-and-media, composition-patterns; hyperframes-cli
lint-validate-inspect): media works at any depth. Preserve the one real
constraint, that a sub-comp timeline cannot reach host-root elements, so
host-root media motion is authored on the main timeline.
This commit is contained in:
@@ -348,7 +348,13 @@ describe("media rules", () => {
|
||||
expect(finding).toBeUndefined();
|
||||
});
|
||||
|
||||
it("flags <video> inside a sub-composition (media must be a host-root child)", async () => {
|
||||
it("does not flag <video> inside a sub-composition (runtime drives nested media)", async () => {
|
||||
// The runtime's global media sweep (querySelectorAll("video, audio")) drives
|
||||
// media at any nesting depth, and startResolver re-bases each nested clip's
|
||||
// local data-start by its host composition's absolute start. Sub-composition
|
||||
// media is therefore seeked + decoded correctly in preview and render — see
|
||||
// packages/core/src/runtime/{media,startResolver,init}.ts. A prior
|
||||
// `media_in_subcomposition` rule wrongly hard-errored this and was removed.
|
||||
const html = `<template id="scene-template">
|
||||
<div id="root" data-composition-id="scene" data-width="1920" data-height="1080">
|
||||
<video id="v1" src="clip.mp4" data-start="0" data-duration="5" muted playsinline></video>
|
||||
@@ -357,10 +363,7 @@ describe("media rules", () => {
|
||||
</template>`;
|
||||
const result = await lintHyperframeHtml(html, { isSubComposition: true });
|
||||
const finding = result.findings.find((f) => f.code === "media_in_subcomposition");
|
||||
expect(finding).toBeDefined();
|
||||
expect(finding?.severity).toBe("error");
|
||||
expect(finding?.elementId).toBe("v1");
|
||||
expect(finding?.message).toContain("sub-composition");
|
||||
expect(finding).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not flag media in a host-root (non-sub) composition", async () => {
|
||||
|
||||
@@ -396,29 +396,6 @@ export const mediaRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> =
|
||||
return findings;
|
||||
},
|
||||
|
||||
// media_in_subcomposition — <video>/<audio> only render as a DIRECT child of the host
|
||||
// root (index.html). Inside a sub-composition <template> the runtime never seeks/decodes
|
||||
// them, so they render BLANK/black in preview and renders — and the other lint/validate
|
||||
// passes otherwise miss it (only a per-frame snapshot reveals the blank panel).
|
||||
({ tags, options }) => {
|
||||
const findings: HyperframeLintFinding[] = [];
|
||||
if (!options.isSubComposition) return findings;
|
||||
for (const tag of tags) {
|
||||
if (tag.name !== "video" && tag.name !== "audio") continue;
|
||||
const elementId = readAttr(tag.raw, "id") || undefined;
|
||||
findings.push({
|
||||
code: "media_in_subcomposition",
|
||||
severity: "error",
|
||||
message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> is inside a sub-composition. The runtime only drives media that is a DIRECT child of the host root (index.html); media inside a sub-comp <template> is never seeked/decoded and renders BLANK/black in preview and renders.`,
|
||||
elementId,
|
||||
fixHint:
|
||||
"Move the media OUT of the sub-composition: place the <video>/<audio> as a direct child of #root in index.html, positioned over the scene, and drive any per-scene motion on the MAIN timeline at global time (a sub-comp timeline cannot reach host elements). See composition-patterns.md archetype B.",
|
||||
snippet: truncateSnippet(tag.raw),
|
||||
});
|
||||
}
|
||||
return findings;
|
||||
},
|
||||
|
||||
// self_closing_media_tag
|
||||
({ source }) => {
|
||||
const findings: HyperframeLintFinding[] = [];
|
||||
|
||||
Reference in New Issue
Block a user