Skill: irenerachel/ebook-maker (version 0.1.0)

# Ebook Maker — AI 电子书制作工作流 从调研到成书的一站式电子书生成引擎，支持即梦插图、统一排版、自动 PDF 导出。 ## 配置文件 本 Skill 由 3 个文件组成，视觉相关的规范独立可改： | 文件 | 职责 | 何时修改 | |------|------|--------| | `SKILL.md`（本文件） | 主流程、阶段定义、调研策略、交付规范 | 改流程逻辑时 | | `layout.md` | 排版规范：配色、字体、间距、对齐、分页、PDF 命令 | 改排版风格时 | | `illustration.md` | 插图规范：即梦参数、风格模板、比例选择、压缩规则 | 改插图风格时 | **执行时必须同时读取这 3 个文件。** 排版和插图的具体参数以配置文件为准，本文件只定义流程。 ## 触发条件 用户提到以下关键词时触发： - "帮我写一本" / "写本电子书" / "出一本书" - "做个 PDF 手册" / "写个小册子" - "ebook" / "电子书" / "手册" ## 总体流程 ``` Stage 1 需求确认 → Stage 2 深度调研 → Stage 3 内容架构 → Stage 4 插图规划 → Stage 5 写书排版 → Stage 6 交付报告 ``` --- # Stage 1：需求确认 触发后，先向用户确认以下参数（能从指令推断的不问，推断不了的才问）： > **收到，准备制作电子书。请确认以下信息：** > > 1. **书名**：「{从指令推断}」，可以吗？ > 2. **目标读者**：小白 / 有基础 / 专业人士？ > 3. **语言风格**：通俗大白话 / 专业严谨 / 混合？ > 4. **篇幅偏好**：精简（8-12 章）/ 详尽（15+ 章）？ > 5. **是否需要插图**：是 / 否？ > 6. **末尾引导**：需要加公众号/个人品牌引导吗？如果是，名称是？ > > 直接回复修改项即可，没问题的我直接开始。 **快捷模式**：如果用户在触发时已说明足够信息（如"帮我写一本关于 XX 的小白手册，加插图，末尾加公众号阿真Irene"），跳过确认直接执行。 **参数默认值**（用户未指定时）： - 目标读者：小白 - 语言风格：通俗大白话 - 篇幅：精简（10-12 章） - 插图：否 - 末尾引导：无 --- # Stage 2：深度调研 ## 调研策略 根据主题拆分为 4-5 个独立方向，派出并行 Agent 搜索： ``` Agent 1：核心概念与定义 Agent 2：工具/方法/技术细节 Agent 3：行业案例与对比 Agent 4：常见问题与最佳实践 Agent 5：视频/社区资源（可选） ``` 每个 Agent 的指令模板： ``` Use WebSearch and WebFetch to research [方向描述]. Search for: 1. [搜索词 1] 2. [搜索词 2] 3. [搜索词 3] 4. [搜索词 4] 5. [搜索词 5（中文信源）] For each search, WebFetch the top 2-3 most relevant results. Return a comprehensive report covering: [期望内容列表] Include all source URLs. ``` ## 调研质量要求 - 信源总数 ≥ 20 个 - S/A 级信源占比 ≥ 50% - 信源质量分级：S（一手）→ A（权威）→ B（从业者）→ C（社区） - 所有关键事实需要至少 2 个独立信源交叉验证 ## 调研文件保存 自动保存到 `~/Downloads/调研报告/`，命名格式：`YYYYMMDD-[方向简述]调研.md` --- # Stage 3：内容架构 ## 大纲生成 基于调研结果，生成章节大纲。每章包含： - 章节编号和标题 - 本章覆盖的核心概念（3-8 个） - 一句话概括本章价值 ## 用户确认 将大纲展示给用户确认： > **以下是初步大纲，请确认或修改：** > > Chapter 01 — [标题]（[概括]） > Chapter 02 — [标题]（[概括]） > ... > 附录 — [内容] > > 需要增删改章节吗？没问题我开始写。 **快捷模式**：如果用户要求"直接写不用确认"，跳过此步。 ## 排版风格确认 默认使用「简洁专业风」排版模板（详见 Stage 5）。如果用户有参考 PDF，先用 Read 工具读取其风格特征，然后对齐。 --- # Stage 4：插图规划 **仅在 Stage 1 确认需要插图时执行此阶段。** **所有插图参数（数量规划、风格模板、比例选择、压缩规则）详见 `illustration.md` 配置文件。** 执行流程： 1. **规划**：根据章节数选插图数量和位置（见 illustration.md 数量表） 2. **定风格**：根据书的主题组装 STYLE_PREFIX（见 illustration.md 主色调方案） 3. **锚定确认**：用 STYLE_PREFIX 生成 1 张锚定图 → 展示给用户确认风格 4. **批量生成**：确认后逐个串行生成其余插图（即梦不支持并发） 5. **下载压缩**：下载图片 + sips 压缩（见 illustration.md 压缩规则） 6. **记录**：在工作报告中记录每张图的 submit_id、prompt、状态 --- # Stage 5：写书 + 排版 ## 排版规范 **所有排版参数（配色、字体、间距、对齐规则、分页、打印适配、PDF 命令）详见 `layout.md` 配置文件。** 生成 HTML 时，从 `layout.md` 读取 CSS 参数。排版自检清单也在 `layout.md` 中。 ## 内容写作规范 ### 每个术语/概念的结构 ```html <div class="term"> <div class="term-name">中文名</div> <div class="term-en">English Name / 补充说明</div> <p>通俗解释正文...</p> <div class="tip"> <span class="analogy">类比：生活化的比喻...</span><br> <span class="hint">实用提示或注意事项...</span> </div> <hr class="term-sep"> </div> ``` ### 写作风格规则 - 小白向：用「就是」「就像」「简单说」等口语化连接 - 类比优先选择中国用户熟悉的场景 - 代码用 `<span class="code">` 包裹，橙色显示 - 每章开头有 `ch-intro` 段落，概括本章价值 - 不堆砌术语，每个概念独立可理解 ### 末尾引导页模板 ```html <div class="ending"> <h2>感谢阅读</h2> <hr> <div class="cta">如果这本小册子对你有帮助，欢迎关注我的公众号</div> <div class="account">@{公众号名称}</div> <div class="desc">{一句话介绍}<br>{一句话价值主张}</div> <div class="action">微信搜索「{名称}」或扫描公众号二维码关注</div> </div> ``` ## PDF 生成 ```bash "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \ --headless=new \ --disable-gpu \ --no-sandbox \ --print-to-pdf="输出路径.pdf" \ --print-to-pdf-no-header \ --no-pdf-header-footer \ "file:///HTML文件路径.html" ``` **注意**： - HTML 中引用的图片必须和 HTML 在同一目录（用相对路径） - `--print-to-pdf-no-header` 去除 Chrome 默认的 URL 页脚 - 配合 CSS `@page` 的 `content: none` 双重保障 --- # Stage 6：交付 + 工作报告 ## 交付动作 1. 打开生成的 PDF：`open "输出路径.pdf"` 2. 报告文件大小 3. 汇总章节数、术语数、信源数等关键数据 ## 工作报告自动生成 保存到 `~/Downloads/调研报告/YYYYMMDD-[书名]-工作报告.md` **工作报告模板**： ```markdown # 工作报告：[书名] > **项目**：[一句话描述] > **完成时间**：YYYY-MM-DD > **最终交付**：`文件名.pdf`（大小） --- ## 一、任务理解 [用户原始需求 + 推断的参数] ## 二、调研阶段 [N 个 Agent、搜索次数、信源数、各 Agent 核心发现摘要] ## 三、内容架构 [章节列表 + 术语数] ## 四、插图生成（如有） [即梦 CLI 生成记录：submit_id、prompt、状态、用于位置] [风格 prompt 模板] [下载/压缩处理记录] ## 五、排版与 PDF [HTML 模板、Chrome headless 转换、对齐检查结果] ## 六、产出文件清单 [完整文件树] ## 七、关键数据 [表格：章节数、术语数、信源数、插图数、PDF 大小等] ``` --- # 全局规则 ## 文件保存路径 - 调研报告：`~/Downloads/调研报告/` - 电子书 HTML/PDF：`~/Downloads/调研报告/` - 插图文件：与 HTML 同目录 - 工作报告：`~/Downloads/调研报告/` ## 即梦 CLI 注意事项 - **必须串行调用**，不支持并发（并发会 EOF） - 每次生成前检查 `dreamina user_credit`，余额不足时提醒用户 - 生成失败时自动重试 1 次，仍然失败则跳过并记录 - 图片下载：字节跳动 CDN 偶发 SSL 错误，用 `--retry 3 --max-time 30` - 下载失败不阻塞流程，在报告中标注 ## 排版铁律 - 所有内容元素左右对齐，不允许宽度不一 - 图片 max-width 不超过正文区域 - 页脚不显示文件路径 - 打印时保留背景色（`print-color-adjust: exact`） ## 禁止事项 - 不使用花哨的渐变、阴影、多彩卡片 - 不在 HTML 中内嵌 base64 图片（文件过大） - 不在生成过程中向用户发过长的中间结果 - 不跳过用户确认环节（除非用户明确说"直接做"）

