# Hkr Render

> WeChat Official Account (微信公众号) publishing pipeline: format Markdown or plain text into WeChat-compatible inline-style HTML with 7 polished themes (dark mode and mobile font sizes tuned), optionally generate a cover image with brightness check and auto-darkening, and push one or many articles to the WeChat draft box (多图文). Use when the user wants to format, typeset or publish a WeChat article, or says 排版, 微信排版, 公众号排版, 公众号发布, 格式化文章, format, /format. Requires a config.json with WeChat AppID/Secret (see SKILL.md).

- Skill: `hanzhangzzz/hkr-render` (Agent Skill, multi-file: 23 files)
- Install (CLI): `npx skillmds@latest add hanzhangzzz/hkr-render`
- Raw SKILL.md: https://api.skillmd.com/api/skills/hanzhangzzz/hkr-render/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: hanzhangzzz (https://skillmd.com/u/hanzhangzzz)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/hanzhangzzz/hkr-render

---


# xiaohu-wechat-format

公众号一键排版技能。把任意文本内容（Markdown、纯文本、格式粗糙的笔记）转成微信公众号兼容的排版 HTML，AI 自动理解内容结构并增强排版，可视化选择主题后一键复制粘贴到微信后台。可选生成封面图、推送草稿箱。

## Skill Description For Claude

公众号完整管线：排版 → 封面（可选）→ 推送（可选）。把 Markdown 文章转为微信公众号兼容的内联样式 HTML，支持纯文本输入，AI 自动补充结构和排版增强。当用户说"排版""微信排版""格式化文章""format"时使用。

## 脚本目录

`{baseDir}` = 本 SKILL.md 所在目录。执行脚本时用 `{baseDir}/scripts/xxx.py` 替换为实际绝对路径。

| 脚本 | 用途 |
|------|------|
| `scripts/format.py` | 排版：Markdown → 微信兼容 HTML |
| `scripts/publish.py` | 推送：HTML → 公众号草稿箱 |
| `scripts/comment_reply.py` | 评论自动回复（可选） |

## 配置

首次使用需创建 `config.json`（参考 `config.example.json`）：

```json
{
  "output_dir": "/tmp/wechat-format",
  "vault_root": "/path/to/your/obsidian/vault",
  "settings": {
    "default_theme": "newspaper",
    "auto_open_browser": true
  },
  "wechat": {
    "app_id": "YOUR_APP_ID",
    "app_secret": "YOUR_APP_SECRET",
    "author": "作者名"
  },
  "cover": {
    "output_dir": "~/Documents/covers",
    "image_generation_script": ""
  }
}
```

- `wechat` 部分仅推送时需要，纯排版可不填
- `cover` 部分仅生成封面时需要
- `config.json` 已在 `.gitignore` 中，不会被提交

## Instructions

### 触发条件

用户说以下任何一种：
- `/format 文件路径`
- `排版这篇文章`
- `微信排版`
- `格式化为公众号格式`
- `把这篇转成微信格式`

### 完整工作流

#### 第 1 步：确认文章

1. 如果用户给了文件路径，直接读取
2. 如果没给路径，问用户要文章路径
3. 读取文章内容，确认标题和字数

#### 第 1.5 步：结构化预处理（仅在需要时）

读取文章后，先检测输入内容的 Markdown 结构完整度，决定是否需要 AI 结构化预处理。

**检测方法**：扫描全文，统计 `##` 标题、`**加粗**`、`- 列表`、`> 引用`、`` ` 代码 ` `` 等格式标记的数量。

**判断规则**：
- 有 `##` 标题且格式标记分布合理 → **跳过**，直接进入第 2 步
- 缺少 `##` 标题，或几乎没有格式标记（纯文本/粗糙笔记）→ **执行结构化**

**结构化规则（底线：只加标记，不改内容）**：

