| name | pptx-generator |
| description | 生成、编辑、读取 PowerPoint 演示文稿。支持用 PptxGenJS 从零创建(封面、目录、内容页、章节分隔页、总结页),通过 XML 工作流编辑已有 PPTX,或使用 markitdown 提取文本。触发器:PPT, PPTX, PowerPoint, 演示文稿, 幻灯片, 幻灯片组。 |
| license | MIT |
| agent_created | true |
| metadata | {"version":"1.2","category":"productivity","source":"MiniMax-AI/skills 仓库(经授权安装),实战反馈修正 v1.2","sources":["https://gitbrent.github.io/PptxGenJS/","https://github.com/microsoft/markitdown"]} |
PPTX Generator & Editor
Overview
本 Skill 处理所有 PowerPoint 任务:读取/分析已有演示文稿、通过 XML 操作编辑基于模板的演示文稿,以及使用 PptxGenJS 从零创建演示文稿。内置完整的设计系统(调色板、字体、风格配方)和每种幻灯片类型的详细指南。
Quick Reference
| 项目 | 值 |
|---|
| 画布尺寸 | 10" x 5.625" (LAYOUT_16x9) |
| 颜色格式 | 6 位十六进制,不带 #(例如 "FF0000") |
| 英文字体 | 微软雅黑(中文PPT建议全篇统一) |
| 中文字体 | 微软雅黑 |
| 页码徽章位置 | x: 9.3", y: 5.1" |
| 基础主题键 | primary, secondary, accent, light, bg |
| 可选扩展键 | gold, coral, violet(根据需要添加) |
| 形状 | RECTANGLE, OVAL, LINE, ROUNDED_RECTANGLE |
| 图表 | BAR, LINE, PIE, DOUGHNUT, SCATTER, BUBBLE, RADAR |
参考文件
读取内容
python -m markitdown presentation.pptx
从零创建 — 工作流
当没有模板或参考演示文稿时使用。
第 1 步:调研需求
搜索以理解用户需求 — 主题、受众、目的、语气、内容深度。
第 2 步:选择调色板与字体
使用 调色板参考 选择与主题和受众匹配的调色板。使用 字体参考 选择字体配对。
第 3 步:选择设计风格
使用 风格配方 选择与演示文稿基调相匹配的视觉风格(Sharp, Soft, Rounded 或 Pill)。
第 4 步:规划幻灯片大纲
将每一张幻灯片精确分类为 5 种页面类型 之一。规划每张幻灯片的内容和布局。确保视觉多样性 — 不要在不同幻灯片上重复相同布局。
第 5 步:生成幻灯片 JS 文件
在 slides/ 目录下为每张幻灯片创建一个 JS 文件。每个文件必须导出一个同步的 createSlide(pres, theme) 函数。遵循 幻灯片输出格式 和 slide-types.md 中的类型特定指南。如果有 subagent,最多同时生成 5 张幻灯片。
告诉每个 subagent:
- 文件命名:
slides/slide-01.js, slides/slide-02.js 等
- 图片存放:
slides/imgs/
- 最终 PPTX 存放:
slides/output/
- 尺寸:10" x 5.625" (LAYOUT_16x9)
- 字体:全部统一使用 微软雅黑(包括英文、数字、中文混排场景)
- 颜色:6 位十六进制,不带 #(例如
"FF0000")
- 必须使用 theme 对象契约(见 Theme 对象契约)
- 必须遵循 PptxGenJS API 参考
- 中文文本字符串使用单引号包裹,避免双引号嵌套问题
- 严格遵循布局间距规则(见下方 布局防重叠规则),每个 slide 生成后必须做 Y 轴重叠检查
大规模 PPTX(30+ 张幻灯片)并行生成策略:
- 启动 8-9 个 subagent 并行生成,每个负责 ~5 张幻灯片
- 均分场景覆盖:封面/分隔页分配给专门的 agent,内容页按顺序均分
- 每个 subagent 必须遵循相同的 theme 契约和 slide 模板
- 最后 compile.js 合并所有 slide 模块
布局防重叠规则(强制)
内容页垂直布局每层元素的底部必须严格小于下一层元素的顶部。 常见重叠场景和标准解法如下:
顶部区域(y: 0 ~ 1.8)三层结构
┌─ 行 1: 章节标签 ─┬── y_min=0.30, h_max=0.25, 底部≤0.55
├─ 行 2: 页面标题 ─┬── y_min=0.75, h_max=0.50, fontSize_max=26
├─ 行 3: 副标题 ───┬── y_min=1.40, h_max=0.30, fontSize_max=14
└─── 之后的内容 ───┬── y≥1.85
| 元素 | 最小 y | 最大 h | 最大字号 | 说明 |
|---|
| 章节标签 | 0.30" | 0.25" | 13pt | 紧凑显示 |
| 页面标题 | 0.75" | 0.50" | 26pt | 长标题会换行,用小字号保证一行显示 |
| 副标题 | 1.40" | 0.30" | 14pt | 灰色/辅助色 |
相邻元素垂直间距规则
| 场景 | 最小间距 | 说明 |
|---|
| 标题底部 → 副标题顶部 | ≥ 0.15" | 防止文字串行重叠 |
| 副标题底部 → 卡片/形状顶部 | ≥ 0.15" | 副标题与内容块之间 |
| 卡片底部 → 反馈循环文本 | ≥ 0.15" | 流程图中箭头文本 |
| 内容底部 → 总结面板顶部 | ≥ 0.10" | 底部总结框 |
| 总结面板底部 → 页码徽章 | ≥ 0.05" | 最后一行的间距 |
容器内元素不越界规则
卡片/组内的子元素必须完全在容器边界内。 这是编写自定义函数时最容易出错的地方。
例如: 靶心图(2×2网格)
┌─────────────────────┐
│ 卡片框 (cx±1.05, cy±0.8) │
│ ├── 靶心环 (cx±0.32) │ ← ✅ 在卡片内
│ └── 弹孔 (cx+dx, cy+dy) │ ← ⚠️ dx,dy 必须在 ±0.77 内
│ 标注 (cy+0.4~0.8) │ ← ✅ 在卡片内
└─────────────────────┘
容器内元素边界检查清单:
水平边界规则
幻灯片画布为 10" × 5.625",所有元素必须在画布范围内:
| 规则 | 条件 | 后果 |
|---|
| 左边界 | 任何元素的 x ≥ 0 | x 为负则内容被裁剪 |
| 右边界 | 任何元素的 x + w ≤ 10 | 超右则内容被裁剪 |
| 上边界 | y ≥ 0 | 同上 |
| 下边界 | y + h ≤ 5.625 | 超下则内容被裁剪 |
| 安全边距 | 建议 x ≥ 0.4, x + w ≤ 9.6 | 打印/投影仪可能裁边 |
常见越界场景:
- 时间线/卡片布局:最后一个节点的卡片右边缘超过 10"
const totalW = 7.5;
const startX = 1.0;
- 文本框内容太长:建议使用
fit: "shrink" 自动缩小文本
slide.addText("长标题文字", { x: 0.5, y: 2, w: 9, h: 0.6, fontSize: 24, fit: "shrink" });
重叠快速自查清单
生成每张 slide 后,逐项检查:
关于 fontSize 的硬性上限
| 元素 | 上限 | 原因 |
|---|
| 内容页标题 | 26pt | 长中文标题(15-20字)在 9" 宽空间内一行显示 |
| 章节分隔页标题 | 32pt | 标题较短,可以稍大 |
| 封面主标题 | 48-54pt | 封面空间大 |
| 副标题/描述 | 14pt | 辅助文本,不需要大字号 |
| 卡片内标题 | 16-18pt | 卡片空间有限 |
| 卡片内正文 | 10-12pt | 紧凑信息展示 |
| 表格/代码内容 | 9-11pt | 密集数据场景 |
上下文感知布局规则(v1.2 新增)
以下规则无法通过纯坐标检查发现,需要结合文本内容和容器边界做语义判断:
Rule A: 标签行文换行检测 + 页码基线对齐
问题: 标签文本(如 PART 01、STEP N 等)因容器宽度不足导致自动折行,或页码徽章与相邻底部面板的文字基线不齐。
标准解法:
❌ 错误:w=0.55 的标签框放 "PART 01"(7字符 @ 10pt)→ 可能折行为 "PAR" / "T 01"
✅ 正确:w≥0.65 或 fontSize≤9pt,确保标签文字单行完整显示
| 场景 | 最小宽度 | 最大字号 | 说明 |
|---|
| "PART 01" 类 | 0.65" | 9pt | 7字符标签,窄框易折行 |
| "STEP 1" 类 | 0.55" | 10pt | 6字符以内 |
| 3字符标签 | 0.40" | 11pt | 如 "01"、"A" 等 |
页码徽章基线对齐检查:
- 页码徽章的垂直中心线应与相邻底部面板的文字基线对齐
- 底部面板
y + h/2 ≈ 页码徽章 y + h/2(差值 ≤ 0.05")
- 徽章不应与面板重叠:面板右边缘 x+w ≤ 徽章 x(或徽章 x 在面板右侧)
Rule B: 时间线上方元素重叠检测
问题: 时间线布局中,年份/标签文字(位于时间线上方)与标题区或副标题区域重叠。
标准解法:
时间线 Y 轴布局模板:
┌─ 标题 ─────────────┬── y=0.60~0.70, 底部≤1.05
├─ 副标题 ───────────┬── y=1.00~1.10, 底部≤1.30
├─ 年份标签 ─────────┬── y≥1.20 (副标题底部), h=0.30
├─ 时间线 ───────────┬── y≥1.65, 圆圈中心在时间线上
├─ 卡片/节点 ────────┬── y=时间线底部+0.3~0.4
└─ 底部面板 ─────────┬── y≥4.0
检查清单:
Rule C: 卡片头部边界检测 + 行内文字重叠
问题:
- 引用文本/副标题与大标题位于同一行(同一 y 坐标),视觉上相互重叠
- 卡片头部标题文字(中文 + 英文混排)溢出卡片头部的彩色背景区域
标准解法:
// ❌ 错误:引用文本与大标题同一行
slide.addText("大标题", { x: 0.65, y: 0.52, w: 6, h: 0.35, fontSize: 22 });
slide.addText("· 引用文本", { x: 3.4, y: 0.52, w: 5, h: 0.35, fontSize: 14 }); // ← 重叠!
// ✅ 正确:引用文本放在单独一行
slide.addText("大标题", { x: 0.65, y: 0.52, w: 6, h: 0.35, fontSize: 22 });
slide.addText("· 引用文本", { x: 0.65, y: 0.95, w: 6, h: 0.3, fontSize: 14 }); // ← 新行
卡片头部溢出检测:
- 卡片头部标题文本框的右边缘(x + w)不得超出卡片头部的彩色背景区域
- 中文 + 英文混排时,英文部分会使文本总宽度超出预期 → 使用
fit: "shrink" 或减小字号
- 头部文本字号建议:中英文混排 ≤ 11pt,纯中文 ≤ 12pt
Rule D: 底部边缘碰撞检测 + 垂直间距均匀分布
问题: 容器(卡片、面板)内的最后一行文字几乎接触到容器底部边界;中间区域的元素间距过于拥挤。
标准解法:
容器内文字垂直分布:
┌─────────────────────┐
│ 标题 (y+0.08~0.15) │ ← 顶部留空
│ 主文字 (y+0.35~0.45) │ ← 间距 0.20~0.30"
│ 描述 (y+0.70~0.80) │ ← 间距 0.25~0.35"
│ ░░░ 底部安全边距 ░░░ │ ← 至少 0.10" 留白
└─────────────────────┘
卡片内垂直间距规则:
| 区域 | 距卡片顶部 | 间距 | 说明 |
|---|
| 头部标签 | 0.08~0.15" | — | 卡片内部标题 |
| 主文字 | 0.35~0.45" | 0.20~0.30" | 大号强调文字 |
| 描述文字 | 0.70~0.80" | 0.25~0.35" | 更靠近底部 |
| 底部安全边距 | — | ≥ 0.10" | 文字底部到卡片底部 |
中间区域拥挤检测:
- 当一页有多个并行元素(如 3 张卡片)时,确保元素间的垂直间距 ≥ 0.15"
- 元素内部文字不超出底部边界(最后一行文字底部 ≤ 元素底部 - 0.10")
- 卡片内最后一行文字的 fontSize 适配:长文本使用 11pt,确保在有限宽度内不换行
Rule E: 列表/概念图方框文字适配
问题: 列表项(bullet items)或概念图方框内的多行文字总高度超出文本框高度,导致文字被裁剪。
标准解法:
// 计算所需高度
const lineCount = items.length;
const lineHeight = fontSize * lineSpacingMultiple / 72; // pt → inches
const requiredH = lineCount * lineHeight + 0.10; // + 底部边距
// 检查:textBox.h ≥ requiredH
if (textBox.h < requiredH) {
// 修复选项:
// 1. 增加卡片高度
// 2. 减小 fontSize
// 3. 减小 lineSpacingMultiple
}
列表项高度速查表:
| 条目数 | 字号 | 行间距倍率 | 所需高度 | 建议框高 |
|---|
| 5 项 | 12pt | 1.6 | 1.33" | ≥ 1.45" |
| 5 项 | 11pt | 1.5 | 1.15" | ≥ 1.30" |
| 4 项 | 12pt | 1.6 | 1.07" | ≥ 1.20" |
| 3 项 | 12pt | 1.6 | 0.80" | ≥ 0.95" |
| 3 项 | 11pt | 1.5 | 0.69" | ≥ 0.85" |
验证方法:
- 使用 PptxGenJS 的
fit: "shrink" 作为保险(但不要依赖它作为唯一手段)
- 生成后通过 python-pptx 解析每张 slide 的文本框高度和内容行数做验证
- 如果页面布局复杂(顶部卡片 + 中部概念图 + 底部面板),确保所有元素之间有合理的垂直间隙
第 6 步:编译为最终 PPTX
创建 slides/compile.js 来合并所有幻灯片模块:
const pptxgen = require('pptxgenjs');
const pres = new pptxgen();
pres.layout = 'LAYOUT_16x9';
const theme = {
primary: "003D24",
secondary: "6B4FCF",
accent: "006A3F",
light: "A8D5BA",
bg: "FFFFFF",
gold: "C49A2A",
coral: "C2411F"
};
for (let i = 1; i <= 43; i++) {
const num = String(i).padStart(2, '0');
const slideModule = require(`./slide-${num}.js`);
slideModule.createSlide(pres, theme);
}
pres.writeFile({ fileName: './output/presentation.pptx' });
运行:cd slides && NODE_OPTIONS= node compile.js
(注意:如果遇到 --use-system-ca is not allowed in NODE_OPTIONS 错误,需要清空该环境变量)
第 7 步:QA(必需)
参见 QA 流程。
输出结构
slides/
├── slide-01.js # 幻灯片模块
├── slide-02.js
├── ...
├── imgs/ # 幻灯片中使用的图片
└── output/ # 最终产物
└── presentation.pptx
幻灯片输出格式
每张幻灯片是一个完整的、可运行的 JS 文件:
const pptxgen = require("pptxgenjs");
const slideConfig = {
type: 'cover',
index: 1,
title: '演示文稿标题'
};
function createSlide(pres, theme) {
const slide = pres.addSlide();
slide.background = { color: theme.bg };
slide.addText(slideConfig.title, {
x: 0.5, y: 2, w: 9, h: 1.2,
fontSize: 48, fontFace: "微软雅黑",
color: theme.primary, bold: true, align: "center"
});
return slide;
}
if (require.main === module) {
const pres = new pptxgen();
pres.layout = 'LAYOUT_16x9';
const theme = {
primary: "22223b",
secondary: "4a4e69",
accent: "9a8c98",
light: "c9ada7",
bg: "f2e9e4"
};
createSlide(pres, theme);
pres.writeFile({ fileName: "slide-01-preview.pptx" });
}
module.exports = { createSlide, slideConfig };
Theme 对象契约(强制)
编译脚本传递一个 theme 对象。以下 5 个键是必须的,可以根据需要增加额外的键(如 gold, coral, violet 等):
| 键 | 用途 | 示例 |
|---|
theme.primary | 最深色,用于深色背景/标题 | "003D24" |
theme.secondary | 次要强调色 | "6B4FCF" |
theme.accent | 主强调色(装饰条/标识/高亮) | "006A3F" |
theme.light | 浅色强调(辅助文字/浅填色) | "A8D5BA" |
theme.bg | 背景色(学术PPT建议白色) | "FFFFFF" |
必须包含以上 5 键,但可以扩展。例如可以添加 gold, coral, violet 等键用于特殊场景。
⚠️ PptxGenJS v3.x 关键陷阱(必读)
以下的踩坑经验来自于实战,严重程度较高,请在生成幻灯片时严格遵守:
1. 使用 pres.shapes.* 而非 pres.ShapeType.*
PptxGenJS v3.x 不支持 pres.ShapeType.RECTANGLE,必须使用 pres.shapes.RECTANGLE:
slide.addShape(pres.shapes.RECTANGLE, { ... });
slide.addShape(pres.shapes.OVAL, { ... });
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { ... });
slide.addShape(pres.ShapeType.RECTANGLE, { ... });
2. slide.background 使用 { color: ... } 而非 { fill: ... }
slide.background = { color: "FFFFFF" };
slide.background = { color: theme.primary };
slide.background = { fill: "FFFFFF" };
slide.background = { fill: { color: "FFFFFF" } };
3. 项目符号用 bullet: true,不要用 bullet: { code: "•" }
{ text: "第一项", options: { bullet: true, breakLine: true } }
{ text: "第一项", options: { bullet: { code: "•" } } }
4. 中文文本使用单引号包裹
如果中文文本中包含双引号(如"关键"、"注意"等),用双引号包裹会产生 SyntaxError:
slide.addText('模型判断"我对哪些样本最不确定"', { ... });
slide.addText("模型判断"我对哪些样本最不确定"", { ... });
5. 运行 node compile.js 时清空 NODE_OPTIONS
cd slides && NODE_OPTIONS= node compile.js
页码徽章(必需)
除封面页外的所有幻灯片必须在右下角包含页码徽章。
- 位置:x: 9.3", y: 5.1"
- 只显示当前页码(如
3 或 03),不要显示 "3/12"
- 使用调色板颜色,保持微妙
圆形徽章(默认)
slide.addShape(pres.shapes.OVAL, {
x: 9.3, y: 5.1, w: 0.4, h: 0.4,
fill: { color: theme.accent }
});
slide.addText("3", {
x: 9.3, y: 5.1, w: 0.4, h: 0.4,
fontSize: 12, fontFace: "微软雅黑",
color: "FFFFFF", bold: true,
align: "center", valign: "middle"
});
胶囊形徽章
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, {
x: 9.1, y: 5.15, w: 0.6, h: 0.35,
fill: { color: theme.accent },
rectRadius: 0.15
});
slide.addText("03", {
x: 9.1, y: 5.15, w: 0.6, h: 0.35,
fontSize: 11, fontFace: "微软雅黑",
color: "FFFFFF", bold: true,
align: "center", valign: "middle"
});
依赖项
pip install "markitdown[pptx]" — 文本提取
npm install -g pptxgenjs — 从零创建
npm install -g react-icons react react-dom sharp — 图标(可选)