chore: update audit script - different resolutions

This commit is contained in:
2026-08-30 20:59:16 +05:00
parent 2d72848e8e
commit 87dbb200d9
10 changed files with 16316 additions and 135 deletions
+1 -1
View File
@@ -9,7 +9,7 @@
"build": "pnpm --dir web build",
"format": "pnpm --dir web format",
"html": "pnpm --dir refs build && node scripts/extract-static.mjs refs/.next/server/app refs-html",
"dom-audit": "pnpm --dir web refs-dom-audit"
"cdp-audit": "pnpm --dir web refs-cdp-audit:responsive"
},
"keywords": [],
"author": "Ku6epXBOCTuK",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+13 -93
View File
@@ -1,8 +1,8 @@
CDP visual audit
2026-08-30T06:21:12.002Z
2026-08-30T09:31:56.937Z
viewport 1440x900, tolerance 1px, theme light
=== /preview/demo (vs demo.html) — 173 differences ===
=== [1440x900] /preview/demo (vs demo.html) — 173 differences ===
body > main > header [topbar]
position: — → sticky
@@ -13,8 +13,6 @@ body > main > header > a > span:nth-of-type(3) [version] "/ WORKSPACE"
color: #6d7883 [var(--muted)] → #1769d2 [var(--blue)]
body > main > header > div > span > i [status-dot]
w: 6 → 8 (+2px)
h: 6 → 8 (+2px)
width: 6px → 8px
height: 6px → 8px
box-shadow: — → 0 0 0 2px color-mix(in srgb, #25a96a 25%, transparent) [0 0 0 2px color-mix(in srgb, var(--success) 25%, transparent)]
@@ -99,7 +97,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) [preview-stack]
min-width: 0px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) [preview-tile]
w: 276.3 → 564.7 (+288.4px)
display: — → flex
flex-direction: — → column
row-gap: — → 0.3rem
@@ -112,7 +109,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
min-width: 0px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(1) [tile-canvas]
w: 274.3 → 549.9 (+275.6px)
display: grid → —
align-items: center → —
padding-top: 16px → —
@@ -127,9 +123,9 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
background-size: 14px 14px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(1) > div [ph]
w: 193.9 → 439.9 (+246px)
min-width: 0px → —
max-width: 100% → —
w: 193.9 → 439.9 (+246px)
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(2) [tile-label]
align-items: — → baseline
@@ -152,7 +148,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
text-align: right → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) [preview-tile]
w: 276.3 → 564.7 (+288.4px)
display: — → flex
flex-direction: — → column
row-gap: — → 0.3rem
@@ -165,7 +160,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
min-width: 0px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) [tile-canvas]
w: 274.3 → 549.9 (+275.6px)
display: grid → —
align-items: center → —
padding-top: 16px → —
@@ -180,9 +174,9 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
background-size: 14px 14px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) > div [ph]
w: 193.9 → 439.9 (+246px)
min-width: 0px → —
max-width: 100% → —
w: 193.9 → 439.9 (+246px)
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) [tile-label]
align-items: — → baseline
@@ -205,7 +199,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
text-align: right → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(3) [preview-tile]
w: 276.3 → 564.7 (+288.4px)
display: — → flex
flex-direction: — → column
row-gap: — → 0.3rem
@@ -218,7 +211,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
min-width: 0px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(1) [tile-canvas]
w: 274.3 → 549.9 (+275.6px)
display: grid → —
align-items: center → —
padding-top: 16px → —
@@ -233,9 +225,9 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
background-size: 14px 14px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(1) > div [ph]
w: 193.9 → 439.9 (+246px)
min-width: 0px → —
max-width: 100% → —
w: 193.9 → 439.9 (+246px)
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(2) [tile-label]
align-items: — → baseline
@@ -258,7 +250,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
text-align: right → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(4) [preview-tile]
w: 276.3 → 564.7 (+288.4px)
display: — → flex
flex-direction: — → column
row-gap: — → 0.3rem
@@ -271,7 +262,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
min-width: 0px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(4) > div:nth-of-type(1) [tile-canvas]
w: 274.3 → 549.9 (+275.6px)
display: grid → —
align-items: center → —
padding-top: 16px → —
@@ -286,9 +276,9 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
background-size: 14px 14px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(4) > div:nth-of-type(1) > div [ph]
w: 193.9 → 439.9 (+246px)
min-width: 0px → —
max-width: 100% → —
w: 193.9 → 439.9 (+246px)
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(4) > div:nth-of-type(2) [tile-label]
align-items: — → baseline
@@ -311,7 +301,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
text-align: right → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(5) [preview-tile]
w: 276.3 → 564.7 (+288.4px)
display: — → flex
flex-direction: — → column
row-gap: — → 0.3rem
@@ -324,7 +313,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
min-width: 0px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(5) > div:nth-of-type(1) [tile-canvas]
w: 274.3 → 549.9 (+275.6px)
display: grid → —
align-items: center → —
padding-top: 16px → —
@@ -339,9 +327,9 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-typ
background-size: 14px 14px → —
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(5) > div:nth-of-type(1) > div [active ph]
w: 193.9 → 439.9 (+246px)
min-width: 0px → —
max-width: 100% → —
w: 193.9 → 439.9 (+246px)
body > main > div > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(5) > div:nth-of-type(2) [tile-label]
align-items: — → baseline
@@ -381,8 +369,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-typ
text-transform: — → uppercase
body > main > div > section:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(2) > button:nth-of-type(2) [download-btn] "Download result"
w: 478.1 → 191.2 (-286.9px)
h: 42 → 36 (-6px)
display: flex → inline-flex
justify-content: center → —
row-gap: 9px → 8px
@@ -406,7 +392,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-typ
letter-spacing: — → 0.04em
body > main > div > section:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(2) > button:nth-of-type(1) [history-toggle] "Hide intermediate"
w: 145.3 → 456.2 (+310.9px)
margin-top: 0px → 18px
margin-right: 0px → —
margin-bottom: 0px → —
@@ -483,8 +468,6 @@ body > main > div > section:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-typ
line-height: — → 1.5
body > main > div > section:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(2) > button:nth-of-type(3) [icon-btn icon-btn--ghost]
w: 29 → 32 (+3px)
h: 29 → 32 (+3px)
display: grid → inline-flex
justify-content: — → center
padding-top: 6px → —
@@ -608,7 +591,6 @@ body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of
text-transform: — → uppercase
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) > div [color-field]
h: 32 → 27.2 (-4.8px)
row-gap: 8px → 0.4rem
column-gap: 8px → 0.4rem
padding-right: 8px → —
@@ -616,8 +598,6 @@ body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of
height: 32px → —
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) > div > span [swatch]
w: 14 → 25.6 (+11.6px)
h: 14 → 25.6 (+11.6px)
width: 14px → 1.6rem
height: 14px → 1.6rem
@@ -655,9 +635,9 @@ body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of
text-transform: — → uppercase
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > input
w: 155 → 190 (+35px)
font-size: inherit → 16px
line-height: inherit → 1.5
w: 155 → 190 (+35px)
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(3) [control-block]
display: — → flex
@@ -896,9 +876,9 @@ body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of
text-transform: — → uppercase
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(3) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) > input
w: 273.1 → 301.1 (+28px)
font-size: inherit → 16px
line-height: inherit → 1.5
w: 273.1 → 301.1 (+28px)
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(3) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) [control-block]
display: — → flex
@@ -916,7 +896,6 @@ body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of
text-transform: — → uppercase
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(3) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > div [color-field]
h: 32 → 27.2 (-4.8px)
row-gap: 8px → 0.4rem
column-gap: 8px → 0.4rem
padding-right: 8px → —
@@ -924,8 +903,6 @@ body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of
height: 32px → —
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(3) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > div > span [dark swatch]
w: 14 → 25.6 (+11.6px)
h: 14 → 25.6 (+11.6px)
width: 14px → 1.6rem
height: 14px → 1.6rem
@@ -1038,9 +1015,9 @@ body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of
text-transform: — → uppercase
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(4) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) > input
w: 273.1 → 301.1 (+28px)
font-size: inherit → 16px
line-height: inherit → 1.5
w: 273.1 → 301.1 (+28px)
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(4) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) [toggle-row]
display: — → flex
@@ -1058,18 +1035,12 @@ body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of
line-height: — → 1.5
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(4) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > button [on toggle]
w: 32 → 38.4 (+6.4px)
h: 18 → 20.8 (+2.8px)
width: 32px → 2.4rem
height: 18px → 1.3rem
font-size: inherit → 0.85rem
line-height: inherit → 1.5
body > main > div > section:nth-of-type(1) > div:nth-of-type(4) > article:nth-of-type(4) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > button > i [toggle-knob]
x: 603.3 → 703.9 (+100.6px)
y: 1027.4 → 951.6 (-75.8px)
w: 0 → 16.8 (+16.8px)
h: 0 → 16.8 (+16.8px)
position: — → absolute
top: — → 1px
left: — → 1px
@@ -1087,8 +1058,6 @@ body > main > div > section:nth-of-type(1) > div:nth-of-type(5) > button > svg
line-height: inherit → 1.5
body > main > div > section:nth-of-type(1) > div:nth-of-type(5) > span > i [status-dot]
w: 6 → 8 (+2px)
h: 6 → 8 (+2px)
width: 6px → 8px
height: 6px → 8px
box-shadow: — → 0 0 0 2px color-mix(in srgb, #25a96a 25%, transparent) [0 0 0 2px color-mix(in srgb, var(--success) 25%, transparent)]
@@ -1150,7 +1119,7 @@ body >div
✗ present in reference, absent in project
=== /preview/list-tools (vs list-tools.html) — 126 differences ===
=== [1440x900] /preview/list-tools (vs list-tools.html) — 126 differences ===
body > main > header [topbar]
position: — → sticky
@@ -1161,8 +1130,6 @@ body > main > header > a > span:nth-of-type(3) [version] "/ CATALOG"
color: #6d7883 [var(--muted)] → #1769d2 [var(--blue)]
body > main > header > div > span > i [status-dot]
w: 6 → 8 (+2px)
h: 6 → 8 (+2px)
width: 6px → 8px
height: 6px → 8px
box-shadow: — → 0 0 0 2px color-mix(in srgb, #25a96a 25%, transparent) [0 0 0 2px color-mix(in srgb, var(--success) 25%, transparent)]
@@ -1299,7 +1266,6 @@ body > main > div > div:nth-of-type(2) [catalog-toolbar]
padding-bottom: 42px → 1.25rem
body > main > div > div:nth-of-type(2) > label [catalog-search]
w: 420 → 202 (-218px)
display: flex → inline-flex
row-gap: 12px → 0.5rem
column-gap: 12px → 0.5rem
@@ -1310,7 +1276,6 @@ body > main > div > div:nth-of-type(2) > label [catalog-search]
width: min(420px, 100%) → —
body > main > div > div:nth-of-type(2) > label > input
w: 363.1 → 152 (-211.1px)
width: 100% → —
border-top-width: 0px → medium
@@ -1836,7 +1801,7 @@ body >div
✗ present in reference, absent in project
=== /preview/tools/linear-gradient-png (vs gradient.html) — 92 differences ===
=== [1440x900] /preview/tools/linear-gradient-png (vs gradient.html) — 92 differences ===
body > main > header [topbar]
position: — → sticky
@@ -1847,8 +1812,6 @@ body > main > header > a > span:nth-of-type(3) [version] "/ GRADIENT"
color: #6d7883 [var(--muted)] → #1769d2 [var(--blue)]
body > main > header > div > span > i [status-dot]
w: 6 → 8 (+2px)
h: 6 → 8 (+2px)
width: 6px → 8px
height: 6px → 8px
box-shadow: — → 0 0 0 2px color-mix(in srgb, #25a96a 25%, transparent) [0 0 0 2px color-mix(in srgb, var(--success) 25%, transparent)]
@@ -1985,8 +1948,6 @@ body > main > div > div:nth-of-type(2) > span [tool-status] "LIVE PREVIEW"
line-height: — → 1.5
body > main > div > div:nth-of-type(2) > span > i
w: 6 → 0 (-6px)
h: 6 → 20 (+14px)
width: 6px → —
height: 6px → —
background-color: rgb(37, 169, 106) → —
@@ -2049,8 +2010,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
letter-spacing: 0.1em → —
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(2) > div [segmented wide]
w: 402.1 → 1440 (+1037.9px)
h: 32 → 25 (-7px)
display: flex → —
width: 100% → —
height: 32px → —
@@ -2095,7 +2054,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
column-gap: 10px → —
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(3) > div:nth-of-type(1) > div:nth-of-type(1) [color-field]
h: 32 → 25 (-7px)
display: flex → —
align-items: center → —
row-gap: 8px → —
@@ -2105,8 +2063,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
height: 32px → —
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(3) > div:nth-of-type(1) > div:nth-of-type(1) > span [swatch]
w: 14 → 0 (-14px)
h: 14 → 20 (+6px)
width: 14px → —
height: 14px → —
@@ -2123,7 +2079,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
color: #6d7883 [var(--muted)] → #17212b [var(--foreground)]
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(3) > div:nth-of-type(1) > div:nth-of-type(2) [color-field]
h: 32 → 25 (-7px)
display: flex → —
align-items: center → —
row-gap: 8px → —
@@ -2133,8 +2088,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
height: 32px → —
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(3) > div:nth-of-type(1) > div:nth-of-type(2) > span [swatch]
w: 14 → 0 (-14px)
h: 14 → 20 (+6px)
width: 14px → —
height: 14px → —
@@ -2148,7 +2101,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
font-size: — → 16px
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(3) > div:nth-of-type(2) [gradient-bar]
h: 14 → 0 (-14px)
margin-top: 14px → —
height: 14px → —
@@ -2314,8 +2266,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
line-height: — → 1.5
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(6) > span > i
w: 6 → 0 (-6px)
h: 6 → 20 (+14px)
display: inline-block → —
width: 6px → —
height: 6px → —
@@ -2373,8 +2323,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-typ
font-size: — → 16px
body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(2) > button:nth-of-type(2) [download-btn] "Download PNG"
w: 210.6 → 141.3 (-69.3px)
h: 42 → 25 (-17px)
display: flex → —
justify-content: center → —
align-items: center → —
@@ -2419,8 +2367,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-typ
line-height: — → 1.5
body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-type(2) > div > div [art-mark] "PNG"
w: 70 → 1440 (+1370px)
h: 70 → 24 (-46px)
display: grid → —
align-items: center → —
margin-bottom: 12px → —
@@ -2521,7 +2467,7 @@ body >div
✗ present in reference, absent in project
=== /preview/tools/remove-background-png (vs background-remover.html) — 100 differences ===
=== [1440x900] /preview/tools/remove-background-png (vs background-remover.html) — 100 differences ===
body > main > header [topbar]
position: — → sticky
@@ -2532,8 +2478,6 @@ body > main > header > a > span:nth-of-type(3) [version] "/ BACKGROUND REMOVER
color: #6d7883 [var(--muted)] → #1769d2 [var(--blue)]
body > main > header > div > span > i [status-dot]
w: 6 → 8 (+2px)
h: 6 → 8 (+2px)
width: 6px → 8px
height: 6px → 8px
box-shadow: — → 0 0 0 2px color-mix(in srgb, #25a96a 25%, transparent) [0 0 0 2px color-mix(in srgb, var(--success) 25%, transparent)]
@@ -2670,8 +2614,6 @@ body > main > div > div:nth-of-type(2) > span [tool-status] "LIVE PREVIEW"
line-height: — → 1.5
body > main > div > div:nth-of-type(2) > span > i
w: 6 → 0 (-6px)
h: 6 → 20 (+14px)
width: 6px → —
height: 6px → —
background-color: rgb(37, 169, 106) → —
@@ -2734,7 +2676,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
letter-spacing: 0.1em → —
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(1) [color-field]
h: 32 → 28 (-4px)
display: flex → —
align-items: center → —
row-gap: 8px → —
@@ -2744,8 +2685,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
height: 32px → —
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(1) > span [swatch]
w: 14 → 0 (-14px)
h: 14 → 20 (+6px)
width: 14px → —
height: 14px → —
@@ -2759,7 +2698,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
font-size: — → 16px
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(1) > input:nth-of-type(2) [native-color]
w: 151.7 → 50 (-101.7px)
padding-top: 0px → —
padding-right: 0px → —
padding-bottom: 0px → —
@@ -2785,8 +2723,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
line-height: — → 1.5
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(2) > span
w: 9 → 0 (-9px)
h: 9 → 20 (+11px)
width: 9px → —
height: 9px → —
color: #6d7883 [var(--muted)] → #17212b [var(--foreground)]
@@ -2867,8 +2803,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
letter-spacing: 0.1em → —
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(4) > label > b [on toggle]
w: 32 → 0 (-32px)
h: 18 → 20 (+2px)
position: relative → —
width: 32px → —
height: 18px → —
@@ -2914,8 +2848,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
letter-spacing: 0.1em → —
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(5) > label > b [toggle]
w: 32 → 0 (-32px)
h: 18 → 20 (+2px)
position: relative → —
width: 32px → —
height: 18px → —
@@ -2974,8 +2906,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-typ
line-height: — → 1.5
body > main > div > div:nth-of-type(3) > section:nth-of-type(1) > div:nth-of-type(6) > span > i
w: 6 → 0 (-6px)
h: 6 → 20 (+14px)
display: inline-block → —
width: 6px → —
height: 6px → —
@@ -3036,8 +2966,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-typ
line-height: — → 1.5
body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(2) > button [download-btn] "Download result"
w: 193.2 → 131.8 (-61.4px)
h: 42 → 25 (-17px)
display: flex → —
justify-content: center → —
align-items: center → —
@@ -3101,8 +3029,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-typ
background-color: rgb(232, 238, 242) → —
body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(2) > div [subject subject-source]
w: 315.1 → 1440 (+1124.9px)
h: 307.7 → 24 (-283.7px)
display: grid → —
align-items: center → —
width: 74% → —
@@ -3120,8 +3046,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-typ
line-height: — → 1.5
body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(2) > span [canvas-size] "1200 × 800"
x: 875.2 → 0 (-875.2px)
y: 900.8 → 698.9 (-201.9px)
position: absolute → —
right: 10px → —
bottom: 9px → —
@@ -3162,8 +3086,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-typ
min-height: clamp(360px, 30vw, 560px) → —
body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > div [subject]
w: 300.3 → 1440 (+1139.7px)
h: 292.4 → 24 (-268.4px)
display: grid → —
align-items: center → —
width: 74% → —
@@ -3180,8 +3102,6 @@ body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-typ
line-height: — → 1.5
body > main > div > div:nth-of-type(3) > section:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(2) > span [canvas-size] "1200 × 800"
x: 1300.9 → 0 (-1300.9px)
y: 900.8 → 770.9 (-129.9px)
position: absolute → —
right: 10px → —
bottom: 9px → —
+2 -1
View File
@@ -13,7 +13,8 @@
"test": "vitest run",
"format": "prettier --write .",
"lint": "eslint .",
"refs-cdp-audit": "node scripts/audit-cdp.mjs http://localhost:3000/demo.html http://localhost:5173/preview/demo",
"refs-cdp-audit": "node scripts/audit-cdp.mjs",
"refs-cdp-audit:responsive": "node scripts/audit-cdp-responsive.mjs",
"refs-css-audit": "node scripts/audit-css.mjs",
"refs-dom-audit": "node scripts/audit-dom.mjs"
},
+26
View File
@@ -0,0 +1,26 @@
// Runs audit-cdp.mjs across the commonly used desktop / tablet / phone
// resolutions. Same CLI options pass through, e.g.:
// node scripts/audit-cdp-responsive.mjs --route /preview/demo --viewport 390x844
import { spawnSync } from "node:child_process";
const VIEWPORTS = ["2560x1440", "1920x1080", "1440x900", "768x1024", "390x844"];
const args = [];
let viewportSeen = false;
for (let i = 0; i < process.argv.length; i++) {
const v = process.argv[i];
if (v === "--viewport") {
viewportSeen = true;
i++;
} else args.push(v);
}
if (!viewportSeen) args.push("--viewport", VIEWPORTS.join(","));
const r = spawnSync(process.execPath, ["scripts/audit-cdp.mjs", ...args.slice(2)], {
stdio: "inherit",
});
if (r.error) {
console.error(r.error.message);
process.exit(1);
}
process.exit(r.status ?? 1);
+98 -40
View File
@@ -20,7 +20,7 @@ import { writeFileSync, mkdirSync, readdirSync } from "node:fs";
import { resolve, join } from "node:path";
const argv = (() => {
const a = {};
const a = { viewports: [] };
for (let i = 0; i < process.argv.length; i++) {
const v = process.argv[i];
if (v === "--no-serve") a.noServe = true;
@@ -28,6 +28,10 @@ const argv = (() => {
else if (v === "--ref") a.ref = process.argv[++i];
else if (v === "--route") a.route = process.argv[++i];
else if (v === "--port") a.port = Number(process.argv[++i]);
else if (v === "--viewport")
a.viewports.push(
...(process.argv[++i] ?? "").split(",").filter(Boolean),
);
}
return a;
})();
@@ -37,6 +41,35 @@ const PORT = argv.port || 5179;
const REFS_DIR = resolve(WEB, "../refs-html");
const PX_TOL = 1;
// Requested viewports; repeatable/comma-separated "--viewport WxH".
// Deduplicated, preserves order. Defaults to 1440x900 when the flag is absent.
const viewports = (() => {
const raw = argv.viewports.length ? argv.viewports : ["1440x900"];
const out = [];
for (const s of raw) {
const m = /^(\d+)x(\d+)$/.exec(s.trim());
if (!m) {
console.error(`[cdp-audit] invalid viewport: ${s} (expected "WxH")`);
process.exit(1);
}
const vp = { width: +m[1], height: +m[2] };
if (!out.some((o) => o.width === vp.width && o.height === vp.height))
out.push(vp);
}
return out;
})();
const vpLabel = (vp) => `${vp.width}x${vp.height}`;
// Explicit --viewport means per-resolution files; default run keeps the
// backward-compatible single cdp-audit.txt name.
const perResFile = argv.viewports.length > 0;
const reportPath = (vp) =>
resolve(
WEB,
"audit",
perResFile ? `cdp-audit-${vpLabel(vp)}.txt` : "cdp-audit.txt",
);
const PROPS = [
"display",
"position",
@@ -98,13 +131,11 @@ const PROPS = [
// --- capture: open a page and snapshot its tree via getComputedStyle ---
async function capture(browser, target) {
async function capture(browser, target, viewport) {
const url = target.startsWith("http")
? target
: "file:///" + target.replace(/\\/g, "/");
const page = await browser.newPage({
viewport: { width: 1440, height: 900 },
});
const page = await browser.newPage({ viewport });
await page.goto(url, { waitUntil: "networkidle" });
await page.evaluate(async () => {
await document.fonts.ready;
@@ -663,14 +694,7 @@ function diffStyles(a, b) {
`render: node is rendered only on one side ` +
`(no layout box — usually display:none on one side)`,
);
if (a.box && b.box)
for (const k of ["x", "y", "w", "h"]) {
const d = +(b.box[k] - a.box[k]).toFixed(1);
if (Math.abs(d) > PX_TOL && !(flowDriven(a, k) && flowDriven(b, k)))
out.push(
`${k}: ${a.box[k]}${b.box[k]} (${d > 0 ? "+" : ""}${d}px)`,
);
}
// If a side is declared via CSS variables, append the raw declaration so
// the defining rule is easy to find (e.g. "color: var(--accent)").
const fmtSide = (n, k) => {
@@ -680,6 +704,9 @@ function diffStyles(a, b) {
return `${res || "—"} [${r}]`;
return res;
};
// Which style props were already reported as diffs — box axes governed by
// them are redundant then.
const styleDiffKeys = new Set();
for (const k of new Set([
...Object.keys(a.styles),
...Object.keys(b.styles),
@@ -697,8 +724,31 @@ function diffStyles(a, b) {
)
continue;
out.push(`${k}: ${fmtSide(a, k) || "—"}${fmtSide(b, k) || "—"}`);
styleDiffKeys.add(k);
}
}
// Box axes map to style props: w→width, h→height, x→left/right, y→top/bottom.
// If the corresponding style diff is already above, the geometry line is a
// duplicate — drop it. Keep geometry only for changes the styles don't
// explain (e.g. different border/padding with the same declared width).
if (a.box && b.box)
for (const k of ["x", "y", "w", "h"]) {
const gov =
k === "w"
? ["width"]
: k === "h"
? ["height"]
: k === "x"
? ["left", "right"]
: ["top", "bottom"];
if (gov.some((p) => styleDiffKeys.has(p))) continue;
const d = +(b.box[k] - a.box[k]).toFixed(1);
if (Math.abs(d) > PX_TOL && !(flowDriven(a, k) && flowDriven(b, k)))
out.push(
`${k}: ${a.box[k]}${b.box[k]} (${d > 0 ? "+" : ""}${d}px)`,
);
}
return out;
}
@@ -861,16 +911,16 @@ const waitFor = async (url, ms = 60000) => {
throw new Error("dev server not up: " + url);
};
async function auditOne(browser, target) {
async function auditOne(browser, target, viewport) {
const oursUrl = argv.ours || `http://127.0.0.1:${PORT}${target.route}`;
const refUrl = resolve(REFS_DIR, target.ref);
const ours = await capture(browser, oursUrl);
const ref = await capture(browser, refUrl);
const ours = await capture(browser, oursUrl, viewport);
const ref = await capture(browser, refUrl, viewport);
const report = [];
compare(ref, ours, ["body"], report);
return { route: target.route, ref: target.ref, lines: report };
return { route: target.route, ref: target.ref, viewport, lines: report };
}
async function main() {
@@ -896,15 +946,19 @@ async function main() {
const browser = await chromium.launch();
const reports = [];
try {
for (const target of targets) {
try {
const rep = await auditOne(browser, target);
reports.push(rep);
console.log(
`[cdp-audit] ${rep.route} (vs ${rep.ref}): ${rep.lines.length} differences`,
);
} catch (e) {
console.error(`[cdp-audit] ${target.route} failed: ${e.message}`);
for (const vp of viewports) {
for (const target of targets) {
try {
const rep = await auditOne(browser, target, vp);
reports.push(rep);
console.log(
`[cdp-audit] [${vpLabel(vp)}] ${rep.route} (vs ${rep.ref}): ${rep.lines.length} differences`,
);
} catch (e) {
console.error(
`[cdp-audit] [${vpLabel(vp)}] ${target.route} failed: ${e.message}`,
);
}
}
}
} finally {
@@ -920,22 +974,26 @@ async function main() {
}
}
const header =
`CDP visual audit\n${new Date().toISOString()}\n` +
`viewport 1440x900, tolerance ${PX_TOL}px, theme light\n\n`;
const body = reports
.map((r) => {
const title = `=== ${r.route} (vs ${r.ref}) — ${r.lines.length} differences ===`;
if (!r.lines.length) return title + "\n ✅ no differences found";
return title + "\n\n" + r.lines.join("\n\n");
})
.join("\n\n\n");
const outDir = resolve(WEB, "audit");
mkdirSync(outDir, { recursive: true });
const outPath = resolve(outDir, "cdp-audit.txt");
writeFileSync(outPath, header + body + "\n", "utf8");
console.log(`report: web/audit/cdp-audit.txt`);
for (const vp of viewports) {
const vReps = reports.filter(
(r) => r.viewport.width === vp.width && r.viewport.height === vp.height,
);
const header =
`CDP visual audit\n${new Date().toISOString()}\n` +
`viewport ${vpLabel(vp)}, tolerance ${PX_TOL}px, theme light\n\n`;
const body = vReps
.map((r) => {
const title = `=== [${vpLabel(vp)}] ${r.route} (vs ${r.ref}) — ${r.lines.length} differences ===`;
if (!r.lines.length) return title + "\n ✅ no differences found";
return title + "\n\n" + r.lines.join("\n\n");
})
.join("\n\n\n");
const outPath = reportPath(vp);
writeFileSync(outPath, header + body + "\n", "utf8");
console.log(`report: ${outPath}`);
}
}
main().catch((e) => {