xhs-card-renderer

star 0

将 Markdown 正文渲染为小红书风格的高清图片卡片(1080×1440,2x DPI)。当用户需要"出图""渲染卡片""生成小红书图片""把文章变成图片"时触发。覆盖:风格规范、HTML 生成、Playwright 高清导出。

cyrus-tt By cyrus-tt schedule Updated 6/6/2026

name: xhs-card-renderer description: 将 Markdown 正文渲染为小红书风格的高清图片卡片(1080×1440,2x DPI)。当用户需要"出图""渲染卡片""生成小红书图片""把文章变成图片"时触发。覆盖:风格规范、HTML 生成、Playwright 高清导出。

小红书图文卡片渲染 Skill

将写好的帖子正文转化为可直接上传小红书的高清 PNG 图片。

About

  • 一个 Claude Code / Agent skill,把 Markdown 正文渲染成小红书风格的高清卡片。
  • 引擎:Playwright + Chromium,2x DPI,输出 1080×1440 卡片。
  • 设计哲学:像书页,不像海报。零装饰、强排版、反 AI 味。
  • {{AUTHOR}} 是占位符——首次安装后全局替换成你的账号名(见 README「自定义」)。

触发条件

用户说类似:

  • "帮我出图 / 渲染成图片"
  • "把这篇帖子变成小红书卡片"
  • "生成小红书图片"
  • "渲染一下"

风格铁律:像书页,不像海报

风格参考:夸克扫描王系列、migeai、Decoder Only 这类「文档感」博主。 核心感受:读者应该觉得"在读一篇文章",而不是"在看一张设计作品"。

背景

  • 奶白色 #f5f0eb,不是纯白
  • 零装饰:无边框、无阴影、无圆角、无渐变、无网格、无纹理
  • 不加任何 emoji 装饰

字体

font-family: 'PingFang SC', -apple-system, 'Noto Sans SC', sans-serif;
-webkit-font-smoothing: antialiased;
元素 字号 字重 颜色
正文 38px 400 #1a1a1a
加粗强调 38px 700 #1a1a1a
小字/补充 34px 400 #888
水印 22px 400 rgba(0,0,0,0.10)

行高 1.85,段间距 margin-bottom: 40px,字间距 0.8px

强调方式(只有两种,不允许发明新的)

1. 加粗(主力,无限制使用)

直接 font-weight: 700,不改颜色、不加背景。

2. 荧光笔划线(点睛,每页最多 1 处)

.hl {
  background: linear-gradient(to top, rgba(255,183,77,0.35) 0%, rgba(255,183,77,0.35) 35%, transparent 35%);
  font-weight: 700;
}

效果:文字下方 35% 有淡橙色色带,像荧光笔划过。只用于全页最核心的金句。

绝对禁止

  • ❌ 彩色边框 / 左边框
  • ❌ 背景色块(紫色、蓝色、任何颜色)
  • ❌ 圆角卡片 / 阴影
  • ❌ 分割线 <hr>
  • ❌ 不同颜色的文字
  • ❌ Emoji 点缀
  • ❌ 任何让人一眼看出"这是 AI 做的"的设计元素

内容密度规范

原则:宁满勿空

页面类型 建议字数 段落数
纯文字页 180-280 字 5-8 段
图文混合页 80-150 字 + 截图 截图占 30-50%
CTA 结尾页 120-200 字 可略少

如果一页不到 120 字,必须和相邻页合并。绝不允许一页只有 2-3 行。

截图嵌入

  • 截图作为 <img> 直接插入正文流
  • 无边框、无阴影、无圆角:width: 100%; margin: 24px 0 32px;
  • 截图前后要有文字解释

执行步骤

Step 1:分析正文,规划分页

读取用户提供的正文(Markdown 或纯文本),按以下规则分页:

  1. 计算每页文字量,确保 180-280 字/页
  2. 将稀疏页面合并
  3. 第 1 页带作者头像 + 名字 + 日期
  4. 最后一页放 CTA

输出分页方案给用户确认:

第 1 页(引入):xxx - xxx(约 220 字)
第 2 页(结构):xxx - xxx(约 250 字)
...
共 N 页,是否 OK?

Step 2:生成 HTML 文件

创建 HTML 文件,文件名格式:YYYYMMDD-标题关键词.html(建议放在一个 output/ 或工作目录下)。

