dsh-visualkit 0.0.0-stage → 0.0.2

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 (283) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/LICENSE +26 -0
  3. package/README.md +443 -2
  4. package/THIRD_PARTY.md +55 -0
  5. package/cordis.patch.yml +29 -0
  6. package/data/assets/README.md +38 -0
  7. package/data/assets/icons/brands/bilibili.svg +1 -0
  8. package/data/assets/icons/brands/discord.svg +1 -0
  9. package/data/assets/icons/brands/neteasecloudmusic.svg +1 -0
  10. package/data/assets/icons/brands/qq.svg +1 -0
  11. package/data/assets/icons/brands/sinaweibo.svg +1 -0
  12. package/data/assets/icons/brands/steam.svg +1 -0
  13. package/data/assets/icons/brands/telegram.svg +1 -0
  14. package/data/assets/icons/brands/tiktok.svg +1 -0
  15. package/data/assets/icons/brands/twitch.svg +1 -0
  16. package/data/assets/icons/brands/wechat.svg +1 -0
  17. package/data/assets/icons/brands/x.svg +1 -0
  18. package/data/assets/icons/brands/youtube.svg +1 -0
  19. package/data/assets/icons/lucide/bell.svg +1 -0
  20. package/data/assets/icons/lucide/calendar.svg +1 -0
  21. package/data/assets/icons/lucide/clock.svg +1 -0
  22. package/data/assets/icons/lucide/gamepad-2.svg +1 -0
  23. package/data/assets/icons/lucide/gift.svg +1 -0
  24. package/data/assets/icons/lucide/heart.svg +1 -0
  25. package/data/assets/icons/lucide/mic.svg +1 -0
  26. package/data/assets/icons/lucide/play.svg +1 -0
  27. package/data/assets/icons/lucide/star.svg +1 -0
  28. package/data/assets/icons/lucide/video.svg +1 -0
  29. package/data/assets/icons/phosphor/LICENSE +21 -0
  30. package/data/assets/icons/phosphor/atom-duotone.svg +1 -0
  31. package/data/assets/icons/phosphor/binary-duotone.svg +1 -0
  32. package/data/assets/icons/phosphor/blueprint-duotone.svg +1 -0
  33. package/data/assets/icons/phosphor/circuitry-duotone.svg +1 -0
  34. package/data/assets/icons/phosphor/cloud-arrow-up-duotone.svg +1 -0
  35. package/data/assets/icons/phosphor/code-duotone.svg +1 -0
  36. package/data/assets/icons/phosphor/compass-duotone.svg +1 -0
  37. package/data/assets/icons/phosphor/cpu-duotone.svg +1 -0
  38. package/data/assets/icons/phosphor/cube-duotone.svg +1 -0
  39. package/data/assets/icons/phosphor/database-duotone.svg +1 -0
  40. package/data/assets/icons/phosphor/flask-duotone.svg +1 -0
  41. package/data/assets/icons/phosphor/frame-corners-duotone.svg +1 -0
  42. package/data/assets/icons/phosphor/function-duotone.svg +1 -0
  43. package/data/assets/icons/phosphor/hard-drives-duotone.svg +1 -0
  44. package/data/assets/icons/phosphor/hexagon-duotone.svg +1 -0
  45. package/data/assets/icons/phosphor/infinity-duotone.svg +1 -0
  46. package/data/assets/icons/phosphor/lightning-duotone.svg +1 -0
  47. package/data/assets/icons/phosphor/magic-wand-duotone.svg +1 -0
  48. package/data/assets/icons/phosphor/moon-stars-duotone.svg +1 -0
  49. package/data/assets/icons/phosphor/paint-brush-duotone.svg +1 -0
  50. package/data/assets/icons/phosphor/pen-nib-duotone.svg +1 -0
  51. package/data/assets/icons/phosphor/planet-duotone.svg +1 -0
  52. package/data/assets/icons/phosphor/rocket-launch-duotone.svg +1 -0
  53. package/data/assets/icons/phosphor/ruler-duotone.svg +1 -0
  54. package/data/assets/icons/phosphor/selection-plus-duotone.svg +1 -0
  55. package/data/assets/icons/phosphor/shapes-duotone.svg +1 -0
  56. package/data/assets/icons/phosphor/sparkle-duotone.svg +1 -0
  57. package/data/assets/icons/phosphor/sun-horizon-duotone.svg +1 -0
  58. package/data/assets/icons/phosphor/terminal-window-duotone.svg +1 -0
  59. package/data/assets/icons/phosphor/triangle-duotone.svg +1 -0
  60. package/data/assets/icons/phosphor/waveform-duotone.svg +1 -0
  61. package/data/assets/icons/tabler/alarm.svg +1 -0
  62. package/data/assets/icons/tabler/badge-ad.svg +1 -0
  63. package/data/assets/icons/tabler/bell.svg +1 -0
  64. package/data/assets/icons/tabler/bolt.svg +1 -0
  65. package/data/assets/icons/tabler/brand-bilibili.svg +1 -0
  66. package/data/assets/icons/tabler/brand-discord.svg +1 -0
  67. package/data/assets/icons/tabler/brand-qq.svg +1 -0
  68. package/data/assets/icons/tabler/brand-twitch.svg +1 -0
  69. package/data/assets/icons/tabler/brand-wechat.svg +1 -0
  70. package/data/assets/icons/tabler/brand-weibo.svg +1 -0
  71. package/data/assets/icons/tabler/brand-youtube.svg +1 -0
  72. package/data/assets/icons/tabler/broadcast.svg +1 -0
  73. package/data/assets/icons/tabler/calendar-event.svg +1 -0
  74. package/data/assets/icons/tabler/calendar-week.svg +1 -0
  75. package/data/assets/icons/tabler/clock-hour-3.svg +1 -0
  76. package/data/assets/icons/tabler/coin.svg +1 -0
  77. package/data/assets/icons/tabler/crown.svg +1 -0
  78. package/data/assets/icons/tabler/currency-yen.svg +1 -0
  79. package/data/assets/icons/tabler/device-gamepad-2.svg +1 -0
  80. package/data/assets/icons/tabler/diamond.svg +1 -0
  81. package/data/assets/icons/tabler/flame.svg +1 -0
  82. package/data/assets/icons/tabler/gift.svg +1 -0
  83. package/data/assets/icons/tabler/headphones.svg +1 -0
  84. package/data/assets/icons/tabler/heart-filled.svg +1 -0
  85. package/data/assets/icons/tabler/heart.svg +1 -0
  86. package/data/assets/icons/tabler/live-view.svg +1 -0
  87. package/data/assets/icons/tabler/microphone.svg +1 -0
  88. package/data/assets/icons/tabler/mood-smile.svg +1 -0
  89. package/data/assets/icons/tabler/mood-tongue.svg +1 -0
  90. package/data/assets/icons/tabler/movie.svg +1 -0
  91. package/data/assets/icons/tabler/player-play.svg +1 -0
  92. package/data/assets/icons/tabler/playlist.svg +1 -0
  93. package/data/assets/icons/tabler/rocket.svg +1 -0
  94. package/data/assets/icons/tabler/sparkles.svg +1 -0
  95. package/data/assets/icons/tabler/star-filled.svg +1 -0
  96. package/data/assets/icons/tabler/star.svg +1 -0
  97. package/data/assets/icons/tabler/tag.svg +1 -0
  98. package/data/assets/icons/tabler/thumb-up.svg +1 -0
  99. package/data/assets/icons/tabler/ticket.svg +1 -0
  100. package/data/assets/icons/tabler/video.svg +1 -0
  101. package/data/assets/illustrations/openpeeps/LICENSE +8 -0
  102. package/data/assets/illustrations/openpeeps/peep-10.svg +29 -0
  103. package/data/assets/illustrations/openpeeps/peep-100.svg +32 -0
  104. package/data/assets/illustrations/openpeeps/peep-101.svg +25 -0
  105. package/data/assets/illustrations/openpeeps/peep-102.svg +28 -0
  106. package/data/assets/illustrations/openpeeps/peep-103.svg +32 -0
  107. package/data/assets/illustrations/openpeeps/peep-105.svg +25 -0
  108. package/data/assets/illustrations/openpeeps/peep-12.svg +29 -0
  109. package/data/assets/illustrations/openpeeps/peep-13.svg +27 -0
  110. package/data/assets/illustrations/openpeeps/peep-16.svg +27 -0
  111. package/data/assets/illustrations/openpeeps/peep-17.svg +31 -0
  112. package/data/assets/illustrations/openpeeps/peep-22.svg +29 -0
  113. package/data/assets/illustrations/openpeeps/peep-25.svg +29 -0
  114. package/data/assets/illustrations/openpeeps/peep-26.svg +29 -0
  115. package/data/assets/illustrations/openpeeps/peep-27.svg +29 -0
  116. package/data/assets/illustrations/openpeeps/peep-30.svg +29 -0
  117. package/data/assets/illustrations/openpeeps/peep-31.svg +27 -0
  118. package/data/assets/illustrations/openpeeps/peep-34.svg +29 -0
  119. package/data/assets/illustrations/openpeeps/peep-38.svg +29 -0
  120. package/data/assets/illustrations/openpeeps/peep-39.svg +31 -0
  121. package/data/assets/illustrations/openpeeps/peep-4.svg +29 -0
  122. package/data/assets/illustrations/openpeeps/peep-41.svg +29 -0
  123. package/data/assets/illustrations/openpeeps/peep-44.svg +29 -0
  124. package/data/assets/illustrations/openpeeps/peep-47.svg +26 -0
  125. package/data/assets/illustrations/openpeeps/peep-48.svg +29 -0
  126. package/data/assets/illustrations/openpeeps/peep-50.svg +31 -0
  127. package/data/assets/illustrations/openpeeps/peep-51.svg +29 -0
  128. package/data/assets/illustrations/openpeeps/peep-53.svg +27 -0
  129. package/data/assets/illustrations/openpeeps/peep-54.svg +26 -0
  130. package/data/assets/illustrations/openpeeps/peep-55.svg +29 -0
  131. package/data/assets/illustrations/openpeeps/peep-56.svg +27 -0
  132. package/data/assets/illustrations/openpeeps/peep-58.svg +29 -0
  133. package/data/assets/illustrations/openpeeps/peep-61.svg +27 -0
  134. package/data/assets/illustrations/openpeeps/peep-64.svg +27 -0
  135. package/data/assets/illustrations/openpeeps/peep-68.svg +27 -0
  136. package/data/assets/illustrations/openpeeps/peep-69.svg +27 -0
  137. package/data/assets/illustrations/openpeeps/peep-7.svg +31 -0
  138. package/data/assets/illustrations/openpeeps/peep-72.svg +29 -0
  139. package/data/assets/illustrations/openpeeps/peep-76.svg +31 -0
  140. package/data/assets/illustrations/openpeeps/peep-77.svg +27 -0
  141. package/data/assets/illustrations/openpeeps/peep-80.svg +27 -0
  142. package/data/assets/illustrations/openpeeps/peep-81.svg +29 -0
  143. package/data/assets/illustrations/openpeeps/peep-83.svg +29 -0
  144. package/data/assets/manifest.json +1 -0
  145. package/data/assets/parts//342/206/223/346/212/225/345/275/261.png +0 -0
  146. package/data/assets/parts//344/270/211/350/247/222/345/217/221/345/244/2711.png +0 -0
  147. package/data/assets/parts//344/270/211/350/247/222/345/217/221/345/244/2712.png +0 -0
  148. package/data/assets/parts//344/270/211/350/247/222/345/217/221/345/244/2713.png +0 -0
  149. package/data/assets/parts//344/270/211/350/247/222/345/217/221/345/244/2714.png +0 -0
  150. package/data/assets/parts//345/217/214/351/251/254/345/260/276.png +0 -0
  151. package/data/assets/parts//345/217/214/351/251/254/345/260/2761.png +0 -0
  152. package/data/assets/parts//345/217/2211.png +0 -0
  153. package/data/assets/parts//345/217/2212.png +0 -0
  154. package/data/assets/parts//345/217/2213.png +0 -0
  155. package/data/assets/parts//345/217/221/345/234/210.png +0 -0
  156. package/data/assets/parts//345/217/221/345/244/2711.png +0 -0
  157. package/data/assets/parts//345/217/221/345/244/2712.png +0 -0
  158. package/data/assets/parts//345/217/243/346/260/264/345/267/276/345/211/215.png +0 -0
  159. package/data/assets/parts//345/217/243/346/260/264/345/267/276/345/220/216.png +0 -0
  160. package/data/assets/parts//345/217/263/344/270/212/347/234/274/347/235/221.png +0 -0
  161. package/data/assets/parts//345/217/263/346/211/213.png +0 -0
  162. package/data/assets/parts//345/217/263/346/211/2131.png +0 -0
  163. package/data/assets/parts//345/217/263/347/234/274/347/220/203.png +0 -0
  164. package/data/assets/parts//345/217/263/347/234/274/347/231/275.png +0 -0
  165. package/data/assets/parts//345/217/263/350/205/277.png +0 -0
  166. package/data/assets/parts//345/221/206/346/257/233.png +0 -0
  167. package/data/assets/parts//345/230/264/345/267/264.png +0 -0
  168. package/data/assets/parts//345/260/276/345/267/264.png +0 -0
  169. package/data/assets/parts//345/267/246/344/270/212/347/234/274/347/235/221.png +0 -0
  170. package/data/assets/parts//345/267/246/345/217/214/347/234/274/347/232/256.png +0 -0
  171. package/data/assets/parts//345/267/246/346/211/213.png +0 -0
  172. package/data/assets/parts//345/267/246/346/211/2131.png +0 -0
  173. package/data/assets/parts//345/267/246/347/234/274/347/220/203.png +0 -0
  174. package/data/assets/parts//345/267/246/347/234/274/347/231/275.png +0 -0
  175. package/data/assets/parts//345/267/246/350/205/277.png +0 -0
  176. package/data/assets/parts//346/212/225/345/275/261.png +0 -0
  177. package/data/assets/parts//347/234/211/346/257/233.png +0 -0
  178. package/data/assets/parts//347/234/274/347/275/251.png +0 -0
  179. package/data/assets/parts//350/200/263/346/234/2651.png +0 -0
  180. package/data/assets/parts//350/200/263/346/234/2652.png +0 -0
  181. package/data/assets/parts//350/204/221/345/243/263.png +0 -0
  182. package/data/assets/parts//350/241/243/346/234/215/345/211/215.png +0 -0
  183. package/data/assets/parts//350/241/243/346/234/215/345/220/216.png +0 -0
  184. package/data/assets/parts//350/241/243/346/234/215/351/273/221.png +0 -0
  185. package/data/assets/parts//350/241/243/346/234/215/351/273/2211.png +0 -0
  186. package/data/assets/parts//350/272/253/344/275/223.png +0 -0
  187. package/data/assets/parts//351/223/201/346/235/277.png +0 -0
  188. package/data/assets/parts//351/273/221/347/234/274/345/234/210.png +0 -0
  189. package/data/assets/parts//351/273/221/347/234/274/345/234/2102.png +0 -0
  190. package/data/assets/patterns/checker.svg +1 -0
  191. package/data/assets/patterns/circles-overlap.svg +1 -0
  192. package/data/assets/patterns/crosshatch.svg +1 -0
  193. package/data/assets/patterns/diagonal.svg +1 -0
  194. package/data/assets/patterns/dots.svg +1 -0
  195. package/data/assets/patterns/grid.svg +1 -0
  196. package/data/assets/patterns/halftone.svg +1 -0
  197. package/data/assets/patterns/plus.svg +1 -0
  198. package/data/assets/patterns/scales.svg +1 -0
  199. package/data/assets/patterns/triangles.svg +1 -0
  200. package/data/assets/patterns/waves.svg +1 -0
  201. package/data/assets/patterns/zigzag.svg +1 -0
  202. package/data/assets/stickers/openmoji/1F375.svg +12 -0
  203. package/data/assets/stickers/openmoji/1F9E8.svg +21 -0
  204. package/data/assets/stickers/twemoji/1f389.svg +1 -0
  205. package/data/assets/stickers/twemoji/1f3a4.svg +1 -0
  206. package/data/assets/stickers/twemoji/1f3a7.svg +1 -0
  207. package/data/assets/stickers/twemoji/1f3ae.svg +1 -0
  208. package/data/assets/stickers/twemoji/1f44b.svg +1 -0
  209. package/data/assets/stickers/twemoji/1f44d.svg +1 -0
  210. package/data/assets/stickers/twemoji/1f494.svg +1 -0
  211. package/data/assets/stickers/twemoji/1f4a2.svg +1 -0
  212. package/data/assets/stickers/twemoji/1f4a8.svg +1 -0
  213. package/data/assets/stickers/twemoji/1f4b5.svg +1 -0
  214. package/data/assets/stickers/twemoji/1f4d6.svg +1 -0
  215. package/data/assets/stickers/twemoji/1f525.svg +1 -0
  216. package/data/assets/stickers/twemoji/1f600.svg +1 -0
  217. package/data/assets/stickers/twemoji/1f602.svg +1 -0
  218. package/data/assets/stickers/twemoji/1f60d.svg +1 -0
  219. package/data/assets/stickers/twemoji/1f62d.svg +1 -0
  220. package/data/assets/stickers/twemoji/1f680.svg +1 -0
  221. package/data/assets/stickers/twemoji/1f979.svg +1 -0
  222. package/data/assets/stickers/twemoji/1f97a.svg +1 -0
  223. package/data/assets/stickers/twemoji/26a1.svg +1 -0
  224. package/data/assets/stickers/twemoji/2705.svg +1 -0
  225. package/data/assets/stickers/twemoji/274c.svg +1 -0
  226. package/data/assets/stickers/twemoji/2764.svg +1 -0
  227. package/data/assets/stickers/twemoji/2b50.svg +1 -0
  228. package/data/assets/stickers/twemoji_1f525.svg +1 -0
  229. package/data/assets/stickers/twemoji_1f600.svg +1 -0
  230. package/data/assets/stickers/twemoji_1f979.svg +1 -0
  231. package/data/assets/stickers/twemoji_2764.svg +1 -0
  232. package/data/assets/textures/grain-dark.png +0 -0
  233. package/data/assets/textures/grain-light.png +0 -0
  234. package/data/assets/textures/grain-warm.png +0 -0
  235. package/data/lucide-icons.json +1 -0
  236. package/data/packs/tabler.icons.json +1 -0
  237. package/icon.svg +26 -0
  238. package/lib/assets.js +228 -0
  239. package/lib/audit.js +284 -0
  240. package/lib/contrast-render.js +213 -0
  241. package/lib/css-rewrite.js +379 -0
  242. package/lib/detect.js +701 -0
  243. package/lib/diff.js +153 -0
  244. package/lib/emit.js +557 -0
  245. package/lib/html-context.js +315 -0
  246. package/lib/icon-render.js +107 -0
  247. package/lib/icondb.js +402 -0
  248. package/lib/image-normalize.js +140 -0
  249. package/lib/index.js +1289 -0
  250. package/lib/layouts/common.js +48 -0
  251. package/lib/layouts/image.js +1010 -0
  252. package/lib/layouts/index.js +10 -0
  253. package/lib/layouts/intent.js +66 -0
  254. package/lib/layouts/metrics-text.js +91 -0
  255. package/lib/layouts/png.js +75 -0
  256. package/lib/layouts/rules-contrast.js +575 -0
  257. package/lib/layouts/rules-punct.js +486 -0
  258. package/lib/layouts/rules-structure.js +182 -0
  259. package/lib/layouts/source.js +1961 -0
  260. package/lib/layouts/svg.js +1204 -0
  261. package/lib/morphcore.js +139 -0
  262. package/lib/preview.js +225 -0
  263. package/lib/render-html.js +255 -0
  264. package/lib/render.js +486 -0
  265. package/lib/rules.js +267 -0
  266. package/lib/shadow.js +83 -0
  267. package/lib/skip.js +56 -0
  268. package/lib/style.js +688 -0
  269. package/lib/svg.js +729 -0
  270. package/lib/taste-image.js +323 -0
  271. package/lib/taste.js +219 -0
  272. package/locale/en.json +6 -0
  273. package/locale/zh.json +6 -0
  274. package/package.json +92 -4
  275. package/vendor/morphicons-adapters.iife.js +903 -0
  276. package/vendor/morphicons.iife.js +2441 -0
  277. package/vendor/resvg/LICENSE +373 -0
  278. package/vendor/resvg/index.d.ts +98 -0
  279. package/vendor/resvg/index.js +23 -0
  280. package/vendor/resvg/js-binding.d.ts +52 -0
  281. package/vendor/resvg/js-binding.js +1 -0
  282. package/vendor/resvg/package.json +138 -0
  283. package/vendor/resvg/resvgjs.win32-x64-msvc.node +0 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,74 @@
