公众号排版主题工作室(都爆鸭)
排版是一份声明式的 themeJson(配色 palette + 每个标签的 inline-style 模板),渲染器按它把
Markdown 确定性地渲成公众号内联样式 HTML。按描述生成 / 修改合法的 themeJson,
本地自检 + 预览,再存回服务端设为默认;发文钉了 --theme / config.mdTheme 时再落一份本机文件。
渲染 / 存主题都免费不扣点。
⚠️ 四条硬红线(先读,全程守住)
红线 1 · 微信兼容:标题装饰只能挂在有文字的元素自身
公众号编辑器会 strip 掉没有文字、纯靠 inline-block 宽高 + background 撑色块的空 <section>/<span>。
标题引导条 / 强调竖条 / 下划线必须作为 inline style 直接写在标题元素自身,绝不用独立的空装饰块。
- ✅ 对:
elements.h2.style里直接写border-left:4px solid {{accent}};border-bottom:1px solid {{border}};padding:0 0 8px 11px; - ❌ 错:用
wrapBefore注入一个空的<section style='width:32px;height:4px;background:…'>当色条(无文字 → 被 strip)。
红线 2 · 微信兼容:别给整篇套 decorations.articleWrap 外框
decorations.articleWrap 包整篇正文的浅底圆角卡片在公众号里会变成一道突兀的边框。
articleWrap.before / after 留空字符串;「呼吸感」用段间距(margin / line-height)和局部卡片(如 blockquote 圆角卡)实现。
红线 3 · 安全:themeJson 会内联进公众号草稿,服务端会拒收不合法主题
服务端 POST/PUT/render 都会 validateTheme,不过直接 400。生成后先跑
scripts/validate-theme.mjs 自检——具体校验规则(顶层键、
palette/page 必填字段、style 禁写清单、体积上限)以它为准,不在这里另存一份会漂移的清单。
微信编辑器官方规范另有八条「不拒但走样」的写法(position、text-align:start、固定像素宽、自定义字体栈、文字底下铺渐变…),
清单与可读性基线见 references/theme-schema.md 末尾;校验器对其中四条打 warning。
红线 4 · 数据安全:动手改前必须落盘备份,没有备份不改
改主题是就地覆写(PUT / POST + isDefault:true),服务端不保留历史版本,改坏了没有第二处能找回。
第 1 步的 GET 命令已经把落盘备份写进命令本身——照抄不删;备份文件路径记下来,改坏了照
references/deploy-scope.md「回滚」一节把它 PUT 回去。
契约:服务端主题 CRUD + 渲染(以 doubaoya.com 主仓 render-routes.ts 为准)
⚠️ 先读 dby-gateway/references/protocol.md 再发请求(鉴权、密钥怎么拿、
信封与报错码全在那一份)。本 skill 自己的六条主题路由(GET/POST /api/wechat/theme、
GET /api/wechat/themes、POST /api/wechat/render、PUT/DELETE /api/wechat/theme/:id)
的请求体与返回 → 读 references/crud.md,不需要就别读。
export DOUBAOYA_API_KEY="dyh_你的密钥"
BASE="${DOUBAOYA_BASE_URL:-https://doubaoya.com}"
AUTH="Authorization: Bearer $DOUBAOYA_API_KEY"
render 的主题解析优先级 themeJson(传了就用这份)> themeId >
我的默认主题 > 兜底 benya-clean,所以预览编辑中的主题就传 themeJson;
一人一默认,isDefault:true 时服务端在事务里把我其他主题的 isDefault 置反。
闭环步骤
1. 读起点主题并落盘备份(红线 4,照抄不删)
# a) 读我当前的默认主题(有就在它上面改)并强制落盘备份——主题体在 data.theme.themeJson
BACKUP="/tmp/dby-theme-backup-$(date +%s).json"
curl -s -H "$AUTH" "$BASE/api/wechat/theme" | tee "$BACKUP"
echo "已备份到 $BACKUP —— 改坏了见 references/deploy-scope.md「回滚」一节"
# b) 或列出内置主题,挑一个复制起步(推荐 benya-clean——已按红线 1 / 2 改造过)
curl -s -H "$AUTH" "$BASE/api/wechat/themes"
本 skill 也自带一个 WeChat-safe 起手模板
themes/theme.example.json(暖橘编辑风,复制改配色即可)。
2. 按用户口语描述改 themeJson
把「换成暖橘色 / 标题要竖条 / 引用做成卡片 / 字再大一点 / 排版长得像某某号」翻译成合法 themeJson。
字段全貌见 references/theme-schema.md;守住上面四条红线。改配色最省事:只动 palette 八个键。
3. 本地先自检
把生成的主题写成本地文件,过本 skill 自带的零依赖校验器:
node scripts/validate-theme.mjs /tmp/my-theme.json # 有硬错误按提示改;exit 0 = 合法
4. 预览(改一版看一版)
API 渲染 → 存本地 .html 打开:
# 用编辑中的 themeJson 渲染样例文章,拿回 HTML 存本地打开肉眼看
curl -s -H "$AUTH" -H 'Content-Type: application/json' \
-d "$(jq -n --arg md "$(cat sample.md)" --slurpfile t /tmp/my-theme.json \
'{markdown:$md, title:"预览", themeJson:$t[0]}')" \
"$BASE/api/wechat/render" | jq -r '.data.html' > /tmp/preview.html
open /tmp/preview.html # macOS;别的平台用浏览器打开
sample.md别带#一级标题:title会被插成 h1,正文再有就显示两个大标题。 render 返回的 HTML 与最终存进草稿的正文逐字一致。data.warnings若有(如未知{{token}})一并看一眼。
→ 本机已装 dby-publish 且想在本机「改文件重跑即换肤」地预览,读 references/live-preview.md,
不需要就别读。改 themeJson 本身以上面 API 渲染那条路为准。
5. ⚠️ 落地生效范围(两条渲染路的主题源)
→ 主题调好、要存回去时读 references/deploy-scope.md——它回答「存了之后哪条路会变、
哪条不会」,并给出存回服务端 / 落本机文件 / 改坏了回滚的完整命令。
存回服务端设为默认是主路(POST/PUT + isDefault:true):doubaoya.com 网页排版
工作室、POST /api/wechat/render、以及未钉本机主题的 dby-publish 发文都读它。
仍需落一份本机 theme 文件的只有三种情形:发文时钉着 --theme / config.mdTheme、
离线或拉取失败要兜底、用的是不带自动拉取的旧版 pipeline。
落完向用户汇报时如实说清各自的生效范围,别混着说。
themeJson 结构(速查)
→ 真要动手写 / 改 themeJson 的字段时读 references/theme-schema.md(top-level 键、
elements 支持的标签、{{token}} 插值、li.marker / img.figureStyle / hr.html 这些位置),
不需要就别读。只换配色的话改 palette 八个键就够,其余用 {{token}} 自动跟随。
主题契约以本包
scripts/validate-theme.mjs为准(跑它,别照文档记); 本 skill 的references/theme-schema.md+themes/theme.example.json足够独立完成一次改主题。
下一步(先看用户要的终态是什么)
别默认往下推——用户要的终态停在哪一档,就在哪一档收手:
| 用户要的终态 | 到这一步够不够 | 下一步 |
|---|---|---|
| 只要把默认排版改成自己想要的样子 | ✅ 够了,到这里就结束(以后每次渲染自动生效) | — |
| 还要用这套主题排版某篇正文、存进自己公众号草稿箱 | 不够 | dby-publish(存回服务端的默认排版它会自动拉;本机主题文件用 --theme 指过去) |
| 已有排好版的图文,只想让它进草稿箱 | 不够 | dby-publish |
| 正文还没写 | 不够 | dby-api(拉同主题爆文样本再写正文,走 api.gzh.hotArticle) |
| 正文没过违禁词 | 不够 | dby-banned-words(三平台一次比对,出安全改写版) |
| 说不清要到哪一步 | — | dby(公众号飞轮的逐跳导航) |
- v1.4.32026-08-26feat(dby-publish)!: 出图与设计工作台整套下线 —— 与 dby-image 是同一条上游能力的两套实现
- v1.4.12026-08-26fix(dby-theme): 终态纪律改成本地一句话,不再引用他包的路由判据文件
- v1.4.22026-08-26feat(dby-publish)!: 瘦身 69 → 51 个文件 —— 包内 14 个主题是服务端旧副本,留着只会让排版对不上
- v1.4.02026-08-25fix(dby-theme): 改主题会就地覆写用户线上默认排版且没有备份 —— 加红线 4「不备份不改」与回滚命令
- v1.3.12026-08-25chore(skills): 11 个 SKILL.md 加 changelog 字段,patch 递增;盖戳生成 index.json 与四份兼容视图
- v1.2.02026-08-24refactor(dby): 11 个 SKILL.md 主体压到 ≤6000 字符——冷门分支下沉 references/,协议改引用不再内联;违禁词入口统一指 dby-banned-words
- v1.2.22026-08-24fix(dby): 20 场景模拟测试后的路由与文档修正
- v1.2.22026-08-24feat(dby-publish,dby-theme): 微信 draft/add 字段上限前置校验;主题校验器按官方编辑器规范加四条 warning
- v1.2.12026-08-24refactor(dby): 11 个 SKILL.md 按写作手艺去废话——删解释/元叙述/历史叙事/跨包重复红线,两处 description 去流程复述
- v1.3.02026-08-24refactor(dby): 逐包领域调研后的规则更正与触发词补齐
- v1.1.02026-08-21fix(dby-publish,dby-theme): engine-2 报错不再教用户做一件不会发生的事
- v1.1.02026-08-20feat(skills)!: 统一 dby- 前缀,合并发布包,下架 investigator——公众号执行外脑定位收敛
文件内容在 GitHub 查看。
- SKILL.md8.9 KB
- references/crud.md2.4 KB
- references/deploy-scope.md3.8 KB
- references/live-preview.md0.8 KB
- references/theme-schema.md3.7 KB
- scripts/validate-theme.mjs20.2 KB
- themes/theme.example.json4.1 KB