生成前必做(防止印错日期)

  • 先跑 date +%Y-%m-%d 取当天真实日期,把模板里第 1 页的 __DATE__ 占位符替换掉。绝不允许直接沿用模板里的旧日期。
  • 文件名里的 YYYYMMDD 同样用当天日期。
  • 作者名 / 水印用你的账号名替换 {{AUTHOR}}(或安装时已全局替换好)。

HTML 模板结构:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<style>
  @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;700&display=swap');
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body {
    font-family: 'PingFang SC', -apple-system, 'Noto Sans SC', sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    background: #ddd;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 40px;
    padding: 40px;
  }
  .slide {
    width: 1080px;
    height: 1440px;
    background: #f5f0eb;
    padding: 80px 88px 64px;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    position: relative;
    overflow: hidden;
  }
  .slide p {
    font-size: 38px;
    font-weight: 400;
    color: #1a1a1a;
    line-height: 1.85;
    margin-bottom: 40px;
    letter-spacing: 0.8px;
  }
  .slide p.bold, .slide strong { font-weight: 700; }
  .slide p.muted { font-size: 34px; color: #888; }
  .slide .hl {
    background: linear-gradient(to top, rgba(255,183,77,0.35) 0%, rgba(255,183,77,0.35) 35%, transparent 35%);
    font-weight: 700;
  }
  .slide img.screenshot { width: 100%; margin: 24px 0 32px; }
  .slide .header { display: flex; align-items: center; gap: 18px; margin-bottom: 56px; }
  .slide .avatar {
    width: 68px; height: 68px; border-radius: 50%;
    background: linear-gradient(135deg, #667eea, #764ba2);
    display: flex; align-items: center; justify-content: center;
    font-size: 30px; color: #fff; font-weight: 700; flex-shrink: 0;
  }
  .slide .author-name { font-size: 32px; font-weight: 700; color: #1a1a1a; }
  .slide .author-date { font-size: 24px; color: #aaa; margin-top: 2px; }
  .slide .watermark {
    position: absolute; bottom: 32px; right: 44px;
    font-size: 22px; color: rgba(0,0,0,0.10);
  }
</style>
</head>
<body>

<!-- 第 1 页 -->
<!-- __DATE__ 必须替换成当天日期(见 Step 2 说明),不要直接用模板里的占位值 -->
<div class="slide">
  <div class="header">
    <div class="avatar">C</div>
    <div>
      <div class="author-name">{{AUTHOR}}</div>
      <div class="author-date">__DATE__</div>
    </div>
  </div>
  <p>正文内容...</p>
  <p class="bold">加粗内容...</p>
  <span class="watermark">@{{AUTHOR}}</span>
</div>

<!-- 第 N 页 -->
<div class="slide">
  <p>正文...</p>
  <p><span class="hl">荧光笔高亮金句</span></p>
  <span class="watermark">@{{AUTHOR}}</span>
</div>

</body>
</html>

Step 3:渲染高清 PNG

用本仓库的渲染脚本导出 2x DPI 图片:

test -f scripts/render-cards.js || echo "⚠️ 找不到渲染脚本,确认路径/工作目录"
node scripts/render-cards.js path/to/YYYYMMDD-xxx.html path/to/output-dir/

输出:slide-01.png ~ slide-0N.png,每张 2160×2880 实际像素。

把本 skill 装到 Claude Code(~/.claude/skills/xhs-card-renderer/)时,记得让 scripts/render-cards.js 跟着一起,或在上面命令里写脚本的绝对路径。

Step 4:展示给用户确认

只展示第 1 张给用户看,等确认后再渲染剩余。

绝对不要一口气渲染所有页面。先出 1 张,用户说 OK 再继续。


质检清单(渲染前必查)

  • 背景 #f5f0eb,无任何装饰
  • 没有彩色色块、边框、阴影
  • 每页内容 ≥ 120 字,不存在稀疏页
  • 加粗是主力强调,划线高亮每页 ≤ 1 处
  • 截图无边框无圆角
  • 字体抗锯齿已开启
  • 水印极淡 rgba(0,0,0,0.10)
  • 第 1 页日期 = 当天真实日期(模板里没残留 __DATE__ 或旧日期)
  • 作者名/水印已替换 {{AUTHOR}}
  • 整体看起来像"在读文章",不像"在看设计"

依赖

  • Node.js
  • Playwright(npm install + npm run setup 装 Chromium)
  • 渲染脚本:scripts/render-cards.js
Install via CLI
npx skills add https://github.com/cyrus-tt/xhs-card-renderer --skill xhs-card-renderer
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator