Files
workbuddy_skills/draw-ui/references/reference-measurement.md
T
admin 237a09a5b0 修:draw-ui / oil-motion 原被当子模块指针收录 ⇒ 改为正常文件入库(两份内容原先对别人是空的)
一、问题(本轮实测)
`draw-ui` 与 `oil-motion` 目录里**各自带一个内嵌 `.git`** ⇒ 上一次提交把它们记成了 **gitlink(子模块指针)**
⇒ 仓库里只存了一个不属于任何远端的 commit id,**别人克隆下来这两份是空的** ✗(`git status` 显示 ` m draw-ui` / ` m oil-motion` = 子模块内容有改动)。

二、处置(可回退)
· 把两处的 `.git` **挪走**(⛔ 不是删除)⇒ `归档/内嵌git-20261008/{draw-ui,oil-motion}.git`;
· `git rm --cached` 掉那两个 gitlink,再 `git add` 两个目录 ⇒ **按正常文件入库**(内容才真的进仓库)。

三、副作用(如实记)
挪走 `.git` 后,这两个技能**不能再原地 `git pull` 取上游更新**(要更新得重新拉一份覆盖);
如需恢复其本地仓库,把 `归档/内嵌git-20261008/` 里的 `.git` 挪回原处即可。
2026-10-08 22:29:52 +08:00

7.6 KiB
Raw Blame History

测量与采集接口

依赖 Python 3.10+ 与 Pillow。执行顺序以 测量与校准 为准;本文件只定义输入、命令和输出。文件路径相对各自清单目录解析,测量、轮次和验收报告均使用新的输出目录。

区域清单

在任务目录保存 regions.json。使用原图像素;看到的是缩略图时,先按原图实际宽高分别换算坐标。

{
  "reference": "reference.png",
  "css_viewport_width": 1024,
  "expected": {
    "url": "http://127.0.0.1:4187/",
    "title": "示例页面",
    "viewport": {"width": 1024, "height": 900},
    "dpr": 1,
    "full_page": true,
    "screenshot_scale": "css"
  },
  "regions": [
    {"name": "background", "kind": "color", "box": [20, 20, 100, 40], "inset": 2},
    {"name": "card-a", "box": [40, 200, 280, 320], "group": "cards", "selector": ".card:nth-child(1)"},
    {"name": "card-b", "box": [344, 200, 280, 320], "group": "cards", "selector": ".card:nth-child(2)"},
    {"name": "title-ink", "box": [40, 90, 420, 70], "box_type": "ink", "selector": "h1"}
  ]
}
字段 含义
name 区域唯一名称
box 原图像素的 [x, y, width, height],整数且不得越界,不是右下角坐标
kind box(默认)记录几何;color 统计框内颜色
box_type element 为元素外框,ink 为可见字形,sample 为采样区;默认随 kind 选择 element 或 sample
inset 颜色采样向内避开的像素数,不得使区域变空
group 同一横向重复结构,至少两个元素框,不混入字形或采样框
selector 实现后定位主文档元素的 CSS 选择器;测量可省略,准备 DOM 采集至少需要一个
css_viewport_width 实现视口约定,用于建立比例;不证明原页面的视口或 DPR。仅测图且未知时可省略
expected 浏览器采集条件;仅测图可省略。视口宽度必须与 CSS 映射一致

expected.screenshot_scale 为 css 或 device,后者按 DPR 输出像素。截图宽度必须等于原图宽度;例如原图宽 2048、CSS 视口宽 1024 时可用 DPR 2 与 device。视口截图还须与原图等高;完整长页由 full_page: true 明确。

颜色只统计完全不透明的像素,并报告排除数量;半透明素材需另行确定合成背景。

命令与产物

以下路径为示例,占位目录需替换为本次任务路径。脚本不启动浏览器;--preflight 是会访问本地 HTTP 页面身份的可选检查。

阶段 命令 主要输出
测量 python3 scripts/measure_reference.py --manifest /task/regions.json --out-dir /task/measurement-01 measurements.json 与自包含标注图 annotations.svg
准备采集 python3 scripts/prepare_capture.py --measurements /task/measurement-01/measurements.json --out-dir /task/round-01 run.json、collect.js、capture-plan.json、round-notes.md
本地静态页预检 python3 scripts/verify_capture.py --manifest /task/round-01/run.json --preflight 服务地址、重定向与 HTML 标题检查
验收 python3 scripts/verify_capture.py --manifest /task/round-01/run.json --out-dir /task/round-01/report verification.json、geometry.md、分区图片差异

