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.
- package/dist/cli.js +3434 -2249
- package/dist/commands/layout-audit.browser.js +54 -30
- package/dist/hyperframe-runtime.js +26 -26
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +26 -26
- package/dist/hyperframes-player.global.js +1 -1
- package/dist/skills/hyperframes/SKILL.md +103 -124
- package/dist/skills/hyperframes/references/capability-menu.md +47 -0
- package/dist/skills/hyperframes/references/pitch-round.md +40 -0
- package/dist/skills/hyperframes/references/route-briefs.md +85 -0
- package/dist/skills/hyperframes/references/skill-lifecycle.md +33 -0
- package/dist/skills/hyperframes/references/workflow-catalog.md +70 -0
- package/dist/skills/hyperframes-cli/SKILL.md +99 -109
- package/dist/skills/hyperframes-cli/references/beats.md +19 -0
- package/dist/skills/hyperframes-cli/references/cloud.md +8 -3
- package/dist/skills/hyperframes-cli/references/cloudrun.md +62 -0
- package/dist/skills/hyperframes-cli/references/compare-and-batch.md +105 -0
- package/dist/skills/hyperframes-cli/references/lambda.md +77 -24
- package/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +3 -3
- package/dist/skills/hyperframes-cli/references/preview-render.md +4 -0
- package/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +2 -0
- package/dist/studio/assets/{hyperframes-player-CtTDO63S.js → hyperframes-player-Bm07FLkl.js} +1 -1
- package/dist/studio/assets/{index-C47jAC3Q.js → index-B995FG46.js} +1 -1
- package/dist/studio/assets/index-CrkAdJkb.js +426 -0
- package/dist/studio/assets/index-Dj5p8U_A.css +1 -0
- package/dist/studio/assets/{index-DeQPzqwH.js → index-FvzmPhfG.js} +1 -1
- package/dist/studio/index.d.ts +12 -3
- package/dist/studio/index.html +2 -2
- package/dist/studio/index.js +13514 -8528
- package/dist/studio/index.js.map +1 -1
- package/dist/studio/styles/tailwind-preset.d.ts +5 -0
- package/dist/studio/styles/tailwind-preset.js +8 -1
- package/dist/studio/styles/tailwind-preset.js.map +1 -1
- package/dist/templates/_shared/AGENTS.md +5 -4
- package/dist/templates/_shared/CLAUDE.md +5 -4
- package/package.json +2 -2
- package/dist/studio/assets/index-B_UvTX3E.js +0 -423
- 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
|
-
|
|
223
|
-
|
|
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
|
|
584
|
-
|
|
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 =
|
|
635
|
-
if (area <= Math.min(
|
|
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
|
|
932
|
-
// overlays covering only part of a multi-line block are caught).
|
|
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,
|
|
952
|
+
function occlusionCoverage(element, textRects) {
|
|
938
953
|
let occluder = null;
|
|
939
954
|
let hits = 0;
|
|
940
|
-
for (const
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
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 {
|
|
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
|
|
989
|
-
const
|
|
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
|
|