mcpField
P
ppt-template-creator

ppt-template-creator

github.com/anthropicsAgent 工作流40.9k2.3k 次安装今天更新
代码仓库

关于 ppt-template-creator

用于将 PowerPoint 模板转为可复用演示文稿生成 skill,而非直接制作演示文稿。它分析版式和占位符,并将模板、自包含说明及示例输出打包。

主要功能

  1. 01分析版式与占位符
  2. 02记录内容区域边界
  3. 03将模板打包到 assets
  4. 04生成自包含的 SKILL.md 说明
  5. 05通过示例演示文稿验证

适用场景

  1. 01将公司模板转为可复用 skill
  2. 02记录生成幻灯片所需的占位符位置
  3. 03测试基于模板的演示文稿工作流

安装

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

$npx skills add https://github.com/anthropics/financial-services --skill ppt-template-creator

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

详细介绍

PPT 模板创建器

此技能创建的是 SKILLS,而不是演示文稿。 当用户想要将其 PowerPoint 模板转化为之后可生成演示文稿的可复用技能时,请使用此技能。如果用户只是想创建演示文稿,请改用 pptx 技能。

生成的技能包含:

  • assets/template.pptx - 模板文件
  • SKILL.md - 完整说明(无需引用此元技能)

关于通用的技能构建最佳实践,请参考 skill-creator 技能。此技能专注于 PPT 特有的模式。

工作流

  1. 用户提供模板(.pptx 或 .potx)
  2. 分析模板 - 提取布局、占位符、尺寸
  3. 初始化技能 - 使用 skill-creator 技能搭建技能结构
  4. 添加模板 - 将 .pptx 复制到 assets/template.pptx
  5. 编写 SKILL.md - 按照下方模板,填入 PPT 特有的细节
  6. 创建示例 - 生成示例演示文稿以进行验证
  7. 打包 - 使用 skill-creator 技能打包为 .skill 文件

步骤 2:分析模板

关键:提取精确的占位符位置 - 这决定了内容区域的边界。

from pptx import Presentation

prs = Presentation(template_path)
print(f"Dimensions: {prs.slide_width/914400:.2f}\" x {prs.slide_height/914400:.2f}\"")
print(f"Layouts: {len(prs.slide_layouts)}")

for idx, layout in enumerate(prs.slide_layouts):
    print(f"\n[{idx}] {layout.name}:")
    for ph in layout.placeholders:
        try:
            ph_idx = ph.placeholder_format.idx
            ph_type = ph.placeholder_format.type
            # IMPORTANT: Extract exact positions in inches
            left = ph.left / 914400
            top = ph.top / 914400
            width = ph.width / 914400
            height = ph.height / 914400
            print(f"    idx={ph_idx}, type={ph_type}")
            print(f"        x={left:.2f}\", y={top:.2f}\", w={width:.2f}\", h={height:.2f}\"")
        except:
            pass

需要记录的关键测量值:

  • 标题位置:标题占位符位于何处?
  • 副标题/描述:副标题行位于何处?
  • 页脚占位符:页脚/来源出现在何处?
  • 内容区域:副标题与页脚之间的空间即为你的内容区域
找到真正的内容起始位置

关键: 内容区域并不总是紧接在副标题占位符之后开始。许多模板在副标题与内容区域之间有视觉边框、线条或预留空间。

最佳方法: 查看 Layout 2 或类似的带有 OBJECT 占位符的“内容”布局 - 此占位符的 y 位置指示内容实际应从何处开始。

# Find the OBJECT placeholder to determine true content start
for idx, layout in enumerate(prs.slide_layouts):
    for ph in layout.placeholders:
        try:
            if ph.placeholder_format.type == 7:  # OBJECT type
                top = ph.top / 914400
                print(f"Layout [{idx}] {layout.name}: OBJECT starts at y={top:.2f}\"")
                # This y value is where your content should start!
        except:
            pass

