mcpField
S
single-slide-ppt

single-slide-ppt

github.com/huyansheng3文档处理0340 次安装35 周前更新
代码仓库

关于 single-slide-ppt

single-slide-ppt 是使用 PptxGenJS 创建单页 PowerPoint 的技能,面向需要将信息整理成一页演示文稿的人。它提供内容结构分析、版式选择和视觉设计流程,也说明如何借助 pptx-automizer 修改现有文件。

主要功能

  1. 01分析内容并选择版式
  2. 02提供对比、网格与流程设计模式
  3. 03制定配色、排版和视觉层级建议
  4. 04使用 PptxGenJS 生成幻灯片
  5. 05介绍使用 pptx-automizer 修改现有文件

适用场景

  1. 01制作问题与解决方案对比页
  2. 02展示产品功能或能力矩阵
  3. 03呈现流程、时间线或决策树
  4. 04基于模板修改已有 PowerPoint

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/huyansheng3/ppt-skills --skill single-slide-ppt

安装后在 Claude Code 中输入/single-slide-ppt确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

IMAGE_GUIDE.md
references/
color-palettes.md
scripts/
template-feature-grid.js
template-problem-solution.js

详细介绍

单页 PowerPoint 创建工具

使用 PptxGenJS 创建专业且视觉吸引力十足的单页 PowerPoint 演示文稿。

适用场景

  • 用户请求“做一页 PPT”“single slide”或“create a PPT slide”
  • 将对比内容可视化(前后对比、新旧对比、问题与解决方案)
  • 展示功能(网格布局、能力矩阵)
  • 概念示意图(工作流、架构、框架)
  • 决策框架或流程图

核心工作流

1. 理解内容结构

分析用户的请求,确定:

  • 核心信息/标题
  • 关键要点或章节(通常为 2-6 项)
  • 自然分组方式(左右、网格、顺序)
  • 视觉隐喻(箭头、图标、卡片)
2. 选择设计模式

选择与内容结构相匹配的布局:

对比布局(2 列):

  • 问题 → 解决方案
  • 前 → 后
  • 旧 → 新
  • 插件 → IDE

网格布局(2x2、2x3、3x3):

  • 功能展示
  • 能力矩阵
  • 多选项对比

顺序流程:

  • 流程步骤
  • 时间线
  • 决策树

单一重点:

  • 关键指标
  • 核心概念
  • 引言或陈述
3. 设计配色方案

根据内容主题选择 3-5 种颜色:

