# Web Artifact

> 【单文件网页制品】把数据渲染成一个自包含、能双击打开、可标注回传的网页，交给懂行的人挑错。 触发词：拓扑图、流程图、检查件、评审件、预览件、发给专家看、离线单文件、双击打开的 HTML、 可交互图表、annotations 反馈。 适用：内容由数据生成而非手写、要发给不在 Workbench 里的人、且没有活的可被驱动的状态。 典型是流程/空间拓扑确认、结构检查、参数对照、结论页。 不适用：有活状态就建 App（用 app-authoring 判断）；营销页与教学页； 从 PDF/会议记录做提取本身（那是 process-understanding-extraction 与 semantica 的事， 本技能只渲染提取结果）。

- Skill: `clearailhc/web-artifact` (Agent Skill, multi-file: 10 files)
- Install (CLI): `npx skillmds@latest add clearailhc/web-artifact`
- Raw SKILL.md: https://api.skillmd.com/api/skills/clearailhc/web-artifact/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: Clearailhc (https://skillmd.com/u/clearailhc)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/clearailhc/web-artifact

---


# 单文件网页制品

做一个自包含、能双击打开、随数据重新生成的网页。它的读者是懂行但不在 Workbench 里的人，
他的任务是挑错——所以这份东西要经得起离线打开、要说清自己从哪来、要让意见能带回来。

## 什么时候用

四条同时成立：产物是一个网页 · 内容由数据生成而非手写 · 要发给不在 Workbench 里的人 ·
没有活的可被驱动的状态。最后一条不成立就不是本技能的活——有活状态的目标需要一个可被
驱动的 App，本技能只负责静态网页这一条腿。

| 相邻职责 | 分工 |
|---|---|
| 数据契约与提取工艺 | 它们拥有数据契约。**本技能只渲染数据，不规定数据里必须有什么** |
| 工程几何 | 它管几何与基准对不对；本技能管把关系画得能让人看懂 |

**本技能不规定数据形状。** 节点与边上除渲染必需字段之外的属性一律原样透传到侧栏——
有位号就显示位号，有出处就显示出处，什么都没有也能正常渲染。数据该长什么样，由上游技能
的契约或 harness 的校验决定，调用时自然带进来。

## 先校准处理档位

校准的是处理规格，而非要不要设计。三档：

- **内部核对**——自己或同事看一眼就丢。够读就行，别花时间。
- **专家评审**（默认档）——外人要在上面挑错。可标注、能离线、有来历，排版清楚。
- **对外交付**——会被转发、会被存档。加完整的视觉身份。

多数任务落在中间档。拿不准时按中间档做：一个排版干净的页面从不会是错的，一个过度设计的
页面有时是。

## 自包含是硬约束

依赖全部内联，运行时零网络请求。构建期联网随意（本技能自己就在构建期跑 ELK）。

这条守的是「没网的会议室里也能打开」，而不是「不许用 CDN」这句字面禁令。理解了本意，
遇到新情况就能自己判断：Google Fonts 也是外部请求，所以字体只用系统栈；图片走 data URI；
连 `<link rel="preconnect">` 都不必留。

被移植进来的上游方案正是栽在这里——它从 esm.sh 与 jsdelivr 取 React 与 React Flow，
而「拿给不在 Workbench 里的专家看」是它唯一的用途。

## 从数据生成，不手工摆位

几何由布局器算，渲染器只画。手改坐标、手挪标签、在布局器之外再跑一次路由，都会让制品与
数据脱节——下次重新生成时那些手工调整全部丢失，而你多半已经忘了改过什么。

需要更紧凑或更松散时，调布局器的参数，不要动它的输出。

## 为什么不用框架

默认无框架：布局在构建期算完，浏览器端用原生 SVG/DOM 加少量 JS 渲染。产物含数据约 40 KB，
脚本直出，没有构建步骤。

两条根本理由。**制品是生成物**，随数据重新生成，框架最大的卖点——可维护性与组件复用——
在这里不成立。**运行时状态规模小且耦合低**，检查类制品通常只有选中项、过滤集、视图变换、
标注列表几个状态，每个的影响都是局部且直接的，没有一处需要虚拟 DOM 去 diff。

具体到量级：zoom/pan 约 30 行，点选高亮约 20 行，侧栏约 30 行，过滤约 40 行，标注导出
约 60 行，minimap 约 40 行。自己写是实事求是，不是逞强。作为对照，内联 React 与 React Flow
约 450 KB，换来的只是画盒子、画路径、放标签、pan/zoom 四件事。

## 想引框架时，先回头看那道岔路

需要虚拟 DOM 的信号是 UI 要随状态重算大量节点：虚拟滚动、多视图联动、表单编辑、undo/redo。
出现这些时先回答另一个问题——

> 一个「制品」复杂到需要框架与构建步骤，多半已经跨过了「要不要 App」的分水岭。