path: illustration.md
content: # 插图规范

本文件定义电子书插图的生成参数、风格模板和嵌入规则。修改此文件即可调整插图风格，无需改动主 Skill。

---

## 生成工具（三选一）

在 Stage 1 需求确认时，选择使用哪个生图工具。默认即梦 CLI。

| 工具 | 适合场景 | 前置条件 |
|------|--------|---------|
| **即梦 CLI**（默认） | 最方便，本地 CLI 直接调用 | `dreamina` 已登录 |
| **SeedDream API** | 质量最高（Seedream 5.0），稳定 | 需要 `ARK_API_KEY` |
| **Nano Banana** | 免费额度大，支持 4K | 需要 `GEMINI_API_KEY` |

---

### 选项 A：即梦 CLI（默认）

```
工具：dreamina CLI
模型：5.0
分辨率：2k（可选 4k）
```

**调用规则**：
- **必须串行调用**，不支持并发（并发会 EOF 失败）
- 每次生成前检查余额：`dreamina user_credit`
- 生成失败自动重试 1 次，仍失败则跳过并记录

**生成命令**：
```bash
dreamina text2image \
  --prompt="[STYLE_PREFIX], [内容描述]" \
  --ratio=3:2 \
  --model_version=5.0 \
  --resolution_type=2k \
  --poll=60
```