根据内容选择配色:

  • 技术:深蓝色(#1a1a2e)、紫色(#4a00e0)、强调色(#8e2de2)
  • 问题/解决方案:问题用红色(#ff6b6b),解决方案用绿色(#51cf66)
  • 专业:藏青色(#2C3E50)、蓝绿色(#16A085)、金色(#F39C12)
  • 创意:紫色(#722880)、粉色(#D72D51)、橙色(#EB5C18)

颜色分配:

  • 背景:深色(#1a1a2e)或浅色(#f5f5f5)
  • 页眉:品牌主色或渐变色
  • 问题/负面:红色/橙色系
  • 解决方案/正面:绿色/蓝色系
  • 强调色:用于突出显示的互补色
4. 添加相关图片以增强效果(可选)

创建关于技术概念、产品或对比的幻灯片时,可考虑添加相关图片,以强化信息传达。

适用图片的场景:

  • 技术架构图(来自官方文档)
  • 产品截图(用于前后对比)
  • Logo 或品牌素材(用于产品幻灯片)
  • 插图(用于解释抽象概念)
  • 图表(用于数据可视化)

查找和下载图片的方法:

// Example: Download VSCode architecture diagram
// Use curl to download images from official sources
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;
  }
}

// Example usage:
downloadImage(
  'https://code.visualstudio.com/assets/api/ux-guidelines/examples/architecture-containers.png',
  'workspace/vscode-architecture.png'
);

图片查找策略:

  1. 官方文档:搜索“[Product Name] architecture documentation”或“[Product Name] official API documentation”
  2. GitHub 仓库:查找 README.md 或 docs/ 文件夹中的图表
  3. 技术博客:从可靠来源查找说明性图表
  4. 使用 search_web 和 fetch_web:搜索相关内容并提取图片 URL

在幻灯片中添加图片:

// After downloading the image, add it to the slide
slide.addImage({
  path: 'workspace/downloaded-image.png',
  x: 0.5,    // X position in inches
  y: 1.5,    // Y position in inches
  w: 4.8,    // Width in inches
  h: 2.7     // Height in inches (maintain aspect ratio)
});

// Optional: Add caption
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'
});

图片最佳实践:

  • ✅ 使用官方来源(公司网站、文档)
  • ✅ 调整大小时保持纵横比
  • ✅ 添加说明文字以提供上下文
  • ✅ 确保图片有助于讲述内容
  • ❌ 不要使用低分辨率图片
  • ❌ 不要在幻灯片中塞入过多图片
  • ❌ 未经许可不要使用图片
5. 使用 PptxGenJS 创建幻灯片
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();
  
  // Background
  slide.background = { color: '1a1a2e' };
  
  // Header bar
  slide.addShape(pptx.shapes.RECTANGLE, {
    x: 0, y: 0, w: 10, h: 0.8,
    fill: { color: '4a00e0' }
  });
  
  // Title
  slide.addText('Your Title Here', {
    x: 0.5, y: 0.18, w: 9, h: 0.5,
    fontSize: 26, bold: true, color: 'ffffff',
    fontFace: 'Arial'
  });
  
  // Optional: Add downloaded image
  // slide.addImage({
  //   path: 'workspace/image.png',
  //   x: 0.5, y: 1.5, w: 4.8, h: 2.7
  // });
  
  // Content sections...
  // [Add your content here following the patterns below]
  
  await pptx.writeFile({ fileName: 'output.pptx' });
}

createSlide().catch(console.error);

设计模式库

模式:对比卡片(左侧与右侧)
// Left section - Problem/Before
slide.addText('🚫 Current State', {
  x: 0.4, y: 1.0, w: 4, h: 0.4,
  fontSize: 14, bold: true, color: 'ff6b6b'
});

// Card with left border accent
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
});

// Right section - Solution/After (mirror structure with green)
slide.addText('✅ New State', {
  x: 5.3, y: 1.0, w: 4, h: 0.4,
  fontSize: 14, bold: true, color: '51cf66'
});
// [Add cards using green color scheme]
模式:功能网格(2x3)
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'
  });
});
模式:可视化对比框
// Before box (dashed border)
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'
});

// After box (solid border)
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'
});
模式:箭头连接符
// Arrow between sections
slide.addText('➔', {
  x: 4.5, y: 2.5, w: 0.8, h: 0.6,
  fontSize: 36, color: '8e2de2',
  align: 'center', valign: 'middle'
});

视觉设计最佳实践

字体排版
  • 标题:22-28pt,加粗,高对比度
  • 章节标题:12-16pt,加粗
  • 正文:9-11pt,中等字重
  • 说明文字:8-9pt,使用较浅的颜色
间距与对齐
  • 页眉高度:0.7-0.9 英寸
  • 章节边距:距离边缘 0.4-0.5 英寸
  • 卡片内边距:0.1-0.15 英寸
  • 网格间距:0.08-0.15 英寸