1
+ # Changelog
2
+
3
+ 本文件记录所有值得注意的变更。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
4
+ 版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。
5
+
6
+ ## [0.0.2] — 2026-11-09
7
+
8
+ 安装文档与工程流程修正,功能与契约不变(`0.0.x`)。
9
+
10
+ ### Changed
11
+
12
+ - **安装说明重写**:改为「DSH 内按包名安装(推荐)/ 命令行 / 源码」三种方式,对齐同系列插件;顶部加 npm 版本、平台与许可徽章。
13
+ - **README 不再写死版本号**:版本以 npm 徽章与 `npm view dsh-visualkit version` 为准,运行时要求指向 `package.json` 的 `engines`,避免每次发版后说明过期。
14
+
15
+ ### Fixed
16
+
17
+ - **CI 四处修正**:测试脚本改显式 glob(Node 22 不接受目录参数);ubuntu 作业 `npm ci --force`(根包声明 `os: win32`);包测试自带 tar 解析(GitHub Windows runner 读不了中文文件名);渲染类用例只在 win32 跑(无 resvg 绑定、字体校准差异)。
18
+ - **发布工作流**:`release.yml` 同样改用 `npm ci --force`,推送 tag 即可自动发布并附带 provenance。
19
+
20
+ ## [0.0.1] — 2026-11-08
21
+
22
+ 首个公开发布版本。
23
+
24
+ 八个工具串成一条工艺链:**取真资产 → 定规格 → 量审美 → 出成品**。同一套原语(配色 / 字体 / 形状 /
25
+ 图案 / 栅格 / 动效 / 交互态)可以落成 UI 界面、网页、平面图、海报与纯文字版式;工具按「回答什么问题」
26
+ 分工,场景与输入介质是参数,工具不按介质另起一套。
27
+
28
+ 用法是一条五步链路:体检 → 核实真假 → 机械改 → 人决定 → 复验。`taste_check` 与 `layout_check` 先量出问题,
29
+ `icon` / `design_render` 取真资产替代模型编造的内容,`css_edit` / `html_edit` 做机械收敛,改完复测到 `clean`。
30
+ 分数只在 `ai-tinged` / `ai-default` 提示返工,`clean` 区间建议停止压分(继续优化会把设计推向安全区)。
31
+
32
+ 全部本地离线运行,不需要 Python、Krita、Playwright 或外部工作区。安装:在桌面插件页添加组合包、
33
+ 把 `target` 填成本仓库根目录,npm 发布后也可用 `dsh plugin add dsh-visualkit`;装好后重启 DSH 生效。
34
+ 运行环境为 Windows x64、Node ≥22.19、DSH ≥0.2.0-rc.2 <0.3.0;包许可 MIT,
35
+ 第三方数据与授权逐项见 `THIRD_PARTY.md`。
36
+
37
+ 使用说明与取舍分析在仓库 `docs/`:工作流五步见 `docs/workflow.md`,定位与场景矩阵见 `docs/positioning.md`,
38
+ 交互层与 CSS 归一化分别见 `docs/interaction-layer.md`、`docs/css-normalization.md`。
39
+
40
+ ### Added
41
+ - **`icon`**:检索 lucide 1.70.0(2029 图标 + 289 别名 + 官方 tags + 43 类目)与 tabler 1.2.43(6302 图标),
42
+ 支持中英同义词、别名解析、单字符词边界与中文品牌名映射,按五种项目约定出码(`colibri` / `echo` / `dsh-plugin` / `whale` / `raw`)。
43
+ - **`icon emit` 的 9 种视觉语言**:`outline` / `hairline` / `bold` / `sharp` / `solid` / `duotone` / `badge` / `knockout` / `gradient`,
44
+ 由 `paint` / `strokeWidth` / `caps` / `join` / `container` / `gradient` / `inset` 等正交参数逐项覆盖;`shapes` 每层可独立设渐变,`fill-rule=evenodd` 直接做镂空与环形。
45
+ - **`morph`**:形变兼容双层体检(项目契约 + morphicons 2.0.2 引擎:fill 走 region、transform 烘焙、viewBox 自动 re-grid),
46
+ 附自包含动效预览页(3 种弹簧预设 + 服务端烘焙 5 帧静帧)。
47
+ - **`taste_check taste`**:AI 味 0–100 分与逐条返工指令,21 项指标分 quality / style / content 三层,三档 profile
48
+ (`balanced` / `strict` / `structure`),`.design-intent.json` 声明豁免;输入支持源码目录、单文件与 PNG,位图层走 `img-indigo-hue` / `img-ramp` 两条像素判据。
49
+ - **`taste_check audit`**:图标规范巡检(`universal` / `echo` / `colibri` / `auto`),查 emoji 图标、MorphIcon 误用与 ICONS 字典。
50
+ - **`layout_check ui`**:排版体检 0–100 分(越低越好),源码规则 `S1`–`S14` 覆盖字号阶梯、最小字号、行高、行长、字体家族、
51
+ 对齐、中英混排、中文标点、对比度(WCAG 2 AA/AAA + APCA)、标题跳级、触摸目标、阴影层级、断点一致性、组件状态矩阵与负外边距;`render=true` 在真实渲染像素上量文字对比度。
52
+ - **`layout_check svg`**:规则 `G1`–`G9`,直接量成品 SVG 的 `text` 坐标与字号(不需 OCR),
53
+ 查层级、行距、安全区、贴边、溢出、文字重叠与基线。
54
+ - **`layout_check image`**:规则 `P1`–`P9`,解码 PNG / JPEG / WebP,
55
+ 查内容边距、出血、密度、视觉平衡、对齐线索、卡片栅格与列表行高一致性;结果带 `rulesRun` / `measured`,
56
+ 能区分「量了且过了」与「什么都没量」。
57
+ - **`design_style`**:8 皮肤 × 6 骨架 = 48 组合,输出 `css` / `json` / `tailwind`;每个皮肤自带 4 档字号阶梯(最大跳变 ≥1.6×)
58
+ 与分层禁用清单,`tokens` 参数可覆盖颜色 / 圆角 / 边框 / 阴影 / 字体 / 字号档 / 密度与机制层 token(图案 / 任意形状 / 有机圆角 / 双线 / 描边字 / 字距 / 动效档 / 栅格)。
59
+ - **`design_style format=motion`**:8 个交互原语(`press` / `lift` / `focus` / `ripple` / `enter` / `stagger` / `reveal` / `shimmer`),
60
+ 只走 `[data-motion~="…"]` 属性钩子,产物无条件带 `prefers-reduced-motion` 兜底。
61
+ - **`html_edit`**:`scan` 判定命中落在文本节点 / 属性 / 脚本 / 样式 / 注释的哪一处,`rewrite` 按 `scope=text|text+attr|all` 限定范围;
62
+ 支持整类扫描(emoji / 直引号 / 中文标点)与「映射缺失」护栏,标记不会漏进属性。
63
+ - **`css_edit`**:`scan` / `snap` / `scale` / `leading` / `radius` 五个 action,分别盘点、对齐 4px 网格、归并字号阶梯、归一正文行高、收敛圆角;
64
+ 默认只出改动清单(`write=true` 才落盘),注释与字符串里的数字、`var()` / `calc()` / `%` 一律不碰。
65
+ - **`design_render render` / `composite`**:SVG→PNG(透明底、等比缩放、`sizes` 多档、六帧 ICO);
66
+ 图层合成支持 `anchor` / `padding` / `fit` / `blend` / `rotate` / `scale` / `canvas`,`under` 可传纯色。
67
+ - **`design_render html` / `diff`**:HTML→PNG,自动探测本机 Edge / Chrome / Chromium,`pageScale` 与 `fullPage` 按真实内容高度截图;
68
+ 两图差异给出均像素差、分区差、热力图与偏移搜索。
69
+ - **`design_render asset`**:221 项内置素材(品牌 / 图标 / 插画 / 角色部件 / 图案 / 贴纸 / 纹理)的检索、内联与改色,
70
+ 带目录穿越防护。
71
+ - **插件图标**:版面画板标记——画板框 + 标题/副标/正文行 + 选中的图文卡片(日、山)+ 底部色板,玫瑰 / 品红 / 紫三组渐变加琥珀点缀;颜色按对比度校准,图形元素对白底、深底均 ≥ 3:1;对应 UI / 平面设计与排版、文本排版能力;`aria-label` 为「视觉设计工具箱」。
72
+ - **运行时健壮性**:vendored resvg 延迟加载——非 win32-x64 平台上其余工具照常可用,只有 SVG 渲染会报出明确的平台说明,而不是一 import 就崩。
73
+ - **发布与运行时**:两档常驻 token 预算 3600 / 4200 字符(默认档 / 全量档);零运行时依赖,resvg-js 2.6.2 以 MPL-2.0
74
+ vendored 到 `vendor/resvg/`(win32-x64 原生绑定),morphicons 2.0.2 走 vendored IIFE;测试用 `node:test` 覆盖契约、渲染、图标、形变、审美、体检、风格、素材与发布边界。
package/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ikeyuchen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ This package bundles third-party assets under their own licenses.
26
+ See THIRD_PARTY.md for the full list and terms.
package/README.md CHANGED
@@ -1,3 +1,444 @@
1
- # Temporary Holding Version
1
+ # dsh-visualkit
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![npm](https://img.shields.io/npm/v/dsh-visualkit)](https://www.npmjs.com/package/dsh-visualkit) [![platform](https://img.shields.io/badge/platform-Windows%20x64-lightgrey)](#安装) [![license](https://img.shields.io/npm/l/dsh-visualkit)](LICENSE)
4
+
5
+ **视觉设计工具箱**:把「好看」变成可执行、可验收的东西。
6
+
7
+ > 模型不缺产能,缺美术判断:它做出的界面能跑但难看——字号没有层级、间距靠手调、图标用 emoji、配色是紫渐变。`dsh-visualkit` 提供一条工艺链:**取真资产 → 定规格 → 量审美 → 出成品**,全部本地离线,不依赖任何系统软件。
8
+
9
+ **先看怎么用**:[工作流:从「看着还行」到「可以验收」](https://github.com/ikeyuchen/dsh-visualkit/blob/main/docs/workflow.md)——五步链路(体检 → 核实真假 → 机械改 → 人决定 → 复验)。
10
+
11
+ **工具和框架,不是风格目录**:同一套原语(配色 / 字体 / 形状 / 图案 / 栅格 / 动效 / 交互态)可以落成 UI 界面、网页、平面图、海报或纯文字版式;「苹果风」在这五个场景里是同一个风格,区别只在取哪几个工具、交什么。→ [定位与场景矩阵](https://github.com/ikeyuchen/dsh-visualkit/blob/main/docs/positioning.md)
12
+
13
+ `dsh-visualkit` — Art toolkit for AI-generated UIs and graphics: icon sourcing, SVG morphing, AI-look scoring, style specs, local rendering.
14
+
15
+ | 项 | 值 |
16
+ |---|---|
17
+ | 包名 / 仓库 | `dsh-visualkit` |
18
+ | 最新版本 | 见顶部 npm 徽章,或 `npm view dsh-visualkit version` |
19
+ | 许可 | MIT |
20
+ | 外部依赖 | **无**(resvg 已 vendored,不需要 Python / Krita / Playwright / 外部工作区) |
21
+
22
+ ## 八个工具
23
+
24
+ | 工具 | action | 作用 |
25
+ |---|---|---|
26
+ | `icon` | `find` / `emit` | 检索 lucide 2029(含官方 tags + 43 类目)+ tabler 6302,中英同义词;按项目约定出码(colibri / echo / dsh-plugin / whale / raw),`style` 有 9 种预设 |
27
+ | `morph` | `check` / `preview` | 形变兼容双层体检(项目契约 + morphicons 2.0.2 引擎);自包含动效预览页 |
28
+ | `taste_check` | `taste` / `audit` | `taste`:AI 味 0–100 分 + 返工指令(**21 项指标**分 quality/style/content 三层,含**成组出现**判断),输入可以是源码目录/单文件,**也可以是一张 PNG**(位图层走像素判据);`audit`:图标规范巡检(emoji 禁令 / MorphIcon 误用 / ICONS 字典) |
29
+ | `layout_check` | `ui` / `svg` / `image` | 排版体检(0–100 分,越低越好):`ui` 扫 HTML/CSS 字体系统/行高/行长/对齐;`svg` 量成品 SVG 的真实文字几何(层级/行距/边距/重叠/溢出);`image` 量渲染图的构图(边距/密度/平衡/对齐;PNG / JPEG / WebP 直读) |
30
+ | `design_style` | —(用 `format=css / json / tailwind / motion`) | 8 皮肤 × 6 骨架 = 48 组合:token + 结构配方 + 分层禁用清单;`motion` 出交互原语层 |
31
+ | `html_edit` | `scan` / `rewrite` | 上下文感知的 HTML 改写:先判定命中在**文本节点 / 属性 / 脚本 / 注释**的哪一处,再决定改不改——标记不会漏进属性里被当文本显示 |
32
+ | `css_edit` | `scan` / `snap` / `scale` / `leading` / `radius` | 机械收敛:间距对 4px 网格、字号归阶梯、行高归一、圆角收敛;**默认只出改动清单不写盘**,注释/字符串/var/calc/% 一律不碰 |
33
+ | `design_render` | `render` / `composite` / `asset` / `html` / `diff` | `render`:SVG→PNG(透明底、可缩放、多尺寸/ICO);`composite`:图层合成(scale/多尺寸/ICO);`asset`:221 项内置素材检索 / 内联 / 改色;`html`:HTML→PNG;`diff`:两图差异与热力图 |
34
+
35
+ ## 安装
36
+
37
+ **方式一:DSH 内安装(推荐)**
38
+
39
+ 1. 打开 DSH →「插件」→「添加插件」
40
+ 2. 输入包名 `dsh-visualkit`,安装源保持「npm 官方源」
41
+ 3. 点「安装」,装好后重启 DSH 生效
42
+
43
+ **方式二:命令行(同样走 npm)**
44
+
45
+ ```bash
46
+ dsh plugin add dsh-visualkit
47
+ ```
48
+
49
+ **方式三:源码**(开发或未发布版本)
50
+
51
+ ```bash
52
+ git clone https://github.com/ikeyuchen/dsh-visualkit.git
53
+ dsh plugin --profile web add ./dsh-visualkit
54
+ ```
55
+
56
+ 运行环境:Windows x64、Node 与 DSH 版本要求见 `package.json` 的 `engines` / `os` / `cpu`。
57
+ 改本地代码后只需触发一次 profile 重组合,不必重装。
58
+
59
+ ### 按需加载:`toolsetProfile`
60
+
61
+ 低频工具默认不进上下文,默认 `standard` 装 6 个高频工具:
62
+
63
+ | 档位 | 工具 | 常驻 |
64
+ |---|---|---|
65
+ | `minimal` | icon, design_render | **2398 字符 ≈ 600 token** |
66
+ | `standard`(默认) | + taste_check, layout_check, html_edit, css_edit | **3583 字符 ≈ 896 token** |
67
+ | `all` | + morph, design_style | 4138 字符 ≈ 1035 token |
68
+
69
+ 分档依据是使用链路:整套项目开发里 `design_style` 调用 0 次、`morph` 只做几次体检,而 icon / design_render / layout_check / taste_check 一直在用。非法档位值响亮报错,不静默回落;提示段只列当前 scope 真看得到的工具,降档或宿主侧再做工具限制时不会指向不存在的东西。
70
+
71
+ ## 它解决什么
72
+
73
+ 模型的默认输出会塌缩到训练分布的众数:紫蓝渐变、`rounded-xl`、毛玻璃、`Inter`、12/13/14/15 碎字号、emoji 图标、三段式 hero。这条链把审美拆成三段:
74
+
75
+ 1. **事前约束** —— `design_style` 给 token(1 个强调色家族 / 4 档字号且 ≥1.6× 跳变 / 4px 网格 / 圆角 ≤8 / ≤1 层中性阴影)+ 结构配方 + 禁用清单
76
+ 2. **事中取真** —— `icon` 取真 SVG、`design_render asset` 取真素材,替代模型编造
77
+ 3. **事后量化** —— `taste_check taste` 打 0–100 分并给**具体改法**,改完复测直到 `clean`;`layout_check` 把排版单独量化:源码看字体系统,成品看文字几何与构图(全自动、不需 OCR)
78
+
79
+ 同一检测器、同一业务内容的分数:
80
+
81
+ | 样本 | 分数 | 等级 |
82
+ |---|---:|---|
83
+ | 模型无约束的典型输出 | 75 | ai-default |
84
+ | 按 `design_style` 规则重写 | 5 | clean |
85
+ | 第三方 AI 生成的插件 UI | 54 | ai-default |
86
+
87
+ **规则与检测同源**:`lib/rules.js` 一份定义同时供约束文案与检测器,避免约束改了检测没改、验收标准打架。**分数口径**:只在 `ai-tinged` / `ai-default` 提示返工;`clean` 区间输出「stop optimizing here」——继续压分只会把设计推向安全区(Goodhart)。分数不可跨 `profile` 比较。
88
+
89
+ ## 风格:给框架,不给目录
90
+
91
+ `design_style` 内置 8 种视觉语言 × 6 种结构配方。对照市面上的风格分类(例如 [设计风格术语](https://vibe-hub.org/topics/design) 的 24 个条目),8 个 skin 覆盖 **8 个直接可用 + 7 个部分可用,还有 9 个表达不了**——扁平、Y2K、Art Deco、有机自然、Material、拟物、新拟态、Memphis、DTC 品牌站。根因是 `skin` 为封闭枚举,补皮肤只会让清单越来越长;所以加的是描述能力:`tokens` 参数在内置 skin 之上覆盖视觉 token。
92
+
93
+ ```text
94
+ design_style skin=swiss-minimal tokens="shadow=none;radius=0;accent=#3B5BDB" # 扁平
95
+ design_style skin=brutalist tokens="ground=#1A1240;accent=#FF4FB0;radius=18;border=2;shadow=0 0 28px rgba(255,79,176,.45)" # Y2K
96
+ design_style skin=quiet-luxe tokens='ground=#0E0B08;accent=#C9A227;radius=0;font="Georgia",serif;border=2' # Art Deco
97
+ ```
98
+
99
+ 可覆盖的键:`ground / surface / ink / inkSoft / muted / line / accent / ok / warn / danger`、`radius / border / shadow / density`、`font / mono`、`micro / body / head / display`。尺寸类 token 自动补 `px`(`radius=18` 等价 `18px`)、时间类自动补 `ms`(`dur=90` 等价 `90ms`);`radius` 会派生另两档,避免只改主档导致档位混用;未知 token 直接报错并列出可用键。
100
+
101
+ ### 机制层:补的是手段,不是风格
102
+
103
+ | 机制 | token | 用途 |
104
+ |---|---|---|
105
+ | 渐变填充 | `ground` / `surface` 直接写渐变值 | Y2K 金属、拟物、苹果官网、光球 |
106
+ | 图案层 | `pattern=repeating-linear-gradient(…)` / `radial-gradient(…)` | 波点、斜纹、网格、装饰纹样 |
107
+ | 任意形状 | `clip=polygon(…)` | 斜切角、六边形、箭头 |
108
+ | 有机圆角 | `organic=42% 58% 55% 45% / …` | 自然/手作感的 blob |
109
+ | 双线边框 | `double=0 0 0 1px c,0 0 0 4px bg,0 0 0 5px c` | Art Deco |
110
+ | 描边字 | `stroke=` | 粗野、终端 |
111
+ | 字距 / 流体字号 | `tracking=.14em`;`display=clamp(32px,6vw,72px)` | 苹果紧排、杂志 |
112
+ | 动效档位 | `dur=180ms;ease=cubic-bezier(…)` | 全局过渡节奏 |
113
+ | 栅格配方 | `grid=repeat(4,1fr) / repeat(3,64px)` | Bento 不等宽、杂志图文穿插 |
114
+ | 交互态 | `format=motion` + `press/lift/focus/ripple/stagger/reveal/shimmer` | 按压、悬停、焦点、波纹、错峰入场、滚动显现 |
115
+
116
+ 输出为 `--pattern` / `--clip` / `--radius-organic` / `--double-line` / `--text-stroke` / `--tracking` / `--dur` / `--ease` / `--grid` / `--press` / `--lift` / `--focus-ring` / `--ripple` / `--stagger` / `--reveal` / `--shimmer`,由使用方写到 CSS 里消费;`css` 与 `json` 两种格式都带这些钩子。token 值里的双引号(`font="Microsoft YaHei"`)不能塞进 HTML 内联 `style="…"`:会提前截断属性,后面所有变量失效——变量应落到 `<style>` 块里(`#p0{…}`)。覆盖:配色、圆角、字体、边框、阴影、字号档、密度、语气,以及渐变 / 图案 / 形状 / 双线 / 字距 / 动效节奏 / 栅格比例。不覆盖:复杂组件行为(涟漪的触发时机、拖拽态)与内容组织(Bento 里哪个格子放什么)——机制层决定「用哪种手段」,不决定「长什么样」。
117
+
118
+ ### 交互层:`format=motion`
119
+
120
+ 产物是一份可选、按元素挂载的 CSS 原语,不是预设动效包:八个原语独立,只挑需要的挂;选择器全走 `[data-motion~="…"]` 属性钩子,不占 class 命名空间;时长/缓动/幅度全读变量,换项目只改 `:root`。
121
+
122
+ ```html
123
+ <button data-motion="press lift focus ripple">提交</button>
124
+ <ul data-motion="stagger"><li style="--i:0">…</li><li style="--i:1">…</li></ul>
125
+ ```
126
+
127
+ | 原语 | 作用 |
128
+ |---|---|
129
+ | `press` / `lift` | 按压贴合 / 悬停抬升(`:active` 归零) |
130
+ | `focus` | 只需 `:focus-visible`,鼠标点击不弹环 |
131
+ | `ripple` | 波纹,`clip-path` 自 `--mx/--my` 扩张,不依赖元素尺寸 |
132
+ | `enter` / `stagger` | 单元素入场 / 列表错峰(子元素读 `--i`) |
133
+ | `reveal` / `shimmer` | 滚动显现(`.is-in`)/ 骨架屏扫光 |
134
+
135
+ 红线:产物无条件带 `prefers-reduced-motion` 兜底,且把 `reveal` 的 `opacity` 补回可见,否则前庭敏感用户看到的是空白页。这是无障碍底线,不可关闭。→ [交互层详解](https://github.com/ikeyuchen/dsh-visualkit/blob/main/docs/interaction-layer.md)
136
+
137
+ ### CSS 层能机械到哪一步
138
+
139
+ 判断线:**能机械化的只有「同一维度上的取值收敛」**;跨维度取舍(配色取向、层级策略、组件形态、阴影方向)工具只该报,不该改。完整取舍分析见 [css-normalization](https://github.com/ikeyuchen/dsh-visualkit/blob/main/docs/css-normalization.md)。
140
+
141
+ | action | 收敛什么 | 保留不动 |
142
+ |---|---|---|
143
+ | `snap` | `margin/padding/gap` → 4px 网格 | 0.5/1/2px(描边与微调)、负值只调幅度不改方向、裸 `0` |
144
+ | `scale` | `font-size` → 给定阶梯 | 平局取**大**的那档(往小缩会让中文变糊) |
145
+ | `leading` | `line-height` → `1.5 / 1.6 / 1.8` | 标题级一律不动(紧凑行高是正确做法)、`<1.2` / `>2.2` / `px` / `var` |
146
+ | `radius` | `border-radius` → `2 / 4 / 8 / 12` | `50%`(圆)/ `0` / `≥100px`(胶囊)/ 单角属性 / 多值简写 |
147
+
148
+ 硬性约束:注释与字符串里的数字不动 · `var()/calc()/%/em/rem/auto` 不碰 · 幂等(归一过的再跑改动数为 0)· **默认 dry-run**,`write=true` 才落盘。校准口径:行高规则从 4 个项目的 **78 处**真实声明里选型,最终「标题不动 + 正文死区抬到 1.5 + ≥1.5 就近归并」让 S3 从 10 处降到 **2 处**;圆角在令牌化率 ≥50% 的项目上直接拒绝——三个现代项目的散落 px 只有 9 / 0 / 1 处,而 `var()` 有 119 / 34 / 7 处。完整数据见 [css-normalization](https://github.com/ikeyuchen/dsh-visualkit/blob/main/docs/css-normalization.md)。
149
+
150
+ ## AI 味:成组出现才是指纹
151
+
152
+ 风格识别口径参考 [AI 味儿图鉴](https://vibe-hub.org/anti-ai-flavor):中文口癖 11 条、页面模板感 8 条、不好用的交互 6 条,每条给原例与改法。`taste_check taste` 的 21 项指标覆盖其中多数视觉项(紫渐变 / 居中大标题 / emoji 图标 / 圆角阴影 / 玻璃拟态 / 渐变文字 / 文案口癖),另补六条页面与交互项:
153
+
154
+ | 规则 | 判据 |
155
+ |---|---|
156
+ | `nest-boxes` 框里再套框 | 三层以上圆角容器链(两层是正常的卡片 + 内部区块) |
157
+ | `divider-sprawl` 分割线泛滥 | ≥8 处 1px border-top/bottom 或 `<hr>`(表格/列表用线是正常设计) |
158
+ | `big-black-tight` 又大又黑又挤 | 同一条规则里 ≥30px + 字重 ≥700 + 行高 ≤1.25 |
159
+ | `dead-button` 按钮没结果 | ≥2 个 `<button>` 无 submit / 点击绑定 / data-action |
160
+ | `icon-tile-uniform` 图标色块一律 | ≥3 个同类图标块,且 CSS 里宽高 32–64px、圆角 ≥12px、背景是渐变(三项取交集) |
161
+ | `eyebrow-spam` 小标签逐段开场 | ≥4 个 eyebrow/kicker 类小标签;0–1 个是正常编辑手法,不报 |
162
+
163
+ 判断原则:单个词、视觉元素或交互问题不能证明作者;看它是否与其他默认选择**成组出现**。单看每条都不致命,命中三项以上,用户就会想「这是 AI 做的」。
164
+
165
+ ### 位图层:手里只有一张图时也能判
166
+
167
+ `taste` 收 `.png` 时换一套像素层判据(自带解码器,零外部进程):
168
+
169
+ | 判据 | 量什么 |
170
+ |---|---|
171
+ | `img-indigo-hue` 紫蓝相主导 | 有色像素里落在 238–300° 的比例(下界不降到 210–235:那是真实产品最常用的蓝) |
172
+ | `img-ramp` 大面积平滑渐变 | 3×3 区域里有多少是**一维线性渐变**(单方向平滑 + 正交方向等色带) |
173
+
174
+ 另有一项只量不判(进 `raw.cardGrid`,不计分):`count` / `maxPerRow` / `equalWidth`。26 张「AI 制作的 UI 界面」截图里只有 1 张是模板长相(紫蓝渐变营销页,52 分),其余 25 张得 0——0 不代表没问题,是像素层看不见字号、间距、图标成套性、文案套路与交互态。
175
+
176
+ 两条像素判据只给事实、不判分:同构三卡片(25 张合格界面里有 6 张满足,计分就是 6/25 误报);中轴对称(三种量法都不成立——逐像素镜像被纯色背景抬到 86–91%,只比边缘像素时谁都归零,左右平衡 AI 0.98 / 某视频站 0.95 / 某安全软件 0.96,差距 0.03)。合格产出上像素层分不出 AI 与人,所以结果固定带 `scope:` 与 `blind spots:` 两行:**0 分 ≠ 这张没问题,更 ≠ 这不是 AI 做的**。
177
+
178
+ 三条纪律,每条都由误报校准:
179
+
180
+ | 纪律 | 为什么 |
181
+ |---|---|
182
+ | 只数**风格指纹**,不数通用质量缺陷 | 桌面应用本来就有 6 档小字号、7 个语义色;算进组合会把成熟产品判成模板(某在线文档产品的参照稿被判最强指纹,但它 24 分 acceptable,自相矛盾) |
183
+ | 只数**分值 ≥40** 的项 | 单个 emoji(20 分)属于零星迹象,凑进三项就是噪音 |
184
+ | 措辞只说**风格风险**,不指认作者 | 「像套模板」≠「这是 AI 做的」,后者不可证 |
185
+
186
+ 刻意没做的三项:单字动作(收一下 / 提一层)要看词性;同一件事换名字要跨文件对齐;每处都加描述小字要 DOM 语义——都需要语义理解,规则做不准。
187
+
188
+ ## 数据与许可
189
+
190
+ | 数据 | 内容 | 许可 |
191
+ |---|---|---|
192
+ | `data/lucide-icons.json` | lucide 1.70.0:2029 图标 + 289 别名 + 官方 tags + 43 类目(0.9 MB) | ISC |
193
+ | `data/packs/tabler.icons.json` | tabler 1.2.43 / iconSet 3.50:6302 图标(2.0 MB) | MIT |
194
+ | `data/assets/` | 221 项素材(品牌 12 / 图标 81 / 插画 42 / 角色部件 45 / 图案 12 / 贴纸 26 / 纹理 3,5.8 MB) | 逐项见 `manifest.json` |
195
+ | `vendor/morphicons*.iife.js` | morphicons 2.0.2(104 KB) | MIT |
196
+ | `vendor/resvg/` | resvg-js 2.6.2 JS 层 + win32-x64 原生绑定(4.4 MB) | MPL-2.0 |
197
+
198
+ simple-icons(3740 品牌)没有随包:它让体积从 11 MB 涨到 16 MB,而 `data/assets/icons/brands` 已覆盖 12 个常用品牌。
199
+
200
+ ## 图标与图形
201
+
202
+ ### 9 种风格预设
203
+
204
+ | style | 视觉语言 | 适合 | 16px 可读 |
205
+ |---|---|---|---|
206
+ | `outline`(默认) | 2px 线性,Feather/Lucide 基线 | 通用 UI | ✅ |
207
+ | `hairline` | 1px 细线,编辑/奢侈品观感 | 大尺寸、高档版面 | ❌ 太细 |
208
+ | `bold` | 2.8px 粗线 | 强调、图标按钮 | ✅ |
209
+ | `sharp` | butt/miter 尖角端点 | 直线型图标(+ − × ✓ 箭头) | ✅ |
210
+ | `solid` | 填充版(tabler `-filled`) | **小尺寸最清楚**、选中态 | ✅✅ |
211
+ | `duotone` | 20% 填充 + 线稿 | 中层装饰、功能入口 | ⚠️ 双色淡 |
212
+ | `badge` | 圆角方块底色 + 反白字形 | SaaS 功能入口、设置项 | ✅ |
213
+ | `knockout` | 正圆底色 + 反白字形 | app icon 语言、头像位 | ✅✅ |
214
+ | `gradient` | 渐变描边(`color` 起色,末色自动导) | 营销位、大尺寸展示 | ⚠️ |
215
+
216
+ **像素级差异**(同一 heart,96px 画布,与 `outline` 对比):`badge` 74% · `knockout` 61% · `solid`/`duotone` 43% · `hairline` 14% · `bold` 12% · `gradient` 6% · **`sharp` 0%**。`sharp` 只改线端与拐角,曲线封闭字形(heart/bell)本就没有可见端点,0% 是正确行为;直线型图标(menu/plus/x)有 7–11% 差异。其他能力:`strokeWidth` 1–64 任意字重(tabler 数据里 path 自带 stroke-width 会覆盖根层,已剥离;`emit strokeWidth=1.5`);tabler `brand-*` 411 个品牌 logo(含微信/淘宝/github,商标仅供平台指示用途;`icon find "微信"`);两态形变(线性 ↔ 填充、菜单 ↔ 关闭)由 morphicons 2.0.2 承担(含 region 填充形变,`morph check/preview icons: [...]`)。多色/渐变字形本体不支持,渐变只能作用于描边,需要时用 `design_render` 叠图层。
217
+
218
+ `badge`/`knockout` 用 `color` 作底色、`color2` 作字形色;`colibri`/`echo` 两个项目约定表达不了容器与渐变,会**明说退化**而不是默默无效。`icon find` 会顺手标注可选版本(如 `可选 filled/duotone 版`),做 hover/active 两态时直接取对应名字。尺寸 16–48px 都用同一套 24 网格数据矢量缩放,16px 下仍可辨认。
219
+
220
+ ### 正交维度:风格由参数拼出
221
+
222
+ | 维度 | 取值 | 作用 |
223
+ |---|---|---|
224
+ | `paint` | `stroke` / `fill` / `both` | 绘法(`both` = 填充 + 描边两层) |
225
+ | `strokeWidth` | 0–64 | 描边粗细 |
226
+ | `caps` | `round` / `butt` / `square` | 线端(`join` 自动配对) |
227
+ | `join` | `round` / `miter` / `bevel` | 显式转角 |
228
+ | `container` | `none` / `rounded` / `circle` / `squircle` | 字形装进底色(`none` 去掉预设容器) |
229
+ | `radius` | 0–12 | 容器圆角(squircle 时是曲率) |
230
+ | `inset` | 0–0.45 | 字形在容器里的留白 |
231
+ | `gradient` | `none` / `linear` / `radial` | 渐变类型 |
232
+ | `gradientAngle` | 0–360 | 渐变方向 |
233
+ | `duoOpacity` | 0–1 | 双色底层不透明度(需填充孪生体) |
234
+ | `color` / `color2` | 任意色值 | 主色 / 渐变末色或容器内字形色 |
235
+
236
+ `style` 的 9 个名字只是预设起点,真正的视觉语言由下列正交维度组合而成,任何维度参数传了就以它为准、覆盖预设。降级会说出口:填充字形上给 `strokeWidth` 会返回 note 明说「不生效」。渐变 id 按内容哈希唯一(`ak-g-<hash>`),同一页面内联多个渐变图标不串色。
237
+
238
+ ### 文字、渐变与 `stops`
239
+
240
+ `text` 给了就**取代字形**(不是叠在上面):用文字当图形,7-Zip 的「方块 + 7z」、字母徽章「K」、字母组合「AI / PDF」都是这一类;内容 1–4 字符,给了就可以不给 `name`。`textSize` 是 24 网格单位字号,不给则按字数自动适配安全区。
241
+
242
+ 自动字号按「可用宽度 ÷ 字数 ÷ 0.62」估算,所以 `K` 会比 `PDF` 大:14.13 / 11.61 / 9.29。居中用 `dominant-baseline="central"`:resvg 下 cy 落在 11.93(目标 12),`middle` 会偏到 11.13。文字能与阴影 / 渐变 / 中孔(`shapes`)叠加;内容做 XML 转义,不破坏 SVG 结构。`stops` 数组,每项 `color` 或 `color@offset`(0–1,对齐 SVG 的 `offset`):
243
+
244
+ ```text
245
+ 3 段 stops: ["#FF0000", "#FFFF00@0.5", "#00FF00"]
246
+ 彩虹 6 色 stops: ["#FF0000","#FF9900","#FFFF00","#00CC00","#0066FF","#9900FF"] ← 未写偏移自动均分
247
+ 径向 4 段 gradient: radial, stops: ["#FFF","#FFD6A5@0.35","#FF6B6B@0.7","#4B1D3F"]
248
+ 锐变分界 stops: ["#111","#111@0.5","#EEE@0.5","#EEE"] ← 同偏移两色
249
+ ```
250
+
251
+ 不传 `stops` 时走 `color`/`color2` 两色路径(末色可自动推导),完全向后兼容;传了 `stops` 就以它为准,且颜色不再限制 hex(`rgba()`、命名色都行)。没有 `spreadMethod`:渐变向量总铺满整个 24 网格盒子,一次循环覆盖全部,pad/repeat/reflect 像素采样相同;条纹用多停靠点 + 同偏移锐变更精确。
252
+
253
+ ### 自绘、`shapes` 与深度图元
254
+
255
+ `path` 参数直接吃原始 SVG path 数据(24 网格坐标):`icon emit path="M12 2 L22 12 L12 22 L2 12 Z" paint=fill color="#E8620C"`。`shapes` 的每一层也可以只给 `path`(此时不需要 `name`):
256
+
257
+ ```jsonc
258
+ shapes: [
259
+ { path: "M2 20 L9 8 L13 14 L16 10 L22 20 Z", color: "#FBBF24" }, // 山
260
+ { path: "M5.5 6 m-2.5 0 a2.5 2.5 0 1 0 5 0 a2.5 2.5 0 1 0 -5 0 Z", color: "#FDE68A" }, // 日
261
+ { path: "M2 17 C5 14 8 20 11 17 C14 14 17 20 20 17", color: "#38BDF8", weight: 1.2 } // 水
262
+ ]
263
+ ```
264
+
265
+ 自绘路径会被包成与库图标同构的节点,容器 / 渐变 / 阴影 / 遮罩减法 / 旋转 / 逐层线宽全部照旧生效。一条路径画环 / 镂空:`d` 里写多个子路径,加 `fillRule: "evenodd"` 就是「外套内挖」,例如环 `path="M12 2 a10 10 0 1 0 .01 0 Z M12 7 a5 5 0 1 0 .01 0 Z" fillRule=evenodd`(三孔板、花窗同法)。resvg 下外圆 + 内圆同向时 `nonzero` 中心 α=255(实心)、`evenodd` 中心 α=0(挖空),已写成像素级测试。
266
+
267
+ **安全**:path 数据直接进 `d="..."`,引号或尖括号能破出属性注入标签,所以走白名单校验(只允许 `MmLlHhVvCcSsQqTtAa` + 数字 + `. , - + e E` + 空白),必须以 `M`/`m` 开头,上限 4000 字符。非法整条丢弃,不静默截断。
268
+
269
+ `shapes` 是对象数组,每个元素是一个独立图层:
270
+
271
+ | 字段 | 取值 | 作用 |
272
+ |---|---|---|
273
+ | `name` | 库内图标名(必填) | — |
274
+ | `scale` | 0.02–4,相对 24 网格中心 | 整体缩放 |
275
+ | `dx` / `dy` | 偏移(网格单位,y 向上为负) | 中孔要靠它避开中心字形,否则永远被盖住 |
276
+ | `rotate` | 绕自身中心旋转的度数 | 场景组合(歪的树、斜飞的鸟);菱形孔只能靠旋转方孔 45° 做出来 |
277
+ | `color` | 该层独立颜色(`rgba()` / 命名色均可) | 异色角标不必绕成「容器当底」 |
278
+ | `stops` | 该层独立渐变:`["#FFD848","#FF7A30@0.5","#E01D5E"]` | 品牌美术几乎每层都有自己的渐变(Firefox 火焰 5 层全带渐变) |
279
+ | `gradient` | `linear`(默认)/ `radial` | 径向做球体、光晕;线性做金属、渐变条 |
280
+ | `angle` | 该层渐变角度 0–360 | 渐变方向 |
281
+ | `weight` | 该层独立线宽 0.1–12 | 插画靠「粗轮廓 + 细细节」拉层次,全图一个线宽只能得图标 |
282
+ | `subtract` | `true` = 从整个合成里挖掉(`<mask>`) | 环 / 吊牌孔 / 斜切角 / 镂空 |
283
+
284
+ 未写的字段走默认值;写了但越界(如 `scale: 99`)整条丢弃,不静默夹到边界。`subtract` 不作用于文字——文字画在 mask 之外。每层渐变用 `objectBoundingBox` 坐标,自动适配该层包围盒,不用手算绝对坐标。
285
+
286
+ 深度与虚线只给图元,不提供「微拟物」「液态玻璃」这些风格名:
287
+
288
+ | 参数 | 适用 | 作用 |
289
+ |---|---|---|
290
+ | `shadow` | `icon emit` / `composite` | CSS box-shadow 语法:逗号 = 多阴影,`inset` = 内阴影,颜色任意 |
291
+ | `dash` | `icon emit` | `stroke-dasharray`(数组,按 24 网格单位) |
292
+
293
+ `shadow` 沿用 CSS 语法:模型对这套写法已经很熟,不用学新格式——双光源微拟物写 `4px 4px 8px #A3B1C6, -4px -4px 8px #FFFFFF`,内阴影写 `inset 0 3px 6px rgba(0,0,0,.4)`,高程体系写 `0 1px 2px rgba(0,0,0,.12), 0 8px 24px rgba(0,0,0,.2)`,技术图虚线写 `dash: [4, 2]`。
294
+
295
+ resvg 约束(写进代码注释):`feDropShadow` 无效 → 外阴影改用「模糊的偏移副本」;`feMorphology`(spread)无效 → `shadow` 的第 4 个数值目前忽略;位图图层用 `feGaussianBlur(SourceAlpha) + feFlood + feComposite` 把 alpha 染成阴影色。
296
+
297
+ ### 图层合成
298
+
299
+ `design_render action=composite` 由九个维度组合:
300
+
301
+ | 维度 | 取值 | 作用 |
302
+ |---|---|---|
303
+ | `anchor` | 9 个方位(`top-left` … `bottom-right`) | 图层放哪里(默认 `center`) |
304
+ | `padding` | px | 四边内缩(app 图标安全区) |
305
+ | `fit` | `contain` / `cover` / `fill` / `none` | 缩放策略(`fill` 会拉伸,不等比) |
306
+ | `scale` | 0.05–8 | 在 `fit` 之后再加一层倍率 |
307
+ | `blend` | `normal`/`multiply`/`screen`/`overlay`/`darken`/`lighten`/`difference` | 混合模式 |
308
+ | `rotate` | 角度 | 绕图层中心旋转 |
309
+ | `canvas` | `[宽, 高]` | 显式画布尺寸 |
310
+ | `under` | 路径或纯色 `#RRGGBB` | 底可以是颜色,不用先做一张底图 |
311
+ | `opacity` | 0–1 | 图层透明度 |
312
+
313
+ 例:`design_render action=composite under=#F5F5F0 canvas=[512,512] over=icon.png anchor=center padding=48 out=app.png ico=true sizes=[256,128,64]`。
314
+
315
+ 产出会回填 `anchor` / `fit` / `padding` / `rotate` / `blend` / `opacity` 与图层的实际几何(`layer.{x,y,width,height}`),能确认参数真的生效。
316
+
317
+ **软件图标(app icon)**:`composite` 三步出一个 1024 圆角图标:`under` 传内联 SVG(圆角矩形 `rx` ≈ 22% 边长 + 渐变/纯色);`over` 传 `icon emit target=raw` 的 SVG;`scale` = 0.5–0.6(主流 app 图标的安全区内缩),`out` = `app-1024.png`。多尺寸与 Windows 图标一次出全套:`sizes=[1024,512,192,180,32] ico=true`。
318
+
319
+ 产出 `<名字>-<尺寸>.png`(从合成 SVG 重渲染,不是缩 PNG)+ `<名字>.ico`(16/32/48/64/128/256 六帧内嵌 PNG,Windows 10/11 原生支持)。没有 .icns / Android adaptive 分层 / PWA maskable 校验,需要请自行转。
320
+
321
+ ## 排版检测(layout_check)
322
+
323
+ 三类输入、同一把尺(0–100,越低越好;error 15 / warn 6 / info 2 扣分,与 `taste_check taste` 同口径):
324
+
325
+ | 模式 | 输入 | 自动检测 | 不覆盖 |
326
+ |---|---|---|---|
327
+ | `ui` | HTML/CSS/Vue/JSX 源码 | 字号梯级与最小字号、行高比例、行长(measure)、字体家族数量、对齐(justify/长段居中)、字距、中英混排空格 | 真实渲染后的换行与断句 |
328
+ | `svg` | 成品 SVG(海报/卡片/banner/信息图) | 文字层级、行距、安全区/贴边、溢出画布、文字重叠、对齐关系、最小字号(含 viewBox 缩放换算) | 字体回退后的真实字形宽度(用字符宽度模型估算) |
329
+ | `image` | 渲染后的 PNG | 内容边距/出血、密度、左右上下视觉平衡、对齐线索、分辨率 | 文字内容与对比度(无 OCR) |
330
+
331
+ `svg` 模式不需要 OCR——SVG 里本来就有 `text` 的坐标与字号,直接量真实几何;`image` 模式补「只有图没有源」的场景。三者产物结构一致(score/grade/counts/findings/metrics),可直接在流水线里当门禁(如 `score < 35` 才允许交付)。规则集(每条 finding 都带 `rule` + 定位 + 实测值 + `fix`):
332
+
333
+ | 模式 | 规则 |
334
+ |---|---|
335
+ | `ui` | `S1`–`S14` 字号梯级/最小字号(字号×字重)/行高/行长/字体数/对齐/字距/混排/标题层级/混排基线/阴影层级/响应式断点/组件状态矩阵/**负外边距** · `punct-*` 12 条中文标点 · `contrast-*` 对比度 · `structure-heading-*` 标题跳级 · `structure-touch-*` 触摸目标 |
336
+ | `svg` | `G1`–`G9` 安全区/层级/行距/行长/溢出/重叠/对齐/最小字号/留白 · `contrast-*` · `structure-baseline-*` 基线网格 |
337
+ | `image` | `P1`–`P9` 贴边/边距对称/密度/平衡/对齐/分辨率/无 OCR 声明/卡片栅格一致性/列表行高一致性 |
338
+
339
+ **应用外壳分档(S1 / S9 / S4 / heading-first)**:桌面/Web 应用的「工具栏 + 栏位」界面与文档/落地页对排版的要求不同,同一套尺子量会误报。检测到应用外壳后自动分档:
340
+
341
+ | 规则 | 文档页 | 应用外壳 |
342
+ |---|---|---|
343
+ | `S1` 字号梯级 | 最大/正文 < 1.6 → **error** | 降为 info(梯级偏平,仅作参考) |
344
+ | `S9` 标题层级 | h3/正文 < 1.25 → **error** | 降为 info(组件标题不靠字号分层级) |
345
+ | `S4` 行长 | 算 `max-width` 与根宽 | 根选择器只认 `max-width`(`body{width:1366px}` 是视口不是阅读栏) |
346
+ | `structure-heading-first` | 文档 + 非外壳 + ≥3 个标题才判 | 不判 |
347
+
348
+ 外壳判据(两条同时成立):① 根元素满高(`height:100%` / `100vh`)或 `overflow:hidden`;② 存在 `display:flex/grid` 的布局容器。分档效果:某在线文档产品参照稿(无豁免)**56 → 24**;Flow-Pilot(Electron 应用)**66 → 27**。重点规则的阈值:
349
+
350
+ | 规则 | 判据 / 阈值 |
351
+ |---|---|
352
+ | `S14` 负外边距 | `margin` 取负即报:用于把两块内容硬拉近会破坏间距层级(块间距 < 块内间距),换主题/字号就崩 |
353
+ | `S13` 组件状态矩阵 | 有 `hover` 没 `focus` → warn(WCAG 2.4.7 AA);组件间状态覆盖差 ≥2 → info;`active`/`disabled` 缺失不单独判 |
354
+ | `S12` 响应式断点 | 同方向差 ≤3px → warn;`max-width: X` 与 `min-width: X` 并存 → warn;两方向各 ≥2 档 → info;767 配 768 的标准互补对不报 |
355
+ | `S11` 阴影层级 | 光源方向不一致 → error;>4 档 → warn;相邻档位倍数 <1.3 → warn |
356
+ | `S10` 混排字号基线 | 阈值 1.8×;22px 大字标 + 16px 标签(1.375×)居中不报;典型场景如 5.42 GiB(72px 数字 + 20px 单位) |
357
+ | `S2` 字号 × 字重 | 有效字号 = 字号 × 字重系数(400→1.0 / 500→1.1 / 600+→1.2);有效 <11 报 error、<13 报 warn。12px/400 仅 **5.5%** 笔画像素实心(94.5% 是半透明灰),12px/600 为 **29.3%** |
358
+
359
+ `punct-*` 的分类参考 [typography-audit](https://github.com/mblode/agent-skills) 的 78 条规则;对比度(WCAG 2 + APCA)与基线网格来自 [typography-skills](https://github.com/thomasguillot/typography-skills);标题顺序与触摸目标来自 [layout-lint-mcp](https://github.com/LOsioChico/layout-lint-mcp);「覆盖度必须声明」来自 [breaklint](https://github.com/godarg/breaklint)。业界主流靠 Playwright 量计算样式,本工具零外部进程:源码项解析声明,产物项读 SVG 真实坐标,文字宽度靠 95 字 advance 表(与 HarfBuzz 差 0.02%)。
360
+
361
+ **覆盖度**:报告里带 `rulesRun`(实际跑了几条规则)与 `measured`(测了什么)。`score` 为 clean 但 `rulesRun: 0` 意味着什么都没测,不要当成排版没问题。**声明豁免**:与 `taste_check taste` 同一套语义,一个项目只需一份 `.design-intent.json`;有意偏离规则时写下来,而不是跳过规则:
362
+
363
+ ```json
364
+ { "allow": ["S9", "structure-heading-first"], "reason": "h5/h6 未做组件映射,有意收敛到正文大小" }
365
+ ```
366
+
367
+ `allow` 里的规则不计分、不进 `findings`,而是进 `metrics.exempted` 与报告的 `intent` 段(带 `reason`)。`ui` 从扫描根目录读,`svg` 从 `.svg` 文件所在目录读。**两个体检工具的分工**:`taste_check` 管审美/风格/文案(emoji 图标、渐变滥施、卡片同构、无交互态、AI 套路文案…21 条);`layout_check` 管排版(字号梯级、行高、行长、标点、对比度、标题结构…)。两边都提到字号,但结论口径一致(都是「最大字号 / 正文」比 1.6),且 `taste_check` 的对应项会把更细的 `file:line` 明细指向 `layout_check`,不会给出两个互相矛盾的分数。
368
+
369
+ ## 渲染与截图
370
+
371
+ **`design_render action=diff` — 两图差异**(`base=orig.png compare=mine.png out=heat.png slices=7 align=true`):返回均像素差(可横比多轮)、分区差(差异在哪一栏)、热力图 PNG。`align=true` 额外做偏移搜索,区分「排错了」与「整块平移了几像素」:整块平移时最佳位移只改善 2.6%。**`layout_check action=image` 的 `profile` — 从截图反推版式**:
372
+
373
+ | 字段 | 含义 |
374
+ |---|---|
375
+ | `palette` | 主色板 top 6 + 面积占比 |
376
+ | `columns` | 栏位/卡片的水平范围(自动排除版心间隙) |
377
+ | `rowPitch` | 行节奏(列表类界面的行距),附样本数 |
378
+ | `cards` / `cardGrid` | **卡片矩形 + 栅格**:每张卡片的 (x,y,w,h),列起点、列间距、行间距 |
379
+ | `vEdges` | **栏位垂直分界线**(x 坐标):贯穿全高的边界,办公/客户端界面靠它分栏最稳 |
380
+ | `list` | **列表/表格行距 + 一致性**:`pitch` 行距、`count` 样本数、`uniformPct` 一致率、`outliers` 异常间距 |
381
+
382
+ 两种布局各用一套判据(互为替代,坏的那个自动不显示):大底色 + 规整栏位看 `columns` + `vEdges`(某视频站动态页:侧栏 / 动态流 / 右侧直播);卡片栅格 / 渐变背景看 `cards` + `cardGrid`(某下载工具仪表板);表格 / 列表密集看 `list`(某在线文档产品:行距 85px,10 行,一致 100%)。两个页面的量值:原图 `49~243 / 441~887 / 895~1082`,改版稿 `48~241 / 441~880 / 891~1080`——差 1~6px,行节奏 48 vs 48。卡片阈值必须相对页面底色算:`#F6F7F9` 三通道都 ≥246,固定 246 会把整页底当卡片、连通成 2072×1414。在线文档参考图 `vEdges x=91/457/1539/1552/2031` 对上图标栏|二级侧栏|主内容|右侧工具面板四条边界;某下载工具卡片 8 张(列起点 314/584/854/1123,列间 24px,行间 24px),4 列 KPI + 双宽卡 + 通栏卡一次量清。
383
+
384
+ **真实渲染:对比度与 HTML → PNG**。静态解析 CSS 遇到 `rgba()`、CSS 变量、渐变背景时算不出真实对比度,只能跳过(`contrast-invalid`);这三类恰好是现在最常用的写法。加 `render=true` 后在真实像素上量:`layout_check action=ui root=page.html render=true width=760 height=420`。
385
+
386
+ 原理(不靠 OCR、不靠 DOM):同一页面渲两遍(A 正常;B 用 `*{color:transparent!important}` 把文字染透明,布局不变)→ A/B 差异大的像素是文字墨迹 → 连通域分组,域内最墨像素给文字色,同位置 B 渲染给真实背景 → 按文字色去重逐种配色报对比度。三条实现约束:不能取最小对比度像素(必然落在抗锯齿边缘,假报 1.28:1);不能按颜色聚类(边缘中间调自成一簇,假报 2.23:1);必须关 LCD 子像素渲染(彩边假报 1.97:1)。渐变底 + 半透明白卡上的输出:
387
+
388
+ ```
389
+ [error] contrast-effective 实际渲染对比度不足:2.52:1 —— 文字 rgb(138,143,168)
390
+ 压在真实背景 rgb(75,58,185) 上(42px 墨迹)
391
+ [error] contrast-effective 实际渲染对比度不足:2.99:1 —— 文字 rgb(180,184,200)
392
+ 压在真实背景 rgb(97,85,191) 上(61px 墨迹)
393
+ ```
394
+
395
+ 同一页面上白字 9.42:1、深灰字 5.79:1 正确不报,与静态计算一致。
396
+
397
+ `design_render action=html` 把 HTML/CSS 渲染成 PNG(`html=page.html out=shot.png width=1280 height=764 pageScale=2 fullPage=true`)。软件内部界面本身就是 web 版,不能渲染 HTML 就看不到自己的输出:静态体检全绿,渲染后才看得见头像视觉重量、侧栏行高、字号偏大。`fullPage` 分两趟:先 `--dump-dom` 让页面把 `scrollHeight` 写进 title 读回内容高,再用 `--window-size=W,内容高` 截第二趟。Chromium 无头模式始终只截视口,不传 `--window-size` 时用默认窗口(750×485);返回值带 `pixelWidth` / `pixelHeight`,直接从 PNG 的 IHDR 读实测像素,不会出现「报 1100×1500、实际 750×485」。
398
+
399
+ | 能力 | 依赖 |
400
+ |---|---|
401
+ | SVG → PNG、图层合成、素材库 | **完全自包含**(vendored resvg,零外部进程) |
402
+ | HTML → PNG | 需要本机 Chromium 系浏览器(Edge / Chrome / Chromium),自动探测 |
403
+
404
+ 不写自研布局引擎:浏览器引擎才是唯一可信的参照。探测不到时明确报错并给出下一步(装浏览器 / 配 `browserPath` / 改用 `action=render`),不静默回退。没有浏览器的机器上,其余工具一切正常。
405
+
406
+ ## 测试
407
+
408
+ ```powershell
409
+ npm test # 全套功能测试(node:test),约 34 秒
410
+ npm run test:spec # 同上,spec 风格逐条列出
411
+ npm run test:pack # 只跑发布边界(真的 npm pack → 解包 → 用拆包副本跑一遍)
412
+ ```
413
+
414
+ | 层 | 文件 | 验什么 |
415
+ |---|---|---|
416
+ | 契约 | `test/contract.test.mjs` | 8 工具注册/参数/必填/常驻 token 预算、输出无损(无 undefined/NaN)、错误消息可行动、确定性、相对路径按会话目录、并发声明、零依赖与无外部程序守卫、包元数据完整性 |
417
+ | 渲染 | `test/render.test.mjs` | 自己解 PNG 看像素:透明底真透明、缩放保比、中文真的画出字、图层不被拉伸、opacity 混合数学、输出后缀与 width 上限 |
418
+ | 图标/形变 | `test/icon.test.mjs`、`test/morph.test.mjs` | 2029 图标全量契约、5 种出码约定、非法 size/strokeWidth、形变体检与预览页自包含 |
419
+ | 体检 | `test/taste.test.mjs`、`test/audit.test.mjs` | 21 条规则逐条命中与反例、三档 profile、声明豁免、坏 JSON 不崩、单文件/大文件/扫描上限 |
420
+ | 风格/素材 | `test/style.test.mjs`、`test/assets.test.mjs` | 48 组合 × 3 格式、去同质化不变量、tailwind 真能执行、素材全库 221 项、目录穿越与标签注入拦截 |
421
+ | 发布边界 | `test/pack.test.mjs` | tarball 必需文件/无泄漏/体积、拆包后只用包内 data+vendor 跑一次工具调用 |
422
+
423
+ 非 win32 平台渲染用例自动 skip(vendored resvg 只有 win32-x64 绑定),其余全部照跑;CI 在 windows 与 ubuntu 都跑整套。渲染产物落在 `.test-out/*.png`,Windows CI 会上传为 artifact 供人工看效果。
424
+
425
+ ## 配置
426
+
427
+ | 键 | 默认 | 说明 |
428
+ |---|---|---|
429
+ | `previewDir` | `""` | morph preview 默认输出目录(空 = 系统临时目录) |
430
+ | `findLimit` | `12` | icon find / asset find 默认条数 |
431
+ | `maxAuditFiles` | `4000` | taste_check audit 扫描上限 |
432
+ | `maxFindings` | `60` | taste_check audit 返回上限 |
433
+ | `iconPacks` | `["tabler"]` | 装载的图标包(默认只 tabler,控制体积) |
434
+
435
+ ## 边界
436
+
437
+ - **不做像素级图像处理**:没有裁剪、滤镜、调色。需要这类能力用 `dsh-imagekit`(造新图);`dsh-visualkit` 管「让图和界面好看」。
438
+ - **不联网**:除 `action=html` 调用本机浏览器外,所有产物都在本地生成,预览页是自包含 HTML(用户自己开)。
439
+ - **合成只做叠加**:`composite` 是「底图 + 上层」两层 alpha 叠加,不做多图层排序。图层保宽高比、居中、不放大;位图图层只收 PNG(JPEG/WebP 量不到尺寸,请先转 PNG)。
440
+ - **`taste_check audit` 的 emoji 规则按字符扫描**:注释、文案、状态标记里的 emoji 也会报(规则语义是「源码里不出现 emoji 图标」,不做语法级区分)。测试/样本目录(`test/` `fixtures/` `spec/` 等)默认跳过。
441
+ - **`morph check` 把非 24 网格当阻塞项**(`ok:false`):引擎层能 re-grid,但项目管线(`UI.svg` / `morphTo`)要求 24 网格数据。`morph preview` 与 `design_render` 会自动归一化。
442
+ - **`layout_check` 的 svg 模式不量 `<g transform>` 内的文字**(坐标系换算不可靠,计入 `unmeasured` 并提示);image 模式无 OCR,不做文字可读性与颜色对比度判定。
443
+ - **字体靠系统**:resvg 用系统字体,中文默认 `Microsoft YaHei`;换机器字体缺失会回退,不保证字形一致。
444
+ - **原生绑定是 win32-x64**:换平台需要重新 vendor `vendor/resvg/` 里对应的 `.node` 文件。
package/THIRD_PARTY.md ADDED
@@ -0,0 +1,55 @@
1
+ # 第三方资产与许可
2
+
3
+ 本包的**代码**以 MIT 发布(见 `LICENSE`);包内分发的**资产**来自第三方项目,各自遵循原许可,逐项列出以便合规审计与署名。
4
+
5
+ ## 一、运行时依赖(vendored)
6
+
7
+ | 组件 | 版本 | 许可 | 用途 | 位置 |
8
+ |---|---|---|---|---|
9
+ | [morphicons](https://github.com/guillermolg00/morphicons) | 2.0.2 | MIT © Guillermo | SVG 图标形变引擎 | `vendor/morphicons.iife.js`、`vendor/morphicons-adapters.iife.js` |
10
+ | [resvg-js](https://github.com/thx/resvg-js) | 2.6.2 | **MPL-2.0** | SVG → PNG 渲染(含 win32-x64 原生绑定) | `vendor/resvg/` |
11
+
12
+ > **resvg 是 MPL-2.0**:本包分发其未修改的构建产物并保留原 `LICENSE`(`vendor/resvg/LICENSE`)。MPL-2.0 是文件级 copyleft——修改 resvg 源文件才需公开那部分,与本包自身代码无关。自行重建绑定见 `vendor/resvg/package.json` 的 `name`/`description`。
13
+
14
+ ## 二、图标数据
15
+
16
+ | 数据 | 版本 | 许可 | 位置 |
17
+ |---|---|---|---|
18
+ | [lucide](https://lucide.dev) | 1.70.0 | **ISC** | `data/lucide-icons.json`(2029 图标 + 289 别名 + 官方 tags + 43 类目) |
19
+ | [Tabler Icons](https://tabler.io/icons) | 1.2.43 / iconSet 3.50.0(via `@iconify-json/tabler`) | **MIT** | `data/packs/tabler.icons.json`(6302 图标) |
20
+
21
+ 两个数据文件都是从上游 npm 包**提取的几何数据**(`[tag, attrs][]` 形式),由 `tools/build-icon-data.mjs` 生成;许可见各文件 `source` 字段。
22
+
23
+ ## 三、素材库(221 项,`data/assets/`)
24
+
25
+ | 目录 | 内容 | 数量 | 来源 | 许可 |
26
+ |---|---|---:|---|---|
27
+ | `icons/lucide/` | 线性图标(currentColor) | 10 | Iconify `@iconify-json/lucide` | ISC |
28
+ | `icons/tabler/` | Tabler 线性图标 | 40 | Iconify `@iconify-json/tabler` | MIT |
29
+ | `icons/phosphor/` | Phosphor duotone 图标(256 viewBox) | 31 | [phosphor-icons/core](https://github.com/phosphor-icons/core) | MIT |
30
+ | `icons/brands/` | 平台品牌图标(B站/油管/TG/QQ/微信/抖音…) | 12 | [simple-icons](https://github.com/simple-icons/simple-icons) | CC0(**商标权属各平台**) |
31
+ | `stickers/twemoji/` | 表情贴纸 | 24 | [jdecked/twemoji 15.1](https://github.com/jdecked/twemoji) | **CC-BY-4.0** |
32
+ | `stickers/openmoji/` | 手绘风表情 | 2 | [hfg-gmuend/openmoji](https://github.com/hfg-gmuend/openmoji) | **CC-BY-SA-4.0** |
33
+ | `illustrations/openpeeps/` | 手绘人物插画(可改色/组合) | 42 | [openpeeps.com](https://www.openpeeps.com)(Pablo Stanley) | CC0 |
34
+ | `patterns/` | 可平铺图案(currentColor) | 12 | 程序化自产 | CC0 |
35
+ | `textures/` | 噪点底纹 PNG 512² | 3 | 程序化自产 | CC0 |
36
+ | `parts/` | 角色部件(透明底 PNG) | 45 | 自有素材拆分 | 自有 |
37
+
38
+ 逐项许可见 `data/assets/manifest.json` 的 `license` 字段;目录用法见 `data/assets/README.md`。
39
+
40
+ ## 四、需要署名的资产(CC-BY)
41
+
42
+ 对外作品中**分发**下表内容时保留署名:
43
+
44
+ | 资产 | 署名要求 |
45
+ |---|---|
46
+ | Twemoji(24 项贴纸) | "Copyright 2020 Twitter, Inc and other contributors" — [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) |
47
+ | OpenMoji(2 项贴纸) | "OpenMoji — the open-source emoji and icon project" — [CC-BY-SA-4.0](https://creativecommons.org/licenses/by-sa/4.0/) |
48
+
49
+ > **CC-BY-SA 提示**:ShareAlike 要求**对该素材的改编作品**同样以 CC-BY-SA 发布。本包只把原文件打包分发(未改动),不触发传染;但基于这 2 个 OpenMoji 文件二次创作并对外发布,那件作品需要 CC-BY-SA。不确定时优先换用 `stickers/twemoji/` 或其他 CC0 素材。
50
+
51
+ ## 五、商标与字体
52
+
53
+ `icons/brands/` 与 `data/packs/`(如有品牌图标)中的 Logo 商标权属各公司。本包以 CC0 分发其 SVG 几何数据(simple-icons 项目本身的许可),**不代表授权**在这些商标所有者的场合使用;仅建议用于"平台指示"(如登录按钮旁标注"用 GitHub 登录")。商业使用请自行确认各平台品牌规范。
54
+
55
+ 本包不内嵌任何字体文件。渲染时使用**系统字体**(`design_render` 默认 `Microsoft YaHei`),字体许可由使用者所在系统承担。