hyperframes 0.7.58 → 0.7.59

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.
Files changed (38) hide show
  1. package/dist/cli.js +3434 -2249
  2. package/dist/commands/layout-audit.browser.js +54 -30
  3. package/dist/hyperframe-runtime.js +26 -26
  4. package/dist/hyperframe.manifest.json +1 -1
  5. package/dist/hyperframe.runtime.iife.js +26 -26
  6. package/dist/hyperframes-player.global.js +1 -1
  7. package/dist/skills/hyperframes/SKILL.md +103 -124
  8. package/dist/skills/hyperframes/references/capability-menu.md +47 -0
  9. package/dist/skills/hyperframes/references/pitch-round.md +40 -0
  10. package/dist/skills/hyperframes/references/route-briefs.md +85 -0
  11. package/dist/skills/hyperframes/references/skill-lifecycle.md +33 -0
  12. package/dist/skills/hyperframes/references/workflow-catalog.md +70 -0
  13. package/dist/skills/hyperframes-cli/SKILL.md +99 -109
  14. package/dist/skills/hyperframes-cli/references/beats.md +19 -0
  15. package/dist/skills/hyperframes-cli/references/cloud.md +8 -3
  16. package/dist/skills/hyperframes-cli/references/cloudrun.md +62 -0
  17. package/dist/skills/hyperframes-cli/references/compare-and-batch.md +105 -0
  18. package/dist/skills/hyperframes-cli/references/lambda.md +77 -24
  19. package/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +3 -3
  20. package/dist/skills/hyperframes-cli/references/preview-render.md +4 -0
  21. package/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +2 -0
  22. package/dist/studio/assets/{hyperframes-player-CtTDO63S.js → hyperframes-player-Bm07FLkl.js} +1 -1
  23. package/dist/studio/assets/{index-C47jAC3Q.js → index-B995FG46.js} +1 -1
  24. package/dist/studio/assets/index-CrkAdJkb.js +426 -0
  25. package/dist/studio/assets/index-Dj5p8U_A.css +1 -0
  26. package/dist/studio/assets/{index-DeQPzqwH.js → index-FvzmPhfG.js} +1 -1
  27. package/dist/studio/index.d.ts +12 -3
  28. package/dist/studio/index.html +2 -2
  29. package/dist/studio/index.js +13514 -8528
  30. package/dist/studio/index.js.map +1 -1
  31. package/dist/studio/styles/tailwind-preset.d.ts +5 -0
  32. package/dist/studio/styles/tailwind-preset.js +8 -1
  33. package/dist/studio/styles/tailwind-preset.js.map +1 -1
  34. package/dist/templates/_shared/AGENTS.md +5 -4
  35. package/dist/templates/_shared/CLAUDE.md +5 -4
  36. package/package.json +2 -2
  37. package/dist/studio/assets/index-B_UvTX3E.js +0 -423
  38. package/dist/studio/assets/index-uahwWkgw.css +0 -1
@@ -219,10 +219,10 @@
219
219
  const text = textContentFor(element, directOnly);
220
220
  if (!text) return false;
221
221
  if (directOnly) return true;
222
- for (const child of Array.from(element.children)) {
223
- if (isVisibleElement(child) && textContentFor(child)) return false;
224
- }
225
- return true;
222
+ // Aggregate text may come exclusively from descendants (including hidden
223
+ // captions). The container itself does not paint that text and must not be
224
+ // audited as though it did.
225
+ return textContentFor(element, true).length > 0;
226
226
  }
227
227
 
228
228
  function textClientRects(element, directOnly) {
@@ -436,9 +436,9 @@
436
436
  }
437
437
 