1. **加标题**：识别文章的逻辑段落和主题转换点，在转换处插入 `##` 标题。标题从内容中提炼，不编造。三段内容不硬拆五个标题——尊重原文信息密度
2. **分段落**：确保段落之间有空行分隔，长段落在语义转换处拆分
3. **加列表**：识别并列/枚举性质的内容，加 `- ` 或 `1. ` 标记
4. **加强调**：识别关键词、产品名、核心概念，加 `**加粗**`
5. **清理格式**：去除多余空行、修正缩进、统一标点
6. **不改措辞**：不调语序、不增删内容、不润色文字。用户写什么就是什么，只加结构标记

**保存与告知**：
- 结构化后保存为 `/tmp/wechat-format/xxx-structured.md`
- 告知用户："检测到输入缺少 Markdown 格式标记，已自动补充标题和结构，保存在 xxx-structured.md，可检查调整"
- 后续第 2 步基于 structured.md 继续处理

---

#### 第 2 步：AI 内容分析 + 自动套格式

读取文章（或上一步输出的 structured.md），Claude 分析内容结构，在 Markdown 层面自动套用合适的排版容器。这是我们比纯手动排版工具强的核心——AI 理解内容，自动匹配最佳呈现方式。

**分析维度**：文章类型（访谈/教程/产品介绍/深度分析）、内容元素（对话/图片/代码/数据）、节奏感（密集段 vs 留白段）。

**自动套用规则**（按优先级）：

1. **对话/访谈** → `:::dialogue[标题]`
   - 检测到 `**名字：**` 或 `名字：` 交替出现 → 用 `:::dialogue` 包裹
   - 格式：`名字: 对话内容`（中英文冒号都支持）
   - 不是所有对话都要套——独白段落、叙述性段落保持原样
   - 同一场景的连续对话放一个 dialogue 块，换场景换一个新块

2. **连续双图并排** → `:::duo`
   - 检测：连续 2 张图片，中间最多隔一段 ≤ 60 字短文字，且两图比例相近（不是一明显横一明显竖）
   - 动作：把两张图包进 `:::duo`（标题通常留空，例：`:::duo\n![...](a.jpg)\n\n![...](b.jpg)\n:::`）
   - **图说处理（方案 B 折叠）**：
     - 紧邻图片的句子若在"讲这张图"（描述内容/举例/"我试了..."） → 折成 `*斜体*` 紧跟对应图片（作为图说）
     - 若是过渡/总括句（"这创意太绝了""还有人..."作为章节承接） → **保留**在 `:::duo` 容器上方正文，不吃
     - 无相邻描述句时 → 自动用 `alt` 文字（`alt` 长度 1–20 字）
   - **尊重作者**：作者已手写 `*斜体*` 图说 → 绝不吃相邻句子
   - 3 张及以上连续图走第 3 条（`:::gallery`）

3. **连续多图 / HTML 图片组** → `:::gallery[标题]`
   - 3 张以上连续图片 → 自动套 `:::gallery`
   - 文章里已有的 `<div align=center><img ...></div>` 图片组会被脚本自动识别
   - 脚本会自动区分顺序型 / 展示型图组：有有效 alt/图说、数量少、或不像同一批素材时保持原序；4 张以上、无有效图说、文件名像同一批素材时判定为展示型，可为版面重排
   - 渲染时按每张图片真实比例选择宽度：特别宽的横图通栏，其他图片最多两列；展示型图组会把尺寸相近的图片放在同一水平栏里，让整组尽量接近矩形，减少大块留白和锯齿形边界；保留完整画面，不做裁剪
   - 适合产品截图、对比图、系列图；不要把所有图片机械堆成纵向列表，也不要强行裁成固定九宫格

4. **超长图片** → `:::longimage[标题]`
   - 流程图、架构图、长截图 → 固定高度容器，纵向滚动
   - 一般需要用户标注或 AI 判断图片内容

5. **核心观点/金句** → callout 格式
   - 核心观点 → `> [!important] 标题`
   - 小技巧/提示 → `> [!tip] 标题`
   - 注意事项 → `> [!warning] 标题`
   - 普通引用 → `> [!callout] 标题`（使用主题色）
   - 不要过度使用，一篇文章 1-3 处即可