**结果提取**：从 JSON 响应的 `result_json.images[0].image_url` 获取图片 URL。

---

### 选项 B：SeedDream API（火山引擎方舟）

```
工具：HTTP API（curl 或 Python SDK）
模型：seedream-5-0-260128（最新）/ doubao-seedream-4-5-251128（稳定）
端点：https://ark.cn-beijing.volces.com/api/v3/images/generations
认证：ARK_API_KEY 环境变量
```

**调用前检查**：
```bash
echo $ARK_API_KEY  # 确认 API Key 已配置
```

**curl 调用**：
```bash
curl -s "https://ark.cn-beijing.volces.com/api/v3/images/generations" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ARK_API_KEY" \
  --max-time 120 \
  -d '{
    "model": "seedream-5-0-260128",
    "prompt": "[STYLE_PREFIX], [内容描述]",
    "size": "2K",
    "response_format": "url",
    "watermark": false
  }'
```

**Python SDK 调用**：
```python
# pip install --upgrade "volcengine-python-sdk[ark]"
from volcenginesdkarkruntime import Ark

client = Ark(
    base_url="https://ark.cn-beijing.volces.com/api/v3",
    [REDACTED_SECRET]"ARK_API_KEY"]
)
response = client.images.generate(
    model="seedream-5-0-260128",
    prompt="[STYLE_PREFIX], [内容描述]",
    size="2K",
    response_format="url"
)
image_url = response.data[0].url
```

**结果提取**：`data[0].url`（链接约 24 小时过期，需及时下载）

**注意事项**：
- 支持 1-4 张图同时生成（`num_images` 参数）
- 可选尺寸：`1K` / `2K` / `4K` 或自定义 WxH（如 `1920x1080`）
- 生成失败不扣费
- 限速约 100 RPM

---

### 选项 C：Nano Banana（Google Gemini 图像生成）

```
工具：Gemini API（curl 或 Python SDK）
模型：gemini-3.1-flash-image-preview（Nano Banana 2，推荐）
      gemini-3-pro-image-preview（Nano Banana Pro，最高质量）
端点：https://generativelanguage.googleapis.com/v1beta/models/{MODEL}:generateContent
认证：GEMINI_API_KEY 环境变量
```

