nimiq-branding-cli 1.0.0

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 (242) hide show
  1. package/LICENSE +25 -0
  2. package/NOTICE.md +32 -0
  3. package/README.md +73 -0
  4. package/assets/css/legacy/nimiq-style.icons.svg +1 -0
  5. package/assets/css/legacy/nimiq-style.min.css +5 -0
  6. package/assets/css/modern/animations.css +179 -0
  7. package/assets/css/modern/atomic.css +148 -0
  8. package/assets/css/modern/colors.css +82 -0
  9. package/assets/css/modern/fonts.css +17 -0
  10. package/assets/css/modern/index.css +8 -0
  11. package/assets/css/modern/preflight.css +190 -0
  12. package/assets/css/modern/spacing.css +1023 -0
  13. package/assets/css/modern/static-content.css +300 -0
  14. package/assets/css/modern/typography.css +632 -0
  15. package/assets/css/modern/utilities.css +861 -0
  16. package/assets/fonts/mulish-0b696a2e.woff2 +0 -0
  17. package/assets/fonts/mulish-294ced17.woff2 +0 -0
  18. package/assets/fonts/mulish-4eb440e1.woff2 +0 -0
  19. package/assets/fonts/mulish-78a2d471.woff2 +0 -0
  20. package/assets/fonts/mulish-81f6c1ba.woff2 +0 -0
  21. package/assets/fonts/mulish-c1a61bc6.woff2 +0 -0
  22. package/assets/fonts/mulish-c7803f2b.woff2 +0 -0
  23. package/assets/fonts/mulish-e64de9e7.woff2 +0 -0
  24. package/assets/fonts/mulish-ecf98336.woff2 +0 -0
  25. package/assets/fonts/mulish-f727ad98.woff2 +0 -0
  26. package/assets/icons/duotone/duotone-arrow-to-top-left-from-corner.svg +1 -0
  27. package/assets/icons/duotone/duotone-bank-building.svg +1 -0
  28. package/assets/icons/duotone/duotone-bell.svg +1 -0
  29. package/assets/icons/duotone/duotone-block-stairs.svg +1 -0
  30. package/assets/icons/duotone/duotone-btc-invoice.svg +1 -0
  31. package/assets/icons/duotone/duotone-cactus.svg +1 -0
  32. package/assets/icons/duotone/duotone-cash-register.svg +1 -0
  33. package/assets/icons/duotone/duotone-column-chart.svg +1 -0
  34. package/assets/icons/duotone/duotone-credit-card.svg +1 -0
  35. package/assets/icons/duotone/duotone-crypto-currencies-btc-eth.svg +1 -0
  36. package/assets/icons/duotone/duotone-crypto-currencies-btc-usdc.svg +1 -0
  37. package/assets/icons/duotone/duotone-cryptos-pizza.svg +1 -0
  38. package/assets/icons/duotone/duotone-dashboard.svg +1 -0
  39. package/assets/icons/duotone/duotone-displaced-hamburguer.svg +1 -0
  40. package/assets/icons/duotone/duotone-document-text.svg +1 -0
  41. package/assets/icons/duotone/duotone-document-vertical-line.svg +1 -0
  42. package/assets/icons/duotone/duotone-document.svg +1 -0
  43. package/assets/icons/duotone/duotone-employee.svg +1 -0
  44. package/assets/icons/duotone/duotone-envelope.svg +1 -0
  45. package/assets/icons/duotone/duotone-fiat-currencies.svg +1 -0
  46. package/assets/icons/duotone/duotone-fiat-exchange.svg +1 -0
  47. package/assets/icons/duotone/duotone-fluctuations.svg +1 -0
  48. package/assets/icons/duotone/duotone-gamepad.svg +1 -0
  49. package/assets/icons/duotone/duotone-globe.svg +1 -0
  50. package/assets/icons/duotone/duotone-group.svg +1 -0
  51. package/assets/icons/duotone/duotone-handshake.svg +1 -0
  52. package/assets/icons/duotone/duotone-high-five.svg +1 -0
  53. package/assets/icons/duotone/duotone-htlc-box.svg +1 -0
  54. package/assets/icons/duotone/duotone-incognito.svg +1 -0
  55. package/assets/icons/duotone/duotone-key-puzzle.svg +1 -0
  56. package/assets/icons/duotone/duotone-languages.svg +1 -0
  57. package/assets/icons/duotone/duotone-magnifying-glass.svg +1 -0
  58. package/assets/icons/duotone/duotone-medal.svg +1 -0
  59. package/assets/icons/duotone/duotone-network.svg +1 -0
  60. package/assets/icons/duotone/duotone-nim-phone.svg +1 -0
  61. package/assets/icons/duotone/duotone-nimiq-environment.svg +1 -0
  62. package/assets/icons/duotone/duotone-no-chargeback.svg +1 -0
  63. package/assets/icons/duotone/duotone-oasis-puzzle.svg +1 -0
  64. package/assets/icons/duotone/duotone-paper-plane.svg +1 -0
  65. package/assets/icons/duotone/duotone-peer-to-peer.svg +1 -0
  66. package/assets/icons/duotone/duotone-pin-with-shadow.svg +1 -0
  67. package/assets/icons/duotone/duotone-safe-lock.svg +1 -0
  68. package/assets/icons/duotone/duotone-smart-contract.svg +1 -0
  69. package/assets/icons/duotone/duotone-sparkling-swap.svg +1 -0
  70. package/assets/icons/duotone/duotone-speedmeter.svg +1 -0
  71. package/assets/icons/duotone/duotone-staking-ripple.svg +1 -0
  72. package/assets/icons/duotone/duotone-successful-sequence.svg +1 -0
  73. package/assets/icons/duotone/duotone-three-hands-hexagon.svg +1 -0
  74. package/assets/icons/nimiq-flags.json +1274 -0
  75. package/assets/icons/nimiq-icons.json +1631 -0
  76. package/assets/img/bg-hexagons.svg +1 -0
  77. package/assets/img/cpl-preview.webp +0 -0
  78. package/assets/img/gods-light.webp +0 -0
  79. package/assets/img/iqons.min.svg +1 -0
  80. package/assets/img/multisig-preview.svg +1 -0
  81. package/assets/img/nimiq-pay-preview.webp +0 -0
  82. package/assets/img/nimiq-wallet-preview.webp +0 -0
  83. package/assets/img/world-map.svg +1 -0
  84. package/assets/logos/nimiq-icons-logos/logos-bitcoin-mono.svg +1 -0
  85. package/assets/logos/nimiq-icons-logos/logos-bitcoin-outline-mono.svg +1 -0
  86. package/assets/logos/nimiq-icons-logos/logos-bitcoin-outline.svg +1 -0
  87. package/assets/logos/nimiq-icons-logos/logos-bitcoin.svg +1 -0
  88. package/assets/logos/nimiq-icons-logos/logos-colones-outline-mono.svg +1 -0
  89. package/assets/logos/nimiq-icons-logos/logos-colones-outline.svg +1 -0
  90. package/assets/logos/nimiq-icons-logos/logos-cpl-horizontal-mono.svg +1 -0
  91. package/assets/logos/nimiq-icons-logos/logos-cpl-horizontal.svg +1 -0
  92. package/assets/logos/nimiq-icons-logos/logos-cpl-tag-mono.svg +1 -0
  93. package/assets/logos/nimiq-icons-logos/logos-cpl-tag.svg +1 -0
  94. package/assets/logos/nimiq-icons-logos/logos-cpl-white-horizontal.svg +1 -0
  95. package/assets/logos/nimiq-icons-logos/logos-crypto-map-horizontal-mono.svg +1 -0
  96. package/assets/logos/nimiq-icons-logos/logos-crypto-map-horizontal.svg +1 -0
  97. package/assets/logos/nimiq-icons-logos/logos-crypto-map-mono.svg +1 -0
  98. package/assets/logos/nimiq-icons-logos/logos-crypto-map-white-horizontal.svg +1 -0
  99. package/assets/logos/nimiq-icons-logos/logos-crypto-map.svg +1 -0
  100. package/assets/logos/nimiq-icons-logos/logos-cryptocity-horizontal-mono.svg +1 -0
  101. package/assets/logos/nimiq-icons-logos/logos-cryptocity-horizontal.svg +1 -0
  102. package/assets/logos/nimiq-icons-logos/logos-cryptocity-mono.svg +1 -0
  103. package/assets/logos/nimiq-icons-logos/logos-cryptocity-white-horizontal.svg +1 -0
  104. package/assets/logos/nimiq-icons-logos/logos-cryptocity.svg +1 -0
  105. package/assets/logos/nimiq-icons-logos/logos-developer-center-horizontal-mono.svg +1 -0
  106. package/assets/logos/nimiq-icons-logos/logos-developer-center-horizontal.svg +1 -0
  107. package/assets/logos/nimiq-icons-logos/logos-developer-center-white-horizontal.svg +1 -0
  108. package/assets/logos/nimiq-icons-logos/logos-discord-mono.svg +1 -0
  109. package/assets/logos/nimiq-icons-logos/logos-discord.svg +1 -0
  110. package/assets/logos/nimiq-icons-logos/logos-ethereum-mono.svg +1 -0
  111. package/assets/logos/nimiq-icons-logos/logos-ethereum.svg +1 -0
  112. package/assets/logos/nimiq-icons-logos/logos-euro-outline-mono.svg +1 -0
  113. package/assets/logos/nimiq-icons-logos/logos-euro-outline.svg +1 -0
  114. package/assets/logos/nimiq-icons-logos/logos-facebook-mono.svg +1 -0
  115. package/assets/logos/nimiq-icons-logos/logos-facebook.svg +1 -0
  116. package/assets/logos/nimiq-icons-logos/logos-fm-horizontal-mono.svg +1 -0
  117. package/assets/logos/nimiq-icons-logos/logos-fm-horizontal.svg +1 -0
  118. package/assets/logos/nimiq-icons-logos/logos-fm-mono.svg +1 -0
  119. package/assets/logos/nimiq-icons-logos/logos-fm-white-horizontal.svg +1 -0
  120. package/assets/logos/nimiq-icons-logos/logos-fm.svg +1 -0
  121. package/assets/logos/nimiq-icons-logos/logos-github-mono.svg +1 -0
  122. package/assets/logos/nimiq-icons-logos/logos-github.svg +1 -0
  123. package/assets/logos/nimiq-icons-logos/logos-gmaps-pin-mono.svg +1 -0
  124. package/assets/logos/nimiq-icons-logos/logos-gmaps-pin.svg +1 -0
  125. package/assets/logos/nimiq-icons-logos/logos-instagram-mono.svg +1 -0
  126. package/assets/logos/nimiq-icons-logos/logos-instagram.svg +1 -0
  127. package/assets/logos/nimiq-icons-logos/logos-lightning-bitcoin-mono.svg +1 -0
  128. package/assets/logos/nimiq-icons-logos/logos-lightning-bitcoin-outline-mono.svg +1 -0
  129. package/assets/logos/nimiq-icons-logos/logos-lightning-bitcoin-outline.svg +1 -0
  130. package/assets/logos/nimiq-icons-logos/logos-lightning-bitcoin.svg +1 -0
  131. package/assets/logos/nimiq-icons-logos/logos-multisig-mono.svg +1 -0
  132. package/assets/logos/nimiq-icons-logos/logos-multisig.svg +1 -0
  133. package/assets/logos/nimiq-icons-logos/logos-nimiq-forum-mono.svg +1 -0
  134. package/assets/logos/nimiq-icons-logos/logos-nimiq-forum.svg +1 -0
  135. package/assets/logos/nimiq-icons-logos/logos-nimiq-hexagon-outline-mono.svg +1 -0
  136. package/assets/logos/nimiq-icons-logos/logos-nimiq-hexagon-outline.svg +1 -0
  137. package/assets/logos/nimiq-icons-logos/logos-nimiq-horizontal-mono.svg +1 -0
  138. package/assets/logos/nimiq-icons-logos/logos-nimiq-horizontal.svg +1 -0
  139. package/assets/logos/nimiq-icons-logos/logos-nimiq-mono.svg +1 -0
  140. package/assets/logos/nimiq-icons-logos/logos-nimiq-pay-horizontal-mono.svg +1 -0
  141. package/assets/logos/nimiq-icons-logos/logos-nimiq-pay-horizontal.svg +1 -0
  142. package/assets/logos/nimiq-icons-logos/logos-nimiq-pay-vertical-mono.svg +1 -0
  143. package/assets/logos/nimiq-icons-logos/logos-nimiq-pay-vertical.svg +1 -0
  144. package/assets/logos/nimiq-icons-logos/logos-nimiq-pay-white-horizontal.svg +1 -0
  145. package/assets/logos/nimiq-icons-logos/logos-nimiq-vertical-mono.svg +1 -0
  146. package/assets/logos/nimiq-icons-logos/logos-nimiq-vertical.svg +1 -0
  147. package/assets/logos/nimiq-icons-logos/logos-nimiq-wallet-horizontal-mono.svg +1 -0
  148. package/assets/logos/nimiq-icons-logos/logos-nimiq-wallet-horizontal.svg +1 -0
  149. package/assets/logos/nimiq-icons-logos/logos-nimiq-wallet-white-horizontal.svg +1 -0
  150. package/assets/logos/nimiq-icons-logos/logos-nimiq-white-horizontal.svg +1 -0
  151. package/assets/logos/nimiq-icons-logos/logos-nimiq-white-vertical.svg +1 -0
  152. package/assets/logos/nimiq-icons-logos/logos-nimiq.svg +1 -0
  153. package/assets/logos/nimiq-icons-logos/logos-reddit-mono.svg +1 -0
  154. package/assets/logos/nimiq-icons-logos/logos-reddit.svg +1 -0
  155. package/assets/logos/nimiq-icons-logos/logos-shiny-nim-mono.svg +1 -0
  156. package/assets/logos/nimiq-icons-logos/logos-shiny-nim.svg +1 -0
  157. package/assets/logos/nimiq-icons-logos/logos-super-simple-swap-mono.svg +1 -0
  158. package/assets/logos/nimiq-icons-logos/logos-super-simple-swap-text-mono.svg +1 -0
  159. package/assets/logos/nimiq-icons-logos/logos-super-simple-swap-text.svg +1 -0
  160. package/assets/logos/nimiq-icons-logos/logos-super-simple-swap.svg +1 -0
  161. package/assets/logos/nimiq-icons-logos/logos-telegram-mono.svg +1 -0
  162. package/assets/logos/nimiq-icons-logos/logos-telegram.svg +1 -0
  163. package/assets/logos/nimiq-icons-logos/logos-twitter-mono.svg +1 -0
  164. package/assets/logos/nimiq-icons-logos/logos-twitter.svg +1 -0
  165. package/assets/logos/nimiq-icons-logos/logos-usd-outline-mono.svg +1 -0
  166. package/assets/logos/nimiq-icons-logos/logos-usd-outline.svg +1 -0
  167. package/assets/logos/nimiq-icons-logos/logos-usdc-mono.svg +1 -0
  168. package/assets/logos/nimiq-icons-logos/logos-usdc.svg +1 -0
  169. package/assets/logos/nimiq-icons-logos/logos-usdt-mono.svg +1 -0
  170. package/assets/logos/nimiq-icons-logos/logos-usdt.svg +1 -0
  171. package/assets/logos/nimiq-icons-logos/logos-youtube-mono.svg +1 -0
  172. package/assets/logos/nimiq-icons-logos/logos-youtube.svg +1 -0
  173. package/assets/logos/official/black/nimiq_logo_black_horizontal.svg +1 -0
  174. package/assets/logos/official/black/nimiq_logo_black_vertical.svg +1 -0
  175. package/assets/logos/official/black/nimiq_signet_black_16x16.svg +1 -0
  176. package/assets/logos/official/black/nimiq_signet_black_32x32.svg +1 -0
  177. package/assets/logos/official/black/nimiq_signet_black_64x64.svg +1 -0
  178. package/assets/logos/official/black/nimiq_signet_black_base_size.svg +1 -0
  179. package/assets/logos/official/colored/_extended/nimiq_keyguard.svg +1 -0
  180. package/assets/logos/official/colored/_extended/nimiq_miner.svg +1 -0
  181. package/assets/logos/official/colored/_extended/nimiq_safe.svg +1 -0
  182. package/assets/logos/official/colored/_extended/nimiq_shop.svg +1 -0
  183. package/assets/logos/official/colored/nimiq_logo_rgb_horizontal.svg +1 -0
  184. package/assets/logos/official/colored/nimiq_logo_rgb_vertical.svg +1 -0
  185. package/assets/logos/official/colored/nimiq_logo_rgb_white_horizontal.svg +1 -0
  186. package/assets/logos/official/colored/nimiq_logo_rgb_white_vertical.svg +1 -0
  187. package/assets/logos/official/colored/nimiq_signet_rgb_16x16.svg +1 -0
  188. package/assets/logos/official/colored/nimiq_signet_rgb_32x32.svg +1 -0
  189. package/assets/logos/official/colored/nimiq_signet_rgb_64x64.svg +1 -0
  190. package/assets/logos/official/colored/nimiq_signet_rgb_base_size.svg +1 -0
  191. package/assets/logos/official/nimiq-logo.min.svg +1 -0
  192. package/assets/logos/official/white/nimiq_logo_white_horizontal.svg +1 -0
  193. package/assets/logos/official/white/nimiq_logo_white_vertical.svg +1 -0
  194. package/assets/logos/official/white/nimiq_signet_white_16x16.svg +1 -0
  195. package/assets/logos/official/white/nimiq_signet_white_32x32.svg +1 -0
  196. package/assets/logos/official/white/nimiq_signet_white_64x64.svg +1 -0
  197. package/assets/logos/official/white/nimiq_signet_white_base_size.svg +1 -0
  198. package/assets/tokens.md +28 -0
  199. package/bin/nq.js +274 -0
  200. package/package.json +51 -0
  201. package/registry/components/account-header/meta.json +70 -0
  202. package/registry/components/account-list/meta.json +84 -0
  203. package/registry/components/account-ring/meta.json +48 -0
  204. package/registry/components/address-display/meta.json +22 -0
  205. package/registry/components/address-input/meta.json +24 -0
  206. package/registry/components/amount/meta.json +26 -0
  207. package/registry/components/amount-input/meta.json +25 -0
  208. package/registry/components/amount-with-fee/meta.json +25 -0
  209. package/registry/components/app-showcase-card/meta.json +24 -0
  210. package/registry/components/backup-banner/meta.json +15 -0
  211. package/registry/components/balance-distribution/meta.json +20 -0
  212. package/registry/components/buttons/meta.json +22 -0
  213. package/registry/components/card/meta.json +18 -0
  214. package/registry/components/close-button/meta.json +18 -0
  215. package/registry/components/consensus-icon/meta.json +20 -0
  216. package/registry/components/copyable/meta.json +20 -0
  217. package/registry/components/fiat-amount/meta.json +24 -0
  218. package/registry/components/hero-section/meta.json +56 -0
  219. package/registry/components/honeycomb-band/meta.json +30 -0
  220. package/registry/components/identicon/meta.json +38 -0
  221. package/registry/components/label-input/meta.json +24 -0
  222. package/registry/components/loading-spinner/meta.json +18 -0
  223. package/registry/components/page-body/meta.json +18 -0
  224. package/registry/components/page-footer/meta.json +18 -0
  225. package/registry/components/page-header/meta.json +23 -0
  226. package/registry/components/payment-info-line/meta.json +97 -0
  227. package/registry/components/price-chart/meta.json +21 -0
  228. package/registry/components/qr-code/meta.json +60 -0
  229. package/registry/components/search-bar/meta.json +20 -0
  230. package/registry/components/select-bar/meta.json +22 -0
  231. package/registry/components/slider-toggle/meta.json +23 -0
  232. package/registry/components/small-page/meta.json +18 -0
  233. package/registry/components/status-alert/meta.json +22 -0
  234. package/registry/components/status-screen/meta.json +27 -0
  235. package/registry/components/swap-balance-bar/meta.json +97 -0
  236. package/registry/components/timer/meta.json +25 -0
  237. package/registry/components/toast-notification/meta.json +24 -0
  238. package/registry/components/tooltip/meta.json +28 -0
  239. package/registry/components/transaction-list/meta.json +48 -0
  240. package/registry/index.json +394 -0
  241. package/scripts/snap.mjs +42 -0
  242. package/scripts/verify.mjs +76 -0