438
438
  function textOverflowIssues(element, root, rootRect, time, tolerance) {
439
- const textRect = textRectFor(element);
439
+ const textRect = textRectFor(element, true);
440
440
  if (!textRect) return [];
441
- const text = textContentFor(element);
441
+ const text = textContentFor(element, true);
442
442
  const selector = selectorFor(element);
443
443
  const issues = [];
444
444
 
@@ -571,7 +571,7 @@
571
571
  // (low colour alpha) is decorative and exempt, as are elements opted out with
572
572
  // data-layout-allow-overlap.
573
573
  function isSolidTextBlock(element) {
574
- if (!isVisibleElement(element) || !hasOwnTextCandidate(element)) return false;
574
+ if (!isVisibleElement(element) || !hasOwnTextCandidate(element, true)) return false;
575
575
  if (hasAllowOverlapFlag(element)) return false;
576
576
  return colorAlpha(getComputedStyle(element).color) >= 0.35;
577
577
  }
@@ -580,8 +580,9 @@
580
580
  const blocks = [];
581
581
  for (const element of Array.from(root.querySelectorAll("*"))) {
582
582
  if (!isSolidTextBlock(element)) continue;
583
- const rect = textRectFor(element);
584
- if (rect) blocks.push({ element, rect });
583
+ const rects = textClientRects(element, true);
584
+ const rect = textRectFor(element, true);
585
+ if (rect) blocks.push({ element, rect, rects });
585
586
  }
586
587
  return blocks;
587
588
  }
@@ -596,6 +597,18 @@
596
597
  return overlapX > 0 && overlapY > 0 ? overlapX * overlapY : 0;
597
598
  }
598
599
 
600
+ function rectsArea(rects) {
601
+ return rects.reduce((total, rect) => total + rectArea(rect), 0);
602
+ }
603
+
604
+ function fragmentIntersectionArea(a, b) {
605
+ let total = 0;
606
+ for (const aRect of a) {
607
+ for (const bRect of b) total += intersectionArea(aRect, bRect);
608
+ }
609
+ return total;
610
+ }
611
+
599
612
  function isNested(a, b) {
600
613
  return a.contains(b) || b.contains(a);
601
614
  }