**禁止使用 Nano Banana 1**（`gemini-2.5-flash-image`）。只能用 v2 或 Pro。如果过载，等待或切换即梦/SeedDream，绝不降级到 v1。

**调用前检查**：
```bash
echo $GEMINI_API_KEY  # 确认 API Key 已配置
```

**curl 调用**：
```bash
curl -s "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent?key=$GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  --max-time 120 \
  -d '{
    "contents": [{"parts": [{"text": "Generate an image in 3:2 landscape aspect ratio: [STYLE_PREFIX], [内容描述]"}]}],
    "generationConfig": {
      "responseModalities": ["TEXT", "IMAGE"],
      "imageConfig": {
        "aspectRatio": "3:2",
        "imageSize": "2K"
      }
    }
  }'
```

**Python SDK 调用**：
```python
# pip install google-genai
from google import genai
from google.genai import types
import base64

client = genai.Client([REDACTED_SECRET]"GEMINI_API_KEY"])
response = client.models.generate_content(
    model="gemini-3.1-flash-image-preview",
    contents="Generate an image in 3:2 landscape aspect ratio: [STYLE_PREFIX], [内容描述]",
    config=types.GenerateContentConfig(
        response_modalities=["TEXT", "IMAGE"],
        image_config=types.ImageConfig(aspect_ratio="3:2", image_size="2K"),
    ),
)
# 提取图片
for part in response.candidates[0].content.parts:
    if hasattr(part, "inline_data"):
        with open("output.png", "wb") as f:
            f.write(base64.b64decode(part.inline_data.data))
```

**结果提取**：图片以 base64 内嵌在响应中（`candidates[0].content.parts[].inline_data.data`），需解码保存。

**注意事项**：
- 免费额度：60 RPM，500 张/天
- 可选尺寸：`512` / `1K` / `2K` / `4K`（4K 仅 Nano Banana 2）
- 比例写在 prompt 文本中更可靠（API 参数偶尔不生效）
- 图片保存到 `~/Downloads/NanoBanana生成图片/`（本地 Skill 默认路径）

---

## 通用调用规则

- 单次电子书最多生成 12 张插图
- 生成失败自动重试 1 次，仍失败则跳过并记录
- 不同工具之间可以混用（如即梦生成大部分，SeedDream 补几张高质量的）
- 所有工具生成的图片统一走后续的下载、压缩、嵌入流程

---

## 插图数量规划

| 书的篇幅 | 建议插图数 | 分布策略 |
|---------|----------|---------|
| 8-10 章 | 5-6 张 | 每 2 章之间 1 张 |
| 11-15 章 | 7-9 张 | 关键章节衔接处各 1 张 |
| 16+ 章 | 10-12 张 | 每 1-2 章之间 1 张 |

### 位置选择优先级

1. 章节之间的自然断点（最优）
2. 章节内较长的空白区域
3. 封面（可选）
4. 末尾引导页前（可选）

### 不放插图的位置

- 表格正上方或正下方（视觉冲突）
- 代码块中间
- 提示框紧邻处

---

## 比例选择

| 插图位置 | 推荐比例 | 效果说明 |
|---------|---------|---------|
| 章节间隔（横幅式） | 21:9 | 宽幅条状，像视觉分隔符，不占纵向空间 |
| 章节间隔（标准） | 16:9 | 略高于 21:9，信息量更大 |
| 正文配图 | 3:2 | 经典横向比例，适合叙事性插图 |
| 封面主图 | 1:1 | 居中展示，稳重 |
| 封面主图（竖向） | 3:4 | 适合人物或纵向构图 |
| 末尾引导页 | 1:1 | 配合居中排版 |

**用户指定比例时，以用户为准。**

---

## 风格模板系统

### 模板结构

每张插图的 prompt = `STYLE_PREFIX` + `内容描述` + `补充修饰词`

```
STYLE_PREFIX + ", " + CONTENT + ", " + MODIFIERS
```

### STYLE_PREFIX（风格前缀）

默认风格前缀：

```
Flat vector illustration, soft pastel purple and blue color palette, white background, no text, minimal clean style, friendly and approachable vibe
```

