bug-reproduce
Turn a known bug into a tight, red-capable reproducer, then prove the reproducer locks that…
Visual-alignment workflow for a new UI need or a UI改进. Index-first (consult the ui-kit registry to avoid re-building an existing primitive), then implement, then run the screenshot harness to capture the component in light/dark against the live /ui-kit, then produce a ReportCard
$ npx -y skills add Prismer-AI/PrismerCloud --skill ui-align --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/ui-alignContext preview
The summary Claude sees to decide when to auto-load this skill.
Visual-alignment workflow for a new UI need or a UI改进. Index-first (consult the ui-kit registry to avoid re-building an existing primitive), then implement, then run the screenshot harness to capture the component in light/dark against the live /ui-kit, then produce a ReportCard
name: ui-align description: Visual-alignment workflow for a new UI need or a UI改进. Index-first (consult the ui-kit registry to avoid re-building an existing primitive), then implement, then run the screenshot harness to capture the component in light/dark against the live /ui-kit, then produce a ReportCard (screenshot assets side by side + a written conclusion) the requester reviews VISUALLY without reading code. The harness computes NO image diff — it verifies side effects (screenshots really have pixels, assets uploaded, ReportCard persisted); both "the visual looks good" and any deviation number are human judgments the machine never produces. license: MIT scope: common compatibility: - claude-code allowed-tools: - Bash metadata: category: design
把「新 UI 需求 / UI 改进对比」跑成 **索引 → 实现 → 截图 → 报告** 的闭环(docs/apc/07 Part A §A4)。 产出是一张 **ReportCard**:把同一组件的 **light / dark 两态截图** + 对比结论落成一张可寻址的富报告页, 需求方**从视觉验收,不读代码**。
**什么时候用**:一个 UI 组件要新增 / 改样式 / 做前后对比时。**第一步永远是查索引**——ui-kit 已经把 现有原语拆成 `registry.ts` 索引,先看有没有现成的,别重复造第 N 个 Dialog / Button / Card。
新需求先对索引,命中就复用,不命中才新增一片。索引是唯一真源——**不 grep 源码猜有没有**。
需求方点开卡就看到 before/after,不必读 diff。
的对比度 / 边框 / 玻璃态塌缩——两态并排是对齐评审最有用的形态。
对比表结构对),**不是**"好不好看"。**别在报告里声称"视觉已验证正确"**——那是人的判断(同 design-review 固有局限)。
reportCard pageId / shots assetId / exit 码),不是把整坨 JSON 甩回去。
从仓库根跑。harness 的 stdout 是纯 JSON。
npx tsx sdk/apc/harness/ui-screenshot.ts --list # 合法 scope 清单 npx tsx sdk/apc/harness/ui-screenshot.ts --help # 全部旗标 + 退出码语义
打印 registry 里所有合法 scope(`{ ok:true, scopes:[...] }`)。**命中就复用那个 scope;不命中** 说明是新需求 → 在 `src/app/ui-kit/registry.ts` 的 `ENTRIES` 加一行(`status:'draft'` + 挂 task/doc) 并在 `sections/<scope>.tsx` 加稿件(07 §A4 步骤 1-2;本 skill 不替你写实现,只教流程 + 产报告)。
npx tsx sdk/apc/harness/ui-screenshot.ts \ --scope <scope> --themes light,dark \ --workspace "$APC_WORKSPACE_ID" --task "$PRISMER_TASK_ID"
harness 会:读 registry 校验 scope(非法 scope → 结构化错误、**不产废卡**)→ 用 Playwright 打 `http://127.0.0.1:3000/ui-kit?scope=<scope>` 对 light/dark 各截一张 → **过像素闸**(单张 0 字节 / < 1 KiB / 不是 PNG / 两态字节完全相同 ⇒ 直接判红,**在上传之前**,不产废 asset 不产废卡)→ 上云成 task-bound asset → **复用 `report-card.ts` 产一张 ReportCard**(截图 + 结论 + TierResult 表)。
卡里两张图的槽位:**before = `--themes` 的第一个态(light),after = 第二个态(dark)**,与卡正文 结论段的措辞逐字一致。
**并排引用一张已有的基线图**(改进现有组件时):
npx tsx sdk/apc/harness/ui-screenshot.ts --scope <scope> --themes light,dark \ --workspace "$APC_WORKSPACE_ID" --task "$PRISMER_TASK_ID" \ --baseline-light <旧light assetId> --baseline-dark <旧dark assetId>
此时 before 槽 = 你传进来的旧图,after 槽 = 本次新截的图,`mode` 变成 `baseline-reference`。
> ⚠️ **这不是"比对"**。本 harness **不计算任何像素/结构差异**——它只是把两张图并排放进同一张卡, > 差异由**人看图**判定(输出 JSON 里的 `"comparison": "none"` 就是在结构化地说这件事)。 > **报告里不许出现任何偏差百分比 / diff 数值 / "像素级通过"**:harness 没算过,写出来就是编造。 > 像素级阈值 diff(`toHaveScreenshot`)属 Playwright spec 层,本 skill 不含。 > > 传进来的 baseline id 会在起 chromium **之前**回读校验(真存在 · 同 workspace · 是图片)。 > 解析不开 ⇒ `ui-screenshot-baseline-unresolvable`、exit 1、不截图不上传不产卡(以前这里只是往卡里 > 填一个字符串,传个根本不存在的 id 也 exit 0,卡里就多一条永远打不开的悬空引用)。
harness stdout(成功):
{ "ok": true, "scope": "basics", "themes": ["light","dark"], "mode": "new-baseline",
"comparison": "none",
"shots": [ {"theme":"light","assetId":"cmr...","bytes":204601},
{"theme":"dark","assetId":"cmr...","bytes":202065} ],
"reportCard": { "pageId":"cmr...", "uri":"prismer://workspace/.../memory/cards/ui-align-<scope>", "version":1 } }(`baseline-reference` 模式下每个带基线的 shot 还会多一个 `baselineRefAssetId`。)
汇报:**scope、截了哪两态、每态 assetId 与 bytes、ReportCard 的 pageId/uri、退出码**。需求方经 ReportCard 视觉验收。`comparison` 恒为 `"none"` —— 照抄,别把它写成任何形式的"差异结论"。
| 情况 | 怎么做 | | --- | --- | | 需求匹配 `--list` 里的某个 scope | 复用该 scope,直接跑步骤 2 | | 新 UI 需求,索引里没有 | 先加 registry 行 + section 稿件(07 §A4),再跑步骤 2 | | 改进现有组件、要把旧图并排放进卡 | 传 `--baseline-light/--baseline-dark`(并排引用,**不算差异**) | | harness 报 `ui-screenshot-unknown-scope` | scope 拼错或没进索引——对 `--list` 核对,别硬跑 | | harness 报 `ui-screenshot-degenerate-shot` | 截图退化(0 字节 / 过小 / 非 PNG / 两态同字节)——这是**真失败**:cloud 页面没渲染出来、或主题没切成。查 `$APC_CLOUD_BASE_URL` 那个 `/ui-kit?scope=` 页面本身,别重试骗绿 | | harness 报 `ui-screenshot-baseline-unresolvable` | `--baseline-*` 给的 asset 不存在/已删/不同 workspace/不是图片——核对 id,别把它当成"基线库还没建" | | harness 报 `ui-screenshot-upload-*` / `write-*` | cloud 不可达或 token 无效——查 `$APC_CLOUD_BASE_URL` / `$APC_API_KEY`,别谎报已产卡 |
如实报,别把 scope 名改成能过的。
两边都空 = 它压根没执行,**不许当成功**(历史上入口守卫在含软链的调用路径下就是这样 fail-open 的)。
写出来的每一个这类数字都是编造 —— 这是本 skill 最容易犯的那种"引用真、结论假"。
「索引优先」是本 skill 的头号反 pattern(不查索引就动手),但旧判据只找 `(--?list|registry|scopes?|索引|清单)` ——**报告里写一句「已查清单」就绿**,零检索也过。现在这一段找的是**两条固定 key 的行**,并把行上的引用**读回磁盘复核**(`structured-criteria.ts` 的 `dimension-coverage`):
- [1] index-first: scope=basics 在索引里命中(--list)→ 复用,不新造原语 | src/app/ui-kit/registry.ts:69 - [2] scope-source: 渲染 ?scope=basics 的稿件源 | src/app/ui-kit/sections/basics.tsx:1
Repo: Prismer-AI/PrismerCloud
Turn a known bug into a tight, red-capable reproducer, then prove the reproducer locks that…
Review a diff against its acceptance criteria in four segments (convention adherence, bug…
Five-dimension design audit (frontend UI/UX · server data-model & flow · endpoint spec ·…
Before merge, mechanize Documentation-First — derive the code delta from git diff, then…
Diagnose the local dev machine before any APC loop step — run apc env doctor, classify each…
Close out a local coding task on the bound daemon — stage, commit, branch, merge, push via…