6. **分隔符** → 在章节转换处确保有 `---` 分隔

7. **图说标记** → 图片后紧跟的说明用斜体：`*这是图片说明*`
   - 在 `:::duo` 内若作者未写 `*斜体*`，AI 可按方案 B 折叠相邻描述句作为图说

8. **外部链接** → 无需处理（脚本自动转脚注）

**处理完成后**，把增强后的 Markdown **直接写回原文件**（图片所在目录）。禁止保存到 `/tmp/` 等其他目录，否则图片相对路径会失效。

#### 第 2.5 步：推荐主题

根据内容分析结果，推荐 2-3 个最适合的主题（不确定时默认 hanzhang）：

| 内容类型 | 推荐主题 |
|----------|----------|
| 深度长文/分析/调查 | hanzhang, newspaper, magazine |
| 科技产品/AI工具/教程 | hanzhang, github |
| 文艺/随笔/观点 | terracotta, ink |
| 传统文化/国风题材 | chinese |

推荐的主题 ID 通过 `--recommend` 参数传给脚本，在 gallery 中高亮显示。

#### 第 3 步：打开主题画廊（默认流程）

```bash
python3 {baseDir}/scripts/format.py \
  --input "文章路径.md" \
  --gallery \
  --recommend hanzhang newspaper github
```

这会用用户的**真实文章**渲染全部精品主题，在浏览器打开画廊页面。用户点按钮切换主题预览，选中后点「用这个风格排版」一键复制到剪贴板。

#### 第 3 步（备选）：直接指定主题排版

如果用户已经知道想用哪个主题，可以跳过画廊直接排版：

```bash
python3 {baseDir}/scripts/format.py \
  --input "文章路径.md" \
  --theme terracotta
```

#### 第 4 步：确认结果

告诉用户：
- Gallery 模式：在浏览器中切换主题预览，选中后点按钮复制，粘贴到公众号后台
- 直接模式：在浏览器中检查预览，点「复制到微信」按钮

---

### 封面图生成（可选）

排版完成后，用户说"配封面""生成封面"时执行。

#### 封面硬规则（生成图和现成图裁切都必须遵守）

微信会在两个场景二次加工封面，不满足下面规则的封面会在这两个场景翻车（2026-08 实测踩坑）：

1. **主封面下沿会被压白字标题**。分享卡片/发表预览会把文章标题用白色文字叠在封面下部约 1/3 区域。因此**封面下部 40% 必须是深色或中深色**——浅色/纯白底封面标题直接隐形。用现成截图当封面且底部偏浅时，必须加"从中部向底部渐深的黑色遮罩"（PIL 渐变合成即可，publish.py 提供 `--darken-cover` 自动处理），或换深色素材。
2. **多图文次条封面是小方图**。第 2 篇起的封面在卡片里以约 1:1 小尺寸展示，**只能用大主体、大色块、粗轮廓的图**；细字截图、密集图表、白底细线图缩小后糊成白块，一律禁用。给次条选封面先问一句：缩到 100px 见方还认得出吗？
3. 主封面 2.35:1（900×383 或等比高清），次条建议同时准备 1:1 裁切版本。
4. 推送前用 publish.py 的封面亮度检查结果确认，警告未消除不要发布。

#### 封面提示词模板

```
请根据提供的内容创建一张吸引眼球的公众号封面图，遵循以下规范：

视觉风格
- Notion插画风格，比例为 2.35:1（公众号封面标准尺寸）
- 色彩鲜明、对比强烈，确保在小尺寸预览时依然醒目
- 风格统一，避免写实元素，保持整体手绘质感

构图要求
- 主视觉元素居中或偏左（右侧预留标题区域）
- 添加 1-2 个简洁的卡通形象、图标或知名人物剪影，增强记忆点
- 大量留白，突出核心信息，避免画面拥挤
- 画面下部 40% 使用深色或中深色调（微信分享卡片会在封面下沿叠加白色标题文字，浅底会让标题隐形）

文字处理
- 标题文字大而醒目，控制在 8 字以内
- 可添加 1 行副标题或关键词标签
- 字体风格与手绘插画协调统一

吸引力法则
- 使用悬念、数字、痛点等钩子元素激发点击欲望
- 视觉元素夸张有反差
- 色彩搭配参考爆款封面：橙黄、蓝紫、红黑等高对比组合

语言
- 除非另有说明，默认使用中文
- 画面内所有可读文字必须使用简体中文，英文只能作为点缀出现

内容主题：{从文章中提炼的一句话主题描述}
```