颜色使用
  • 每张幻灯片最多使用 5 种颜色
  • 使用透明度实现分层:rgba(R,G,B,0.1) 转换为 RRGGBB + 较浅的填充色
  • 确保文本对比度大于 4.5:1(深色背景上使用 #e0e0e0 文本)
视觉层级
  1. 标题/页眉(字号最大,对比度最高)
  2. 章节标题(字号中等,按颜色区分)
  3. 内容卡片(分组并带边框)
  4. 辅助文本(字号最小,对比度较低)

常见幻灯片类型

1. 问题 → 解决方案幻灯片
  • 左侧:问题卡片(红色主题)
  • 中间:箭头连接符
  • 右侧:解决方案功能(绿色主题)
  • 底部:核心价值主张
2. 功能展示
  • 包含产品名称的标题
  • 2x3 或 3x3 功能网格
  • 每个单元格:图标 + 简短说明
  • 可选:底部的关键优势卡片
3. 前后对比
  • 说明变化的标题
  • 并排对比框
  • 视觉指示符(表情符号/图标)
  • 展示变化过程的箭头
4. 流程
  • 按顺序排列的编号卡片
  • 步骤之间用箭头连接
  • 颜色渐变
  • 突出显示最终状态
5. 技术架构幻灯片(含图片)
  • 包含架构名称的标题
  • 官方架构图(从文档下载)
  • 注明来源的图片说明
  • 在卡片中突出显示要点或限制

示例: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';
  
  // Download VSCode architecture image
  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' };
  
  // Header
  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'
  });
  
  // Left: Architecture image
  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'
  });
  
  // Right: Limitation cards
  slide.addText('API 限制', {
    x: 5.5, y: 1.2, w: 4.2, h: 0.4,
    fontSize: 18, bold: true, color: 'fc5a1f'
  });
  
  // Add limitation cards...
  
  await pptx.writeFile({ fileName: 'technical-slide.pptx' });
}

createTechnicalSlide().catch(console.error);

执行检查清单

  • 分析内容以确定结构
  • 选择合适的设计模式
  • 选择与主题相匹配的配色方案
  • 搜索相关图片(技术/产品内容需要时)
  • 使用 curl 或网页工具下载图片
  • 创建 PptxGenJS 脚本(包含图片路径)
  • 运行脚本以生成 .pptx
  • 生成缩略图预览
  • 检查视觉效果
  • 向用户交付文件和预览

文件输出

将文件保存在专用工作区中:

mkdir -p workspace
cd workspace
node generate-slide.js

生成预览:

python3 /path/to/pptx/scripts/thumbnail.py output.pptx preview --cols 1

修改现有 PPT 文件

为什么 PptxGenJS 无法编辑现有文件?

技术原因:

  1. 设计用途:PptxGenJS 是一个专注于从头创建 PPT 的“生成”库
  2. 文件结构复杂:.pptx 文件是包含多个 XML 文件的 ZIP 压缩包(Office Open XML 格式)
  3. 关系处理:编辑需要解析幻灯片、形状、媒体等之间复杂的关联关系
解决方案:使用 pptx-automizer 编辑现有文件

pptx-automizer 是一个功能强大的 Node.js 库,专为编辑和合并现有 .pptx 文件而设计。

安装
npm install pptx-automizer
# or
yarn add pptx-automizer
核心功能
功能说明
加载模板导入现有 .pptx 文件作为模板
合并幻灯片有选择地从多个模板中添加幻灯片
修改元素按名称或 creationId 定位并修改形状
修改文本替换文本,使用基于标签的替换
修改图片替换图片来源,调整大小
修改表格更新表格数据和样式
修改图表更新图表数据(包括扩展图表类型)
导入幻灯片母版保留原始样式和布局
PptxGenJS 集成使用 PptxGenJS 在模板上创建元素
基本示例:加载并修改现有 PPT
import Automizer from 'pptx-automizer';

const automizer = new Automizer({
  templateDir: 'path/to/templates',
  outputDir: 'path/to/output',
  // Keep existing slides (don't truncate)
  removeExistingSlides: false,
});

let pres = automizer
  // Load root template (output will be based on this)
  .loadRoot('MyPresentation.pptx')
  // Load same file again to modify its slides
  .load('MyPresentation.pptx', 'myPres');

// Add slide 2 from template and modify it
pres.addSlide('myPres', 2, (slide) => {
  // Modify element by shape name
  slide.modifyElement('Title', [
    modify.setText('Updated Title Text'),
  ]);
  
  slide.modifyElement('ContentBox', [
    modify.replaceText([{
      replace: '{{placeholder}}',
      by: { text: 'Dynamic Content' }
    }])
  ]);
});

// Write output
pres.write('UpdatedPresentation.pptx').then(summary => {
  console.log(summary);
});
修改现有 PPT 中的单张幻灯片
import Automizer, { modify, ModifyTextHelper } from 'pptx-automizer';

