@hyperframes/lint 0.7.41 → 0.7.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +121 -0
- package/dist/browser.js.map +1 -1
- package/dist/index.js +127 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts","../src/context.ts","../src/rules/core.ts","../src/rules/media.ts","../src/rules/gsap.ts","../src/rules/captions.ts","../src/rules/composition.ts","../src/rules/adapters.ts","../src/rules/textures.ts","../src/rules/fonts.ts","../src/rules/slideshow.ts","../src/hyperframeLinter.ts","../src/shouldBlockRender.ts"],"sourcesContent":["// Shared types, regex constants, and utility functions used across lint rule modules.\n// Nothing in this file should emit findings — it only parses and extracts.\n\nexport type OpenTag = {\n raw: string;\n name: string;\n attrs: string;\n index: number;\n};\n\nexport type ExtractedBlock = {\n attrs: string;\n content: string;\n raw: string;\n index: number;\n};\n\nconst TAG_PATTERN = /<([a-z][\\w:-]*)(\\s[^<>]*?)?>/gi;\nexport const STYLE_BLOCK_PATTERN = /<style\\b([^>]*)>([\\s\\S]*?)<\\/style>/gi;\nexport const SCRIPT_BLOCK_PATTERN = /<script\\b([^>]*)>([\\s\\S]*?)<\\/script>/gi;\nconst COMPOSITION_ID_IN_CSS_PATTERN = /\\[data-composition-id=[\"']([^\"']+)[\"']\\]/g;\nexport const TIMELINE_REGISTRY_INIT_PATTERN =\n /window\\.__timelines\\s*=\\s*window\\.__timelines\\s*\\|\\|\\s*\\{\\}|window\\.__timelines\\s*=\\s*\\{\\}|window\\.__timelines\\s*\\?\\?=\\s*\\{\\}/i;\n// Object-literal registration that assigns at least one `key: value` entry inline,\n// e.g. `window.__timelines = { main: tl }` or `window.__timelines = { \"comp-1\": tl }`.\n// Distinct from the empty-init form (`= {}`) — requires a key followed by `:`.\nexport const TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN =\n /window\\.__timelines\\s*=\\s*\\{\\s*(?:[\"'][^\"']+[\"']|[A-Za-z_$][\\w$]*)\\s*:/i;\nexport const TIMELINE_REGISTRY_ASSIGN_PATTERN =\n /window\\.__timelines(?:\\[[^\\]]+\\]|\\.[A-Za-z_$][\\w$]*)\\s*=/i;\n// The bracket branch accepts either a quoted string key (`[\"root\"]`) or a\n// computed key (`[spec.id]`, `[id]`) — a bare-identifier-only bracket branch\n// missed `window.__timelines[spec.id] = tl`, a pattern the shipped\n// code-particle-assemble/code-3d-extrude registry blocks actually use,\n// making gsap_timeline_not_registered false-fire on correctly registered\n// timelines. The computed-key alternative is deliberately non-capturing:\n// its text isn't a literal composition id, so callers reading group 1/2\n// (readRegisteredTimelineCompositionId) must keep falling back to null for it.\nexport const WINDOW_TIMELINE_ASSIGN_PATTERN =\n /window\\.__timelines(?:\\[\\s*(?:[\"']([^\"']+)[\"']|[A-Za-z_$][\\w$.]*)\\s*\\]|\\.\\s*([A-Za-z_$][\\w$]*))\\s*=\\s*([A-Za-z_$][\\w$]*)/i;\nexport const INVALID_SCRIPT_CLOSE_PATTERN = /<script[^>]*>[\\s\\S]*?<\\s*\\/\\s*script(?!>)/i;\n\nconst TIMELINE_REGISTRY_KEY_PATTERN =\n /window\\.__timelines(?:\\[\\s*[\"']([^\"']+)[\"']\\s*\\]|\\.\\s*([A-Za-z_$][\\w$]*))\\s*=/g;\n\n// The `window.__timelines = { ... }` object-literal body (group 1), captured so its\n// `key: value` entries can be scanned for registered keys.\nconst TIMELINE_REGISTRY_OBJECT_BODY_PATTERN = /window\\.__timelines\\s*=\\s*\\{([\\s\\S]*?)\\}/i;\n// A single object-literal entry whose value is an identifier (real timeline registration),\n// e.g. `main: tl` or `\"comp-1\": tl`. Captures the key in group 1 (quoted) or 2 (bare).\nconst TIMELINE_REGISTRY_OBJECT_ENTRY_PATTERN =\n /(?:[\"']([^\"']+)[\"']|([A-Za-z_$][\\w$]*))\\s*:\\s*[A-Za-z_$][\\w$]*/g;\n\nexport function extractOpenTags(source: string): OpenTag[] {\n const tags: OpenTag[] = [];\n let match: RegExpExecArray | null;\n const pattern = new RegExp(TAG_PATTERN.source, TAG_PATTERN.flags);\n while ((match = pattern.exec(source)) !== null) {\n const raw = match[0];\n if (raw.startsWith(\"</\") || raw.startsWith(\"<!\")) continue;\n tags.push({\n raw,\n name: (match[1] || \"\").toLowerCase(),\n attrs: match[2] || \"\",\n index: match.index,\n });\n }\n return tags;\n}\n\nexport function extractBlocks(source: string, pattern: RegExp): ExtractedBlock[] {\n const blocks: ExtractedBlock[] = [];\n let match: RegExpExecArray | null;\n const p = new RegExp(pattern.source, pattern.flags);\n while ((match = p.exec(source)) !== null) {\n blocks.push({\n attrs: match[1] || \"\",\n content: match[2] || \"\",\n raw: match[0],\n index: match.index,\n });\n }\n return blocks;\n}\n\n/**\n * Find the `<html>` open tag in the source. Distinct from `findRootTag`,\n * which returns the first element inside `<body>` — the latter is \"the\n * composition's visible root\", whereas `<html>` is where document-level\n * metadata like `data-composition-variables` lives.\n */\nexport function findHtmlTag(source: string): OpenTag | null {\n const match = /<html\\b([^<>]*)>/i.exec(source);\n if (!match) return null;\n return {\n raw: match[0],\n name: \"html\",\n attrs: match[1] ?? \"\",\n index: match.index,\n };\n}\n\n// fallow-ignore-next-line complexity\nexport function findRootTag(source: string): OpenTag | null {\n const bodyOpenMatch = /<body\\b([^>]*)>/i.exec(source);\n const bodyCloseMatch = /<\\/body>/i.exec(source);\n if (\n bodyOpenMatch &&\n (readAttr(bodyOpenMatch[0], \"data-composition-id\") ||\n readAttr(bodyOpenMatch[0], \"data-width\") ||\n readAttr(bodyOpenMatch[0], \"data-height\"))\n ) {\n return {\n raw: bodyOpenMatch[0],\n name: \"body\",\n attrs: bodyOpenMatch[1] ?? \"\",\n index: bodyOpenMatch.index,\n };\n }\n const bodyStart = bodyOpenMatch ? bodyOpenMatch.index + bodyOpenMatch[0].length : 0;\n const bodyEnd =\n bodyOpenMatch && bodyCloseMatch && bodyCloseMatch.index > bodyStart\n ? bodyCloseMatch.index\n : source.length;\n const bodyContent = bodyOpenMatch ? source.slice(bodyStart, bodyEnd) : source;\n const bodyTags = extractOpenTags(bodyContent);\n // Set when a leading <svg> defs block is skipped (see below) — extractOpenTags\n // is a flat, nesting-unaware scan, so without this the very next tag it\n // returns is the svg's own nested child (<defs>, <filter>, ...), not the\n // sibling that follows the closed </svg>.\n let skipBefore = -1;\n for (const tag of bodyTags) {\n if (tag.index < skipBefore) continue;\n if ([\"script\", \"style\", \"meta\", \"link\", \"title\"].includes(tag.name)) continue;\n // A leading <svg> block (icon/gradient/filter <defs>, referenced by url(#id)\n // from elsewhere in the document) is shared visual plumbing, not the\n // composition root — two independent reports of this being mistaken for\n // the root, manufacturing root_missing_composition_id/root_missing_dimensions\n // on an otherwise-correct composition. Only skip it when it carries none of\n // the composition markers itself, so an intentionally SVG-rooted composition\n // (data-composition-id/data-width/data-height directly on the <svg>) is\n // still eligible as the root.\n if (\n tag.name === \"svg\" &&\n !readAttr(tag.raw, \"data-composition-id\") &&\n !readAttr(tag.raw, \"data-width\") &&\n !readAttr(tag.raw, \"data-height\")\n ) {\n const closeMatch = /<\\/svg\\s*>/i.exec(bodyContent.slice(tag.index));\n // No closing tag found (malformed HTML) — skip everything rather than\n // risk returning one of the svg's own children as the root.\n skipBefore = closeMatch ? tag.index + closeMatch.index + closeMatch[0].length : Infinity;\n continue;\n }\n return { ...tag, index: tag.index + bodyStart };\n }\n return null;\n}\n\nexport function readAttr(tagSource: string, attr: string): string | null {\n if (!tagSource) return null;\n const escaped = attr.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n // `(?<![\\w-])` not `\\b`: a plain `\\b` boundary treats the hyphen in a longer\n // attribute as a word break, so reading \"id\" would wrongly match the trailing\n // `id=\"…\"` inside `data-hf-id=\"…\"` (and \"width\" inside `data-width`, etc.).\n // The lookbehind requires the match to start a fresh attribute name.\n const match = tagSource.match(new RegExp(`(?<![\\\\w-])${escaped}\\\\s*=\\\\s*[\"']([^\"']+)[\"']`, \"i\"));\n return match?.[1] || null;\n}\n\n/**\n * Read an attribute that may legitimately contain the opposite quote\n * character. `readAttr` truncates `data-variable-values='{\"title\":\"Hello\"}'`\n * at the first internal `\"` because its `[^\"']+` class excludes both quote\n * types. This variant alternates: a double-quoted value never contains an\n * unescaped `\"`, and a single-quoted value never contains an unescaped `'`,\n * so each branch can use a quote-specific class.\n *\n * Use for attributes whose values are JSON or otherwise carry the opposite\n * quote character. Existing single-token attributes (`id`, `class`, etc.)\n * stick with `readAttr` for consistency with the rest of the lint code.\n */\nexport function readJsonAttr(tagSource: string, attr: string): string | null {\n if (!tagSource) return null;\n const escaped = attr.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n // See readAttr: `(?<![\\w-])` prevents a short name from matching the tail of a\n // longer hyphenated attribute (e.g. \"id\" inside `data-hf-id`).\n const match = tagSource.match(\n new RegExp(`(?<![\\\\w-])${escaped}\\\\s*=\\\\s*(?:\"([^\"]*)\"|'([^']*)')`, \"i\"),\n );\n if (!match) return null;\n return match[1] ?? match[2] ?? null;\n}\n\nexport function collectCompositionIds(tags: OpenTag[]): Set<string> {\n const ids = new Set<string>();\n for (const tag of tags) {\n const compId = readAttr(tag.raw, \"data-composition-id\");\n if (compId) ids.add(compId);\n }\n return ids;\n}\n\nexport function extractCompositionIdsFromCss(css: string): string[] {\n const ids = new Set<string>();\n let match: RegExpExecArray | null;\n const pattern = new RegExp(\n COMPOSITION_ID_IN_CSS_PATTERN.source,\n COMPOSITION_ID_IN_CSS_PATTERN.flags,\n );\n while ((match = pattern.exec(css)) !== null) {\n if (match[1]) ids.add(match[1]);\n }\n return [...ids];\n}\n\nexport function extractTimelineRegistryKeys(source: string): string[] {\n const keys = new Set<string>();\n let match: RegExpExecArray | null;\n const pattern = new RegExp(\n TIMELINE_REGISTRY_KEY_PATTERN.source,\n TIMELINE_REGISTRY_KEY_PATTERN.flags,\n );\n while ((match = pattern.exec(source)) !== null) {\n const key = match[1] ?? match[2];\n if (key) keys.add(key);\n }\n const objectBody = TIMELINE_REGISTRY_OBJECT_BODY_PATTERN.exec(source)?.[1];\n if (objectBody) {\n const entryPattern = new RegExp(\n TIMELINE_REGISTRY_OBJECT_ENTRY_PATTERN.source,\n TIMELINE_REGISTRY_OBJECT_ENTRY_PATTERN.flags,\n );\n while ((match = entryPattern.exec(objectBody)) !== null) {\n const key = match[1] ?? match[2];\n if (key) keys.add(key);\n }\n }\n return [...keys];\n}\n\nexport function getInlineScriptSyntaxError(source: string): string | null {\n if (!source.trim()) return null;\n try {\n // eslint-disable-next-line no-new-func\n new Function(source);\n return null;\n } catch (error) {\n if (error instanceof Error) return error.message;\n return String(error);\n }\n}\n\n// fallow-ignore-next-line complexity\nexport function stripJsComments(source: string): string {\n let out = \"\";\n let i = 0;\n let quote: \"'\" | '\"' | \"`\" | null = null;\n let escaped = false;\n\n while (i < source.length) {\n const ch = source[i] ?? \"\";\n const next = source[i + 1] ?? \"\";\n\n if (quote) {\n out += ch;\n if (escaped) {\n escaped = false;\n } else if (ch === \"\\\\\") {\n escaped = true;\n } else if (ch === quote) {\n quote = null;\n }\n i += 1;\n continue;\n }\n\n if (ch === \"'\" || ch === '\"' || ch === \"`\") {\n quote = ch;\n out += ch;\n i += 1;\n continue;\n }\n\n if (ch === \"/\" && next === \"/\") {\n out += \" \";\n i += 2;\n while (i < source.length && source[i] !== \"\\n\" && source[i] !== \"\\r\") {\n out += \" \";\n i += 1;\n }\n continue;\n }\n\n if (ch === \"/\" && next === \"*\") {\n out += \" \";\n i += 2;\n while (i < source.length) {\n const blockCh = source[i] ?? \"\";\n const blockNext = source[i + 1] ?? \"\";\n if (blockCh === \"*\" && blockNext === \"/\") {\n out += \" \";\n i += 2;\n break;\n }\n out += blockCh === \"\\n\" || blockCh === \"\\r\" ? blockCh : \" \";\n i += 1;\n }\n continue;\n }\n\n out += ch;\n i += 1;\n }\n\n return out;\n}\n\n// One linear pass that drops every `<!-- … -->` region. Uses indexOf, not a\n// `/<!--[\\s\\S]*?-->/` regex: that pattern backtracks O(n²) on inputs with many\n// unterminated \"<!--\" (CodeQL js/polynomial-redos). An unterminated \"<!--\" with\n// no closing \"-->\" is kept verbatim, matching the prior regex's no-match behavior.\nfunction stripHtmlCommentsOnce(source: string): string {\n let out = \"\";\n let i = 0;\n for (;;) {\n const start = source.indexOf(\"<!--\", i);\n if (start < 0) return out + source.slice(i);\n const end = source.indexOf(\"-->\", start + 4);\n if (end < 0) return out + source.slice(i);\n out += source.slice(i, start);\n i = end + 3;\n }\n}\n\n// Strip HTML comments to a fixpoint. A single pass is not enough: deleting one\n// comment can splice adjacent markers into a fresh, complete <!-- … --> (e.g.\n// \"<<!-- -->!-- … -->\" → \"<!-- … -->\"), which would otherwise survive and let a\n// commented-out <template>/tag hijack the linter's tag scan.\nexport function stripHtmlComments(source: string): string {\n let out = source;\n for (let prev = \"\"; prev !== out; ) {\n prev = out;\n out = stripHtmlCommentsOnce(out);\n }\n return out;\n}\n\nexport function extractScriptTextsAndSrcs(scripts: ExtractedBlock[]): {\n texts: string[];\n srcs: string[];\n} {\n const texts = scripts.filter((s) => !/\\bsrc\\s*=/.test(s.attrs)).map((s) => s.content);\n const srcs = scripts.map((s) => readAttr(`<script ${s.attrs}>`, \"src\") || \"\").filter(Boolean);\n return { texts, srcs };\n}\n\nexport function isMediaTag(tagName: string): boolean {\n return tagName === \"video\" || tagName === \"audio\" || tagName === \"img\";\n}\n\n// Whether any <style> block in the composition defines caption group/word\n// classes (`.caption-group`, `.caption_word`, etc.) — the signal several\n// caption-specific rules use to skip non-caption compositions entirely.\nexport function hasCaptionStyles(styles: ExtractedBlock[]): boolean {\n return styles.some((s) => /\\.caption[-_]?(?:group|word)/i.test(s.content));\n}\n\nexport function truncateSnippet(value: string, maxLength = 220): string | undefined {\n const normalized = value.replace(/\\s+/g, \" \").trim();\n if (!normalized) return undefined;\n if (normalized.length <= maxLength) return normalized;\n return `${normalized.slice(0, maxLength - 3)}...`;\n}\n","import type { HyperframeLintFinding, HyperframeLinterOptions } from \"./types\";\nimport {\n extractBlocks,\n extractOpenTags,\n findRootTag,\n collectCompositionIds,\n readAttr,\n stripHtmlComments,\n STYLE_BLOCK_PATTERN,\n SCRIPT_BLOCK_PATTERN,\n} from \"./utils\";\nimport type { OpenTag, ExtractedBlock } from \"./utils\";\n\nexport type { OpenTag, ExtractedBlock };\n\nexport type LintContext = {\n source: string;\n rawSource: string;\n tags: OpenTag[];\n styles: ExtractedBlock[];\n scripts: ExtractedBlock[];\n compositionIds: Set<string>;\n rootTag: OpenTag | null;\n rootCompositionId: string | null;\n options: HyperframeLinterOptions;\n};\n\n// Re-export for convenience so rule modules only need one import for the finding type\nexport type { HyperframeLintFinding };\n\nexport function buildLintContext(html: string, options: HyperframeLinterOptions = {}): LintContext {\n const rawSource = html || \"\";\n // Strip HTML comments before scanning so a commented-out <template> or tag can't\n // hijack the boundary match below. Linear + fixpoint (see stripHtmlComments) to\n // stay ReDoS-free and catch markers that re-form when a comment is removed.\n let source = stripHtmlComments(rawSource);\n const sourceWithoutTemplates = source.replace(\n /<template\\b[^>]*>[\\s\\S]*?<\\/template(?:\\s[^>]*)?>/gi,\n \" \",\n );\n const templateMatch = source.match(/<template[^>]*>([\\s\\S]*)<\\/template>/i);\n // Some sub-composition files are HTML shells whose real root lives inside a\n // <template>. Keep nested templates intact when the visible document already\n // has a composition root; only unwrap when no root exists outside templates.\n if (templateMatch?.[1] && !findRootTag(sourceWithoutTemplates)) source = templateMatch[1];\n\n const tags = extractOpenTags(source);\n const styles = [\n ...extractBlocks(source, STYLE_BLOCK_PATTERN),\n ...(options.externalStyles ?? []).map((style) => ({\n attrs: `href=\"${style.href}\"`,\n content: style.content,\n raw: style.content,\n index: -1,\n })),\n ];\n const scripts = extractBlocks(source, SCRIPT_BLOCK_PATTERN);\n const compositionIds = collectCompositionIds(tags);\n const rootTag = findRootTag(source);\n const rootCompositionId = readAttr(rootTag?.raw || \"\", \"data-composition-id\");\n\n return {\n source,\n rawSource,\n tags,\n styles,\n scripts,\n compositionIds,\n rootTag,\n rootCompositionId,\n options,\n };\n}\n","import type { LintContext, HyperframeLintFinding } from \"../context\";\nimport postcss from \"postcss\";\nimport {\n readAttr,\n truncateSnippet,\n stripJsComments,\n extractCompositionIdsFromCss,\n extractTimelineRegistryKeys,\n getInlineScriptSyntaxError,\n TIMELINE_REGISTRY_INIT_PATTERN,\n TIMELINE_REGISTRY_ASSIGN_PATTERN,\n TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN,\n INVALID_SCRIPT_CLOSE_PATTERN,\n} from \"../utils\";\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction selectorTargetsCompositionId(selector: string, compositionId: string): boolean {\n const escaped = escapeRegExp(compositionId);\n return new RegExp(\n String.raw`\\[\\s*data-composition-id\\s*=\\s*(?:\"${escaped}\"|'${escaped}')\\s*\\]`,\n ).test(selector);\n}\n\nfunction isStudioTimelineElement(tag: { raw: string; name: string }): boolean {\n if ([\"script\", \"style\", \"link\", \"meta\", \"template\", \"noscript\"].includes(tag.name)) {\n return false;\n }\n return Boolean(\n readAttr(tag.raw, \"data-start\") ||\n readAttr(tag.raw, \"data-track-index\") ||\n readAttr(tag.raw, \"data-track\") ||\n readAttr(tag.raw, \"data-composition-src\") ||\n readAttr(tag.raw, \"data-composition-file\"),\n );\n}\n\nfunction describeStudioElement(tag: { raw: string; name: string }): string {\n const parts = [`<${tag.name}`];\n const className = readAttr(tag.raw, \"class\");\n const compositionId = readAttr(tag.raw, \"data-composition-id\");\n const dataStart = readAttr(tag.raw, \"data-start\");\n const dataTrack = readAttr(tag.raw, \"data-track-index\") ?? readAttr(tag.raw, \"data-track\");\n\n if (className) {\n const primaryClass = className\n .split(/\\s+/)\n .map((value) => value.trim())\n .find((value) => value && value !== \"clip\");\n if (primaryClass) parts.push(` class=\"${primaryClass}\"`);\n }\n if (compositionId) parts.push(` data-composition-id=\"${compositionId}\"`);\n if (dataStart) parts.push(` data-start=\"${dataStart}\"`);\n if (dataTrack) parts.push(` data-track-index=\"${dataTrack}\"`);\n parts.push(\">\");\n return parts.join(\"\");\n}\n\nconst HEAD_BLOCKS_TO_IGNORE_PATTERN =\n /<(?:style|script|template|title|noscript)\\b[^>]*>[\\s\\S]*?<\\/(?:style|script|template|title|noscript)(?:\\s[^>]*)?>/gi;\nconst HTML_TAG_PATTERN = /<[^>]+>/g;\nconst HEAD_CONTENT_PATTERN = /<head\\b[^>]*>([\\s\\S]*?)(?:<\\/head>|<body\\b|$)/gi;\nconst AFTER_HEAD_BEFORE_BODY_PATTERN = /<\\/head(?:\\s[^>]*)?>([\\s\\S]*?)(?=<body\\b|$)/gi;\nconst STRAY_HEAD_CLOSE_PATTERN = /<\\/(?:style|script)(?:\\s[^>]*)?>/i;\nconst MARKDOWN_CODE_FENCE_PATTERN = /```[^\\r\\n`]*(?:\\r?\\n|$)[\\s\\S]*?```/i;\nconst ORPHAN_CSS_AT_RULE_PATTERN =\n /(?:^|\\s)@(?:container|font-face|keyframes|layer|media|page|property|scope|supports)[^{<]*\\{[\\s\\S]*?:[\\s\\S]*?\\}/i;\nconst ORPHAN_CSS_RULE_PATTERN =\n /(?:^|\\s)(?:\\/\\*[\\s\\S]*?\\*\\/\\s*)?(?:@[a-z-]+[^{}<]*|[.#][\\w-]+[^{}<]*|[a-z][\\w-]*(?:\\s+[.#:[\\w-][^{}<]*)?)\\s*\\{[^{}]*:[^{}]*\\}/i;\nconst VISIBLE_MARKUP_COMMENT_PATTERN = /\\/\\*[\\s\\S]*?\\*\\//g;\nconst VISIBLE_MARKUP_COMMENT_PROTECTED_BLOCK_PATTERN =\n /<(style|script|template|title|noscript|pre|code|textarea|text)\\b[^>]*>[\\s\\S]*?<\\/\\1(?:\\s[^>]*)?>/gi;\n\ninterface SourceRange {\n start: number;\n end: number;\n}\n\nfunction findCodeFenceLeak(headWithoutValidBlocks: string): string | null {\n return MARKDOWN_CODE_FENCE_PATTERN.exec(headWithoutValidBlocks)?.[0] ?? null;\n}\n\nfunction findOrphanCssLeak(headContent: string): string | null {\n const residualText = headContent\n .replace(HEAD_BLOCKS_TO_IGNORE_PATTERN, \" \")\n .replace(HTML_TAG_PATTERN, \" \");\n return (\n ORPHAN_CSS_AT_RULE_PATTERN.exec(residualText)?.[0] ??\n ORPHAN_CSS_RULE_PATTERN.exec(residualText)?.[0] ??\n null\n );\n}\n\nfunction findStrayCloseLeak(headWithoutValidBlocks: string): string | null {\n return STRAY_HEAD_CLOSE_PATTERN.exec(headWithoutValidBlocks)?.[0] ?? null;\n}\n\nfunction findLeakedTextInHeadContent(headContent: string): string | null {\n const withoutValidBlocks = headContent.replace(HEAD_BLOCKS_TO_IGNORE_PATTERN, \" \");\n return (\n findCodeFenceLeak(withoutValidBlocks) ??\n findOrphanCssLeak(headContent) ??\n findStrayCloseLeak(withoutValidBlocks)\n );\n}\n\nfunction findLeakedTextInHead(rawSource: string): string | null {\n const headMatches = [...rawSource.matchAll(HEAD_CONTENT_PATTERN)];\n for (const match of headMatches) {\n const leakedText = findLeakedTextInHeadContent(match[1] ?? \"\");\n if (leakedText) return leakedText;\n }\n return null;\n}\n\nfunction findLeakedTextBetweenHeadAndBody(rawSource: string): string | null {\n const boundaryMatches = [...rawSource.matchAll(AFTER_HEAD_BEFORE_BODY_PATTERN)];\n for (const match of boundaryMatches) {\n const leakedText = findLeakedTextInHeadContent(match[1] ?? \"\");\n if (leakedText) return leakedText;\n }\n return null;\n}\n\nfunction findLeakedTextBeforeCompositionRoot(\n source: string,\n rootTag: LintContext[\"rootTag\"],\n): string | null {\n if (!rootTag || rootTag.name === \"body\") return null;\n const bodyOpenMatch = /<body\\b[^>]*>/i.exec(source);\n const prefixStart = bodyOpenMatch ? bodyOpenMatch.index + bodyOpenMatch[0].length : 0;\n const prefixEnd = rootTag.index;\n if (prefixEnd <= prefixStart) return null;\n return findLeakedTextInHeadContent(source.slice(prefixStart, prefixEnd));\n}\n\nfunction findProtectedVisibleMarkupRanges(source: string): SourceRange[] {\n const ranges: SourceRange[] = [];\n for (const match of source.matchAll(VISIBLE_MARKUP_COMMENT_PROTECTED_BLOCK_PATTERN)) {\n ranges.push({ start: match.index, end: match.index + match[0].length });\n }\n return ranges;\n}\n\nfunction isInsideSourceRange(index: number, ranges: SourceRange[]): boolean {\n return ranges.some((range) => range.start <= index && index < range.end);\n}\n\nfunction isInsideHtmlTag(source: string, index: number): boolean {\n let inTag = false;\n let quote: '\"' | \"'\" | null = null;\n for (let i = 0; i < index; i++) {\n const char = source[i];\n if (!inTag) {\n if (char === \"<\") inTag = true;\n continue;\n }\n if (quote) {\n if (char === quote) quote = null;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n } else if (char === \">\") {\n inTag = false;\n }\n }\n return inTag;\n}\n\nfunction findVisibleMarkupCommentLeak(source: string): string | null {\n const protectedRanges = findProtectedVisibleMarkupRanges(source);\n for (const match of source.matchAll(VISIBLE_MARKUP_COMMENT_PATTERN)) {\n if (isInsideHtmlTag(source, match.index)) continue;\n if (isInsideSourceRange(match.index, protectedRanges)) continue;\n return match[0];\n }\n return null;\n}\n\nexport const coreRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // root_missing_composition_id + root_missing_dimensions\n ({ rootTag }) => {\n const findings: HyperframeLintFinding[] = [];\n if (!rootTag || !readAttr(rootTag.raw, \"data-composition-id\")) {\n findings.push({\n code: \"root_missing_composition_id\",\n severity: \"error\",\n message: \"Root composition is missing `data-composition-id`.\",\n elementId: rootTag ? readAttr(rootTag.raw, \"id\") || undefined : undefined,\n fixHint: \"Add a stable `data-composition-id` to the entry composition wrapper.\",\n snippet: truncateSnippet(rootTag?.raw || \"\"),\n });\n }\n if (!rootTag || !readAttr(rootTag.raw, \"data-width\") || !readAttr(rootTag.raw, \"data-height\")) {\n findings.push({\n code: \"root_missing_dimensions\",\n severity: \"error\",\n message: \"Root composition is missing `data-width` or `data-height`.\",\n elementId: rootTag ? readAttr(rootTag.raw, \"id\") || undefined : undefined,\n fixHint: \"Set numeric `data-width` and `data-height` on the entry composition root.\",\n snippet: truncateSnippet(rootTag?.raw || \"\"),\n });\n }\n return findings;\n },\n\n // head_leaked_text\n ({ source, rootTag }) => {\n const snippet =\n findLeakedTextInHead(source) ??\n findLeakedTextBetweenHeadAndBody(source) ??\n findLeakedTextBeforeCompositionRoot(source, rootTag);\n if (!snippet) return [];\n return [\n {\n code: \"head_leaked_text\",\n severity: \"error\",\n message:\n \"Detected leaked code or CSS text around the document `<head>` or before the composition root. Browsers render this as visible text in the video.\",\n fixHint:\n \"Move CSS into a single `<style>...</style>` block and remove stray close tags, markdown fences, or code text from `<head>`, the `</head>`/`<body>` boundary, or the pre-root body prefix.\",\n snippet: truncateSnippet(snippet),\n },\n ];\n },\n\n // visible_markup_comment\n ({ source }) => {\n const snippet = findVisibleMarkupCommentLeak(source);\n if (!snippet) return [];\n return [\n {\n code: \"visible_markup_comment\",\n severity: \"error\",\n message:\n \"CSS/JS block comment syntax (`/* ... */`) appears in visible HTML markup. HTML only treats `<!-- ... -->` as comments, so this renders as on-screen text.\",\n fixHint:\n \"Remove the text or convert it to a real HTML comment (`<!-- ... -->`). Keep CSS comments inside `<style>` and JS comments inside `<script>`.\",\n snippet: truncateSnippet(snippet),\n },\n ];\n },\n\n // missing_timeline_registry + timeline_registry_missing_init\n ({ source, rawSource, options }) => {\n // Sub-compositions inherit window.__timelines from the host composition\n if (options.isSubComposition || rawSource.trimStart().toLowerCase().startsWith(\"<template\")) {\n return [];\n }\n const findings: HyperframeLintFinding[] = [];\n if (\n !TIMELINE_REGISTRY_INIT_PATTERN.test(source) &&\n !TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source) &&\n !TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN.test(source)\n ) {\n findings.push({\n code: \"missing_timeline_registry\",\n severity: \"error\",\n message: \"Missing `window.__timelines` registration.\",\n fixHint: \"Register each composition timeline on `window.__timelines[compositionId]`.\",\n });\n }\n if (\n TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source) &&\n !TIMELINE_REGISTRY_INIT_PATTERN.test(source)\n ) {\n findings.push({\n code: \"timeline_registry_missing_init\",\n severity: \"error\",\n message:\n \"`window.__timelines[…] = …` is used without initializing `window.__timelines` first.\",\n fixHint:\n \"Add `window.__timelines = window.__timelines || {};` before any timeline assignment.\",\n });\n }\n return findings;\n },\n\n // timeline_id_mismatch\n ({ source }) => {\n const findings: HyperframeLintFinding[] = [];\n const htmlCompIds = new Set<string>();\n const timelineRegKeys = new Set<string>();\n const compIdRe = /data-composition-id\\s*=\\s*[\"']([^\"']+)[\"']/gi;\n let m: RegExpExecArray | null;\n while ((m = compIdRe.exec(source)) !== null) {\n if (m[1]) htmlCompIds.add(m[1]);\n }\n for (const key of extractTimelineRegistryKeys(source)) {\n timelineRegKeys.add(key);\n }\n for (const key of timelineRegKeys) {\n if (!htmlCompIds.has(key)) {\n findings.push({\n code: \"timeline_id_mismatch\",\n severity: \"error\",\n message: `Timeline registered as \"${key}\" but no element has data-composition-id=\"${key}\". The runtime cannot auto-nest this timeline.`,\n fixHint: `Change window.__timelines[\"${key}\"] to match the data-composition-id attribute, or vice versa.`,\n });\n }\n }\n return findings;\n },\n\n // invalid_inline_script_syntax (malformed close tag)\n ({ source }) => {\n if (!INVALID_SCRIPT_CLOSE_PATTERN.test(source)) return [];\n return [\n {\n code: \"invalid_inline_script_syntax\",\n severity: \"error\",\n message: \"Detected malformed inline `<script>` closing syntax.\",\n fixHint: \"Close inline scripts with a valid `</script>` tag.\",\n },\n ];\n },\n\n // invalid_inline_script_syntax (JS parse error)\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const script of scripts) {\n const attrs = script.attrs || \"\";\n if (\n /\\bsrc\\s*=/.test(attrs) ||\n /\\btype\\s*=\\s*[\"'](?:application\\/json|application\\/hyperframes-slideshow\\+json|importmap|module)[\"']/.test(\n attrs,\n )\n )\n continue;\n const syntaxError = getInlineScriptSyntaxError(script.content);\n if (!syntaxError) continue;\n findings.push({\n code: \"invalid_inline_script_syntax\",\n severity: \"error\",\n message: `Inline script has invalid syntax: ${syntaxError}`,\n fixHint: \"Fix the inline script syntax before render verification.\",\n snippet: truncateSnippet(script.content),\n });\n }\n return findings;\n },\n\n // host_missing_composition_id\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n const src = readAttr(tag.raw, \"data-composition-src\");\n if (!src) continue;\n if (readAttr(tag.raw, \"data-composition-id\")) continue;\n findings.push({\n code: \"host_missing_composition_id\",\n severity: \"error\",\n message: `Composition host for \"${src}\" is missing \\`data-composition-id\\`.`,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint: \"Set `data-composition-id` on every `data-composition-src` host element.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n return findings;\n },\n\n // scoped_css_missing_wrapper\n ({ styles, compositionIds }) => {\n const findings: HyperframeLintFinding[] = [];\n const scopedCssCompositionIds = new Set<string>();\n for (const style of styles) {\n for (const compId of extractCompositionIdsFromCss(style.content)) {\n scopedCssCompositionIds.add(compId);\n }\n }\n for (const compId of scopedCssCompositionIds) {\n if (compositionIds.has(compId)) continue;\n findings.push({\n code: \"scoped_css_missing_wrapper\",\n severity: \"warning\",\n message: `Scoped CSS targets composition \"${compId}\" but no matching wrapper exists in this HTML.`,\n selector: `[data-composition-id=\"${compId}\"]`,\n fixHint:\n \"Preserve the matching composition wrapper or align the CSS scope to an existing wrapper.\",\n });\n }\n return findings;\n },\n\n // composition_self_attribute_selector\n ({ styles, rootCompositionId, rootTag }) => {\n const findings: HyperframeLintFinding[] = [];\n if (!rootCompositionId) return findings;\n const seenSelectors = new Set<string>();\n const rootId = readAttr(rootTag?.raw || \"\", \"id\");\n for (const style of styles) {\n let root: postcss.Root;\n try {\n root = postcss.parse(style.content);\n } catch {\n continue;\n }\n root.walkRules((rule) => {\n for (const selector of rule.selectors) {\n if (!selectorTargetsCompositionId(selector, rootCompositionId)) continue;\n if (seenSelectors.has(selector)) continue;\n seenSelectors.add(selector);\n findings.push({\n code: \"composition_self_attribute_selector\",\n severity: \"warning\",\n message:\n \"Selector matches the block's own id; will leak to sibling instances when the block is embedded twice.\",\n selector,\n fixHint: rootId\n ? `Use #${rootId} for clearer authoring intent and instance-isolated styling.`\n : \"Add a stable id to the composition root and use that id selector for clearer authoring intent and instance-isolated styling.\",\n });\n }\n });\n }\n return findings;\n },\n\n // studio_missing_editable_id\n ({ tags, rootTag }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (rootTag && tag.index === rootTag.index) continue;\n if (!isStudioTimelineElement(tag)) continue;\n if (readAttr(tag.raw, \"id\")) continue;\n\n const descriptor = describeStudioElement(tag);\n findings.push({\n code: \"studio_missing_editable_id\",\n severity: \"warning\",\n message: `${descriptor} has no id, so Studio cannot use a stable edit target for its timeline and canvas controls.`,\n selector: readAttr(tag.raw, \"data-composition-id\")\n ? `[data-composition-id=\"${readAttr(tag.raw, \"data-composition-id\")}\"]`\n : undefined,\n fixHint:\n 'Add a stable, human-readable id such as id=\"hero-title\" or id=\"scene-1-card\" to every timeline-visible element you want agents or Studio to edit.',\n snippet: truncateSnippet(tag.raw),\n });\n }\n return findings;\n },\n\n // non_deterministic_code\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n const patterns: Array<{ pattern: RegExp; label: string; hint: string }> = [\n {\n pattern: /Math\\.random\\s*\\(/,\n label: \"Math.random()\",\n hint: \"Use a seeded PRNG (e.g. a simple mulberry32) so renders are deterministic across frames.\",\n },\n {\n pattern: /Date\\.now\\s*\\(/,\n label: \"Date.now()\",\n hint: \"Remove time-dependent code. Use GSAP timeline position instead of wall-clock time.\",\n },\n {\n pattern: /new\\s+Date\\s*\\(/,\n label: \"new Date()\",\n hint: \"Remove time-dependent code. Use GSAP timeline position instead of wall-clock time.\",\n },\n {\n pattern: /performance\\.now\\s*\\(/,\n label: \"performance.now()\",\n hint: \"Remove time-dependent code. Use GSAP timeline position instead of wall-clock time.\",\n },\n {\n pattern: /crypto\\.getRandomValues\\s*\\(/,\n label: \"crypto.getRandomValues()\",\n hint: \"Remove time-dependent code. Use a seeded PRNG for deterministic renders.\",\n },\n ];\n\n for (const script of scripts) {\n const stripped = stripJsComments(script.content);\n for (const { pattern, label, hint } of patterns) {\n if (pattern.test(stripped)) {\n findings.push({\n code: \"non_deterministic_code\",\n severity: \"error\",\n message: `Script contains \\`${label}\\` which produces non-deterministic output. Renders may differ between frames or runs.`,\n fixHint: hint,\n snippet: truncateSnippet(script.content),\n });\n }\n }\n }\n return findings;\n },\n\n // pointer_events_none\n // fallow-ignore-next-line complexity\n ({ tags, styles }) => {\n const findings: HyperframeLintFinding[] = [];\n const reported = new Set<string>();\n\n for (const tag of tags) {\n if ([\"script\", \"style\", \"link\", \"meta\", \"template\", \"noscript\"].includes(tag.name)) continue;\n const inlineStyle = readAttr(tag.raw, \"style\") ?? \"\";\n if (!/pointer-events\\s*:\\s*none/i.test(inlineStyle)) continue;\n const id = readAttr(tag.raw, \"id\");\n const key = id ?? tag.raw;\n if (reported.has(key)) continue;\n reported.add(key);\n findings.push({\n code: \"pointer_events_none\",\n severity: \"info\",\n message: `<${tag.name}${id ? ` id=\"${id}\"` : \"\"}> has \\`pointer-events: none\\` in its inline style. Elements with this property are harder to select in the Studio preview.`,\n elementId: id || undefined,\n fixHint:\n \"If this element should be selectable in the Studio, remove `pointer-events: none` or move it to a wrapper that doesn't contain editable content.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n\n for (const style of styles) {\n let root: postcss.Root;\n try {\n root = postcss.parse(style.content);\n } catch {\n continue;\n }\n root.walkDecls(\"pointer-events\", (decl) => {\n if (decl.value.trim().toLowerCase() !== \"none\") return;\n const rule = decl.parent;\n if (!rule || rule.type !== \"rule\") return;\n const selector = (rule as postcss.Rule).selector;\n if (reported.has(selector)) return;\n reported.add(selector);\n findings.push({\n code: \"pointer_events_none\",\n severity: \"info\",\n message: `\\`${selector}\\` sets \\`pointer-events: none\\`. Elements matching this selector are harder to select in the Studio preview.`,\n selector,\n fixHint:\n \"If these elements should be selectable in the Studio, remove `pointer-events: none` or move it to a wrapper that doesn't contain editable content.\",\n });\n });\n }\n\n return findings;\n },\n];\n","import type { LintContext, HyperframeLintFinding } from \"../context\";\nimport { readAttr, truncateSnippet, isMediaTag } from \"../utils\";\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction hasAttrName(tagSource: string, attr: string): boolean {\n const escaped = escapeRegExp(attr);\n const attrs = tagSource.replace(/^<\\s*[a-z][\\w:-]*/i, \"\");\n return new RegExp(`(?:^|\\\\s)${escaped}(?:\\\\s*=|\\\\s|/?>)`, \"i\").test(attrs);\n}\n\nfunction classNamesFromAttr(classAttr: string | null): string[] {\n if (!classAttr) return [];\n return classAttr.split(/\\s+/).filter(Boolean);\n}\n\ntype MediaSelectorIndex = {\n ids: Set<string>;\n classes: Set<string>;\n hasVideo: boolean;\n hasAudio: boolean;\n};\n\nfunction selectorTargetsManagedMedia(selector: string, mediaIndex: MediaSelectorIndex): boolean {\n const normalized = selector.trim();\n if (!normalized) return false;\n if (mediaIndex.hasVideo && /\\bvideo\\b/i.test(normalized)) return true;\n if (mediaIndex.hasAudio && /\\baudio\\b/i.test(normalized)) return true;\n for (const mediaId of mediaIndex.ids) {\n const escapedId = escapeRegExp(mediaId);\n if (\n new RegExp(`#${escapedId}(?![\\\\w-])`).test(normalized) ||\n normalized.includes(`[id=\"${mediaId}\"]`) ||\n normalized.includes(`[id='${mediaId}']`)\n ) {\n return true;\n }\n }\n for (const className of mediaIndex.classes) {\n if (new RegExp(`\\\\.${escapeRegExp(className)}(?![\\\\w-])`).test(normalized)) {\n return true;\n }\n }\n return false;\n}\n\nfunction findImperativeMediaControlFindings(ctx: LintContext): HyperframeLintFinding[] {\n const findings: HyperframeLintFinding[] = [];\n const mediaTags = ctx.tags.filter((tag) => tag.name === \"video\" || tag.name === \"audio\");\n const mediaIndex: MediaSelectorIndex = {\n ids: new Set(\n mediaTags.map((tag) => readAttr(tag.raw, \"id\")).filter((id): id is string => Boolean(id)),\n ),\n classes: new Set(mediaTags.flatMap((tag) => classNamesFromAttr(readAttr(tag.raw, \"class\")))),\n hasVideo: mediaTags.some((tag) => tag.name === \"video\"),\n hasAudio: mediaTags.some((tag) => tag.name === \"audio\"),\n };\n\n if (mediaTags.length === 0 || ctx.scripts.length === 0) return findings;\n\n for (const script of ctx.scripts) {\n const mediaVars = new Map<string, string | undefined>();\n const assignmentPatterns = [\n {\n pattern:\n /\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*(?:document|window\\.document)\\.getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/g,\n variableIndex: 1,\n targetIndex: 2,\n },\n {\n pattern:\n /\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*(?:document|window\\.document)\\.querySelector\\(\\s*([\"'])([\\s\\S]*?)\\2\\s*\\)/g,\n variableIndex: 1,\n targetIndex: 3,\n },\n ];\n\n for (const { pattern, variableIndex, targetIndex } of assignmentPatterns) {\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(script.content)) !== null) {\n const variableName = match[variableIndex];\n const target = match[targetIndex];\n if (!variableName || !target) continue;\n if (mediaIndex.ids.has(target) || selectorTargetsManagedMedia(target, mediaIndex)) {\n mediaVars.set(variableName, mediaIndex.ids.has(target) ? target : undefined);\n }\n }\n }\n\n const directIdPatterns = [\n {\n pattern:\n /\\b(?:document|window\\.document)\\.getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)\\.play\\s*\\(/g,\n kind: \"play()\",\n targetIndex: 1,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)\\.pause\\s*\\(/g,\n kind: \"pause()\",\n targetIndex: 1,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)\\.currentTime\\s*=/g,\n kind: \"currentTime\",\n targetIndex: 1,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)\\.muted\\s*=/g,\n kind: \"muted assignment\",\n targetIndex: 1,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.querySelector\\(\\s*([\"'])([\\s\\S]*?)\\1\\s*\\)\\.play\\s*\\(/g,\n kind: \"play()\",\n targetIndex: 2,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.querySelector\\(\\s*([\"'])([\\s\\S]*?)\\1\\s*\\)\\.pause\\s*\\(/g,\n kind: \"pause()\",\n targetIndex: 2,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.querySelector\\(\\s*([\"'])([\\s\\S]*?)\\1\\s*\\)\\.currentTime\\s*=/g,\n kind: \"currentTime\",\n targetIndex: 2,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.querySelector\\(\\s*([\"'])([\\s\\S]*?)\\1\\s*\\)\\.muted\\s*=/g,\n kind: \"muted assignment\",\n targetIndex: 2,\n },\n ];\n\n for (const { pattern, kind, targetIndex } of directIdPatterns) {\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(script.content)) !== null) {\n const target = match[targetIndex];\n if (!target) continue;\n const elementId = mediaIndex.ids.has(target)\n ? target\n : selectorTargetsManagedMedia(target, mediaIndex)\n ? undefined\n : null;\n if (elementId === null) continue;\n findings.push({\n code: \"imperative_media_control\",\n severity: \"error\",\n message: `Inline <script> imperatively controls managed media via ${kind}. HyperFrames must own media play/pause/seek to keep preview, timeline, and renders deterministic.`,\n elementId: elementId || undefined,\n fixHint:\n \"Remove imperative media play/pause/currentTime/muted control. Express timing with data-start/data-duration and media offsets like data-media-start or data-playback-start instead.\",\n snippet: truncateSnippet(match[0]),\n });\n }\n }\n\n for (const [variableName, elementId] of mediaVars) {\n const escapedVar = escapeRegExp(variableName);\n const variablePatterns = [\n { pattern: new RegExp(`\\\\b${escapedVar}\\\\.play\\\\s*\\\\(`, \"g\"), kind: \"play()\" },\n { pattern: new RegExp(`\\\\b${escapedVar}\\\\.pause\\\\s*\\\\(`, \"g\"), kind: \"pause()\" },\n { pattern: new RegExp(`\\\\b${escapedVar}\\\\.currentTime\\\\s*=`, \"g\"), kind: \"currentTime\" },\n {\n pattern: new RegExp(`\\\\b${escapedVar}\\\\.muted\\\\s*=`, \"g\"),\n kind: \"muted assignment\",\n },\n ];\n for (const { pattern, kind } of variablePatterns) {\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(script.content)) !== null) {\n findings.push({\n code: \"imperative_media_control\",\n severity: \"error\",\n message: `Inline <script> imperatively controls managed media via ${kind}. HyperFrames must own media play/pause/seek to keep preview, timeline, and renders deterministic.`,\n elementId,\n fixHint:\n \"Remove imperative media play/pause/currentTime/muted control. Express timing with data-start/data-duration and media offsets like data-media-start or data-playback-start instead.\",\n snippet: truncateSnippet(match[0]),\n });\n }\n }\n }\n }\n\n return findings;\n}\n\nexport const mediaRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // duplicate_media_id + duplicate_media_discovery_risk\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const mediaById = new Map<string, typeof tags>();\n const mediaFingerprintCounts = new Map<string, number>();\n\n for (const tag of tags) {\n if (!isMediaTag(tag.name)) continue;\n const elementId = readAttr(tag.raw, \"id\");\n if (elementId) {\n const existing = mediaById.get(elementId) || [];\n existing.push(tag);\n mediaById.set(elementId, existing);\n }\n const fingerprint = [\n tag.name,\n readAttr(tag.raw, \"src\") || \"\",\n readAttr(tag.raw, \"data-start\") || \"\",\n readAttr(tag.raw, \"data-duration\") || \"\",\n ].join(\"|\");\n mediaFingerprintCounts.set(fingerprint, (mediaFingerprintCounts.get(fingerprint) || 0) + 1);\n }\n\n for (const [elementId, mediaTags] of mediaById) {\n if (mediaTags.length < 2) continue;\n findings.push({\n code: \"duplicate_media_id\",\n severity: \"error\",\n message: `Media id \"${elementId}\" is defined multiple times.`,\n elementId,\n fixHint:\n \"Give each media element a unique id so preview and producer discover the same media graph.\",\n snippet: truncateSnippet(mediaTags[0]?.raw || \"\"),\n });\n }\n\n for (const [fingerprint, count] of mediaFingerprintCounts) {\n if (count < 2) continue;\n const [tagName, src, dataStart, dataDuration] = fingerprint.split(\"|\");\n findings.push({\n code: \"duplicate_media_discovery_risk\",\n severity: \"warning\",\n message: `Detected ${count} matching ${tagName} entries with the same source/start/duration.`,\n fixHint: \"Avoid duplicated media nodes that can be discovered twice during compilation.\",\n snippet: truncateSnippet(\n `${tagName} src=${src} data-start=${dataStart} data-duration=${dataDuration}`,\n ),\n });\n }\n return findings;\n },\n\n // video_missing_muted\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (tag.name !== \"video\") continue;\n const hasMuted = hasAttrName(tag.raw, \"muted\");\n const hasDeclaredAudio = readAttr(tag.raw, \"data-has-audio\") === \"true\";\n if (!hasMuted && !hasDeclaredAudio && readAttr(tag.raw, \"data-start\")) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"video_missing_muted\",\n severity: \"error\",\n message: `<video${elementId ? ` id=\"${elementId}\"` : \"\"}> has data-start but is not muted. Mark audible videos with data-has-audio=\"true\"; otherwise keep video muted and use a separate <audio> element for sound.`,\n elementId,\n fixHint:\n 'Add the `muted` attribute for silent video, or add data-has-audio=\"true\" when the video track should contribute audio.',\n snippet: truncateSnippet(tag.raw),\n });\n }\n if (hasMuted && hasDeclaredAudio) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"video_muted_with_declared_audio\",\n severity: \"error\",\n message: `<video${elementId ? ` id=\"${elementId}\"` : \"\"}> declares data-has-audio=\"true\" but also has muted. Studio preview will silence the video audio.`,\n elementId,\n fixHint:\n 'Remove the `muted` attribute if this video should be audible, or remove data-has-audio=\"true\" and use data-volume=\"0\" for silent visual video.',\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // video_nested_in_timed_element\n ({ source, tags }) => {\n const findings: HyperframeLintFinding[] = [];\n // HTML5 void elements cannot contain children, so they can never be a\n // parent of a nested <video>. Skipping them avoids false positives where\n // the linter looks for `</img>` and never finds it.\n const voidElements = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"source\",\n \"track\",\n \"wbr\",\n ]);\n const timedTagPositions: Array<{ name: string; start: number; id?: string }> = [];\n for (const tag of tags) {\n if (tag.name === \"video\" || tag.name === \"audio\") continue;\n if (voidElements.has(tag.name)) continue;\n // Skip the composition root — it uses data-start as a playback anchor, not as a clip timer\n if (readAttr(tag.raw, \"data-composition-id\")) continue;\n if (readAttr(tag.raw, \"data-start\")) {\n timedTagPositions.push({\n name: tag.name,\n start: tag.index,\n id: readAttr(tag.raw, \"id\") || undefined,\n });\n }\n }\n for (const tag of tags) {\n if (tag.name !== \"video\") continue;\n if (!readAttr(tag.raw, \"data-start\")) continue;\n for (const parent of timedTagPositions) {\n if (parent.start < tag.index) {\n const parentClosePattern = new RegExp(`</${parent.name}>`, \"gi\");\n const between = source.substring(parent.start, tag.index);\n if (!parentClosePattern.test(between)) {\n findings.push({\n code: \"video_nested_in_timed_element\",\n severity: \"error\",\n message: `<video> with data-start is nested inside <${parent.name}${parent.id ? ` id=\"${parent.id}\"` : \"\"}> which also has data-start. The framework cannot manage playback of nested media — video will be FROZEN in renders.`,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n \"Move the <video> to be a direct child of the stage, or remove data-start from the wrapper div (use it as a non-timed visual container).\",\n snippet: truncateSnippet(tag.raw),\n });\n break;\n }\n }\n }\n }\n return findings;\n },\n\n // media_in_subcomposition — <video>/<audio> only render as a DIRECT child of the host\n // root (index.html). Inside a sub-composition <template> the runtime never seeks/decodes\n // them, so they render BLANK/black in preview and renders — and the other lint/validate\n // passes otherwise miss it (only a per-frame snapshot reveals the blank panel).\n ({ tags, options }) => {\n const findings: HyperframeLintFinding[] = [];\n if (!options.isSubComposition) return findings;\n for (const tag of tags) {\n if (tag.name !== \"video\" && tag.name !== \"audio\") continue;\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"media_in_subcomposition\",\n severity: \"error\",\n 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.`,\n elementId,\n fixHint:\n \"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.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n return findings;\n },\n\n // self_closing_media_tag\n ({ source }) => {\n const findings: HyperframeLintFinding[] = [];\n const selfClosingMediaRe = /<(audio|video)\\b[^>]*\\/>/gi;\n let scMatch: RegExpExecArray | null;\n while ((scMatch = selfClosingMediaRe.exec(source)) !== null) {\n const tagName = scMatch[1] || \"audio\";\n const elementId = readAttr(scMatch[0], \"id\") || undefined;\n findings.push({\n code: \"self_closing_media_tag\",\n severity: \"error\",\n message: `Self-closing <${tagName}/> is invalid HTML. The browser will leave the tag open, swallowing all subsequent elements as invisible fallback content. This makes compositions INVISIBLE.`,\n elementId,\n fixHint: `Change <${tagName} .../> to <${tagName} ...></${tagName}> — media elements MUST have explicit closing tags.`,\n snippet: truncateSnippet(scMatch[0]),\n });\n }\n return findings;\n },\n\n // placeholder_media_url\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const PLACEHOLDER_DOMAINS =\n /\\b(placehold\\.co|placeholder\\.com|placekitten\\.com|picsum\\.photos|example\\.com|via\\.placeholder\\.com|dummyimage\\.com)\\b/i;\n for (const tag of tags) {\n if (!isMediaTag(tag.name)) continue;\n const src = readAttr(tag.raw, \"src\");\n if (!src) continue;\n if (PLACEHOLDER_DOMAINS.test(src)) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"placeholder_media_url\",\n severity: \"error\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> uses a placeholder URL that will 404 at render time: ${src.slice(0, 80)}`,\n elementId,\n fixHint: \"Replace with a real media URL. Placeholder domains will 404 at render time.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // base64_media_prohibited\n ({ source }) => {\n const findings: HyperframeLintFinding[] = [];\n const base64MediaRe =\n /src\\s*=\\s*[\"'](data:(?:audio|video)\\/[^;]+;base64,([A-Za-z0-9+/=]{20,}))[\"']/gi;\n let b64Match: RegExpExecArray | null;\n while ((b64Match = base64MediaRe.exec(source)) !== null) {\n const sample = (b64Match[2] || \"\").slice(0, 200);\n const uniqueChars = new Set(sample.replace(/[A-Za-z0-9+/=]/g, (c) => c)).size;\n const dataSize = Math.round(((b64Match[2] || \"\").length * 3) / 4);\n const isSuspicious = uniqueChars < 15 || (dataSize > 1000 && dataSize < 50000);\n findings.push({\n code: \"base64_media_prohibited\",\n severity: \"error\",\n message: `Inline base64 audio/video detected (${(dataSize / 1024).toFixed(0)} KB)${isSuspicious ? \" — likely fabricated data\" : \"\"}. Base64 media is prohibited — it bloats file size and breaks rendering.`,\n fixHint:\n \"Use a relative path (assets/music.mp3) or HTTPS URL for the audio/video src. Never embed media as base64.\",\n snippet: truncateSnippet((b64Match[1] ?? \"\").slice(0, 80) + \"...\"),\n });\n }\n return findings;\n },\n\n // media_missing_data_start + media_missing_id + media_missing_src + media_preload_none\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (tag.name !== \"video\" && tag.name !== \"audio\") continue;\n const hasDataStart = readAttr(tag.raw, \"data-start\");\n const hasId = readAttr(tag.raw, \"id\");\n const hasSrc = readAttr(tag.raw, \"src\");\n if (hasSrc && !hasDataStart) {\n findings.push({\n code: \"media_missing_data_start\",\n severity: \"error\",\n message: `<${tag.name}${hasId ? ` id=\"${hasId}\"` : \"\"}> has src but no data-start. HyperFrames cannot own playback for untimed media, so preview and render behavior can diverge.`,\n elementId: hasId || undefined,\n fixHint: `Add data-start=\"0\" (or the intended start time) and data-duration if the clip should stop before the source ends.`,\n snippet: truncateSnippet(tag.raw),\n });\n }\n if (hasDataStart && !hasId) {\n findings.push({\n code: \"media_missing_id\",\n severity: \"error\",\n message: `<${tag.name}> has data-start but no id attribute. The renderer requires id to discover media elements — this ${tag.name === \"audio\" ? \"audio will be SILENT\" : \"video will be FROZEN\"} in renders.`,\n fixHint: `Add a unique id attribute: <${tag.name} id=\"my-${tag.name}\" ...>`,\n snippet: truncateSnippet(tag.raw),\n });\n }\n if (hasDataStart && hasId && !hasSrc) {\n findings.push({\n code: \"media_missing_src\",\n severity: \"error\",\n message: `<${tag.name} id=\"${hasId}\"> has data-start but no src attribute. The renderer cannot load this media.`,\n elementId: hasId,\n fixHint: `Add a src attribute to the <${tag.name}> element directly. If using <source> children, the renderer still requires src on the parent element.`,\n snippet: truncateSnippet(tag.raw),\n });\n }\n if (readAttr(tag.raw, \"preload\") === \"none\") {\n findings.push({\n code: \"media_preload_none\",\n severity: \"warning\",\n message: `<${tag.name}${hasId ? ` id=\"${hasId}\"` : \"\"}> has preload=\"none\" which prevents the renderer from loading this media. The compiler strips it for renders, but preview may also have issues.`,\n elementId: hasId || undefined,\n fixHint: `Remove preload=\"none\" or change to preload=\"auto\". The framework manages media loading.`,\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // media_crossorigin_breaks_preview — `crossorigin` on <video>/<audio> forces a\n // CORS-checked fetch. The server-side renderer downloads media directly (no CORS),\n // so it always works there; but Studio preview runs in the browser, where a media\n // host that omits Access-Control-Allow-Origin silently fails the load — the media\n // shows BLANK/black in preview while renders look fine, hiding the bug. Plain\n // displayed media never needs crossorigin; it's only required to read pixels/samples\n // back (canvas/WebGL texture, WebAudio createMediaElementSource) AND only when the\n // host is known CORS-enabled.\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (tag.name !== \"video\" && tag.name !== \"audio\") continue;\n if (!hasAttrName(tag.raw, \"crossorigin\")) continue;\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"media_crossorigin_breaks_preview\",\n severity: \"error\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> has crossorigin, which forces a CORS-checked fetch. If the media host omits Access-Control-Allow-Origin, the load silently fails in Studio preview (media shows BLANK/black) while server-side renders still work — hiding the bug.`,\n elementId,\n fixHint:\n \"Remove the crossorigin attribute unless you read the media back via canvas/WebGL/WebAudio AND the host is known to send CORS headers. Plain displayed media never needs it.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n return findings;\n },\n\n // video_audio_double_source — catches audible <video> paired with a separate\n // <audio> pointing to the same file, which causes double playback at runtime\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const videoSources = new Map<string, { id?: string; raw: string }>();\n const audioSources = new Map<string, { id?: string; raw: string }>();\n\n for (const tag of tags) {\n if (!readAttr(tag.raw, \"data-start\")) continue;\n const src = readAttr(tag.raw, \"src\");\n if (!src) continue;\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n if (tag.name === \"video\") {\n const isMuted = hasAttrName(tag.raw, \"muted\");\n if (!isMuted) {\n videoSources.set(src, { id: elementId, raw: tag.raw });\n }\n } else if (tag.name === \"audio\") {\n audioSources.set(src, { id: elementId, raw: tag.raw });\n }\n }\n\n for (const [src, audioInfo] of audioSources) {\n const videoInfo = videoSources.get(src);\n if (!videoInfo) continue;\n findings.push({\n code: \"video_audio_double_source\",\n severity: \"error\",\n message: `<audio${audioInfo.id ? ` id=\"${audioInfo.id}\"` : \"\"}> and <video${videoInfo.id ? ` id=\"${videoInfo.id}\"` : \"\"}> both point to the same source. The unmuted video already provides audio — the duplicate <audio> will cause double playback and echo.`,\n elementId: audioInfo.id,\n fixHint:\n \"Either mute the video (add `muted` attribute) and keep the separate <audio>, or remove the <audio> element and let the video provide its own audio track.\",\n snippet: truncateSnippet(audioInfo.raw),\n });\n }\n return findings;\n },\n\n // imperative_media_control\n findImperativeMediaControlFindings,\n];\n","interface LintParsedGsap {\n animations: Array<{\n targetSelector: string;\n method: string;\n position: number | string;\n properties: Record<string, number | string>;\n duration?: number;\n ease?: string;\n extras?: Record<string, unknown>;\n }>;\n timelineVar: string;\n}\n\n// Use the acorn read parser: it resolves computed timelines (helpers, bounded\n// loops) so lint findings like overlapping_gsap_tweens reflect true positions\n// instead of all-collapsed-at-0. It's also browser-safe, so this keeps recast\n// out of the lint graph entirely. Dynamic import preserves the lazy load.\nasync function loadParseGsapScript(): Promise<(script: string) => LintParsedGsap> {\n const mod = await import(\"@hyperframes/parsers/gsap-parser-acorn\");\n return mod.parseGsapScriptAcorn as unknown as (script: string) => LintParsedGsap;\n}\nimport type { LintContext } from \"../context\";\nimport type { HyperframeLintFinding, LintRule } from \"../types\";\nimport type { OpenTag } from \"../utils\";\nimport {\n readAttr,\n truncateSnippet,\n stripJsComments,\n hasCaptionStyles,\n WINDOW_TIMELINE_ASSIGN_PATTERN,\n TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN,\n} from \"../utils\";\n\n// ── GSAP-specific types ────────────────────────────────────────────────────\n\ntype GsapWindow = {\n targetSelector: string;\n position: number;\n end: number;\n properties: string[];\n propertyValues: Record<string, string | number>;\n overwriteAuto: boolean;\n method: string;\n raw: string;\n};\n\ntype CompositionRange = {\n id: string;\n start: number;\n end: number;\n};\n\nconst SCENE_BOUNDARY_EPSILON_SECONDS = 0.05;\n\n// Sentinel the GSAP parser assigns to a tween whose target it cannot statically\n// resolve to a concrete element (a computed variable, a helper call, etc.). It is\n// NOT an identity: two distinct unresolved selectors are not the same element, so\n// overlap analysis must never treat them as one.\nconst UNRESOLVED_TARGET = \"__unresolved__\";\n\n// ── GSAP parsing utilities ─────────────────────────────────────────────────\n\nfunction countClassUsage(tags: OpenTag[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const tag of tags) {\n const classAttr = readAttr(tag.raw, \"class\");\n if (!classAttr) continue;\n for (const className of classAttr.split(/\\s+/).filter(Boolean)) {\n counts.set(className, (counts.get(className) || 0) + 1);\n }\n }\n return counts;\n}\n\nfunction readRegisteredTimelineCompositionId(script: string): string | null {\n const match = script.match(WINDOW_TIMELINE_ASSIGN_PATTERN);\n return match?.[1] || match?.[2] || null;\n}\n\n/** Strip a `__raw:` prefix the parser adds to unresolvable values. */\nfunction unwrapRaw(value: unknown): string | number | undefined {\n if (typeof value === \"number\") return value;\n if (typeof value !== \"string\") return undefined;\n const code = value.startsWith(\"__raw:\") ? value.slice(6) : value;\n return code.replace(/^\\s*[\"']|[\"']\\s*$/g, \"\");\n}\n\nfunction extrasNumber(value: unknown): number {\n const unwrapped = unwrapRaw(value);\n const numeric = typeof unwrapped === \"number\" ? unwrapped : Number(unwrapped);\n return Number.isFinite(numeric) ? numeric : 0;\n}\n\n/** A readable single-line snippet of a tween for finding messages. */\nfunction synthesizeWindowRaw(\n timelineVar: string,\n anim: LintParsedGsap[\"animations\"][number],\n): string {\n const entries = Object.entries(anim.properties).map(([k, v]) => {\n if (typeof v === \"string\" && v.startsWith(\"__raw:\")) return `${k}: ${v.slice(6)}`;\n return `${k}: ${typeof v === \"string\" ? JSON.stringify(v) : v}`;\n });\n if (anim.duration !== undefined) entries.push(`duration: ${anim.duration}`);\n if (anim.ease) entries.push(`ease: ${JSON.stringify(anim.ease)}`);\n const pos = typeof anim.position === \"number\" ? anim.position : JSON.stringify(anim.position);\n return `${timelineVar}.${anim.method}(\"${anim.targetSelector}\", { ${entries.join(\", \")} }, ${pos})`;\n}\n\nconst gsapWindowsCache = new Map<string, GsapWindow[]>();\n\nasync function cachedExtractGsapWindows(scriptContent: string): Promise<GsapWindow[]> {\n const cached = gsapWindowsCache.get(scriptContent);\n if (cached) return cached;\n const windows = await extractGsapWindows(scriptContent);\n gsapWindowsCache.set(scriptContent, windows);\n return windows;\n}\n\n// fallow-ignore-next-line complexity\nasync function extractGsapWindows(script: string): Promise<GsapWindow[]> {\n if (!/gsap\\.timeline/.test(script)) return [];\n const parseGsapScript = await loadParseGsapScript();\n const parsed = parseGsapScript(script);\n if (parsed.animations.length === 0) return [];\n\n const windows: GsapWindow[] = [];\n for (const animation of parsed.animations) {\n // Skip animations with string positions (e.g. \"+=1\", \"<\") — their absolute\n // timing depends on runtime evaluation and can't be statically linted.\n if (typeof animation.position !== \"number\") continue;\n const repeat = extrasNumber(animation.extras?.repeat);\n const cycleCount = repeat > 0 ? repeat + 1 : 1;\n const effectiveDuration =\n animation.method === \"set\" ? 0 : (animation.duration ?? 0) * cycleCount;\n windows.push({\n targetSelector: animation.targetSelector,\n position: animation.position,\n end: animation.position + effectiveDuration,\n properties: Object.keys(animation.properties),\n propertyValues: animation.properties,\n overwriteAuto: unwrapRaw(animation.extras?.overwrite) === \"auto\",\n method: animation.method,\n raw: synthesizeWindowRaw(parsed.timelineVar, animation),\n });\n }\n return windows;\n}\n\nfunction numberValue(value: string | number | undefined): number | null {\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\" && value.trim()) {\n const numeric = Number(value);\n return Number.isFinite(numeric) ? numeric : null;\n }\n return null;\n}\n\nfunction stringValue(value: string | number | undefined): string | null {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\") return String(value);\n return null;\n}\n\nfunction zeroValue(value: string | number | undefined): boolean {\n if (typeof value === \"number\") return value === 0;\n if (typeof value !== \"string\") return false;\n return Number(value.trim()) === 0;\n}\n\nfunction isHiddenGsapState(values: Record<string, string | number>): boolean {\n const visibility = stringValue(values.visibility)?.toLowerCase();\n const display = stringValue(values.display)?.toLowerCase();\n return (\n zeroValue(values.opacity) ||\n zeroValue(values.autoAlpha) ||\n visibility === \"hidden\" ||\n display === \"none\"\n );\n}\n\nfunction oneValue(\n values: Record<string, string | number>,\n keys: string[],\n): string | number | undefined {\n for (const key of keys) {\n const value = values[key];\n if (value !== undefined) return value;\n }\n return undefined;\n}\n\nfunction isVisibleGsapState(values: Record<string, string | number>): boolean {\n const opacity = oneValue(values, [\"opacity\", \"autoAlpha\"]);\n if (typeof opacity === \"number\") return opacity > 0;\n if (typeof opacity === \"string\" && opacity.trim()) {\n const numeric = Number(opacity);\n if (Number.isFinite(numeric)) return numeric > 0;\n }\n\n const visibility = stringValue(values.visibility)?.toLowerCase();\n if (visibility === \"visible\" || visibility === \"inherit\") return true;\n\n const display = stringValue(values.display)?.toLowerCase();\n if (display && display !== \"none\") return true;\n\n return false;\n}\n\nfunction makesOverlayVisible(win: GsapWindow): boolean {\n if (win.method === \"from\" && isHiddenGsapState(win.propertyValues)) return true;\n return isVisibleGsapState(win.propertyValues);\n}\n\nfunction isSceneBoundaryExit(win: GsapWindow): boolean {\n if (win.end <= win.position) return false;\n if (win.method !== \"to\" && win.method !== \"fromTo\") return false;\n return isHiddenGsapState(win.propertyValues);\n}\n\nfunction isHardKillSet(win: GsapWindow, selector: string, boundary: number): boolean {\n return (\n win.method === \"set\" &&\n win.targetSelector === selector &&\n Math.abs(win.position - boundary) <= SCENE_BOUNDARY_EPSILON_SECONDS &&\n isHiddenGsapState(win.propertyValues)\n );\n}\n\nfunction hiddenStateLiteral(values: Record<string, string | number>): string {\n if (zeroValue(values.autoAlpha)) return \"{ autoAlpha: 0 }\";\n if (zeroValue(values.opacity)) return \"{ opacity: 0 }\";\n if (stringValue(values.visibility)?.toLowerCase() === \"hidden\") return '{ visibility: \"hidden\" }';\n if (stringValue(values.display)?.toLowerCase() === \"none\") return '{ display: \"none\" }';\n return \"{ opacity: 0 }\";\n}\n\nfunction findTagEnd(source: string, tag: OpenTag): number {\n const escapedTagName = tag.name.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = new RegExp(`<\\\\/?${escapedTagName}\\\\b[^>]*>`, \"gi\");\n pattern.lastIndex = tag.index;\n\n let depth = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(source)) !== null) {\n const raw = match[0];\n const isClosing = /^<\\s*\\//.test(raw);\n const isSelfClosing = /\\/\\s*>$/.test(raw);\n if (!isClosing && !isSelfClosing) depth += 1;\n if (isClosing) depth -= 1;\n if (depth === 0) return pattern.lastIndex;\n }\n\n return source.length;\n}\n\nfunction collectCompositionRanges(source: string, tags: OpenTag[]): CompositionRange[] {\n return tags\n .map((tag) => {\n const id = readAttr(tag.raw, \"data-composition-id\");\n if (!id) return null;\n return {\n id,\n start: tag.index,\n end: findTagEnd(source, tag),\n };\n })\n .filter((range) => range !== null);\n}\n\nfunction findContainingCompositionId(tag: OpenTag, ranges: CompositionRange[]): string | null {\n let match: CompositionRange | null = null;\n for (const range of ranges) {\n if (tag.index < range.start || tag.index >= range.end) continue;\n if (!match || range.start >= match.start) match = range;\n }\n return match?.id || null;\n}\n\n// A tag's `class` attribute, split into tokens, but only when it carries the\n// `clip` marker class — the common \"is this a clip element?\" filter used by\n// several rules that walk every tag looking for clips.\ntype ClipTagClasses = { classAttr: string; classes: string[] };\n\nfunction getClipTagClasses(tag: OpenTag): ClipTagClasses | null {\n const classAttr = readAttr(tag.raw, \"class\") || \"\";\n const classes = classAttr.split(/\\s+/).filter(Boolean);\n return classes.includes(\"clip\") ? { classAttr, classes } : null;\n}\n\nfunction collectClipStartBoundariesByComposition(\n source: string,\n tags: OpenTag[],\n): Map<string, number[]> {\n const ranges = collectCompositionRanges(source, tags);\n const boundaries = new Map<string, Set<number>>();\n\n for (const tag of tags) {\n if (!getClipTagClasses(tag)) continue;\n const compositionId = findContainingCompositionId(tag, ranges);\n if (!compositionId) continue;\n const start = numberValue(readAttr(tag.raw, \"data-start\") ?? undefined);\n if (start == null || start <= 0) continue;\n const compositionBoundaries = boundaries.get(compositionId) ?? new Set<number>();\n compositionBoundaries.add(start);\n boundaries.set(compositionId, compositionBoundaries);\n }\n\n return new Map(\n [...boundaries.entries()].map(([compositionId, values]) => [\n compositionId,\n [...values].sort((a, b) => a - b),\n ]),\n );\n}\n\nfunction findMatchingSceneBoundary(time: number, boundaries: number[]): number | null {\n for (const boundary of boundaries) {\n if (Math.abs(time - boundary) <= SCENE_BOUNDARY_EPSILON_SECONDS) return boundary;\n }\n return null;\n}\n\nfunction isSuspiciousGlobalSelector(selector: string): boolean {\n if (!selector) return false;\n if (selector.includes(\"[data-composition-id=\")) return false;\n if (selector.startsWith(\"#\")) return false;\n return selector.startsWith(\".\") || /^[a-z]/i.test(selector);\n}\n\nfunction getSingleClassSelector(selector: string): string | null {\n const match = selector.trim().match(/^\\.(?<name>[A-Za-z0-9_-]+)$/);\n return match?.groups?.name || null;\n}\n\nfunction readStyleProperty(style: string, property: string): string | null {\n const escapedProperty = property.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const match = style.match(new RegExp(`(?:^|;)\\\\s*${escapedProperty}\\\\s*:\\\\s*([^;]+)`, \"i\"));\n return match?.[1]?.trim() || null;\n}\n\nfunction cssZero(value: string | null): boolean {\n if (!value) return false;\n return /^0(?:\\.0+)?(?:px|%|vw|vh|rem|em)?$/i.test(value.trim());\n}\n\nfunction styleHasHiddenInitialState(style: string): boolean {\n const opacity = readStyleProperty(style, \"opacity\");\n if (opacity && Number(opacity) === 0) return true;\n if (readStyleProperty(style, \"visibility\")?.toLowerCase() === \"hidden\") return true;\n if (readStyleProperty(style, \"display\")?.toLowerCase() === \"none\") return true;\n return false;\n}\n\nfunction styleHasOpaqueBackground(style: string): boolean {\n const background =\n readStyleProperty(style, \"background\") || readStyleProperty(style, \"background-color\");\n if (!background) return false;\n const normalized = background.toLowerCase().replace(/\\s+/g, \"\");\n if (normalized === \"transparent\" || normalized === \"none\") return false;\n if (/rgba?\\([^)]*,0(?:\\.0+)?\\)$/.test(normalized)) return false;\n if (/hsla?\\([^)]*,0(?:\\.0+)?\\)$/.test(normalized)) return false;\n return true;\n}\n\nfunction styleLooksFullFrameOverlay(style: string): boolean {\n const position = readStyleProperty(style, \"position\")?.toLowerCase();\n if (position !== \"fixed\" && position !== \"absolute\") return false;\n const coversFrame =\n cssZero(readStyleProperty(style, \"inset\")) ||\n (cssZero(readStyleProperty(style, \"top\")) &&\n cssZero(readStyleProperty(style, \"right\")) &&\n cssZero(readStyleProperty(style, \"bottom\")) &&\n cssZero(readStyleProperty(style, \"left\")));\n return coversFrame && styleHasOpaqueBackground(style);\n}\n\nfunction collectSimpleStyleRules(styles: LintContext[\"styles\"]): Map<string, string> {\n const rules = new Map<string, string>();\n for (const style of styles) {\n for (const [, selectorList, body] of style.content.matchAll(/([^{}]+)\\{([^}]+)\\}/g)) {\n if (!selectorList || !body) continue;\n for (const selector of selectorList.split(\",\")) {\n const token = selector.trim();\n if (!/^[#.][A-Za-z0-9_-]+$/.test(token)) continue;\n rules.set(token, `${rules.get(token) || \"\"};${body}`);\n }\n }\n }\n return rules;\n}\n\nfunction tagSimpleSelectors(tag: OpenTag): string[] {\n const selectors: string[] = [];\n const id = readAttr(tag.raw, \"id\");\n if (id) selectors.push(`#${id}`);\n const classes = readAttr(tag.raw, \"class\")?.split(/\\s+/).filter(Boolean) ?? [];\n for (const className of classes) selectors.push(`.${className}`);\n return selectors;\n}\n\nfunction combinedTagStyle(tag: OpenTag, styleRules: Map<string, string>): string {\n const styles = [readAttr(tag.raw, \"style\") || \"\"];\n for (const selector of tagSimpleSelectors(tag)) {\n const ruleStyle = styleRules.get(selector);\n if (ruleStyle) styles.push(ruleStyle);\n }\n return styles.filter(Boolean).join(\";\");\n}\n\n// fallow-ignore-next-line complexity\nfunction cssTransformToGsapProps(cssTransform: string): string | null {\n const parts: string[] = [];\n\n // translate(-50%, -50%) or translate(X, Y)\n const translateMatch = cssTransform.match(\n /translate\\(\\s*(-?[\\d.]+)(%|px)?\\s*,\\s*(-?[\\d.]+)(%|px)?\\s*\\)/,\n );\n if (translateMatch) {\n const [, xVal, xUnit, yVal, yUnit] = translateMatch;\n if (xUnit === \"%\") parts.push(`xPercent: ${xVal}`);\n else parts.push(`x: ${xVal}`);\n if (yUnit === \"%\") parts.push(`yPercent: ${yVal}`);\n else parts.push(`y: ${yVal}`);\n }\n\n // translateX(-50%) or translateX(px)\n const txMatch = cssTransform.match(/translateX\\(\\s*(-?[\\d.]+)(%|px)?\\s*\\)/);\n if (txMatch) {\n const [, val, unit] = txMatch;\n parts.push(unit === \"%\" ? `xPercent: ${val}` : `x: ${val}`);\n }\n\n // translateY(-50%) or translateY(px)\n const tyMatch = cssTransform.match(/translateY\\(\\s*(-?[\\d.]+)(%|px)?\\s*\\)/);\n if (tyMatch) {\n const [, val, unit] = tyMatch;\n parts.push(unit === \"%\" ? `yPercent: ${val}` : `y: ${val}`);\n }\n\n // scale(N)\n const scaleMatch = cssTransform.match(/scale\\(\\s*([\\d.]+)\\s*\\)/);\n if (scaleMatch) {\n parts.push(`scale: ${scaleMatch[1]}`);\n }\n\n return parts.length > 0 ? parts.join(\", \") : null;\n}\n\n// ── CSS-transform ↔ GSAP-transform conflict matching ─────────────────────────\n\n// Transform components that COMBINE with a CSS translate/scale on the same\n// element. GSAP bakes the element's existing CSS transform in when it seeks, so\n// these stack rather than override in the capture path (e.g. CSS translateX(-50%)\n// + xPercent:-50 renders as -100% — off-centre). `rotation` is excluded: it maps\n// to CSS rotate(), which this rule treats separately (no false positive on spin).\nconst CONFLICTING_TRANSLATE_PROPS = [\"x\", \"y\", \"xPercent\", \"yPercent\"];\nconst CONFLICTING_SCALE_PROPS = [\"scale\", \"scaleX\", \"scaleY\"];\n\ntype GsapTransformCall = {\n method: string;\n selector: string;\n properties: string[];\n raw: string;\n};\n\n// Decompose a (possibly grouped / descendant / compound) GSAP target selector\n// into the simple `#id` / `.class` tokens of the elements it actually targets —\n// the RIGHTMOST compound of each comma group is the targeted element. This lets a\n// CSS rule keyed by a simple selector (`.m04-label`) match a scoped GSAP selector\n// (`\"#root .m04-label, #root .m04-sub\"`), which the prior exact-string lookup\n// missed — so every scoped/grouped selector slipped past the rule entirely.\nfunction targetedSelectorTokens(selector: string): Set<string> {\n const tokens = new Set<string>();\n for (const group of selector.split(\",\")) {\n const compounds = group\n .trim()\n .split(/[\\s>+~]+/)\n .filter(Boolean);\n const last = compounds[compounds.length - 1];\n if (!last) continue;\n const simple = last.match(/[#.][A-Za-z0-9_-]+/g);\n if (simple) for (const token of simple) tokens.add(token);\n }\n return tokens;\n}\n\n// Find a CSS transform conflicting with a GSAP target selector: exact-string\n// match first (fast path + back-compat with the original behaviour), then a\n// token match so scoped/grouped/descendant selectors resolve to their class/id.\nfunction matchCssTransform(gsapSelector: string, cssMap: Map<string, string>): string | undefined {\n if (cssMap.size === 0) return undefined;\n const direct = cssMap.get(gsapSelector);\n if (direct) return direct;\n const tokens = targetedSelectorTokens(gsapSelector);\n for (const [cssSelector, value] of cssMap) {\n if (tokens.has(cssSelector)) return value;\n }\n return undefined;\n}\n\n// Scan for STANDALONE `gsap.set/to/from/fromTo(\"selector\", { ...props })` calls.\n// The acorn timeline parser only captures calls rooted on the timeline var\n// (`tl.to`, `tl.set`, …); a top-level `gsap.set(\"#root .label\", { xPercent: -50 })`\n// — a common way to seat shared base transforms before the timeline runs — is\n// invisible to it, so the conflict rule never saw it. Variable selectors\n// (`gsap.set(kicker, …)`) can't be resolved statically and are skipped.\nfunction extractStandaloneGsapTransformCalls(script: string): GsapTransformCall[] {\n const calls: GsapTransformCall[] = [];\n const pattern = /gsap\\.(set|to|from|fromTo)\\s*\\(\\s*([\"'])([^\"']+)\\2\\s*,\\s*\\{([^{}]*)\\}/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(script)) !== null) {\n const method = match[1] ?? \"set\";\n const selector = match[3] ?? \"\";\n const propsBody = match[4] ?? \"\";\n const properties = [...propsBody.matchAll(/([A-Za-z_$][\\w$]*)\\s*:/g)].map((m) => m[1] ?? \"\");\n calls.push({ method, selector, properties, raw: truncateSnippet(match[0]) ?? match[0] });\n }\n return calls;\n}\n\n// Run a global regex over every script's content, yielding each match plus a\n// context-padded snippet around it. Shared by the repeat-count and\n// group-selector-keyframes rules below, which differ only in the pattern,\n// whether comments are stripped first, and the context window size.\nfunction scanScriptsForRegexMatches(\n scripts: LintContext[\"scripts\"],\n pattern: RegExp,\n options: { stripComments: boolean; contextBefore: number; contextAfter: number },\n): Array<{ match: RegExpExecArray; snippet: string }> {\n const hits: Array<{ match: RegExpExecArray; snippet: string }> = [];\n for (const script of scripts) {\n const content = options.stripComments ? stripJsComments(script.content) : script.content;\n const regex = new RegExp(pattern.source, pattern.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(content)) !== null) {\n const contextStart = Math.max(0, match.index - options.contextBefore);\n const contextEnd = Math.min(\n content.length,\n match.index + match[0].length + options.contextAfter,\n );\n hits.push({ match, snippet: content.slice(contextStart, contextEnd) });\n }\n }\n return hits;\n}\n\n// ── GSAP rules ─────────────────────────────────────────────────────────────\n\n// fallow-ignore-next-line complexity\nexport const gsapRules: LintRule<LintContext>[] = [\n // overlapping_gsap_tweens + gsap_animates_clip_element + unscoped_gsap_selector\n // fallow-ignore-next-line complexity\n async ({ source, tags, scripts, styles, rootCompositionId }) => {\n const findings: HyperframeLintFinding[] = [];\n\n // Build clip element selector map\n type ClipInfo = { tag: string; id: string; classes: string };\n const clipIds = new Map<string, ClipInfo>();\n const clipClasses = new Map<string, ClipInfo>();\n for (const tag of tags) {\n const clipTag = getClipTagClasses(tag);\n if (!clipTag) continue;\n const id = readAttr(tag.raw, \"id\");\n const info: ClipInfo = {\n tag: tag.name,\n id: id || \"\",\n classes: clipTag.classAttr,\n };\n if (id) clipIds.set(`#${id}`, info);\n for (const cls of clipTag.classes) {\n if (cls !== \"clip\") clipClasses.set(`.${cls}`, info);\n }\n }\n\n const classUsage = countClassUsage(tags);\n const clipStartBoundariesByComposition = collectClipStartBoundariesByComposition(source, tags);\n const styleRules = collectSimpleStyleRules(styles);\n const reportedVisibleOverlayKeys = new Set<string>();\n\n for (const script of scripts) {\n const localTimelineCompId = readRegisteredTimelineCompositionId(script.content);\n const gsapWindows = await cachedExtractGsapWindows(script.content);\n const clipStartBoundaries =\n clipStartBoundariesByComposition.get(localTimelineCompId || rootCompositionId || \"\") ?? [];\n\n // overlapping_gsap_tweens\n for (let i = 0; i < gsapWindows.length; i++) {\n const left = gsapWindows[i];\n if (!left) continue;\n if (left.end <= left.position) continue;\n // Unresolved targets are unknown elements: two of them are not provably\n // the same element, so an overlap between them cannot be asserted.\n if (left.targetSelector === UNRESOLVED_TARGET) continue;\n for (let j = i + 1; j < gsapWindows.length; j++) {\n const right = gsapWindows[j];\n if (!right) continue;\n if (right.end <= right.position) continue;\n if (left.targetSelector !== right.targetSelector) continue;\n const overlapStart = Math.max(left.position, right.position);\n const overlapEnd = Math.min(left.end, right.end);\n if (overlapEnd <= overlapStart) continue;\n if (left.overwriteAuto || right.overwriteAuto) continue;\n const sharedProperties = left.properties.filter((prop) =>\n right.properties.includes(prop),\n );\n if (sharedProperties.length === 0) continue;\n findings.push({\n code: \"overlapping_gsap_tweens\",\n severity: \"warning\",\n message: `GSAP tweens overlap on \"${left.targetSelector}\" for ${sharedProperties.join(\", \")} between ${overlapStart.toFixed(2)}s and ${overlapEnd.toFixed(2)}s.`,\n selector: left.targetSelector,\n fixHint: 'Shorten the earlier tween, move the later tween, or add `overwrite: \"auto\"`.',\n snippet: truncateSnippet(`${left.raw}\\n${right.raw}`),\n });\n }\n }\n\n // gsap_exit_missing_hard_kill\n if (clipStartBoundaries.length > 0) {\n for (const win of gsapWindows) {\n // Unresolved targets are unknown elements: you cannot assert a missing\n // hard kill on one, and a `tl.set(\"__unresolved__\", ...)` hint is meaningless.\n if (win.targetSelector === UNRESOLVED_TARGET) continue;\n if (!isSceneBoundaryExit(win)) continue;\n const boundary = findMatchingSceneBoundary(win.end, clipStartBoundaries);\n if (boundary == null) continue;\n const hasHardKill = gsapWindows.some((candidate) =>\n isHardKillSet(candidate, win.targetSelector, boundary),\n );\n if (hasHardKill) continue;\n\n // A tl.set hard kill on the exiting selector itself is the fix — unless\n // that selector IS a clip element, in which case gsap_animates_clip_element\n // (below) errors on that exact tl.set: the framework already owns\n // visibility/display on clip elements. Point at the inner-wrapper\n // pattern instead so the two rules' advice doesn't contradict.\n const exitClipInfo =\n clipIds.get(win.targetSelector) || clipClasses.get(win.targetSelector);\n const fixHint = exitClipInfo\n ? `\"${win.targetSelector}\" is a clip element — the framework already manages its visibility. ` +\n \"Wrap the scene's content in an inner non-clip <div>, move the exit tween and the hard kill \" +\n `(\\`tl.set(\"<inner-selector>\", ${hiddenStateLiteral(win.propertyValues)}, ${boundary.toFixed(2)})\\`) onto that wrapper instead.`\n : `Add \\`tl.set(\"${win.targetSelector}\", ${hiddenStateLiteral(win.propertyValues)}, ${boundary.toFixed(2)})\\` ` +\n \"after the exit tween.\";\n\n findings.push({\n code: \"gsap_exit_missing_hard_kill\",\n severity: \"error\",\n message:\n `GSAP exit on \"${win.targetSelector}\" ends at the ${boundary.toFixed(2)}s clip start boundary ` +\n \"without a matching tl.set hard kill. Non-linear seeking can land after the fade and leave stale visibility state.\",\n selector: win.targetSelector,\n fixHint,\n snippet: truncateSnippet(win.raw),\n });\n }\n }\n\n // gsap_fullscreen_overlay_starts_visible\n for (const tag of tags) {\n const selectors = tagSimpleSelectors(tag);\n if (selectors.length === 0) continue;\n const overlayKey = readAttr(tag.raw, \"id\") || String(tag.index);\n if (reportedVisibleOverlayKeys.has(overlayKey)) continue;\n const authoredStyle = combinedTagStyle(tag, styleRules);\n if (!authoredStyle || !styleLooksFullFrameOverlay(authoredStyle)) continue;\n if (styleHasHiddenInitialState(authoredStyle)) continue;\n\n const visibilityWindows = gsapWindows\n .filter((win) => {\n const tokens = targetedSelectorTokens(win.targetSelector);\n if (!selectors.some((selector) => tokens.has(selector))) return false;\n return win.properties.some((prop) =>\n [\"opacity\", \"autoAlpha\", \"visibility\", \"display\"].includes(prop),\n );\n })\n .sort((a, b) => a.position - b.position);\n const startsHiddenAtZero = visibilityWindows.some(\n (win) =>\n win.position <= SCENE_BOUNDARY_EPSILON_SECONDS && isHiddenGsapState(win.propertyValues),\n );\n if (startsHiddenAtZero) continue;\n const firstVisible = visibilityWindows.find((win) => makesOverlayVisible(win));\n if (!firstVisible) continue;\n const selector =\n selectors.find((candidate) =>\n targetedSelectorTokens(firstVisible.targetSelector).has(candidate),\n ) ||\n selectors[0] ||\n tag.name;\n const laterHidden = visibilityWindows.some(\n (win) => win.position >= firstVisible.position && isHiddenGsapState(win.propertyValues),\n );\n if (firstVisible.method !== \"from\" && !laterHidden) continue;\n\n reportedVisibleOverlayKeys.add(overlayKey);\n findings.push({\n code: \"gsap_fullscreen_overlay_starts_visible\",\n severity: \"error\",\n message:\n `Full-frame overlay \"${selector}\" starts visible before its first GSAP opacity tween at ` +\n `${firstVisible.position.toFixed(2)}s. It will cover earlier render frames, often as a blank/white video.`,\n selector,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n `Add \\`opacity: 0\\` to \"${selector}\" in CSS/inline styles, or add ` +\n `\\`tl.set(\"${selector}\", { opacity: 0 }, 0)\\` before the reveal tween.`,\n snippet: truncateSnippet(firstVisible.raw),\n });\n }\n\n // gsap_animates_clip_element — only error when GSAP animates visibility/display\n for (const win of gsapWindows) {\n const sel = win.targetSelector;\n const clipInfo = clipIds.get(sel) || clipClasses.get(sel);\n if (!clipInfo) continue;\n const conflictingProps = win.properties.filter(\n (p) => p === \"visibility\" || p === \"display\",\n );\n if (conflictingProps.length === 0) continue;\n const elDesc = `<${clipInfo.tag}${clipInfo.id ? ` id=\"${clipInfo.id}\"` : \"\"} class=\"${clipInfo.classes}\">`;\n findings.push({\n code: \"gsap_animates_clip_element\",\n severity: \"error\",\n message: `GSAP animation sets ${conflictingProps.join(\", \")} on a clip element. Selector \"${sel}\" resolves to element ${elDesc}. The framework manages clip visibility via ${conflictingProps.join(\"/\")} — do not animate these properties on clip elements.`,\n selector: sel,\n elementId: clipInfo.id || undefined,\n fixHint:\n \"Remove the visibility/display tween, or move the content into a child <div> and target that instead.\",\n snippet: truncateSnippet(win.raw),\n });\n }\n\n // unscoped_gsap_selector\n if (!localTimelineCompId || localTimelineCompId === rootCompositionId) continue;\n for (const win of gsapWindows) {\n if (!isSuspiciousGlobalSelector(win.targetSelector)) continue;\n const className = getSingleClassSelector(win.targetSelector);\n if (className && (classUsage.get(className) || 0) < 2) continue;\n findings.push({\n code: \"unscoped_gsap_selector\",\n severity: \"error\",\n message: `Timeline \"${localTimelineCompId}\" uses unscoped selector \"${win.targetSelector}\" that will target elements in ALL compositions when bundled, causing data loss (opacity, transforms, etc.).`,\n selector: win.targetSelector,\n fixHint: `Scope the selector: \\`[data-composition-id=\"${localTimelineCompId}\"] ${win.targetSelector}\\` or use a unique id.`,\n snippet: truncateSnippet(win.raw),\n });\n }\n }\n return findings;\n },\n\n // gsap_css_transform_conflict\n // fallow-ignore-next-line complexity\n async ({ styles, scripts, tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const cssTranslateSelectors = new Map<string, string>();\n const cssScaleSelectors = new Map<string, string>();\n\n // Check <style> blocks for transform rules\n for (const style of styles) {\n for (const [, selector, body] of style.content.matchAll(\n /([#.][a-zA-Z0-9_-]+)\\s*\\{([^}]+)\\}/g,\n )) {\n const tMatch = body?.match(/transform\\s*:\\s*([^;]+)/);\n if (!tMatch || !tMatch[1]) continue;\n const transformVal = tMatch[1].trim();\n if (/translate/i.test(transformVal))\n cssTranslateSelectors.set((selector ?? \"\").trim(), transformVal);\n if (/scale/i.test(transformVal))\n cssScaleSelectors.set((selector ?? \"\").trim(), transformVal);\n }\n }\n\n // Also check inline style=\"...\" attributes on tags\n for (const tag of tags) {\n const inlineStyle = readAttr(tag.raw, \"style\");\n if (!inlineStyle) continue;\n const tMatch = inlineStyle.match(/transform\\s*:\\s*([^;]+)/);\n if (!tMatch || !tMatch[1]) continue;\n const transformVal = tMatch[1].trim();\n // Derive selectors from the tag's id and all classes\n const id = readAttr(tag.raw, \"id\");\n const classes = readAttr(tag.raw, \"class\")?.split(/\\s+/).filter(Boolean) ?? [];\n const selectors: string[] = [];\n if (id) selectors.push(`#${id}`);\n for (const cls of classes) selectors.push(`.${cls}`);\n if (selectors.length === 0) continue;\n for (const sel of selectors) {\n if (/translate/i.test(transformVal) && !cssTranslateSelectors.has(sel))\n cssTranslateSelectors.set(sel, transformVal);\n if (/scale/i.test(transformVal) && !cssScaleSelectors.has(sel))\n cssScaleSelectors.set(sel, transformVal);\n }\n }\n\n if (cssTranslateSelectors.size === 0 && cssScaleSelectors.size === 0) return findings;\n\n for (const script of scripts) {\n if (!/gsap\\.timeline/.test(script.content)) continue;\n const windows = await cachedExtractGsapWindows(script.content);\n\n // Two sources of transform-setting calls: timeline-rooted tweens (from the\n // acorn parser) and standalone gsap.* calls (regex — the parser ignores\n // these). Normalize both into one shape and run the same conflict check.\n const calls: GsapTransformCall[] = [\n ...windows.map((win) => ({\n method: win.method,\n selector: win.targetSelector,\n properties: win.properties,\n raw: win.raw,\n })),\n ...extractStandaloneGsapTransformCalls(stripJsComments(script.content)),\n ];\n\n type Conflict = { cssTransform: string; props: Set<string>; raw: string };\n const conflicts = new Map<string, Conflict>();\n\n for (const call of calls) {\n // from() and fromTo() both supply explicit start values so GSAP owns\n // the full transform from t=0, making the CSS conflict moot\n if (call.method === \"fromTo\" || call.method === \"from\") continue;\n const sel = call.selector;\n const translateProps = call.properties.filter((p) =>\n CONFLICTING_TRANSLATE_PROPS.includes(p),\n );\n const scaleProps = call.properties.filter((p) => CONFLICTING_SCALE_PROPS.includes(p));\n const cssFromTranslate =\n translateProps.length > 0 ? matchCssTransform(sel, cssTranslateSelectors) : undefined;\n const cssFromScale =\n scaleProps.length > 0 ? matchCssTransform(sel, cssScaleSelectors) : undefined;\n if (!cssFromTranslate && !cssFromScale) continue;\n const existing = conflicts.get(sel) ?? {\n cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(\" \"),\n props: new Set<string>(),\n raw: call.raw,\n };\n for (const p of [...translateProps, ...scaleProps]) existing.props.add(p);\n conflicts.set(sel, existing);\n }\n\n for (const [sel, { cssTransform, props, raw }] of conflicts) {\n const propList = [...props].join(\"/\");\n const gsapEquivalent = cssTransformToGsapProps(cssTransform);\n const fixHint = gsapEquivalent\n ? `Remove \\`transform: ${cssTransform}\\` from CSS and replace with GSAP properties: ${gsapEquivalent}. ` +\n `Example: tl.fromTo('${sel}', { ${gsapEquivalent} }, { ${gsapEquivalent}, ...yourAnimation }). ` +\n `tl.fromTo is exempt from this rule.`\n : `Remove the transform from CSS and use tl.fromTo('${sel}', ` +\n `{ xPercent: -50, x: -1000 }, { xPercent: -50, x: 0 }) so GSAP owns ` +\n `the full transform state. tl.fromTo is exempt from this rule.`;\n findings.push({\n code: \"gsap_css_transform_conflict\",\n severity: \"error\",\n message:\n `\"${sel}\" has CSS \\`transform: ${cssTransform}\\` and a GSAP tween animates ` +\n `${propList}. GSAP will overwrite the full CSS transform, discarding any ` +\n `translateX(-50%) centering or CSS scale value.`,\n selector: sel,\n fixHint,\n snippet: truncateSnippet(raw),\n });\n }\n }\n return findings;\n },\n\n // missing_gsap_script\n ({ scripts, rawSource, options }) => {\n const allScriptTexts = scripts.filter((s) => !/\\bsrc\\s*=/.test(s.attrs)).map((s) => s.content);\n const allScriptSrcs = scripts\n .map((s) => readAttr(`<script ${s.attrs}>`, \"src\") || \"\")\n .filter(Boolean);\n const canInheritGsapFromHost =\n options.isSubComposition || rawSource.trimStart().toLowerCase().startsWith(\"<template\");\n\n const usesGsap = allScriptTexts.some((t) =>\n /gsap\\.(to|from|fromTo|timeline|set|registerPlugin)\\b/.test(t),\n );\n const hasGsapScript = allScriptSrcs.some((src) => /gsap/i.test(src));\n // Detect GSAP bundled inline (no src attribute). Match:\n // - Producer's CDN-inlining comment: /* inlined: ...gsap... */\n // - GSAP library internals: _gsScope, GreenSock, gsap.config\n // - Large inline scripts (>5KB) that reference gsap (likely bundled library)\n const hasInlineGsap = allScriptTexts.some(\n (t) =>\n /\\/\\*\\s*inlined:.*gsap/i.test(t) ||\n /\\b_gsScope\\b/.test(t) ||\n /\\bGreenSock\\b/.test(t) ||\n /\\bgsap\\.(config|defaults|version)\\b/.test(t) ||\n (t.length > 5000 && /\\bgsap\\b/i.test(t)),\n );\n\n if (!usesGsap || hasGsapScript || hasInlineGsap || canInheritGsapFromHost) return [];\n return [\n {\n code: \"missing_gsap_script\",\n severity: \"error\",\n message: \"Composition uses GSAP but no GSAP script is loaded. The animation will not run.\",\n fixHint:\n 'Add <script src=\"https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js\"></script> before your animation script.',\n },\n ];\n },\n\n // audio_reactive_single_tween_per_group\n // fallow-ignore-next-line complexity\n ({ scripts, styles }) => {\n const findings: HyperframeLintFinding[] = [];\n if (!hasCaptionStyles(styles)) return findings;\n\n for (const script of scripts) {\n const content = script.content;\n // Detect audio data loading\n const hasAudioData = /AUDIO|audio[-_]?data|bands\\[/.test(content);\n if (!hasAudioData) continue;\n\n // Detect caption group loop\n const hasCaptionLoop = /forEach/.test(content) && /caption|group|cg-/.test(content);\n if (!hasCaptionLoop) continue;\n\n // Check if audio-reactive tweens are created at intervals (loop inside the group loop)\n // vs a single tween per group (no inner time-sampling loop)\n const hasInnerSamplingLoop =\n /for\\s*\\(\\s*var\\s+\\w+\\s*=\\s*group\\.start/.test(content) ||\n /for\\s*\\(\\s*var\\s+at\\s*=/.test(content) ||\n /while\\s*\\(\\s*\\w+\\s*<\\s*group\\.end/.test(content);\n\n if (!hasInnerSamplingLoop) {\n // Check if there's at least a peak-based single tween (the minimal pattern)\n const hasPeakTween =\n /peak(?:Bass|Treble|Energy)/.test(content) && /group\\.start/.test(content);\n if (hasPeakTween) {\n findings.push({\n code: \"audio_reactive_single_tween_per_group\",\n severity: \"warning\",\n message:\n \"Audio-reactive captions use a single tween per group based on peak values. \" +\n \"This sets one static value at group.start — not perceptible as audio reactivity.\",\n fixHint:\n \"Sample audio data at 100-200ms intervals throughout each group's lifetime \" +\n \"(for loop from group.start to group.end) and create a tween at each sample \" +\n \"point for visible pulsing.\",\n });\n }\n }\n }\n return findings;\n },\n\n // gsap_infinite_repeat\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n // Match repeat: -1 in GSAP tweens or timeline configs\n const pattern = /repeat\\s*:\\s*-1(?!\\d)/g;\n for (const { snippet } of scanScriptsForRegexMatches(scripts, pattern, {\n stripComments: true,\n contextBefore: 60,\n contextAfter: 60,\n })) {\n findings.push({\n code: \"gsap_infinite_repeat\",\n severity: \"error\",\n message:\n \"GSAP tween uses `repeat: -1` (infinite). Infinite repeats break the deterministic \" +\n \"capture engine which seeks to exact frame times. Use a finite repeat count calculated \" +\n \"from the composition duration: `repeat: Math.floor(duration / cycleDuration) - 1`.\",\n fixHint:\n \"Replace `repeat: -1` with a finite count, e.g. `repeat: Math.floor(totalDuration / singleCycleDuration) - 1`. \" +\n \"Use Math.floor (not Math.ceil) to ensure the animation fits within the total duration.\",\n snippet: truncateSnippet(snippet),\n });\n }\n return findings;\n },\n\n // gsap_repeat_ceil_overshoot\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n // Match patterns like: repeat: Math.ceil(duration / X) - 1\n // or repeat: Math.ceil(totalDuration / cycleDuration) - 1\n const pattern = /repeat\\s*:\\s*Math\\.ceil\\s*\\([^)]+\\)\\s*-\\s*1/g;\n for (const { snippet } of scanScriptsForRegexMatches(scripts, pattern, {\n stripComments: false,\n contextBefore: 40,\n contextAfter: 40,\n })) {\n findings.push({\n code: \"gsap_repeat_ceil_overshoot\",\n severity: \"warning\",\n message:\n \"GSAP repeat calculation uses `Math.ceil` which can overshoot the composition duration. \" +\n \"For example, Math.ceil(10.5 / 2) - 1 = 5 repeats → 6 cycles × 2s = 12s, exceeding 10.5s.\",\n fixHint:\n \"Use `Math.floor` instead of `Math.ceil` to ensure the animation fits within the duration: \" +\n \"`repeat: Math.floor(totalDuration / cycleDuration) - 1`. \" +\n \"Math.floor(10.5 / 2) - 1 = 4 repeats → 5 cycles × 2s = 10s ✓\",\n snippet: truncateSnippet(snippet),\n });\n }\n return findings;\n },\n\n // scene_layer_missing_visibility_kill\n ({ scripts, tags }) => {\n const findings: HyperframeLintFinding[] = [];\n\n // Detect multi-scene compositions: multiple elements with \"scene\" in their id\n const sceneElements = tags.filter((t) => {\n const id = readAttr(t.raw, \"id\") || \"\";\n return /^scene\\d+$/i.test(id);\n });\n if (sceneElements.length < 2) return findings;\n\n for (const script of scripts) {\n const content = stripJsComments(script.content);\n // For each scene, check if there's a visibility:hidden set after exit tweens\n for (const tag of sceneElements) {\n const id = readAttr(tag.raw, \"id\") || \"\";\n // Check if this scene has exit tweens (opacity: 0)\n const exitPattern = new RegExp(`[\"']#${id}[\"'][^)]*opacity\\\\s*:\\\\s*0`);\n const hasExit = exitPattern.test(content);\n if (!hasExit) continue;\n\n // Check if there's a hard visibility kill\n const killPattern = new RegExp(`[\"']#${id}[\"'][^)]*visibility\\\\s*:\\\\s*[\"']hidden[\"']`);\n const hasKill = killPattern.test(content);\n if (!hasKill) {\n // A tl.set on \"#id\" is only safe advice when the scene element isn't\n // itself a clip — otherwise gsap_animates_clip_element errors on that\n // exact tl.set, since the framework already owns visibility/display on\n // clip elements. Point at the inner-wrapper pattern instead.\n const classes = (readAttr(tag.raw, \"class\") || \"\").split(/\\s+/).filter(Boolean);\n const isClip = classes.includes(\"clip\");\n const fixHint = isClip\n ? `\"#${id}\" is a clip element — the framework already manages its visibility. ` +\n \"Wrap the scene's content in an inner non-clip <div>, move the exit tween and the hard kill \" +\n '(`tl.set(\"<inner-selector>\", { visibility: \"hidden\" }, <exit-end-time>)`) onto that wrapper instead.'\n : `Add \\`tl.set(\"#${id}\", { visibility: \"hidden\" }, <exit-end-time>)\\` after the scene's exit tweens.`;\n\n findings.push({\n code: \"scene_layer_missing_visibility_kill\",\n severity: \"error\",\n elementId: id,\n message:\n `Scene layer \"#${id}\" exits via opacity tween but has no visibility: hidden hard kill. ` +\n \"When scrubbing or when tweens conflict, the scene may remain partially visible and overlap the next scene.\",\n fixHint,\n });\n }\n }\n }\n return findings;\n },\n\n // gsap_timeline_not_registered\n ({ scripts, rawSource, options }) => {\n const findings: HyperframeLintFinding[] = [];\n const canInheritFromHost =\n options.isSubComposition || rawSource.trimStart().toLowerCase().startsWith(\"<template\");\n\n for (const script of scripts) {\n const content = script.content;\n if (!/gsap\\.timeline/.test(content)) continue;\n const hasRegistration =\n WINDOW_TIMELINE_ASSIGN_PATTERN.test(content) ||\n TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN.test(content);\n if (hasRegistration || canInheritFromHost) continue;\n findings.push({\n code: \"gsap_timeline_not_registered\",\n severity: \"error\",\n message:\n \"GSAP timeline is created but never registered in window.__timelines. \" +\n \"The runtime discovers timelines from this registry — without registration, \" +\n \"animations will not play during preview or render.\",\n fixHint:\n \"Add `window.__timelines = window.__timelines || {};` and \" +\n '`window.__timelines[\"root\"] = tl;` after creating the timeline (use the ' +\n \"composition's data-composition-id as the key).\",\n });\n }\n return findings;\n },\n\n // gsap_timeline_registered_before_async_build — registering window.__timelines[id]\n // BEFORE the timeline is built inside document.fonts.ready (or any async callback)\n // leaves an EMPTY timeline registered. The runtime's sub-composition readiness gate\n // treats \"key present\" as \"ready\" and nests the child ONCE, while still empty — so the\n // animation never renders when this composition is mounted as a sub-composition.\n // Register only AFTER the build completes (the documented async-setup contract).\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const script of scripts) {\n const content = stripJsComments(script.content);\n const regIdx = content.search(/window\\s*\\.\\s*__timelines\\s*\\[/);\n if (regIdx < 0) continue;\n const fontsReadyIdx = content.search(/document\\s*\\.\\s*fonts\\s*\\.\\s*ready/);\n if (fontsReadyIdx < 0) continue;\n // Registering after the async boundary is the correct pattern — skip it.\n if (regIdx >= fontsReadyIdx) continue;\n // Confirm the build is actually deferred past the boundary (a tween/build call\n // appears after document.fonts.ready), i.e. the registered timeline starts empty.\n const tail = content.slice(fontsReadyIdx);\n if (!/\\.(?:to|from|fromTo)\\s*\\(|buildEffect\\s*\\(/.test(tail)) continue;\n findings.push({\n code: \"gsap_timeline_registered_before_async_build\",\n severity: \"error\",\n message:\n \"window.__timelines is assigned BEFORE the timeline is built inside \" +\n \"document.fonts.ready. An empty timeline registered early gets nested empty \" +\n \"when this composition is used as a sub-composition (the readiness gate treats \" +\n '\"key present\" as \"ready\" and never re-nests), so the animation renders blank.',\n fixHint:\n \"Move the `window.__timelines[id] = tl;` assignment to the END of the \" +\n \"document.fonts.ready callback, after the tweens are added. Optionally call \" +\n \"window.__hfForceTimelineRebind() right after, to re-nest the populated timeline.\",\n });\n }\n return findings;\n },\n\n // gsap_from_opacity_noop — CSS opacity:0 + gsap.from({opacity:0}) = invisible forever\n // fallow-ignore-next-line complexity\n async ({ styles, scripts, tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const cssOpacityZeroSelectors = new Set<string>();\n\n for (const style of styles) {\n for (const [, selector, body] of style.content.matchAll(\n /([#.][a-zA-Z0-9_-]+)\\s*\\{([^}]+)\\}/g,\n )) {\n if (body && /opacity\\s*:\\s*0\\s*[;}]/.test(body)) {\n cssOpacityZeroSelectors.add((selector ?? \"\").trim());\n }\n }\n }\n\n for (const tag of tags) {\n const inlineStyle = readAttr(tag.raw, \"style\");\n if (!inlineStyle || !/opacity\\s*:\\s*0/.test(inlineStyle)) continue;\n const id = readAttr(tag.raw, \"id\");\n const classes = readAttr(tag.raw, \"class\")?.split(/\\s+/).filter(Boolean) ?? [];\n if (id) cssOpacityZeroSelectors.add(`#${id}`);\n for (const cls of classes) cssOpacityZeroSelectors.add(`.${cls}`);\n }\n\n if (cssOpacityZeroSelectors.size === 0) return findings;\n\n for (const script of scripts) {\n if (!/gsap\\.timeline/.test(script.content)) continue;\n const windows = await cachedExtractGsapWindows(script.content);\n\n for (const win of windows) {\n if (win.method !== \"from\") continue;\n if (!win.properties.includes(\"opacity\")) continue;\n // Only a noop when the tween animates FROM 0 (same as the CSS value)\n if (win.propertyValues[\"opacity\"] !== 0) continue;\n const sel = win.targetSelector;\n const cssKey = sel.startsWith(\"#\") || sel.startsWith(\".\") ? sel : `#${sel}`;\n if (!cssOpacityZeroSelectors.has(cssKey)) continue;\n\n findings.push({\n code: \"gsap_from_opacity_noop\",\n severity: \"error\",\n message:\n `\"${sel}\" has CSS \\`opacity: 0\\` and a gsap.${win.method}() that also sets opacity to 0. ` +\n `gsap.from() animates FROM the specified value TO the current CSS value — ` +\n `since CSS is already 0, the element animates from 0→0 and never becomes visible.`,\n selector: sel,\n fixHint:\n `Remove \\`opacity: 0\\` from the CSS/inline style on \"${sel}\". ` +\n `Let gsap.from({opacity: 0}) handle the initial hidden state — ` +\n `it will animate FROM 0 TO the CSS value (1 by default).`,\n snippet: truncateSnippet(win.raw),\n });\n }\n }\n return findings;\n },\n\n // gsap_group_selector_keyframes\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n const pattern = /\\.(?:to|from|fromTo)\\(\\s*[\"']([^\"']+,\\s*[^\"']+)[\"']\\s*,\\s*\\{[^}]*keyframes/g;\n for (const { match, snippet } of scanScriptsForRegexMatches(scripts, pattern, {\n stripComments: true,\n contextBefore: 20,\n contextAfter: 40,\n })) {\n const selector = match[1]!;\n const count = selector.split(\",\").length;\n findings.push({\n code: \"gsap_group_selector_keyframes\",\n severity: \"warning\",\n message:\n `GSAP tween targets ${count} elements with shared keyframes (\"${truncateSnippet(selector, 60)}\"). ` +\n `Editing one element's keyframes in Studio will affect all ${count} elements. ` +\n `Split into individual tweens for per-element keyframe control.`,\n fixHint:\n `Replace the group selector with individual tl.to() calls per element, ` +\n `each with their own keyframes object.`,\n snippet: truncateSnippet(snippet),\n });\n }\n return findings;\n },\n];\n","import type { LintContext, HyperframeLintFinding } from \"../context\";\n\n/** Extract a bracket-balanced array literal starting at the `[` found by `varMatch`. */\n// fallow-ignore-next-line complexity\nfunction extractArrayLiteral(src: string, varMatch: RegExpExecArray): string | null {\n const openIdx = varMatch.index + varMatch[0].length - 1;\n let depth = 0;\n let inStr = false;\n let strChar = \"\";\n for (let i = openIdx; i < src.length; i++) {\n const c = src[i]!;\n if (inStr) {\n if (c === \"\\\\\") {\n i++;\n continue;\n }\n if (c === strChar) inStr = false;\n } else if (c === '\"' || c === \"'\") {\n inStr = true;\n strChar = c;\n } else if (c === \"[\") {\n depth++;\n } else if (c === \"]\") {\n depth--;\n if (depth === 0) return src.slice(openIdx, i + 1);\n }\n }\n return null;\n}\n\nexport const captionRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // caption_exit_missing_hard_kill\n ({ scripts, styles, options, rootCompositionId }) => {\n const findings: HyperframeLintFinding[] = [];\n // Only the ACTUAL captions composition. A content frame that merely mentions\n // \"karaoke\" / \"caption-*\" in a comment (or uses an unrelated forEach + opacity:0\n // screen-swap) is NOT captions — gating here prevents the false positive that fired\n // on a content frame whose only caption signal was a descriptive comment.\n const isCaptionComposition =\n Boolean(options.filePath && /caption/i.test(options.filePath)) ||\n rootCompositionId === \"captions\" ||\n styles.some((s) => /\\.caption[-_]?(?:group|word|line|block)\\b|\\.cg-/.test(s.content));\n if (!isCaptionComposition) return findings;\n for (const script of scripts) {\n const content = script.content;\n const hasExitTween = /\\.to\\s*\\([^,]+,\\s*\\{[^}]*opacity\\s*:\\s*0/.test(content);\n const hasHardKill =\n /\\.set\\s*\\([^,]+,\\s*\\{[^}]*(?:visibility\\s*:\\s*[\"']hidden[\"']|opacity\\s*:\\s*0)/.test(\n content,\n );\n const hasCaptionLoop =\n /forEach|\\.forEach\\s*\\(/.test(content) &&\n /karaoke|caption[-_]?(?:group|word|line|block)|cg-/.test(content);\n if (hasCaptionLoop && hasExitTween && !hasHardKill) {\n findings.push({\n code: \"caption_exit_missing_hard_kill\",\n severity: \"error\",\n message:\n \"Caption exit animations (tl.to with opacity: 0) detected without a hard tl.set kill. \" +\n \"Exit tweens can fail when karaoke word-level tweens conflict, leaving captions stuck on screen.\",\n fixHint:\n 'Add `tl.set(groupEl, { opacity: 0, visibility: \"hidden\" }, group.end)` after every ' +\n \"exit tl.to animation as a deterministic kill.\",\n });\n }\n }\n return findings;\n },\n\n // caption_text_overflow_risk\n ({ styles }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const style of styles) {\n const captionBlocks = style.content.matchAll(\n /(\\.caption[-_]?(?:group|container|text|line|word)|#caption[-_]?container)\\s*\\{([^}]+)\\}/gi,\n );\n for (const [, selector, body] of captionBlocks) {\n if (!body) continue;\n const hasNowrap = /white-space\\s*:\\s*nowrap/i.test(body);\n const hasMaxWidth = /max-width/i.test(body);\n if (hasNowrap && !hasMaxWidth) {\n findings.push({\n code: \"caption_text_overflow_risk\",\n severity: \"warning\",\n selector: (selector ?? \"\").trim(),\n message: `Caption selector \"${(selector ?? \"\").trim()}\" has white-space: nowrap but no max-width. Long phrases will clip off-screen.`,\n fixHint:\n \"Add max-width: 1600px (landscape) or max-width: 900px (portrait) and overflow: hidden.\",\n });\n }\n }\n }\n return findings;\n },\n\n // caption_transcript_not_inline\n // fallow-ignore-next-line complexity\n ({ scripts, styles, options }) => {\n const findings: HyperframeLintFinding[] = [];\n // Only check files that look like caption compositions\n const isCaptionFile =\n (options.filePath && /caption/i.test(options.filePath)) ||\n styles.some((s) => /\\.caption[-_]?(?:group|word)/i.test(s.content));\n if (!isCaptionFile) return findings;\n\n const allScript = scripts.map((s) => s.content).join(\"\\n\");\n const hasInlineTranscript = /(?:const|let|var)\\s+(?:TRANSCRIPT|script)\\s*=\\s*\\[/.test(\n allScript,\n );\n const hasFetchTranscript = /fetch\\s*\\(\\s*[\"'][^\"']*transcript/i.test(allScript);\n\n if (!hasInlineTranscript && hasFetchTranscript) {\n findings.push({\n code: \"caption_transcript_not_inline\",\n severity: \"error\",\n message:\n \"Captions composition loads transcript via fetch(). The studio caption editor \" +\n \"requires an inline `var TRANSCRIPT = [...]` array to detect and edit captions.\",\n fixHint:\n 'Embed the transcript as `var TRANSCRIPT = [{ \"text\": \"...\", \"start\": 0, \"end\": 1 }, ...]` ' +\n \"with JSON-quoted property keys. See the captions skill for details.\",\n });\n }\n\n if (hasInlineTranscript) {\n // Verify the inline transcript can be parsed.\n // Use a balanced-bracket scan instead of a regex to correctly handle\n // nested arrays (e.g. word-level timing arrays inside each entry).\n const varStart = /(?:const|let|var)\\s+(?:TRANSCRIPT|script)\\s*=\\s*\\[/.exec(allScript);\n const transcriptJson = varStart ? extractArrayLiteral(allScript, varStart) : null;\n if (transcriptJson) {\n try {\n JSON.parse(transcriptJson);\n } catch {\n findings.push({\n code: \"caption_transcript_parse_error\",\n severity: \"error\",\n message:\n \"Inline TRANSCRIPT array is not valid JSON. The studio caption editor may fail \" +\n \"to parse it. Common cause: unquoted property keys with apostrophes in text.\",\n fixHint:\n 'Use JSON-quoted keys: { \"text\": \"don\\'t\", \"start\": 0, \"end\": 1 } instead of ' +\n '{ text: \"don\\'t\", start: 0, end: 1 }.',\n });\n }\n }\n }\n\n return findings;\n },\n\n // caption_container_relative_position\n ({ styles }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const style of styles) {\n const captionBlocks = style.content.matchAll(\n /(\\.caption[-_]?(?:group|container|text|line)|#caption[-_]?container)\\s*\\{([^}]+)\\}/gi,\n );\n for (const [, selector, body] of captionBlocks) {\n if (!body) continue;\n if (/position\\s*:\\s*relative/i.test(body)) {\n findings.push({\n code: \"caption_container_relative_position\",\n severity: \"error\",\n selector: (selector ?? \"\").trim(),\n message: `Caption selector \"${(selector ?? \"\").trim()}\" uses position: relative which causes overflow and breaks caption stacking.`,\n fixHint: \"Use position: absolute for all caption elements.\",\n });\n }\n }\n }\n return findings;\n },\n\n // caption_overflow_clips_scaled_words\n ({ styles, scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n const hasScaledWords = scripts.some(\n (s) => /scale\\s*:\\s*1\\.[2-9]/.test(s.content) && /caption|word|cg-/.test(s.content),\n );\n if (!hasScaledWords) return findings;\n\n for (const style of styles) {\n const captionBlocks = style.content.matchAll(\n /(\\.caption[-_]?(?:group|container)|#caption[-_]?(?:layer|container))\\s*\\{([^}]+)\\}/gi,\n );\n for (const [, selector, body] of captionBlocks) {\n if (!body) continue;\n if (/overflow\\s*:\\s*hidden/i.test(body)) {\n findings.push({\n code: \"caption_overflow_clips_scaled_words\",\n severity: \"error\",\n selector: (selector ?? \"\").trim(),\n message: `\"${(selector ?? \"\").trim()}\" has overflow: hidden but GSAP scales caption words above 1.0x. Scaled emphasis words and their glow effects will be clipped.`,\n fixHint:\n \"Use overflow: visible on caption containers. Rely on fitTextFontSize with reduced maxWidth to prevent overflow instead.\",\n });\n }\n }\n }\n return findings;\n },\n\n // caption_textshadow_on_group_container\n ({ scripts, styles }) => {\n const findings: HyperframeLintFinding[] = [];\n const isCaptionFile = styles.some((s) => /\\.caption[-_]?(?:group|word)/i.test(s.content));\n if (!isCaptionFile) return findings;\n\n for (const script of scripts) {\n // Detect textShadow tweened on a group container (div with child word spans)\n const groupShadowPattern =\n /\\.to\\s*\\(\\s*(?:div|groupEl|el|captionEl|document\\.getElementById\\s*\\(\\s*[\"']cg-)\\s*[^,]*,\\s*\\{[^}]*textShadow/g;\n // Also catch selector-based targeting of group containers\n const selectorShadowPattern =\n /\\.to\\s*\\(\\s*[\"'](?:#cg-\\d+|\\.caption[-_]?group)[\"']\\s*,\\s*\\{[^}]*textShadow/g;\n if (groupShadowPattern.test(script.content) || selectorShadowPattern.test(script.content)) {\n findings.push({\n code: \"caption_textshadow_on_group_container\",\n severity: \"warning\",\n message:\n \"textShadow is tweened on a caption group container. When children have semi-transparent \" +\n \"color (e.g., inactive karaoke words at rgba opacity), the glow renders as a visible \" +\n \"rectangle behind the entire group.\",\n fixHint:\n \"Apply textShadow to individual active word elements instead of the group container. \" +\n \"Use scale on the group for bass-reactive pulsing.\",\n });\n }\n }\n return findings;\n },\n\n // caption_fittext_scale_mismatch\n // fallow-ignore-next-line complexity\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const script of scripts) {\n const content = script.content;\n const fitTextMatch = content.match(/fitTextFontSize\\s*\\([^)]*maxWidth\\s*:\\s*(\\d+)/);\n if (!fitTextMatch) continue;\n const maxWidth = parseInt(fitTextMatch[1] ?? \"0\", 10);\n if (!maxWidth) continue;\n\n // Find max scale on caption words\n const scaleMatches = [...content.matchAll(/scale\\s*:\\s*(1\\.\\d+)/g)];\n const captionContext = /caption|word|cg-|karaoke/i.test(content);\n if (!captionContext || scaleMatches.length === 0) continue;\n\n let maxScale = 1;\n for (const m of scaleMatches) {\n const val = parseFloat(m[1] ?? \"1\");\n if (val > maxScale) maxScale = val;\n }\n\n // Check if maxWidth * maxScale exceeds safe bounds (1920 - reasonable margins)\n const effectiveWidth = maxWidth * maxScale;\n if (effectiveWidth > 1760) {\n findings.push({\n code: \"caption_fittext_scale_mismatch\",\n severity: \"warning\",\n message:\n `fitTextFontSize uses maxWidth: ${maxWidth}px but emphasis words scale up to ${maxScale}x. ` +\n `Effective width ${Math.round(effectiveWidth)}px may overflow the composition (1920px minus margins).`,\n fixHint: `Reduce maxWidth to ${Math.floor(1700 / maxScale)}px to leave headroom for scaled emphasis words.`,\n });\n }\n }\n return findings;\n },\n];\n","import type { LintContext, HyperframeLintFinding, ExtractedBlock } from \"../context\";\nimport {\n findHtmlTag,\n readAttr,\n readJsonAttr,\n stripJsComments,\n truncateSnippet,\n WINDOW_TIMELINE_ASSIGN_PATTERN,\n} from \"../utils\";\nimport { COMPOSITION_VARIABLE_TYPES } from \"@hyperframes/parsers/composition\";\n\n// Agent guidance thresholds: warning-only nudges for files/tracks that become hard\n// to inspect and revise reliably in a single composition.\nconst MAX_COMPOSITION_LINES = 300;\nconst MAX_TIMED_ELEMENTS_PER_TRACK = 3;\nconst TRACK_DENSITY_EXEMPT_TAGS = new Set([\"audio\", \"script\", \"style\", \"video\"]);\n\n// `parseFloat(\"0.1\") + parseFloat(\"0.2\") = 0.30000000000000004`. Sub-second\n// authored adjacencies survive parse + add as a value a few ulps above the\n// next clip's start; a strict `>` fires the overlap rule on adjacencies that\n// are exact in the source HTML. 1μs sits ~11 orders of magnitude above the\n// observed drift (worst ~2e-16s across every realistic decimal pair) and 4\n// below one 60fps frame (~16.67ms), so this only ever swallows float slop.\nconst OVERLAP_EPSILON_SECONDS = 1e-6;\n\nfunction countPhysicalLines(source: string): number {\n if (source.length === 0) return 0;\n\n const normalized = source.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n const withoutFinalNewline = normalized.endsWith(\"\\n\") ? normalized.slice(0, -1) : normalized;\n return withoutFinalNewline.split(\"\\n\").length;\n}\n\nfunction countStructuralLines(source: string): number {\n return countPhysicalLines(source.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, \"<style></style>\"));\n}\n\nexport function isRegistrySourceFile(filePath?: string): boolean {\n if (!filePath) return false;\n\n const normalized = filePath.replace(/\\\\/g, \"/\");\n return /(?:^|\\/)registry\\/blocks\\/([^/]+)\\/\\1\\.html$/i.test(normalized);\n}\n\nexport function isRegistryInstalledFile(rawSource: string): boolean {\n return /^\\s*<!--\\s*hyperframes-registry-item:[^>]*-->/i.test(rawSource.slice(0, 512));\n}\n\nfunction isCompositionRootOrMount(rawTag: string): boolean {\n return Boolean(\n readAttr(rawTag, \"data-composition-id\") || readAttr(rawTag, \"data-composition-src\"),\n );\n}\n\n// Asset references inside CSS `url(...)`/`url(\"...\")`/`url('...')` functions.\n// Returns the inner path without quotes; comments are stripped first so\n// `/* url(foo) */` is ignored. Bare `url()` and `data:` are excluded by the\n// rules that consume this — the helper just yields raw URL values.\nfunction extractCssUrlReferences(css: string): string[] {\n const out: string[] = [];\n const noComments = css.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n const urlPattern = /\\burl\\(\\s*([\"']?)([^)\"']+)\\1\\s*\\)/g;\n let m: RegExpExecArray | null;\n while ((m = urlPattern.exec(noComments)) !== null) {\n const raw = (m[2] ?? \"\").trim();\n if (raw) out.push(raw);\n }\n return out;\n}\n\n// Top-level CSS selectors (comma-split) in a stylesheet, skipping at-rule headers\n// (@media/@keyframes/...) and keyframe stops. Heuristic — the lint layer has no\n// full CSS parser, and rules elsewhere in this file scan CSS the same way.\nfunction extractCssSelectors(css: string): string[] {\n const out: string[] = [];\n const noComments = css.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n const ruleHeader = /([^{}]+)\\{/g;\n let m: RegExpExecArray | null;\n while ((m = ruleHeader.exec(noComments)) !== null) {\n const header = (m[1] ?? \"\").trim();\n if (!header || header.startsWith(\"@\")) continue;\n for (const sel of header.split(\",\")) {\n const s = sel.trim();\n if (s) out.push(s);\n }\n }\n return out;\n}\n\n// Class tokens in a selector's leftmost compound (before the first descendant /\n// child / sibling combinator). `.frame .title` → [\"frame\"]; `.a.b > .c` → [\"a\",\"b\"].\nfunction leftmostCompoundClasses(selector: string): string[] {\n const leftmost = selector.trim().split(/[\\s>+~]+/)[0] ?? \"\";\n return (leftmost.match(/\\.([\\w-]+)/g) ?? []).map((c) => c.slice(1));\n}\n\n// Distinct selectors across all <style> blocks whose leftmost compound keys off one\n// of the root element's own classes — the ones that break under id-scoping.\nfunction rootClassStyledSelectors(styles: ExtractedBlock[], rootClasses: string[]): string[] {\n const offenders: string[] = [];\n for (const style of styles) {\n for (const selector of extractCssSelectors(style.content)) {\n const hitsRoot = leftmostCompoundClasses(selector).some((c) => rootClasses.includes(c));\n if (hitsRoot && !offenders.includes(selector)) offenders.push(selector);\n }\n }\n return offenders;\n}\n\nexport const compositionRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // invalid_parent_traversal_in_asset_path — catches `../` traversal in src,\n // href, inline-style url(), and <style> url() asset references on\n // compositions. Sub-compositions live under compositions/ but are served\n // with the project root as their base URL, so any `../`-traversing path\n // climbs above the project root and 404s in Studio preview. Renders\n // tolerate it because the server-side bundler rewrites `../foo` against\n // each sub-composition's source path; the runtime now mirrors that fallback\n // (see rewriteSubCompositionAssetPaths in runtime/compositionLoader.ts), but\n // the authoring-time signal is still wrong — flag it at lint time so the\n // baked path is plain root-relative and matches what the bundler emits.\n //\n // Mirrors the runtime fallback's surface: `[src]` / `[href]` attribute\n // values, `[style]` inline url(), and `<style>` block url() references.\n // Skips absolute URLs (http(s)://, //, data:, /-prefixed root-relative),\n // hash anchors, and plain relative paths (`assets/x.mp4`) — only `../`\n // traversal is flagged. Subsumes the older `../capture/`-specific rule.\n // fallow-ignore-next-line complexity\n ({ tags, styles, rawSource, options }) => {\n if (isRegistrySourceFile(options.filePath) || isRegistryInstalledFile(rawSource)) return [];\n\n const offenders: string[] = [];\n const collect = (value: string | null) => {\n if (!value) return;\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"../\") && trimmed !== \"..\") return;\n offenders.push(trimmed);\n };\n\n for (const tag of tags) {\n collect(readAttr(tag.raw, \"src\"));\n collect(readAttr(tag.raw, \"href\"));\n // Use readJsonAttr for `style` — inline url('...') values contain the\n // opposite quote, which readAttr's [^\"']+ class would truncate.\n const styleAttr = readJsonAttr(tag.raw, \"style\");\n if (styleAttr) {\n for (const url of extractCssUrlReferences(styleAttr)) collect(url);\n }\n }\n for (const style of styles) {\n for (const url of extractCssUrlReferences(style.content)) collect(url);\n }\n\n if (offenders.length === 0) return [];\n\n // Group counts by leading path token (e.g. ../capture/, ../assets/, ../../assets/)\n // so the message names the offending prefixes instead of a bare count.\n const prefixCounts = new Map<string, number>();\n for (const path of offenders) {\n const prefix = path.match(/^(?:\\.\\.\\/)+[^/]+\\//)?.[0] ?? path;\n prefixCounts.set(prefix, (prefixCounts.get(prefix) ?? 0) + 1);\n }\n const prefixSummary = Array.from(prefixCounts.entries())\n .sort(([, a], [, b]) => b - a)\n .map(([prefix, count]) => (count > 1 ? `${prefix} (${count})` : prefix))\n .join(\", \");\n\n return [\n {\n code: \"invalid_parent_traversal_in_asset_path\",\n severity: \"error\",\n message:\n `Found ${offenders.length} asset path(s) traversing above the project root with \"../\" ` +\n `(${prefixSummary}). Renders rewrite this against each sub-composition's source path, but Studio preview and other live consumers resolve against the project root and 404.`,\n fixHint:\n 'Use plain root-relative paths (e.g. \"assets/...\", \"capture/...\", \"fonts/...\") — compositions are served with the project root as their base URL, so paths must be root-relative, not relative to the compositions/ directory.',\n },\n ];\n },\n\n // composition_file_too_large\n ({ rawSource, options }) => {\n if (isRegistrySourceFile(options.filePath) || isRegistryInstalledFile(rawSource)) return [];\n\n const lineCount = countStructuralLines(rawSource);\n if (lineCount <= MAX_COMPOSITION_LINES) return [];\n\n const splitTarget = options.isSubComposition\n ? \"Split this sub-composition further into smaller .html files\"\n : \"Split coherent scenes or layers into separate .html files under compositions/\";\n\n return [\n {\n code: \"composition_file_too_large\",\n severity: \"warning\",\n message: `This HTML composition file has ${lineCount} lines. Smaller sub-compositions are easier to read, iterate on, and diff.`,\n fixHint: `${splitTarget}, then mount them from the parent with data-composition-src so each file stays small enough to inspect, revise, and validate independently.`,\n },\n ];\n },\n\n // timeline_track_too_dense\n // fallow-ignore-next-line complexity\n ({ tags, options }) => {\n const trackCounts = new Map<string, number>();\n for (const tag of tags) {\n if (TRACK_DENSITY_EXEMPT_TAGS.has(tag.name)) continue;\n if (isCompositionRootOrMount(tag.raw)) continue;\n if (!readAttr(tag.raw, \"data-start\")) continue;\n\n const track = readAttr(tag.raw, \"data-track-index\");\n if (!track) continue;\n trackCounts.set(track, (trackCounts.get(track) ?? 0) + 1);\n }\n\n const findings: HyperframeLintFinding[] = [];\n for (const [track, count] of trackCounts) {\n if (count <= MAX_TIMED_ELEMENTS_PER_TRACK) continue;\n const splitTarget = options.isSubComposition\n ? \"Move coherent scene groups into smaller .html files\"\n : \"Move coherent scene groups into separate .html files under compositions/\";\n findings.push({\n code: \"timeline_track_too_dense\",\n severity: \"warning\",\n message: `Track ${track} has ${count} timed elements in this HTML file. Smaller sub-compositions keep timelines easier to read, iterate on, and diff.`,\n fixHint: `${splitTarget} and mount them from the parent with data-composition-src so the timeline stays easier to inspect, revise, and validate.`,\n });\n }\n\n return findings;\n },\n\n // timed_element_missing_visibility_hidden\n // fallow-ignore-next-line complexity\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (tag.name === \"audio\" || tag.name === \"script\" || tag.name === \"style\") continue;\n if (!readAttr(tag.raw, \"data-start\")) continue;\n if (readAttr(tag.raw, \"data-composition-id\")) continue;\n if (readAttr(tag.raw, \"data-composition-src\")) continue;\n const classAttr = readAttr(tag.raw, \"class\") || \"\";\n const styleAttr = readAttr(tag.raw, \"style\") || \"\";\n const hasClip = classAttr.split(/\\s+/).includes(\"clip\");\n const hasHiddenStyle =\n /visibility\\s*:\\s*hidden/i.test(styleAttr) || /opacity\\s*:\\s*0/i.test(styleAttr);\n if (!hasClip && !hasHiddenStyle) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"timed_element_missing_visibility_hidden\",\n severity: \"info\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> has data-start but no class=\"clip\", visibility:hidden, or opacity:0. Consider adding initial hidden state if the element should not be visible before its start time.`,\n elementId,\n fixHint:\n 'Add class=\"clip\" (with CSS: .clip { visibility: hidden; }) or style=\"opacity:0\" if the element should start hidden.',\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // deprecated_data_layer + deprecated_data_end\n // fallow-ignore-next-line complexity\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (readAttr(tag.raw, \"data-layer\") && !readAttr(tag.raw, \"data-track-index\")) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"deprecated_data_layer\",\n severity: \"error\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> uses data-layer instead of data-track-index.`,\n elementId,\n fixHint: \"Replace data-layer with data-track-index. The runtime reads data-track-index.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n if (readAttr(tag.raw, \"data-end\") && !readAttr(tag.raw, \"data-duration\")) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"deprecated_data_end\",\n severity: \"error\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> uses data-end without data-duration. Use data-duration in source HTML.`,\n elementId,\n fixHint:\n \"Replace data-end with data-duration. The compiler generates data-end from data-duration automatically.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // split_data_attribute_selector\n ({ scripts, styles }) => {\n const findings: HyperframeLintFinding[] = [];\n const splitDataAttrSelectorPattern =\n /\\[data-composition-id=([\"'])([^\"'\\]]+)\\1\\s+(data-[\\w:-]+)=([\"'])([^\"'\\]]*)\\4\\]/g;\n const scan = (content: string) => {\n splitDataAttrSelectorPattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = splitDataAttrSelectorPattern.exec(content)) !== null) {\n const compId = match[2] ?? \"\";\n const attrName = match[3] ?? \"\";\n const attrValue = match[5] ?? \"\";\n findings.push({\n code: \"split_data_attribute_selector\",\n severity: \"error\",\n message:\n `Selector \"${match[0]}\" combines two attributes inside one CSS attribute selector. ` +\n \"Browsers reject it, so GSAP timelines or querySelector calls will fail before registering.\",\n selector: match[0],\n fixHint: `Use separate attribute selectors: [data-composition-id=\"${compId}\"][${attrName}=\"${attrValue}\"].`,\n snippet: truncateSnippet(match[0]),\n });\n }\n };\n for (const style of styles) scan(style.content);\n for (const script of scripts) scan(script.content);\n return findings;\n },\n\n // template_literal_selector\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const script of scripts) {\n const templateLiteralSelectorPattern =\n /(?:querySelector|querySelectorAll)\\s*\\(\\s*`[^`]*\\$\\{[^}]+\\}[^`]*`\\s*\\)/g;\n let tlMatch: RegExpExecArray | null;\n while ((tlMatch = templateLiteralSelectorPattern.exec(script.content)) !== null) {\n findings.push({\n code: \"template_literal_selector\",\n severity: \"error\",\n message:\n \"querySelector uses a template literal variable (e.g. `${compId}`). \" +\n \"The HTML bundler's CSS parser crashes on these. Use a hardcoded string instead.\",\n fixHint:\n \"Replace the template literal variable with a hardcoded string. The bundler's CSS parser cannot handle interpolated variables in script content.\",\n snippet: truncateSnippet(tlMatch[0]),\n });\n }\n }\n return findings;\n },\n\n // timed_element_missing_clip_class\n // fallow-ignore-next-line complexity\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const skipTags = new Set([\"audio\", \"video\", \"script\", \"style\", \"template\"]);\n for (const tag of tags) {\n if (skipTags.has(tag.name)) continue;\n // Skip composition hosts\n if (readAttr(tag.raw, \"data-composition-id\")) continue;\n if (readAttr(tag.raw, \"data-composition-src\")) continue;\n\n const hasStart = readAttr(tag.raw, \"data-start\") !== null;\n const hasDuration = readAttr(tag.raw, \"data-duration\") !== null;\n // data-track-index alone marks a layer container, not a time-bounded clip\n if (!hasStart && !hasDuration) continue;\n\n const classAttr = readAttr(tag.raw, \"class\") || \"\";\n const hasClip = classAttr.split(/\\s+/).includes(\"clip\");\n if (hasClip) continue;\n\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"timed_element_missing_clip_class\",\n severity: \"error\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> has timing attributes but no class=\"clip\". The element will be visible for the entire composition instead of only during its scheduled time range.`,\n elementId,\n fixHint:\n 'Add class=\"clip\" to the element. The HyperFrames runtime uses .clip to control visibility based on data-start/data-duration.',\n snippet: truncateSnippet(tag.raw),\n });\n }\n return findings;\n },\n\n // overlapping_clips_same_track\n // fallow-ignore-next-line complexity\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n\n type ClipInfo = { start: number; end: number; elementId?: string; snippet: string };\n const trackMap = new Map<string, ClipInfo[]>();\n\n for (const tag of tags) {\n const startStr = readAttr(tag.raw, \"data-start\");\n const durationStr = readAttr(tag.raw, \"data-duration\");\n const trackStr = readAttr(tag.raw, \"data-track-index\");\n if (!startStr || !durationStr || !trackStr) continue;\n\n const start = Number(startStr);\n const duration = Number(durationStr);\n const track = trackStr;\n\n // Skip non-numeric (relative timing references like \"intro-comp\")\n if (Number.isNaN(start) || Number.isNaN(duration)) continue;\n\n const clips = trackMap.get(track) || [];\n clips.push({\n start,\n end: start + duration,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n snippet: truncateSnippet(tag.raw) || \"\",\n });\n trackMap.set(track, clips);\n }\n\n for (const [track, clips] of trackMap) {\n clips.sort((a, b) => a.start - b.start);\n for (let i = 0; i < clips.length - 1; i++) {\n const current = clips[i];\n const next = clips[i + 1];\n if (!current || !next) continue;\n if (current.end - next.start > OVERLAP_EPSILON_SECONDS) {\n findings.push({\n code: \"overlapping_clips_same_track\",\n severity: \"error\",\n message: `Track ${track}: clip ending at ${current.end}s overlaps with clip starting at ${next.start}s. Overlapping clips on the same track cause rendering conflicts.`,\n fixHint:\n \"Adjust data-start or data-duration so clips on the same track do not overlap, or move one clip to a different data-track-index.\",\n });\n }\n }\n }\n\n return findings;\n },\n\n // root_composition_missing_data_start\n ({ rootTag, options }) => {\n const findings: HyperframeLintFinding[] = [];\n if (options.isSubComposition) return findings;\n if (!rootTag) return findings;\n const compId = readAttr(rootTag.raw, \"data-composition-id\");\n if (!compId) return findings;\n const hasStart = readAttr(rootTag.raw, \"data-start\") !== null;\n if (!hasStart) {\n findings.push({\n code: \"root_composition_missing_data_start\",\n severity: \"error\",\n message: `Root composition \"${compId}\" is missing data-start. The runtime needs data-start=\"0\" on the root element to begin playback.`,\n fixHint: 'Add data-start=\"0\" to the root composition element.',\n snippet: truncateSnippet(rootTag.raw),\n });\n }\n return findings;\n },\n\n // standalone_composition_wrapped_in_template\n ({ rawSource, options }) => {\n const findings: HyperframeLintFinding[] = [];\n if (options.isSubComposition) return findings;\n const trimmed = rawSource.trimStart().toLowerCase();\n if (trimmed.startsWith(\"<template\")) {\n findings.push({\n code: \"standalone_composition_wrapped_in_template\",\n severity: \"error\",\n message:\n \"Root index.html is wrapped in a <template> tag. \" +\n \"Only sub-compositions loaded via data-composition-src should use <template> wrappers. \" +\n \"The runtime cannot play a standalone composition inside a template.\",\n fixHint:\n \"Remove the <template> wrapper. Use <!DOCTYPE html><html>...<div data-composition-id>...</div>...</html> instead.\",\n });\n }\n return findings;\n },\n\n // root_composition_missing_html_wrapper\n ({ rawSource, rootTag, options }) => {\n const findings: HyperframeLintFinding[] = [];\n if (options.isSubComposition) return findings;\n const trimmed = rawSource.trimStart().toLowerCase();\n // Compositions inside <template> are caught by standalone_composition_wrapped_in_template\n if (trimmed.startsWith(\"<template\")) return findings;\n const hasDoctype = trimmed.startsWith(\"<!doctype\") || trimmed.startsWith(\"<html\");\n const hasComposition = rawSource.includes(\"data-composition-id\");\n if (hasComposition && !hasDoctype) {\n findings.push({\n code: \"root_composition_missing_html_wrapper\",\n severity: \"error\",\n message:\n \"Composition starts with a bare element instead of a proper HTML document. \" +\n \"An index.html that contains data-composition-id but no <!DOCTYPE html>, <html>, or <body> \" +\n \"is a fragment — browsers quirks-mode it, the preview server cannot load it, and \" +\n \"the bundler will fail to inject runtime scripts.\",\n fixHint:\n 'Wrap the composition in <!DOCTYPE html><html><head><meta charset=\"UTF-8\"></head><body>...</body></html>.',\n snippet: rootTag ? truncateSnippet(rootTag.raw) : undefined,\n });\n }\n return findings;\n },\n\n // missing_data_no_timeline\n // The producer polls window.__timelines[id] with a 45-second timeout waiting\n // for GSAP timeline registration. Compositions that never call\n // window.__timelines[id] = tl stall for 45 s every render. Adding\n // data-no-timeline to the root element tells the producer to skip the poll.\n ({ rootTag, rootCompositionId, scripts, rawSource, options }) => {\n if (options.isSubComposition) return [];\n if (!rootCompositionId || !rootTag) return [];\n // readAttr only matches valued attrs (attr=\"...\"); data-no-timeline is\n // typically boolean (no value). Strip quoted attribute values first to\n // avoid matching attr names that appear inside other values\n // (e.g. title=\"add data-no-timeline here\"), then check with a boundary\n // that rejects hyphenated variants (data-no-timeline-start has '-' next,\n // not a word-break char).\n const tagNoValues = rootTag.raw.replace(/\"[^\"]*\"|'[^']*'/g, '\"\"');\n if (/(?:^|\\s)data-no-timeline(?=[\\s>=/]|$)/i.test(tagNoValues)) return [];\n // Can't scan external script files for timeline registration; skip to avoid\n // false positives on compositions that register via a bundled JS file.\n if (/<script\\b[^>]*\\bsrc\\s*=/i.test(rawSource)) return [];\n const registersTimeline = scripts.some((s) => s.content.includes(\"window.__timelines[\"));\n if (registersTimeline) return [];\n return [\n {\n code: \"missing_data_no_timeline\",\n severity: \"warning\",\n message:\n \"This composition has no `window.__timelines` registration but is missing `data-no-timeline`. \" +\n \"The producer polls for timeline registration for up to 45 seconds before timing out, \" +\n \"adding 45 s to every render.\",\n fixHint:\n 'Add `data-no-timeline` to the root element to skip the poll: `<div data-composition-id=\"...\" data-no-timeline ...>`.',\n snippet: truncateSnippet(rootTag.raw),\n },\n ];\n },\n\n // requestanimationframe_in_composition\n ({ scripts, rawSource, options }) => {\n if (isRegistrySourceFile(options.filePath) || isRegistryInstalledFile(rawSource)) return [];\n const findings: HyperframeLintFinding[] = [];\n for (const script of scripts) {\n const stripped = stripJsComments(script.content);\n if (/requestAnimationFrame\\s*\\(/.test(stripped)) {\n findings.push({\n code: \"requestanimationframe_in_composition\",\n severity: \"error\",\n message:\n \"`requestAnimationFrame` runs on wall-clock time, not the GSAP timeline. It will not sync with frame capture and may cause flickering or missed frames during rendering.\",\n fixHint:\n \"Use GSAP tweens or onUpdate callbacks instead of requestAnimationFrame for animation logic.\",\n snippet: truncateSnippet(script.content),\n });\n }\n }\n return findings;\n },\n\n // invalid_variable_values_json\n // Host elements (`[data-composition-src]`) carry per-instance values via\n // `data-variable-values`. The runtime swallows JSON errors silently and\n // falls back to declared defaults, which masks typos. This rule surfaces\n // the parse failure so authors notice before render time.\n // fallow-ignore-next-line complexity\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n const raw = readJsonAttr(tag.raw, \"data-variable-values\");\n if (!raw) continue;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"unknown\";\n findings.push({\n code: \"invalid_variable_values_json\",\n severity: \"error\",\n message: `data-variable-values is not valid JSON (${reason}).`,\n fixHint:\n 'Wrap the attribute value in single quotes and the JSON keys/values in double quotes, e.g. data-variable-values=\\'{\"title\":\"Hello\"}\\'.',\n elementId: readAttr(tag.raw, \"id\") || undefined,\n snippet: truncateSnippet(tag.raw),\n });\n continue;\n }\n\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n findings.push({\n code: \"invalid_variable_values_json\",\n severity: \"error\",\n message:\n 'data-variable-values must be a JSON object keyed by variable id (e.g. {\"title\":\"Hello\"}).',\n fixHint:\n \"Replace the value with a JSON object whose keys are variable ids declared in the sub-composition's data-composition-variables.\",\n elementId: readAttr(tag.raw, \"id\") || undefined,\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // invalid_composition_variables_declaration\n // The runtime parses `data-composition-variables` and silently returns []\n // on any structural problem. Surface JSON / shape failures so authors\n // catch them at lint time rather than wondering why their `getVariables()`\n // defaults aren't applied.\n // fallow-ignore-next-line complexity\n ({ source }) => {\n const htmlTag = findHtmlTag(source);\n if (!htmlTag) return [];\n const raw = readJsonAttr(htmlTag.raw, \"data-composition-variables\");\n if (!raw) return [];\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"unknown\";\n return [\n {\n code: \"invalid_composition_variables_declaration\",\n severity: \"error\",\n message: `data-composition-variables is not valid JSON (${reason}).`,\n fixHint:\n 'Provide a JSON array of variable declarations: data-composition-variables=\\'[{\"id\":\"title\",\"type\":\"string\",\"label\":\"Title\",\"default\":\"Hello\"}]\\'.',\n snippet: truncateSnippet(htmlTag.raw),\n },\n ];\n }\n\n if (!Array.isArray(parsed)) {\n return [\n {\n code: \"invalid_composition_variables_declaration\",\n severity: \"error\",\n message: \"data-composition-variables must be a JSON array of variable declarations.\",\n fixHint:\n 'Wrap declarations in [] and give each an id, type, label, and default: \\'[{\"id\":\"title\",\"type\":\"string\",\"label\":\"Title\",\"default\":\"Hello\"}]\\'.',\n snippet: truncateSnippet(htmlTag.raw),\n },\n ];\n }\n\n const findings: HyperframeLintFinding[] = [];\n const knownTypes = new Set<string>(COMPOSITION_VARIABLE_TYPES);\n for (let i = 0; i < parsed.length; i += 1) {\n const entry = parsed[i];\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n findings.push({\n code: \"invalid_composition_variables_declaration\",\n severity: \"error\",\n message: `data-composition-variables entry [${i}] must be an object with id, type, label, and default.`,\n snippet: truncateSnippet(htmlTag.raw),\n });\n continue;\n }\n const e = entry as Record<string, unknown>;\n const missing: string[] = [];\n if (typeof e.id !== \"string\") missing.push(\"id\");\n if (typeof e.type !== \"string\" || !knownTypes.has(e.type)) missing.push(\"type\");\n if (typeof e.label !== \"string\") missing.push(\"label\");\n if (!(\"default\" in e)) missing.push(\"default\");\n if (missing.length > 0) {\n findings.push({\n code: \"invalid_composition_variables_declaration\",\n severity: \"error\",\n message: `data-composition-variables entry [${i}] is missing or has invalid: ${missing.join(\", \")}. Type must be one of string, number, color, boolean, enum, font, image.`,\n snippet: truncateSnippet(htmlTag.raw),\n });\n }\n }\n return findings;\n },\n\n // html_dir_attribute_breaks_render — valid non-LTR dir values on\n // <html> renders correctly in preview/snapshot but produces a fully\n // blank/black video from render, with no other lint/validate/inspect\n // check catching it (output file size, far smaller than expected, is the\n // only tell). Confirmed independently by two separate reports, both\n // diagnosing the same exact trigger and the same fix: drop dir from\n // <html>, keep lang, and scope `direction: rtl` to individual\n // text-containing elements via CSS instead (text still bidi-shapes\n // correctly). Advisory-only — this does not attempt to fix the render\n // pipeline's own root cause (suspected to be a capture step that clips a\n // fixed top-left-origin screenshot region, which RTL layout can shift the\n // actual content away from), only surfaces the already-confirmed footgun\n // before someone hits it blind.\n ({ source }) => {\n const htmlTag = findHtmlTag(source);\n if (!htmlTag) return [];\n const dir = readAttr(htmlTag.raw, \"dir\");\n if (!dir) return [];\n const normalizedDir = dir.toLowerCase();\n if (normalizedDir !== \"rtl\" && normalizedDir !== \"auto\") return [];\n const scopedDirection = normalizedDir === \"auto\" ? 'dir=\"auto\"' : `direction: ${normalizedDir}`;\n return [\n {\n code: \"html_dir_attribute_breaks_render\",\n severity: \"error\",\n message: `<html dir=\"${dir}\"> renders correctly in preview/snapshot but produces a fully blank/black video from render — a confirmed, silent failure.`,\n fixHint: `Remove dir=\"${dir}\" from <html>. Keep lang, and scope ${scopedDirection} to individual text-containing elements instead — text still shapes correctly via the browser's own bidi algorithm.`,\n snippet: truncateSnippet(htmlTag.raw),\n },\n ];\n },\n\n // subcomposition_blanks_before_host\n // Warns when a full-bleed sub-composition slot ends before the host composition\n // does, leaving the slot blank for the remainder (issue #1540). Scoped narrowly to\n // the high-signal shape — a sole/dominant external mount starting at ~0 — so it\n // stays silent on intentional short clips (an intro followed by other clips that\n // carry the timeline forward).\n // fallow-ignore-next-line complexity\n ({ tags, rootTag }) => {\n if (!rootTag) return [];\n const rootDuration = Number(readAttr(rootTag.raw, \"data-duration\"));\n if (!Number.isFinite(rootDuration) || rootDuration <= 0) return [];\n\n // Two independent knobs that happen to share a 0.5s magnitude. Tuned for\n // real hosts (tens to hundreds of seconds); on a very short host (~6s) the\n // EPSILON slack would let a ~10% blank tail pass unflagged — acceptable\n // because the silent-blank trap this rule targets only matters at scale.\n const EPSILON = 0.5; // seconds; tolerance for \"ends/covers near the host end\"\n const START_TOLERANCE = 0.5; // seconds; \"starts at the composition start\"\n const round3 = (n: number) => Math.round(n * 1000) / 1000;\n\n // Timed children of the root. An element with data-start but no usable\n // data-duration is treated as covering the tail (end = Infinity), so an\n // unknown-length sibling suppresses the warning rather than triggering it.\n const timed = tags\n .filter((tag) => tag.index !== rootTag.index && readAttr(tag.raw, \"data-start\") !== null)\n .map((tag) => {\n const start = Number(readAttr(tag.raw, \"data-start\")) || 0;\n const dur = Number(readAttr(tag.raw, \"data-duration\"));\n const end = Number.isFinite(dur) && dur > 0 ? start + dur : Infinity;\n return { tag, start, end };\n });\n\n // `tags` is a flat list (no nesting depth), so a timed element nested\n // *inside* a candidate slot is treated as a tail-covering sibling rather\n // than a descendant. Acceptable: external src mounts are empty by\n // convention (content is loaded from the linked file), so the only\n // false-negative path is rare and matches the flat-tag scope of the\n // sibling rules in this file.\n const tailCovered = (exceptIndex: number) =>\n timed.some((t) => t.tag.index !== exceptIndex && t.end >= rootDuration - EPSILON);\n\n const findings: HyperframeLintFinding[] = [];\n for (const t of timed) {\n if (readAttr(t.tag.raw, \"data-composition-src\") === null) continue; // external slot only\n if (t.start > START_TOLERANCE) continue; // must start at the composition start\n if (!Number.isFinite(t.end)) continue; // known, finite slot length\n if (t.end >= rootDuration - EPSILON) continue; // already fills the host window\n if (tailCovered(t.tag.index)) continue; // another clip covers the tail — not full-bleed\n const elementId = readAttr(t.tag.raw, \"id\") || undefined;\n const gap = round3(rootDuration - t.end);\n findings.push({\n code: \"subcomposition_blanks_before_host\",\n severity: \"warning\",\n message: `<${t.tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> sub-composition ends at ${round3(t.end)}s but the composition runs to ${round3(rootDuration)}s — its slot will be blank for ~${gap}s.`,\n elementId,\n fixHint: `data-duration is the slot's visible window. Set this sub-composition's data-duration to ${round3(rootDuration - t.start)} to fill the host window, or add another clip to cover the remaining ~${gap}s.`,\n snippet: truncateSnippet(t.tag.raw),\n });\n }\n return findings;\n },\n\n // subcomposition_root_styled_by_class\n // A sub-composition's <style> is scoped at render time to\n // `[data-composition-id=\"<id>\"] <selector>` so scenes inlined into one document\n // can't leak styles into each other. A rule whose LEFTMOST selector is the ROOT\n // element's own class (e.g. `.frame { ... }` on the same element that carries\n // data-composition-id) therefore becomes a DESCENDANT selector that can never\n // match the root — the whole scene renders unstyled (tiny text top-left, images\n // at natural size). lint/validate/inspect evaluate the file in isolation (no\n // scoping) and Studio previews each scene in its own iframe (no scoping), so the\n // break is invisible until the composited MP4 render. Style the root via `#root`\n // (the scoper special-cases the root id) and descendants via plain selectors,\n // like the registry blocks — the runtime already scopes each scene by id, so a\n // class namespace on the root is redundant.\n ({ rootTag, rootCompositionId, styles, options }) => {\n if (!options.isSubComposition) return [];\n if (isRegistrySourceFile(options.filePath)) return [];\n if (!rootTag || !rootCompositionId) return [];\n\n const rootClasses = (readAttr(rootTag.raw, \"class\") || \"\").split(/\\s+/).filter(Boolean);\n if (rootClasses.length === 0) return [];\n\n const offenders = rootClassStyledSelectors(styles, rootClasses);\n if (offenders.length === 0) return [];\n\n const example = offenders.slice(0, 3).join(\", \");\n return [\n {\n code: \"subcomposition_root_styled_by_class\",\n severity: \"error\",\n message:\n `Root element has class=\"${rootClasses.join(\" \")}\" and is styled by ${offenders.length} rule(s) keyed off that class (e.g. ${example}). ` +\n `At render, every sub-composition rule is scoped to [data-composition-id=\"${rootCompositionId}\"] <selector>, so a selector whose leftmost part is the ROOT's own class becomes a descendant selector that cannot match the root — the scene renders unstyled (tiny text top-left, full-size images). ` +\n `lint/validate/inspect and Studio's per-frame iframe preview do not scope, so this passes every static check and looks correct in preview.`,\n selector: example,\n fixHint: `Give the root id=\"root\" and style it with \\`#root { ... }\\` plus plain descendant selectors (\\`.kicker\\`, \\`#hero\\`) — the runtime already scopes each sub-composition by data-composition-id, so a class namespace on the root is redundant and breaks under scoping.`,\n snippet: truncateSnippet(rootTag.raw),\n },\n ];\n },\n\n // root_composition_missing_duration_source\n //\n // The render engine (packages/engine/src/services/frameCapture.ts) needs a\n // positive window.__hf.duration to know how many frames to capture. GSAP\n // timelines set this automatically. Non-GSAP runtimes (CSS, WAAPI, Lottie)\n // are now auto-inferred by the runtime too (see\n // packages/core/src/runtime/init.ts resolveAdapterDurationFloorSeconds and\n // the adapters' getInferredDurationSeconds) — so data-duration is optional\n // wherever the runtime can work it out on its own.\n //\n // This rule fires for cases where the total render length is not reliably\n // determinable without an explicit data-duration:\n // - No GSAP timeline AND no data-duration AND no non-GSAP animation\n // signal at all (nothing for any adapter to discover — render fails).\n // - Three.js used with no data-duration (no discoverable AnimationClip\n // duration in this codebase's adapter — see adapters/three.ts).\n // - Any infinite CSS animation-iteration-count with no data-duration,\n // EVEN when a finite CSS animation is present alongside it. An unbounded\n // animation makes the intended total length ambiguous — the runtime will\n // infer a finite sibling's length if one exists, but that's a fallback,\n // not a declaration of intent, so we still require data-duration here.\n // (This is intentionally stricter than the runtime's own inference.)\n // Purely finite CSS/WAAPI animations and Lottie are excluded — the runtime\n // infers those unambiguously, so requiring data-duration there would be a\n // false positive against the runtime's own auto-inference. Note lint is\n // advisory by default (see shouldBlockRender) — it only blocks render under\n // --strict/--strict-all — so a strict flag here nudges toward an explicit,\n // guaranteed-correct value without failing renders that would succeed.\n // fallow-ignore-next-line complexity\n ({ rootTag, scripts, styles, tags, options }) => {\n if (options.isSubComposition) return [];\n if (!rootTag) return [];\n // Not every file linted as a \"root\" HTML document is a video composition\n // — e.g. a slideshow demo.html mounts <hyperframes-player src=\"index.html\">\n // with no data-composition-id of its own. Nothing to capture there, so\n // there's no duration contract to enforce.\n if (readAttr(rootTag.raw, \"data-composition-id\") === null) return [];\n if (readAttr(rootTag.raw, \"data-duration\") !== null) return [];\n\n // Strip comments before scanning for signals — a commented-out\n // `.animate(...)` call or `/* animation: spin 2s infinite; */` must not\n // satisfy the \"has a duration source\" check, or the composition still\n // fails at render with zero duration despite lint passing.\n const allScriptTexts = scripts.map((s) => stripJsComments(s.content));\n const hasGsapTimeline = allScriptTexts.some((t) => /gsap\\.timeline\\s*\\(/.test(t));\n const hasRegisteredTimeline = allScriptTexts.some((t) =>\n WINDOW_TIMELINE_ASSIGN_PATTERN.test(t),\n );\n // A GSAP timeline drives duration via window.__timelines regardless of\n // data-duration — nothing to flag once one is registered.\n if (hasGsapTimeline && hasRegisteredTimeline) return [];\n\n const allCss = styles.map((s) => s.content).join(\"\\n\");\n const allInlineStyles = tags.map((t) => readAttr(t.raw, \"style\") || \"\").join(\"\\n\");\n const combinedCss = `${allCss}\\n${allInlineStyles}`.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n\n const usesLottie =\n tags.some((t) => readAttr(t.raw, \"data-lottie-src\") !== null) ||\n allScriptTexts.some((t) => /lottie\\.(loadAnimation)\\b|__hfLottie\\b/.test(t));\n const usesThree = allScriptTexts.some((t) => /\\bTHREE\\./.test(t));\n // `.animate([...], ...)` catches the array-literal keyframes form;\n // `.animate({...}, ...)` catches the object-literal (PropertyIndexedKeyframes)\n // form; `.animate(someVar, ...)` catches keyframes built up in a variable\n // first.\n const usesWaapi = allScriptTexts.some((t) => /\\.animate\\s*\\(\\s*[[{$A-Za-z_]/.test(t));\n const hasCssAnimationName = /\\banimation(?:-name)?\\s*:/.test(combinedCss);\n const hasInfiniteCssAnimation =\n /\\banimation(?:-iteration-count)?\\s*:[^;{}]*(?<![\\w-])infinite(?![\\w-])/.test(combinedCss);\n\n const hasAnyNonGsapSignal = usesLottie || usesThree || usesWaapi || hasCssAnimationName;\n\n if (!hasAnyNonGsapSignal) {\n // No GSAP timeline, no data-duration, and nothing for any adapter to\n // discover — the composition has no source of truth for duration at\n // all. This is the exact shape of the 27K \"zero duration\" render\n // failures this rule exists to catch before render time.\n return [\n {\n code: \"root_composition_missing_duration_source\",\n severity: \"error\",\n message:\n \"Root composition has no data-duration, no GSAP timeline, and no CSS/WAAPI/Lottie/Three.js \" +\n \"animation for the runtime to infer a duration from. The render engine cannot determine \" +\n 'how long to capture and will fail with \"Composition has zero duration\".',\n fixHint:\n 'Add data-duration=\"<seconds>\" to the root element, or add a paused GSAP timeline registered ' +\n \"on window.__timelines.\",\n snippet: truncateSnippet(rootTag.raw),\n },\n ];\n }\n\n if (usesThree) {\n // No AnimationMixer/AnimationClip discovery in the three.js adapter\n // today (see adapters/three.ts) — genuinely not inferable.\n return [\n {\n code: \"root_composition_missing_duration_source\",\n severity: \"error\",\n message:\n \"Root composition uses Three.js with no data-duration. The runtime cannot discover a \" +\n \"Three.js scene's duration automatically (no AnimationClip/AnimationMixer inspection) — \" +\n 'render will fail with \"Composition has zero duration\".',\n fixHint: 'Add data-duration=\"<seconds>\" to the root element.',\n snippet: truncateSnippet(rootTag.raw),\n },\n ];\n }\n\n if (hasInfiniteCssAnimation && !usesLottie && !usesWaapi) {\n // An infinite/unbounded CSS animation makes the intended total length\n // ambiguous, so we require an explicit data-duration even when a finite\n // CSS animation is present alongside it. This is deliberately stricter\n // than the runtime's own inference: the CSS adapter's\n // getInferredDurationSeconds (see adapters/css.ts) returns the longest\n // finite animation end-time when one exists (so a finite sibling would\n // render at that length) and null when every animation is unbounded (so\n // a render with no finite source fails outright). Either way the author\n // hasn't declared how long the video should be — a decorative infinite\n // spinner next to a 3s fade doesn't tell us the clip is meant to be 3s\n // — so we flag it and let them state intent. The message stays honest\n // about both outcomes rather than claiming the render always fails.\n return [\n {\n code: \"root_composition_missing_duration_source\",\n severity: \"error\",\n message:\n \"Root composition uses a CSS animation with animation-iteration-count: infinite and no \" +\n \"data-duration, so the intended total length is ambiguous. If a finite animation is also \" +\n \"present the runtime infers that length; with no finite source the render fails with \" +\n '\"Composition has zero duration\". Declare the intended length explicitly.',\n fixHint:\n 'Add data-duration=\"<seconds>\" to the root element with the intended total length.',\n snippet: truncateSnippet(rootTag.raw),\n },\n ];\n }\n\n // Finite CSS animation, WAAPI .animate(), or Lottie — the runtime infers\n // duration from these at render time (see resolveAdapterDurationFloorSeconds\n // in runtime/init.ts). Not an error; data-duration is optional here.\n return [];\n },\n];\n","import type { LintContext, HyperframeLintFinding } from \"../context\";\nimport { readAttr, extractScriptTextsAndSrcs } from \"../utils\";\n\nexport const adapterRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // missing_lottie_script\n ({ tags, scripts }) => {\n const { texts, srcs } = extractScriptTextsAndSrcs(scripts);\n\n const hasLottieAttr = tags.some((t) => readAttr(t.raw, \"data-lottie-src\") !== null);\n const usesLottieApi = texts.some((t) =>\n /lottie\\.(loadAnimation|setSpeed|play|stop|destroy)\\b/.test(t),\n );\n const hasLottieScript = srcs.some((src) => /lottie/i.test(src));\n\n if (!(hasLottieAttr || usesLottieApi) || hasLottieScript) return [];\n return [\n {\n code: \"missing_lottie_script\",\n severity: \"error\",\n message:\n \"Composition uses Lottie but no Lottie script is loaded. The animation will not render.\",\n fixHint:\n 'Add <script src=\"https://cdn.jsdelivr.net/npm/lottie-web@5/build/player/lottie.min.js\"></script> before your Lottie code.',\n },\n ];\n },\n\n // missing_three_script\n ({ scripts }) => {\n const { texts, srcs } = extractScriptTextsAndSrcs(scripts);\n\n const usesThree = texts.some((t) => /\\bTHREE\\./.test(t));\n const hasThreeScript = srcs.some((src) => /three/i.test(src));\n const hasThreeImportMap = texts.some(\n (t) =>\n /[\"']three[\"']/.test(t) &&\n /importmap/.test(scripts.find((s) => s.content === t)?.attrs || \"\"),\n );\n // Matches any import/from whose specifier contains \"three\" (bare 'three', or a\n // URL/path like .../+esm, esm.sh/three, three.module.js), mirroring the loose\n // /three/i treatment of <script src>.\n const hasThreeModuleImport = texts.some((t) =>\n /\\b(?:import|from)\\s*[^;\\n]*['\"][^'\"]*three[^'\"]*['\"]/i.test(t),\n );\n\n if (!usesThree || hasThreeScript || hasThreeImportMap || hasThreeModuleImport) return [];\n return [\n {\n code: \"missing_three_script\",\n severity: \"error\",\n message:\n \"Composition uses Three.js but no Three.js script is loaded. The 3D scene will not render.\",\n fixHint:\n 'Add <script src=\"https://cdn.jsdelivr.net/npm/three@0.160/build/three.min.js\"></script> before your Three.js code.',\n },\n ];\n },\n];\n","import postcss from \"postcss\";\nimport type { LintContext, HyperframeLintFinding, OpenTag } from \"../context\";\nimport { readAttr, truncateSnippet } from \"../utils\";\n\nconst TEXTURE_BASE_CLASS = \"hf-texture-text\";\nconst TEXTURE_CLASS_PREFIX = \"hf-texture-\";\n\ntype DropShadowRule = {\n selector: string;\n directlyTargetsTexture: boolean;\n};\n\nfunction classNames(tag: OpenTag): string[] {\n return (readAttr(tag.raw, \"class\") ?? \"\").split(/\\s+/).filter(Boolean);\n}\n\nfunction isTextureMaterialClass(className: string): boolean {\n return className.startsWith(TEXTURE_CLASS_PREFIX) && className !== TEXTURE_BASE_CLASS;\n}\n\nfunction hasInlineMaskImage(tag: OpenTag): boolean {\n const style = readAttr(tag.raw, \"style\") ?? \"\";\n return /\\b(?:-webkit-)?mask-image\\s*:/i.test(style);\n}\n\nfunction hasInlineDropShadow(tag: OpenTag): boolean {\n const style = readAttr(tag.raw, \"style\") ?? \"\";\n return /\\bfilter\\s*:\\s*[^;]*\\bdrop-shadow\\s*\\(/i.test(style);\n}\n\nfunction classNamesInSelector(selector: string): string[] {\n const classes = new Set<string>();\n const pattern = /\\.([A-Za-z_][\\w-]*)/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(selector)) !== null) {\n const className = match[1];\n if (!className) continue;\n classes.add(className);\n }\n return [...classes];\n}\n\nfunction textureClassesInSelector(selector: string): string[] {\n return classNamesInSelector(selector).filter(isTextureMaterialClass);\n}\n\nfunction simpleSelectorMatchesTag(selector: string, tag: OpenTag, tagClasses: string[]): boolean {\n const trimmed = selector.trim();\n const simpleSelectorPattern = /^(?:[A-Za-z][\\w-]*)?(?:\\.[A-Za-z_][\\w-]*)+$/;\n if (!simpleSelectorPattern.test(trimmed)) return false;\n\n const typeMatch = /^([A-Za-z][\\w-]*)/.exec(trimmed);\n if (typeMatch && typeMatch[1]!.toLowerCase() !== tag.name) return false;\n\n const selectorClasses = classNamesInSelector(trimmed);\n return (\n selectorClasses.length > 0 &&\n selectorClasses.every((className) => tagClasses.includes(className))\n );\n}\n\nfunction collectTextureCss(styles: LintContext[\"styles\"]): {\n definedTextureClasses: Set<string>;\n dropShadowRules: DropShadowRule[];\n} {\n const definedTextureClasses = new Set<string>();\n const dropShadowRules: DropShadowRule[] = [];\n const roots: postcss.Root[] = [];\n\n for (const style of styles) {\n let root: postcss.Root;\n try {\n root = postcss.parse(style.content);\n } catch {\n continue;\n }\n roots.push(root);\n\n // fallow-ignore-next-line complexity\n root.walkRules((rule) => {\n const selectors = rule.selectors ?? [];\n let hasMaskImage = false;\n\n for (const node of rule.nodes ?? []) {\n if (node.type !== \"decl\") continue;\n const prop = node.prop.toLowerCase();\n if (prop === \"mask-image\" || prop === \"-webkit-mask-image\") hasMaskImage = true;\n }\n\n if (hasMaskImage) {\n for (const selector of selectors) {\n for (const className of textureClassesInSelector(selector)) {\n definedTextureClasses.add(className);\n }\n }\n }\n });\n }\n\n for (const root of roots) {\n // fallow-ignore-next-line complexity\n root.walkRules((rule) => {\n const selectors = rule.selectors ?? [];\n let hasDropShadow = false;\n\n for (const node of rule.nodes ?? []) {\n if (node.type !== \"decl\") continue;\n if (node.prop.toLowerCase() === \"filter\" && /\\bdrop-shadow\\s*\\(/i.test(node.value)) {\n hasDropShadow = true;\n }\n }\n\n if (hasDropShadow) {\n for (const selector of selectors) {\n const targetsBaseClass = /\\.hf-texture-text\\b/.test(selector);\n const targetsDefinedTextureClass = textureClassesInSelector(selector).some((className) =>\n definedTextureClasses.has(className),\n );\n dropShadowRules.push({\n selector,\n directlyTargetsTexture: targetsBaseClass || targetsDefinedTextureClass,\n });\n }\n }\n });\n }\n\n return { definedTextureClasses, dropShadowRules };\n}\n\n// fallow-ignore-next-line complexity\nexport const textureRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n ({ tags, styles }) => {\n const findings: HyperframeLintFinding[] = [];\n const { definedTextureClasses, dropShadowRules } = collectTextureCss(styles);\n\n for (const { selector, directlyTargetsTexture } of dropShadowRules) {\n if (!directlyTargetsTexture) continue;\n findings.push({\n code: \"texture_drop_shadow_on_text\",\n severity: \"warning\",\n message: \"Drop shadow is applied directly to textured text.\",\n selector,\n fixHint:\n \"Wrap the textured text and apply `filter: drop-shadow(...)` to the wrapper, not the `hf-texture-text` element.\",\n });\n }\n\n for (const tag of tags) {\n if (tag.name === \"style\" || tag.name === \"script\") continue;\n\n const classes = classNames(tag);\n if (classes.length === 0) continue;\n\n const hasBaseClass = classes.includes(TEXTURE_BASE_CLASS);\n const textureClasses = classes.filter(isTextureMaterialClass);\n\n if (textureClasses.length > 0 && !hasBaseClass) {\n findings.push({\n code: \"texture_class_missing_base\",\n severity: \"warning\",\n message: `Texture material class \\`${textureClasses[0]}\\` is used without \\`${TEXTURE_BASE_CLASS}\\`.`,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint: `Add \\`${TEXTURE_BASE_CLASS}\\` alongside the material class, for example \\`class=\"${TEXTURE_BASE_CLASS} ${textureClasses[0]}\"\\`.`,\n snippet: truncateSnippet(tag.raw),\n });\n }\n\n if (hasBaseClass && textureClasses.length === 0 && !hasInlineMaskImage(tag)) {\n findings.push({\n code: \"texture_text_missing_mask\",\n severity: \"warning\",\n message: `\\`${TEXTURE_BASE_CLASS}\\` is used without a texture material class or custom mask image.`,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n \"Add a material class such as `hf-texture-lava`, or set `mask-image` and `-webkit-mask-image` on the element.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n\n for (const textureClass of textureClasses) {\n if (definedTextureClasses.has(textureClass)) continue;\n findings.push({\n code: \"texture_class_unknown\",\n severity: \"error\",\n message: `Texture material class \\`${textureClass}\\` is not defined by local CSS.`,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n \"Paste the Texture Mask Text component `<style>...</style>` block into the composition, or fix the texture class typo.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n\n if (hasBaseClass) {\n for (const rule of dropShadowRules) {\n if (rule.directlyTargetsTexture) continue;\n if (!simpleSelectorMatchesTag(rule.selector, tag, classes)) continue;\n findings.push({\n code: \"texture_drop_shadow_on_text\",\n severity: \"warning\",\n message: \"Drop shadow is applied directly to textured text.\",\n selector: rule.selector,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n \"Wrap the textured text and apply `filter: drop-shadow(...)` to the wrapper, not the `hf-texture-text` element.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n\n if (hasBaseClass && hasInlineDropShadow(tag)) {\n findings.push({\n code: \"texture_drop_shadow_on_text\",\n severity: \"warning\",\n message: \"Drop shadow is applied directly to textured text.\",\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n \"Wrap the textured text and apply `filter: drop-shadow(...)` to the wrapper, not the `hf-texture-text` element.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n\n return findings;\n },\n];\n","import { FONT_ALIAS_KEYS, resolveAliasDisplayName } from \"@hyperframes/parsers/composition\";\nimport type { LintContext, HyperframeLintFinding } from \"../context\";\nimport { isRegistrySourceFile, isRegistryInstalledFile } from \"./composition\";\n\nconst GENERIC_FAMILIES = new Set([\n \"serif\",\n \"sans-serif\",\n \"monospace\",\n \"cursive\",\n \"fantasy\",\n \"system-ui\",\n \"ui-serif\",\n \"ui-sans-serif\",\n \"ui-monospace\",\n \"ui-rounded\",\n \"math\",\n \"emoji\",\n \"fangsong\",\n // Vendor-prefixed system-font keywords. Like `system-ui`, the engine resolves\n // these to the OS UI font — they are never installable files and must not be\n // flagged as a missing @font-face, even when a generic fallback follows them\n // (e.g. `-apple-system, system-ui, sans-serif`).\n \"-apple-system\",\n \"blinkmacsystemfont\",\n \"inherit\",\n \"initial\",\n \"unset\",\n \"revert\",\n]);\n\n// A CSS comment can contain a `}` (e.g. `@font-face { /* 400 } regular */\n// font-family: 'X'; ... }`), which truncates the naive `@font-face\\s*\\{[^}]*\\}`\n// block match at the comment's brace — so the rule never sees the real\n// `font-family` and reports a false-positive font_family_without_font_face.\n// Large/\"framework\" stylesheets hit this far more often than minimal ones,\n// which is why a simple <style> passes while a complex one fails. Strip\n// comments before scanning so a brace inside one cannot split a block. See #1534.\nfunction stripCssComments(css: string): string {\n return css.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \");\n}\n\nfunction extractFontFaceFamilies(styles: Array<{ content: string }>): Set<string> {\n const families = new Set<string>();\n const fontFaceRe = /@font-face\\s*\\{[^}]*\\}/gi;\n const familyRe = /font-family\\s*:\\s*(['\"]?)([^;'\"]+)\\1/i;\n for (const style of styles) {\n const content = stripCssComments(style.content);\n let match: RegExpExecArray | null;\n while ((match = fontFaceRe.exec(content)) !== null) {\n const familyMatch = match[0].match(familyRe);\n if (familyMatch?.[2]) {\n families.add(familyMatch[2].trim().toLowerCase());\n }\n }\n }\n return families;\n}\n\n// Normalize one comma-separated font-family entry to a lowercase family name,\n// or null if it carries no resolvable name. `var(--heading)` (or any function\n// token) is an indirection the linter cannot statically resolve, so the literal\n// `var(...)` is not a font name and flagging it is a false positive. Comma-split\n// fallbacks like `var(--x, 'Inter')` also leave a dangling `)` on the fallback\n// part, so skip anything bearing parentheses.\nfunction normalizeUsedFontName(part: string): string | null {\n const name = part\n .trim()\n .replace(/^['\"]|['\"]$/g, \"\")\n .trim()\n .toLowerCase();\n if (!name || name.includes(\"(\") || name.includes(\")\")) return null;\n return name;\n}\n\nfunction extractUsedFontFamilies(styles: Array<{ content: string }>): string[] {\n const used: string[] = [];\n const seen = new Set<string>();\n const propRe = /font-family\\s*:\\s*([^;}{]+)/gi;\n for (const style of styles) {\n const withoutFontFace = stripCssComments(style.content).replace(/@font-face\\s*\\{[^}]*\\}/gi, \"\");\n let match: RegExpExecArray | null;\n while ((match = propRe.exec(withoutFontFace)) !== null) {\n for (const part of match[1]!.split(\",\")) {\n const name = normalizeUsedFontName(part);\n if (name && !GENERIC_FAMILIES.has(name) && !seen.has(name)) {\n seen.add(name);\n used.push(name);\n }\n }\n }\n }\n return used;\n}\n\nfunction collectAliasedFonts(used: string[], declared: Set<string>): string[] {\n const aliased: string[] = [];\n for (const name of used) {\n if (declared.has(name)) continue;\n const displayName = resolveAliasDisplayName(name);\n if (!displayName) continue;\n if (displayName.toLowerCase() === name) continue;\n aliased.push(`'${name}' → ${displayName}`);\n }\n return aliased;\n}\n\nfunction normalizeFontFamily(name: string): string | null {\n const decoded = name.replace(/\\+/g, \" \").trim();\n if (!decoded) return null;\n try {\n return decodeURIComponent(decoded).trim().toLowerCase() || null;\n } catch {\n return decoded.toLowerCase();\n }\n}\n\nfunction extractGoogleFontFamiliesFromUrl(rawUrl: string): string[] {\n const url = rawUrl.replace(/&/gi, \"&\");\n let parsed: URL;\n try {\n parsed = new URL(url, \"https://fonts.googleapis.com\");\n } catch {\n return [];\n }\n\n if (parsed.hostname.toLowerCase() !== \"fonts.googleapis.com\") return [];\n const families: string[] = [];\n for (const value of parsed.searchParams.getAll(\"family\")) {\n for (const familySpec of value.split(\"|\")) {\n const family = normalizeFontFamily(familySpec.split(\":\")[0] || \"\");\n if (family) families.push(family);\n }\n }\n return families;\n}\n\nfunction collectGoogleFontFamilies(\n source: string,\n styles: Array<{ content: string }>,\n): Set<string> {\n const families = new Set<string>();\n const addUrl = (url: string) => {\n for (const family of extractGoogleFontFamiliesFromUrl(url)) families.add(family);\n };\n\n const linkHrefRe =\n /<link\\b[^>]*\\bhref\\s*=\\s*(?:([\"'])([^\"']*fonts\\.googleapis\\.com[^\"']*)\\1|([^\\s>]*fonts\\.googleapis\\.com[^\\s>]*))[^>]*>/gi;\n for (const match of source.matchAll(linkHrefRe)) {\n const href = match[2] || match[3];\n if (href) addUrl(href);\n }\n\n const importUrlRe =\n /@import\\s+(?:url\\(\\s*)?([\"']?)([^\"')\\s]*fonts\\.googleapis\\.com[^\"')\\s]*)\\1\\s*\\)?/gi;\n for (const style of styles) {\n for (const match of style.content.matchAll(importUrlRe)) {\n if (match[2]) addUrl(match[2]);\n }\n }\n\n return families;\n}\n\nexport const fontRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // google_fonts_import\n ({ styles, source, rawSource, options }) => {\n if (isRegistrySourceFile(options.filePath) || isRegistryInstalledFile(rawSource)) return [];\n const findings: HyperframeLintFinding[] = [];\n const googleFontsInLink = /<link\\b[^>]*fonts\\.googleapis\\.com[^>]*>/i.test(source);\n const googleFontsInImport = styles.some((s) =>\n /@import\\s+url\\s*\\(\\s*['\"]?[^)]*fonts\\.googleapis\\.com/i.test(s.content),\n );\n\n if (googleFontsInLink || googleFontsInImport) {\n findings.push({\n code: \"google_fonts_import\",\n severity: \"warning\",\n message:\n \"Composition loads fonts from fonts.googleapis.com. The producer resolves Google Fonts \" +\n \"during compile/render, but raw external font requests add latency and can fail before \" +\n \"canonicalization. Prefer mapped family names or local @font-face declarations when possible.\",\n fixHint:\n \"For bundled fonts, remove the Google Fonts <link> or @import and keep the font-family \" +\n \"declaration. For custom fonts, use @font-face { font-family: '...'; src: url('...woff2'); }.\",\n });\n }\n return findings;\n },\n\n // system_font_will_alias — inform when a font will be silently substituted\n ({ styles, options }) => {\n const declared = extractFontFaceFamilies(styles);\n const used = extractUsedFontFamilies(styles);\n const aliased = collectAliasedFonts(used, declared);\n if (aliased.length === 0) return [];\n // In distributed / Lambda renders system-font capture is disabled, so\n // the alias substitution does NOT happen — elevate to a warning.\n const severity = options.distributed ? (\"warning\" as const) : (\"info\" as const);\n return [\n {\n code: \"system_font_will_alias\",\n severity,\n message:\n `Font ${aliased.length === 1 ? \"family\" : \"families\"} will be substituted at render time: ${aliased.join(\", \")}. ` +\n (options.distributed\n ? \"In distributed/Lambda rendering system-font capture is disabled — these fonts will fall back to OS defaults. Embed explicit @font-face declarations instead.\"\n : \"The renderer maps these to bundled fonts for cross-platform consistency. \" +\n \"Use the target font name directly for consistent preview and render results.\"),\n },\n ];\n },\n\n // font_family_without_font_face\n ({ styles, source, rawSource, options }) => {\n if (isRegistrySourceFile(options.filePath) || isRegistryInstalledFile(rawSource)) return [];\n const findings: HyperframeLintFinding[] = [];\n const declared = extractFontFaceFamilies(styles);\n const used = extractUsedFontFamilies(styles);\n const googleFonts = collectGoogleFontFamilies(source, styles);\n\n const undeclared = used.filter(\n (name) => !declared.has(name) && !FONT_ALIAS_KEYS.has(name) && !googleFonts.has(name),\n );\n if (undeclared.length === 0) return findings;\n\n findings.push({\n code: \"font_family_without_font_face\",\n severity: \"error\",\n message:\n `Font ${undeclared.length === 1 ? \"family\" : \"families\"} used without @font-face declaration: ${undeclared.join(\", \")}. ` +\n \"These are not in the auto-resolved font list, so the renderer cannot supply them automatically. \" +\n \"Text will fall back to a generic font, producing incorrect typography in the video.\",\n fixHint:\n \"Add @font-face { font-family: '...'; src: url('capture/assets/fonts/...woff2'); } \" +\n \"for each font family, pointing to the captured .woff2 files. For an OS-bundled \" +\n \"system font (e.g. Hiragino Sans, Microsoft YaHei) that has no downloadable file, \" +\n \"use src: local('Exact Font Name') instead — the declaration alone satisfies this \" +\n \"check without needing a font file.\",\n });\n return findings;\n },\n];\n","import type { LintContext, HyperframeLintFinding } from \"../context\";\nimport type { LintRule } from \"../types\";\nimport { readAttr } from \"../utils\";\nimport {\n parseSlideshowManifest,\n resolveSlideshow,\n isSceneLikeCompositionId,\n} from \"@hyperframes/parsers/slideshow\";\n\ntype Scene = { id: string; start: number; duration: number };\n\nfunction parseTiming(raw: string): { start: number; duration: number } | null {\n const startStr = readAttr(raw, \"data-start\");\n if (startStr === null) return null;\n const start = Number(startStr);\n if (!Number.isFinite(start)) return null;\n\n const durationStr = readAttr(raw, \"data-duration\");\n if (durationStr !== null) {\n const duration = Number(durationStr);\n if (Number.isFinite(duration)) return { start, duration };\n }\n const endStr = readAttr(raw, \"data-end\") ?? readAttr(raw, \"data-hf-authored-end\");\n if (endStr !== null) {\n const end = Number(endStr);\n if (Number.isFinite(end) && end > start) return { start, duration: end - start };\n }\n return null;\n}\n\nfunction collectCompositionIdScenes(ctx: LintContext, seen: Set<string>, out: Scene[]): void {\n for (const tag of ctx.tags) {\n const compositionId = readAttr(tag.raw, \"data-composition-id\");\n if (!compositionId || !isSceneLikeCompositionId(compositionId) || seen.has(compositionId))\n continue;\n const timing = parseTiming(tag.raw);\n if (!timing || timing.duration <= 0) continue;\n seen.add(compositionId);\n out.push({ id: compositionId, ...timing });\n }\n}\n\nfunction extractScenesFromClips(ctx: LintContext): Scene[] {\n const seen = new Set<string>();\n const scenes: Scene[] = [];\n collectCompositionIdScenes(ctx, seen, scenes);\n return scenes;\n}\n\nexport const slideshowRules: LintRule<LintContext>[] = [\n (ctx) => {\n const findings: HyperframeLintFinding[] = [];\n\n let manifest;\n try {\n manifest = parseSlideshowManifest(ctx.source);\n } catch (e) {\n findings.push({\n code: \"slideshow_invalid\",\n severity: \"error\",\n message: `Slideshow island contains invalid JSON or structure: ${e instanceof Error ? e.message : String(e)}`,\n fixHint:\n 'Ensure the <script type=\"application/hyperframes-slideshow+json\"> block contains valid JSON matching the SlideshowManifest schema.',\n });\n return findings;\n }\n\n if (!manifest) return findings;\n\n const scenes = extractScenesFromClips(ctx);\n const { errors } = resolveSlideshow(manifest, scenes);\n\n for (const error of errors) {\n findings.push({\n code: \"slideshow_unresolved_ref\",\n severity: \"error\",\n message: `Slideshow manifest error: ${error}`,\n fixHint:\n \"Ensure every sceneId in the slideshow island matches the data-composition-id of a scene element in the composition, or provide explicit startTime/endTime.\",\n });\n }\n\n return findings;\n },\n];\n","import type { HyperframeLintFinding, HyperframeLintResult, HyperframeLinterOptions } from \"./types\";\nimport { buildLintContext } from \"./context\";\nimport { readAttr, truncateSnippet } from \"./utils\";\nimport { coreRules } from \"./rules/core\";\nimport { mediaRules } from \"./rules/media\";\nimport { gsapRules } from \"./rules/gsap\";\nimport { captionRules } from \"./rules/captions\";\nimport { compositionRules } from \"./rules/composition\";\nimport { adapterRules } from \"./rules/adapters\";\nimport { textureRules } from \"./rules/textures\";\nimport { fontRules } from \"./rules/fonts\";\nimport { slideshowRules } from \"./rules/slideshow\";\n\nconst ALL_RULES = [\n ...coreRules,\n ...mediaRules,\n ...gsapRules,\n ...captionRules,\n ...compositionRules,\n ...adapterRules,\n ...textureRules,\n ...fontRules,\n ...slideshowRules,\n];\n\nexport async function lintHyperframeHtml(\n html: string,\n options: HyperframeLinterOptions = {},\n): Promise<HyperframeLintResult> {\n const ctx = buildLintContext(html, options);\n const findings: HyperframeLintFinding[] = [];\n const seen = new Set<string>();\n\n for (const rule of ALL_RULES) {\n for (const finding of await Promise.resolve(rule(ctx))) {\n const dedupeKey = [\n finding.code,\n finding.severity,\n finding.selector || \"\",\n finding.elementId || \"\",\n finding.message,\n ].join(\"|\");\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n findings.push(options.filePath ? { ...finding, file: options.filePath } : finding);\n }\n }\n\n const errorCount = findings.filter((f) => f.severity === \"error\").length;\n const warningCount = findings.filter((f) => f.severity === \"warning\").length;\n const infoCount = findings.filter((f) => f.severity === \"info\").length;\n\n return {\n ok: errorCount === 0,\n errorCount,\n warningCount,\n infoCount,\n findings,\n };\n}\n\n// ── Async media URL accessibility checker ─────────────────────────────────\n\nfunction extractMediaUrls(html: string): Array<{\n url: string;\n tagName: string;\n elementId?: string;\n snippet: string;\n}> {\n const results: Array<{\n url: string;\n tagName: string;\n elementId?: string;\n snippet: string;\n }> = [];\n const tagRe = /<(video|audio|img|source)\\b[^>]*>/gi;\n let match: RegExpExecArray | null;\n while ((match = tagRe.exec(html)) !== null) {\n const tagName = (match[1] ?? \"\").toLowerCase();\n const raw = match[0];\n const src = readAttr(raw, \"src\");\n if (!src) continue;\n if (/^https?:\\/\\//i.test(src)) {\n results.push({\n url: src,\n tagName,\n elementId: readAttr(raw, \"id\") || undefined,\n snippet: truncateSnippet(raw) ?? \"\",\n });\n }\n }\n return results;\n}\n\n/**\n * Async lint pass: HEAD-checks every remote media URL in the HTML.\n * Returns findings for URLs that are unreachable (non-2xx status or network error).\n *\n * Call this after `lintHyperframeHtml()` and merge the findings.\n *\n * @param timeoutMs - per-request timeout (default 8000ms)\n */\nexport async function lintMediaUrls(\n html: string,\n options: { timeoutMs?: number } = {},\n): Promise<HyperframeLintFinding[]> {\n const urls = extractMediaUrls(html);\n if (urls.length === 0) return [];\n\n const timeout = options.timeoutMs ?? 8000;\n const findings: HyperframeLintFinding[] = [];\n\n const seen = new Set<string>();\n const unique = urls.filter((u) => {\n if (seen.has(u.url)) return false;\n seen.add(u.url);\n return true;\n });\n\n const checks = unique.map(async ({ url, tagName, elementId, snippet }) => {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n const resp = await fetch(url, {\n method: \"HEAD\",\n signal: controller.signal,\n redirect: \"follow\",\n });\n clearTimeout(timer);\n if (!resp.ok) {\n findings.push({\n code: \"inaccessible_media_url\",\n severity: \"error\",\n message: `<${tagName}${elementId ? ` id=\"${elementId}\"` : \"\"}> references a URL that returned HTTP ${resp.status}: ${url.slice(0, 100)}`,\n elementId,\n fixHint: \"This URL is not accessible. Replace with a valid, reachable media URL.\",\n snippet,\n });\n }\n } catch (err) {\n const reason = err instanceof Error ? err.name : \"unknown\";\n findings.push({\n code: \"inaccessible_media_url\",\n severity: \"error\",\n message: `<${tagName}${elementId ? ` id=\"${elementId}\"` : \"\"}> references an unreachable URL (${reason}): ${url.slice(0, 100)}`,\n elementId,\n fixHint: \"This URL is not accessible. Replace with a valid, reachable media URL.\",\n snippet,\n });\n }\n });\n\n await Promise.all(checks);\n return findings;\n}\n","/**\n * Pure render-gate decision — no Node.js dependencies, so it is safe to import\n * from the browser entry alongside the rule engine.\n */\nexport function shouldBlockRender(\n strictErrors: boolean,\n strictAll: boolean,\n totalErrors: number,\n totalWarnings: number,\n): boolean {\n return (strictErrors && totalErrors > 0) || (strictAll && (totalErrors > 0 || totalWarnings > 0));\n}\n"],"mappings":"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","names":["escapeRegExp","selector","postcss","postcss"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/context.ts","../src/rules/core.ts","../src/rules/media.ts","../src/rules/gsap.ts","../src/rules/captions.ts","../src/rules/composition.ts","../src/rules/adapters.ts","../src/rules/textures.ts","../src/rules/fonts.ts","../src/rules/slideshow.ts","../src/hyperframeLinter.ts","../src/shouldBlockRender.ts"],"sourcesContent":["// Shared types, regex constants, and utility functions used across lint rule modules.\n// Nothing in this file should emit findings — it only parses and extracts.\n\nexport type OpenTag = {\n raw: string;\n name: string;\n attrs: string;\n index: number;\n};\n\nexport type ExtractedBlock = {\n attrs: string;\n content: string;\n raw: string;\n index: number;\n};\n\nconst TAG_PATTERN = /<([a-z][\\w:-]*)(\\s[^<>]*?)?>/gi;\nexport const STYLE_BLOCK_PATTERN = /<style\\b([^>]*)>([\\s\\S]*?)<\\/style>/gi;\nexport const SCRIPT_BLOCK_PATTERN = /<script\\b([^>]*)>([\\s\\S]*?)<\\/script>/gi;\nconst COMPOSITION_ID_IN_CSS_PATTERN = /\\[data-composition-id=[\"']([^\"']+)[\"']\\]/g;\nexport const TIMELINE_REGISTRY_INIT_PATTERN =\n /window\\.__timelines\\s*=\\s*window\\.__timelines\\s*\\|\\|\\s*\\{\\}|window\\.__timelines\\s*=\\s*\\{\\}|window\\.__timelines\\s*\\?\\?=\\s*\\{\\}/i;\n// Object-literal registration that assigns at least one `key: value` entry inline,\n// e.g. `window.__timelines = { main: tl }` or `window.__timelines = { \"comp-1\": tl }`.\n// Distinct from the empty-init form (`= {}`) — requires a key followed by `:`.\nexport const TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN =\n /window\\.__timelines\\s*=\\s*\\{\\s*(?:[\"'][^\"']+[\"']|[A-Za-z_$][\\w$]*)\\s*:/i;\nexport const TIMELINE_REGISTRY_ASSIGN_PATTERN =\n /window\\.__timelines(?:\\[[^\\]]+\\]|\\.[A-Za-z_$][\\w$]*)\\s*=/i;\n// The bracket branch accepts either a quoted string key (`[\"root\"]`) or a\n// computed key (`[spec.id]`, `[id]`) — a bare-identifier-only bracket branch\n// missed `window.__timelines[spec.id] = tl`, a pattern the shipped\n// code-particle-assemble/code-3d-extrude registry blocks actually use,\n// making gsap_timeline_not_registered false-fire on correctly registered\n// timelines. The computed-key alternative is deliberately non-capturing:\n// its text isn't a literal composition id, so callers reading group 1/2\n// (readRegisteredTimelineCompositionId) must keep falling back to null for it.\nexport const WINDOW_TIMELINE_ASSIGN_PATTERN =\n /window\\.__timelines(?:\\[\\s*(?:[\"']([^\"']+)[\"']|[A-Za-z_$][\\w$.]*)\\s*\\]|\\.\\s*([A-Za-z_$][\\w$]*))\\s*=\\s*([A-Za-z_$][\\w$]*)/i;\nexport const INVALID_SCRIPT_CLOSE_PATTERN = /<script[^>]*>[\\s\\S]*?<\\s*\\/\\s*script(?!>)/i;\n\nconst TIMELINE_REGISTRY_KEY_PATTERN =\n /window\\.__timelines(?:\\[\\s*[\"']([^\"']+)[\"']\\s*\\]|\\.\\s*([A-Za-z_$][\\w$]*))\\s*=/g;\n\n// The `window.__timelines = { ... }` object-literal body (group 1), captured so its\n// `key: value` entries can be scanned for registered keys.\nconst TIMELINE_REGISTRY_OBJECT_BODY_PATTERN = /window\\.__timelines\\s*=\\s*\\{([\\s\\S]*?)\\}/i;\n// A single object-literal entry whose value is an identifier (real timeline registration),\n// e.g. `main: tl` or `\"comp-1\": tl`. Captures the key in group 1 (quoted) or 2 (bare).\nconst TIMELINE_REGISTRY_OBJECT_ENTRY_PATTERN =\n /(?:[\"']([^\"']+)[\"']|([A-Za-z_$][\\w$]*))\\s*:\\s*[A-Za-z_$][\\w$]*/g;\n\nexport function extractOpenTags(source: string): OpenTag[] {\n const tags: OpenTag[] = [];\n let match: RegExpExecArray | null;\n const pattern = new RegExp(TAG_PATTERN.source, TAG_PATTERN.flags);\n while ((match = pattern.exec(source)) !== null) {\n const raw = match[0];\n if (raw.startsWith(\"</\") || raw.startsWith(\"<!\")) continue;\n tags.push({\n raw,\n name: (match[1] || \"\").toLowerCase(),\n attrs: match[2] || \"\",\n index: match.index,\n });\n }\n return tags;\n}\n\nexport function extractBlocks(source: string, pattern: RegExp): ExtractedBlock[] {\n const blocks: ExtractedBlock[] = [];\n let match: RegExpExecArray | null;\n const p = new RegExp(pattern.source, pattern.flags);\n while ((match = p.exec(source)) !== null) {\n blocks.push({\n attrs: match[1] || \"\",\n content: match[2] || \"\",\n raw: match[0],\n index: match.index,\n });\n }\n return blocks;\n}\n\n/**\n * Find the `<html>` open tag in the source. Distinct from `findRootTag`,\n * which returns the first element inside `<body>` — the latter is \"the\n * composition's visible root\", whereas `<html>` is where document-level\n * metadata like `data-composition-variables` lives.\n */\nexport function findHtmlTag(source: string): OpenTag | null {\n const match = /<html\\b([^<>]*)>/i.exec(source);\n if (!match) return null;\n return {\n raw: match[0],\n name: \"html\",\n attrs: match[1] ?? \"\",\n index: match.index,\n };\n}\n\n// fallow-ignore-next-line complexity\nexport function findRootTag(source: string): OpenTag | null {\n const bodyOpenMatch = /<body\\b([^>]*)>/i.exec(source);\n const bodyCloseMatch = /<\\/body>/i.exec(source);\n if (\n bodyOpenMatch &&\n (readAttr(bodyOpenMatch[0], \"data-composition-id\") ||\n readAttr(bodyOpenMatch[0], \"data-width\") ||\n readAttr(bodyOpenMatch[0], \"data-height\"))\n ) {\n return {\n raw: bodyOpenMatch[0],\n name: \"body\",\n attrs: bodyOpenMatch[1] ?? \"\",\n index: bodyOpenMatch.index,\n };\n }\n const bodyStart = bodyOpenMatch ? bodyOpenMatch.index + bodyOpenMatch[0].length : 0;\n const bodyEnd =\n bodyOpenMatch && bodyCloseMatch && bodyCloseMatch.index > bodyStart\n ? bodyCloseMatch.index\n : source.length;\n const bodyContent = bodyOpenMatch ? source.slice(bodyStart, bodyEnd) : source;\n const bodyTags = extractOpenTags(bodyContent);\n // Set when a leading <svg> defs block is skipped (see below) — extractOpenTags\n // is a flat, nesting-unaware scan, so without this the very next tag it\n // returns is the svg's own nested child (<defs>, <filter>, ...), not the\n // sibling that follows the closed </svg>.\n let skipBefore = -1;\n for (const tag of bodyTags) {\n if (tag.index < skipBefore) continue;\n if ([\"script\", \"style\", \"meta\", \"link\", \"title\"].includes(tag.name)) continue;\n // A leading <svg> block (icon/gradient/filter <defs>, referenced by url(#id)\n // from elsewhere in the document) is shared visual plumbing, not the\n // composition root — two independent reports of this being mistaken for\n // the root, manufacturing root_missing_composition_id/root_missing_dimensions\n // on an otherwise-correct composition. Only skip it when it carries none of\n // the composition markers itself, so an intentionally SVG-rooted composition\n // (data-composition-id/data-width/data-height directly on the <svg>) is\n // still eligible as the root.\n if (\n tag.name === \"svg\" &&\n !readAttr(tag.raw, \"data-composition-id\") &&\n !readAttr(tag.raw, \"data-width\") &&\n !readAttr(tag.raw, \"data-height\")\n ) {\n const closeMatch = /<\\/svg\\s*>/i.exec(bodyContent.slice(tag.index));\n // No closing tag found (malformed HTML) — skip everything rather than\n // risk returning one of the svg's own children as the root.\n skipBefore = closeMatch ? tag.index + closeMatch.index + closeMatch[0].length : Infinity;\n continue;\n }\n return { ...tag, index: tag.index + bodyStart };\n }\n return null;\n}\n\nexport function readAttr(tagSource: string, attr: string): string | null {\n if (!tagSource) return null;\n const escaped = attr.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n // `(?<![\\w-])` not `\\b`: a plain `\\b` boundary treats the hyphen in a longer\n // attribute as a word break, so reading \"id\" would wrongly match the trailing\n // `id=\"…\"` inside `data-hf-id=\"…\"` (and \"width\" inside `data-width`, etc.).\n // The lookbehind requires the match to start a fresh attribute name.\n const match = tagSource.match(new RegExp(`(?<![\\\\w-])${escaped}\\\\s*=\\\\s*[\"']([^\"']+)[\"']`, \"i\"));\n return match?.[1] || null;\n}\n\n/**\n * Read an attribute that may legitimately contain the opposite quote\n * character. `readAttr` truncates `data-variable-values='{\"title\":\"Hello\"}'`\n * at the first internal `\"` because its `[^\"']+` class excludes both quote\n * types. This variant alternates: a double-quoted value never contains an\n * unescaped `\"`, and a single-quoted value never contains an unescaped `'`,\n * so each branch can use a quote-specific class.\n *\n * Use for attributes whose values are JSON or otherwise carry the opposite\n * quote character. Existing single-token attributes (`id`, `class`, etc.)\n * stick with `readAttr` for consistency with the rest of the lint code.\n */\nexport function readJsonAttr(tagSource: string, attr: string): string | null {\n if (!tagSource) return null;\n const escaped = attr.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n // See readAttr: `(?<![\\w-])` prevents a short name from matching the tail of a\n // longer hyphenated attribute (e.g. \"id\" inside `data-hf-id`).\n const match = tagSource.match(\n new RegExp(`(?<![\\\\w-])${escaped}\\\\s*=\\\\s*(?:\"([^\"]*)\"|'([^']*)')`, \"i\"),\n );\n if (!match) return null;\n return match[1] ?? match[2] ?? null;\n}\n\nexport function collectCompositionIds(tags: OpenTag[]): Set<string> {\n const ids = new Set<string>();\n for (const tag of tags) {\n const compId = readAttr(tag.raw, \"data-composition-id\");\n if (compId) ids.add(compId);\n }\n return ids;\n}\n\nexport function extractCompositionIdsFromCss(css: string): string[] {\n const ids = new Set<string>();\n let match: RegExpExecArray | null;\n const pattern = new RegExp(\n COMPOSITION_ID_IN_CSS_PATTERN.source,\n COMPOSITION_ID_IN_CSS_PATTERN.flags,\n );\n while ((match = pattern.exec(css)) !== null) {\n if (match[1]) ids.add(match[1]);\n }\n return [...ids];\n}\n\nexport function extractTimelineRegistryKeys(source: string): string[] {\n const keys = new Set<string>();\n let match: RegExpExecArray | null;\n const pattern = new RegExp(\n TIMELINE_REGISTRY_KEY_PATTERN.source,\n TIMELINE_REGISTRY_KEY_PATTERN.flags,\n );\n while ((match = pattern.exec(source)) !== null) {\n const key = match[1] ?? match[2];\n if (key) keys.add(key);\n }\n const objectBody = TIMELINE_REGISTRY_OBJECT_BODY_PATTERN.exec(source)?.[1];\n if (objectBody) {\n const entryPattern = new RegExp(\n TIMELINE_REGISTRY_OBJECT_ENTRY_PATTERN.source,\n TIMELINE_REGISTRY_OBJECT_ENTRY_PATTERN.flags,\n );\n while ((match = entryPattern.exec(objectBody)) !== null) {\n const key = match[1] ?? match[2];\n if (key) keys.add(key);\n }\n }\n return [...keys];\n}\n\nexport function getInlineScriptSyntaxError(source: string): string | null {\n if (!source.trim()) return null;\n try {\n // eslint-disable-next-line no-new-func\n new Function(source);\n return null;\n } catch (error) {\n if (error instanceof Error) return error.message;\n return String(error);\n }\n}\n\n// fallow-ignore-next-line complexity\nexport function stripJsComments(source: string): string {\n let out = \"\";\n let i = 0;\n let quote: \"'\" | '\"' | \"`\" | null = null;\n let escaped = false;\n\n while (i < source.length) {\n const ch = source[i] ?? \"\";\n const next = source[i + 1] ?? \"\";\n\n if (quote) {\n out += ch;\n if (escaped) {\n escaped = false;\n } else if (ch === \"\\\\\") {\n escaped = true;\n } else if (ch === quote) {\n quote = null;\n }\n i += 1;\n continue;\n }\n\n if (ch === \"'\" || ch === '\"' || ch === \"`\") {\n quote = ch;\n out += ch;\n i += 1;\n continue;\n }\n\n if (ch === \"/\" && next === \"/\") {\n out += \" \";\n i += 2;\n while (i < source.length && source[i] !== \"\\n\" && source[i] !== \"\\r\") {\n out += \" \";\n i += 1;\n }\n continue;\n }\n\n if (ch === \"/\" && next === \"*\") {\n out += \" \";\n i += 2;\n while (i < source.length) {\n const blockCh = source[i] ?? \"\";\n const blockNext = source[i + 1] ?? \"\";\n if (blockCh === \"*\" && blockNext === \"/\") {\n out += \" \";\n i += 2;\n break;\n }\n out += blockCh === \"\\n\" || blockCh === \"\\r\" ? blockCh : \" \";\n i += 1;\n }\n continue;\n }\n\n out += ch;\n i += 1;\n }\n\n return out;\n}\n\n// One linear pass that drops every `<!-- … -->` region. Uses indexOf, not a\n// `/<!--[\\s\\S]*?-->/` regex: that pattern backtracks O(n²) on inputs with many\n// unterminated \"<!--\" (CodeQL js/polynomial-redos). An unterminated \"<!--\" with\n// no closing \"-->\" is kept verbatim, matching the prior regex's no-match behavior.\nfunction stripHtmlCommentsOnce(source: string): string {\n let out = \"\";\n let i = 0;\n for (;;) {\n const start = source.indexOf(\"<!--\", i);\n if (start < 0) return out + source.slice(i);\n const end = source.indexOf(\"-->\", start + 4);\n if (end < 0) return out + source.slice(i);\n out += source.slice(i, start);\n i = end + 3;\n }\n}\n\n// Strip HTML comments to a fixpoint. A single pass is not enough: deleting one\n// comment can splice adjacent markers into a fresh, complete <!-- … --> (e.g.\n// \"<<!-- -->!-- … -->\" → \"<!-- … -->\"), which would otherwise survive and let a\n// commented-out <template>/tag hijack the linter's tag scan.\nexport function stripHtmlComments(source: string): string {\n let out = source;\n for (let prev = \"\"; prev !== out; ) {\n prev = out;\n out = stripHtmlCommentsOnce(out);\n }\n return out;\n}\n\nexport function extractScriptTextsAndSrcs(scripts: ExtractedBlock[]): {\n texts: string[];\n srcs: string[];\n} {\n const texts = scripts.filter((s) => !/\\bsrc\\s*=/.test(s.attrs)).map((s) => s.content);\n const srcs = scripts.map((s) => readAttr(`<script ${s.attrs}>`, \"src\") || \"\").filter(Boolean);\n return { texts, srcs };\n}\n\nexport function isMediaTag(tagName: string): boolean {\n return tagName === \"video\" || tagName === \"audio\" || tagName === \"img\";\n}\n\n// Whether any <style> block in the composition defines caption group/word\n// classes (`.caption-group`, `.caption_word`, etc.) — the signal several\n// caption-specific rules use to skip non-caption compositions entirely.\nexport function hasCaptionStyles(styles: ExtractedBlock[]): boolean {\n return styles.some((s) => /\\.caption[-_]?(?:group|word)/i.test(s.content));\n}\n\nexport function truncateSnippet(value: string, maxLength = 220): string | undefined {\n const normalized = value.replace(/\\s+/g, \" \").trim();\n if (!normalized) return undefined;\n if (normalized.length <= maxLength) return normalized;\n return `${normalized.slice(0, maxLength - 3)}...`;\n}\n","import type { HyperframeLintFinding, HyperframeLinterOptions } from \"./types\";\nimport {\n extractBlocks,\n extractOpenTags,\n findRootTag,\n collectCompositionIds,\n readAttr,\n stripHtmlComments,\n STYLE_BLOCK_PATTERN,\n SCRIPT_BLOCK_PATTERN,\n} from \"./utils\";\nimport type { OpenTag, ExtractedBlock } from \"./utils\";\n\nexport type { OpenTag, ExtractedBlock };\n\nexport type LintContext = {\n source: string;\n rawSource: string;\n tags: OpenTag[];\n styles: ExtractedBlock[];\n scripts: ExtractedBlock[];\n compositionIds: Set<string>;\n rootTag: OpenTag | null;\n rootCompositionId: string | null;\n options: HyperframeLinterOptions;\n};\n\n// Re-export for convenience so rule modules only need one import for the finding type\nexport type { HyperframeLintFinding };\n\nexport function buildLintContext(html: string, options: HyperframeLinterOptions = {}): LintContext {\n const rawSource = html || \"\";\n // Strip HTML comments before scanning so a commented-out <template> or tag can't\n // hijack the boundary match below. Linear + fixpoint (see stripHtmlComments) to\n // stay ReDoS-free and catch markers that re-form when a comment is removed.\n let source = stripHtmlComments(rawSource);\n const sourceWithoutTemplates = source.replace(\n /<template\\b[^>]*>[\\s\\S]*?<\\/template(?:\\s[^>]*)?>/gi,\n \" \",\n );\n const templateMatch = source.match(/<template[^>]*>([\\s\\S]*)<\\/template>/i);\n // Some sub-composition files are HTML shells whose real root lives inside a\n // <template>. Keep nested templates intact when the visible document already\n // has a composition root; only unwrap when no root exists outside templates.\n if (templateMatch?.[1] && !findRootTag(sourceWithoutTemplates)) source = templateMatch[1];\n\n const tags = extractOpenTags(source);\n const styles = [\n ...extractBlocks(source, STYLE_BLOCK_PATTERN),\n ...(options.externalStyles ?? []).map((style) => ({\n attrs: `href=\"${style.href}\"`,\n content: style.content,\n raw: style.content,\n index: -1,\n })),\n ];\n const scripts = extractBlocks(source, SCRIPT_BLOCK_PATTERN);\n const compositionIds = collectCompositionIds(tags);\n const rootTag = findRootTag(source);\n const rootCompositionId = readAttr(rootTag?.raw || \"\", \"data-composition-id\");\n\n return {\n source,\n rawSource,\n tags,\n styles,\n scripts,\n compositionIds,\n rootTag,\n rootCompositionId,\n options,\n };\n}\n","import type { LintContext, HyperframeLintFinding } from \"../context\";\nimport postcss from \"postcss\";\nimport {\n readAttr,\n truncateSnippet,\n stripJsComments,\n extractCompositionIdsFromCss,\n extractTimelineRegistryKeys,\n getInlineScriptSyntaxError,\n TIMELINE_REGISTRY_INIT_PATTERN,\n TIMELINE_REGISTRY_ASSIGN_PATTERN,\n TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN,\n INVALID_SCRIPT_CLOSE_PATTERN,\n} from \"../utils\";\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction selectorTargetsCompositionId(selector: string, compositionId: string): boolean {\n const escaped = escapeRegExp(compositionId);\n return new RegExp(\n String.raw`\\[\\s*data-composition-id\\s*=\\s*(?:\"${escaped}\"|'${escaped}')\\s*\\]`,\n ).test(selector);\n}\n\nfunction isStudioTimelineElement(tag: { raw: string; name: string }): boolean {\n if ([\"script\", \"style\", \"link\", \"meta\", \"template\", \"noscript\"].includes(tag.name)) {\n return false;\n }\n return Boolean(\n readAttr(tag.raw, \"data-start\") ||\n readAttr(tag.raw, \"data-track-index\") ||\n readAttr(tag.raw, \"data-track\") ||\n readAttr(tag.raw, \"data-composition-src\") ||\n readAttr(tag.raw, \"data-composition-file\"),\n );\n}\n\nfunction describeStudioElement(tag: { raw: string; name: string }): string {\n const parts = [`<${tag.name}`];\n const className = readAttr(tag.raw, \"class\");\n const compositionId = readAttr(tag.raw, \"data-composition-id\");\n const dataStart = readAttr(tag.raw, \"data-start\");\n const dataTrack = readAttr(tag.raw, \"data-track-index\") ?? readAttr(tag.raw, \"data-track\");\n\n if (className) {\n const primaryClass = className\n .split(/\\s+/)\n .map((value) => value.trim())\n .find((value) => value && value !== \"clip\");\n if (primaryClass) parts.push(` class=\"${primaryClass}\"`);\n }\n if (compositionId) parts.push(` data-composition-id=\"${compositionId}\"`);\n if (dataStart) parts.push(` data-start=\"${dataStart}\"`);\n if (dataTrack) parts.push(` data-track-index=\"${dataTrack}\"`);\n parts.push(\">\");\n return parts.join(\"\");\n}\n\nconst HEAD_BLOCKS_TO_IGNORE_PATTERN =\n /<(?:style|script|template|title|noscript)\\b[^>]*>[\\s\\S]*?<\\/(?:style|script|template|title|noscript)(?:\\s[^>]*)?>/gi;\nconst HTML_TAG_PATTERN = /<[^>]+>/g;\nconst HEAD_CONTENT_PATTERN = /<head\\b[^>]*>([\\s\\S]*?)(?:<\\/head>|<body\\b|$)/gi;\nconst AFTER_HEAD_BEFORE_BODY_PATTERN = /<\\/head(?:\\s[^>]*)?>([\\s\\S]*?)(?=<body\\b|$)/gi;\nconst STRAY_HEAD_CLOSE_PATTERN = /<\\/(?:style|script)(?:\\s[^>]*)?>/i;\nconst MARKDOWN_CODE_FENCE_PATTERN = /```[^\\r\\n`]*(?:\\r?\\n|$)[\\s\\S]*?```/i;\nconst ORPHAN_CSS_AT_RULE_PATTERN =\n /(?:^|\\s)@(?:container|font-face|keyframes|layer|media|page|property|scope|supports)[^{<]*\\{[\\s\\S]*?:[\\s\\S]*?\\}/i;\nconst ORPHAN_CSS_RULE_PATTERN =\n /(?:^|\\s)(?:\\/\\*[\\s\\S]*?\\*\\/\\s*)?(?:@[a-z-]+[^{}<]*|[.#][\\w-]+[^{}<]*|[a-z][\\w-]*(?:\\s+[.#:[\\w-][^{}<]*)?)\\s*\\{[^{}]*:[^{}]*\\}/i;\nconst VISIBLE_MARKUP_COMMENT_PATTERN = /\\/\\*[\\s\\S]*?\\*\\//g;\nconst VISIBLE_MARKUP_COMMENT_PROTECTED_BLOCK_PATTERN =\n /<(style|script|template|title|noscript|pre|code|textarea|text)\\b[^>]*>[\\s\\S]*?<\\/\\1(?:\\s[^>]*)?>/gi;\n\ninterface SourceRange {\n start: number;\n end: number;\n}\n\nfunction findCodeFenceLeak(headWithoutValidBlocks: string): string | null {\n return MARKDOWN_CODE_FENCE_PATTERN.exec(headWithoutValidBlocks)?.[0] ?? null;\n}\n\nfunction findOrphanCssLeak(headContent: string): string | null {\n const residualText = headContent\n .replace(HEAD_BLOCKS_TO_IGNORE_PATTERN, \" \")\n .replace(HTML_TAG_PATTERN, \" \");\n return (\n ORPHAN_CSS_AT_RULE_PATTERN.exec(residualText)?.[0] ??\n ORPHAN_CSS_RULE_PATTERN.exec(residualText)?.[0] ??\n null\n );\n}\n\nfunction findStrayCloseLeak(headWithoutValidBlocks: string): string | null {\n return STRAY_HEAD_CLOSE_PATTERN.exec(headWithoutValidBlocks)?.[0] ?? null;\n}\n\nfunction findLeakedTextInHeadContent(headContent: string): string | null {\n const withoutValidBlocks = headContent.replace(HEAD_BLOCKS_TO_IGNORE_PATTERN, \" \");\n return (\n findCodeFenceLeak(withoutValidBlocks) ??\n findOrphanCssLeak(headContent) ??\n findStrayCloseLeak(withoutValidBlocks)\n );\n}\n\nfunction findLeakedTextInHead(rawSource: string): string | null {\n const headMatches = [...rawSource.matchAll(HEAD_CONTENT_PATTERN)];\n for (const match of headMatches) {\n const leakedText = findLeakedTextInHeadContent(match[1] ?? \"\");\n if (leakedText) return leakedText;\n }\n return null;\n}\n\nfunction findLeakedTextBetweenHeadAndBody(rawSource: string): string | null {\n const boundaryMatches = [...rawSource.matchAll(AFTER_HEAD_BEFORE_BODY_PATTERN)];\n for (const match of boundaryMatches) {\n const leakedText = findLeakedTextInHeadContent(match[1] ?? \"\");\n if (leakedText) return leakedText;\n }\n return null;\n}\n\nfunction findLeakedTextBeforeCompositionRoot(\n source: string,\n rootTag: LintContext[\"rootTag\"],\n): string | null {\n if (!rootTag || rootTag.name === \"body\") return null;\n const bodyOpenMatch = /<body\\b[^>]*>/i.exec(source);\n const prefixStart = bodyOpenMatch ? bodyOpenMatch.index + bodyOpenMatch[0].length : 0;\n const prefixEnd = rootTag.index;\n if (prefixEnd <= prefixStart) return null;\n return findLeakedTextInHeadContent(source.slice(prefixStart, prefixEnd));\n}\n\nfunction findProtectedVisibleMarkupRanges(source: string): SourceRange[] {\n const ranges: SourceRange[] = [];\n for (const match of source.matchAll(VISIBLE_MARKUP_COMMENT_PROTECTED_BLOCK_PATTERN)) {\n ranges.push({ start: match.index, end: match.index + match[0].length });\n }\n return ranges;\n}\n\nfunction isInsideSourceRange(index: number, ranges: SourceRange[]): boolean {\n return ranges.some((range) => range.start <= index && index < range.end);\n}\n\nfunction isInsideHtmlTag(source: string, index: number): boolean {\n let inTag = false;\n let quote: '\"' | \"'\" | null = null;\n for (let i = 0; i < index; i++) {\n const char = source[i];\n if (!inTag) {\n if (char === \"<\") inTag = true;\n continue;\n }\n if (quote) {\n if (char === quote) quote = null;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n } else if (char === \">\") {\n inTag = false;\n }\n }\n return inTag;\n}\n\nfunction findVisibleMarkupCommentLeak(source: string): string | null {\n const protectedRanges = findProtectedVisibleMarkupRanges(source);\n for (const match of source.matchAll(VISIBLE_MARKUP_COMMENT_PATTERN)) {\n if (isInsideHtmlTag(source, match.index)) continue;\n if (isInsideSourceRange(match.index, protectedRanges)) continue;\n return match[0];\n }\n return null;\n}\n\nexport const coreRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // root_missing_composition_id + root_missing_dimensions\n ({ rootTag }) => {\n const findings: HyperframeLintFinding[] = [];\n if (!rootTag || !readAttr(rootTag.raw, \"data-composition-id\")) {\n findings.push({\n code: \"root_missing_composition_id\",\n severity: \"error\",\n message: \"Root composition is missing `data-composition-id`.\",\n elementId: rootTag ? readAttr(rootTag.raw, \"id\") || undefined : undefined,\n fixHint: \"Add a stable `data-composition-id` to the entry composition wrapper.\",\n snippet: truncateSnippet(rootTag?.raw || \"\"),\n });\n }\n if (!rootTag || !readAttr(rootTag.raw, \"data-width\") || !readAttr(rootTag.raw, \"data-height\")) {\n findings.push({\n code: \"root_missing_dimensions\",\n severity: \"error\",\n message: \"Root composition is missing `data-width` or `data-height`.\",\n elementId: rootTag ? readAttr(rootTag.raw, \"id\") || undefined : undefined,\n fixHint: \"Set numeric `data-width` and `data-height` on the entry composition root.\",\n snippet: truncateSnippet(rootTag?.raw || \"\"),\n });\n }\n return findings;\n },\n\n // head_leaked_text\n ({ source, rootTag }) => {\n const snippet =\n findLeakedTextInHead(source) ??\n findLeakedTextBetweenHeadAndBody(source) ??\n findLeakedTextBeforeCompositionRoot(source, rootTag);\n if (!snippet) return [];\n return [\n {\n code: \"head_leaked_text\",\n severity: \"error\",\n message:\n \"Detected leaked code or CSS text around the document `<head>` or before the composition root. Browsers render this as visible text in the video.\",\n fixHint:\n \"Move CSS into a single `<style>...</style>` block and remove stray close tags, markdown fences, or code text from `<head>`, the `</head>`/`<body>` boundary, or the pre-root body prefix.\",\n snippet: truncateSnippet(snippet),\n },\n ];\n },\n\n // visible_markup_comment\n ({ source }) => {\n const snippet = findVisibleMarkupCommentLeak(source);\n if (!snippet) return [];\n return [\n {\n code: \"visible_markup_comment\",\n severity: \"error\",\n message:\n \"CSS/JS block comment syntax (`/* ... */`) appears in visible HTML markup. HTML only treats `<!-- ... -->` as comments, so this renders as on-screen text.\",\n fixHint:\n \"Remove the text or convert it to a real HTML comment (`<!-- ... -->`). Keep CSS comments inside `<style>` and JS comments inside `<script>`.\",\n snippet: truncateSnippet(snippet),\n },\n ];\n },\n\n // missing_timeline_registry + timeline_registry_missing_init\n ({ source, rawSource, options }) => {\n // Sub-compositions inherit window.__timelines from the host composition\n if (options.isSubComposition || rawSource.trimStart().toLowerCase().startsWith(\"<template\")) {\n return [];\n }\n const findings: HyperframeLintFinding[] = [];\n if (\n !TIMELINE_REGISTRY_INIT_PATTERN.test(source) &&\n !TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source) &&\n !TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN.test(source)\n ) {\n findings.push({\n code: \"missing_timeline_registry\",\n severity: \"error\",\n message: \"Missing `window.__timelines` registration.\",\n fixHint: \"Register each composition timeline on `window.__timelines[compositionId]`.\",\n });\n }\n if (\n TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source) &&\n !TIMELINE_REGISTRY_INIT_PATTERN.test(source)\n ) {\n findings.push({\n code: \"timeline_registry_missing_init\",\n severity: \"error\",\n message:\n \"`window.__timelines[…] = …` is used without initializing `window.__timelines` first.\",\n fixHint:\n \"Add `window.__timelines = window.__timelines || {};` before any timeline assignment.\",\n });\n }\n return findings;\n },\n\n // timeline_id_mismatch\n ({ source }) => {\n const findings: HyperframeLintFinding[] = [];\n const htmlCompIds = new Set<string>();\n const timelineRegKeys = new Set<string>();\n const compIdRe = /data-composition-id\\s*=\\s*[\"']([^\"']+)[\"']/gi;\n let m: RegExpExecArray | null;\n while ((m = compIdRe.exec(source)) !== null) {\n if (m[1]) htmlCompIds.add(m[1]);\n }\n for (const key of extractTimelineRegistryKeys(source)) {\n timelineRegKeys.add(key);\n }\n for (const key of timelineRegKeys) {\n if (!htmlCompIds.has(key)) {\n findings.push({\n code: \"timeline_id_mismatch\",\n severity: \"error\",\n message: `Timeline registered as \"${key}\" but no element has data-composition-id=\"${key}\". The runtime cannot auto-nest this timeline.`,\n fixHint: `Change window.__timelines[\"${key}\"] to match the data-composition-id attribute, or vice versa.`,\n });\n }\n }\n return findings;\n },\n\n // invalid_inline_script_syntax (malformed close tag)\n ({ source }) => {\n if (!INVALID_SCRIPT_CLOSE_PATTERN.test(source)) return [];\n return [\n {\n code: \"invalid_inline_script_syntax\",\n severity: \"error\",\n message: \"Detected malformed inline `<script>` closing syntax.\",\n fixHint: \"Close inline scripts with a valid `</script>` tag.\",\n },\n ];\n },\n\n // invalid_inline_script_syntax (JS parse error)\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const script of scripts) {\n const attrs = script.attrs || \"\";\n if (\n /\\bsrc\\s*=/.test(attrs) ||\n /\\btype\\s*=\\s*[\"'](?:application\\/json|application\\/hyperframes-slideshow\\+json|importmap|module)[\"']/.test(\n attrs,\n )\n )\n continue;\n const syntaxError = getInlineScriptSyntaxError(script.content);\n if (!syntaxError) continue;\n findings.push({\n code: \"invalid_inline_script_syntax\",\n severity: \"error\",\n message: `Inline script has invalid syntax: ${syntaxError}`,\n fixHint: \"Fix the inline script syntax before render verification.\",\n snippet: truncateSnippet(script.content),\n });\n }\n return findings;\n },\n\n // host_missing_composition_id\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n const src = readAttr(tag.raw, \"data-composition-src\");\n if (!src) continue;\n if (readAttr(tag.raw, \"data-composition-id\")) continue;\n findings.push({\n code: \"host_missing_composition_id\",\n severity: \"error\",\n message: `Composition host for \"${src}\" is missing \\`data-composition-id\\`.`,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint: \"Set `data-composition-id` on every `data-composition-src` host element.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n return findings;\n },\n\n // scoped_css_missing_wrapper\n ({ styles, compositionIds }) => {\n const findings: HyperframeLintFinding[] = [];\n const scopedCssCompositionIds = new Set<string>();\n for (const style of styles) {\n for (const compId of extractCompositionIdsFromCss(style.content)) {\n scopedCssCompositionIds.add(compId);\n }\n }\n for (const compId of scopedCssCompositionIds) {\n if (compositionIds.has(compId)) continue;\n findings.push({\n code: \"scoped_css_missing_wrapper\",\n severity: \"warning\",\n message: `Scoped CSS targets composition \"${compId}\" but no matching wrapper exists in this HTML.`,\n selector: `[data-composition-id=\"${compId}\"]`,\n fixHint:\n \"Preserve the matching composition wrapper or align the CSS scope to an existing wrapper.\",\n });\n }\n return findings;\n },\n\n // composition_self_attribute_selector\n ({ styles, rootCompositionId, rootTag }) => {\n const findings: HyperframeLintFinding[] = [];\n if (!rootCompositionId) return findings;\n const seenSelectors = new Set<string>();\n const rootId = readAttr(rootTag?.raw || \"\", \"id\");\n for (const style of styles) {\n let root: postcss.Root;\n try {\n root = postcss.parse(style.content);\n } catch {\n continue;\n }\n root.walkRules((rule) => {\n for (const selector of rule.selectors) {\n if (!selectorTargetsCompositionId(selector, rootCompositionId)) continue;\n if (seenSelectors.has(selector)) continue;\n seenSelectors.add(selector);\n findings.push({\n code: \"composition_self_attribute_selector\",\n severity: \"warning\",\n message:\n \"Selector matches the block's own id; will leak to sibling instances when the block is embedded twice.\",\n selector,\n fixHint: rootId\n ? `Use #${rootId} for clearer authoring intent and instance-isolated styling.`\n : \"Add a stable id to the composition root and use that id selector for clearer authoring intent and instance-isolated styling.\",\n });\n }\n });\n }\n return findings;\n },\n\n // studio_missing_editable_id\n ({ tags, rootTag }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (rootTag && tag.index === rootTag.index) continue;\n if (!isStudioTimelineElement(tag)) continue;\n if (readAttr(tag.raw, \"id\")) continue;\n\n const descriptor = describeStudioElement(tag);\n findings.push({\n code: \"studio_missing_editable_id\",\n severity: \"warning\",\n message: `${descriptor} has no id, so Studio cannot use a stable edit target for its timeline and canvas controls.`,\n selector: readAttr(tag.raw, \"data-composition-id\")\n ? `[data-composition-id=\"${readAttr(tag.raw, \"data-composition-id\")}\"]`\n : undefined,\n fixHint:\n 'Add a stable, human-readable id such as id=\"hero-title\" or id=\"scene-1-card\" to every timeline-visible element you want agents or Studio to edit.',\n snippet: truncateSnippet(tag.raw),\n });\n }\n return findings;\n },\n\n // non_deterministic_code\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n const patterns: Array<{ pattern: RegExp; label: string; hint: string }> = [\n {\n pattern: /Math\\.random\\s*\\(/,\n label: \"Math.random()\",\n hint: \"Use a seeded PRNG (e.g. a simple mulberry32) so renders are deterministic across frames.\",\n },\n {\n pattern: /Date\\.now\\s*\\(/,\n label: \"Date.now()\",\n hint: \"Remove time-dependent code. Use GSAP timeline position instead of wall-clock time.\",\n },\n {\n pattern: /new\\s+Date\\s*\\(/,\n label: \"new Date()\",\n hint: \"Remove time-dependent code. Use GSAP timeline position instead of wall-clock time.\",\n },\n {\n pattern: /performance\\.now\\s*\\(/,\n label: \"performance.now()\",\n hint: \"Remove time-dependent code. Use GSAP timeline position instead of wall-clock time.\",\n },\n {\n pattern: /crypto\\.getRandomValues\\s*\\(/,\n label: \"crypto.getRandomValues()\",\n hint: \"Remove time-dependent code. Use a seeded PRNG for deterministic renders.\",\n },\n ];\n\n for (const script of scripts) {\n const stripped = stripJsComments(script.content);\n for (const { pattern, label, hint } of patterns) {\n if (pattern.test(stripped)) {\n findings.push({\n code: \"non_deterministic_code\",\n severity: \"error\",\n message: `Script contains \\`${label}\\` which produces non-deterministic output. Renders may differ between frames or runs.`,\n fixHint: hint,\n snippet: truncateSnippet(script.content),\n });\n }\n }\n }\n return findings;\n },\n\n // pointer_events_none\n // fallow-ignore-next-line complexity\n ({ tags, styles }) => {\n const findings: HyperframeLintFinding[] = [];\n const reported = new Set<string>();\n\n for (const tag of tags) {\n if ([\"script\", \"style\", \"link\", \"meta\", \"template\", \"noscript\"].includes(tag.name)) continue;\n const inlineStyle = readAttr(tag.raw, \"style\") ?? \"\";\n if (!/pointer-events\\s*:\\s*none/i.test(inlineStyle)) continue;\n const id = readAttr(tag.raw, \"id\");\n const key = id ?? tag.raw;\n if (reported.has(key)) continue;\n reported.add(key);\n findings.push({\n code: \"pointer_events_none\",\n severity: \"info\",\n message: `<${tag.name}${id ? ` id=\"${id}\"` : \"\"}> has \\`pointer-events: none\\` in its inline style. Elements with this property are harder to select in the Studio preview.`,\n elementId: id || undefined,\n fixHint:\n \"If this element should be selectable in the Studio, remove `pointer-events: none` or move it to a wrapper that doesn't contain editable content.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n\n for (const style of styles) {\n let root: postcss.Root;\n try {\n root = postcss.parse(style.content);\n } catch {\n continue;\n }\n root.walkDecls(\"pointer-events\", (decl) => {\n if (decl.value.trim().toLowerCase() !== \"none\") return;\n const rule = decl.parent;\n if (!rule || rule.type !== \"rule\") return;\n const selector = (rule as postcss.Rule).selector;\n if (reported.has(selector)) return;\n reported.add(selector);\n findings.push({\n code: \"pointer_events_none\",\n severity: \"info\",\n message: `\\`${selector}\\` sets \\`pointer-events: none\\`. Elements matching this selector are harder to select in the Studio preview.`,\n selector,\n fixHint:\n \"If these elements should be selectable in the Studio, remove `pointer-events: none` or move it to a wrapper that doesn't contain editable content.\",\n });\n });\n }\n\n return findings;\n },\n];\n","import type { LintContext, HyperframeLintFinding } from \"../context\";\nimport { readAttr, truncateSnippet, isMediaTag } from \"../utils\";\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction hasAttrName(tagSource: string, attr: string): boolean {\n const escaped = escapeRegExp(attr);\n const attrs = tagSource.replace(/^<\\s*[a-z][\\w:-]*/i, \"\");\n return new RegExp(`(?:^|\\\\s)${escaped}(?:\\\\s*=|\\\\s|/?>)`, \"i\").test(attrs);\n}\n\nfunction classNamesFromAttr(classAttr: string | null): string[] {\n if (!classAttr) return [];\n return classAttr.split(/\\s+/).filter(Boolean);\n}\n\ntype MediaSelectorIndex = {\n ids: Set<string>;\n classes: Set<string>;\n hasVideo: boolean;\n hasAudio: boolean;\n};\n\nfunction selectorTargetsManagedMedia(selector: string, mediaIndex: MediaSelectorIndex): boolean {\n const normalized = selector.trim();\n if (!normalized) return false;\n if (mediaIndex.hasVideo && /\\bvideo\\b/i.test(normalized)) return true;\n if (mediaIndex.hasAudio && /\\baudio\\b/i.test(normalized)) return true;\n for (const mediaId of mediaIndex.ids) {\n const escapedId = escapeRegExp(mediaId);\n if (\n new RegExp(`#${escapedId}(?![\\\\w-])`).test(normalized) ||\n normalized.includes(`[id=\"${mediaId}\"]`) ||\n normalized.includes(`[id='${mediaId}']`)\n ) {\n return true;\n }\n }\n for (const className of mediaIndex.classes) {\n if (new RegExp(`\\\\.${escapeRegExp(className)}(?![\\\\w-])`).test(normalized)) {\n return true;\n }\n }\n return false;\n}\n\nfunction findImperativeMediaControlFindings(ctx: LintContext): HyperframeLintFinding[] {\n const findings: HyperframeLintFinding[] = [];\n const mediaTags = ctx.tags.filter((tag) => tag.name === \"video\" || tag.name === \"audio\");\n const mediaIndex: MediaSelectorIndex = {\n ids: new Set(\n mediaTags.map((tag) => readAttr(tag.raw, \"id\")).filter((id): id is string => Boolean(id)),\n ),\n classes: new Set(mediaTags.flatMap((tag) => classNamesFromAttr(readAttr(tag.raw, \"class\")))),\n hasVideo: mediaTags.some((tag) => tag.name === \"video\"),\n hasAudio: mediaTags.some((tag) => tag.name === \"audio\"),\n };\n\n if (mediaTags.length === 0 || ctx.scripts.length === 0) return findings;\n\n for (const script of ctx.scripts) {\n const mediaVars = new Map<string, string | undefined>();\n const assignmentPatterns = [\n {\n pattern:\n /\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*(?:document|window\\.document)\\.getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/g,\n variableIndex: 1,\n targetIndex: 2,\n },\n {\n pattern:\n /\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*(?:document|window\\.document)\\.querySelector\\(\\s*([\"'])([\\s\\S]*?)\\2\\s*\\)/g,\n variableIndex: 1,\n targetIndex: 3,\n },\n ];\n\n for (const { pattern, variableIndex, targetIndex } of assignmentPatterns) {\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(script.content)) !== null) {\n const variableName = match[variableIndex];\n const target = match[targetIndex];\n if (!variableName || !target) continue;\n if (mediaIndex.ids.has(target) || selectorTargetsManagedMedia(target, mediaIndex)) {\n mediaVars.set(variableName, mediaIndex.ids.has(target) ? target : undefined);\n }\n }\n }\n\n const directIdPatterns = [\n {\n pattern:\n /\\b(?:document|window\\.document)\\.getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)\\.play\\s*\\(/g,\n kind: \"play()\",\n targetIndex: 1,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)\\.pause\\s*\\(/g,\n kind: \"pause()\",\n targetIndex: 1,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)\\.currentTime\\s*=/g,\n kind: \"currentTime\",\n targetIndex: 1,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.getElementById\\(\\s*[\"']([^\"']+)[\"']\\s*\\)\\.muted\\s*=/g,\n kind: \"muted assignment\",\n targetIndex: 1,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.querySelector\\(\\s*([\"'])([\\s\\S]*?)\\1\\s*\\)\\.play\\s*\\(/g,\n kind: \"play()\",\n targetIndex: 2,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.querySelector\\(\\s*([\"'])([\\s\\S]*?)\\1\\s*\\)\\.pause\\s*\\(/g,\n kind: \"pause()\",\n targetIndex: 2,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.querySelector\\(\\s*([\"'])([\\s\\S]*?)\\1\\s*\\)\\.currentTime\\s*=/g,\n kind: \"currentTime\",\n targetIndex: 2,\n },\n {\n pattern:\n /\\b(?:document|window\\.document)\\.querySelector\\(\\s*([\"'])([\\s\\S]*?)\\1\\s*\\)\\.muted\\s*=/g,\n kind: \"muted assignment\",\n targetIndex: 2,\n },\n ];\n\n for (const { pattern, kind, targetIndex } of directIdPatterns) {\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(script.content)) !== null) {\n const target = match[targetIndex];\n if (!target) continue;\n const elementId = mediaIndex.ids.has(target)\n ? target\n : selectorTargetsManagedMedia(target, mediaIndex)\n ? undefined\n : null;\n if (elementId === null) continue;\n findings.push({\n code: \"imperative_media_control\",\n severity: \"error\",\n message: `Inline <script> imperatively controls managed media via ${kind}. HyperFrames must own media play/pause/seek to keep preview, timeline, and renders deterministic.`,\n elementId: elementId || undefined,\n fixHint:\n \"Remove imperative media play/pause/currentTime/muted control. Express timing with data-start/data-duration and media offsets like data-media-start or data-playback-start instead.\",\n snippet: truncateSnippet(match[0]),\n });\n }\n }\n\n for (const [variableName, elementId] of mediaVars) {\n const escapedVar = escapeRegExp(variableName);\n const variablePatterns = [\n { pattern: new RegExp(`\\\\b${escapedVar}\\\\.play\\\\s*\\\\(`, \"g\"), kind: \"play()\" },\n { pattern: new RegExp(`\\\\b${escapedVar}\\\\.pause\\\\s*\\\\(`, \"g\"), kind: \"pause()\" },\n { pattern: new RegExp(`\\\\b${escapedVar}\\\\.currentTime\\\\s*=`, \"g\"), kind: \"currentTime\" },\n {\n pattern: new RegExp(`\\\\b${escapedVar}\\\\.muted\\\\s*=`, \"g\"),\n kind: \"muted assignment\",\n },\n ];\n for (const { pattern, kind } of variablePatterns) {\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(script.content)) !== null) {\n findings.push({\n code: \"imperative_media_control\",\n severity: \"error\",\n message: `Inline <script> imperatively controls managed media via ${kind}. HyperFrames must own media play/pause/seek to keep preview, timeline, and renders deterministic.`,\n elementId,\n fixHint:\n \"Remove imperative media play/pause/currentTime/muted control. Express timing with data-start/data-duration and media offsets like data-media-start or data-playback-start instead.\",\n snippet: truncateSnippet(match[0]),\n });\n }\n }\n }\n }\n\n return findings;\n}\n\nexport const mediaRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // duplicate_media_id + duplicate_media_discovery_risk\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const mediaById = new Map<string, typeof tags>();\n const mediaFingerprintCounts = new Map<string, number>();\n\n for (const tag of tags) {\n if (!isMediaTag(tag.name)) continue;\n const elementId = readAttr(tag.raw, \"id\");\n if (elementId) {\n const existing = mediaById.get(elementId) || [];\n existing.push(tag);\n mediaById.set(elementId, existing);\n }\n const fingerprint = [\n tag.name,\n readAttr(tag.raw, \"src\") || \"\",\n readAttr(tag.raw, \"data-start\") || \"\",\n readAttr(tag.raw, \"data-duration\") || \"\",\n ].join(\"|\");\n mediaFingerprintCounts.set(fingerprint, (mediaFingerprintCounts.get(fingerprint) || 0) + 1);\n }\n\n for (const [elementId, mediaTags] of mediaById) {\n if (mediaTags.length < 2) continue;\n findings.push({\n code: \"duplicate_media_id\",\n severity: \"error\",\n message: `Media id \"${elementId}\" is defined multiple times.`,\n elementId,\n fixHint:\n \"Give each media element a unique id so preview and producer discover the same media graph.\",\n snippet: truncateSnippet(mediaTags[0]?.raw || \"\"),\n });\n }\n\n for (const [fingerprint, count] of mediaFingerprintCounts) {\n if (count < 2) continue;\n const [tagName, src, dataStart, dataDuration] = fingerprint.split(\"|\");\n findings.push({\n code: \"duplicate_media_discovery_risk\",\n severity: \"warning\",\n message: `Detected ${count} matching ${tagName} entries with the same source/start/duration.`,\n fixHint: \"Avoid duplicated media nodes that can be discovered twice during compilation.\",\n snippet: truncateSnippet(\n `${tagName} src=${src} data-start=${dataStart} data-duration=${dataDuration}`,\n ),\n });\n }\n return findings;\n },\n\n // video_missing_muted\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (tag.name !== \"video\") continue;\n const hasMuted = hasAttrName(tag.raw, \"muted\");\n const hasDeclaredAudio = readAttr(tag.raw, \"data-has-audio\") === \"true\";\n if (!hasMuted && !hasDeclaredAudio && readAttr(tag.raw, \"data-start\")) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"video_missing_muted\",\n severity: \"error\",\n message: `<video${elementId ? ` id=\"${elementId}\"` : \"\"}> has data-start but is not muted. Mark audible videos with data-has-audio=\"true\"; otherwise keep video muted and use a separate <audio> element for sound.`,\n elementId,\n fixHint:\n 'Add the `muted` attribute for silent video, or add data-has-audio=\"true\" when the video track should contribute audio.',\n snippet: truncateSnippet(tag.raw),\n });\n }\n if (hasMuted && hasDeclaredAudio) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"video_muted_with_declared_audio\",\n severity: \"error\",\n message: `<video${elementId ? ` id=\"${elementId}\"` : \"\"}> declares data-has-audio=\"true\" but also has muted. Studio preview will silence the video audio.`,\n elementId,\n fixHint:\n 'Remove the `muted` attribute if this video should be audible, or remove data-has-audio=\"true\" and use data-volume=\"0\" for silent visual video.',\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // video_nested_in_timed_element\n ({ source, tags }) => {\n const findings: HyperframeLintFinding[] = [];\n // HTML5 void elements cannot contain children, so they can never be a\n // parent of a nested <video>. Skipping them avoids false positives where\n // the linter looks for `</img>` and never finds it.\n const voidElements = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"source\",\n \"track\",\n \"wbr\",\n ]);\n const timedTagPositions: Array<{ name: string; start: number; id?: string }> = [];\n for (const tag of tags) {\n if (tag.name === \"video\" || tag.name === \"audio\") continue;\n if (voidElements.has(tag.name)) continue;\n // Skip the composition root — it uses data-start as a playback anchor, not as a clip timer\n if (readAttr(tag.raw, \"data-composition-id\")) continue;\n if (readAttr(tag.raw, \"data-start\")) {\n timedTagPositions.push({\n name: tag.name,\n start: tag.index,\n id: readAttr(tag.raw, \"id\") || undefined,\n });\n }\n }\n for (const tag of tags) {\n if (tag.name !== \"video\") continue;\n if (!readAttr(tag.raw, \"data-start\")) continue;\n for (const parent of timedTagPositions) {\n if (parent.start < tag.index) {\n const parentClosePattern = new RegExp(`</${parent.name}>`, \"gi\");\n const between = source.substring(parent.start, tag.index);\n if (!parentClosePattern.test(between)) {\n findings.push({\n code: \"video_nested_in_timed_element\",\n severity: \"error\",\n message: `<video> with data-start is nested inside <${parent.name}${parent.id ? ` id=\"${parent.id}\"` : \"\"}> which also has data-start. The framework cannot manage playback of nested media — video will be FROZEN in renders.`,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n \"Move the <video> to be a direct child of the stage, or remove data-start from the wrapper div (use it as a non-timed visual container).\",\n snippet: truncateSnippet(tag.raw),\n });\n break;\n }\n }\n }\n }\n return findings;\n },\n\n // media_in_subcomposition — <video>/<audio> only render as a DIRECT child of the host\n // root (index.html). Inside a sub-composition <template> the runtime never seeks/decodes\n // them, so they render BLANK/black in preview and renders — and the other lint/validate\n // passes otherwise miss it (only a per-frame snapshot reveals the blank panel).\n ({ tags, options }) => {\n const findings: HyperframeLintFinding[] = [];\n if (!options.isSubComposition) return findings;\n for (const tag of tags) {\n if (tag.name !== \"video\" && tag.name !== \"audio\") continue;\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"media_in_subcomposition\",\n severity: \"error\",\n 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.`,\n elementId,\n fixHint:\n \"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.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n return findings;\n },\n\n // self_closing_media_tag\n ({ source }) => {\n const findings: HyperframeLintFinding[] = [];\n const selfClosingMediaRe = /<(audio|video)\\b[^>]*\\/>/gi;\n let scMatch: RegExpExecArray | null;\n while ((scMatch = selfClosingMediaRe.exec(source)) !== null) {\n const tagName = scMatch[1] || \"audio\";\n const elementId = readAttr(scMatch[0], \"id\") || undefined;\n findings.push({\n code: \"self_closing_media_tag\",\n severity: \"error\",\n message: `Self-closing <${tagName}/> is invalid HTML. The browser will leave the tag open, swallowing all subsequent elements as invisible fallback content. This makes compositions INVISIBLE.`,\n elementId,\n fixHint: `Change <${tagName} .../> to <${tagName} ...></${tagName}> — media elements MUST have explicit closing tags.`,\n snippet: truncateSnippet(scMatch[0]),\n });\n }\n return findings;\n },\n\n // placeholder_media_url\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const PLACEHOLDER_DOMAINS =\n /\\b(placehold\\.co|placeholder\\.com|placekitten\\.com|picsum\\.photos|example\\.com|via\\.placeholder\\.com|dummyimage\\.com)\\b/i;\n for (const tag of tags) {\n if (!isMediaTag(tag.name)) continue;\n const src = readAttr(tag.raw, \"src\");\n if (!src) continue;\n if (PLACEHOLDER_DOMAINS.test(src)) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"placeholder_media_url\",\n severity: \"error\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> uses a placeholder URL that will 404 at render time: ${src.slice(0, 80)}`,\n elementId,\n fixHint: \"Replace with a real media URL. Placeholder domains will 404 at render time.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // base64_media_prohibited\n ({ source }) => {\n const findings: HyperframeLintFinding[] = [];\n const base64MediaRe =\n /src\\s*=\\s*[\"'](data:(?:audio|video)\\/[^;]+;base64,([A-Za-z0-9+/=]{20,}))[\"']/gi;\n let b64Match: RegExpExecArray | null;\n while ((b64Match = base64MediaRe.exec(source)) !== null) {\n const sample = (b64Match[2] || \"\").slice(0, 200);\n const uniqueChars = new Set(sample.replace(/[A-Za-z0-9+/=]/g, (c) => c)).size;\n const dataSize = Math.round(((b64Match[2] || \"\").length * 3) / 4);\n const isSuspicious = uniqueChars < 15 || (dataSize > 1000 && dataSize < 50000);\n findings.push({\n code: \"base64_media_prohibited\",\n severity: \"error\",\n message: `Inline base64 audio/video detected (${(dataSize / 1024).toFixed(0)} KB)${isSuspicious ? \" — likely fabricated data\" : \"\"}. Base64 media is prohibited — it bloats file size and breaks rendering.`,\n fixHint:\n \"Use a relative path (assets/music.mp3) or HTTPS URL for the audio/video src. Never embed media as base64.\",\n snippet: truncateSnippet((b64Match[1] ?? \"\").slice(0, 80) + \"...\"),\n });\n }\n return findings;\n },\n\n // media_missing_data_start + media_missing_id + media_missing_src + media_preload_none\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (tag.name !== \"video\" && tag.name !== \"audio\") continue;\n const hasDataStart = readAttr(tag.raw, \"data-start\");\n const hasId = readAttr(tag.raw, \"id\");\n const hasSrc = readAttr(tag.raw, \"src\");\n if (hasSrc && !hasDataStart) {\n findings.push({\n code: \"media_missing_data_start\",\n severity: \"error\",\n message: `<${tag.name}${hasId ? ` id=\"${hasId}\"` : \"\"}> has src but no data-start. HyperFrames cannot own playback for untimed media, so preview and render behavior can diverge.`,\n elementId: hasId || undefined,\n fixHint: `Add data-start=\"0\" (or the intended start time) and data-duration if the clip should stop before the source ends.`,\n snippet: truncateSnippet(tag.raw),\n });\n }\n if (hasDataStart && !hasId) {\n findings.push({\n code: \"media_missing_id\",\n severity: \"error\",\n message: `<${tag.name}> has data-start but no id attribute. The renderer requires id to discover media elements — this ${tag.name === \"audio\" ? \"audio will be SILENT\" : \"video will be FROZEN\"} in renders.`,\n fixHint: `Add a unique id attribute: <${tag.name} id=\"my-${tag.name}\" ...>`,\n snippet: truncateSnippet(tag.raw),\n });\n }\n if (hasDataStart && hasId && !hasSrc) {\n findings.push({\n code: \"media_missing_src\",\n severity: \"error\",\n message: `<${tag.name} id=\"${hasId}\"> has data-start but no src attribute. The renderer cannot load this media.`,\n elementId: hasId,\n fixHint: `Add a src attribute to the <${tag.name}> element directly. If using <source> children, the renderer still requires src on the parent element.`,\n snippet: truncateSnippet(tag.raw),\n });\n }\n if (readAttr(tag.raw, \"preload\") === \"none\") {\n findings.push({\n code: \"media_preload_none\",\n severity: \"warning\",\n message: `<${tag.name}${hasId ? ` id=\"${hasId}\"` : \"\"}> has preload=\"none\" which prevents the renderer from loading this media. The compiler strips it for renders, but preview may also have issues.`,\n elementId: hasId || undefined,\n fixHint: `Remove preload=\"none\" or change to preload=\"auto\". The framework manages media loading.`,\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // media_crossorigin_breaks_preview — `crossorigin` on <video>/<audio> forces a\n // CORS-checked fetch. The server-side renderer downloads media directly (no CORS),\n // so it always works there; but Studio preview runs in the browser, where a media\n // host that omits Access-Control-Allow-Origin silently fails the load — the media\n // shows BLANK/black in preview while renders look fine, hiding the bug. Plain\n // displayed media never needs crossorigin; it's only required to read pixels/samples\n // back (canvas/WebGL texture, WebAudio createMediaElementSource) AND only when the\n // host is known CORS-enabled.\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (tag.name !== \"video\" && tag.name !== \"audio\") continue;\n if (!hasAttrName(tag.raw, \"crossorigin\")) continue;\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"media_crossorigin_breaks_preview\",\n severity: \"error\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> has crossorigin, which forces a CORS-checked fetch. If the media host omits Access-Control-Allow-Origin, the load silently fails in Studio preview (media shows BLANK/black) while server-side renders still work — hiding the bug.`,\n elementId,\n fixHint:\n \"Remove the crossorigin attribute unless you read the media back via canvas/WebGL/WebAudio AND the host is known to send CORS headers. Plain displayed media never needs it.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n return findings;\n },\n\n // video_audio_double_source — catches audible <video> paired with a separate\n // <audio> pointing to the same file, which causes double playback at runtime\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const videoSources = new Map<string, { id?: string; raw: string }>();\n const audioSources = new Map<string, { id?: string; raw: string }>();\n\n for (const tag of tags) {\n if (!readAttr(tag.raw, \"data-start\")) continue;\n const src = readAttr(tag.raw, \"src\");\n if (!src) continue;\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n if (tag.name === \"video\") {\n const isMuted = hasAttrName(tag.raw, \"muted\");\n if (!isMuted) {\n videoSources.set(src, { id: elementId, raw: tag.raw });\n }\n } else if (tag.name === \"audio\") {\n audioSources.set(src, { id: elementId, raw: tag.raw });\n }\n }\n\n for (const [src, audioInfo] of audioSources) {\n const videoInfo = videoSources.get(src);\n if (!videoInfo) continue;\n findings.push({\n code: \"video_audio_double_source\",\n severity: \"error\",\n message: `<audio${audioInfo.id ? ` id=\"${audioInfo.id}\"` : \"\"}> and <video${videoInfo.id ? ` id=\"${videoInfo.id}\"` : \"\"}> both point to the same source. The unmuted video already provides audio — the duplicate <audio> will cause double playback and echo.`,\n elementId: audioInfo.id,\n fixHint:\n \"Either mute the video (add `muted` attribute) and keep the separate <audio>, or remove the <audio> element and let the video provide its own audio track.\",\n snippet: truncateSnippet(audioInfo.raw),\n });\n }\n return findings;\n },\n\n // imperative_media_control\n findImperativeMediaControlFindings,\n];\n","interface LintParsedGsap {\n animations: Array<{\n targetSelector: string;\n method: string;\n position: number | string;\n properties: Record<string, number | string>;\n // fromTo() exposes its first (\"from\") vars object separately; a layout/reflow prop\n // that appears only here still animates and must be checked.\n fromProperties?: Record<string, number | string>;\n duration?: number;\n ease?: string;\n extras?: Record<string, unknown>;\n }>;\n timelineVar: string;\n}\n\n// Use the acorn read parser: it resolves computed timelines (helpers, bounded\n// loops) so lint findings like overlapping_gsap_tweens reflect true positions\n// instead of all-collapsed-at-0. It's also browser-safe, so this keeps recast\n// out of the lint graph entirely. Dynamic import preserves the lazy load.\nasync function loadParseGsapScript(): Promise<(script: string) => LintParsedGsap> {\n const mod = await import(\"@hyperframes/parsers/gsap-parser-acorn\");\n return mod.parseGsapScriptAcorn as unknown as (script: string) => LintParsedGsap;\n}\nimport type { LintContext } from \"../context\";\nimport type { HyperframeLintFinding, LintRule } from \"../types\";\nimport type { OpenTag } from \"../utils\";\nimport {\n readAttr,\n truncateSnippet,\n stripJsComments,\n hasCaptionStyles,\n WINDOW_TIMELINE_ASSIGN_PATTERN,\n TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN,\n} from \"../utils\";\n\n// ── GSAP-specific types ────────────────────────────────────────────────────\n\ntype GsapWindow = {\n targetSelector: string;\n position: number;\n end: number;\n properties: string[];\n propertyValues: Record<string, string | number>;\n overwriteAuto: boolean;\n method: string;\n raw: string;\n};\n\ntype CompositionRange = {\n id: string;\n start: number;\n end: number;\n};\n\nconst SCENE_BOUNDARY_EPSILON_SECONDS = 0.05;\n\n// Sentinel the GSAP parser assigns to a tween whose target it cannot statically\n// resolve to a concrete element (a computed variable, a helper call, etc.). It is\n// NOT an identity: two distinct unresolved selectors are not the same element, so\n// overlap analysis must never treat them as one.\nconst UNRESOLVED_TARGET = \"__unresolved__\";\n\n// ── GSAP parsing utilities ─────────────────────────────────────────────────\n\nfunction countClassUsage(tags: OpenTag[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const tag of tags) {\n const classAttr = readAttr(tag.raw, \"class\");\n if (!classAttr) continue;\n for (const className of classAttr.split(/\\s+/).filter(Boolean)) {\n counts.set(className, (counts.get(className) || 0) + 1);\n }\n }\n return counts;\n}\n\nfunction readRegisteredTimelineCompositionId(script: string): string | null {\n const match = script.match(WINDOW_TIMELINE_ASSIGN_PATTERN);\n return match?.[1] || match?.[2] || null;\n}\n\n/** Strip a `__raw:` prefix the parser adds to unresolvable values. */\nfunction unwrapRaw(value: unknown): string | number | undefined {\n if (typeof value === \"number\") return value;\n if (typeof value !== \"string\") return undefined;\n const code = value.startsWith(\"__raw:\") ? value.slice(6) : value;\n return code.replace(/^\\s*[\"']|[\"']\\s*$/g, \"\");\n}\n\nfunction extrasNumber(value: unknown): number {\n const unwrapped = unwrapRaw(value);\n const numeric = typeof unwrapped === \"number\" ? unwrapped : Number(unwrapped);\n return Number.isFinite(numeric) ? numeric : 0;\n}\n\n/** A readable single-line snippet of a tween for finding messages. */\nfunction synthesizeWindowRaw(\n timelineVar: string,\n anim: LintParsedGsap[\"animations\"][number],\n): string {\n const entries = Object.entries(anim.properties).map(([k, v]) => {\n if (typeof v === \"string\" && v.startsWith(\"__raw:\")) return `${k}: ${v.slice(6)}`;\n return `${k}: ${typeof v === \"string\" ? JSON.stringify(v) : v}`;\n });\n if (anim.duration !== undefined) entries.push(`duration: ${anim.duration}`);\n if (anim.ease) entries.push(`ease: ${JSON.stringify(anim.ease)}`);\n const pos = typeof anim.position === \"number\" ? anim.position : JSON.stringify(anim.position);\n return `${timelineVar}.${anim.method}(\"${anim.targetSelector}\", { ${entries.join(\", \")} }, ${pos})`;\n}\n\nconst gsapWindowsCache = new Map<string, GsapWindow[]>();\n\nasync function cachedExtractGsapWindows(scriptContent: string): Promise<GsapWindow[]> {\n const cached = gsapWindowsCache.get(scriptContent);\n if (cached) return cached;\n const windows = await extractGsapWindows(scriptContent);\n gsapWindowsCache.set(scriptContent, windows);\n return windows;\n}\n\n// fallow-ignore-next-line complexity\nasync function extractGsapWindows(script: string): Promise<GsapWindow[]> {\n if (!/gsap\\.timeline/.test(script)) return [];\n const parseGsapScript = await loadParseGsapScript();\n const parsed = parseGsapScript(script);\n if (parsed.animations.length === 0) return [];\n\n const windows: GsapWindow[] = [];\n for (const animation of parsed.animations) {\n // Skip animations with string positions (e.g. \"+=1\", \"<\") — their absolute\n // timing depends on runtime evaluation and can't be statically linted.\n if (typeof animation.position !== \"number\") continue;\n const repeat = extrasNumber(animation.extras?.repeat);\n const cycleCount = repeat > 0 ? repeat + 1 : 1;\n const effectiveDuration =\n animation.method === \"set\" ? 0 : (animation.duration ?? 0) * cycleCount;\n windows.push({\n targetSelector: animation.targetSelector,\n position: animation.position,\n end: animation.position + effectiveDuration,\n properties: Object.keys(animation.properties),\n propertyValues: animation.properties,\n overwriteAuto: unwrapRaw(animation.extras?.overwrite) === \"auto\",\n method: animation.method,\n raw: synthesizeWindowRaw(parsed.timelineVar, animation),\n });\n }\n return windows;\n}\n\nfunction numberValue(value: string | number | undefined): number | null {\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\" && value.trim()) {\n const numeric = Number(value);\n return Number.isFinite(numeric) ? numeric : null;\n }\n return null;\n}\n\nfunction stringValue(value: string | number | undefined): string | null {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\") return String(value);\n return null;\n}\n\nfunction zeroValue(value: string | number | undefined): boolean {\n if (typeof value === \"number\") return value === 0;\n if (typeof value !== \"string\") return false;\n return Number(value.trim()) === 0;\n}\n\nfunction isHiddenGsapState(values: Record<string, string | number>): boolean {\n const visibility = stringValue(values.visibility)?.toLowerCase();\n const display = stringValue(values.display)?.toLowerCase();\n return (\n zeroValue(values.opacity) ||\n zeroValue(values.autoAlpha) ||\n visibility === \"hidden\" ||\n display === \"none\"\n );\n}\n\nfunction oneValue(\n values: Record<string, string | number>,\n keys: string[],\n): string | number | undefined {\n for (const key of keys) {\n const value = values[key];\n if (value !== undefined) return value;\n }\n return undefined;\n}\n\nfunction isVisibleGsapState(values: Record<string, string | number>): boolean {\n const opacity = oneValue(values, [\"opacity\", \"autoAlpha\"]);\n if (typeof opacity === \"number\") return opacity > 0;\n if (typeof opacity === \"string\" && opacity.trim()) {\n const numeric = Number(opacity);\n if (Number.isFinite(numeric)) return numeric > 0;\n }\n\n const visibility = stringValue(values.visibility)?.toLowerCase();\n if (visibility === \"visible\" || visibility === \"inherit\") return true;\n\n const display = stringValue(values.display)?.toLowerCase();\n if (display && display !== \"none\") return true;\n\n return false;\n}\n\nfunction makesOverlayVisible(win: GsapWindow): boolean {\n if (win.method === \"from\" && isHiddenGsapState(win.propertyValues)) return true;\n return isVisibleGsapState(win.propertyValues);\n}\n\nfunction isSceneBoundaryExit(win: GsapWindow): boolean {\n if (win.end <= win.position) return false;\n if (win.method !== \"to\" && win.method !== \"fromTo\") return false;\n return isHiddenGsapState(win.propertyValues);\n}\n\nfunction isHardKillSet(win: GsapWindow, selector: string, boundary: number): boolean {\n return (\n win.method === \"set\" &&\n win.targetSelector === selector &&\n Math.abs(win.position - boundary) <= SCENE_BOUNDARY_EPSILON_SECONDS &&\n isHiddenGsapState(win.propertyValues)\n );\n}\n\nfunction hiddenStateLiteral(values: Record<string, string | number>): string {\n if (zeroValue(values.autoAlpha)) return \"{ autoAlpha: 0 }\";\n if (zeroValue(values.opacity)) return \"{ opacity: 0 }\";\n if (stringValue(values.visibility)?.toLowerCase() === \"hidden\") return '{ visibility: \"hidden\" }';\n if (stringValue(values.display)?.toLowerCase() === \"none\") return '{ display: \"none\" }';\n return \"{ opacity: 0 }\";\n}\n\nfunction findTagEnd(source: string, tag: OpenTag): number {\n const escapedTagName = tag.name.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = new RegExp(`<\\\\/?${escapedTagName}\\\\b[^>]*>`, \"gi\");\n pattern.lastIndex = tag.index;\n\n let depth = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(source)) !== null) {\n const raw = match[0];\n const isClosing = /^<\\s*\\//.test(raw);\n const isSelfClosing = /\\/\\s*>$/.test(raw);\n if (!isClosing && !isSelfClosing) depth += 1;\n if (isClosing) depth -= 1;\n if (depth === 0) return pattern.lastIndex;\n }\n\n return source.length;\n}\n\nfunction collectCompositionRanges(source: string, tags: OpenTag[]): CompositionRange[] {\n return tags\n .map((tag) => {\n const id = readAttr(tag.raw, \"data-composition-id\");\n if (!id) return null;\n return {\n id,\n start: tag.index,\n end: findTagEnd(source, tag),\n };\n })\n .filter((range) => range !== null);\n}\n\nfunction findContainingCompositionId(tag: OpenTag, ranges: CompositionRange[]): string | null {\n let match: CompositionRange | null = null;\n for (const range of ranges) {\n if (tag.index < range.start || tag.index >= range.end) continue;\n if (!match || range.start >= match.start) match = range;\n }\n return match?.id || null;\n}\n\n// A tag's `class` attribute, split into tokens, but only when it carries the\n// `clip` marker class — the common \"is this a clip element?\" filter used by\n// several rules that walk every tag looking for clips.\ntype ClipTagClasses = { classAttr: string; classes: string[] };\n\nfunction getClipTagClasses(tag: OpenTag): ClipTagClasses | null {\n const classAttr = readAttr(tag.raw, \"class\") || \"\";\n const classes = classAttr.split(/\\s+/).filter(Boolean);\n return classes.includes(\"clip\") ? { classAttr, classes } : null;\n}\n\nfunction collectClipStartBoundariesByComposition(\n source: string,\n tags: OpenTag[],\n): Map<string, number[]> {\n const ranges = collectCompositionRanges(source, tags);\n const boundaries = new Map<string, Set<number>>();\n\n for (const tag of tags) {\n if (!getClipTagClasses(tag)) continue;\n const compositionId = findContainingCompositionId(tag, ranges);\n if (!compositionId) continue;\n const start = numberValue(readAttr(tag.raw, \"data-start\") ?? undefined);\n if (start == null || start <= 0) continue;\n const compositionBoundaries = boundaries.get(compositionId) ?? new Set<number>();\n compositionBoundaries.add(start);\n boundaries.set(compositionId, compositionBoundaries);\n }\n\n return new Map(\n [...boundaries.entries()].map(([compositionId, values]) => [\n compositionId,\n [...values].sort((a, b) => a - b),\n ]),\n );\n}\n\nfunction findMatchingSceneBoundary(time: number, boundaries: number[]): number | null {\n for (const boundary of boundaries) {\n if (Math.abs(time - boundary) <= SCENE_BOUNDARY_EPSILON_SECONDS) return boundary;\n }\n return null;\n}\n\nfunction isSuspiciousGlobalSelector(selector: string): boolean {\n if (!selector) return false;\n if (selector.includes(\"[data-composition-id=\")) return false;\n if (selector.startsWith(\"#\")) return false;\n return selector.startsWith(\".\") || /^[a-z]/i.test(selector);\n}\n\nfunction getSingleClassSelector(selector: string): string | null {\n const match = selector.trim().match(/^\\.(?<name>[A-Za-z0-9_-]+)$/);\n return match?.groups?.name || null;\n}\n\nfunction readStyleProperty(style: string, property: string): string | null {\n const escapedProperty = property.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const match = style.match(new RegExp(`(?:^|;)\\\\s*${escapedProperty}\\\\s*:\\\\s*([^;]+)`, \"i\"));\n return match?.[1]?.trim() || null;\n}\n\nfunction cssZero(value: string | null): boolean {\n if (!value) return false;\n return /^0(?:\\.0+)?(?:px|%|vw|vh|rem|em)?$/i.test(value.trim());\n}\n\nfunction styleHasHiddenInitialState(style: string): boolean {\n const opacity = readStyleProperty(style, \"opacity\");\n if (opacity && Number(opacity) === 0) return true;\n if (readStyleProperty(style, \"visibility\")?.toLowerCase() === \"hidden\") return true;\n if (readStyleProperty(style, \"display\")?.toLowerCase() === \"none\") return true;\n return false;\n}\n\nfunction styleHasOpaqueBackground(style: string): boolean {\n const background =\n readStyleProperty(style, \"background\") || readStyleProperty(style, \"background-color\");\n if (!background) return false;\n const normalized = background.toLowerCase().replace(/\\s+/g, \"\");\n if (normalized === \"transparent\" || normalized === \"none\") return false;\n if (/rgba?\\([^)]*,0(?:\\.0+)?\\)$/.test(normalized)) return false;\n if (/hsla?\\([^)]*,0(?:\\.0+)?\\)$/.test(normalized)) return false;\n return true;\n}\n\nfunction styleLooksFullFrameOverlay(style: string): boolean {\n const position = readStyleProperty(style, \"position\")?.toLowerCase();\n if (position !== \"fixed\" && position !== \"absolute\") return false;\n const coversFrame =\n cssZero(readStyleProperty(style, \"inset\")) ||\n (cssZero(readStyleProperty(style, \"top\")) &&\n cssZero(readStyleProperty(style, \"right\")) &&\n cssZero(readStyleProperty(style, \"bottom\")) &&\n cssZero(readStyleProperty(style, \"left\")));\n return coversFrame && styleHasOpaqueBackground(style);\n}\n\nfunction collectSimpleStyleRules(styles: LintContext[\"styles\"]): Map<string, string> {\n const rules = new Map<string, string>();\n for (const style of styles) {\n for (const [, selectorList, body] of style.content.matchAll(/([^{}]+)\\{([^}]+)\\}/g)) {\n if (!selectorList || !body) continue;\n for (const selector of selectorList.split(\",\")) {\n const token = selector.trim();\n if (!/^[#.][A-Za-z0-9_-]+$/.test(token)) continue;\n rules.set(token, `${rules.get(token) || \"\"};${body}`);\n }\n }\n }\n return rules;\n}\n\nfunction tagSimpleSelectors(tag: OpenTag): string[] {\n const selectors: string[] = [];\n const id = readAttr(tag.raw, \"id\");\n if (id) selectors.push(`#${id}`);\n const classes = readAttr(tag.raw, \"class\")?.split(/\\s+/).filter(Boolean) ?? [];\n for (const className of classes) selectors.push(`.${className}`);\n return selectors;\n}\n\nfunction combinedTagStyle(tag: OpenTag, styleRules: Map<string, string>): string {\n const styles = [readAttr(tag.raw, \"style\") || \"\"];\n for (const selector of tagSimpleSelectors(tag)) {\n const ruleStyle = styleRules.get(selector);\n if (ruleStyle) styles.push(ruleStyle);\n }\n return styles.filter(Boolean).join(\";\");\n}\n\n// fallow-ignore-next-line complexity\nfunction cssTransformToGsapProps(cssTransform: string): string | null {\n const parts: string[] = [];\n\n // translate(-50%, -50%) or translate(X, Y)\n const translateMatch = cssTransform.match(\n /translate\\(\\s*(-?[\\d.]+)(%|px)?\\s*,\\s*(-?[\\d.]+)(%|px)?\\s*\\)/,\n );\n if (translateMatch) {\n const [, xVal, xUnit, yVal, yUnit] = translateMatch;\n if (xUnit === \"%\") parts.push(`xPercent: ${xVal}`);\n else parts.push(`x: ${xVal}`);\n if (yUnit === \"%\") parts.push(`yPercent: ${yVal}`);\n else parts.push(`y: ${yVal}`);\n }\n\n // translateX(-50%) or translateX(px)\n const txMatch = cssTransform.match(/translateX\\(\\s*(-?[\\d.]+)(%|px)?\\s*\\)/);\n if (txMatch) {\n const [, val, unit] = txMatch;\n parts.push(unit === \"%\" ? `xPercent: ${val}` : `x: ${val}`);\n }\n\n // translateY(-50%) or translateY(px)\n const tyMatch = cssTransform.match(/translateY\\(\\s*(-?[\\d.]+)(%|px)?\\s*\\)/);\n if (tyMatch) {\n const [, val, unit] = tyMatch;\n parts.push(unit === \"%\" ? `yPercent: ${val}` : `y: ${val}`);\n }\n\n // scale(N)\n const scaleMatch = cssTransform.match(/scale\\(\\s*([\\d.]+)\\s*\\)/);\n if (scaleMatch) {\n parts.push(`scale: ${scaleMatch[1]}`);\n }\n\n return parts.length > 0 ? parts.join(\", \") : null;\n}\n\n// ── CSS-transform ↔ GSAP-transform conflict matching ─────────────────────────\n\n// Transform components that COMBINE with a CSS translate/scale on the same\n// element. GSAP bakes the element's existing CSS transform in when it seeks, so\n// these stack rather than override in the capture path (e.g. CSS translateX(-50%)\n// + xPercent:-50 renders as -100% — off-centre). `rotation` is excluded: it maps\n// to CSS rotate(), which this rule treats separately (no false positive on spin).\nconst CONFLICTING_TRANSLATE_PROPS = [\"x\", \"y\", \"xPercent\", \"yPercent\"];\nconst CONFLICTING_SCALE_PROPS = [\"scale\", \"scaleX\", \"scaleY\"];\n\ntype GsapTransformCall = {\n method: string;\n selector: string;\n properties: string[];\n raw: string;\n};\n\n// Decompose a (possibly grouped / descendant / compound) GSAP target selector\n// into the simple `#id` / `.class` tokens of the elements it actually targets —\n// the RIGHTMOST compound of each comma group is the targeted element. This lets a\n// CSS rule keyed by a simple selector (`.m04-label`) match a scoped GSAP selector\n// (`\"#root .m04-label, #root .m04-sub\"`), which the prior exact-string lookup\n// missed — so every scoped/grouped selector slipped past the rule entirely.\nfunction targetedSelectorTokens(selector: string): Set<string> {\n const tokens = new Set<string>();\n for (const group of selector.split(\",\")) {\n const compounds = group\n .trim()\n .split(/[\\s>+~]+/)\n .filter(Boolean);\n const last = compounds[compounds.length - 1];\n if (!last) continue;\n const simple = last.match(/[#.][A-Za-z0-9_-]+/g);\n if (simple) for (const token of simple) tokens.add(token);\n }\n return tokens;\n}\n\n// Find a CSS transform conflicting with a GSAP target selector: exact-string\n// match first (fast path + back-compat with the original behaviour), then a\n// token match so scoped/grouped/descendant selectors resolve to their class/id.\nfunction matchCssTransform(gsapSelector: string, cssMap: Map<string, string>): string | undefined {\n if (cssMap.size === 0) return undefined;\n const direct = cssMap.get(gsapSelector);\n if (direct) return direct;\n const tokens = targetedSelectorTokens(gsapSelector);\n for (const [cssSelector, value] of cssMap) {\n if (tokens.has(cssSelector)) return value;\n }\n return undefined;\n}\n\n// Scan for STANDALONE `gsap.set/to/from/fromTo(\"selector\", { ...props })` calls.\n// The acorn timeline parser only captures calls rooted on the timeline var\n// (`tl.to`, `tl.set`, …); a top-level `gsap.set(\"#root .label\", { xPercent: -50 })`\n// — a common way to seat shared base transforms before the timeline runs — is\n// invisible to it, so the conflict rule never saw it. Variable selectors\n// (`gsap.set(kicker, …)`) can't be resolved statically and are skipped.\nfunction extractStandaloneGsapTransformCalls(script: string): GsapTransformCall[] {\n const calls: GsapTransformCall[] = [];\n const pattern = /gsap\\.(set|to|from|fromTo)\\s*\\(\\s*([\"'])([^\"']+)\\2\\s*,\\s*\\{([^{}]*)\\}/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(script)) !== null) {\n const method = match[1] ?? \"set\";\n const selector = match[3] ?? \"\";\n const propsBody = match[4] ?? \"\";\n const properties = [...propsBody.matchAll(/([A-Za-z_$][\\w$]*)\\s*:/g)].map((m) => m[1] ?? \"\");\n calls.push({ method, selector, properties, raw: truncateSnippet(match[0]) ?? match[0] });\n }\n return calls;\n}\n\n// Run a global regex over every script's content, yielding each match plus a\n// context-padded snippet around it. Shared by the repeat-count and\n// group-selector-keyframes rules below, which differ only in the pattern,\n// whether comments are stripped first, and the context window size.\nfunction scanScriptsForRegexMatches(\n scripts: LintContext[\"scripts\"],\n pattern: RegExp,\n options: { stripComments: boolean; contextBefore: number; contextAfter: number },\n): Array<{ match: RegExpExecArray; snippet: string }> {\n const hits: Array<{ match: RegExpExecArray; snippet: string }> = [];\n for (const script of scripts) {\n const content = options.stripComments ? stripJsComments(script.content) : script.content;\n const regex = new RegExp(pattern.source, pattern.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(content)) !== null) {\n const contextStart = Math.max(0, match.index - options.contextBefore);\n const contextEnd = Math.min(\n content.length,\n match.index + match[0].length + options.contextAfter,\n );\n hits.push({ match, snippet: content.slice(contextStart, contextEnd) });\n }\n }\n return hits;\n}\n\n// ── GSAP rules ─────────────────────────────────────────────────────────────\n\n// fallow-ignore-next-line complexity\nexport const gsapRules: LintRule<LintContext>[] = [\n // overlapping_gsap_tweens + gsap_animates_clip_element + unscoped_gsap_selector\n // fallow-ignore-next-line complexity\n async ({ source, tags, scripts, styles, rootCompositionId }) => {\n const findings: HyperframeLintFinding[] = [];\n\n // Build clip element selector map\n type ClipInfo = { tag: string; id: string; classes: string };\n const clipIds = new Map<string, ClipInfo>();\n const clipClasses = new Map<string, ClipInfo>();\n for (const tag of tags) {\n const clipTag = getClipTagClasses(tag);\n if (!clipTag) continue;\n const id = readAttr(tag.raw, \"id\");\n const info: ClipInfo = {\n tag: tag.name,\n id: id || \"\",\n classes: clipTag.classAttr,\n };\n if (id) clipIds.set(`#${id}`, info);\n for (const cls of clipTag.classes) {\n if (cls !== \"clip\") clipClasses.set(`.${cls}`, info);\n }\n }\n\n const classUsage = countClassUsage(tags);\n const clipStartBoundariesByComposition = collectClipStartBoundariesByComposition(source, tags);\n const styleRules = collectSimpleStyleRules(styles);\n const reportedVisibleOverlayKeys = new Set<string>();\n\n for (const script of scripts) {\n const localTimelineCompId = readRegisteredTimelineCompositionId(script.content);\n const gsapWindows = await cachedExtractGsapWindows(script.content);\n const clipStartBoundaries =\n clipStartBoundariesByComposition.get(localTimelineCompId || rootCompositionId || \"\") ?? [];\n\n // overlapping_gsap_tweens\n for (let i = 0; i < gsapWindows.length; i++) {\n const left = gsapWindows[i];\n if (!left) continue;\n if (left.end <= left.position) continue;\n // Unresolved targets are unknown elements: two of them are not provably\n // the same element, so an overlap between them cannot be asserted.\n if (left.targetSelector === UNRESOLVED_TARGET) continue;\n for (let j = i + 1; j < gsapWindows.length; j++) {\n const right = gsapWindows[j];\n if (!right) continue;\n if (right.end <= right.position) continue;\n if (left.targetSelector !== right.targetSelector) continue;\n const overlapStart = Math.max(left.position, right.position);\n const overlapEnd = Math.min(left.end, right.end);\n if (overlapEnd <= overlapStart) continue;\n if (left.overwriteAuto || right.overwriteAuto) continue;\n const sharedProperties = left.properties.filter((prop) =>\n right.properties.includes(prop),\n );\n if (sharedProperties.length === 0) continue;\n findings.push({\n code: \"overlapping_gsap_tweens\",\n severity: \"warning\",\n message: `GSAP tweens overlap on \"${left.targetSelector}\" for ${sharedProperties.join(\", \")} between ${overlapStart.toFixed(2)}s and ${overlapEnd.toFixed(2)}s.`,\n selector: left.targetSelector,\n fixHint: 'Shorten the earlier tween, move the later tween, or add `overwrite: \"auto\"`.',\n snippet: truncateSnippet(`${left.raw}\\n${right.raw}`),\n });\n }\n }\n\n // gsap_exit_missing_hard_kill\n if (clipStartBoundaries.length > 0) {\n for (const win of gsapWindows) {\n // Unresolved targets are unknown elements: you cannot assert a missing\n // hard kill on one, and a `tl.set(\"__unresolved__\", ...)` hint is meaningless.\n if (win.targetSelector === UNRESOLVED_TARGET) continue;\n if (!isSceneBoundaryExit(win)) continue;\n const boundary = findMatchingSceneBoundary(win.end, clipStartBoundaries);\n if (boundary == null) continue;\n const hasHardKill = gsapWindows.some((candidate) =>\n isHardKillSet(candidate, win.targetSelector, boundary),\n );\n if (hasHardKill) continue;\n\n // A tl.set hard kill on the exiting selector itself is the fix — unless\n // that selector IS a clip element, in which case gsap_animates_clip_element\n // (below) errors on that exact tl.set: the framework already owns\n // visibility/display on clip elements. Point at the inner-wrapper\n // pattern instead so the two rules' advice doesn't contradict.\n const exitClipInfo =\n clipIds.get(win.targetSelector) || clipClasses.get(win.targetSelector);\n const fixHint = exitClipInfo\n ? `\"${win.targetSelector}\" is a clip element — the framework already manages its visibility. ` +\n \"Wrap the scene's content in an inner non-clip <div>, move the exit tween and the hard kill \" +\n `(\\`tl.set(\"<inner-selector>\", ${hiddenStateLiteral(win.propertyValues)}, ${boundary.toFixed(2)})\\`) onto that wrapper instead.`\n : `Add \\`tl.set(\"${win.targetSelector}\", ${hiddenStateLiteral(win.propertyValues)}, ${boundary.toFixed(2)})\\` ` +\n \"after the exit tween.\";\n\n findings.push({\n code: \"gsap_exit_missing_hard_kill\",\n severity: \"error\",\n message:\n `GSAP exit on \"${win.targetSelector}\" ends at the ${boundary.toFixed(2)}s clip start boundary ` +\n \"without a matching tl.set hard kill. Non-linear seeking can land after the fade and leave stale visibility state.\",\n selector: win.targetSelector,\n fixHint,\n snippet: truncateSnippet(win.raw),\n });\n }\n }\n\n // gsap_fullscreen_overlay_starts_visible\n for (const tag of tags) {\n const selectors = tagSimpleSelectors(tag);\n if (selectors.length === 0) continue;\n const overlayKey = readAttr(tag.raw, \"id\") || String(tag.index);\n if (reportedVisibleOverlayKeys.has(overlayKey)) continue;\n const authoredStyle = combinedTagStyle(tag, styleRules);\n if (!authoredStyle || !styleLooksFullFrameOverlay(authoredStyle)) continue;\n if (styleHasHiddenInitialState(authoredStyle)) continue;\n\n const visibilityWindows = gsapWindows\n .filter((win) => {\n const tokens = targetedSelectorTokens(win.targetSelector);\n if (!selectors.some((selector) => tokens.has(selector))) return false;\n return win.properties.some((prop) =>\n [\"opacity\", \"autoAlpha\", \"visibility\", \"display\"].includes(prop),\n );\n })\n .sort((a, b) => a.position - b.position);\n const startsHiddenAtZero = visibilityWindows.some(\n (win) =>\n win.position <= SCENE_BOUNDARY_EPSILON_SECONDS && isHiddenGsapState(win.propertyValues),\n );\n if (startsHiddenAtZero) continue;\n const firstVisible = visibilityWindows.find((win) => makesOverlayVisible(win));\n if (!firstVisible) continue;\n const selector =\n selectors.find((candidate) =>\n targetedSelectorTokens(firstVisible.targetSelector).has(candidate),\n ) ||\n selectors[0] ||\n tag.name;\n const laterHidden = visibilityWindows.some(\n (win) => win.position >= firstVisible.position && isHiddenGsapState(win.propertyValues),\n );\n if (firstVisible.method !== \"from\" && !laterHidden) continue;\n\n reportedVisibleOverlayKeys.add(overlayKey);\n findings.push({\n code: \"gsap_fullscreen_overlay_starts_visible\",\n severity: \"error\",\n message:\n `Full-frame overlay \"${selector}\" starts visible before its first GSAP opacity tween at ` +\n `${firstVisible.position.toFixed(2)}s. It will cover earlier render frames, often as a blank/white video.`,\n selector,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n `Add \\`opacity: 0\\` to \"${selector}\" in CSS/inline styles, or add ` +\n `\\`tl.set(\"${selector}\", { opacity: 0 }, 0)\\` before the reveal tween.`,\n snippet: truncateSnippet(firstVisible.raw),\n });\n }\n\n // gsap_animates_clip_element — only error when GSAP animates visibility/display\n for (const win of gsapWindows) {\n const sel = win.targetSelector;\n const clipInfo = clipIds.get(sel) || clipClasses.get(sel);\n if (!clipInfo) continue;\n const conflictingProps = win.properties.filter(\n (p) => p === \"visibility\" || p === \"display\",\n );\n if (conflictingProps.length === 0) continue;\n const elDesc = `<${clipInfo.tag}${clipInfo.id ? ` id=\"${clipInfo.id}\"` : \"\"} class=\"${clipInfo.classes}\">`;\n findings.push({\n code: \"gsap_animates_clip_element\",\n severity: \"error\",\n message: `GSAP animation sets ${conflictingProps.join(\", \")} on a clip element. Selector \"${sel}\" resolves to element ${elDesc}. The framework manages clip visibility via ${conflictingProps.join(\"/\")} — do not animate these properties on clip elements.`,\n selector: sel,\n elementId: clipInfo.id || undefined,\n fixHint:\n \"Remove the visibility/display tween, or move the content into a child <div> and target that instead.\",\n snippet: truncateSnippet(win.raw),\n });\n }\n\n // unscoped_gsap_selector\n if (!localTimelineCompId || localTimelineCompId === rootCompositionId) continue;\n for (const win of gsapWindows) {\n if (!isSuspiciousGlobalSelector(win.targetSelector)) continue;\n const className = getSingleClassSelector(win.targetSelector);\n if (className && (classUsage.get(className) || 0) < 2) continue;\n findings.push({\n code: \"unscoped_gsap_selector\",\n severity: \"error\",\n message: `Timeline \"${localTimelineCompId}\" uses unscoped selector \"${win.targetSelector}\" that will target elements in ALL compositions when bundled, causing data loss (opacity, transforms, etc.).`,\n selector: win.targetSelector,\n fixHint: `Scope the selector: \\`[data-composition-id=\"${localTimelineCompId}\"] ${win.targetSelector}\\` or use a unique id.`,\n snippet: truncateSnippet(win.raw),\n });\n }\n }\n return findings;\n },\n\n // gsap_css_transform_conflict\n // fallow-ignore-next-line complexity\n async ({ styles, scripts, tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const cssTranslateSelectors = new Map<string, string>();\n const cssScaleSelectors = new Map<string, string>();\n\n // Check <style> blocks for transform rules\n for (const style of styles) {\n for (const [, selector, body] of style.content.matchAll(\n /([#.][a-zA-Z0-9_-]+)\\s*\\{([^}]+)\\}/g,\n )) {\n const tMatch = body?.match(/transform\\s*:\\s*([^;]+)/);\n if (!tMatch || !tMatch[1]) continue;\n const transformVal = tMatch[1].trim();\n if (/translate/i.test(transformVal))\n cssTranslateSelectors.set((selector ?? \"\").trim(), transformVal);\n if (/scale/i.test(transformVal))\n cssScaleSelectors.set((selector ?? \"\").trim(), transformVal);\n }\n }\n\n // Also check inline style=\"...\" attributes on tags\n for (const tag of tags) {\n const inlineStyle = readAttr(tag.raw, \"style\");\n if (!inlineStyle) continue;\n const tMatch = inlineStyle.match(/transform\\s*:\\s*([^;]+)/);\n if (!tMatch || !tMatch[1]) continue;\n const transformVal = tMatch[1].trim();\n // Derive selectors from the tag's id and all classes\n const id = readAttr(tag.raw, \"id\");\n const classes = readAttr(tag.raw, \"class\")?.split(/\\s+/).filter(Boolean) ?? [];\n const selectors: string[] = [];\n if (id) selectors.push(`#${id}`);\n for (const cls of classes) selectors.push(`.${cls}`);\n if (selectors.length === 0) continue;\n for (const sel of selectors) {\n if (/translate/i.test(transformVal) && !cssTranslateSelectors.has(sel))\n cssTranslateSelectors.set(sel, transformVal);\n if (/scale/i.test(transformVal) && !cssScaleSelectors.has(sel))\n cssScaleSelectors.set(sel, transformVal);\n }\n }\n\n if (cssTranslateSelectors.size === 0 && cssScaleSelectors.size === 0) return findings;\n\n for (const script of scripts) {\n if (!/gsap\\.timeline/.test(script.content)) continue;\n const windows = await cachedExtractGsapWindows(script.content);\n\n // Two sources of transform-setting calls: timeline-rooted tweens (from the\n // acorn parser) and standalone gsap.* calls (regex — the parser ignores\n // these). Normalize both into one shape and run the same conflict check.\n const calls: GsapTransformCall[] = [\n ...windows.map((win) => ({\n method: win.method,\n selector: win.targetSelector,\n properties: win.properties,\n raw: win.raw,\n })),\n ...extractStandaloneGsapTransformCalls(stripJsComments(script.content)),\n ];\n\n type Conflict = { cssTransform: string; props: Set<string>; raw: string };\n const conflicts = new Map<string, Conflict>();\n\n for (const call of calls) {\n // from() and fromTo() both supply explicit start values so GSAP owns\n // the full transform from t=0, making the CSS conflict moot\n if (call.method === \"fromTo\" || call.method === \"from\") continue;\n const sel = call.selector;\n const translateProps = call.properties.filter((p) =>\n CONFLICTING_TRANSLATE_PROPS.includes(p),\n );\n const scaleProps = call.properties.filter((p) => CONFLICTING_SCALE_PROPS.includes(p));\n const cssFromTranslate =\n translateProps.length > 0 ? matchCssTransform(sel, cssTranslateSelectors) : undefined;\n const cssFromScale =\n scaleProps.length > 0 ? matchCssTransform(sel, cssScaleSelectors) : undefined;\n if (!cssFromTranslate && !cssFromScale) continue;\n const existing = conflicts.get(sel) ?? {\n cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(\" \"),\n props: new Set<string>(),\n raw: call.raw,\n };\n for (const p of [...translateProps, ...scaleProps]) existing.props.add(p);\n conflicts.set(sel, existing);\n }\n\n for (const [sel, { cssTransform, props, raw }] of conflicts) {\n const propList = [...props].join(\"/\");\n const gsapEquivalent = cssTransformToGsapProps(cssTransform);\n const fixHint = gsapEquivalent\n ? `Remove \\`transform: ${cssTransform}\\` from CSS and replace with GSAP properties: ${gsapEquivalent}. ` +\n `Example: tl.fromTo('${sel}', { ${gsapEquivalent} }, { ${gsapEquivalent}, ...yourAnimation }). ` +\n `tl.fromTo is exempt from this rule.`\n : `Remove the transform from CSS and use tl.fromTo('${sel}', ` +\n `{ xPercent: -50, x: -1000 }, { xPercent: -50, x: 0 }) so GSAP owns ` +\n `the full transform state. tl.fromTo is exempt from this rule.`;\n findings.push({\n code: \"gsap_css_transform_conflict\",\n severity: \"error\",\n message:\n `\"${sel}\" has CSS \\`transform: ${cssTransform}\\` and a GSAP tween animates ` +\n `${propList}. GSAP will overwrite the full CSS transform, discarding any ` +\n `translateX(-50%) centering or CSS scale value.`,\n selector: sel,\n fixHint,\n snippet: truncateSnippet(raw),\n });\n }\n }\n return findings;\n },\n\n // missing_gsap_script\n ({ scripts, rawSource, options }) => {\n const allScriptTexts = scripts.filter((s) => !/\\bsrc\\s*=/.test(s.attrs)).map((s) => s.content);\n const allScriptSrcs = scripts\n .map((s) => readAttr(`<script ${s.attrs}>`, \"src\") || \"\")\n .filter(Boolean);\n const canInheritGsapFromHost =\n options.isSubComposition || rawSource.trimStart().toLowerCase().startsWith(\"<template\");\n\n const usesGsap = allScriptTexts.some((t) =>\n /gsap\\.(to|from|fromTo|timeline|set|registerPlugin)\\b/.test(t),\n );\n const hasGsapScript = allScriptSrcs.some((src) => /gsap/i.test(src));\n // Detect GSAP bundled inline (no src attribute). Match:\n // - Producer's CDN-inlining comment: /* inlined: ...gsap... */\n // - GSAP library internals: _gsScope, GreenSock, gsap.config\n // - Large inline scripts (>5KB) that reference gsap (likely bundled library)\n const hasInlineGsap = allScriptTexts.some(\n (t) =>\n /\\/\\*\\s*inlined:.*gsap/i.test(t) ||\n /\\b_gsScope\\b/.test(t) ||\n /\\bGreenSock\\b/.test(t) ||\n /\\bgsap\\.(config|defaults|version)\\b/.test(t) ||\n (t.length > 5000 && /\\bgsap\\b/i.test(t)),\n );\n\n if (!usesGsap || hasGsapScript || hasInlineGsap || canInheritGsapFromHost) return [];\n return [\n {\n code: \"missing_gsap_script\",\n severity: \"error\",\n message: \"Composition uses GSAP but no GSAP script is loaded. The animation will not run.\",\n fixHint:\n 'Add <script src=\"https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js\"></script> before your animation script.',\n },\n ];\n },\n\n // audio_reactive_single_tween_per_group\n // fallow-ignore-next-line complexity\n ({ scripts, styles }) => {\n const findings: HyperframeLintFinding[] = [];\n if (!hasCaptionStyles(styles)) return findings;\n\n for (const script of scripts) {\n const content = script.content;\n // Detect audio data loading\n const hasAudioData = /AUDIO|audio[-_]?data|bands\\[/.test(content);\n if (!hasAudioData) continue;\n\n // Detect caption group loop\n const hasCaptionLoop = /forEach/.test(content) && /caption|group|cg-/.test(content);\n if (!hasCaptionLoop) continue;\n\n // Check if audio-reactive tweens are created at intervals (loop inside the group loop)\n // vs a single tween per group (no inner time-sampling loop)\n const hasInnerSamplingLoop =\n /for\\s*\\(\\s*var\\s+\\w+\\s*=\\s*group\\.start/.test(content) ||\n /for\\s*\\(\\s*var\\s+at\\s*=/.test(content) ||\n /while\\s*\\(\\s*\\w+\\s*<\\s*group\\.end/.test(content);\n\n if (!hasInnerSamplingLoop) {\n // Check if there's at least a peak-based single tween (the minimal pattern)\n const hasPeakTween =\n /peak(?:Bass|Treble|Energy)/.test(content) && /group\\.start/.test(content);\n if (hasPeakTween) {\n findings.push({\n code: \"audio_reactive_single_tween_per_group\",\n severity: \"warning\",\n message:\n \"Audio-reactive captions use a single tween per group based on peak values. \" +\n \"This sets one static value at group.start — not perceptible as audio reactivity.\",\n fixHint:\n \"Sample audio data at 100-200ms intervals throughout each group's lifetime \" +\n \"(for loop from group.start to group.end) and create a tween at each sample \" +\n \"point for visible pulsing.\",\n });\n }\n }\n }\n return findings;\n },\n\n // gsap_infinite_repeat\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n // Match repeat: -1 in GSAP tweens or timeline configs\n const pattern = /repeat\\s*:\\s*-1(?!\\d)/g;\n for (const { snippet } of scanScriptsForRegexMatches(scripts, pattern, {\n stripComments: true,\n contextBefore: 60,\n contextAfter: 60,\n })) {\n findings.push({\n code: \"gsap_infinite_repeat\",\n severity: \"error\",\n message:\n \"GSAP tween uses `repeat: -1` (infinite). Infinite repeats break the deterministic \" +\n \"capture engine which seeks to exact frame times. Use a finite repeat count calculated \" +\n \"from the composition duration: `repeat: Math.floor(duration / cycleDuration) - 1`.\",\n fixHint:\n \"Replace `repeat: -1` with a finite count, e.g. `repeat: Math.floor(totalDuration / singleCycleDuration) - 1`. \" +\n \"Use Math.floor (not Math.ceil) to ensure the animation fits within the total duration.\",\n snippet: truncateSnippet(snippet),\n });\n }\n return findings;\n },\n\n // gsap_repeat_ceil_overshoot\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n // Match patterns like: repeat: Math.ceil(duration / X) - 1\n // or repeat: Math.ceil(totalDuration / cycleDuration) - 1\n const pattern = /repeat\\s*:\\s*Math\\.ceil\\s*\\([^)]+\\)\\s*-\\s*1/g;\n for (const { snippet } of scanScriptsForRegexMatches(scripts, pattern, {\n stripComments: false,\n contextBefore: 40,\n contextAfter: 40,\n })) {\n findings.push({\n code: \"gsap_repeat_ceil_overshoot\",\n severity: \"warning\",\n message:\n \"GSAP repeat calculation uses `Math.ceil` which can overshoot the composition duration. \" +\n \"For example, Math.ceil(10.5 / 2) - 1 = 5 repeats → 6 cycles × 2s = 12s, exceeding 10.5s.\",\n fixHint:\n \"Use `Math.floor` instead of `Math.ceil` to ensure the animation fits within the duration: \" +\n \"`repeat: Math.floor(totalDuration / cycleDuration) - 1`. \" +\n \"Math.floor(10.5 / 2) - 1 = 4 repeats → 5 cycles × 2s = 10s ✓\",\n snippet: truncateSnippet(snippet),\n });\n }\n return findings;\n },\n\n // scene_layer_missing_visibility_kill\n ({ scripts, tags }) => {\n const findings: HyperframeLintFinding[] = [];\n\n // Detect multi-scene compositions: multiple elements with \"scene\" in their id\n const sceneElements = tags.filter((t) => {\n const id = readAttr(t.raw, \"id\") || \"\";\n return /^scene\\d+$/i.test(id);\n });\n if (sceneElements.length < 2) return findings;\n\n for (const script of scripts) {\n const content = stripJsComments(script.content);\n // For each scene, check if there's a visibility:hidden set after exit tweens\n for (const tag of sceneElements) {\n const id = readAttr(tag.raw, \"id\") || \"\";\n // Check if this scene has exit tweens (opacity: 0)\n const exitPattern = new RegExp(`[\"']#${id}[\"'][^)]*opacity\\\\s*:\\\\s*0`);\n const hasExit = exitPattern.test(content);\n if (!hasExit) continue;\n\n // Check if there's a hard visibility kill\n const killPattern = new RegExp(`[\"']#${id}[\"'][^)]*visibility\\\\s*:\\\\s*[\"']hidden[\"']`);\n const hasKill = killPattern.test(content);\n if (!hasKill) {\n // A tl.set on \"#id\" is only safe advice when the scene element isn't\n // itself a clip — otherwise gsap_animates_clip_element errors on that\n // exact tl.set, since the framework already owns visibility/display on\n // clip elements. Point at the inner-wrapper pattern instead.\n const classes = (readAttr(tag.raw, \"class\") || \"\").split(/\\s+/).filter(Boolean);\n const isClip = classes.includes(\"clip\");\n const fixHint = isClip\n ? `\"#${id}\" is a clip element — the framework already manages its visibility. ` +\n \"Wrap the scene's content in an inner non-clip <div>, move the exit tween and the hard kill \" +\n '(`tl.set(\"<inner-selector>\", { visibility: \"hidden\" }, <exit-end-time>)`) onto that wrapper instead.'\n : `Add \\`tl.set(\"#${id}\", { visibility: \"hidden\" }, <exit-end-time>)\\` after the scene's exit tweens.`;\n\n findings.push({\n code: \"scene_layer_missing_visibility_kill\",\n severity: \"error\",\n elementId: id,\n message:\n `Scene layer \"#${id}\" exits via opacity tween but has no visibility: hidden hard kill. ` +\n \"When scrubbing or when tweens conflict, the scene may remain partially visible and overlap the next scene.\",\n fixHint,\n });\n }\n }\n }\n return findings;\n },\n\n // gsap_timeline_not_registered\n ({ scripts, rawSource, options }) => {\n const findings: HyperframeLintFinding[] = [];\n const canInheritFromHost =\n options.isSubComposition || rawSource.trimStart().toLowerCase().startsWith(\"<template\");\n\n for (const script of scripts) {\n const content = script.content;\n if (!/gsap\\.timeline/.test(content)) continue;\n const hasRegistration =\n WINDOW_TIMELINE_ASSIGN_PATTERN.test(content) ||\n TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN.test(content);\n if (hasRegistration || canInheritFromHost) continue;\n findings.push({\n code: \"gsap_timeline_not_registered\",\n severity: \"error\",\n message:\n \"GSAP timeline is created but never registered in window.__timelines. \" +\n \"The runtime discovers timelines from this registry — without registration, \" +\n \"animations will not play during preview or render.\",\n fixHint:\n \"Add `window.__timelines = window.__timelines || {};` and \" +\n '`window.__timelines[\"root\"] = tl;` after creating the timeline (use the ' +\n \"composition's data-composition-id as the key).\",\n });\n }\n return findings;\n },\n\n // gsap_timeline_registered_before_async_build — registering window.__timelines[id]\n // BEFORE the timeline is built inside document.fonts.ready (or any async callback)\n // leaves an EMPTY timeline registered. The runtime's sub-composition readiness gate\n // treats \"key present\" as \"ready\" and nests the child ONCE, while still empty — so the\n // animation never renders when this composition is mounted as a sub-composition.\n // Register only AFTER the build completes (the documented async-setup contract).\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const script of scripts) {\n const content = stripJsComments(script.content);\n const regIdx = content.search(/window\\s*\\.\\s*__timelines\\s*\\[/);\n if (regIdx < 0) continue;\n const fontsReadyIdx = content.search(/document\\s*\\.\\s*fonts\\s*\\.\\s*ready/);\n if (fontsReadyIdx < 0) continue;\n // Registering after the async boundary is the correct pattern — skip it.\n if (regIdx >= fontsReadyIdx) continue;\n // Confirm the build is actually deferred past the boundary (a tween/build call\n // appears after document.fonts.ready), i.e. the registered timeline starts empty.\n const tail = content.slice(fontsReadyIdx);\n if (!/\\.(?:to|from|fromTo)\\s*\\(|buildEffect\\s*\\(/.test(tail)) continue;\n findings.push({\n code: \"gsap_timeline_registered_before_async_build\",\n severity: \"error\",\n message:\n \"window.__timelines is assigned BEFORE the timeline is built inside \" +\n \"document.fonts.ready. An empty timeline registered early gets nested empty \" +\n \"when this composition is used as a sub-composition (the readiness gate treats \" +\n '\"key present\" as \"ready\" and never re-nests), so the animation renders blank.',\n fixHint:\n \"Move the `window.__timelines[id] = tl;` assignment to the END of the \" +\n \"document.fonts.ready callback, after the tweens are added. Optionally call \" +\n \"window.__hfForceTimelineRebind() right after, to re-nest the populated timeline.\",\n });\n }\n return findings;\n },\n\n // gsap_from_opacity_noop — CSS opacity:0 + gsap.from({opacity:0}) = invisible forever\n // fallow-ignore-next-line complexity\n async ({ styles, scripts, tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const cssOpacityZeroSelectors = new Set<string>();\n\n for (const style of styles) {\n for (const [, selector, body] of style.content.matchAll(\n /([#.][a-zA-Z0-9_-]+)\\s*\\{([^}]+)\\}/g,\n )) {\n if (body && /opacity\\s*:\\s*0\\s*[;}]/.test(body)) {\n cssOpacityZeroSelectors.add((selector ?? \"\").trim());\n }\n }\n }\n\n for (const tag of tags) {\n const inlineStyle = readAttr(tag.raw, \"style\");\n if (!inlineStyle || !/opacity\\s*:\\s*0/.test(inlineStyle)) continue;\n const id = readAttr(tag.raw, \"id\");\n const classes = readAttr(tag.raw, \"class\")?.split(/\\s+/).filter(Boolean) ?? [];\n if (id) cssOpacityZeroSelectors.add(`#${id}`);\n for (const cls of classes) cssOpacityZeroSelectors.add(`.${cls}`);\n }\n\n if (cssOpacityZeroSelectors.size === 0) return findings;\n\n for (const script of scripts) {\n if (!/gsap\\.timeline/.test(script.content)) continue;\n const windows = await cachedExtractGsapWindows(script.content);\n\n for (const win of windows) {\n if (win.method !== \"from\") continue;\n if (!win.properties.includes(\"opacity\")) continue;\n // Only a noop when the tween animates FROM 0 (same as the CSS value)\n if (win.propertyValues[\"opacity\"] !== 0) continue;\n const sel = win.targetSelector;\n const cssKey = sel.startsWith(\"#\") || sel.startsWith(\".\") ? sel : `#${sel}`;\n if (!cssOpacityZeroSelectors.has(cssKey)) continue;\n\n findings.push({\n code: \"gsap_from_opacity_noop\",\n severity: \"error\",\n message:\n `\"${sel}\" has CSS \\`opacity: 0\\` and a gsap.${win.method}() that also sets opacity to 0. ` +\n `gsap.from() animates FROM the specified value TO the current CSS value — ` +\n `since CSS is already 0, the element animates from 0→0 and never becomes visible.`,\n selector: sel,\n fixHint:\n `Remove \\`opacity: 0\\` from the CSS/inline style on \"${sel}\". ` +\n `Let gsap.from({opacity: 0}) handle the initial hidden state — ` +\n `it will animate FROM 0 TO the CSS value (1 by default).`,\n snippet: truncateSnippet(win.raw),\n });\n }\n }\n return findings;\n },\n\n // gsap_non_transform_motion — animating layout props (left/top/right/bottom/margin*)\n // or using roundProps snaps motion to integer device pixels. On the seek-by-frame\n // capture engine this looks smooth at high per-frame deltas (fast tweens) but visibly\n // stutters at low deltas (slow tweens / ease-out tails): sub-pixel movement rounds to\n // the same pixel for several frames, then jumps a whole pixel. Transforms (x/y/scale)\n // interpolate sub-pixel and stay smooth.\n //\n // EXEMPTION: elements rasterized via the html-in-canvas API — those under a\n // `<canvas layoutsubtree>` ancestor (e.g. the liquid-glass blocks) — are NOT laid out\n // by the browser compositor. The canvas lib reads getComputedStyle().left/top (a\n // sub-pixel value) and draws the element to a bitmap, so animating a layout prop on\n // them does not integer-snap and does not stutter. We resolve each tween's target to\n // its element(s) and skip the finding only when EVERY target is html-in-canvas; a\n // grouped tween that also touches a plain-DOM element (which does stutter) still fires.\n //\n // No suppression by design: there is intentionally no per-line/per-file opt-out (unlike\n // eslint-disable). The stance is fix-the-motion, not silence-the-rule — a plain-DOM\n // layout-prop animation always has a faithful transform equivalent (per-glyph x for\n // spacing, scale for size, x/y for position). An author who has consciously accepted a\n // stutter still has no flag to flip; that is deliberate, not a missing feature.\n async ({ scripts, tags, source }) => {\n const findings: HyperframeLintFinding[] = [];\n\n // Byte-ranges of every <canvas layoutsubtree>. An element whose open-tag index falls\n // inside one of these ranges is html-in-canvas composited.\n const layoutSubtreeRanges = tags\n .filter((t) => t.name.toLowerCase() === \"canvas\" && /\\blayoutsubtree\\b/i.test(t.raw))\n .map((t) => ({ start: t.index, end: findTagEnd(source, t) }));\n const isHtmlInCanvas = (tag: OpenTag): boolean =>\n layoutSubtreeRanges.some((r) => tag.index > r.start && tag.index < r.end);\n\n // Resolve a simple #id / .class token to the element tag(s) it matches.\n const tagsByToken = new Map<string, OpenTag[]>();\n const addToken = (token: string, tag: OpenTag): void => {\n const list = tagsByToken.get(token);\n if (list) list.push(tag);\n else tagsByToken.set(token, [tag]);\n };\n for (const tag of tags) {\n const id = readAttr(tag.raw, \"id\");\n if (id) addToken(`#${id}`, tag);\n for (const cls of readAttr(tag.raw, \"class\")?.split(/\\s+/).filter(Boolean) ?? [])\n addToken(`.${cls}`, tag);\n }\n\n // True only when the selector resolves to at least one element AND every resolved\n // element is html-in-canvas. Unresolvable selectors (no match) are NOT exempt — we\n // stay conservative and let the finding fire rather than risk a false negative.\n const allTargetsHtmlInCanvas = (selector: string): boolean => {\n if (layoutSubtreeRanges.length === 0) return false;\n const matched = [...targetedSelectorTokens(selector)].flatMap(\n (token) => tagsByToken.get(token) ?? [],\n );\n return matched.length > 0 && matched.every(isHtmlInCanvas);\n };\n // Positional layout props → each maps to its transform replacement axis (x/y).\n const LAYOUT_FIX: Record<string, string[]> = {\n left: [\"x\"],\n right: [\"x\"],\n top: [\"y\"],\n bottom: [\"y\"],\n margin: [\"x\", \"y\"],\n marginLeft: [\"x\"],\n marginRight: [\"x\"],\n marginTop: [\"y\"],\n marginBottom: [\"y\"],\n };\n // Text-reflow props: animating them reflows text and snaps glyph positions to the\n // pixel grid, stuttering on slow motion exactly like positional props. They have no\n // transform replacement (the fix is to not animate them — settle via scale or hold the\n // value), and the snap happens during browser layout, UPSTREAM of any canvas raster, so\n // they are never html-in-canvas-exempt. (width/height are deliberately omitted: they\n // have legitimate animated uses — progress bars, reveals — and would over-report.)\n const REFLOW_PROPS = [\"letterSpacing\", \"wordSpacing\", \"fontSize\"];\n // Resolve the parser once, above the loop (the other async rules in this file do the\n // same); the dynamic-import cache makes per-iteration calls equivalent, but hoisting\n // keeps the placement from reading as load-bearing.\n const parseGsapScript = await loadParseGsapScript();\n for (const script of scripts) {\n if (!/gsap\\.timeline/.test(script.content)) continue;\n\n // Two sources: timeline-rooted tweens (tl.to/from/fromTo) and standalone\n // gsap.to/from/fromTo calls the acorn parser ignores.\n //\n // Timeline tweens come straight from the acorn parser's animation list — NOT\n // cachedExtractGsapWindows, which drops every tween with a non-numeric timeline\n // position (a string label or `+=`/`-=` offset, e.g. `tl.to(\"#x\",{left:9},\"hold6\")`).\n // Position is irrelevant to whether a tween animates a layout prop, so dropping\n // those would let real stutter-prone tweens escape. The parser also gives real AST\n // keys, so a nested `{}` value (an onComplete body, modifiers) and a layout-prop\n // name appearing inside a string value can't be misread — both hazards of a raw scan.\n const parsed = parseGsapScript(script.content);\n const calls: GsapTransformCall[] = [\n ...parsed.animations.map((anim) => ({\n method: anim.method,\n selector: anim.targetSelector,\n // Union the from-vars: a fromTo() can animate a layout/reflow prop that appears\n // only in its first (\"from\") object, which is just as stutter-prone as the to-vars.\n properties: [\n ...new Set([\n ...Object.keys(anim.properties),\n ...Object.keys(anim.fromProperties ?? {}),\n ]),\n ],\n raw: synthesizeWindowRaw(parsed.timelineVar, anim),\n })),\n ...extractStandaloneGsapTransformCalls(stripJsComments(script.content)),\n ];\n\n for (const call of calls) {\n // set() is instantaneous — it never animates, so it cannot stutter. A set() that\n // seats an integer-snapped layout position (e.g. tl.set(\"#x\",{left:100})) before a\n // later transform tween is a single from-state frame, not motion; intentionally skipped.\n if (call.method === \"set\") continue;\n // Object.hasOwn, not `in`: a tween property named `toString`/`constructor` would\n // match the prototype chain and resolve LAYOUT_FIX[p] to an inherited function.\n let layoutProps = call.properties.filter((p) => Object.hasOwn(LAYOUT_FIX, p));\n const reflowProps = call.properties.filter((p) => REFLOW_PROPS.includes(p));\n const usesRoundProps = call.properties.includes(\"roundProps\");\n // Only positional props are html-in-canvas-exempt: the canvas positions the draw\n // from sub-pixel computed left/top. Reflow props (glyph layout) and roundProps\n // (value rounding) snap upstream of the raster, so they always fire.\n if (layoutProps.length > 0 && allTargetsHtmlInCanvas(call.selector)) layoutProps = [];\n if (layoutProps.length === 0 && reflowProps.length === 0 && !usesRoundProps) continue;\n\n const flagged = [...layoutProps, ...reflowProps, ...(usesRoundProps ? [\"roundProps\"] : [])];\n const message =\n `GSAP tween on \"${call.selector}\" uses motion that snaps to integer device pixels: ` +\n `${flagged.join(\", \")}. Layout and text-reflow properties snap during browser layout; ` +\n \"roundProps rounds the tween value. Slow motion or an ease-out tail then stutters under \" +\n \"the seek-by-frame capture engine — animate transforms (x/y/scale/opacity) instead.\";\n\n const fixes: string[] = [];\n if (layoutProps.length > 0) {\n const tokens = [...new Set(layoutProps.flatMap((p) => LAYOUT_FIX[p] ?? []))];\n fixes.push(\n `replace ${layoutProps.join(\"/\")} with the transform equivalent (${tokens.join(\", \")}) — ` +\n `e.g. tl.fromTo(\"${call.selector}\", { x: -1300 }, { x: 0, ...yourAnimation })`,\n );\n }\n if (reflowProps.length > 0) {\n // Faithful fix differs by property: fontSize maps to scale (same visual), but\n // letterSpacing/wordSpacing do NOT — uniform scale resizes glyphs, it does not\n // change the gaps between them. The smooth equivalent of a spacing tween is a\n // per-glyph split with an x transform per character.\n const sizing = reflowProps.filter((p) => p === \"fontSize\");\n const spacing = reflowProps.filter((p) => p !== \"fontSize\");\n const parts: string[] = [];\n if (sizing.length > 0) {\n parts.push(`replace ${sizing.join(\"/\")} with scale (same visual, no reflow)`);\n }\n if (spacing.length > 0) {\n parts.push(\n `for ${spacing.join(\"/\")}, split the text into per-character elements and animate ` +\n \"each glyph's x (the spread) — uniform scale is NOT equivalent — or hold the final value statically\",\n );\n }\n fixes.push(\n `do not animate ${reflowProps.join(\"/\")} (they reflow text and snap glyph positions): ` +\n parts.join(\"; \"),\n );\n }\n if (usesRoundProps) fixes.push(\"remove roundProps\");\n const fixHint = `${fixes.join(\"; \")}. Transforms interpolate sub-pixel and stay smooth at any speed.`;\n\n findings.push({\n code: \"gsap_non_transform_motion\",\n severity: \"error\",\n message,\n selector: call.selector,\n fixHint,\n snippet: truncateSnippet(call.raw),\n });\n }\n }\n return findings;\n },\n\n // gsap_group_selector_keyframes\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n const pattern = /\\.(?:to|from|fromTo)\\(\\s*[\"']([^\"']+,\\s*[^\"']+)[\"']\\s*,\\s*\\{[^}]*keyframes/g;\n for (const { match, snippet } of scanScriptsForRegexMatches(scripts, pattern, {\n stripComments: true,\n contextBefore: 20,\n contextAfter: 40,\n })) {\n const selector = match[1]!;\n const count = selector.split(\",\").length;\n findings.push({\n code: \"gsap_group_selector_keyframes\",\n severity: \"warning\",\n message:\n `GSAP tween targets ${count} elements with shared keyframes (\"${truncateSnippet(selector, 60)}\"). ` +\n `Editing one element's keyframes in Studio will affect all ${count} elements. ` +\n `Split into individual tweens for per-element keyframe control.`,\n fixHint:\n `Replace the group selector with individual tl.to() calls per element, ` +\n `each with their own keyframes object.`,\n snippet: truncateSnippet(snippet),\n });\n }\n return findings;\n },\n];\n","import type { LintContext, HyperframeLintFinding } from \"../context\";\n\n/** Extract a bracket-balanced array literal starting at the `[` found by `varMatch`. */\n// fallow-ignore-next-line complexity\nfunction extractArrayLiteral(src: string, varMatch: RegExpExecArray): string | null {\n const openIdx = varMatch.index + varMatch[0].length - 1;\n let depth = 0;\n let inStr = false;\n let strChar = \"\";\n for (let i = openIdx; i < src.length; i++) {\n const c = src[i]!;\n if (inStr) {\n if (c === \"\\\\\") {\n i++;\n continue;\n }\n if (c === strChar) inStr = false;\n } else if (c === '\"' || c === \"'\") {\n inStr = true;\n strChar = c;\n } else if (c === \"[\") {\n depth++;\n } else if (c === \"]\") {\n depth--;\n if (depth === 0) return src.slice(openIdx, i + 1);\n }\n }\n return null;\n}\n\nexport const captionRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // caption_exit_missing_hard_kill\n ({ scripts, styles, options, rootCompositionId }) => {\n const findings: HyperframeLintFinding[] = [];\n // Only the ACTUAL captions composition. A content frame that merely mentions\n // \"karaoke\" / \"caption-*\" in a comment (or uses an unrelated forEach + opacity:0\n // screen-swap) is NOT captions — gating here prevents the false positive that fired\n // on a content frame whose only caption signal was a descriptive comment.\n const isCaptionComposition =\n Boolean(options.filePath && /caption/i.test(options.filePath)) ||\n rootCompositionId === \"captions\" ||\n styles.some((s) => /\\.caption[-_]?(?:group|word|line|block)\\b|\\.cg-/.test(s.content));\n if (!isCaptionComposition) return findings;\n for (const script of scripts) {\n const content = script.content;\n const hasExitTween = /\\.to\\s*\\([^,]+,\\s*\\{[^}]*opacity\\s*:\\s*0/.test(content);\n const hasHardKill =\n /\\.set\\s*\\([^,]+,\\s*\\{[^}]*(?:visibility\\s*:\\s*[\"']hidden[\"']|opacity\\s*:\\s*0)/.test(\n content,\n );\n const hasCaptionLoop =\n /forEach|\\.forEach\\s*\\(/.test(content) &&\n /karaoke|caption[-_]?(?:group|word|line|block)|cg-/.test(content);\n if (hasCaptionLoop && hasExitTween && !hasHardKill) {\n findings.push({\n code: \"caption_exit_missing_hard_kill\",\n severity: \"error\",\n message:\n \"Caption exit animations (tl.to with opacity: 0) detected without a hard tl.set kill. \" +\n \"Exit tweens can fail when karaoke word-level tweens conflict, leaving captions stuck on screen.\",\n fixHint:\n 'Add `tl.set(groupEl, { opacity: 0, visibility: \"hidden\" }, group.end)` after every ' +\n \"exit tl.to animation as a deterministic kill.\",\n });\n }\n }\n return findings;\n },\n\n // caption_text_overflow_risk\n ({ styles }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const style of styles) {\n const captionBlocks = style.content.matchAll(\n /(\\.caption[-_]?(?:group|container|text|line|word)|#caption[-_]?container)\\s*\\{([^}]+)\\}/gi,\n );\n for (const [, selector, body] of captionBlocks) {\n if (!body) continue;\n const hasNowrap = /white-space\\s*:\\s*nowrap/i.test(body);\n const hasMaxWidth = /max-width/i.test(body);\n if (hasNowrap && !hasMaxWidth) {\n findings.push({\n code: \"caption_text_overflow_risk\",\n severity: \"warning\",\n selector: (selector ?? \"\").trim(),\n message: `Caption selector \"${(selector ?? \"\").trim()}\" has white-space: nowrap but no max-width. Long phrases will clip off-screen.`,\n fixHint:\n \"Add max-width: 1600px (landscape) or max-width: 900px (portrait) and overflow: hidden.\",\n });\n }\n }\n }\n return findings;\n },\n\n // caption_transcript_not_inline\n // fallow-ignore-next-line complexity\n ({ scripts, styles, options }) => {\n const findings: HyperframeLintFinding[] = [];\n // Only check files that look like caption compositions\n const isCaptionFile =\n (options.filePath && /caption/i.test(options.filePath)) ||\n styles.some((s) => /\\.caption[-_]?(?:group|word)/i.test(s.content));\n if (!isCaptionFile) return findings;\n\n const allScript = scripts.map((s) => s.content).join(\"\\n\");\n const hasInlineTranscript = /(?:const|let|var)\\s+(?:TRANSCRIPT|script)\\s*=\\s*\\[/.test(\n allScript,\n );\n const hasFetchTranscript = /fetch\\s*\\(\\s*[\"'][^\"']*transcript/i.test(allScript);\n\n if (!hasInlineTranscript && hasFetchTranscript) {\n findings.push({\n code: \"caption_transcript_not_inline\",\n severity: \"error\",\n message:\n \"Captions composition loads transcript via fetch(). The studio caption editor \" +\n \"requires an inline `var TRANSCRIPT = [...]` array to detect and edit captions.\",\n fixHint:\n 'Embed the transcript as `var TRANSCRIPT = [{ \"text\": \"...\", \"start\": 0, \"end\": 1 }, ...]` ' +\n \"with JSON-quoted property keys. See the captions skill for details.\",\n });\n }\n\n if (hasInlineTranscript) {\n // Verify the inline transcript can be parsed.\n // Use a balanced-bracket scan instead of a regex to correctly handle\n // nested arrays (e.g. word-level timing arrays inside each entry).\n const varStart = /(?:const|let|var)\\s+(?:TRANSCRIPT|script)\\s*=\\s*\\[/.exec(allScript);\n const transcriptJson = varStart ? extractArrayLiteral(allScript, varStart) : null;\n if (transcriptJson) {\n try {\n JSON.parse(transcriptJson);\n } catch {\n findings.push({\n code: \"caption_transcript_parse_error\",\n severity: \"error\",\n message:\n \"Inline TRANSCRIPT array is not valid JSON. The studio caption editor may fail \" +\n \"to parse it. Common cause: unquoted property keys with apostrophes in text.\",\n fixHint:\n 'Use JSON-quoted keys: { \"text\": \"don\\'t\", \"start\": 0, \"end\": 1 } instead of ' +\n '{ text: \"don\\'t\", start: 0, end: 1 }.',\n });\n }\n }\n }\n\n return findings;\n },\n\n // caption_container_relative_position\n ({ styles }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const style of styles) {\n const captionBlocks = style.content.matchAll(\n /(\\.caption[-_]?(?:group|container|text|line)|#caption[-_]?container)\\s*\\{([^}]+)\\}/gi,\n );\n for (const [, selector, body] of captionBlocks) {\n if (!body) continue;\n if (/position\\s*:\\s*relative/i.test(body)) {\n findings.push({\n code: \"caption_container_relative_position\",\n severity: \"error\",\n selector: (selector ?? \"\").trim(),\n message: `Caption selector \"${(selector ?? \"\").trim()}\" uses position: relative which causes overflow and breaks caption stacking.`,\n fixHint: \"Use position: absolute for all caption elements.\",\n });\n }\n }\n }\n return findings;\n },\n\n // caption_overflow_clips_scaled_words\n ({ styles, scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n const hasScaledWords = scripts.some(\n (s) => /scale\\s*:\\s*1\\.[2-9]/.test(s.content) && /caption|word|cg-/.test(s.content),\n );\n if (!hasScaledWords) return findings;\n\n for (const style of styles) {\n const captionBlocks = style.content.matchAll(\n /(\\.caption[-_]?(?:group|container)|#caption[-_]?(?:layer|container))\\s*\\{([^}]+)\\}/gi,\n );\n for (const [, selector, body] of captionBlocks) {\n if (!body) continue;\n if (/overflow\\s*:\\s*hidden/i.test(body)) {\n findings.push({\n code: \"caption_overflow_clips_scaled_words\",\n severity: \"error\",\n selector: (selector ?? \"\").trim(),\n message: `\"${(selector ?? \"\").trim()}\" has overflow: hidden but GSAP scales caption words above 1.0x. Scaled emphasis words and their glow effects will be clipped.`,\n fixHint:\n \"Use overflow: visible on caption containers. Rely on fitTextFontSize with reduced maxWidth to prevent overflow instead.\",\n });\n }\n }\n }\n return findings;\n },\n\n // caption_textshadow_on_group_container\n ({ scripts, styles }) => {\n const findings: HyperframeLintFinding[] = [];\n const isCaptionFile = styles.some((s) => /\\.caption[-_]?(?:group|word)/i.test(s.content));\n if (!isCaptionFile) return findings;\n\n for (const script of scripts) {\n // Detect textShadow tweened on a group container (div with child word spans)\n const groupShadowPattern =\n /\\.to\\s*\\(\\s*(?:div|groupEl|el|captionEl|document\\.getElementById\\s*\\(\\s*[\"']cg-)\\s*[^,]*,\\s*\\{[^}]*textShadow/g;\n // Also catch selector-based targeting of group containers\n const selectorShadowPattern =\n /\\.to\\s*\\(\\s*[\"'](?:#cg-\\d+|\\.caption[-_]?group)[\"']\\s*,\\s*\\{[^}]*textShadow/g;\n if (groupShadowPattern.test(script.content) || selectorShadowPattern.test(script.content)) {\n findings.push({\n code: \"caption_textshadow_on_group_container\",\n severity: \"warning\",\n message:\n \"textShadow is tweened on a caption group container. When children have semi-transparent \" +\n \"color (e.g., inactive karaoke words at rgba opacity), the glow renders as a visible \" +\n \"rectangle behind the entire group.\",\n fixHint:\n \"Apply textShadow to individual active word elements instead of the group container. \" +\n \"Use scale on the group for bass-reactive pulsing.\",\n });\n }\n }\n return findings;\n },\n\n // caption_fittext_scale_mismatch\n // fallow-ignore-next-line complexity\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const script of scripts) {\n const content = script.content;\n const fitTextMatch = content.match(/fitTextFontSize\\s*\\([^)]*maxWidth\\s*:\\s*(\\d+)/);\n if (!fitTextMatch) continue;\n const maxWidth = parseInt(fitTextMatch[1] ?? \"0\", 10);\n if (!maxWidth) continue;\n\n // Find max scale on caption words\n const scaleMatches = [...content.matchAll(/scale\\s*:\\s*(1\\.\\d+)/g)];\n const captionContext = /caption|word|cg-|karaoke/i.test(content);\n if (!captionContext || scaleMatches.length === 0) continue;\n\n let maxScale = 1;\n for (const m of scaleMatches) {\n const val = parseFloat(m[1] ?? \"1\");\n if (val > maxScale) maxScale = val;\n }\n\n // Check if maxWidth * maxScale exceeds safe bounds (1920 - reasonable margins)\n const effectiveWidth = maxWidth * maxScale;\n if (effectiveWidth > 1760) {\n findings.push({\n code: \"caption_fittext_scale_mismatch\",\n severity: \"warning\",\n message:\n `fitTextFontSize uses maxWidth: ${maxWidth}px but emphasis words scale up to ${maxScale}x. ` +\n `Effective width ${Math.round(effectiveWidth)}px may overflow the composition (1920px minus margins).`,\n fixHint: `Reduce maxWidth to ${Math.floor(1700 / maxScale)}px to leave headroom for scaled emphasis words.`,\n });\n }\n }\n return findings;\n },\n];\n","import type { LintContext, HyperframeLintFinding, ExtractedBlock } from \"../context\";\nimport {\n findHtmlTag,\n readAttr,\n readJsonAttr,\n stripJsComments,\n truncateSnippet,\n WINDOW_TIMELINE_ASSIGN_PATTERN,\n} from \"../utils\";\nimport { COMPOSITION_VARIABLE_TYPES } from \"@hyperframes/parsers/composition\";\n\n// Agent guidance thresholds: warning-only nudges for files/tracks that become hard\n// to inspect and revise reliably in a single composition.\nconst MAX_COMPOSITION_LINES = 300;\nconst MAX_TIMED_ELEMENTS_PER_TRACK = 3;\nconst TRACK_DENSITY_EXEMPT_TAGS = new Set([\"audio\", \"script\", \"style\", \"video\"]);\n\n// `parseFloat(\"0.1\") + parseFloat(\"0.2\") = 0.30000000000000004`. Sub-second\n// authored adjacencies survive parse + add as a value a few ulps above the\n// next clip's start; a strict `>` fires the overlap rule on adjacencies that\n// are exact in the source HTML. 1μs sits ~11 orders of magnitude above the\n// observed drift (worst ~2e-16s across every realistic decimal pair) and 4\n// below one 60fps frame (~16.67ms), so this only ever swallows float slop.\nconst OVERLAP_EPSILON_SECONDS = 1e-6;\n\nfunction countPhysicalLines(source: string): number {\n if (source.length === 0) return 0;\n\n const normalized = source.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n const withoutFinalNewline = normalized.endsWith(\"\\n\") ? normalized.slice(0, -1) : normalized;\n return withoutFinalNewline.split(\"\\n\").length;\n}\n\nfunction countStructuralLines(source: string): number {\n return countPhysicalLines(source.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, \"<style></style>\"));\n}\n\nexport function isRegistrySourceFile(filePath?: string): boolean {\n if (!filePath) return false;\n\n const normalized = filePath.replace(/\\\\/g, \"/\");\n return /(?:^|\\/)registry\\/blocks\\/([^/]+)\\/\\1\\.html$/i.test(normalized);\n}\n\nexport function isRegistryInstalledFile(rawSource: string): boolean {\n return /^\\s*<!--\\s*hyperframes-registry-item:[^>]*-->/i.test(rawSource.slice(0, 512));\n}\n\nfunction isCompositionRootOrMount(rawTag: string): boolean {\n return Boolean(\n readAttr(rawTag, \"data-composition-id\") || readAttr(rawTag, \"data-composition-src\"),\n );\n}\n\n// Asset references inside CSS `url(...)`/`url(\"...\")`/`url('...')` functions.\n// Returns the inner path without quotes; comments are stripped first so\n// `/* url(foo) */` is ignored. Bare `url()` and `data:` are excluded by the\n// rules that consume this — the helper just yields raw URL values.\nfunction extractCssUrlReferences(css: string): string[] {\n const out: string[] = [];\n const noComments = css.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n const urlPattern = /\\burl\\(\\s*([\"']?)([^)\"']+)\\1\\s*\\)/g;\n let m: RegExpExecArray | null;\n while ((m = urlPattern.exec(noComments)) !== null) {\n const raw = (m[2] ?? \"\").trim();\n if (raw) out.push(raw);\n }\n return out;\n}\n\n// Top-level CSS selectors (comma-split) in a stylesheet, skipping at-rule headers\n// (@media/@keyframes/...) and keyframe stops. Heuristic — the lint layer has no\n// full CSS parser, and rules elsewhere in this file scan CSS the same way.\nfunction extractCssSelectors(css: string): string[] {\n const out: string[] = [];\n const noComments = css.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n const ruleHeader = /([^{}]+)\\{/g;\n let m: RegExpExecArray | null;\n while ((m = ruleHeader.exec(noComments)) !== null) {\n const header = (m[1] ?? \"\").trim();\n if (!header || header.startsWith(\"@\")) continue;\n for (const sel of header.split(\",\")) {\n const s = sel.trim();\n if (s) out.push(s);\n }\n }\n return out;\n}\n\n// Class tokens in a selector's leftmost compound (before the first descendant /\n// child / sibling combinator). `.frame .title` → [\"frame\"]; `.a.b > .c` → [\"a\",\"b\"].\nfunction leftmostCompoundClasses(selector: string): string[] {\n const leftmost = selector.trim().split(/[\\s>+~]+/)[0] ?? \"\";\n return (leftmost.match(/\\.([\\w-]+)/g) ?? []).map((c) => c.slice(1));\n}\n\n// Distinct selectors across all <style> blocks whose leftmost compound keys off one\n// of the root element's own classes — the ones that break under id-scoping.\nfunction rootClassStyledSelectors(styles: ExtractedBlock[], rootClasses: string[]): string[] {\n const offenders: string[] = [];\n for (const style of styles) {\n for (const selector of extractCssSelectors(style.content)) {\n const hitsRoot = leftmostCompoundClasses(selector).some((c) => rootClasses.includes(c));\n if (hitsRoot && !offenders.includes(selector)) offenders.push(selector);\n }\n }\n return offenders;\n}\n\nexport const compositionRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // invalid_parent_traversal_in_asset_path — catches `../` traversal in src,\n // href, inline-style url(), and <style> url() asset references on\n // compositions. Sub-compositions live under compositions/ but are served\n // with the project root as their base URL, so any `../`-traversing path\n // climbs above the project root and 404s in Studio preview. Renders\n // tolerate it because the server-side bundler rewrites `../foo` against\n // each sub-composition's source path; the runtime now mirrors that fallback\n // (see rewriteSubCompositionAssetPaths in runtime/compositionLoader.ts), but\n // the authoring-time signal is still wrong — flag it at lint time so the\n // baked path is plain root-relative and matches what the bundler emits.\n //\n // Mirrors the runtime fallback's surface: `[src]` / `[href]` attribute\n // values, `[style]` inline url(), and `<style>` block url() references.\n // Skips absolute URLs (http(s)://, //, data:, /-prefixed root-relative),\n // hash anchors, and plain relative paths (`assets/x.mp4`) — only `../`\n // traversal is flagged. Subsumes the older `../capture/`-specific rule.\n // fallow-ignore-next-line complexity\n ({ tags, styles, rawSource, options }) => {\n if (isRegistrySourceFile(options.filePath) || isRegistryInstalledFile(rawSource)) return [];\n\n const offenders: string[] = [];\n const collect = (value: string | null) => {\n if (!value) return;\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"../\") && trimmed !== \"..\") return;\n offenders.push(trimmed);\n };\n\n for (const tag of tags) {\n collect(readAttr(tag.raw, \"src\"));\n collect(readAttr(tag.raw, \"href\"));\n // Use readJsonAttr for `style` — inline url('...') values contain the\n // opposite quote, which readAttr's [^\"']+ class would truncate.\n const styleAttr = readJsonAttr(tag.raw, \"style\");\n if (styleAttr) {\n for (const url of extractCssUrlReferences(styleAttr)) collect(url);\n }\n }\n for (const style of styles) {\n for (const url of extractCssUrlReferences(style.content)) collect(url);\n }\n\n if (offenders.length === 0) return [];\n\n // Group counts by leading path token (e.g. ../capture/, ../assets/, ../../assets/)\n // so the message names the offending prefixes instead of a bare count.\n const prefixCounts = new Map<string, number>();\n for (const path of offenders) {\n const prefix = path.match(/^(?:\\.\\.\\/)+[^/]+\\//)?.[0] ?? path;\n prefixCounts.set(prefix, (prefixCounts.get(prefix) ?? 0) + 1);\n }\n const prefixSummary = Array.from(prefixCounts.entries())\n .sort(([, a], [, b]) => b - a)\n .map(([prefix, count]) => (count > 1 ? `${prefix} (${count})` : prefix))\n .join(\", \");\n\n return [\n {\n code: \"invalid_parent_traversal_in_asset_path\",\n severity: \"error\",\n message:\n `Found ${offenders.length} asset path(s) traversing above the project root with \"../\" ` +\n `(${prefixSummary}). Renders rewrite this against each sub-composition's source path, but Studio preview and other live consumers resolve against the project root and 404.`,\n fixHint:\n 'Use plain root-relative paths (e.g. \"assets/...\", \"capture/...\", \"fonts/...\") — compositions are served with the project root as their base URL, so paths must be root-relative, not relative to the compositions/ directory.',\n },\n ];\n },\n\n // composition_file_too_large\n ({ rawSource, options }) => {\n if (isRegistrySourceFile(options.filePath) || isRegistryInstalledFile(rawSource)) return [];\n\n const lineCount = countStructuralLines(rawSource);\n if (lineCount <= MAX_COMPOSITION_LINES) return [];\n\n const splitTarget = options.isSubComposition\n ? \"Split this sub-composition further into smaller .html files\"\n : \"Split coherent scenes or layers into separate .html files under compositions/\";\n\n return [\n {\n code: \"composition_file_too_large\",\n severity: \"warning\",\n message: `This HTML composition file has ${lineCount} lines. Smaller sub-compositions are easier to read, iterate on, and diff.`,\n fixHint: `${splitTarget}, then mount them from the parent with data-composition-src so each file stays small enough to inspect, revise, and validate independently.`,\n },\n ];\n },\n\n // timeline_track_too_dense\n // fallow-ignore-next-line complexity\n ({ tags, options }) => {\n const trackCounts = new Map<string, number>();\n for (const tag of tags) {\n if (TRACK_DENSITY_EXEMPT_TAGS.has(tag.name)) continue;\n if (isCompositionRootOrMount(tag.raw)) continue;\n if (!readAttr(tag.raw, \"data-start\")) continue;\n\n const track = readAttr(tag.raw, \"data-track-index\");\n if (!track) continue;\n trackCounts.set(track, (trackCounts.get(track) ?? 0) + 1);\n }\n\n const findings: HyperframeLintFinding[] = [];\n for (const [track, count] of trackCounts) {\n if (count <= MAX_TIMED_ELEMENTS_PER_TRACK) continue;\n const splitTarget = options.isSubComposition\n ? \"Move coherent scene groups into smaller .html files\"\n : \"Move coherent scene groups into separate .html files under compositions/\";\n findings.push({\n code: \"timeline_track_too_dense\",\n severity: \"warning\",\n message: `Track ${track} has ${count} timed elements in this HTML file. Smaller sub-compositions keep timelines easier to read, iterate on, and diff.`,\n fixHint: `${splitTarget} and mount them from the parent with data-composition-src so the timeline stays easier to inspect, revise, and validate.`,\n });\n }\n\n return findings;\n },\n\n // timed_element_missing_visibility_hidden\n // fallow-ignore-next-line complexity\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (tag.name === \"audio\" || tag.name === \"script\" || tag.name === \"style\") continue;\n if (!readAttr(tag.raw, \"data-start\")) continue;\n if (readAttr(tag.raw, \"data-composition-id\")) continue;\n if (readAttr(tag.raw, \"data-composition-src\")) continue;\n const classAttr = readAttr(tag.raw, \"class\") || \"\";\n const styleAttr = readAttr(tag.raw, \"style\") || \"\";\n const hasClip = classAttr.split(/\\s+/).includes(\"clip\");\n const hasHiddenStyle =\n /visibility\\s*:\\s*hidden/i.test(styleAttr) || /opacity\\s*:\\s*0/i.test(styleAttr);\n if (!hasClip && !hasHiddenStyle) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"timed_element_missing_visibility_hidden\",\n severity: \"info\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> has data-start but no class=\"clip\", visibility:hidden, or opacity:0. Consider adding initial hidden state if the element should not be visible before its start time.`,\n elementId,\n fixHint:\n 'Add class=\"clip\" (with CSS: .clip { visibility: hidden; }) or style=\"opacity:0\" if the element should start hidden.',\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // deprecated_data_layer + deprecated_data_end\n // fallow-ignore-next-line complexity\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n if (readAttr(tag.raw, \"data-layer\") && !readAttr(tag.raw, \"data-track-index\")) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"deprecated_data_layer\",\n severity: \"error\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> uses data-layer instead of data-track-index.`,\n elementId,\n fixHint: \"Replace data-layer with data-track-index. The runtime reads data-track-index.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n if (readAttr(tag.raw, \"data-end\") && !readAttr(tag.raw, \"data-duration\")) {\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"deprecated_data_end\",\n severity: \"error\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> uses data-end without data-duration. Use data-duration in source HTML.`,\n elementId,\n fixHint:\n \"Replace data-end with data-duration. The compiler generates data-end from data-duration automatically.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // split_data_attribute_selector\n ({ scripts, styles }) => {\n const findings: HyperframeLintFinding[] = [];\n const splitDataAttrSelectorPattern =\n /\\[data-composition-id=([\"'])([^\"'\\]]+)\\1\\s+(data-[\\w:-]+)=([\"'])([^\"'\\]]*)\\4\\]/g;\n const scan = (content: string) => {\n splitDataAttrSelectorPattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = splitDataAttrSelectorPattern.exec(content)) !== null) {\n const compId = match[2] ?? \"\";\n const attrName = match[3] ?? \"\";\n const attrValue = match[5] ?? \"\";\n findings.push({\n code: \"split_data_attribute_selector\",\n severity: \"error\",\n message:\n `Selector \"${match[0]}\" combines two attributes inside one CSS attribute selector. ` +\n \"Browsers reject it, so GSAP timelines or querySelector calls will fail before registering.\",\n selector: match[0],\n fixHint: `Use separate attribute selectors: [data-composition-id=\"${compId}\"][${attrName}=\"${attrValue}\"].`,\n snippet: truncateSnippet(match[0]),\n });\n }\n };\n for (const style of styles) scan(style.content);\n for (const script of scripts) scan(script.content);\n return findings;\n },\n\n // template_literal_selector\n ({ scripts }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const script of scripts) {\n const templateLiteralSelectorPattern =\n /(?:querySelector|querySelectorAll)\\s*\\(\\s*`[^`]*\\$\\{[^}]+\\}[^`]*`\\s*\\)/g;\n let tlMatch: RegExpExecArray | null;\n while ((tlMatch = templateLiteralSelectorPattern.exec(script.content)) !== null) {\n findings.push({\n code: \"template_literal_selector\",\n severity: \"error\",\n message:\n \"querySelector uses a template literal variable (e.g. `${compId}`). \" +\n \"The HTML bundler's CSS parser crashes on these. Use a hardcoded string instead.\",\n fixHint:\n \"Replace the template literal variable with a hardcoded string. The bundler's CSS parser cannot handle interpolated variables in script content.\",\n snippet: truncateSnippet(tlMatch[0]),\n });\n }\n }\n return findings;\n },\n\n // timed_element_missing_clip_class\n // fallow-ignore-next-line complexity\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n const skipTags = new Set([\"audio\", \"video\", \"script\", \"style\", \"template\"]);\n for (const tag of tags) {\n if (skipTags.has(tag.name)) continue;\n // Skip composition hosts\n if (readAttr(tag.raw, \"data-composition-id\")) continue;\n if (readAttr(tag.raw, \"data-composition-src\")) continue;\n\n const hasStart = readAttr(tag.raw, \"data-start\") !== null;\n const hasDuration = readAttr(tag.raw, \"data-duration\") !== null;\n // data-track-index alone marks a layer container, not a time-bounded clip\n if (!hasStart && !hasDuration) continue;\n\n const classAttr = readAttr(tag.raw, \"class\") || \"\";\n const hasClip = classAttr.split(/\\s+/).includes(\"clip\");\n if (hasClip) continue;\n\n const elementId = readAttr(tag.raw, \"id\") || undefined;\n findings.push({\n code: \"timed_element_missing_clip_class\",\n severity: \"error\",\n message: `<${tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> has timing attributes but no class=\"clip\". The element will be visible for the entire composition instead of only during its scheduled time range.`,\n elementId,\n fixHint:\n 'Add class=\"clip\" to the element. The HyperFrames runtime uses .clip to control visibility based on data-start/data-duration.',\n snippet: truncateSnippet(tag.raw),\n });\n }\n return findings;\n },\n\n // overlapping_clips_same_track\n // fallow-ignore-next-line complexity\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n\n type ClipInfo = { start: number; end: number; elementId?: string; snippet: string };\n const trackMap = new Map<string, ClipInfo[]>();\n\n for (const tag of tags) {\n const startStr = readAttr(tag.raw, \"data-start\");\n const durationStr = readAttr(tag.raw, \"data-duration\");\n const trackStr = readAttr(tag.raw, \"data-track-index\");\n if (!startStr || !durationStr || !trackStr) continue;\n\n const start = Number(startStr);\n const duration = Number(durationStr);\n const track = trackStr;\n\n // Skip non-numeric (relative timing references like \"intro-comp\")\n if (Number.isNaN(start) || Number.isNaN(duration)) continue;\n\n const clips = trackMap.get(track) || [];\n clips.push({\n start,\n end: start + duration,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n snippet: truncateSnippet(tag.raw) || \"\",\n });\n trackMap.set(track, clips);\n }\n\n for (const [track, clips] of trackMap) {\n clips.sort((a, b) => a.start - b.start);\n for (let i = 0; i < clips.length - 1; i++) {\n const current = clips[i];\n const next = clips[i + 1];\n if (!current || !next) continue;\n if (current.end - next.start > OVERLAP_EPSILON_SECONDS) {\n findings.push({\n code: \"overlapping_clips_same_track\",\n severity: \"error\",\n message: `Track ${track}: clip ending at ${current.end}s overlaps with clip starting at ${next.start}s. Overlapping clips on the same track cause rendering conflicts.`,\n fixHint:\n \"Adjust data-start or data-duration so clips on the same track do not overlap, or move one clip to a different data-track-index.\",\n });\n }\n }\n }\n\n return findings;\n },\n\n // root_composition_missing_data_start\n ({ rootTag, options }) => {\n const findings: HyperframeLintFinding[] = [];\n if (options.isSubComposition) return findings;\n if (!rootTag) return findings;\n const compId = readAttr(rootTag.raw, \"data-composition-id\");\n if (!compId) return findings;\n const hasStart = readAttr(rootTag.raw, \"data-start\") !== null;\n if (!hasStart) {\n findings.push({\n code: \"root_composition_missing_data_start\",\n severity: \"error\",\n message: `Root composition \"${compId}\" is missing data-start. The runtime needs data-start=\"0\" on the root element to begin playback.`,\n fixHint: 'Add data-start=\"0\" to the root composition element.',\n snippet: truncateSnippet(rootTag.raw),\n });\n }\n return findings;\n },\n\n // standalone_composition_wrapped_in_template\n ({ rawSource, options }) => {\n const findings: HyperframeLintFinding[] = [];\n if (options.isSubComposition) return findings;\n const trimmed = rawSource.trimStart().toLowerCase();\n if (trimmed.startsWith(\"<template\")) {\n findings.push({\n code: \"standalone_composition_wrapped_in_template\",\n severity: \"error\",\n message:\n \"Root index.html is wrapped in a <template> tag. \" +\n \"Only sub-compositions loaded via data-composition-src should use <template> wrappers. \" +\n \"The runtime cannot play a standalone composition inside a template.\",\n fixHint:\n \"Remove the <template> wrapper. Use <!DOCTYPE html><html>...<div data-composition-id>...</div>...</html> instead.\",\n });\n }\n return findings;\n },\n\n // root_composition_missing_html_wrapper\n ({ rawSource, rootTag, options }) => {\n const findings: HyperframeLintFinding[] = [];\n if (options.isSubComposition) return findings;\n const trimmed = rawSource.trimStart().toLowerCase();\n // Compositions inside <template> are caught by standalone_composition_wrapped_in_template\n if (trimmed.startsWith(\"<template\")) return findings;\n const hasDoctype = trimmed.startsWith(\"<!doctype\") || trimmed.startsWith(\"<html\");\n const hasComposition = rawSource.includes(\"data-composition-id\");\n if (hasComposition && !hasDoctype) {\n findings.push({\n code: \"root_composition_missing_html_wrapper\",\n severity: \"error\",\n message:\n \"Composition starts with a bare element instead of a proper HTML document. \" +\n \"An index.html that contains data-composition-id but no <!DOCTYPE html>, <html>, or <body> \" +\n \"is a fragment — browsers quirks-mode it, the preview server cannot load it, and \" +\n \"the bundler will fail to inject runtime scripts.\",\n fixHint:\n 'Wrap the composition in <!DOCTYPE html><html><head><meta charset=\"UTF-8\"></head><body>...</body></html>.',\n snippet: rootTag ? truncateSnippet(rootTag.raw) : undefined,\n });\n }\n return findings;\n },\n\n // missing_data_no_timeline\n // The producer polls window.__timelines[id] with a 45-second timeout waiting\n // for GSAP timeline registration. Compositions that never call\n // window.__timelines[id] = tl stall for 45 s every render. Adding\n // data-no-timeline to the root element tells the producer to skip the poll.\n ({ rootTag, rootCompositionId, scripts, rawSource, options }) => {\n if (options.isSubComposition) return [];\n if (!rootCompositionId || !rootTag) return [];\n // readAttr only matches valued attrs (attr=\"...\"); data-no-timeline is\n // typically boolean (no value). Strip quoted attribute values first to\n // avoid matching attr names that appear inside other values\n // (e.g. title=\"add data-no-timeline here\"), then check with a boundary\n // that rejects hyphenated variants (data-no-timeline-start has '-' next,\n // not a word-break char).\n const tagNoValues = rootTag.raw.replace(/\"[^\"]*\"|'[^']*'/g, '\"\"');\n if (/(?:^|\\s)data-no-timeline(?=[\\s>=/]|$)/i.test(tagNoValues)) return [];\n // Can't scan external script files for timeline registration; skip to avoid\n // false positives on compositions that register via a bundled JS file.\n if (/<script\\b[^>]*\\bsrc\\s*=/i.test(rawSource)) return [];\n const registersTimeline = scripts.some((s) => s.content.includes(\"window.__timelines[\"));\n if (registersTimeline) return [];\n return [\n {\n code: \"missing_data_no_timeline\",\n severity: \"warning\",\n message:\n \"This composition has no `window.__timelines` registration but is missing `data-no-timeline`. \" +\n \"The producer polls for timeline registration for up to 45 seconds before timing out, \" +\n \"adding 45 s to every render.\",\n fixHint:\n 'Add `data-no-timeline` to the root element to skip the poll: `<div data-composition-id=\"...\" data-no-timeline ...>`.',\n snippet: truncateSnippet(rootTag.raw),\n },\n ];\n },\n\n // requestanimationframe_in_composition\n ({ scripts, rawSource, options }) => {\n if (isRegistrySourceFile(options.filePath) || isRegistryInstalledFile(rawSource)) return [];\n const findings: HyperframeLintFinding[] = [];\n for (const script of scripts) {\n const stripped = stripJsComments(script.content);\n if (/requestAnimationFrame\\s*\\(/.test(stripped)) {\n findings.push({\n code: \"requestanimationframe_in_composition\",\n severity: \"error\",\n message:\n \"`requestAnimationFrame` runs on wall-clock time, not the GSAP timeline. It will not sync with frame capture and may cause flickering or missed frames during rendering.\",\n fixHint:\n \"Use GSAP tweens or onUpdate callbacks instead of requestAnimationFrame for animation logic.\",\n snippet: truncateSnippet(script.content),\n });\n }\n }\n return findings;\n },\n\n // invalid_variable_values_json\n // Host elements (`[data-composition-src]`) carry per-instance values via\n // `data-variable-values`. The runtime swallows JSON errors silently and\n // falls back to declared defaults, which masks typos. This rule surfaces\n // the parse failure so authors notice before render time.\n // fallow-ignore-next-line complexity\n ({ tags }) => {\n const findings: HyperframeLintFinding[] = [];\n for (const tag of tags) {\n const raw = readJsonAttr(tag.raw, \"data-variable-values\");\n if (!raw) continue;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"unknown\";\n findings.push({\n code: \"invalid_variable_values_json\",\n severity: \"error\",\n message: `data-variable-values is not valid JSON (${reason}).`,\n fixHint:\n 'Wrap the attribute value in single quotes and the JSON keys/values in double quotes, e.g. data-variable-values=\\'{\"title\":\"Hello\"}\\'.',\n elementId: readAttr(tag.raw, \"id\") || undefined,\n snippet: truncateSnippet(tag.raw),\n });\n continue;\n }\n\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n findings.push({\n code: \"invalid_variable_values_json\",\n severity: \"error\",\n message:\n 'data-variable-values must be a JSON object keyed by variable id (e.g. {\"title\":\"Hello\"}).',\n fixHint:\n \"Replace the value with a JSON object whose keys are variable ids declared in the sub-composition's data-composition-variables.\",\n elementId: readAttr(tag.raw, \"id\") || undefined,\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n return findings;\n },\n\n // invalid_composition_variables_declaration\n // The runtime parses `data-composition-variables` and silently returns []\n // on any structural problem. Surface JSON / shape failures so authors\n // catch them at lint time rather than wondering why their `getVariables()`\n // defaults aren't applied.\n // fallow-ignore-next-line complexity\n ({ source }) => {\n const htmlTag = findHtmlTag(source);\n if (!htmlTag) return [];\n const raw = readJsonAttr(htmlTag.raw, \"data-composition-variables\");\n if (!raw) return [];\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"unknown\";\n return [\n {\n code: \"invalid_composition_variables_declaration\",\n severity: \"error\",\n message: `data-composition-variables is not valid JSON (${reason}).`,\n fixHint:\n 'Provide a JSON array of variable declarations: data-composition-variables=\\'[{\"id\":\"title\",\"type\":\"string\",\"label\":\"Title\",\"default\":\"Hello\"}]\\'.',\n snippet: truncateSnippet(htmlTag.raw),\n },\n ];\n }\n\n if (!Array.isArray(parsed)) {\n return [\n {\n code: \"invalid_composition_variables_declaration\",\n severity: \"error\",\n message: \"data-composition-variables must be a JSON array of variable declarations.\",\n fixHint:\n 'Wrap declarations in [] and give each an id, type, label, and default: \\'[{\"id\":\"title\",\"type\":\"string\",\"label\":\"Title\",\"default\":\"Hello\"}]\\'.',\n snippet: truncateSnippet(htmlTag.raw),\n },\n ];\n }\n\n const findings: HyperframeLintFinding[] = [];\n const knownTypes = new Set<string>(COMPOSITION_VARIABLE_TYPES);\n for (let i = 0; i < parsed.length; i += 1) {\n const entry = parsed[i];\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n findings.push({\n code: \"invalid_composition_variables_declaration\",\n severity: \"error\",\n message: `data-composition-variables entry [${i}] must be an object with id, type, label, and default.`,\n snippet: truncateSnippet(htmlTag.raw),\n });\n continue;\n }\n const e = entry as Record<string, unknown>;\n const missing: string[] = [];\n if (typeof e.id !== \"string\") missing.push(\"id\");\n if (typeof e.type !== \"string\" || !knownTypes.has(e.type)) missing.push(\"type\");\n if (typeof e.label !== \"string\") missing.push(\"label\");\n if (!(\"default\" in e)) missing.push(\"default\");\n if (missing.length > 0) {\n findings.push({\n code: \"invalid_composition_variables_declaration\",\n severity: \"error\",\n message: `data-composition-variables entry [${i}] is missing or has invalid: ${missing.join(\", \")}. Type must be one of string, number, color, boolean, enum, font, image.`,\n snippet: truncateSnippet(htmlTag.raw),\n });\n }\n }\n return findings;\n },\n\n // html_dir_attribute_breaks_render — valid non-LTR dir values on\n // <html> renders correctly in preview/snapshot but produces a fully\n // blank/black video from render, with no other lint/validate/inspect\n // check catching it (output file size, far smaller than expected, is the\n // only tell). Confirmed independently by two separate reports, both\n // diagnosing the same exact trigger and the same fix: drop dir from\n // <html>, keep lang, and scope `direction: rtl` to individual\n // text-containing elements via CSS instead (text still bidi-shapes\n // correctly). Advisory-only — this does not attempt to fix the render\n // pipeline's own root cause (suspected to be a capture step that clips a\n // fixed top-left-origin screenshot region, which RTL layout can shift the\n // actual content away from), only surfaces the already-confirmed footgun\n // before someone hits it blind.\n ({ source }) => {\n const htmlTag = findHtmlTag(source);\n if (!htmlTag) return [];\n const dir = readAttr(htmlTag.raw, \"dir\");\n if (!dir) return [];\n const normalizedDir = dir.toLowerCase();\n if (normalizedDir !== \"rtl\" && normalizedDir !== \"auto\") return [];\n const scopedDirection = normalizedDir === \"auto\" ? 'dir=\"auto\"' : `direction: ${normalizedDir}`;\n return [\n {\n code: \"html_dir_attribute_breaks_render\",\n severity: \"error\",\n message: `<html dir=\"${dir}\"> renders correctly in preview/snapshot but produces a fully blank/black video from render — a confirmed, silent failure.`,\n fixHint: `Remove dir=\"${dir}\" from <html>. Keep lang, and scope ${scopedDirection} to individual text-containing elements instead — text still shapes correctly via the browser's own bidi algorithm.`,\n snippet: truncateSnippet(htmlTag.raw),\n },\n ];\n },\n\n // subcomposition_blanks_before_host\n // Warns when a full-bleed sub-composition slot ends before the host composition\n // does, leaving the slot blank for the remainder (issue #1540). Scoped narrowly to\n // the high-signal shape — a sole/dominant external mount starting at ~0 — so it\n // stays silent on intentional short clips (an intro followed by other clips that\n // carry the timeline forward).\n // fallow-ignore-next-line complexity\n ({ tags, rootTag }) => {\n if (!rootTag) return [];\n const rootDuration = Number(readAttr(rootTag.raw, \"data-duration\"));\n if (!Number.isFinite(rootDuration) || rootDuration <= 0) return [];\n\n // Two independent knobs that happen to share a 0.5s magnitude. Tuned for\n // real hosts (tens to hundreds of seconds); on a very short host (~6s) the\n // EPSILON slack would let a ~10% blank tail pass unflagged — acceptable\n // because the silent-blank trap this rule targets only matters at scale.\n const EPSILON = 0.5; // seconds; tolerance for \"ends/covers near the host end\"\n const START_TOLERANCE = 0.5; // seconds; \"starts at the composition start\"\n const round3 = (n: number) => Math.round(n * 1000) / 1000;\n\n // Timed children of the root. An element with data-start but no usable\n // data-duration is treated as covering the tail (end = Infinity), so an\n // unknown-length sibling suppresses the warning rather than triggering it.\n const timed = tags\n .filter((tag) => tag.index !== rootTag.index && readAttr(tag.raw, \"data-start\") !== null)\n .map((tag) => {\n const start = Number(readAttr(tag.raw, \"data-start\")) || 0;\n const dur = Number(readAttr(tag.raw, \"data-duration\"));\n const end = Number.isFinite(dur) && dur > 0 ? start + dur : Infinity;\n return { tag, start, end };\n });\n\n // `tags` is a flat list (no nesting depth), so a timed element nested\n // *inside* a candidate slot is treated as a tail-covering sibling rather\n // than a descendant. Acceptable: external src mounts are empty by\n // convention (content is loaded from the linked file), so the only\n // false-negative path is rare and matches the flat-tag scope of the\n // sibling rules in this file.\n const tailCovered = (exceptIndex: number) =>\n timed.some((t) => t.tag.index !== exceptIndex && t.end >= rootDuration - EPSILON);\n\n const findings: HyperframeLintFinding[] = [];\n for (const t of timed) {\n if (readAttr(t.tag.raw, \"data-composition-src\") === null) continue; // external slot only\n if (t.start > START_TOLERANCE) continue; // must start at the composition start\n if (!Number.isFinite(t.end)) continue; // known, finite slot length\n if (t.end >= rootDuration - EPSILON) continue; // already fills the host window\n if (tailCovered(t.tag.index)) continue; // another clip covers the tail — not full-bleed\n const elementId = readAttr(t.tag.raw, \"id\") || undefined;\n const gap = round3(rootDuration - t.end);\n findings.push({\n code: \"subcomposition_blanks_before_host\",\n severity: \"warning\",\n message: `<${t.tag.name}${elementId ? ` id=\"${elementId}\"` : \"\"}> sub-composition ends at ${round3(t.end)}s but the composition runs to ${round3(rootDuration)}s — its slot will be blank for ~${gap}s.`,\n elementId,\n fixHint: `data-duration is the slot's visible window. Set this sub-composition's data-duration to ${round3(rootDuration - t.start)} to fill the host window, or add another clip to cover the remaining ~${gap}s.`,\n snippet: truncateSnippet(t.tag.raw),\n });\n }\n return findings;\n },\n\n // subcomposition_root_styled_by_class\n // A sub-composition's <style> is scoped at render time to\n // `[data-composition-id=\"<id>\"] <selector>` so scenes inlined into one document\n // can't leak styles into each other. A rule whose LEFTMOST selector is the ROOT\n // element's own class (e.g. `.frame { ... }` on the same element that carries\n // data-composition-id) therefore becomes a DESCENDANT selector that can never\n // match the root — the whole scene renders unstyled (tiny text top-left, images\n // at natural size). lint/validate/inspect evaluate the file in isolation (no\n // scoping) and Studio previews each scene in its own iframe (no scoping), so the\n // break is invisible until the composited MP4 render. Style the root via `#root`\n // (the scoper special-cases the root id) and descendants via plain selectors,\n // like the registry blocks — the runtime already scopes each scene by id, so a\n // class namespace on the root is redundant.\n ({ rootTag, rootCompositionId, styles, options }) => {\n if (!options.isSubComposition) return [];\n if (isRegistrySourceFile(options.filePath)) return [];\n if (!rootTag || !rootCompositionId) return [];\n\n const rootClasses = (readAttr(rootTag.raw, \"class\") || \"\").split(/\\s+/).filter(Boolean);\n if (rootClasses.length === 0) return [];\n\n const offenders = rootClassStyledSelectors(styles, rootClasses);\n if (offenders.length === 0) return [];\n\n const example = offenders.slice(0, 3).join(\", \");\n return [\n {\n code: \"subcomposition_root_styled_by_class\",\n severity: \"error\",\n message:\n `Root element has class=\"${rootClasses.join(\" \")}\" and is styled by ${offenders.length} rule(s) keyed off that class (e.g. ${example}). ` +\n `At render, every sub-composition rule is scoped to [data-composition-id=\"${rootCompositionId}\"] <selector>, so a selector whose leftmost part is the ROOT's own class becomes a descendant selector that cannot match the root — the scene renders unstyled (tiny text top-left, full-size images). ` +\n `lint/validate/inspect and Studio's per-frame iframe preview do not scope, so this passes every static check and looks correct in preview.`,\n selector: example,\n fixHint: `Give the root id=\"root\" and style it with \\`#root { ... }\\` plus plain descendant selectors (\\`.kicker\\`, \\`#hero\\`) — the runtime already scopes each sub-composition by data-composition-id, so a class namespace on the root is redundant and breaks under scoping.`,\n snippet: truncateSnippet(rootTag.raw),\n },\n ];\n },\n\n // root_composition_missing_duration_source\n //\n // The render engine (packages/engine/src/services/frameCapture.ts) needs a\n // positive window.__hf.duration to know how many frames to capture. GSAP\n // timelines set this automatically. Non-GSAP runtimes (CSS, WAAPI, Lottie)\n // are now auto-inferred by the runtime too (see\n // packages/core/src/runtime/init.ts resolveAdapterDurationFloorSeconds and\n // the adapters' getInferredDurationSeconds) — so data-duration is optional\n // wherever the runtime can work it out on its own.\n //\n // This rule fires for cases where the total render length is not reliably\n // determinable without an explicit data-duration:\n // - No GSAP timeline AND no data-duration AND no non-GSAP animation\n // signal at all (nothing for any adapter to discover — render fails).\n // - Three.js used with no data-duration (no discoverable AnimationClip\n // duration in this codebase's adapter — see adapters/three.ts).\n // - Any infinite CSS animation-iteration-count with no data-duration,\n // EVEN when a finite CSS animation is present alongside it. An unbounded\n // animation makes the intended total length ambiguous — the runtime will\n // infer a finite sibling's length if one exists, but that's a fallback,\n // not a declaration of intent, so we still require data-duration here.\n // (This is intentionally stricter than the runtime's own inference.)\n // Purely finite CSS/WAAPI animations and Lottie are excluded — the runtime\n // infers those unambiguously, so requiring data-duration there would be a\n // false positive against the runtime's own auto-inference. Note lint is\n // advisory by default (see shouldBlockRender) — it only blocks render under\n // --strict/--strict-all — so a strict flag here nudges toward an explicit,\n // guaranteed-correct value without failing renders that would succeed.\n // fallow-ignore-next-line complexity\n ({ rootTag, scripts, styles, tags, options }) => {\n if (options.isSubComposition) return [];\n if (!rootTag) return [];\n // Not every file linted as a \"root\" HTML document is a video composition\n // — e.g. a slideshow demo.html mounts <hyperframes-player src=\"index.html\">\n // with no data-composition-id of its own. Nothing to capture there, so\n // there's no duration contract to enforce.\n if (readAttr(rootTag.raw, \"data-composition-id\") === null) return [];\n if (readAttr(rootTag.raw, \"data-duration\") !== null) return [];\n\n // Strip comments before scanning for signals — a commented-out\n // `.animate(...)` call or `/* animation: spin 2s infinite; */` must not\n // satisfy the \"has a duration source\" check, or the composition still\n // fails at render with zero duration despite lint passing.\n const allScriptTexts = scripts.map((s) => stripJsComments(s.content));\n const hasGsapTimeline = allScriptTexts.some((t) => /gsap\\.timeline\\s*\\(/.test(t));\n const hasRegisteredTimeline = allScriptTexts.some((t) =>\n WINDOW_TIMELINE_ASSIGN_PATTERN.test(t),\n );\n // A GSAP timeline drives duration via window.__timelines regardless of\n // data-duration — nothing to flag once one is registered.\n if (hasGsapTimeline && hasRegisteredTimeline) return [];\n\n const allCss = styles.map((s) => s.content).join(\"\\n\");\n const allInlineStyles = tags.map((t) => readAttr(t.raw, \"style\") || \"\").join(\"\\n\");\n const combinedCss = `${allCss}\\n${allInlineStyles}`.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n\n const usesLottie =\n tags.some((t) => readAttr(t.raw, \"data-lottie-src\") !== null) ||\n allScriptTexts.some((t) => /lottie\\.(loadAnimation)\\b|__hfLottie\\b/.test(t));\n const usesThree = allScriptTexts.some((t) => /\\bTHREE\\./.test(t));\n // `.animate([...], ...)` catches the array-literal keyframes form;\n // `.animate({...}, ...)` catches the object-literal (PropertyIndexedKeyframes)\n // form; `.animate(someVar, ...)` catches keyframes built up in a variable\n // first.\n const usesWaapi = allScriptTexts.some((t) => /\\.animate\\s*\\(\\s*[[{$A-Za-z_]/.test(t));\n const hasCssAnimationName = /\\banimation(?:-name)?\\s*:/.test(combinedCss);\n const hasInfiniteCssAnimation =\n /\\banimation(?:-iteration-count)?\\s*:[^;{}]*(?<![\\w-])infinite(?![\\w-])/.test(combinedCss);\n\n const hasAnyNonGsapSignal = usesLottie || usesThree || usesWaapi || hasCssAnimationName;\n\n if (!hasAnyNonGsapSignal) {\n // No GSAP timeline, no data-duration, and nothing for any adapter to\n // discover — the composition has no source of truth for duration at\n // all. This is the exact shape of the 27K \"zero duration\" render\n // failures this rule exists to catch before render time.\n return [\n {\n code: \"root_composition_missing_duration_source\",\n severity: \"error\",\n message:\n \"Root composition has no data-duration, no GSAP timeline, and no CSS/WAAPI/Lottie/Three.js \" +\n \"animation for the runtime to infer a duration from. The render engine cannot determine \" +\n 'how long to capture and will fail with \"Composition has zero duration\".',\n fixHint:\n 'Add data-duration=\"<seconds>\" to the root element, or add a paused GSAP timeline registered ' +\n \"on window.__timelines.\",\n snippet: truncateSnippet(rootTag.raw),\n },\n ];\n }\n\n if (usesThree) {\n // No AnimationMixer/AnimationClip discovery in the three.js adapter\n // today (see adapters/three.ts) — genuinely not inferable.\n return [\n {\n code: \"root_composition_missing_duration_source\",\n severity: \"error\",\n message:\n \"Root composition uses Three.js with no data-duration. The runtime cannot discover a \" +\n \"Three.js scene's duration automatically (no AnimationClip/AnimationMixer inspection) — \" +\n 'render will fail with \"Composition has zero duration\".',\n fixHint: 'Add data-duration=\"<seconds>\" to the root element.',\n snippet: truncateSnippet(rootTag.raw),\n },\n ];\n }\n\n if (hasInfiniteCssAnimation && !usesLottie && !usesWaapi) {\n // An infinite/unbounded CSS animation makes the intended total length\n // ambiguous, so we require an explicit data-duration even when a finite\n // CSS animation is present alongside it. This is deliberately stricter\n // than the runtime's own inference: the CSS adapter's\n // getInferredDurationSeconds (see adapters/css.ts) returns the longest\n // finite animation end-time when one exists (so a finite sibling would\n // render at that length) and null when every animation is unbounded (so\n // a render with no finite source fails outright). Either way the author\n // hasn't declared how long the video should be — a decorative infinite\n // spinner next to a 3s fade doesn't tell us the clip is meant to be 3s\n // — so we flag it and let them state intent. The message stays honest\n // about both outcomes rather than claiming the render always fails.\n return [\n {\n code: \"root_composition_missing_duration_source\",\n severity: \"error\",\n message:\n \"Root composition uses a CSS animation with animation-iteration-count: infinite and no \" +\n \"data-duration, so the intended total length is ambiguous. If a finite animation is also \" +\n \"present the runtime infers that length; with no finite source the render fails with \" +\n '\"Composition has zero duration\". Declare the intended length explicitly.',\n fixHint:\n 'Add data-duration=\"<seconds>\" to the root element with the intended total length.',\n snippet: truncateSnippet(rootTag.raw),\n },\n ];\n }\n\n // Finite CSS animation, WAAPI .animate(), or Lottie — the runtime infers\n // duration from these at render time (see resolveAdapterDurationFloorSeconds\n // in runtime/init.ts). Not an error; data-duration is optional here.\n return [];\n },\n];\n","import type { LintContext, HyperframeLintFinding } from \"../context\";\nimport { readAttr, extractScriptTextsAndSrcs } from \"../utils\";\n\nexport const adapterRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // missing_lottie_script\n ({ tags, scripts }) => {\n const { texts, srcs } = extractScriptTextsAndSrcs(scripts);\n\n const hasLottieAttr = tags.some((t) => readAttr(t.raw, \"data-lottie-src\") !== null);\n const usesLottieApi = texts.some((t) =>\n /lottie\\.(loadAnimation|setSpeed|play|stop|destroy)\\b/.test(t),\n );\n const hasLottieScript = srcs.some((src) => /lottie/i.test(src));\n\n if (!(hasLottieAttr || usesLottieApi) || hasLottieScript) return [];\n return [\n {\n code: \"missing_lottie_script\",\n severity: \"error\",\n message:\n \"Composition uses Lottie but no Lottie script is loaded. The animation will not render.\",\n fixHint:\n 'Add <script src=\"https://cdn.jsdelivr.net/npm/lottie-web@5/build/player/lottie.min.js\"></script> before your Lottie code.',\n },\n ];\n },\n\n // missing_three_script\n ({ scripts }) => {\n const { texts, srcs } = extractScriptTextsAndSrcs(scripts);\n\n const usesThree = texts.some((t) => /\\bTHREE\\./.test(t));\n const hasThreeScript = srcs.some((src) => /three/i.test(src));\n const hasThreeImportMap = texts.some(\n (t) =>\n /[\"']three[\"']/.test(t) &&\n /importmap/.test(scripts.find((s) => s.content === t)?.attrs || \"\"),\n );\n // Matches any import/from whose specifier contains \"three\" (bare 'three', or a\n // URL/path like .../+esm, esm.sh/three, three.module.js), mirroring the loose\n // /three/i treatment of <script src>.\n const hasThreeModuleImport = texts.some((t) =>\n /\\b(?:import|from)\\s*[^;\\n]*['\"][^'\"]*three[^'\"]*['\"]/i.test(t),\n );\n\n if (!usesThree || hasThreeScript || hasThreeImportMap || hasThreeModuleImport) return [];\n return [\n {\n code: \"missing_three_script\",\n severity: \"error\",\n message:\n \"Composition uses Three.js but no Three.js script is loaded. The 3D scene will not render.\",\n fixHint:\n 'Add <script src=\"https://cdn.jsdelivr.net/npm/three@0.160/build/three.min.js\"></script> before your Three.js code.',\n },\n ];\n },\n];\n","import postcss from \"postcss\";\nimport type { LintContext, HyperframeLintFinding, OpenTag } from \"../context\";\nimport { readAttr, truncateSnippet } from \"../utils\";\n\nconst TEXTURE_BASE_CLASS = \"hf-texture-text\";\nconst TEXTURE_CLASS_PREFIX = \"hf-texture-\";\n\ntype DropShadowRule = {\n selector: string;\n directlyTargetsTexture: boolean;\n};\n\nfunction classNames(tag: OpenTag): string[] {\n return (readAttr(tag.raw, \"class\") ?? \"\").split(/\\s+/).filter(Boolean);\n}\n\nfunction isTextureMaterialClass(className: string): boolean {\n return className.startsWith(TEXTURE_CLASS_PREFIX) && className !== TEXTURE_BASE_CLASS;\n}\n\nfunction hasInlineMaskImage(tag: OpenTag): boolean {\n const style = readAttr(tag.raw, \"style\") ?? \"\";\n return /\\b(?:-webkit-)?mask-image\\s*:/i.test(style);\n}\n\nfunction hasInlineDropShadow(tag: OpenTag): boolean {\n const style = readAttr(tag.raw, \"style\") ?? \"\";\n return /\\bfilter\\s*:\\s*[^;]*\\bdrop-shadow\\s*\\(/i.test(style);\n}\n\nfunction classNamesInSelector(selector: string): string[] {\n const classes = new Set<string>();\n const pattern = /\\.([A-Za-z_][\\w-]*)/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(selector)) !== null) {\n const className = match[1];\n if (!className) continue;\n classes.add(className);\n }\n return [...classes];\n}\n\nfunction textureClassesInSelector(selector: string): string[] {\n return classNamesInSelector(selector).filter(isTextureMaterialClass);\n}\n\nfunction simpleSelectorMatchesTag(selector: string, tag: OpenTag, tagClasses: string[]): boolean {\n const trimmed = selector.trim();\n const simpleSelectorPattern = /^(?:[A-Za-z][\\w-]*)?(?:\\.[A-Za-z_][\\w-]*)+$/;\n if (!simpleSelectorPattern.test(trimmed)) return false;\n\n const typeMatch = /^([A-Za-z][\\w-]*)/.exec(trimmed);\n if (typeMatch && typeMatch[1]!.toLowerCase() !== tag.name) return false;\n\n const selectorClasses = classNamesInSelector(trimmed);\n return (\n selectorClasses.length > 0 &&\n selectorClasses.every((className) => tagClasses.includes(className))\n );\n}\n\nfunction collectTextureCss(styles: LintContext[\"styles\"]): {\n definedTextureClasses: Set<string>;\n dropShadowRules: DropShadowRule[];\n} {\n const definedTextureClasses = new Set<string>();\n const dropShadowRules: DropShadowRule[] = [];\n const roots: postcss.Root[] = [];\n\n for (const style of styles) {\n let root: postcss.Root;\n try {\n root = postcss.parse(style.content);\n } catch {\n continue;\n }\n roots.push(root);\n\n // fallow-ignore-next-line complexity\n root.walkRules((rule) => {\n const selectors = rule.selectors ?? [];\n let hasMaskImage = false;\n\n for (const node of rule.nodes ?? []) {\n if (node.type !== \"decl\") continue;\n const prop = node.prop.toLowerCase();\n if (prop === \"mask-image\" || prop === \"-webkit-mask-image\") hasMaskImage = true;\n }\n\n if (hasMaskImage) {\n for (const selector of selectors) {\n for (const className of textureClassesInSelector(selector)) {\n definedTextureClasses.add(className);\n }\n }\n }\n });\n }\n\n for (const root of roots) {\n // fallow-ignore-next-line complexity\n root.walkRules((rule) => {\n const selectors = rule.selectors ?? [];\n let hasDropShadow = false;\n\n for (const node of rule.nodes ?? []) {\n if (node.type !== \"decl\") continue;\n if (node.prop.toLowerCase() === \"filter\" && /\\bdrop-shadow\\s*\\(/i.test(node.value)) {\n hasDropShadow = true;\n }\n }\n\n if (hasDropShadow) {\n for (const selector of selectors) {\n const targetsBaseClass = /\\.hf-texture-text\\b/.test(selector);\n const targetsDefinedTextureClass = textureClassesInSelector(selector).some((className) =>\n definedTextureClasses.has(className),\n );\n dropShadowRules.push({\n selector,\n directlyTargetsTexture: targetsBaseClass || targetsDefinedTextureClass,\n });\n }\n }\n });\n }\n\n return { definedTextureClasses, dropShadowRules };\n}\n\n// fallow-ignore-next-line complexity\nexport const textureRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n ({ tags, styles }) => {\n const findings: HyperframeLintFinding[] = [];\n const { definedTextureClasses, dropShadowRules } = collectTextureCss(styles);\n\n for (const { selector, directlyTargetsTexture } of dropShadowRules) {\n if (!directlyTargetsTexture) continue;\n findings.push({\n code: \"texture_drop_shadow_on_text\",\n severity: \"warning\",\n message: \"Drop shadow is applied directly to textured text.\",\n selector,\n fixHint:\n \"Wrap the textured text and apply `filter: drop-shadow(...)` to the wrapper, not the `hf-texture-text` element.\",\n });\n }\n\n for (const tag of tags) {\n if (tag.name === \"style\" || tag.name === \"script\") continue;\n\n const classes = classNames(tag);\n if (classes.length === 0) continue;\n\n const hasBaseClass = classes.includes(TEXTURE_BASE_CLASS);\n const textureClasses = classes.filter(isTextureMaterialClass);\n\n if (textureClasses.length > 0 && !hasBaseClass) {\n findings.push({\n code: \"texture_class_missing_base\",\n severity: \"warning\",\n message: `Texture material class \\`${textureClasses[0]}\\` is used without \\`${TEXTURE_BASE_CLASS}\\`.`,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint: `Add \\`${TEXTURE_BASE_CLASS}\\` alongside the material class, for example \\`class=\"${TEXTURE_BASE_CLASS} ${textureClasses[0]}\"\\`.`,\n snippet: truncateSnippet(tag.raw),\n });\n }\n\n if (hasBaseClass && textureClasses.length === 0 && !hasInlineMaskImage(tag)) {\n findings.push({\n code: \"texture_text_missing_mask\",\n severity: \"warning\",\n message: `\\`${TEXTURE_BASE_CLASS}\\` is used without a texture material class or custom mask image.`,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n \"Add a material class such as `hf-texture-lava`, or set `mask-image` and `-webkit-mask-image` on the element.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n\n for (const textureClass of textureClasses) {\n if (definedTextureClasses.has(textureClass)) continue;\n findings.push({\n code: \"texture_class_unknown\",\n severity: \"error\",\n message: `Texture material class \\`${textureClass}\\` is not defined by local CSS.`,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n \"Paste the Texture Mask Text component `<style>...</style>` block into the composition, or fix the texture class typo.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n\n if (hasBaseClass) {\n for (const rule of dropShadowRules) {\n if (rule.directlyTargetsTexture) continue;\n if (!simpleSelectorMatchesTag(rule.selector, tag, classes)) continue;\n findings.push({\n code: \"texture_drop_shadow_on_text\",\n severity: \"warning\",\n message: \"Drop shadow is applied directly to textured text.\",\n selector: rule.selector,\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n \"Wrap the textured text and apply `filter: drop-shadow(...)` to the wrapper, not the `hf-texture-text` element.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n\n if (hasBaseClass && hasInlineDropShadow(tag)) {\n findings.push({\n code: \"texture_drop_shadow_on_text\",\n severity: \"warning\",\n message: \"Drop shadow is applied directly to textured text.\",\n elementId: readAttr(tag.raw, \"id\") || undefined,\n fixHint:\n \"Wrap the textured text and apply `filter: drop-shadow(...)` to the wrapper, not the `hf-texture-text` element.\",\n snippet: truncateSnippet(tag.raw),\n });\n }\n }\n\n return findings;\n },\n];\n","import { FONT_ALIAS_KEYS, resolveAliasDisplayName } from \"@hyperframes/parsers/composition\";\nimport type { LintContext, HyperframeLintFinding } from \"../context\";\nimport { isRegistrySourceFile, isRegistryInstalledFile } from \"./composition\";\n\nconst GENERIC_FAMILIES = new Set([\n \"serif\",\n \"sans-serif\",\n \"monospace\",\n \"cursive\",\n \"fantasy\",\n \"system-ui\",\n \"ui-serif\",\n \"ui-sans-serif\",\n \"ui-monospace\",\n \"ui-rounded\",\n \"math\",\n \"emoji\",\n \"fangsong\",\n // Vendor-prefixed system-font keywords. Like `system-ui`, the engine resolves\n // these to the OS UI font — they are never installable files and must not be\n // flagged as a missing @font-face, even when a generic fallback follows them\n // (e.g. `-apple-system, system-ui, sans-serif`).\n \"-apple-system\",\n \"blinkmacsystemfont\",\n \"inherit\",\n \"initial\",\n \"unset\",\n \"revert\",\n]);\n\n// A CSS comment can contain a `}` (e.g. `@font-face { /* 400 } regular */\n// font-family: 'X'; ... }`), which truncates the naive `@font-face\\s*\\{[^}]*\\}`\n// block match at the comment's brace — so the rule never sees the real\n// `font-family` and reports a false-positive font_family_without_font_face.\n// Large/\"framework\" stylesheets hit this far more often than minimal ones,\n// which is why a simple <style> passes while a complex one fails. Strip\n// comments before scanning so a brace inside one cannot split a block. See #1534.\nfunction stripCssComments(css: string): string {\n return css.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \");\n}\n\nfunction extractFontFaceFamilies(styles: Array<{ content: string }>): Set<string> {\n const families = new Set<string>();\n const fontFaceRe = /@font-face\\s*\\{[^}]*\\}/gi;\n const familyRe = /font-family\\s*:\\s*(['\"]?)([^;'\"]+)\\1/i;\n for (const style of styles) {\n const content = stripCssComments(style.content);\n let match: RegExpExecArray | null;\n while ((match = fontFaceRe.exec(content)) !== null) {\n const familyMatch = match[0].match(familyRe);\n if (familyMatch?.[2]) {\n families.add(familyMatch[2].trim().toLowerCase());\n }\n }\n }\n return families;\n}\n\n// Normalize one comma-separated font-family entry to a lowercase family name,\n// or null if it carries no resolvable name. `var(--heading)` (or any function\n// token) is an indirection the linter cannot statically resolve, so the literal\n// `var(...)` is not a font name and flagging it is a false positive. Comma-split\n// fallbacks like `var(--x, 'Inter')` also leave a dangling `)` on the fallback\n// part, so skip anything bearing parentheses.\nfunction normalizeUsedFontName(part: string): string | null {\n const name = part\n .trim()\n .replace(/^['\"]|['\"]$/g, \"\")\n .trim()\n .toLowerCase();\n if (!name || name.includes(\"(\") || name.includes(\")\")) return null;\n return name;\n}\n\nfunction extractUsedFontFamilies(styles: Array<{ content: string }>): string[] {\n const used: string[] = [];\n const seen = new Set<string>();\n const propRe = /font-family\\s*:\\s*([^;}{]+)/gi;\n for (const style of styles) {\n const withoutFontFace = stripCssComments(style.content).replace(/@font-face\\s*\\{[^}]*\\}/gi, \"\");\n let match: RegExpExecArray | null;\n while ((match = propRe.exec(withoutFontFace)) !== null) {\n for (const part of match[1]!.split(\",\")) {\n const name = normalizeUsedFontName(part);\n if (name && !GENERIC_FAMILIES.has(name) && !seen.has(name)) {\n seen.add(name);\n used.push(name);\n }\n }\n }\n }\n return used;\n}\n\nfunction collectAliasedFonts(used: string[], declared: Set<string>): string[] {\n const aliased: string[] = [];\n for (const name of used) {\n if (declared.has(name)) continue;\n const displayName = resolveAliasDisplayName(name);\n if (!displayName) continue;\n if (displayName.toLowerCase() === name) continue;\n aliased.push(`'${name}' → ${displayName}`);\n }\n return aliased;\n}\n\nfunction normalizeFontFamily(name: string): string | null {\n const decoded = name.replace(/\\+/g, \" \").trim();\n if (!decoded) return null;\n try {\n return decodeURIComponent(decoded).trim().toLowerCase() || null;\n } catch {\n return decoded.toLowerCase();\n }\n}\n\nfunction extractGoogleFontFamiliesFromUrl(rawUrl: string): string[] {\n const url = rawUrl.replace(/&/gi, \"&\");\n let parsed: URL;\n try {\n parsed = new URL(url, \"https://fonts.googleapis.com\");\n } catch {\n return [];\n }\n\n if (parsed.hostname.toLowerCase() !== \"fonts.googleapis.com\") return [];\n const families: string[] = [];\n for (const value of parsed.searchParams.getAll(\"family\")) {\n for (const familySpec of value.split(\"|\")) {\n const family = normalizeFontFamily(familySpec.split(\":\")[0] || \"\");\n if (family) families.push(family);\n }\n }\n return families;\n}\n\nfunction collectGoogleFontFamilies(\n source: string,\n styles: Array<{ content: string }>,\n): Set<string> {\n const families = new Set<string>();\n const addUrl = (url: string) => {\n for (const family of extractGoogleFontFamiliesFromUrl(url)) families.add(family);\n };\n\n const linkHrefRe =\n /<link\\b[^>]*\\bhref\\s*=\\s*(?:([\"'])([^\"']*fonts\\.googleapis\\.com[^\"']*)\\1|([^\\s>]*fonts\\.googleapis\\.com[^\\s>]*))[^>]*>/gi;\n for (const match of source.matchAll(linkHrefRe)) {\n const href = match[2] || match[3];\n if (href) addUrl(href);\n }\n\n const importUrlRe =\n /@import\\s+(?:url\\(\\s*)?([\"']?)([^\"')\\s]*fonts\\.googleapis\\.com[^\"')\\s]*)\\1\\s*\\)?/gi;\n for (const style of styles) {\n for (const match of style.content.matchAll(importUrlRe)) {\n if (match[2]) addUrl(match[2]);\n }\n }\n\n return families;\n}\n\nexport const fontRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [\n // google_fonts_import\n ({ styles, source, rawSource, options }) => {\n if (isRegistrySourceFile(options.filePath) || isRegistryInstalledFile(rawSource)) return [];\n const findings: HyperframeLintFinding[] = [];\n const googleFontsInLink = /<link\\b[^>]*fonts\\.googleapis\\.com[^>]*>/i.test(source);\n const googleFontsInImport = styles.some((s) =>\n /@import\\s+url\\s*\\(\\s*['\"]?[^)]*fonts\\.googleapis\\.com/i.test(s.content),\n );\n\n if (googleFontsInLink || googleFontsInImport) {\n findings.push({\n code: \"google_fonts_import\",\n severity: \"warning\",\n message:\n \"Composition loads fonts from fonts.googleapis.com. The producer resolves Google Fonts \" +\n \"during compile/render, but raw external font requests add latency and can fail before \" +\n \"canonicalization. Prefer mapped family names or local @font-face declarations when possible.\",\n fixHint:\n \"For bundled fonts, remove the Google Fonts <link> or @import and keep the font-family \" +\n \"declaration. For custom fonts, use @font-face { font-family: '...'; src: url('...woff2'); }.\",\n });\n }\n return findings;\n },\n\n // system_font_will_alias — inform when a font will be silently substituted\n ({ styles, options }) => {\n const declared = extractFontFaceFamilies(styles);\n const used = extractUsedFontFamilies(styles);\n const aliased = collectAliasedFonts(used, declared);\n if (aliased.length === 0) return [];\n // In distributed / Lambda renders system-font capture is disabled, so\n // the alias substitution does NOT happen — elevate to a warning.\n const severity = options.distributed ? (\"warning\" as const) : (\"info\" as const);\n return [\n {\n code: \"system_font_will_alias\",\n severity,\n message:\n `Font ${aliased.length === 1 ? \"family\" : \"families\"} will be substituted at render time: ${aliased.join(\", \")}. ` +\n (options.distributed\n ? \"In distributed/Lambda rendering system-font capture is disabled — these fonts will fall back to OS defaults. Embed explicit @font-face declarations instead.\"\n : \"The renderer maps these to bundled fonts for cross-platform consistency. \" +\n \"Use the target font name directly for consistent preview and render results.\"),\n },\n ];\n },\n\n // font_family_without_font_face\n ({ styles, source, rawSource, options }) => {\n if (isRegistrySourceFile(options.filePath) || isRegistryInstalledFile(rawSource)) return [];\n const findings: HyperframeLintFinding[] = [];\n const declared = extractFontFaceFamilies(styles);\n const used = extractUsedFontFamilies(styles);\n const googleFonts = collectGoogleFontFamilies(source, styles);\n\n const undeclared = used.filter(\n (name) => !declared.has(name) && !FONT_ALIAS_KEYS.has(name) && !googleFonts.has(name),\n );\n if (undeclared.length === 0) return findings;\n\n findings.push({\n code: \"font_family_without_font_face\",\n severity: \"error\",\n message:\n `Font ${undeclared.length === 1 ? \"family\" : \"families\"} used without @font-face declaration: ${undeclared.join(\", \")}. ` +\n \"These are not in the auto-resolved font list, so the renderer cannot supply them automatically. \" +\n \"Text will fall back to a generic font, producing incorrect typography in the video.\",\n fixHint:\n \"Add @font-face { font-family: '...'; src: url('capture/assets/fonts/...woff2'); } \" +\n \"for each font family, pointing to the captured .woff2 files. For an OS-bundled \" +\n \"system font (e.g. Hiragino Sans, Microsoft YaHei) that has no downloadable file, \" +\n \"use src: local('Exact Font Name') instead — the declaration alone satisfies this \" +\n \"check without needing a font file.\",\n });\n return findings;\n },\n];\n","import type { LintContext, HyperframeLintFinding } from \"../context\";\nimport type { LintRule } from \"../types\";\nimport { readAttr } from \"../utils\";\nimport {\n parseSlideshowManifest,\n resolveSlideshow,\n isSceneLikeCompositionId,\n} from \"@hyperframes/parsers/slideshow\";\n\ntype Scene = { id: string; start: number; duration: number };\n\nfunction parseTiming(raw: string): { start: number; duration: number } | null {\n const startStr = readAttr(raw, \"data-start\");\n if (startStr === null) return null;\n const start = Number(startStr);\n if (!Number.isFinite(start)) return null;\n\n const durationStr = readAttr(raw, \"data-duration\");\n if (durationStr !== null) {\n const duration = Number(durationStr);\n if (Number.isFinite(duration)) return { start, duration };\n }\n const endStr = readAttr(raw, \"data-end\") ?? readAttr(raw, \"data-hf-authored-end\");\n if (endStr !== null) {\n const end = Number(endStr);\n if (Number.isFinite(end) && end > start) return { start, duration: end - start };\n }\n return null;\n}\n\nfunction collectCompositionIdScenes(ctx: LintContext, seen: Set<string>, out: Scene[]): void {\n for (const tag of ctx.tags) {\n const compositionId = readAttr(tag.raw, \"data-composition-id\");\n if (!compositionId || !isSceneLikeCompositionId(compositionId) || seen.has(compositionId))\n continue;\n const timing = parseTiming(tag.raw);\n if (!timing || timing.duration <= 0) continue;\n seen.add(compositionId);\n out.push({ id: compositionId, ...timing });\n }\n}\n\nfunction extractScenesFromClips(ctx: LintContext): Scene[] {\n const seen = new Set<string>();\n const scenes: Scene[] = [];\n collectCompositionIdScenes(ctx, seen, scenes);\n return scenes;\n}\n\nexport const slideshowRules: LintRule<LintContext>[] = [\n (ctx) => {\n const findings: HyperframeLintFinding[] = [];\n\n let manifest;\n try {\n manifest = parseSlideshowManifest(ctx.source);\n } catch (e) {\n findings.push({\n code: \"slideshow_invalid\",\n severity: \"error\",\n message: `Slideshow island contains invalid JSON or structure: ${e instanceof Error ? e.message : String(e)}`,\n fixHint:\n 'Ensure the <script type=\"application/hyperframes-slideshow+json\"> block contains valid JSON matching the SlideshowManifest schema.',\n });\n return findings;\n }\n\n if (!manifest) return findings;\n\n const scenes = extractScenesFromClips(ctx);\n const { errors } = resolveSlideshow(manifest, scenes);\n\n for (const error of errors) {\n findings.push({\n code: \"slideshow_unresolved_ref\",\n severity: \"error\",\n message: `Slideshow manifest error: ${error}`,\n fixHint:\n \"Ensure every sceneId in the slideshow island matches the data-composition-id of a scene element in the composition, or provide explicit startTime/endTime.\",\n });\n }\n\n return findings;\n },\n];\n","import type { HyperframeLintFinding, HyperframeLintResult, HyperframeLinterOptions } from \"./types\";\nimport { buildLintContext } from \"./context\";\nimport { readAttr, truncateSnippet } from \"./utils\";\nimport { coreRules } from \"./rules/core\";\nimport { mediaRules } from \"./rules/media\";\nimport { gsapRules } from \"./rules/gsap\";\nimport { captionRules } from \"./rules/captions\";\nimport { compositionRules } from \"./rules/composition\";\nimport { adapterRules } from \"./rules/adapters\";\nimport { textureRules } from \"./rules/textures\";\nimport { fontRules } from \"./rules/fonts\";\nimport { slideshowRules } from \"./rules/slideshow\";\n\nconst ALL_RULES = [\n ...coreRules,\n ...mediaRules,\n ...gsapRules,\n ...captionRules,\n ...compositionRules,\n ...adapterRules,\n ...textureRules,\n ...fontRules,\n ...slideshowRules,\n];\n\nexport async function lintHyperframeHtml(\n html: string,\n options: HyperframeLinterOptions = {},\n): Promise<HyperframeLintResult> {\n const ctx = buildLintContext(html, options);\n const findings: HyperframeLintFinding[] = [];\n const seen = new Set<string>();\n\n for (const rule of ALL_RULES) {\n for (const finding of await Promise.resolve(rule(ctx))) {\n const dedupeKey = [\n finding.code,\n finding.severity,\n finding.selector || \"\",\n finding.elementId || \"\",\n finding.message,\n ].join(\"|\");\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n findings.push(options.filePath ? { ...finding, file: options.filePath } : finding);\n }\n }\n\n const errorCount = findings.filter((f) => f.severity === \"error\").length;\n const warningCount = findings.filter((f) => f.severity === \"warning\").length;\n const infoCount = findings.filter((f) => f.severity === \"info\").length;\n\n return {\n ok: errorCount === 0,\n errorCount,\n warningCount,\n infoCount,\n findings,\n };\n}\n\n// ── Async media URL accessibility checker ─────────────────────────────────\n\nfunction extractMediaUrls(html: string): Array<{\n url: string;\n tagName: string;\n elementId?: string;\n snippet: string;\n}> {\n const results: Array<{\n url: string;\n tagName: string;\n elementId?: string;\n snippet: string;\n }> = [];\n const tagRe = /<(video|audio|img|source)\\b[^>]*>/gi;\n let match: RegExpExecArray | null;\n while ((match = tagRe.exec(html)) !== null) {\n const tagName = (match[1] ?? \"\").toLowerCase();\n const raw = match[0];\n const src = readAttr(raw, \"src\");\n if (!src) continue;\n if (/^https?:\\/\\//i.test(src)) {\n results.push({\n url: src,\n tagName,\n elementId: readAttr(raw, \"id\") || undefined,\n snippet: truncateSnippet(raw) ?? \"\",\n });\n }\n }\n return results;\n}\n\n/**\n * Async lint pass: HEAD-checks every remote media URL in the HTML.\n * Returns findings for URLs that are unreachable (non-2xx status or network error).\n *\n * Call this after `lintHyperframeHtml()` and merge the findings.\n *\n * @param timeoutMs - per-request timeout (default 8000ms)\n */\nexport async function lintMediaUrls(\n html: string,\n options: { timeoutMs?: number } = {},\n): Promise<HyperframeLintFinding[]> {\n const urls = extractMediaUrls(html);\n if (urls.length === 0) return [];\n\n const timeout = options.timeoutMs ?? 8000;\n const findings: HyperframeLintFinding[] = [];\n\n const seen = new Set<string>();\n const unique = urls.filter((u) => {\n if (seen.has(u.url)) return false;\n seen.add(u.url);\n return true;\n });\n\n const checks = unique.map(async ({ url, tagName, elementId, snippet }) => {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n const resp = await fetch(url, {\n method: \"HEAD\",\n signal: controller.signal,\n redirect: \"follow\",\n });\n clearTimeout(timer);\n if (!resp.ok) {\n findings.push({\n code: \"inaccessible_media_url\",\n severity: \"error\",\n message: `<${tagName}${elementId ? ` id=\"${elementId}\"` : \"\"}> references a URL that returned HTTP ${resp.status}: ${url.slice(0, 100)}`,\n elementId,\n fixHint: \"This URL is not accessible. Replace with a valid, reachable media URL.\",\n snippet,\n });\n }\n } catch (err) {\n const reason = err instanceof Error ? err.name : \"unknown\";\n findings.push({\n code: \"inaccessible_media_url\",\n severity: \"error\",\n message: `<${tagName}${elementId ? ` id=\"${elementId}\"` : \"\"}> references an unreachable URL (${reason}): ${url.slice(0, 100)}`,\n elementId,\n fixHint: \"This URL is not accessible. Replace with a valid, reachable media URL.\",\n snippet,\n });\n }\n });\n\n await Promise.all(checks);\n return findings;\n}\n","/**\n * Pure render-gate decision — no Node.js dependencies, so it is safe to import\n * from the browser entry alongside the rule engine.\n */\nexport function shouldBlockRender(\n strictErrors: boolean,\n strictAll: boolean,\n totalErrors: number,\n totalWarnings: number,\n): boolean {\n return (strictErrors && totalErrors > 0) || (strictAll && (totalErrors > 0 || totalWarnings > 0));\n}\n"],"mappings":"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","names":["escapeRegExp","selector","postcss","postcss"]}
|