#### 封面工作流

1. 从文章提炼一句话主题
2. 用上述模板生成提示词，保存为 `prompt.md`（YAML 头 `aspect_ratio: "21:9"`, `image_size: "2K"`）
3. 调用图片生成服务（需在 `config.json` 中配置 `cover.image_generation_script`，或手动使用任意 AI 生图工具）
4. 生成后默认插入文章标题下方

---

### 推送到公众号草稿箱（可选）

排版完成后，用户说"推送""发公众号"时执行。需要在 `config.json` 配置 `wechat.app_id` 和 `wechat.app_secret`。

```bash
python3 {baseDir}/scripts/publish.py \
  --dir "排版输出目录" \
  --cover "封面图路径（可选）"
```

推送流程：
1. 读取排版后的 HTML（`article.html`）
2. 上传文章内图片到微信 CDN
3. 上传封面图为素材
4. 创建草稿（自动填充标题、摘要、作者）
5. 返回 media_id，可在公众号后台「内容管理→草稿箱」查看

也支持从 Markdown 直接推送（自动排版再推）：

```bash
python3 {baseDir}/scripts/publish.py \
  --input "文章.md" \
  --theme hanzhang
```

多图文（一条草稿多篇文章，微信上限 8 篇）：

```bash
python3 {baseDir}/scripts/publish.py \
  --input 第一篇.md 第二篇.md \
  --cover 封面1.jpg 封面2.jpg \
  --theme hanzhang --yes
```

---

### 参数说明

**format.py**：
- `--input` / `-i`：Markdown 文件路径（必须）
- `--gallery`：打开主题画廊（推荐，默认使用）
- `--theme` / `-t`：直接指定主题名（跳过画廊）
- `--output` / `-o`：输出目录（默认 /tmp/wechat-format）
- `--vault-root`：Obsidian Vault 根目录（用于搜索 wikilink 图片）
- `--recommend`：推荐的主题 ID 列表，gallery 中高亮显示
- `--no-open`：不自动打开浏览器
- `--format`：输出格式 wechat/html/plain

**publish.py**：
- `--dir`：排版输出目录路径（已排版好的 HTML，单篇）
- `--input`：Markdown 文件路径，**可传多个**（多个文件 = 一条多图文草稿，微信上限 8 篇）
- `--cover` / `-c`：封面图路径，可传多个与 `--input` 一一对应（省略则自动搜索）
- `--title` / `-t`：文章标题（默认从 HTML 提取；多图文时仅作用于第一篇）
- `--digest`：文章摘要（默认自动取首段前 100 字；多图文时仅作用于第一篇）
- `--theme`：排版主题（仅 `--input` 模式有效）
- `--author` / `-a`：作者名（默认读 config.json）
- `--darken-cover`：封面下部自动加渐暗遮罩（浅底封面必开，见封面硬规则）
- `--yes` / `-y`：跳过交互确认（非交互环境下部分图片失败时默认中止，需此参数放行）
- `--dry-run`：只做排版和图片上传，不推送草稿箱
- `--source-dir`：源文件目录（仅 `--dir` 模式需要，用于查找封面图）

**封面图搜索逻辑**：默认按以下顺序查找封面图 `*-cover.png`：
1. `--cover` 指定路径
2. `--dir` 目录的子目录 `images/`
3. `--source-dir` 目录（`--dir` 模式）或 `--input` 文件同级目录（`--input` 模式）

