@hyperframes/producer 0.1.9 → 0.1.11
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/index.js +84 -6
- package/dist/index.js.map +3 -3
- package/dist/public-server.js +84 -6
- package/dist/public-server.js.map +3 -3
- package/dist/server.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -99193,7 +99193,9 @@ var INVALID_SCRIPT_CLOSE_PATTERN = /<script[^>]*>[\s\S]*?<\s*\/\s*script(?!>)/i;
|
|
|
99193
99193
|
var WINDOW_TIMELINE_ASSIGN_PATTERN = /window\.__timelines\[\s*["']([^"']+)["']\s*\]\s*=\s*([A-Za-z_$][\w$]*)/i;
|
|
99194
99194
|
var META_GSAP_KEYS = /* @__PURE__ */ new Set(["duration", "ease", "repeat", "yoyo", "overwrite", "delay"]);
|
|
99195
99195
|
function lintHyperframeHtml(html, options = {}) {
|
|
99196
|
-
|
|
99196
|
+
let source2 = html || "";
|
|
99197
|
+
const templateMatch = source2.match(/<template[^>]*>([\s\S]*)<\/template>/i);
|
|
99198
|
+
if (templateMatch?.[1]) source2 = templateMatch[1];
|
|
99197
99199
|
const filePath = options.filePath;
|
|
99198
99200
|
const findings = [];
|
|
99199
99201
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -99550,18 +99552,20 @@ ${right2.raw}`)
|
|
|
99550
99552
|
for (const tag of tags) {
|
|
99551
99553
|
if (tag.name === "audio" || tag.name === "script" || tag.name === "style") continue;
|
|
99552
99554
|
if (!readAttr(tag.raw, "data-start")) continue;
|
|
99555
|
+
if (readAttr(tag.raw, "data-composition-id")) continue;
|
|
99556
|
+
if (readAttr(tag.raw, "data-composition-src")) continue;
|
|
99553
99557
|
const classAttr = readAttr(tag.raw, "class") || "";
|
|
99554
99558
|
const styleAttr = readAttr(tag.raw, "style") || "";
|
|
99555
99559
|
const hasClip = classAttr.split(/\s+/).includes("clip");
|
|
99556
|
-
const hasHiddenStyle = /visibility\s*:\s*hidden/i.test(styleAttr);
|
|
99560
|
+
const hasHiddenStyle = /visibility\s*:\s*hidden/i.test(styleAttr) || /opacity\s*:\s*0/i.test(styleAttr);
|
|
99557
99561
|
if (!hasClip && !hasHiddenStyle) {
|
|
99558
99562
|
const elementId = readAttr(tag.raw, "id") || void 0;
|
|
99559
99563
|
pushFinding({
|
|
99560
99564
|
code: "timed_element_missing_visibility_hidden",
|
|
99561
|
-
severity: "
|
|
99562
|
-
message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> has data-start but no class="clip" or
|
|
99565
|
+
severity: "info",
|
|
99566
|
+
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.`,
|
|
99563
99567
|
elementId,
|
|
99564
|
-
fixHint: 'Add class="clip"
|
|
99568
|
+
fixHint: 'Add class="clip" (with CSS: .clip { visibility: hidden; }) or style="opacity:0" if the element should start hidden.',
|
|
99565
99569
|
snippet: truncateSnippet(tag.raw)
|
|
99566
99570
|
});
|
|
99567
99571
|
}
|
|
@@ -99590,6 +99594,76 @@ ${right2.raw}`)
|
|
|
99590
99594
|
});
|
|
99591
99595
|
}
|
|
99592
99596
|
}
|
|
99597
|
+
for (const script of scripts) {
|
|
99598
|
+
const templateLiteralSelectorPattern = /(?:querySelector|querySelectorAll)\s*\(\s*`[^`]*\$\{[^}]+\}[^`]*`\s*\)/g;
|
|
99599
|
+
let tlMatch;
|
|
99600
|
+
while ((tlMatch = templateLiteralSelectorPattern.exec(script.content)) !== null) {
|
|
99601
|
+
pushFinding({
|
|
99602
|
+
code: "template_literal_selector",
|
|
99603
|
+
severity: "error",
|
|
99604
|
+
message: "querySelector uses a template literal variable (e.g. `${compId}`). The HTML bundler's CSS parser crashes on these. Use a hardcoded string instead.",
|
|
99605
|
+
file: filePath,
|
|
99606
|
+
fixHint: "Replace the template literal variable with a hardcoded string. The bundler's CSS parser cannot handle interpolated variables in script content.",
|
|
99607
|
+
snippet: truncateSnippet(tlMatch[0])
|
|
99608
|
+
});
|
|
99609
|
+
}
|
|
99610
|
+
}
|
|
99611
|
+
{
|
|
99612
|
+
const cssTranslateSelectors = /* @__PURE__ */ new Map();
|
|
99613
|
+
const cssScaleSelectors = /* @__PURE__ */ new Map();
|
|
99614
|
+
for (const style of styles) {
|
|
99615
|
+
for (const [, selector, body] of style.content.matchAll(
|
|
99616
|
+
/([#.][a-zA-Z0-9_-]+)\s*\{([^}]+)\}/g
|
|
99617
|
+
)) {
|
|
99618
|
+
const tMatch = body?.match(/transform\s*:\s*([^;]+)/);
|
|
99619
|
+
if (!tMatch || !tMatch[1]) continue;
|
|
99620
|
+
const transformVal = tMatch[1].trim();
|
|
99621
|
+
if (/translate/i.test(transformVal)) {
|
|
99622
|
+
cssTranslateSelectors.set((selector ?? "").trim(), transformVal);
|
|
99623
|
+
}
|
|
99624
|
+
if (/scale/i.test(transformVal)) {
|
|
99625
|
+
cssScaleSelectors.set((selector ?? "").trim(), transformVal);
|
|
99626
|
+
}
|
|
99627
|
+
}
|
|
99628
|
+
}
|
|
99629
|
+
if (cssTranslateSelectors.size > 0 || cssScaleSelectors.size > 0) {
|
|
99630
|
+
for (const script of scripts) {
|
|
99631
|
+
if (!/gsap\.timeline/.test(script.content)) continue;
|
|
99632
|
+
const windows = extractGsapWindows(script.content);
|
|
99633
|
+
const conflicts = /* @__PURE__ */ new Map();
|
|
99634
|
+
for (const win of windows) {
|
|
99635
|
+
if (win.method === "fromTo") continue;
|
|
99636
|
+
const sel = win.targetSelector;
|
|
99637
|
+
const cssKey = sel.startsWith("#") || sel.startsWith(".") ? sel : `#${sel}`;
|
|
99638
|
+
const translateProps = win.properties.filter(
|
|
99639
|
+
(p) => ["x", "y", "xPercent", "yPercent"].includes(p)
|
|
99640
|
+
);
|
|
99641
|
+
const scaleProps = win.properties.filter((p) => p === "scale");
|
|
99642
|
+
const cssFromTranslate = translateProps.length > 0 ? cssTranslateSelectors.get(cssKey) : void 0;
|
|
99643
|
+
const cssFromScale = scaleProps.length > 0 ? cssScaleSelectors.get(cssKey) : void 0;
|
|
99644
|
+
if (!cssFromTranslate && !cssFromScale) continue;
|
|
99645
|
+
const existing = conflicts.get(sel) ?? {
|
|
99646
|
+
cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(" "),
|
|
99647
|
+
props: /* @__PURE__ */ new Set(),
|
|
99648
|
+
raw: win.raw
|
|
99649
|
+
};
|
|
99650
|
+
for (const p of [...translateProps, ...scaleProps]) existing.props.add(p);
|
|
99651
|
+
conflicts.set(sel, existing);
|
|
99652
|
+
}
|
|
99653
|
+
for (const [sel, { cssTransform, props, raw: raw2 }] of conflicts) {
|
|
99654
|
+
const propList = [...props].join("/");
|
|
99655
|
+
pushFinding({
|
|
99656
|
+
code: "gsap_css_transform_conflict",
|
|
99657
|
+
severity: "warning",
|
|
99658
|
+
message: `"${sel}" has CSS \`transform: ${cssTransform}\` and a GSAP tween animates ${propList}. GSAP will overwrite the full CSS transform, discarding any translateX(-50%) centering or CSS scale value.`,
|
|
99659
|
+
selector: sel,
|
|
99660
|
+
fixHint: `Remove the transform from CSS and use tl.fromTo('${sel}', { xPercent: -50, x: -1000 }, { xPercent: -50, x: 0 }) so GSAP owns the full transform state. tl.fromTo is exempt from this rule.`,
|
|
99661
|
+
snippet: truncateSnippet(raw2)
|
|
99662
|
+
});
|
|
99663
|
+
}
|
|
99664
|
+
}
|
|
99665
|
+
}
|
|
99666
|
+
}
|
|
99593
99667
|
const errorCount = findings.filter((finding) => finding.severity === "error").length;
|
|
99594
99668
|
const warningCount = findings.length - errorCount;
|
|
99595
99669
|
return {
|
|
@@ -99733,6 +99807,7 @@ function extractGsapWindows(script) {
|
|
|
99733
99807
|
end: animation.position + meta.effectiveDuration,
|
|
99734
99808
|
properties: meta.properties.length > 0 ? meta.properties : Object.keys(animation.properties),
|
|
99735
99809
|
overwriteAuto: meta.overwriteAuto,
|
|
99810
|
+
method: match2[1] ?? "to",
|
|
99736
99811
|
raw: raw2
|
|
99737
99812
|
});
|
|
99738
99813
|
}
|
|
@@ -106959,7 +107034,8 @@ function parseRenderOptions(body) {
|
|
|
106959
107034
|
const debug6 = body.debug === true;
|
|
106960
107035
|
const outputPath = typeof body.outputPath === "string" && body.outputPath.trim().length > 0 ? body.outputPath : typeof body.output === "string" && body.output.trim().length > 0 ? body.output : null;
|
|
106961
107036
|
const entryFile = typeof body.entryFile === "string" && body.entryFile.trim().length > 0 ? body.entryFile.trim() : void 0;
|
|
106962
|
-
|
|
107037
|
+
const format3 = ["mp4", "webm"].includes(body.format) ? body.format : void 0;
|
|
107038
|
+
return { outputPath, fps, quality, workers, useGpu, debug: debug6, entryFile, format: format3 };
|
|
106963
107039
|
}
|
|
106964
107040
|
async function prepareRenderBody(body) {
|
|
106965
107041
|
const options = parseRenderOptions(body);
|
|
@@ -107127,6 +107203,7 @@ function createRenderHandlers(options = {}) {
|
|
|
107127
107203
|
const job = createRenderJob({
|
|
107128
107204
|
fps: input2.fps,
|
|
107129
107205
|
quality: input2.quality,
|
|
107206
|
+
format: input2.format,
|
|
107130
107207
|
workers: input2.workers,
|
|
107131
107208
|
useGpu: input2.useGpu,
|
|
107132
107209
|
debug: input2.debug,
|
|
@@ -107230,6 +107307,7 @@ function createRenderHandlers(options = {}) {
|
|
|
107230
107307
|
const job = createRenderJob({
|
|
107231
107308
|
fps: input2.fps,
|
|
107232
107309
|
quality: input2.quality,
|
|
107310
|
+
format: input2.format,
|
|
107233
107311
|
workers: input2.workers,
|
|
107234
107312
|
useGpu: input2.useGpu,
|
|
107235
107313
|
debug: input2.debug,
|