@@ -631,8 +644,8 @@
631
644
  function overlapIssue(a, b, time) {
632
645
  if (isNested(a.element, b.element)) return null;
633
646
  if (isManagedFlowOverlap(a.element, b.element)) return null;
634
- const area = intersectionArea(a.rect, b.rect);
635
- if (area <= Math.min(rectArea(a.rect), rectArea(b.rect)) * 0.2) return null;
647
+ const area = fragmentIntersectionArea(a.rects, b.rects);
648
+ if (area <= Math.min(rectsArea(a.rects), rectsArea(b.rects)) * 0.2) return null;
636
649
  return {
637
650
  // Warning at the per-sample level: a single-sample overlap is usually an
638
651
  // entrance/exit transient (two blocks crossing mid-animation), not a real
@@ -928,25 +941,32 @@
928
941
  return text.length > 0 && text.length <= ATOMIC_LABEL_MAX_CHARS && !/\s/.test(text);
929
942
  }
930
943
 
931
- // Sweep a grid across the text box (three rows, not just the mid-line, so
932
- // overlays covering only part of a multi-line block are caught). Unlike a
944
+ // Sweep a grid across each painted text fragment (three rows, not just the
945
+ // mid-line, so overlays covering only part of a multi-line block are caught).
946
+ // Sampling fragments instead of their union avoids probing empty line gaps.
947
+ // Unlike a
933
948
  // first-hit scan, this keeps sampling every point so it can report what
934
949
  // fraction of the box is actually covered — a corner nibble on a paragraph
935
950
  // reads very differently from a label buried under an overlay. Still
936
951
  // returns the first opaque element found, for `containerSelector`.
937
- function occlusionCoverage(element, textRect) {
952
+ function occlusionCoverage(element, textRects) {
938
953
  let occluder = null;
939
954
  let hits = 0;
940
- for (const yFraction of OCCLUSION_PROBE_Y_FRACTIONS) {
941
- const y = textRect.top + textRect.height * yFraction;
942
- for (const xFraction of OCCLUSION_PROBE_X_FRACTIONS) {
943
- const hit = occluderAt(element, textRect.left + textRect.width * xFraction, y);
944
- if (!hit) continue;
945
- hits += 1;
946
- if (!occluder) occluder = hit;
955
+ for (const textRect of textRects) {
956
+ for (const yFraction of OCCLUSION_PROBE_Y_FRACTIONS) {
957
+ const y = textRect.top + textRect.height * yFraction;
958
+ for (const xFraction of OCCLUSION_PROBE_X_FRACTIONS) {
959
+ const hit = occluderAt(element, textRect.left + textRect.width * xFraction, y);
960
+ if (!hit) continue;
961
+ hits += 1;
962
+ if (!occluder) occluder = hit;
963
+ }
947
964
  }
948
965
  }
949
- return { occluder, coveredFraction: round(hits / OCCLUSION_GRID_POINTS) };
966
+ return {
967
+ occluder,
968
+ coveredFraction: round(hits / (OCCLUSION_GRID_POINTS * textRects.length)),
969
+ };
950
970
  }
951
971
 
952
972
  // pointer-events:none hides elements from elementFromPoint — both probed text AND occluders.
@@ -983,10 +1003,14 @@
983
1003
  function occludedTextIssue(element, time) {
984
1004
  if (hasAllowOcclusionFlag(element)) return null;
985
1005
  if (!hasVisibleTextInk(element)) return null;
986
- const textRect = textRectFor(element);
1006
+ const textRect = textRectFor(element, true);
987
1007
  if (!textRect) return null;
988
- const text = textContentFor(element);
989
- const { occluder, coveredFraction } = occlusionCoverage(element, textRect);
1008
+ const textRects = textClientRects(element, true);
1009
+ const text = textContentFor(element, true);
1010
+ const { occluder, coveredFraction } = occlusionCoverage(
1011
+ element,
1012
+ textRects.length > 0 ? textRects : [textRect],
1013
+ );
990
1014
  if (!occluder) return null;
991
1015
  if (!isAtomicLabel(text) && coveredFraction < PROSE_COVERAGE_FLOOR) return null;
992
1016
  return {
@@ -1016,9 +1040,9 @@
1016
1040
  // paints the glyphs; a `background-clip: text` with no gradient/image and no
1017
1041
  // opaque background-color paints nothing, so it stays reportable.
1018
1042
  function invisibleTextIssue(element, time) {
1019
- const textRect = textRectFor(element);
1043
+ const textRect = textRectFor(element, true);
1020
1044
  if (!textRect) return null;
1021
- const text = textContentFor(element);
1045
+ const text = textContentFor(element, true);
1022
1046
  if (!text) return null;
1023
1047
  const cs = getComputedStyle(element);
1024
1048
  // Vendor computed-style props are read by property (camelCase), matching
@@ -1141,8 +1165,8 @@
1141
1165
  if (escapedElements.has(element)) continue;
1142
1166
  // Ownership is geometric and strict-mutex: any text breach past canvas_overflow's own
1143
1167
  // tolerance cedes the element to canvas_overflow; in-bounds text leaves the panel finding.
1144
- if (hasOwnTextCandidate(element)) {
1145
- const textRect = textRectFor(element);
1168
+ if (hasOwnTextCandidate(element, true)) {
1169
+ const textRect = textRectFor(element, true);
1146
1170
  if (textRect && overflowFor(textRect, rootRect, tolerance)) continue;
1147
1171
  }
1148
1172
  const rect = toRect(element.getBoundingClientRect());
@@ -1372,7 +1396,7 @@
1372
1396
  document.body;
1373
1397
  const rootRect = rootRectFor(root);
1374
1398
  const elements = Array.from(root.querySelectorAll("*")).filter((element) =>
1375
- isVisibleElement(element),
1399
+ isVisibleElement(element, 0.05),
1376
1400
  );
1377
1401
  const issues = [];
1378
1402