### 主色调方案

根据书的主题自动选择（或由用户指定）：

| 主题类型 | 主色 + 辅色 | 适合场景 |
|---------|-----------|---------|
| 技术/编程 | purple and blue | 代码、开发、AI |
| 设计/创意 | pink and coral | 设计、美学、品牌 |
| 商业/增长 | blue and green | 创业、营销、数据 |
| 教育/学习 | orange and teal | 教程、课程、知识 |
| 健康/生活 | green and warm yellow | 健康、生活方式 |
| 通用 | purple and teal | 不确定时的安全选择 |

### MODIFIERS（补充修饰词库）

按需求选用，不要全部堆叠：

| 感觉 | 关键词 |
|------|--------|
| 亲和力 | kawaii, cute, friendly, warm, cozy |
| 专业感 | geometric, structured, organized, precise |
| 科技感 | digital, futuristic, glowing, tech |
| 简约感 | minimalist, flat, clean, simple, sparse |
| 自然感 | organic, soft, natural, gentle |

### 禁用关键词

以下关键词会导致风格不一致或过于复杂，**不要使用**：

```
photorealistic, gradients, soft shadows, 3D, detailed,
complex, realistic, textured, ornate, busy, cluttered,
heavy, dark, moody, dramatic
```

---

## 风格锚定流程

### Step 1：生成风格前缀

根据书的主题，组装 STYLE_PREFIX：

```python
STYLE_PREFIX = f"Flat vector illustration, soft pastel {主色} and {辅色} color palette, white background, no text, minimal clean style, {亲和力/专业感修饰词}"
```

### Step 2：生成锚定图

用第一张插图的内容 + STYLE_PREFIX 生成锚定图：

```bash
dreamina text2image \
  --prompt="{STYLE_PREFIX}, {第一张图内容描述}" \
  --ratio=3:2 \
  --model_version=5.0 \
  --resolution_type=2k \
  --poll=60
```

### Step 3：用户确认

展示锚定图给用户，确认风格满意后继续。

如果用户要求调整，修改 STYLE_PREFIX 后重新生成锚定图。

常见调整方向：
- "更卡通" → 加 kawaii, cute
- "更专业" → 去掉 kawaii, 加 geometric, structured
- "换配色" → 修改主色辅色
- "更简单" → 加 sparse, minimal, fewer elements
- "更丰富" → 加 detailed scene, multiple elements

### Step 4：批量生成

锚定图确认后，用同一个 STYLE_PREFIX 逐个生成其余插图。

---

## 图片处理

### 下载

```bash
curl -sL --max-time 30 --retry 3 \
  -o "/tmp/ebook-imgs/img${i}.png" "${image_url}"
```

注意：字节跳动 CDN 偶发 SSL 错误（LibreSSL 兼容问题）。
失败 3 次后跳过，不阻塞流程。

### 压缩

```bash
sips --resampleWidth ${WIDTH} "input.png" \
  --out "output.jpg" \
  -s format jpeg \
  -s formatOptions ${QUALITY}
```

| 比例 | 缩小宽度 | JPEG 质量 | 目标大小 |
|------|---------|----------|---------|
| 21:9 / 16:9 | 800px | 80 | ≤ 60KB |
| 3:2 / 4:3 | 800px | 80 | ≤ 80KB |
| 1:1 | 600px | 80 | ≤ 50KB |
| 3:4 / 9:16 | 500px | 80 | ≤ 60KB |

### 文件组织

```
插图文件放在 HTML 同目录，用相对路径引用。
命名：img1.jpg, img2.jpg, ...（按插入顺序编号）
```

---

## 嵌入规则

### HTML 标签

```html
<!-- 标准配图 -->
<img class="ebook-img" src="img1.jpg" alt="描述文字">

<!-- 横幅图 -->
<img class="ebook-img banner" src="img2.jpg" alt="描述文字">
```

### 插入位置

插在章节 `</div>` 闭合标签之后、下一个 `<div class="chapter">` 之前：

```html
</div>  <!-- 上一章结束 -->

<img class="ebook-img" src="img3.jpg" alt="描述">

<!-- ========== 下一章 ========== -->
<div class="chapter">
```

### alt 文字

