@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 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
- const source2 = html || "";
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: "warning",
99562
- message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> has data-start but no class="clip" or visibility:hidden. The framework needs elements to start hidden so it can manage their lifecycle.`,
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" to the element (with CSS: .clip { visibility: hidden; }).',
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
- return { outputPath, fps, quality, workers, useGpu, debug: debug6, entryFile };
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,