npx skills add https://github.com/huyansheng3/ppt-skills --skill single-slide-ppt使用 PptxGenJS 创建专业、视觉吸引人的单页 PowerPoint 演示文稿。
分析用户的请求以确定:
选择与内容结构匹配的布局:
对比布局(2 列):
网格布局(2x2、2x3、3x3):
顺序流:
单一焦点:
根据内容主题选择 3-5 种颜色:
基于内容的调色板:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
颜色分配:
当创建关于技术概念、产品或比较的幻灯片时,考虑添加相关图像以强化信息。
何时使用图像:
如何查找和下载图像:
// 示例:下载 VSCode 架构图
// 使用 curl 从官方来源下载图像
const { execSync } = require('child_process');
function downloadImage(url, outputPath) {
try {
execSync(`curl -o ${outputPath} "${url}"`, { stdio: 'inherit' });
console.log(`Downloaded: ${outputPath}`);
return true;
} catch (error) {
console.error(`Failed to download image: ${error.message}`);
return false;
}
}
// 示例用法:
downloadImage(
'https://code.visualstudio.com/assets/api/ux-guidelines/examples/architecture-containers.png',
'workspace/vscode-architecture.png'
);
查找图像的策略:
将图像添加到幻灯片:
// 下载图像后,将其添加到幻灯片
slide.addImage({
path: 'workspace/downloaded-image.png',
x: 0.5, // X 位置(英寸)
y: 1.5, // Y 位置(英寸)
w: 4.8, // 宽度(英寸)
h: 2.7 // 高度(英寸)(保持宽高比)
});
// 可选:添加标题
slide.addText('Image caption or source attribution', {
x: 0.5, y: 4.25, w: 4.8, h: 0.3,
fontSize: 9, color: '707070', italic: true,
align: 'center'
});
图像最佳实践:
const pptxgen = require('pptxgenjs');
const { execSync } = require('child_process');
const path = require('path');
async function createSlide() {
const pptx = new pptxgen();
pptx.layout = 'LAYOUT_16x9';
pptx.author = 'Your Name';
pptx.title = 'Slide Title';
const slide = pptx.addSlide();
// 背景
slide.background = { color: '1a1a2e' };
// 标题栏
slide.addShape(pptx.shapes.RECTANGLE, {
x: 0, y: 0, w: 10, h: 0.8,
fill: { color: '4a00e0' }
});
// 标题
slide.addText('Your Title Here', {
x: 0.5, y: 0.18, w: 9, h: 0.5,
fontSize: 26, bold: true, color: 'ffffff',
fontFace: 'Arial'
});
// 可选:添加下载的图像
// slide.addImage({
// path: 'workspace/image.png',
// x: 0.5, y: 1.5, w: 4.8, h: 2.7
// });
// 内容部分...
// [在此处添加您的内容,遵循以下模式]
await pptx.writeFile({ fileName: 'output.pptx' });
}
createSlide().catch(console.error);
// 左侧部分 - 问题/之前
slide.addText('🚫 Current State', {
x: 0.4, y: 1.0, w: 4, h: 0.4,
fontSize: 14, bold: true, color: 'ff6b6b'
});
// 带左侧边框强调的卡片
slide.addShape(pptx.shapes.RECTANGLE, {
x: 0.4, y: 1.5, w: 4.2, h: 0.95,
fill: { color: '2d1f1f' }
});
slide.addShape(pptx.shapes.RECTANGLE, {
x: 0.4, y: 1.5, w: 0.08, h: 0.95,
fill: { color: 'ff6b6b' }
});
slide.addText('Issue Title', {
x: 0.6, y: 1.55, w: 3.8, h: 0.3,
fontSize: 12, bold: true, color: 'ff6b6b'
});
slide.addText('Detailed description...', {
x: 0.6, y: 1.85, w: 3.8, h: 0.5,
fontSize: 9, color: 'a0a0a0', wrap: true
});
// 右侧部分 - 解决方案/之后(镜像结构,使用绿色)
slide.addText('✅ New State', {
x: 5.3, y: 1.0, w: 4, h: 0.4,
fontSize: 14, bold: true, color: '51cf66'
});
// [使用绿色配色方案添加卡片]
const features = [
{ icon: '🔧', text: 'Feature 1' },
{ icon: '⚡', text: 'Feature 2' },
{ icon: '💻', text: 'Feature 3' },
{ icon: '📝', text: 'Feature 4' },
{ icon: '👻', text: 'Feature 5' },
{ icon: '🎨', text: 'Feature 6' }
];
const startX = 1.0;
const startY = 1.5;
const itemW = 2.6;
const itemH = 0.7;
const gapX = 0.15;
const gapY = 0.12;
features.forEach((feat, idx) => {
const col = idx % 3;
const row = Math.floor(idx / 3);
const x = startX + col * (itemW + gapX);
const y = startY + row * (itemH + gapY);
slide.addShape(pptx.shapes.ROUNDED_RECTANGLE, {
x, y, w: itemW, h: itemH,
fill: { color: '1a2a1a' },
line: { color: '51cf66', width: 0.5 },
rectRadius: 0.08
});
slide.addText(feat.icon + ' ' + feat.text, {
x: x + 0.1, y: y + 0.15, w: itemW - 0.2, h: itemH - 0.3,
fontSize: 11, color: 'e0e0e0', valign: 'middle'
});
});
// 之前框(虚线边框)
slide.addShape(pptx.shapes.RECTANGLE, {
x: 1.5, y: 3.0, w: 2.5, h: 1.5,
fill: { color: '2a1a1a' },
line: { color: 'ff6b6b', width: 1, dashType: 'dash' }
});
slide.addText('Before', {
x: 1.5, y: 3.1, w: 2.5, h: 0.3,
fontSize: 12, bold: true, color: 'ff6b6b', align: 'center'
});
slide.addText('🧩', {
x: 1.5, y: 3.5, w: 2.5, h: 0.5,
fontSize: 32, align: 'center'
});
slide.addText('Old approach', {
x: 1.5, y: 4.0, w: 2.5, h: 0.3,
fontSize: 9, color: '888888', align: 'center'
});
// 之后框(实线边框)
slide.addShape(pptx.shapes.RECTANGLE, {
x: 6.0, y: 3.0, w: 2.5, h: 1.5,
fill: { color: '1a2a1a' },
line: { color: '51cf66', width: 2 }
});
slide.addText('After', {
x: 6.0, y: 3.1, w: 2.5, h: 0.3,
fontSize: 12, bold: true, color: '51cf66', align: 'center'
});
slide.addText('👑', {
x: 6.0, y: 3.5, w: 2.5, h: 0.5,
fontSize: 32, align: 'center'
});
slide.addText('New approach', {
x: 6.0, y: 4.0, w: 2.5, h: 0.3,
fontSize: 9, color: '888888', align: 'center'
});
// 各部分之间的箭头
slide.addText('➔', {
x: 4.5, y: 2.5, w: 0.8, h: 0.6,
fontSize: 36, color: '8e2de2',
align: 'center', valign: 'middle'
});
rgba(R,G,B,0.1) 变为 RRGGBB + 较浅填充示例:VSCode 扩展限制幻灯片
const pptxgen = require('pptxgenjs');
const { execSync } = require('child_process');
const path = require('path');
async function createTechnicalSlide() {
const pptx = new pptxgen();
pptx.layout = 'LAYOUT_16x9';
// 下载 VSCode 架构图像
const imageUrl = 'https://code.visualstudio.com/assets/api/ux-guidelines/examples/architecture-containers.png';
const imagePath = 'workspace/vscode-architecture.png';
try {
execSync(`curl -o ${imagePath} "${imageUrl}"`, { stdio: 'inherit' });
} catch (error) {
console.log('Image download failed, continuing without image');
}
const slide = pptx.addSlide();
slide.background = { color: 'FFFFFF' };
// 标题
slide.addShape(pptx.shapes.RECTANGLE, {
x: 0, y: 0, w: 10, h: 0.8,
fill: { color: 'fc5a1f' }
});
slide.addText('VSCode 插件架构限制', {
x: 0.5, y: 0.18, w: 9, h: 0.45,
fontSize: 26, bold: true, color: 'ffffff',
fontFace: 'Arial'
});
// 左侧:架构图像
slide.addImage({
path: imagePath,
x: 0.5, y: 1.2, w: 4.8, h: 2.7
});
slide.addText('VSCode 只对插件开放固定的"插槽"(Containers)', {
x: 0.5, y: 4.0, w: 4.8, h: 0.3,
fontSize: 10, color: '707070', italic: true,
align: 'center'
});
// 右侧:限制卡片
slide.addText('API 限制', {
x: 5.5, y: 1.2, w: 4.2, h: 0.4,
fontSize: 18, bold: true, color: 'fc5a1f'
});
// 添加限制卡片...
await pptx.writeFile({ fileName: 'technical-slide.pptx' });
}
createTechnicalSlide().catch(console.error);
将文件保存在专用工作区中:
mkdir -p workspace
cd workspace
node generate-slide.js
生成预览:
python3 /path/to/pptx/scripts/thumbnail.py output.pptx preview --cols 1
技术原因:
pptx-automizer 编辑现有文件pptx-automizer 是一个专门设计用于编辑和合并现有 .pptx 文件的强大 Node.js 库。
npm install pptx-automizer
# 或
yarn add pptx-automizer
| 功能 | 描述 |
|---|---|
| 加载模板 | 导入现有的 .pptx 文件作为模板 |
| 合并幻灯片 | 从多个模板中选择性添加幻灯片 |
| 修改元素 | 按名称或 creationId 定位和修改形状 |
| 修改文本 | 替换文本,使用基于标签的替换 |
| 修改图像 | 替换图像源,调整大小 |
| 修改表格 | 更新表格数据和样式 |
| 修改图表 | 更新图表数据(包括扩展图表类型) |
| 导入幻灯片母版 | 保留原始样式和布局 |
| PptxGenJS 集成 | 使用 PptxGenJS 在模板上创建元素 |
import Automizer from 'pptx-automizer';
const automizer = new Automizer({
templateDir: 'path/to/templates',
outputDir: 'path/to/output',
// 保留现有幻灯片(不截断)
removeExistingSlides: false,
});
let pres = automizer
// 加载根模板(输出将基于此)
.loadRoot('MyPresentation.pptx')
// 再次加载同一文件以修改其幻灯片
.load('MyPresentation.pptx', 'myPres');
// 从模板添加幻灯片 2 并修改它
pres.addSlide('myPres', 2, (slide) => {
// 按形状名称修改元素
slide.modifyElement('Title', [
modify.setText('Updated Title Text'),
]);
slide.modifyElement('ContentBox', [
modify.replaceText([{
replace: '{{placeholder}}',
by: { text: 'Dynamic Content' }
}])
]);
});
// 写入输出
pres.write('UpdatedPresentation.pptx').then(summary => {
console.log(summary);
});
import Automizer, { modify, ModifyTextHelper } from 'pptx-automizer';
async function modifySingleSlide(inputFile, slideNumber, modifications) {
const automizer = new Automizer({
templateDir: './',
outputDir: './',
removeExistingSlides: true, // 重新开始
});
// 加载文件两次 - 作为根和作为模板
let pres = automizer
.loadRoot(inputFile)
.load(inputFile, 'source');
// 获取所有幻灯片编号
const slideNumbers = await pres
.getTemplate('source')
.getAllSlideNumbers();
// 重新添加所有幻灯片,仅修改目标幻灯片
for (const num of slideNumbers) {
if (num === slideNumber) {
// 对目标幻灯片应用修改
pres.addSlide('source', num, modifications);
} else {
// 保持其他幻灯片不变
pres.addSlide('source', num);
}
}
// 写入新文件(或同一文件)
await pres.write(inputFile.replace('.pptx', '-modified.pptx'));
}
// 用法:
await modifySingleSlide('plugin-to-ide.pptx', 1, (slide) => {
slide.modifyElement('Title', [
ModifyTextHelper.setText('New Title'),
]);
});
import Automizer, { modify } from 'pptx-automizer';
pres.addSlide('charts', 2, (slide) => {
slide.modifyElement('ColumnChart', [
modify.setChartData({
series: [
{ label: 'Q1 Sales' },
{ label: 'Q2 Sales' },
],
categories: [
{ label: 'Product A', values: [150, 180] },
{ label: 'Product B', values: [200, 220] },
{ label: 'Product C', values: [130, 160] },
],
}),
]);
});
import Automizer, { ModifyImageHelper, ModifyShapeHelper, CmToDxa } from 'pptx-automizer';
const automizer = new Automizer({
templateDir: 'templates',
outputDir: 'output',
mediaDir: 'images', // 外部图像目录
});
let pres = automizer
.loadRoot('Template.pptx')
.loadMedia(['new-image.png']) // 加载外部图像
.load('Template.pptx', 'template');
pres.addSlide('template', 1, (slide) => {
slide.modifyElement('ImagePlaceholder', [
// 替换图像源
ModifyImageHelper.setRelationTarget('new-image.png'),
// 可选调整大小
ModifyShapeHelper.setPosition({
w: CmToDxa(8),
h: CmToDxa(6),
}),
]);
});
pres.write('UpdatedWithNewImage.pptx');
PowerPoint 形状可以包含占位符标签,如 {{title}},这些标签会被替换:
pres.addSlide('template', 1, (slide) => {
slide.modifyElement('TextWithTags', [
modify.replaceText([
{ replace: 'title', by: { text: 'My Dynamic Title' } },
{ replace: 'date', by: { text: '2026-02-28' } },
{ replace: 'author', by: { text: 'Your Name' } },
]),
]);
});
| 功能 | PptxGenJS | pptx-automizer |
|---|---|---|
| 从头创建 | ✅ 优秀 | ⚠️ 有限(包装 PptxGenJS) |
| 编辑现有文件 | ❌ 否 | ✅ 是 |
| 合并模板 | ❌ 否 | ✅ 是 |
| 保留样式 | ❌ 不适用 | ✅ 是 |
| 修改图表 | ❌ 否 | ✅ 是 |
| 标签替换 | ❌ 否 | ✅ 是 |
| 学习曲线 | 低 | 中等 |
创建新 PPT:使用 PptxGenJS 编辑现有 PPT:使用 pptx-automizer 混合工作流:使用 pptx-automizer 与 PptxGenJS 集成
// pptx-automizer 可以包装 PptxGenJS 以创建新元素
pres.addSlide('template', 1, (slide) => {
// 使用 pptxgenjs 从头添加新形状
slide.generate((pptxGenJSSlide, pptxGenJs) => {
pptxGenJSSlide.addText('New Text Box', {
x: 1, y: 1, w: 3, h: 0.5,
fontSize: 14, color: '333333'
});
pptxGenJSSlide.addChart(pptxGenJs.ChartType.bar, chartData, {
x: 4, y: 1, w: 5, h: 3
});
});
});
slide.modifyElement('MyShapeName', [ /* modifiers */ ]);
// 更稳定 - 在幻灯片重新排列后仍然有效
slide.modifyElement('{E43D12C3-AD5A-4317-BC00-FDED287C0BE8}', [ /* modifiers */ ]);
slide.modifyElement({
creationId: '{E43D12C3-AD5A-4317-BC00-FDED287C0BE8}',
name: 'MyShapeName', // 如果未找到 creationId 则回退
}, [ /* modifiers */ ]);
{{tagName}}"ff6b6b" 而不是 "#ff6b6b"(会导致损坏)每周安装次数
99
仓库
首次出现
2026年2月28日
安全审计
安装于
opencode99
kimi-cli98
amp98
cline98
github-copilot98
codex98
Skills CLI 使用指南:AI Agent 技能包管理器安装与管理教程
40,000 周安装