impeccable layout 实战指南:从空间论点到两段评估,修复间距、节奏与视觉层级
layout 是 impeccable 技能(AI 设计语言包)中 Enhance 类别的一条命令,负责"Fix spacing, rhythm, and visual hierarchy"——把产品优先级转译成阅读顺序、分组、节奏与可用空间。读完本篇,你将掌握 layout 工作流的完整执行路径:先按访客模式确定布局目标,再做相互隔离的两段评估(视觉布局评估 + 机械扫描),随后写下"空间论点"(spatial thesis)再动手编辑,最后用可验证的清单收尾并交接给 polish;同时会深入源码,看清 --scope layout 机械扫描背后 13 条 layout 域规则、检测引擎的分工以及退出码语义。
一、layout 命令在技能体系中的定位
impeccable 以"技能"(skill)形式分发给 AI 编程助手,SKILL.md 中的命令表把 layout [target] 归入 Enhance 类别,其参考文档即 layout.md。该文档的开篇一句话定义了命令的职责:
Layout turns product priority into reading order, grouping, rhythm, and usable space. Diagnose the structural problem before moving boxes.
(布局把产品优先级转化为阅读顺序、分组、节奏与可用空间。移动盒子之前,先诊断结构问题。)
这句话确立了整条工作流的第一原则:先诊断,后动手。原文档还划定了两条边界:
- 保留既有视觉世界(Preserve the established visual world)。一条 layout 命令只在其内部改变结构;替换身份(identity replacement)属于 new-work.md 的职责,不应混入布局修复。
- 收尾交接:当结构立住(the structure holds)时,交接给
/impeccable polish做最终质量打磨,对应 polish.md。
二、访客模式:布局目标因"访客成功定义"而异
impeccable 用"访客在这个界面上如何才算成功"划分四种模式(Persuade / Operate / Read / Experience,见 SKILL.md 的 Modes 一节)。layout.md 据此给出三类布局取向:
| 模式组合 | 布局取向 |
|---|---|
| Persuade + Experience | 构图可以不对称、流动,甚至刻意"破坏"——前提是所选世界(visual world)值得这样做 |
| Operate + Read | 可预测的结构、稳定的密度、可导航的线性,本身就是可用性(affordances) |
| Native | 遵循 ios.md 或 android.md 中关于导航、安全边距(insets)、自适应与触控目标的规定 |
判断布局"对不对"之前,必须先确定这是哪种模式:一个营销落地页的 hero 区允许破格,而一个管理后台的表格区则要求稳定的栅格与密度——用同一把尺子量两者都会出错。
三、两段相互隔离的评估
这是 layout 工作流最核心的机制。文档要求:当子代理工具(sub-agent tool)可用且被允许时,下面两段评估要独立运行;否则由你自己按顺序完成。隔离的目的是防止"先入为主"——机械证据不能污染第一眼判断。
3.1 第一段:布局评估(Layout assessment)
检查代表性状态(representative states)与视口(viewports),并用渲染结果或源码证据回答以下全部问题(原文档逐条继承如下):
- 阅读顺序(Reading order):做"眯眼测试"(squint test)。把细节模糊掉之后,你还能按顺序认出主元素、次元素和各主要分组吗?
- 分组(Grouping):相关元素是否彼此靠近、不同分组之间是否有清晰分隔?还是容器在替弱 proximity(邻近性)打补丁?
- 节奏(Rhythm):紧凑区间与宽裕区间是否构成有意的节拍?还是同一个间距值被重复到所有元素权重相等?
- 结构(Structure):拓扑是否与内容和任务匹配?重复的卡片、列、区块是真正等价的,还是仅仅因为框架默认长这样?
- 密度(Density):每个区域的信息量是否匹配使用频率、决策复杂度与访客模式?
- 自适应(Adaptation):在窄屏、中屏、宽屏、缩放、本地化(长文案)各状态下,什么被重排、折叠、换行、滚动或保持固定?DOM 顺序与焦点顺序是否仍与视觉顺序一致?
- 极端情况(Extremes):超长内容、空状态、浮层、粘性元素、安全区、小触控目标,是否暴露出结构性失败?
3.2 第二段:机械扫描(Mechanical scan)
跑 impeccable 自带的反模式检测器,只看 layout 域:
node .agent/skills/impeccable/scripts/detect.mjs --json --scope layout [target files or dirs]
命令语义与底层实现要点(均可在仓库源码中核对):
- 入口转发:detect.mjs 只是一个约 20 行的转发器,它依次探测
detector/detect-antipatterns.mjs与cli/engine/detect-antipatterns.mjs两个候选,导入并调用detectCli(),真正逻辑在 CLI 主程序中。 - 参数解析:cli/main.mjs 中
--scope支持逗号分隔的多值(如--scope layout,type),取值必须来自规则注册表声明的 scope,否则报错退出;--json把全部发现(每条 advisory 带advisory: true标记)以 JSON 数组打到 stdout;无目标参数时会回退扫描当前目录,非 TTY 且无目标时走 stdin(用于 hook 场景)。 - 退出码:非 advisory 的发现数 > 0 时退出码为
2,否则为0;advisory(建议级)发现单独打印、永不计入失败,因此不会被--scope layout的 CI 阻断。 - 可选视口:
--viewport WxH(默认 1280x800,如--viewport 390x844做移动端宽度过渡检查),URL 目标(http(s) 或 file://)会走 Puppeteer 真实渲染路径,拿到真实级联与计算样式。 - 项目上下文:扫描默认读取
.impeccable/config.json的忽略配置与项目 DESIGN.md 设计系统,--no-config/--no-design-system可关闭。
文档特别强调两个认知纪律:
- 机械证据不得进入第一段评估,两段结果要在编辑前才做综合(synthesize both passes before editing);
- 干净扫描不能证明层级或节奏(A clean scan cannot prove hierarchy or rhythm)——扫描器查的是可判定的失败,眯眼测试里"读不出主次"这种问题它看不见。此外,还要人工检查检测器无法解析的任意间距、溢出、层叠与容器行为。
3.3 --scope layout 到底会扫出什么:13 条 layout 域规则
scope 过滤的实现是 registry/antipatterns.mjs 中的 filterByScopes():RULE_SCOPES 由全部规则的 scopes 字段派生,CLI 只保留声明了对应 scope 的发现。带 layout scope 的规则分两类:
"AI 味"反模式(category: slop)
| 规则 id | 名称 | 判定要点 |
|---|---|---|
nested-cards |
卡片套卡片 | 卡片内再嵌卡片制造视觉噪音与过度深度;应改用间距、排版与分隔线压平层级 |
monotonous-spacing |
单调间距 | 同一间距值到处使用、没有节奏;应对相关项用紧分组、对区块用宽分隔 |
icon-tile-stack |
图标瓦片压在标题上方 | "圆角方图标容器 + 下方标题"的通用 AI 特性卡模板;可改为图标与标题并排,或让图标不套容器 |
质量与可访问性(category: quality)
| 规则 id | 名称 | 判定要点 |
|---|---|---|
content-hidden-at-rest |
内容静止时不可见 | 页面大量文本在 reveal 处理器跑完后仍是 opacity 0 / visibility hidden(失败 reveal 特征);内容应默认可见 |
edge-flush-cards |
卡片贴住滚动器边缘 | 横向滚动器/标签面板中的卡片一边留 gutter、一边贴边,边缘与圆角被裁切 |
text-occlusion |
文本被重叠元素遮挡 | 文字被不透明层或第二行文本压住不可读 |
first-viewport-column-overflow |
单列拉长首屏 | 多列首屏中一列远超首屏而另一列留白,折线(fold)落入单个区块内部 |
cramped-padding |
内边距局促 | 文本离容器边缘太近;两种形态:元素自带文本但 padding 低于字号需求;包裹带文本子元素且自身近乎零 padding 的容器贴着可见边界。建议至少 8px,理想 12–16px |
body-text-viewport-edge |
正文贴视口边缘 | 段落无容器水平 padding 直接贴住视口左/右边;建议容器至少 16px(理想 24–32px)或 max-width + 自动外边距 |
text-overflow |
内容溢出容器 | 内容渲染得比容器更宽,外溢或逼出横向滚动条 |
clipped-overflow-container |
定位子元素被裁剪 | overflow: hidden/clip 容器包绝对定位子元素,把需要逃逸的 tooltip、菜单、弹层剪掉 |
line-length(type+layout 双域) |
行长过长 | 超过约 80 字符;应给文本容器 65ch–75ch 的 max-width |
heading-rhythm(layout+type 双域) |
标题挤在前一块之上 | 标题应与它所引入的内容绑定:其上方留白应大于下方留白,否则每个区块都像在给上一块做字幕 |
这些规则的具体检测逻辑集中在 rules/checks.mjs(5000+ 行),例如 monotonous-spacing 的匹配分支与 checkHeadingRhythmDOM()(该文件 #L3904 附近)分别对应节奏与标题留白两条规则;规则注册表还声明了引擎支持矩阵(RULE_ENGINE_SUPPORT):browser 引擎支持 element / page / layout 三类检查,static-html 引擎支持 element / page,正则引擎支持 source / page-analyzer——即部分 layout 规则只有真实浏览器渲染路径才完整生效,这也是 CLI 在检测到框架 dev server 时提示"改用 URL 扫描更准"的原因。
四、编辑前:写下空间论点(Spatial thesis)
两段评估合成结论后、动任何代码之前,原文档要求先"点名"(name)以下五件事:
- 主阅读路径或任务路径是什么;
- 什么属于一组、什么必须分开;
- 哪个元素领衔、哪些是支撑;
- 预期的密度与间距节奏;
- 结构在容器、视口、输入模式与内容极端之间如何变化。
然后:选择能表达这些关系的最简结构模型,按"布局原语所控制的关系"选用它们,并给可复用的间距与容器角色起语义化名字(而不是 margin: 17px 式的匿名值)。这一步的作用是把"感觉不对"翻译成可执行、可复查的结构决策。
五、Apply:动手编辑时的十一条原则
原文档 Apply 一节给出的是判断标准而非 CSS 速查,逐条继承如下:
- 按语义分组:先用 proximity(邻近性),再考虑加容器或装饰;
- 用"紧—松"刻意的对比制造节奏,而不是均质间距;
- 使用有文档的间距刻度(documented spacing scale),拒绝一次性魔数。原文档给出经验值:4 为基数的刻度能提供 8-only 刻度漏掉的有用中间档位;
- 层级跟随产品优先级,不跟随框架默认;
- 让不同的内容保持视觉差异,但别把每个分组都变成孤立组件;
- 响应式行为是结构性的:基于"什么仍然重要"来重排、折叠、回流或揭示(reveal),而不是只缩放字号;
- 同一组件出现在不同上下文时,优先容器感知(container-aware)组件;
- 当
gap比子元素 margin 更直接地表达关系时,用gap做兄弟节奏; - 可见标记(marks)很小的时候,触控目标依然要够大可用;
- 深度(阴影、层叠)只在它澄清状态或层级时使用;
- 光学修正(optical corrections)只放在检查过渲染结果之后做,不要凭感觉预设。
收尾还有一句总纲:变化本身不是目的(Variation is not a goal by itself)。重复应该服务于识别;只有当内容或优先级变化时才打破它。
六、Verify:用证据验收,不接受"裸 yes"
结构改完后,用以下 8 条清单逐项验收,每项都必须给出渲染或源码证据,然后重跑机械扫描:
- 眯眼测试仍能按顺序看出主元素、次元素与主要分组;
- 阅读与任务路径在每个支持的尺寸下保持清晰;
- 相关内容自然成组,不相关内容没有糊在一起;
- 紧与松的间距构成有意节奏,而非单调重复;
- 密度匹配使用频率与内容复杂度;
- 长文本、空状态、本地化、缩放、动态内容都不破坏结构;
- 键盘、触控与辅助技术的操作顺序与视觉顺序一致;
- 最终机械扫描没有无法解释的发现(rerun
detect.mjs --scope layout)。
文档原话要求:不要用一句光板 "yes" 冒充验收(Do not substitute a bare "yes" for verification)。当结构立住时,交接给 /impeccable polish。
七、Live 模式的签名参数:density
当通过 live.md 描述的 live 变体模式做可视化迭代时,layout 领域有固定的"签名参数"约定:每个变体声明一个粗粒度的 density 参数,并且所有间距都对着 var(--p-density, 1) 书写:
{"id":"density","kind":"range","min":0.6,"max":1.4,"step":0.05,"default":1,"label":"Density"}
参数契约(见 live.md 的参数一节)要点:
range参数驱动 CSS 变量--p-<id>,组件<style>里写成var(--p-<id>, 默认值);steps参数驱动data-p-<id>属性选择器;toggle两者都驱动。layout.md 的 density 声明里min/max/step/default/label字段完整,是range类型的标准形态;- 只有当拓扑真正分叉时(topology genuinely branches)才额外增加一个结构性参数——参数不是越多越好,密度旋钮应能覆盖大多数布局变体。
这样做的收益是:同一个布局变体的"松紧"被收敛成一个 0.6–1.4 的连续旋钮(默认 1),间距规则不用为每个变体重写,验收时也能直接拖动对比节奏变化。
八、验证与测试依据
这套 layout 工作流在仓库中有对应的测试与 fixture 支撑,可用于自查理解:
- tests/detect-antipatterns-fixtures.test.mjs:对 tests/fixtures/layout.html、tests/fixtures/cramped-padding.html 等 fixture 做静态 HTML/CSS 引擎断言,例如 nested-cards 的 flag 列应产出 ≥4 条发现,且
monotonous-spacing作为页面级规则在该 fixture 上不触发(页面级规则需要完整布局矩形,测试注释明确说明了这一分层)。 - tests/detect-antipatterns.test.js:正则引擎路径的单测,如
detects monotonous spacing via regex(约 #L793)验证同一规则在源码扫描路径下同样可用。 - tests/fixtures/ 目录还包含
text-overflow.html、edge-flush-cards.html、first-viewport-column-overflow.html、text-occlusion.html等与本文规则一一对应的样例页,可直接用detect.mjs复现扫描结果。
九、小结:layout 工作流的执行顺序
| 步骤 | 动作 | 原文档章节 |
|---|---|---|
| 1 | 判定访客模式,确定布局取向;保留既有视觉世界 | Visitor mode |
| 2 | 独立跑布局评估(7 问,全部要证据) | Two isolated assessments |
| 3 | 独立跑机械扫描 detect.mjs --json --scope layout,再综合两段 |
Two isolated assessments |
| 4 | 写下空间论点(5 项点名 + 最简结构模型) | Set the spatial thesis |
| 5 | 按 11 条原则编辑(4 基数间距刻度、gap、容器感知组件等) | Apply |
| 6 | 8 条清单逐项取证验收,重跑扫描,无未解释发现 | Verify |
| 7 | 结构立住后交接 /impeccable polish;live 变体统一声明 density 参数 |
Verify / Live-mode signature params |
核心可以浓缩成文档第一句:先诊断结构问题,再移动盒子——诊断有双通道(眯眼测试式评估 + 13 条 layout 域规则扫描),动手有空间论点约束,收尾有证据清单兜底。这套流程不产出"更花哨的布局",而是产出"产品优先级在空间里被如实表达、且在每个视口与极端内容下都立得住"的布局。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00