@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/public-server.js
CHANGED
|
@@ -101982,7 +101982,9 @@ var INVALID_SCRIPT_CLOSE_PATTERN = /<script[^>]*>[\s\S]*?<\s*\/\s*script(?!>)/i;
|
|
|
101982
101982
|
var WINDOW_TIMELINE_ASSIGN_PATTERN = /window\.__timelines\[\s*["']([^"']+)["']\s*\]\s*=\s*([A-Za-z_$][\w$]*)/i;
|
|
101983
101983
|
var META_GSAP_KEYS = /* @__PURE__ */ new Set(["duration", "ease", "repeat", "yoyo", "overwrite", "delay"]);
|
|
101984
101984
|
function lintHyperframeHtml(html, options = {}) {
|
|
101985
|
-
|
|
101985
|
+
let source2 = html || "";
|
|
101986
|
+
const templateMatch = source2.match(/<template[^>]*>([\s\S]*)<\/template>/i);
|
|
101987
|
+
if (templateMatch?.[1]) source2 = templateMatch[1];
|
|
101986
101988
|
const filePath = options.filePath;
|
|
101987
101989
|
const findings = [];
|
|
101988
101990
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -102339,18 +102341,20 @@ ${right2.raw}`)
|
|
|
102339
102341
|
for (const tag of tags) {
|
|
102340
102342
|
if (tag.name === "audio" || tag.name === "script" || tag.name === "style") continue;
|
|
102341
102343
|
if (!readAttr(tag.raw, "data-start")) continue;
|
|
102344
|
+
if (readAttr(tag.raw, "data-composition-id")) continue;
|
|
102345
|
+
if (readAttr(tag.raw, "data-composition-src")) continue;
|
|
102342
102346
|
const classAttr = readAttr(tag.raw, "class") || "";
|
|
102343
102347
|
const styleAttr = readAttr(tag.raw, "style") || "";
|
|
102344
102348
|
const hasClip = classAttr.split(/\s+/).includes("clip");
|
|
102345
|
-
const hasHiddenStyle = /visibility\s*:\s*hidden/i.test(styleAttr);
|
|
102349
|
+
const hasHiddenStyle = /visibility\s*:\s*hidden/i.test(styleAttr) || /opacity\s*:\s*0/i.test(styleAttr);
|
|
102346
102350
|
if (!hasClip && !hasHiddenStyle) {
|
|
102347
102351
|
const elementId = readAttr(tag.raw, "id") || void 0;
|
|
102348
102352
|
pushFinding({
|
|
102349
102353
|
code: "timed_element_missing_visibility_hidden",
|
|
102350
|
-
severity: "
|
|
102351
|
-
message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> has data-start but no class="clip" or
|
|
102354
|
+
severity: "info",
|
|
102355
|
+
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.`,
|
|
102352
102356
|
elementId,
|
|
102353
|
-
fixHint: 'Add class="clip"
|
|
102357
|
+
fixHint: 'Add class="clip" (with CSS: .clip { visibility: hidden; }) or style="opacity:0" if the element should start hidden.',
|
|
102354
102358
|
snippet: truncateSnippet(tag.raw)
|
|
102355
102359
|
});
|
|
102356
102360
|
}
|
|
@@ -102379,6 +102383,76 @@ ${right2.raw}`)
|
|
|
102379
102383
|
});
|
|
102380
102384
|
}
|
|
102381
102385
|
}
|
|
102386
|
+
for (const script of scripts) {
|
|
102387
|
+
const templateLiteralSelectorPattern = /(?:querySelector|querySelectorAll)\s*\(\s*`[^`]*\$\{[^}]+\}[^`]*`\s*\)/g;
|
|
102388
|
+
let tlMatch;
|
|
102389
|
+
while ((tlMatch = templateLiteralSelectorPattern.exec(script.content)) !== null) {
|
|
102390
|
+
pushFinding({
|
|
102391
|
+
code: "template_literal_selector",
|
|
102392
|
+
severity: "error",
|
|
102393
|
+
message: "querySelector uses a template literal variable (e.g. `${compId}`). The HTML bundler's CSS parser crashes on these. Use a hardcoded string instead.",
|
|
102394
|
+
file: filePath,
|
|
102395
|
+
fixHint: "Replace the template literal variable with a hardcoded string. The bundler's CSS parser cannot handle interpolated variables in script content.",
|
|
102396
|
+
snippet: truncateSnippet(tlMatch[0])
|
|
102397
|
+
});
|
|
102398
|
+
}
|
|
102399
|
+
}
|
|
102400
|
+
{
|
|
102401
|
+
const cssTranslateSelectors = /* @__PURE__ */ new Map();
|
|
102402
|
+
const cssScaleSelectors = /* @__PURE__ */ new Map();
|
|
102403
|
+
for (const style of styles) {
|
|
102404
|
+
for (const [, selector, body] of style.content.matchAll(
|
|
102405
|
+
/([#.][a-zA-Z0-9_-]+)\s*\{([^}]+)\}/g
|
|
102406
|
+
)) {
|
|
102407
|
+
const tMatch = body?.match(/transform\s*:\s*([^;]+)/);
|
|
102408
|
+
if (!tMatch || !tMatch[1]) continue;
|
|
102409
|
+
const transformVal = tMatch[1].trim();
|
|
102410
|
+
if (/translate/i.test(transformVal)) {
|
|
102411
|
+
cssTranslateSelectors.set((selector ?? "").trim(), transformVal);
|
|
102412
|
+
}
|
|
102413
|
+
if (/scale/i.test(transformVal)) {
|
|
102414
|
+
cssScaleSelectors.set((selector ?? "").trim(), transformVal);
|
|
102415
|
+
}
|
|
102416
|
+
}
|
|
102417
|
+
}
|
|
102418
|
+
if (cssTranslateSelectors.size > 0 || cssScaleSelectors.size > 0) {
|
|
102419
|
+
for (const script of scripts) {
|
|
102420
|
+
if (!/gsap\.timeline/.test(script.content)) continue;
|
|
102421
|
+
const windows = extractGsapWindows(script.content);
|
|
102422
|
+
const conflicts = /* @__PURE__ */ new Map();
|
|
102423
|
+
for (const win of windows) {
|
|
102424
|
+
if (win.method === "fromTo") continue;
|
|
102425
|
+
const sel = win.targetSelector;
|
|
102426
|
+
const cssKey = sel.startsWith("#") || sel.startsWith(".") ? sel : `#${sel}`;
|
|
102427
|
+
const translateProps = win.properties.filter(
|
|
102428
|
+
(p) => ["x", "y", "xPercent", "yPercent"].includes(p)
|
|
102429
|
+
);
|
|
102430
|
+
const scaleProps = win.properties.filter((p) => p === "scale");
|
|
102431
|
+
const cssFromTranslate = translateProps.length > 0 ? cssTranslateSelectors.get(cssKey) : void 0;
|
|
102432
|
+
const cssFromScale = scaleProps.length > 0 ? cssScaleSelectors.get(cssKey) : void 0;
|
|
102433
|
+
if (!cssFromTranslate && !cssFromScale) continue;
|
|
102434
|
+
const existing = conflicts.get(sel) ?? {
|
|
102435
|
+
cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(" "),
|
|
102436
|
+
props: /* @__PURE__ */ new Set(),
|
|
102437
|
+
raw: win.raw
|
|
102438
|
+
};
|
|
102439
|
+
for (const p of [...translateProps, ...scaleProps]) existing.props.add(p);
|
|
102440
|
+
conflicts.set(sel, existing);
|
|
102441
|
+
}
|
|
102442
|
+
for (const [sel, { cssTransform, props, raw: raw2 }] of conflicts) {
|
|
102443
|
+
const propList = [...props].join("/");
|
|
102444
|
+
pushFinding({
|
|
102445
|
+
code: "gsap_css_transform_conflict",
|
|
102446
|
+
severity: "warning",
|
|
102447
|
+
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.`,
|
|
102448
|
+
selector: sel,
|
|
102449
|
+
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.`,
|
|
102450
|
+
snippet: truncateSnippet(raw2)
|
|
102451
|
+
});
|
|
102452
|
+
}
|
|
102453
|
+
}
|
|
102454
|
+
}
|
|
102455
|
+
}
|
|
102382
102456
|
const errorCount = findings.filter((finding) => finding.severity === "error").length;
|
|
102383
102457
|
const warningCount = findings.length - errorCount;
|
|
102384
102458
|
return {
|
|
@@ -102522,6 +102596,7 @@ function extractGsapWindows(script) {
|
|
|
102522
102596
|
end: animation.position + meta.effectiveDuration,
|
|
102523
102597
|
properties: meta.properties.length > 0 ? meta.properties : Object.keys(animation.properties),
|
|
102524
102598
|
overwriteAuto: meta.overwriteAuto,
|
|
102599
|
+
method: match2[1] ?? "to",
|
|
102525
102600
|
raw: raw2
|
|
102526
102601
|
});
|
|
102527
102602
|
}
|
|
@@ -106960,7 +107035,8 @@ function parseRenderOptions(body) {
|
|
|
106960
107035
|
const debug6 = body.debug === true;
|
|
106961
107036
|
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;
|
|
106962
107037
|
const entryFile = typeof body.entryFile === "string" && body.entryFile.trim().length > 0 ? body.entryFile.trim() : void 0;
|
|
106963
|
-
|
|
107038
|
+
const format3 = ["mp4", "webm"].includes(body.format) ? body.format : void 0;
|
|
107039
|
+
return { outputPath, fps, quality, workers, useGpu, debug: debug6, entryFile, format: format3 };
|
|
106964
107040
|
}
|
|
106965
107041
|
async function prepareRenderBody(body) {
|
|
106966
107042
|
const options = parseRenderOptions(body);
|
|
@@ -107128,6 +107204,7 @@ function createRenderHandlers(options = {}) {
|
|
|
107128
107204
|
const job = createRenderJob({
|
|
107129
107205
|
fps: input2.fps,
|
|
107130
107206
|
quality: input2.quality,
|
|
107207
|
+
format: input2.format,
|
|
107131
107208
|
workers: input2.workers,
|
|
107132
107209
|
useGpu: input2.useGpu,
|
|
107133
107210
|
debug: input2.debug,
|
|
@@ -107231,6 +107308,7 @@ function createRenderHandlers(options = {}) {
|
|
|
107231
107308
|
const job = createRenderJob({
|
|
107232
107309
|
fps: input2.fps,
|
|
107233
107310
|
quality: input2.quality,
|
|
107311
|
+
format: input2.format,
|
|
107234
107312
|
workers: input2.workers,
|
|
107235
107313
|
useGpu: input2.useGpu,
|
|
107236
107314
|
debug: input2.debug,
|