后续轮次用同一 measurements.json 准备新目录;验收命令增加 --previous /task/round-01/report/verification.json 可比较前轮。verify_html_mockup.sh 是 verify_capture 的薄封装,参数相同,不负责打开浏览器。

measurements.json 保存原图尺寸与摘要、原始坐标、归一化比例、可选 CSS 映射、RGB 中位数与 10%/90% 分位数、网格尺寸和间距分布。annotations.svg 用于核对人工选区,不代表自动识别边界。

run.json 绑定同一参考图、测量摘要、预期条件和待采集文件;capture-plan.json 供核对目标。记录实现取舍用 round-notes.md,不另抄坐标表。

浏览器采集数据

读取生成的 collect.js,在浏览器主文档上下文求值,不能在 Node.js 全局执行。表达式只读页面,不访问网络或读取表单值;返回以下数据:

  • url、title、viewport、dpr、document_height、fonts_ready、images_ready。
  • 绑定的 measurement_sha256、各区域的 elements(选择器、状态、文档 CSS 坐标外框与计算样式),以及图片 assets。
  • 宿主另从真实截图选项补充 full_page、screenshot_scale,将完整对象保存为 capture.json;同次截图保存为 candidate.png。

采集状态为 measured、missing、ambiguous、hidden、unmeasurable 或 invalid_selector。选择器必须唯一;离开视口但仍在文档流中的元素可测量。iframe、Shadow DOM、canvas 和小程序不在此采集器范围内。

关键图片可在区域清单中增加 expected_assets,以同名区域关联,selector 必须指向 img:

{"expected_assets": {"logo": {"src": "http://127.0.0.1:4187/assets/logo-v2.png", "natural_width": 2048}}}

采集的 src 来自 currentSrc,另有 natural_width、natural_height、version(来自 data-version)。验收逐字段匹配;复用相同路径与尺寸时需增加可靠的版本标记或另验内容哈希,路径相同不能证明图片更新。背景图等非 img 资源由宿主额外检查。

报告与失败语义

  • 标注越界、区域无效、颜色没有不透明样本、输出目录已存在:退出码 2,不自动裁短错误框或覆盖旧轮次。
  • 准备时缺少条件、没有选择器、映射不符或参考图已变:退出码 2,修正源清单后重新测量。
  • 页面身份、渲染条件、截图尺寸或基线不一致:验收拒绝;保留原始采集与错误,不能当成通过。
  • 元素采集不完整:保存诊断报告并以退出码 2 结束。visual_only(字形或采样区)和 reference_only(无选择器)不计算 DOM 外框误差。
  • 相同基线与采集条件下,前后报告用 reduced、increased、unchanged、unavailable 表示最大绝对 CSS 偏差的变化,不设通用审美通过阈值。

只有截图或非 DOM 渲染

只有两张图片时使用文件比较,不伪造采集数据:

python3 scripts/compare_mockup.py --reference /task/reference.png --candidate /task/candidate.png --out-dir /task/image-report --prefix screen

可增加 --clip header:0,0,1024,80,坐标为图片像素。默认拒绝宽高不一致;长页显式增加 --allow-height-difference 后仅比较共同坐标,保留高度差与未匹配尾部,缺失完整分区不计分。宽度不一致始终停止,不自动拉伸。该分支不提供浏览器身份或交互验证。

已有真实浏览器截图及元数据、但没有区域测量时,可手写 run.json:填写 reference、candidate、capture_metadata 与上方同结构的 expected。可选 allow_height_difference、clips 和 section_positions;后者为区域名到 CSS y 坐标的映射,与元数据 sections: [{"name":"hero","y":80}] 对照。该分支使用 verify_capture,但不支持 --previous 的自动元素比较。

可选的竖向色带扫描

适合阈值判断的平坦色带可在区域清单中增加:

{"vertical_scans": [{"name": "light-band-left", "x": 10, "y": 300, "height": 500, "min_channel": 175, "max_channel_spread": 45, "min_run": 20}]}

脚本寻找各通道不低于 min_channel、通道最大差不超过 max_channel_spread、长度至少为 min_run 的不透明连续区间,结束坐标不包含尾像素。多个横坐标可帮助定位斜边;命中也可能是文字或插画高光,不能自动认定为区块边界。