每张图都要有简短的 alt 描述，用于：
- 无障碍（屏幕阅读器）
- 图片加载失败时的回退文字
- 格式：动词 + 名词，如"人与 AI 协作编程"、"火箭发射代表部署上线"

---

## 记录模板

每次生成插图后，在工作报告中记录：

```markdown
| # | submit_id | prompt 摘要 | 比例 | 状态 | 用于位置 |
|---|-----------|-----------|------|------|---------|
| 1 | xxxx | 人与AI协作 | 3:2 | 成功 ✅ | Ch01→Ch02 |
| 2 | xxxx | 积木搭建 | 21:9 | 成功 ✅ | Ch03→Ch04 |
| 3 | xxxx | 数据传递 | 3:2 | 下载失败 ❌ | 跳过 |
```


path: layout.md
content: # 排版规范

本文件定义电子书的排版参数。修改此文件即可全局调整排版风格，无需改动主 Skill。

---

## 页面尺寸

```
纸张：A4
页边距：上 2.2cm / 下 2.2cm / 左 2cm / 右 2cm
```

## 内容区域

```
正文最大宽度：680px
正文内边距：0 2rem
```

## 页眉页脚

```
页眉：无
页脚：显示页码（默认开启）
```

如果需要关闭页码，注释掉以下 CSS 中的 `@bottom-center` 行。

如果需要额外的页脚文字（如书名/公众号），使用字符串拼接：
```css
@bottom-center { content: "书名 | 公众号 @xxx | 第 " counter(page) " 页"; }
```

---

## 字体

| 用途 | 字体 | 粗细 |
|------|------|------|
| 正文 | Noto Sans SC | 400 |
| 加粗 | Noto Sans SC | 700 |
| 标题（封面、章节） | Noto Serif SC | 900 |
| 代码 | JetBrains Mono | 400 |

字体加载源：
```
https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700;900&family=Noto+Serif+SC:wght@600;700;900&family=JetBrains+Mono:wght@400;500&display=swap
```

如果需要离线字体，替换为本地 @font-face 声明。

## 字号

| 元素 | 屏幕字号 | 打印字号 |
|------|---------|---------|
| 正文 | 15px | 11pt |
| 章节标题 | 1.9rem | — |
| 封面主标题 | 2.4-2.8rem | — |
| 术语名称 | 1.25rem | — |
| 英文副标题 | 0.88rem | — |
| 提示框 | 0.92rem | — |
| 表格 | 0.88-0.9rem | — |
| 代码块 | 0.85rem | — |

## 行高

```
正文行高：1.85
提示框行高：1.85
代码块行高：1.7
```

---

## 配色

```css
--purple: #5B4FBF;       /* 主色：章节标签、术语标题、表头背景 */
--purple-light: #7C71D8;  /* 辅色：提示框左边框 */
--orange: #D35400;        /* 强调色：代码文字、命令、操作提示 */
--text: #2D2D2D;          /* 正文文字 */
--gray: #888;             /* 次要文字：英文名、日期、副标题 */
--tip-bg: #F3F1FB;        /* 提示框背景 */
--tip-border: #DCD8F0;    /* 提示框边框（备用） */
```

如需更换主题色，只改这里的 hex 值即可。其他元素全部通过 var() 引用。

### 配色快捷方案

| 风格 | --purple | --purple-light | --orange | --tip-bg |
|------|----------|---------------|----------|----------|
| 默认紫 | #5B4FBF | #7C71D8 | #D35400 | #F3F1FB |
| 蓝色调 | #2563EB | #60A5FA | #EA580C | #EFF6FF |
| 绿色调 | #059669 | #34D399 | #D97706 | #ECFDF5 |
| 红棕调 | #B91C1C | #F87171 | #92400E | #FEF2F2 |
| 中性灰 | #374151 | #6B7280 | #B45309 | #F3F4F6 |

---

## 元素对齐规范

### 铁律：所有内容元素左右对齐