**推荐目录结构**：文章 `.md` 与图片 `images/` 同级平铺，封面图放在 `images/` 内。

### 可用主题（精品 7 个）

2026-08 从 34 个精简而来，只保留互相拉得开差距、手机端验证过的主题；被删主题可从 git 历史找回。

| 主题 | 命令值 | 风格 | 适用 |
|------|--------|------|------|
| 含彰（默认） | hanzhang | 克制现代，单一靛蓝强调，零渐变，深色模式原生安全 | 所有内容的首选 |
| 报纸 | newspaper | 纽约时报风 | 严肃深度长文 |
| GitHub | github | 开发者风，浅色代码块 | 技术文章、代码分享 |
| 杂志 | magazine | 超大留白 | 品质长文 |
| 墨韵 | ink | 纯黑水墨，极简留白 | 极简审美 |
| 中国风 | chinese | 朱砂红，古典雅致 | 传统文化题材 |
| 赤陶 | terracotta | 暖橙色 | 文艺随笔 |

### 内置排版增强

脚本自动处理以下内容：
- **CJK 间距修复**：中英文/中数字之间自动加空格
- **加粗标点修复**：`**文字，**` → `**文字**，`，中文标点移到标记外
- **纯内联样式**：所有 CSS 直接写在每个标签的 `style="..."` 属性上
- **列表模拟**：`<ul>/<ol>` 改为 `<section>` + flexbox 模拟
- **外链转脚注**：`[text](url)` 自动变成正文 `text[1]` + 文末脚注列表
- **图片处理**：`![[image.jpg]]` 自动搜索 Vault 并复制到输出目录
- **图片自适应宽度**：单图按真实长宽比自动映射渲染宽度（横图 100%、近方形 75%、轻竖图 60%、长竖图 45%），避免竖图在手机上占满屏幕。测量失败回退 70%。
- **HTML 图片组自适应图墙**：自动处理 `<div align=center><img ...></div>` 这类原生 HTML 图片组，按每张图片比例分配通栏 / 双列；顺序型保持原序，展示型允许自动重排，把尺寸相近的图配成水平栏来减少留白；保留原图比例，不使用 `object-fit: cover` 裁剪。
- **多类型提示框**：`[!tip]`/`[!note]`/`[!important]`/`[!warning]`/`[!caution]` 各有独立配色
- **图说识别**：图片后紧跟的斜体段落自动变为居中灰色图说
- **对话气泡**：`:::dialogue[标题]` → 左右交替聊天气泡
- **图片画廊**：`:::gallery[标题]` → 多图自适应图墙，按图片比例分配宽度；手写 gallery 默认保持原序，自动识别到的展示型 HTML 图组可重排以减少留白，并保留完整画面
- **长图展示**：`:::longimage[标题]` → 固定高度纵向滚动容器
- **两栏并排**：`:::duo[标题]` → 两图左右并排 + 下方居中图说，适合成对对比图（AI 在连续双图时自动套用）

### 注意事项

- 依赖 Python `markdown` 库和 `Pillow`（`pip install markdown Pillow`）
- 图片在预览中可见，但粘贴到微信后需要手动上传（或用推送功能自动上传）
- 如果用户对排版不满意，可以切换主题重新生成
- 画廊模式渲染 20 个主题，用的是用户的真实文章

### 图片路径规则（必须遵守）

脚本的 `--input` 文件必须和图片在同一目录。脚本按 `--input` 文件所在目录解析相对路径的图片引用（如 `![alt](photo.jpg)`）。

**禁止**以下操作：
- 把增强版 Markdown 保存到 `/tmp/` 等不含图片的目录
- 用 `--input` 指向一个不在图片目录中的文件
- 带远程图片 URL（`![...](http...)`）直接排版——外链图无法测量尺寸（一律回退 70%），且公众号后台不加载外链图。发现外链图先下载到本地 `images/` 并改为相对路径，再继续排版

**正确做法**：始终用原始文章文件的路径作为 `--input`。如需做排版增强（加 callout、分隔符等），直接写回原文件。

