ppt-template-creator by anthropics/financial-services-plugins
npx skills add https://github.com/anthropics/financial-services-plugins --skill ppt-template-creator此技能创建的是 SKILLS,而非演示文稿。 当用户希望将其 PowerPoint 模板转换为可重复使用的、用于后续生成演示文稿的技能时,请使用此技能。如果用户只是想创建演示文稿,请改用 pptx 技能。
生成的技能包含:
assets/template.pptx - 模板文件SKILL.md - 完整的说明(无需参考此元技能)关于通用技能构建的最佳实践,请参考 skill-creator 技能。本技能侧重于 PPT 特有的模式。
skill-creator 技能来设置技能结构assets/template.pptx广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
skill-creator 技能打包成 .skill 文件关键:提取精确的占位符位置 - 这决定了内容区域的边界。
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
# 重要:以英寸为单位提取精确位置
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
需要记录的关键测量值:
关键: 内容区域并非总是紧接在副标题占位符之后开始。许多模板在副标题和内容区域之间有视觉边框、线条或预留空间。
最佳方法: 查看版式 2 或类似的具有 OBJECT 占位符的"内容"版式 - 此占位符的 y 位置指示了内容实际应该开始的位置。
# 查找 OBJECT 占位符以确定真实的内容起始位置
for idx, layout in enumerate(prs.slide_layouts):
for ph in layout.placeholders:
try:
if ph.placeholder_format.type == 7: # OBJECT 类型
top = ph.top / 914400
print(f"Layout [{idx}] {layout.name}: OBJECT starts at y={top:.2f}\"")
# 这个 y 值就是你的内容应该开始的位置!
except:
pass
示例: 一个模板可能具有:
使用 OBJECT 占位符的 y 位置作为你的内容起始点,而不是副标题的结束位置。
生成的技能应具有以下结构:
[company]-ppt-template/
├── SKILL.md
└── assets/
└── template.pptx
生成的 SKILL.md 必须是自包含的,所有说明都嵌入其中。使用此模板,并根据你的分析填写括号内的值:
---
name: [company]-ppt-template
description: 用于创建演示文稿的 [Company] PowerPoint 模板。在创建 [Company] 品牌推介材料、董事会材料或客户演示文稿时使用。
---
# [Company] PPT 模板
模板:`assets/template.pptx` ([WIDTH]" x [HEIGHT]", [N] 个版式)
## 创建演示文稿
```python
from pptx import Presentation
prs = Presentation("path/to/skill/assets/template.pptx")
# 首先删除所有现有幻灯片
while len(prs.slides) > 0:
rId = prs.slides._sldIdLst[0].rId
prs.part.drop_rel(rId)
del prs.slides._sldIdLst[0]
# 根据版式添加幻灯片
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_IDX])
| 索引 | 名称 | 用途 |
|---|---|---|
| [0] | [Layout Name] | [封面/标题幻灯片] |
| [N] | [Layout Name] | [带项目符号的内容] |
| [N] | [Layout Name] | [两栏布局] |
关键:包含每个占位符的精确位置(x, y 坐标)。
| idx | 类型 | 位置 | 用途 |
|---|---|---|---|
| [idx] | TITLE (1) | y=[Y]" | 幻灯片标题 |
| [idx] | BODY (2) | y=[Y]" | 副标题/描述 |
| [idx] | BODY (2) | y=[Y]" | 页脚 |
| [idx] | BODY (2) | y=[Y]" | 来源/备注 |
记录用于自定义形状/表格/图表的安全内容区域:
内容区域 (适用于版式 [N]):
- 左边距: [X]" (内容从此处开始)
- 顶部: [Y]" (副标题占位符下方)
- 宽度: [W]"
- 高度: [H]" (在页脚之前结束)
对于 4 象限布局:
- 左列: x=[X]", width=[W]"
- 右列: x=[X]", width=[W]"
- 顶行: y=[Y]", height=[H]"
- 底行: y=[Y]", height=[H]"
为什么这很重要: 自定义内容(文本框、表格、图表)必须保持在边界内,以避免与模板占位符(如标题、页脚和来源行)重叠。
不要手动添加项目符号字符 - 幻灯片母版处理格式。
# 填充标题
for shape in slide.shapes:
if hasattr(shape, 'placeholder_format'):
if shape.placeholder_format.type == 1: # TITLE
shape.text = "Slide Title"
# 用层级结构填充内容 (级别 0 = 标题,级别 1 = 项目符号)
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
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"
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
生成一个示例演示文稿以验证技能是否正常工作。将其保存在技能文件夹中作为参考。
paragraph.level 表示层级结构每周安装次数
137
代码仓库
GitHub 星标
5.7K
首次出现
2026年2月25日
安全审计
安装于
opencode133
kimi-cli132
gemini-cli132
codex132
cursor132
amp131
This skill creates SKILLS, not presentations. Use this when a user wants to turn their PowerPoint template into a reusable skill that can generate presentations later. If the user just wants to create a presentation, use the pptx skill instead.
The generated skill includes:
assets/template.pptx - the template fileSKILL.md - complete instructions (no reference to this meta skill needed)For general skill-building best practices , refer to the skill-creator skill. This skill focuses on PPT-specific patterns.
skill-creator skill to set up the skill structureassets/template.pptxskill-creator skill to package into a .skill fileCRITICAL: Extract precise placeholder positions - this determines content area boundaries.
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
Key measurements to document:
CRITICAL: The content area does NOT always start immediately after the subtitle placeholder. Many templates have a visual border, line, or reserved space between the subtitle and content area.
Best approach: Look at Layout 2 or similar "content" layouts that have an OBJECT placeholder - this placeholder's y position indicates where content should actually start.
# 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
Example: A template might have:
Use the OBJECT placeholder's y position as your content start, not the subtitle's end position.
The generated skill should have this structure:
[company]-ppt-template/
├── SKILL.md
└── assets/
└── template.pptx
The generated SKILL.md must be self-contained with all instructions embedded. Use this template, filling in the bracketed values from your analysis:
---
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
```
Generate a sample presentation to validate the skill works. Save it alongside the skill for reference.
paragraph.level for hierarchyWeekly Installs
137
Repository
GitHub Stars
5.7K
First Seen
Feb 25, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode133
kimi-cli132
gemini-cli132
codex132
cursor132
amp131
通过 LiteLLM 代理让 Claude Code 对接 GitHub Copilot 运行 | 高级变通方案指南
22,200 周安装
Nx Import 使用指南:从源仓库导入代码并保留Git历史
250 周安装
OpenPencil CLI 工具:.fig 设计文件命令行操作与 MCP 服务器 | 设计自动化
250 周安装
学术深度研究技能:AI驱动的学术文献综述与多源验证工具,生成APA格式报告
250 周安装
React PDF 渲染器 - 使用 JSON 生成 PDF 文档,支持自定义组件和流式渲染
250 周安装
后端安全编码专家 | 安全开发实践、漏洞预防与防御性编程技术指南
250 周安装
TanStack Form:高性能无头表单库,支持TypeScript、Zod、Valibot验证
250 周安装