@@ -0,0 +1,42 @@
1
+ // Snapshot a component's truth render to its reference.png.
2
+ // Usage: node scripts/snap.mjs <component> [--demo]
3
+ // default: renders registry/components/<name>/truth/truth.html -> reference.png
4
+ // --demo : renders html/demo.html -> .verify/<name>.got.png (for eyeballing)
5
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
6
+ import { existsSync } from 'node:fs';
7
+ import { dirname, join, resolve } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
11
+ const name = process.argv[2];
12
+ const demoMode = process.argv.includes('--demo');
13
+ if (!name) { console.error('usage: node scripts/snap.mjs <component> [--demo]'); process.exit(1); }
14
+
15
+ const dir = join(ROOT, 'registry', 'components', name);
16
+ const meta = JSON.parse(await readFile(join(dir, 'meta.json'), 'utf8'));
17
+ const v = meta.verify ?? {};
18
+ const src = demoMode ? join(dir, 'html', 'demo.html') : join(dir, 'truth', 'truth.html');
19
+ if (!existsSync(src)) { console.error(`missing ${src}`); process.exit(1); }
20
+
21
+ const { chromium } = await import('playwright');
22
+ const browser = await chromium.launch();
23
+ const page = await browser.newPage({
24
+ viewport: v.viewport ?? { width: 800, height: 600 },
25
+ deviceScaleFactor: v.scale ?? 2,
26
+ });
27
+ await page.goto('file://' + src);
28
+ await page.waitForLoadState('networkidle');
29
+ await page.evaluate(() => document.fonts.ready);
30
+ await page.waitForTimeout(v.settleMs ?? 250);
31
+ const target = v.selector ? page.locator(v.selector) : page;
32
+ const buf = await target.screenshot({ animations: 'disabled' });
33
+ let out;
34
+ if (demoMode) {
35
+ await mkdir(join(ROOT, '.verify'), { recursive: true });
36
+ out = join(ROOT, '.verify', `${name}.got.png`);
37
+ } else {
38
+ out = join(dir, 'reference.png');
39
+ }
40
+ await writeFile(out, buf);
41
+ console.log(out);
42
+ await browser.close();
@@ -0,0 +1,76 @@
1
+ // Pixel-verification harness: renders a component's html variant headlessly,
2
+ // screenshots it, and diffs against registry/components/<name>/reference.png.
3
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
4
+ import { existsSync } from 'node:fs';
5
+ import { dirname, join, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
9
+ const REGISTRY = join(ROOT, 'registry', 'components');
10
+
11
+ export async function verify(name) {
12
+ const dir = join(REGISTRY, name);
13
+ const metaPath = join(dir, 'meta.json');
14
+ if (!existsSync(metaPath)) return { status: 'skip', reason: 'no meta.json' };
15
+ const meta = JSON.parse(await readFile(metaPath, 'utf8'));
16
+ const demo = join(dir, 'html', 'demo.html');
17
+ const ref = join(dir, 'reference.png');
18
+ if (!existsSync(demo)) return { status: 'skip', reason: 'no html/demo.html' };
19
+ if (!existsSync(ref)) return { status: 'skip', reason: 'no reference.png' };
20
+
21
+ const { chromium } = await import('playwright');
22
+ const { PNG } = await import('pngjs');
23
+ const pixelmatch = (await import('pixelmatch')).default;
24
+
25
+ const v = meta.verify ?? {};
26
+ const viewport = v.viewport ?? { width: 800, height: 600 };
27
+ const threshold = v.maxDiffPct ?? 1.0; // percent of pixels allowed to differ
28
+
29
+ const browser = await chromium.launch();
30
+ try {
31
+ const page = await browser.newPage({ viewport, deviceScaleFactor: v.scale ?? 2 });
32
+ await page.goto('file://' + demo);
33
+ await page.waitForLoadState('networkidle');
34
+ await page.evaluate(() => document.fonts.ready);
35
+ await page.waitForTimeout(v.settleMs ?? 250); // let transitions settle
36
+ const target = v.selector ? page.locator(v.selector) : page;
37
+ const shotBuf = await target.screenshot({ animations: 'disabled' });
38
+
39
+ const refPng = PNG.sync.read(await readFile(ref));
40
+ let gotPng = PNG.sync.read(shotBuf);
41
+ if (gotPng.width !== refPng.width || gotPng.height !== refPng.height) {
42
+ return {
43
+ status: 'fail', diffPct: 100, threshold,
44
+ diffPath: `size mismatch: got ${gotPng.width}x${gotPng.height}, ref ${refPng.width}x${refPng.height}`,
45
+ };
46
+ }
47
+ const diff = new PNG({ width: refPng.width, height: refPng.height });
48
+ const badPixels = pixelmatch(refPng.data, gotPng.data, diff.data, refPng.width, refPng.height, {
49
+ threshold: v.pixelThreshold ?? 0.1,
50
+ });
51
+ const diffPct = +(100 * badPixels / (refPng.width * refPng.height)).toFixed(3);
52
+ if (diffPct <= threshold) return { status: 'pass', diffPct, threshold };
53
+ const outDir = join(ROOT, '.verify');
54
+ await mkdir(outDir, { recursive: true });
55
+ const diffPath = join(outDir, `${name}.diff.png`);
56
+ await writeFile(diffPath, PNG.sync.write(diff));
57
+ await writeFile(join(outDir, `${name}.got.png`), shotBuf);
58
+ return { status: 'fail', diffPct, threshold, diffPath };
59
+ } finally {
60
+ await browser.close();
61
+ }
62
+ }
63
+
64
+ // CLI entry: node scripts/verify.mjs <name|all>
65
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
66
+ const { readdir } = await import('node:fs/promises');
67
+ const target = process.argv[2] ?? 'all';
68
+ const names = target === 'all' ? (await readdir(REGISTRY)).sort() : [target];
69
+ let fail = 0;
70
+ for (const n of names) {
71
+ const r = await verify(n);
72
+ console.log(`${r.status === 'pass' ? '✓' : r.status === 'skip' ? '·' : '✗'} ${n}`, r);
73
+ if (r.status === 'fail') fail++;
74
+ }
75
+ process.exitCode = fail ? 1 : 0;
76
+ }