示例: 某个模板可能有:

  • 副标题结束于 y=1.38"
  • 但 OBJECT 占位符起始于 y=1.90"
  • 这段间隙(0.52")是为边框/线条预留的 - 不要在此处放置内容

请使用 OBJECT 占位符的 y 位置作为内容起始位置,而不是副标题的结束位置。

步骤 5:编写 SKILL.md

生成的技能应具有以下结构:

[company]-ppt-template/
├── SKILL.md
└── assets/
    └── template.pptx
生成的 SKILL.md 模板

生成的 SKILL.md 必须自包含,所有说明都内嵌其中。使用此模板,并根据你的分析填入方括号中的值:

---
name: [company]-ppt-template
description: [Company] PowerPoint template for creating presentations. Use when creating [Company]-branded pitch decks, board materials, or client presentations.
---

# [Company] PPT Template

Template: `assets/template.pptx` ([WIDTH]" x [HEIGHT]", [N] layouts)

## Creating Presentations

```python
from pptx import Presentation

prs = Presentation("path/to/skill/assets/template.pptx")

# DELETE all existing slides first
while len(prs.slides) > 0:
    rId = prs.slides._sldIdLst[0].rId
    prs.part.drop_rel(rId)
    del prs.slides._sldIdLst[0]

# Add slides from layouts
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_IDX])
```

## Key Layouts

| Index | Name | Use For |
|-------|------|---------|
| [0] | [Layout Name] | [Cover/title slide] |
| [N] | [Layout Name] | [Content with bullets] |
| [N] | [Layout Name] | [Two-column layout] |

## Placeholder Mapping

**CRITICAL: Include exact positions (x, y coordinates) for each placeholder.**

### Layout [N]: [Name]
| idx | Type | Position | Use |
|-----|------|----------|-----|
| [idx] | TITLE (1) | y=[Y]" | Slide title |
| [idx] | BODY (2) | y=[Y]" | Subtitle/description |
| [idx] | BODY (2) | y=[Y]" | Footer |
| [idx] | BODY (2) | y=[Y]" | Source/notes |

### Content Area Boundaries

**Document the safe content area for custom shapes/tables/charts:**

```
Content Area (for Layout [N]):
- Left margin: [X]" (content starts here)
- Top: [Y]" (below subtitle placeholder)
- Width: [W]"
- Height: [H]" (ends before footer)

For 4-quadrant layouts:
- Left column: x=[X]", width=[W]"
- Right column: x=[X]", width=[W]"
- Top row: y=[Y]", height=[H]"
- Bottom row: y=[Y]", height=[H]"
```

**Why this matters:** Custom content (textboxes, tables, charts) must stay within these boundaries to avoid overlapping with template placeholders like titles, footers, and source lines.

## Filling Content

**Do NOT add manual bullet characters** - slide master handles formatting.

```python
# Fill title
for shape in slide.shapes:
    if hasattr(shape, 'placeholder_format'):
        if shape.placeholder_format.type == 1:  # TITLE
            shape.text = "Slide Title"

# Fill content with hierarchy (level 0 = header, level 1 = bullet)
for shape in slide.shapes:
    if hasattr(shape, 'placeholder_format'):
        idx = shape.placeholder_format.idx
        if idx == [CONTENT_IDX]:
            tf = shape.text_frame
            for para in tf.paragraphs:
                para.clear()

            content = [
                ("Section Header", 0),
                ("First bullet point", 1),
                ("Second bullet point", 1),
            ]

            tf.paragraphs[0].text = content[0][0]
            tf.paragraphs[0].level = content[0][1]
            for text, level in content[1:]:
                p = tf.add_paragraph()
                p.text = text
                p.level = level
```

## Example: Cover Slide

```python
slide = prs.slides.add_slide(prs.slide_layouts[[COVER_IDX]])
for shape in slide.shapes:
    if hasattr(shape, 'placeholder_format'):
        idx = shape.placeholder_format.idx
        if idx == [TITLE_IDX]:
            shape.text = "Company Name"
        elif idx == [SUBTITLE_IDX]:
            shape.text = "Presentation Title | Date"
```

## Example: Content Slide

```python
slide = prs.slides.add_slide(prs.slide_layouts[[CONTENT_IDX]])
for shape in slide.shapes:
    if hasattr(shape, 'placeholder_format'):
        ph_type = shape.placeholder_format.type
        idx = shape.placeholder_format.idx
        if ph_type == 1:
            shape.text = "Executive Summary"
        elif idx == [BODY_IDX]:
            tf = shape.text_frame
            for para in tf.paragraphs:
                para.clear()
            content = [
                ("Key Findings", 0),
                ("Revenue grew 40% YoY to $50M", 1),
                ("Expanded to 3 new markets", 1),
                ("Recommendation", 0),
                ("Proceed with strategic initiative", 1),
            ]
            tf.paragraphs[0].text = content[0][0]
            tf.paragraphs[0].level = content[0][1]
            for text, level in content[1:]:
                p = tf.add_paragraph()
                p.text = text
                p.level = level
```

步骤 6:创建示例输出

生成一份示例演示文稿,以验证该技能可以正常工作。将其与技能保存在一起以供参考。

生成的技能需遵循的 PPT 特有规则

  1. 模板放在 assets/ 中 - 始终捆绑 .pptx 文件
  2. 自包含的 SKILL.md - 所有说明内嵌,不引用外部内容
  3. 不要手动添加项目符号 - 使用 paragraph.level 表示层级
  4. 先删除幻灯片 - 在添加新幻灯片之前,始终清除现有幻灯片
  5. 按 idx 记录占位符 - 占位符 idx 值因模板而异

评论

支持 Markdown