| name | docs-blog-converter |
| description | Use when converting a finished retikz blog MDX article into external-platform Markdown plus captured SVG assets. |
retikz blog 文章外站发布规范
使用时机
把一篇已写好的 blog 文章(apps/docs/src/modules/docs/contents/blog/<section>/<slug>/index.{zh,en}.mdx)转换为可直接贴到掘金 / 公众号 / 知乎等平台的 markdown + 配套 SVG 时使用。
前置依赖:先读 docs-doc-blog——本 skill 假设文章已按那套规范写好(ComponentPreview 前后有点题句、## 引用 节齐全、双语对齐等),转换步骤依赖这些不变量。
输入与输出
| 项 | 内容 |
|---|
| 输入 | apps/docs/src/modules/docs/contents/blog/<section>/<slug>/index.<lang>.mdx(lang ∈ zh / en,默认 zh) |
| 输出根 | .markdown/<slug>/(仓库根下的隐藏目录,不进 git,加 .gitignore) |
| 输出文件 | content.md(正文) + <demo-name>.svg(每个 ComponentPreview 一份) 双语并行时 content.zh.md / content.en.md 并存,SVG 共用同目录 |
输出目录扁平——所有 SVG 与 content.md 同级,方便整目录拖到掘金编辑器或一次性上传图床。
总流程
- 扫源 mdx 的
<ComponentPreview files=...>:string 直接取值,object 取 file,array 取第一项后按前两种形式解析;得到主 demo id 后按出现顺序去重。
- 起 docs dev server,用脚本抓 SVG 到
.markdown/<slug>/。
- 把 mdx 重写成平台通吃 markdown。
- 落
content.md,本地预览和自检。
- 作者手抄到目标平台并上传 SVG。
SVG 抓取
retikz 的渲染依赖 DOM 文本测量(packages/kernel/react/src/render/browser-measurer.ts),SSR / jsdom 不可靠——SVG 必须从浏览器渲染好的 DOM 里抓。
走 Node 22 自带 WebSocket + 系统 Edge/Chrome headless 经 CDP 抓 这条零依赖自动化路径,配套脚本 grab-svg.mjs 同目录已备好。
步骤
pnpm --filter @retikz/docs dev &
node .agents/skills/docs-blog-converter/grab-svg.mjs \
--url http://localhost:7102/blog/<section>/<slug> \
--out .markdown/<slug> \
--demos demo1,demo2,demo3
- Node ≥ 22,系统有 Edge/Chrome;dev server 端口以实际输出为准。
--demos 按 mdx 中 ComponentPreview 出现顺序填;同名只列一次。
- 目标语言打开对应页面再抓:zh 页抓 zh demo,en 页抓 en demo。
离线色坑
retikz demo 里若用了 CSS var(如 var(--foreground)、hsl(var(--primary)))作 stroke / fill,SVG 离开 docs 站的 CSS context 后变量解析不到,会 fallback 成黑或透明。
抓 SVG 前扫一眼 demo 源码:
| 模式 | 状态 |
|---|
字面色 red / dodgerblue / darkorange / darkviolet / gray / lightgray / dimgray / #ef4444 / oklch(0.55 0.16 145) | ✅ 离线可用 |
var(--foreground) / hsl(var(--primary)) 等 token | ❌ 离线变黑 |
currentColor | ⚠️ 取决于 SVG 外层是否有 color;下载后通常变黑 |
发现 token / currentColor——回去把 demo 改字面色(学 unit-circle.zh.demo.tsx 顶部的 HELP_LINE / SIN_COLOR 等本地常量)再抓。这一改顺带利好原 demo 在离线场景下的复用能力,应当顺手提 PR。
脚本不可用时兜底:浏览器打开文章页 → 每个 ComponentPreview 点 Download SVG → 挪到 .markdown/<slug>/,文件名用 files 中的主 demo id。
正文重写(5 类改写)
输入是 mdx,输出是平台通吃的 markdown。逐类改:
| 源 | 输出 |
|---|
frontmatter ---...--- | 删除;title 提为 #,description 提为引用段;date/tags 放文末平台元数据 |
<ComponentPreview files="X" ... /> | ;object 取 file,array 解析第一项;同名复用同一 SVG |
站内 /kernel/...、/viz/...、/blog/... 链接 | 前缀 https://pionpill.github.io/retikz/;外部链接原样保留 |
| 站内 UI 表述 | 加“retikz 官方文档站”限定,如 Ask AI、侧边栏、搜索、TOC、demo 卡片 |
<Comparison> | 把对比要点一句话内联到正文 |
<ZodSchema> / <ExamplePrompt> | blog 不该出现;回去让作者修 mdx,不在转换器硬转 |
<br />、代码块语言标识 | 保留 |
不要凭印象改 base URL;只用 https://pionpill.github.io/retikz/。
文末平台元数据节
content.md 末尾追加一节,方便作者复制到掘金 / 公众号的封面 / 摘要 / tag 字段(不是给读者看的,是给作者发布时填表用的):
---
<!-- 平台元数据(手抄到掘金 / 公众号 / 知乎的封面 / 摘要 / 标签字段;正文不显示) -->
- **标题**:retikz 的起点
- **摘要**:retikz 项目的起点与定位
- **发布日期**:2026-05-17
- **标签**:设计 / 起点
- **原文链接**:https://pionpill.github.io/retikz/blog/journey/origin
用 HTML 注释包裹标签段头,避免平台当正文标题;原文链接 填站内 canonical URL。
落 content.md
把上述 5 类改写产物按文章原顺序拼成 content.md:
# 标题(来自 frontmatter title)
> 副标题(来自 frontmatter description)
<正文 H2 节按原序>
---
<!-- 平台元数据... -->
- **标题**: ...
- **摘要**: ...
- **发布日期**: ...
- **标签**: ...
- **原文链接**: ...
验证(落盘前自检)
ls .markdown/<slug>/
正文自检:
- frontmatter 已剥;第一行是
# <标题>。
- 无
<ComponentPreview / <Comparison / <ZodSchema / <ExamplePrompt 残留。
- 无
](/blog / ](/core / ](/about 残留。
- 每个
 都有同级 SVG 文件。
- 文末平台元数据含标题、摘要、发布日期、标签、原文链接。
速查:
rg '<(ComponentPreview|Comparison|ZodSchema|ExamplePrompt)' .markdown/<slug>/content.md
rg '\]\(/(blog|kernel|viz|about)/' .markdown/<slug>/content.md
两条都应该 0 行输出。
发布步骤建议(手抄环节)
把 content.md 整体粘到平台 Markdown 编辑器;逐张上传 .markdown/<slug>/X.svg,让平台把 ./X.svg 替换成 CDN URL;从平台元数据复制摘要、标签、原文链接。发布前用平台预览确认图和链接。
.gitignore
.markdown/ 是手抄中间产物,不该进 git。仓库根 .gitignore 加:
.markdown/
如果根 .gitignore 已存在,去重后追加这一行即可。
双语并行
文章双语都要发时,zh / en 分别转换。SVG 按 demo 语言抓,同目录时按需重命名避免覆盖:
| 模式 | 输出 |
|---|
纯几何 demo(无文字差异,单 .demo.tsx) | 共用一份 X.svg |
文字 demo(双语 .zh.demo.tsx / .en.demo.tsx) | 两份独立 X.zh.svg / X.en.svg,content.{zh,en}.md 各自引用对应版 |
判断方式:看 demo 文件存不存在 .<lang>.demo.tsx 副本——存在则双语 SVG 不同,分文件名;不存在则共用单 SVG。
Common Mistakes
- frontmatter 或 docs JSX 残留。
- alt 写成“图片/示例/demo 名”,没有取点题句。
- 站内链接未绝对化,或 base URL 凭印象写错。
- 站内 UI 表述没重述,外站读者不知道“站内/右上角”指什么。
- CSS var / currentColor SVG 离线变黑。
--demos 顺序错、同名 demo 重复抓、抓错语言。
- SVG 相对路径没上传成平台 CDN URL。
.markdown/ 未进 .gitignore,或平台元数据漏原文链接。
与 docs-doc-blog 的关系
| docs-doc-blog | 本 skill |
|---|
| 用途 | 在 mdx 里写一篇符合规范的 blog 文章 | 把已写好的 mdx 转为外站可贴 markdown |
| 触发时机 | 起一篇新 blog / 改正文 | 文章定稿 / 要发到掘金 / 公众号时 |
| 输入 / 输出 | 输入需求与提纲,输出 index.{zh,en}.mdx + <name>.demo.tsx | 输入 mdx + demo,输出 .markdown/<slug>/content.md + SVG |
| 关键不变量 | ComponentPreview 前后点题句、## 引用 节、frontmatter 4 字段 | 依赖以上不变量做转换;缺哪条回去让作者补,本 skill 不补 |
docs-doc-blog 是写作端的规范,本 skill 是发布端的规范,不替代——一篇文章可能只写不发(站内自足就行);要发就过本 skill。