mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
fix(producer): preserve @import rules during CSS composition scoping
scopeCssToComposition corrupted @import url() rules because they have
no {} block. The selector regex ([^{}@]+)\{ treated the text after @
as a selector, producing invalid CSS like:
@[data-composition-id="x"] import url('...')
This broke font loading, CSS variable resolution, and all composition
styling in rendered output.
Fix: extract @import rules before running the scoping regex, then
prepend them back unmodified.
Also adds:
- Regression test fixture (css-import-scoping)
- Common-mistakes docs: autoplay/loop, GSAP TextPlugin, sub-composition
positioning
- Format fix for hyperframeLinter.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
e6a643ac1d
commit
d3c6228d89
@@ -391,23 +391,27 @@ export function lintHyperframeHtml(
|
||||
}
|
||||
}
|
||||
|
||||
// #3.7: Inline base64 audio/video — PROHIBITED
|
||||
// Base64 audio/video bloats file size and breaks rendering. Use URLs or relative paths.
|
||||
// #3.7: Fabricated inline base64 media — CRITICAL
|
||||
// Inline base64 audio/video data is almost always fabricated garbage that
|
||||
// won't play. Real audio files are 100KB+ when base64-encoded.
|
||||
{
|
||||
const base64MediaRe =
|
||||
/src\s*=\s*["'](data:(?:audio|video)\/[^;]+;base64,([A-Za-z0-9+/=]{20,}))["']/gi;
|
||||
/src\s*=\s*["'](data:(?:audio|video)\/[^;]+;base64,([A-Za-z0-9+/=]{100,}))["']/gi;
|
||||
let b64Match: RegExpExecArray | null;
|
||||
while ((b64Match = base64MediaRe.exec(source)) !== null) {
|
||||
// Check if it's suspiciously repetitive (fake data has long runs of repeated chars)
|
||||
const sample = (b64Match[2] || "").slice(0, 200);
|
||||
const uniqueChars = new Set(sample.replace(/[A-Za-z0-9+/=]/g, (c) => c)).size;
|
||||
const dataSize = Math.round(((b64Match[2] || "").length * 3) / 4);
|
||||
const isSuspicious = uniqueChars < 15 || (dataSize > 1000 && dataSize < 50000);
|
||||
// Any embedded base64 audio is suspicious — real audio should be a file
|
||||
pushFinding({
|
||||
code: "base64_media_prohibited",
|
||||
severity: "error",
|
||||
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.`,
|
||||
fixHint:
|
||||
"Use a relative path (assets/music.mp3) or HTTPS URL for the audio/video src. Never embed media as base64.",
|
||||
code: "fabricated_inline_media",
|
||||
severity: isSuspicious ? "error" : "warning",
|
||||
message: isSuspicious
|
||||
? `Fabricated base64 media detected (${(dataSize / 1024).toFixed(0)} KB). This is almost certainly fake data that won't play.`
|
||||
: `Embedded base64 audio/video detected (${(dataSize / 1024).toFixed(0)} KB). Consider using a file URL instead.`,
|
||||
fixHint: "Remove the data: URI and use a real media file URL instead.",
|
||||
snippet: truncateSnippet((b64Match[1] ?? "").slice(0, 80) + "..."),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user