async function modifySingleSlide(inputFile, slideNumber, modifications) {
  const automizer = new Automizer({
    templateDir: './',
    outputDir: './',
    removeExistingSlides: true, // Start fresh
  });

  // Load the file twice - as root and as template
  let pres = automizer
    .loadRoot(inputFile)
    .load(inputFile, 'source');

  // Get all slide numbers
  const slideNumbers = await pres
    .getTemplate('source')
    .getAllSlideNumbers();

  // Re-add all slides, modifying only the target slide
  for (const num of slideNumbers) {
    if (num === slideNumber) {
      // Apply modifications to target slide
      pres.addSlide('source', num, modifications);
    } else {
      // Keep other slides unchanged
      pres.addSlide('source', num);
    }
  }

  // Write to new file (or same file)
  await pres.write(inputFile.replace('.pptx', '-modified.pptx'));
}

// Usage:
await modifySingleSlide('plugin-to-ide.pptx', 1, (slide) => {
  slide.modifyElement('Title', [
    ModifyTextHelper.setText('New Title'),
  ]);
});
修改现有 PPT 中的图表数据
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] },
      ],
    }),
  ]);
});
替换现有 PPT 中的图片
import Automizer, { ModifyImageHelper, ModifyShapeHelper, CmToDxa } from 'pptx-automizer';

const automizer = new Automizer({
  templateDir: 'templates',
  outputDir: 'output',
  mediaDir: 'images', // Directory for external images
});

let pres = automizer
  .loadRoot('Template.pptx')
  .loadMedia(['new-image.png']) // Load external image
  .load('Template.pptx', 'template');

pres.addSlide('template', 1, (slide) => {
  slide.modifyElement('ImagePlaceholder', [
    // Replace image source
    ModifyImageHelper.setRelationTarget('new-image.png'),
    // Optionally adjust size
    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
功能PptxGenJSpptx-automizer
从头创建✅ 优秀⚠️ 有限(封装了 PptxGenJS)
编辑现有文件❌ 否✅ 是
合并模板❌ 否✅ 是
保留样式❌ 不适用✅ 是
修改图表❌ 否✅ 是
标签替换❌ 否✅ 是
学习曲线低中
推荐工作流

创建新的 PPT:使用 PptxGenJS 编辑现有 PPT:使用 pptx-automizer 混合工作流:使用集成了 PptxGenJS 的 pptx-automizer

// pptx-automizer can wrap PptxGenJS for creating new elements
pres.addSlide('template', 1, (slide) => {
  // Use pptxgenjs to add new shapes from scratch
  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 */ ]);
按 creationId(稳健)
// More stable - survives slide rearrangement
slide.modifyElement('{E43D12C3-AD5A-4317-BC00-FDED287C0BE8}', [ /* modifiers */ ]);
带回退方案
slide.modifyElement({
  creationId: '{E43D12C3-AD5A-4317-BC00-FDED287C0BE8}',
  name: 'MyShapeName', // Fallback if creationId not found
}, [ /* modifiers */ ]);
最佳实践
  1. 模板管理:维护一个设计精良的 .pptx 模板库
  2. 形状命名:在 PowerPoint 中为形状指定有意义的名称(按 ALT+F10 打开「选择窗格」)
  3. 标签约定:使用一致的标签格式,例如 {{tagName}}
  4. 版本控制:在 git 中跟踪模板的更改
  5. 编辑后预览:始终生成缩略图以验证更改
  6. 错误处理:妥善处理找不到形状的情况

注意事项

  • 颜色前不要加 #:使用 "ff6b6b",而非 "#ff6b6b"(否则会导致文件损坏)
  • 仅使用 Web 安全字体:Arial、Helvetica、Times New Roman、Georgia、Courier New、Verdana
  • 测试表情符号支持:部分表情符号可能无法在所有平台上正确显示
  • 16:9 宽高比:大多数演示文稿的标准比例(10 x 5.625 英寸)
  • pptx-automizer:用于编辑现有的 .pptx 文件
  • PptxGenJS:用于从头创建新的演示文稿

评论

支持 Markdown