需要复杂状态管理，通常意味着有活的、可被驱动的状态，那正是建 App 的判据。真到那一步，走
`web-app-v1` scaffold（vite 构建，任何 npm 包随便用，vite 负责打成自包含产物），而不是在
这里手搓半个框架。

## 让读者知道从哪里开始看

专家的时间很贵。让他从头扫一遍图，和让他先看那 12 处存疑，效率差一个量级。

所以摘要先于细节，状态用形式编码而非只给数字。数据里带了置信度、告警、缺口、未覆盖区域时，
把它们提到顶部做成入口，点一下就跳到现场。**具体报什么由数据决定**——本技能只要求有入口，
没有可报的就不占地方。

## 制品要自陈来历

页脚固定交代：从什么数据生成、什么时候、生成器什么版本，以及**这份东西证明了什么、不证明
什么**。最后一项最容易被略过，也最容易避免误读——一张拓扑图证明设备间的连接关系，不证明
阀门、控制回路与管径。

只声称观察到的设置支持的结论。

## 反馈要能回来

读者能在制品上标注，导出结构化反馈，且反馈带得回源数据的版本（稳定 id 加源数据摘要）。
口头反馈会丢失、会走样、说不清针对哪一版；一份带 id 的 JSON 可以直接被下一轮生成消费。

## 交付前

先跑确定性检查，它比人眼可靠：

```bash
python3 scripts/check_artifact.py out/topology.html --source data.json --json out/check.json
```

它查外部引用、内嵌数据合法性、id 唯一性、悬挂边、来历字段、主题三态。全 PASS 才算可交付。

`--json` 写出的那份结果是**证据门的实体供给**：`done_criteria` 直接引用它就行（例如
「`out/check.json` 的 `ok` 为 true」），Evaluator跑一条命令便有定论，不必读散文。本技能是加载
进上下文的文本，**没有执行力**——能规则化的判据交给脚本与证据门，别交给自觉。

然后在浏览器里看一眼：页面不空白、控制台无错误、计数与源数据一致、缩放平移只影响该影响的
东西。**先证明渲染在跑**——`file://` 下某些宿主根本不跑 requestAnimationFrame，所以要用
http origin 验证，不要只看双击打开的那一份。

## 设计基本功

**双主题三态**。读者的浏览器有三种状态：显式浅色、显式深色、以及什么都没标的系统态——最后
一种最常见也最常被漏掉。所以在裸 `:root` 里定义完整的浅色令牌，在
`@media (prefers-color-scheme: dark)` 里以 `:root:not([data-theme="light"])` 为守卫重定义，
再在 `:root[data-theme="dark"]` 里重定义一次。组件只用令牌，任何颜色都不要只定义在媒体查询
或属性选择器里面。`body` 必须显式上底色，否则会借用宿主的底，深浅一串就露馅。

**排版与布局**。正文宽度收在约 65 字符；定一套字号阶梯并守住；数字列用
`font-variant-numeric: tabular-nums`；宽内容（表格、代码、图）各自 `overflow-x: auto`，
别让页面横向滚动。业务字符串用 `textContent` 渲染，不要拼进 `innerHTML`。

**避开一眼假的默认**。当前 AI 生成的页面高度雷同：暖奶油底配衬线标题与陶土色点缀、近黑底
配一抹荧光绿、紫蓝渐变大标题、Inter 或 Space Grotesk 当万能字体、emoji 当章节标记、什么都
居中、到处圆角卡片。用户明确要求某种风格时照做；没要求时，别把这份自由花在这些默认上。
从主题本身找线索——工业流程图的调性在控制室与蓝图里，不在营销落地页里。

## 门类

- [when-drawing-a-topology.md](references/when-drawing-a-topology.md) — 流程与空间拓扑图：
  布局参数基线、关系分类、排序与密度、节点内容克制。配 `scripts/render_topology.js`。
- [when-the-page-must-work-offline.md](references/when-the-page-must-work-offline.md) —
  内联的具体做法、体积预算、与 App 侧 freeze 的区别。

## 已知盲区

由失败复盘回填。写进来的条件是：作者读过本技能，仍然在同一个地方栽了。

- **「不引 CDN」被当成字面禁令，于是在「要双击即开」的需求下被判定为不适用**。被移植的上游
  方案与本仓的一次微体素沙盘开发都栽在这里。补上本意（运行时可离线）之后，正确解（依赖内联）
  是自明的。本技能因此不写禁令，写理由。
- **制品可能在 0 尺寸的容器里初始化**（面板折叠、iframe 未显示、打印预览）。此时
  `getBoundingClientRect()` 返回 0×0，据此算出的取景位移会把内容推到画布外，表现为「打开就
  是空白，手动点一下适应窗口才好」。取景要等到容器真有尺寸，用 ResizeObserver 兜底。

