小红书图文卡片
把一段已经写好的文字排成小红书轮播图(1080×1440 PNG)。只做排版,不做内容:
文字必须来自已经按 SKILL.md 或 random-history-anecdote/SKILL.md 查证过的结果,
本 skill 不新增任何史料,也不改写译文。
平台规范(脚本已内建,不要改)
- 尺寸 1080×1440(3:4 竖版),封面和内页同规格;一篇笔记只能用一种比例,混用会被补白边。
- 一篇 最多 18 张(旧资料说 9 张,那是过时的;现在 App 就给到 18),超出脚本直接报错。
- 真正的硬约束只有张数(18),没有总字数上限。 内容多就多切几张,切到 18 张还放不下 才需要删或拆成两篇。低于 8 张通常说明内容本身太单薄,该回去补或换一则, 而不是把字塞进少数几张里。
- 安全区:上 160px(头像昵称遮挡)、下 210px(点赞收藏栏遮挡)、左右各 88px。 标题和关键信息落在画面偏上 1/3。
- 单图 ≤20MB、建议 ≤5MB;带字用 PNG、sRGB。本脚本出的图约 50–200KB。
- 配套文案:标题 ≤20 字,正文 ≤800 字,话题标签 3–5 个。
主题:每次换一套,不要每篇长一个样
脚本内建 6 套主题。每套同时定五件事:配色、字体、小标题版式、封面构图、卡面装饰 + 页脚。 只换颜色不换版式的话,两篇发出去还是一个样,所以后三项也跟着主题走。
| 主题 | 气质 | 底色 | 标题字 | 小标题 | 封面 | 装饰 / 页脚 |
|---|---|---|---|---|---|---|
xuan |
宣纸暖白 | 米白 | 宋体 | 左竖线 | 左对齐 | 无 / 细线 |
mo |
墨夜 | 近黑 | 宋体 | 顶横线 | 居中,粗线压顶 | 无 / 无框 |
qing |
青瓷 | 浅青灰 | 兰亭黑 | 色块徽章 | 左对齐,标题压色块反白 | 无 / 无框 |
zhu |
朱白 | 冷白 | 圆体 | 下划线 | 居中 | 右上角色块 / 细线 |
lan |
靛青 | 深蓝 | 苹方 | 左竖线 | 左对齐 | 顶部色带 / 胶囊页码 |
jian |
简牍 | 土黄 | 隶书 | 顶横线 | 居中,粗线压顶 | 细边框 / 无框 |
**默认 --theme random,每跑一次换一套。**想定死就 --theme mo。
同一篇笔记的所有卡共用一套主题(脚本保证),跨笔记才换。
随机不是均匀抽:脚本先算这批文字在每套主题下的总溢出,只在较宽松的一半里挑。
文字多的时候,字号最大的 zhu 会被自动跳过——整篇卡卡都缩,比单调更难看。
改版式不要在 JSON 里逐卡指定,那样出来的东西会不统一。要新样子就加一套主题,
在 scripts/xhs_cards.py 的 THEMES 里加一行,五个维度一次配齐。
字号与密度(这是最容易做错的地方)
小红书在信息流里是小图,通行做法是字大、字少、铺满,不是塞满小字。
下面是 xuan 主题的基准字号,其余主题按各自的 scale 倍率整体缩放:
| 元素 | 字号 |
|---|---|
| 封面主标题 | 128px(业界建议 80–120px,知识卡可再大) |
| 封面副标题 | 54px |
| 卡片小标题 | 68px |
| 正文 | 52px(约 17 字一行) |
| 原文 | 48px |
| 脚注 / 页脚 | 34 / 32px |
每张卡约 150 字(跑的时候脚本会打印当前主题的实际预算,字号大的主题更少)。 这个上限来自字号和卡片面积:52px 的字在 1080×1440 里就只放得下这么多。
塞超了不会压到页脚——页面里有段脚本会整体缩到放得下为止(下限 62%)。所以警告的意思是 「这张会被缩小」,不是「这张会烂」。但缩过头的卡在信息流里就看不清了,看到警告还是拆卡。
没有上限的是总量:切够张数即可。正文和原文卡在安全区内垂直居中, 封面居中偏上——短卡片不会挂在顶上留一大片空白。
典型流程
- 先跑
/random-history-anecdote出一则段子(或用主SKILL.md的完整问答结果)。 - 把那一轮已经查证过的译文、出处、出处考证、职官表、原文切成卡片 JSON。
- 跑本 skill 渲染,然后按下面「怎么交付」把 PNG 发出去。
内容一律沿用上一轮的结论,不得重新检索、不得改写、不得补新史料。 上一轮没查到的东西,这一轮也不许补。
用法
venv/bin/python scripts/xhs_cards.py cards.json --outdir outputs/xhs/<段子名>
加 --theme <名字> 可以指定主题,不加就随机换一套。
跑完会在 outputs/xhs/<段子名>/ 下得到 01-cover.png、02-body.png …… 每张卡一个 PNG,
按顺序编号,直接就是发小红书的上传顺序。
怎么交付
- 把所有 PNG 发出去(
SendUserFile,display: "render"),让用户直接在对话里看到渲染效果。 - 末尾写清楚文件夹的绝对路径——图片就在项目目录里,用户从文件夹直接选中上传, 不需要一张张下载。
不要打包成 zip:文件本来就在本机项目目录下,再打个包只是多一步解压。
--html-only:只出 HTML 不截图,用于本机没有 Chrome 时调版式。--selftest:跑自检。
渲染靠本机 Chrome / Chromium / Edge 无头截图,不引入 Node、Playwright、Pillow 等新依赖。
输入 JSON
{
"footer": "《魏书》卷六十六",
"cards": [
{"kind": "cover", "eyebrow": "史 料 段 子 · 北 魏",
"title": "他给弟弟\n办了场葬礼", "sub": "问题是\n弟弟还活着"},
{"kind": "body", "heading": "小标题", "text": "段落一\n\n段落二", "note": "脚注(可省)"},
{"kind": "quote", "heading": "原文 一", "text": "古文照录,宋体竖排感"}
]
}
kind:cover(封面,大标题)/body(译文、考证、职官,正文体)/quote(原文,衬线体)。 具体用什么字体由主题决定,不在 JSON 里指定。text用空行分段,单个\n是段内换行。所有字段自动转义,不要写 HTML。text/sub里用**重点**标出一句金句或反转句,渲染成主题强调色加底纹。 一张最多标一处,标多了等于没标。footer全篇统一,右下角自动打n/N。
切卡建议
段子按 封面 → 译文若干 → 出处考证 → 职官表 → 原文若干 切;
一张 body 约 150 字、quote 约 170 字到顶(随主题字号浮动),脚本会估算并在超出时警告。
超出的卡会被自动缩小而不是溢出,所以警告不致命;但缩太多就看不清了,宁可多切几张。
outputs/ 已在 .gitignore 里,渲染产物不进版本库——它们是每次重跑就能重建的中间物,
不是源文件。
红线
- 不擅自配图。要加照片、地图、书影一律先跟用户确认用哪几张,不要自己塞。
- 卡片文字必须和本轮查证结果一致;不得为了排版好看删掉「今地未能确认」「(推断)」这类限定语。
- 年号、古地名今地、职官释义照
SKILL.md规矩走,卡片不是豁免区。