```css
/* 图片 */
.ebook-img {
  width: 100%;
  max-width: 600px;   /* 不超过正文宽度 */
  display: block;
  margin: 2rem auto;
  border-radius: 10px;
}

/* 横幅图（21:9 / 16:9）可以更宽 */
.ebook-img.banner {
  max-width: 100%;
  border-radius: 8px;
}

/* 表格 */
table {
  width: 100%;
  border-collapse: collapse;
}

/* 代码块 */
pre.codeblock {
  width: 100%;
  overflow-x: auto;        /* 屏幕端：长代码可横向滚动 */
  white-space: pre-wrap;   /* 打印/PDF 端：自动换行 */
  word-break: break-all;   /* 超长单词/URL 强制换行 */
}

/* 提示框 */
.tip {
  width: auto;       /* 跟随父容器宽度 */
}
```

### 对齐自检清单

生成 HTML 后，自查以下项目：
- [ ] 所有 `<img>` 都有 `class="ebook-img"` 且居中
- [ ] 所有 `<table>` 都有 `width: 100%`
- [ ] 所有 `<pre>` 都有 `overflow-x: auto` 和 `white-space: pre-wrap; word-break: break-all;`
- [ ] 没有元素的实际渲染宽度超出 `.content` 的 680px
- [ ] 图片、表格、代码块的左右边距视觉一致
- [ ] 提示框没有比正文更窄或更宽

---

## 分页规则

```css
/* 封面独占一页 */
.cover { page-break-after: always; }

/* 目录独占一页 */
.toc { page-break-after: always; }

/* 每章从新页开始 */
.chapter { page-break-before: always; }

/* 术语卡片不拆页 */
.term { page-break-inside: avoid; }

/* 末尾引导页从新页开始 */
.ending { page-break-before: always; }
```

---

## 间距体系

| 元素 | margin-bottom |
|------|-------------|
| 章节引言 (ch-intro) | 2rem |
| 术语块 (term) | 2.5rem |
| 术语分割线 (term-sep) | — (margin-top: 0.5rem) |
| 提示框 (tip) | 0.8rem top / 0.5rem bottom |
| 代码块 (codeblock) | 0.8rem top+bottom |
| 表格 | 1rem top+bottom |
| 图片 | 2rem top+bottom |

---

## 打印适配

```css
@page {
  size: A4;
  margin: 2.2cm 2cm 2.8cm 2cm;  /* 下方多留空间放页码 */
}
```

**页码实现方式**：

Chrome headless 的 `@page` CSS 计数器支持有限。页码通过以下两种方案实现：

**方案 A（推荐）：不加 `--print-to-pdf-no-header`，用 Chrome 默认页脚**

Chrome 默认页脚会显示页码。只需在 PDF 命令中**去掉** `--print-to-pdf-no-header` 和 `--no-pdf-header-footer`，Chrome 会自动在底部居中显示页码。默认格式：`1 / N`。

缺点：同时会显示日期和文件路径在页眉。

**方案 B（精确控制）：HTML 内嵌页码 + JavaScript**

在 HTML 底部加入 JavaScript 计数页码，配合 CSS fixed 定位：

```css
.page-number {
  position: fixed;
  bottom: 0.5cm;
  width: 100%;
  text-align: center;
  font-size: 0.75rem;
  color: #bbb;
}
```

由于 Chrome headless 对 CSS `counter(page)` 支持不完善，实际生产中建议 **方案 A**（接受默认页眉页脚），或在 HTML 末尾手动标注章节页码范围。

**如果用户不要页眉只要页码**：用 `--print-to-pdf-no-header` 去掉所有，然后在 HTML 里用 `position: fixed` 模拟页码（但此方案在长文档中页码不会自动递增，仅适合短文档）。

```css

@media print {
  body { font-size: 11pt; }
  .content { max-width: 100%; padding: 0; }

  /* 保留背景色 */
  .tip, th, pre.codeblock {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}
```

## PDF 生成命令

**带页码版（默认）**：
```bash
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
  --headless=new \
  --disable-gpu \
  --no-sandbox \
  --print-to-pdf="输出路径.pdf" \
  "file:///HTML文件路径.html"
```
Chrome 默认页脚会显示居中页码（格式 `1/N`）。页眉会显示标题和日期。

**无页眉页脚版**：
```bash
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
  --headless=new \
  --disable-gpu \
  --no-sandbox \
  --print-to-pdf="输出路径.pdf" \
  --print-to-pdf-no-header \
  --no-pdf-header-footer \
  "file:///HTML文件路径.html"
```

**默认使用带页码版**，除非用户明确要求不要页码。


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)