Add pptx-plugin

This commit is contained in:
akai
2026-03-21 16:00:22 +08:00
parent 2e6511d8f6
commit 6154dd3699
14 changed files with 2072 additions and 0 deletions

View File

@@ -0,0 +1,156 @@
---
name: color-font-skill
description: "Choose presentation-ready color palettes and font pairings for PPT/design tasks. Use when users ask for visual theme choices, brand-safe palettes, or font recommendations. Triggers include: 配色, 色板, 字体, color palette, font, PPT配色, 字体搭配."
---
# Color Scheme - PPT 配色方案指南
| # | 名称 | 色值 | 风格 | 适用场景 | 建议 |
|---|------|------|------|----------|------|
| 1 | 现代与健康 | `#006d77` `#83c5be` `#edf6f9` `#ffddd2` `#e29578` | 清新、治愈 | 医疗健康、心理咨询、护肤品、瑜伽Spa | 深青做标题,浅粉做背景 |
| 2 | 商务与权威 | `#2b2d42` `#8d99ae` `#edf2f4` `#ef233c` `#d90429` | 严谨、经典 | 年度汇报、金融分析、企业介绍、政务报告 | 深蓝显专业,亮红强调数据 |
| 3 | 自然与户外 | `#606c38` `#283618` `#fefae0` `#dda15e` `#bc6c25` | 沉稳、大地色 | 户外用品、环境保护、农业项目、历史文化 | 深绿为底,米色为字 |
| 4 | 复古与学院 | `#780000` `#c1121f` `#fdf0d5` `#003049` `#669bbc` | 经典、书卷气 | 学术讲座、历史回顾、博物馆、复古品牌 | 深红与深蓝对比强烈 |
| 5 | 柔美与创意 | `#cdb4db` `#ffc8dd` `#ffafcc` `#bde0fe` `#a2d2ff` | 梦幻、糖果色 | 母婴产品、甜品店、女性时尚、幼儿园 | 文字用深灰或黑色 |
| 6 | 波西米亚 | `#ccd5ae` `#e9edc9` `#fefae0` `#faedcd` `#d4a373` | 温柔、低饱和 | 婚礼策划、家居软装、有机食品、慢生活 | 米色背景,绿棕点缀 |
| 7 | 活力与科技 | `#8ecae6` `#219ebc` `#023047` `#ffb703` `#fb8500` | 高能量、运动 | 体育赛事、健身房、创业路演、少儿教育 | 深蓝稳重心,橙色做焦点 |
| 8 | 匠心与手作 | `#7f5539` `#a68a64` `#ede0d4` `#656d4a` `#414833` | 质朴、咖啡调 | 咖啡店、手工艺品、传统文化、烘焙教学 | 适合纸质/皮革质感 |
| 9 | 科技与夜景 | `#000814` `#001d3d` `#003566` `#ffc300` `#ffd60a` | 深邃、高亮 | 科技发布会、星空天文、夜间经济、高端汽车 | 必须用深色模式 |
| 10 | 教育与图表 | `#264653` `#2a9d8f` `#e9c46a` `#f4a261` `#e76f51` | 清晰、逻辑强 | 统计报告、教育培训、市场分析、通用商务 | 完美的图表配色 |
| 11 | 森林与环保 | `#dad7cd` `#a3b18a` `#588157` `#3a5a40` `#344e41` | 单色渐变、森系 | 园林设计、ESG报告、环保公益、植物研究 | 单色系安全不会乱 |
| 12 | 优雅与时尚 | `#edafb8` `#f7e1d7` `#dedbd2` `#b0c4b1` `#4a5759` | 低饱和、莫兰迪 | 高定服装、艺术画廊、美妆品牌、杂志风 | 留白是关键 |
| 13 | 艺术与美食 | `#335c67` `#fff3b0` `#e09f3e` `#9e2a2b` `#540b0e` | 浓郁、复古画报 | 美食纪录片、艺术展、民族风情、复古餐厅 | 适合大色块拼接 |
| 14 | 轻奢与神秘 | `#22223b` `#4a4e69` `#9a8c98` `#c9ada7` `#f2e9e4` | 冷艳、紫调 | 珠宝展示、酒店管理、高端咨询、心理学 | 紫色营造高端氛围 |
| 15 | 纯净科技蓝 | `#03045e` `#0077b6` `#00b4d8` `#90e0ef` `#caf0f8` | 未来感、纯净 | 云计算/AI、水利海洋、医院医疗、洁净能源 | 从深海到天空的渐变 |
| 16 | 海岸珊瑚 | `#0081a7` `#00afb9` `#fdfcdc` `#fed9b7` `#f07167` | 清爽、夏日感 | 旅游度假、夏季活动、饮品品牌、海洋主题 | 青色与珊瑚色互补亮眼 |
| 17 | 活力橙薄荷 | `#ff9f1c` `#ffbf69` `#ffffff` `#cbf3f0` `#2ec4b6` | 明亮、欢快 | 儿童活动、促销海报、快消品、社交媒体 | 橙色吸睛,薄荷绿清爽 |
| 18 | 铂金白金 | `#0a0a0a` `#0070F3` `#D4AF37` `#f5f5f5` `#ffffff` | 高端、专业 | Agent产品、企业官网、金融科技、高端品牌 | 白金主调,蓝色行动,金色强调 |
---
# Agent Design System - 完整色板
基于 tokens.css/ts 的 Platinum White-Gold Theme提供完整色阶供精细设计使用。
## White 白色系(背景与浅色表面)
| 色阶 | 色值 | 用途 |
|------|------|------|
| white-0 | `#ffffff` | 主背景 |
| white-50 | `#fefefe` | 略带暖调的白 |
| white-75 | `#fcfcfc` | 微灰白 |
| white-100 | `#fafafa` | 次级背景 |
| white-200 | `#f7f7f7` | 卡片背景 |
| white-300 | `#f5f5f5` | 三级背景 |
| white-400 | `#f0f0f0` | 分隔区域 |
| white-500 | `#ebebeb` | 边框浅色 |
| white-600 | `#e5e5e5` | 禁用态背景 |
| white-700 | `#e0e0e0` | 深灰白 |
| white-800 | `#d9d9d9` | 占位符 |
| white-900 | `#d4d4d4` | 分隔线 |
| white-1000 | `#cccccc` | 最深白 |
## Gold 金色系(铂金商务强调色)
| 色阶 | 色值 | 用途 |
|------|------|------|
| gold-25 | `#FFFDF5` | 极浅金背景 |
| gold-50 | `#FEF9E7` | 浅金背景 |
| gold-75 | `#FCF3D0` | 淡金高亮 |
| gold-100 | `#FAECB8` | 金色 hover 态 |
| gold-200 | `#F5DC8A` | 亮金强调 |
| gold-300 | `#E8C860` | 金色悬停 |
| gold-400 | `#D4AF37` | **主金色(核心)** |
| gold-500 | `#B8972E` | 金色文字 |
| gold-600 | `#9A7E26` | 深金强调 |
| gold-700 | `#7C651E` | 暗金边框 |
| gold-800 | `#5E4C16` | 深金背景 |
| gold-900 | `#40330F` | 极深金 |
| gold-1000 | `#221A08` | 黑金 |
## Blue 蓝色系(主操作色)
| 色阶 | 色值 | 用途 |
|------|------|------|
| blue-25 | `#F0F7FF` | 极浅蓝背景 |
| blue-50 | `#E0EFFF` | 信息提示背景 |
| blue-75 | `#C2DFFF` | 浅蓝高亮 |
| blue-100 | `#A3CFFF` | 禁用态蓝 |
| blue-200 | `#66AFFF` | 亮蓝 |
| blue-300 | `#338FFF` | 蓝色悬停 |
| blue-400 | `#0070F3` | **主蓝色(核心)** |
| blue-500 | `#005FCC` | 蓝色文字 |
| blue-600 | `#004FA6` | 深蓝强调 |
| blue-700 | `#003F80` | 暗蓝边框 |
| blue-800 | `#002F5A` | 深蓝背景 |
| blue-900 | `#001F3D` | 极深蓝 |
| blue-1000 | `#001026` | 黑蓝 |
## Gray 灰色系(文字与中性色)
| 色阶 | 色值 | 用途 |
|------|------|------|
| gray-0 | `#ffffff` | 白色 |
| gray-50 | `#fafafa` | 极浅灰 |
| gray-75 | `#f5f5f5` | 浅灰背景 |
| gray-100 | `#ededed` | 分隔线浅 |
| gray-200 | `#d4d4d4` | 边框浅 |
| gray-300 | `#a3a3a3` | 四级文字 |
| gray-400 | `#737373` | 三级文字 |
| gray-500 | `#525252` | 二级文字 |
| gray-600 | `#404040` | 深灰 |
| gray-700 | `#2e2e2e` | 暗色背景 |
| gray-800 | `#1f1f1f` | 深色背景 |
| gray-900 | `#141414` | 极深背景 |
| gray-1000 | `#0a0a0a` | **主文字色(核心)** |
## 透明度色值
### Opacity Black黑色透明
| 透明度 | 色值 | 用途 |
|--------|------|------|
| 0% | `#0a0a0a00` | 全透明 |
| 2% | `#0a0a0a05` | 微弱遮罩 |
| 4% | `#0a0a0a0a` | 次级交互背景 |
| 8% | `#0a0a0a14` | 边框/分隔 |
| 15% | `#0a0a0a26` | 按压态 |
| 20% | `#0a0a0a33` | 浅遮罩 |
| 25% | `#0a0a0a40` | 中遮罩 |
| 50% | `#0a0a0a80` | 半透明 |
| 70% | `#0a0a0ab2` | 深遮罩 |
| 80% | `#0a0a0acc` | 悬停态 |
| 90% | `#0a0a0ae5` | tooltip |
| 95% | `#0a0a0af2` | 弹窗 |
### Opacity White白色透明
| 透明度 | 色值 | 用途 |
|--------|------|------|
| 0% | `#ffffff00` | 全透明 |
| 2% | `#ffffff05` | 微弱遮罩 |
| 4% | `#ffffff0a` | 次级交互背景 |
| 8% | `#ffffff12` | 边框/分隔 |
| 15% | `#ffffff26` | 按压态 |
| 20% | `#ffffff33` | 浅遮罩 |
| 25% | `#ffffff40` | 中遮罩 |
| 50% | `#ffffff80` | 半透明 |
| 70% | `#ffffffb2` | 深遮罩 |
| 80% | `#ffffffcc` | 悬停态 |
| 90% | `#ffffffe5` | tooltip |
| 95% | `#fffffff2` | 弹窗 |
---
# Font Family - 字体规范
## 推荐字体
| 语言 | 默认字体 | 可选字体 |
|------|----------|----------|
| **中文** | 微软雅黑 (Microsoft YaHei) | — |
| **英文** | Arial | Georgia, Calibri, Cambria, Trebuchet MS |
- 中英文混排时:中文使用微软雅黑,英文使用所选字体
- 优先使用系统自带字体,确保跨平台兼容
- 标题和正文可使用不同字体配对(如 Georgia + Calibri

View File

@@ -0,0 +1,209 @@
---
name: design-style-skill
description: >
Select a consistent visual design system for PPT slides using radius/spacing style recipes.
Use when users ask for overall style direction or component styling consistency.
Includes Sharp/Soft/Rounded/Pill recipes, component mappings, typography/spacing rules, and mixing guidance.
Triggers: 风格, style, radius, spacing, 圆角, 间距, PPT风格, 视觉风格, design style, component style.
---
# Style Recipes - PPT视觉风格系统
同一套设计可通过调整圆角rectRadius和间距呈现4种不同风格。根据场景选择合适的风格配方。
> **单位说明**: PptxGenJS 使用英寸(inch)作为单位。幻灯片尺寸为 10" × 5.625" (LAYOUT_16x9)
## 风格概览
| 风格 | 圆角范围 | 间距范围 | 适合场景 |
|---|---|---|---|
| **Sharp & Compact** | 0 ~ 0.05" | 紧凑 | 数据密集型、表格、专业报告 |
| **Soft & Balanced** | 0.08" ~ 0.12" | 适中 | 企业汇报、商务演示、通用PPT |
| **Rounded & Spacious** | 0.15" ~ 0.25" | 宽松 | 产品介绍、营销演示、创意展示 |
| **Pill & Airy** | 0.3" ~ 0.5" | 通透 | 品牌展示、发布会、高端演示 |
---
## Sharp & Compact锐利紧凑
**视觉特征**: 方正、信息密度高、专业严肃感。
### Token 配方
| 类别 | 值 (英寸) | 说明 |
|---|---|---|
| 圆角-小 | 0" | 完全直角 |
| 圆角-中 | 0.03" | 微圆角 |
| 圆角-大 | 0.05" | 小圆角 |
| 元素内边距 | 0.1" ~ 0.15" | 紧凑 |
| 元素间距 | 0.1" ~ 0.2" | 紧凑 |
| 页面边距 | 0.3" | 较窄 |
| 区块间距 | 0.25" ~ 0.35" | 紧凑 |
---
## Soft & Balanced柔和均衡
**视觉特征**: 适中的圆角、舒适的留白、专业又不失亲和。
### Token 配方
| 类别 | 值 (英寸) | 说明 |
|---|---|---|
| 圆角-小 | 0.05" | 小圆角 |
| 圆角-中 | 0.08" | 中等圆角 |
| 圆角-大 | 0.12" | 较大圆角 |
| 元素内边距 | 0.15" ~ 0.2" | 适中 |
| 元素间距 | 0.15" ~ 0.25" | 适中 |
| 页面边距 | 0.4" | 标准 |
| 区块间距 | 0.35" ~ 0.5" | 适中 |
---
## Rounded & Spacious圆润宽松
**视觉特征**: 大圆角、充裕留白、友好亲切、现代感。
### Token 配方
| 类别 | 值 (英寸) | 说明 |
|---|---|---|
| 圆角-小 | 0.1" | 中等圆角 |
| 圆角-中 | 0.15" | 大圆角 |
| 圆角-大 | 0.25" | 很大圆角 |
| 元素内边距 | 0.2" ~ 0.3" | 宽松 |
| 元素间距 | 0.25" ~ 0.4" | 宽松 |
| 页面边距 | 0.5" | 较宽 |
| 区块间距 | 0.5" ~ 0.7" | 宽松 |
---
## Pill & Airy胶囊通透
**视觉特征**: 全圆角胶囊形、大量留白、轻盈通透、品牌展示感强。
### Token 配方
| 类别 | 值 (英寸) | 说明 |
|---|---|---|
| 圆角-小 | 0.2" | 大圆角 |
| 圆角-中 | 0.3" | 胶囊形 |
| 圆角-大 | 0.5" | 完全胶囊 |
| 元素内边距 | 0.25" ~ 0.4" | 通透 |
| 元素间距 | 0.3" ~ 0.5" | 通透 |
| 页面边距 | 0.6" | 宽 |
| 区块间距 | 0.6" ~ 0.9" | 通透 |
---
# 组件级风格映射表
| 组件 | Sharp | Soft | Rounded | Pill |
|---|---|---|---|---|
| **按钮/标签** | rectRadius: 0 | rectRadius: 0.05 | rectRadius: 0.1 | rectRadius: 0.2 |
| **卡片/容器** | rectRadius: 0.03 | rectRadius: 0.1 | rectRadius: 0.2 | rectRadius: 0.3 |
| **图片容器** | rectRadius: 0 | rectRadius: 0.08 | rectRadius: 0.15 | rectRadius: 0.25 |
| **输入框形状** | rectRadius: 0 | rectRadius: 0.05 | rectRadius: 0.1 | rectRadius: 0.2 |
| **徽章/Badge** | rectRadius: 0.02 | rectRadius: 0.05 | rectRadius: 0.08 | rectRadius: 0.15 |
| **头像框** | rectRadius: 0 | rectRadius: 0.1 | rectRadius: 0.2 | rectRadius: 0.5 (圆形) |
### PptxGenJS 圆角示例
```javascript
// Sharp 风格卡片
slide.addShape("rect", {
x: 0.5, y: 1, w: 4, h: 2.5,
fill: { color: "F5F5F5" },
rectRadius: 0.03
});
// Rounded 风格卡片
slide.addShape("rect", {
x: 0.5, y: 1, w: 4, h: 2.5,
fill: { color: "F5F5F5" },
rectRadius: 0.2
});
// Pill 风格按钮 (高度0.4"时rectRadius设为0.2"即为胶囊形)
slide.addShape("rect", {
x: 3, y: 4, w: 2, h: 0.4,
fill: { color: "4A90D9" },
rectRadius: 0.2
});
```
---
# 混搭原则
## 1. 外层容器 ≥ 内层圆角
```javascript
// 正确:外 > 内
card: rectRadius: 0.2
button: rectRadius: 0.1
// 错误:内 > 外 → 视觉溢出感
card: rectRadius: 0.1
button: rectRadius: 0.2
```
## 2. 信息密度决定间距
| 区域类型 | 推荐风格 |
|---|---|
| 数据展示区 | Sharp / Soft紧凑间距 |
| 内容浏览区 | Rounded / Pill宽松间距 |
| 标题区域 | Soft / Rounded适中间距 |
## 3. 圆角与元素高度的关系
| 元素高度 | Sharp | Soft | Rounded | Pill |
|---|---|---|---|---|
| 小 (< 0.3") | 0" | 0.03" | 0.08" | 高度/2 |
| 中 (0.3" ~ 0.6") | 0.02" | 0.05" | 0.12" | 高度/2 |
| 大 (0.6" ~ 1.2") | 0.03" | 0.08" | 0.2" | 0.3" |
| 超大 (> 1.2") | 0.05" | 0.12" | 0.25" | 0.4" |
> **Pill风格提示**: 要实现完美胶囊形,设置 `rectRadius = 元素高度 / 2`
---
# Typography 排版规范 (PPT)
| 用途 | 字号 (pt) | 说明 |
|---|---|---|
| 注释/来源 | 10 ~ 12 | 最小可读字号 |
| 正文/描述 | 14 ~ 16 | 标准正文 |
| 副标题 | 18 ~ 22 | 次要标题 |
| 标题 | 28 ~ 36 | 页面标题 |
| 大标题 | 44 ~ 60 | 封面/章节标题 |
| 数据高亮 | 60 ~ 96 | 关键数字展示 |
---
# Spacing 间距规范 (PPT)
基于10" × 5.625"幻灯片尺寸:
| 用途 | 推荐值 (英寸) |
|---|---|
| 图标与文字间距 | 0.08" ~ 0.15" |
| 列表项间距 | 0.15" ~ 0.25" |
| 卡片内边距 | 0.2" ~ 0.4" |
| 元素组间距 | 0.3" ~ 0.5" |
| 页面安全边距 | 0.4" ~ 0.6" |
| 主要区块间距 | 0.5" ~ 0.8" |
---
# 快速选择指南
| 演示类型 | 推荐风格 | 原因 |
|---|---|---|
| 财务/数据报告 | Sharp & Compact | 信息密度高,专业严谨 |
| 企业汇报/商务 | Soft & Balanced | 平衡专业与友好 |
| 产品介绍/营销 | Rounded & Spacious | 现代感,亲切感 |
| 发布会/品牌展示 | Pill & Airy | 高端感,视觉冲击 |
| 培训/教育 | Soft / Rounded | 清晰易读,友好 |
| 技术分享 | Sharp / Soft | 专业,信息清晰 |

View File

@@ -0,0 +1,193 @@
---
name: ppt-editing-skill
description: "Edit existing PowerPoint files or templates with XML-safe workflows. Use for template-based deck updates: analyze layouts, map content to slides, duplicate/reorder/delete slides safely, edit slide XML in parallel, clean orphaned assets, and repack validated PPTX output."
license: Proprietary. LICENSE.txt has complete terms
---
# Editing Presentations
## Template-Based Workflow
When using an existing presentation as a template:
1. **Copy and analyze**:
```bash
cp /path/to/user-provided.pptx template.pptx
python -m markitdown template.pptx > template.md
```
Review `template.md` to see placeholder text and slide structure.
2. **Plan slide mapping**: For each content section, choose a template slide.
⚠️ **USE VARIED LAYOUTS** — monotonous presentations are a common failure mode. Don't default to basic title + bullet slides. Actively seek out:
- Multi-column layouts (2-column, 3-column)
- Image + text combinations
- Full-bleed images with text overlay
- Quote or callout slides
- Section dividers
- Stat/number callouts
- Icon grids or icon + text rows
**Avoid:** Repeating the same text-heavy layout for every slide.
Match content type to layout style (e.g., key points → bullet slide, team info → multi-column, testimonials → quote slide).
3. **Unpack**
4. **Build presentation** (do this yourself, not with subagents):
- Delete unwanted slides (remove from `<p:sldIdLst>`)
- Duplicate slides you want to reuse (`add_slide.py`)
- Reorder slides in `<p:sldIdLst>`
- **Complete all structural changes before step 5**
5. **Edit content**: Update text in each `slide{N}.xml`.
**Use subagents here if available** — slides are separate XML files, so subagents can edit in parallel.
6. **Clean**
7. **Pack**
## Output Structure
Copy the user-provided file to `template.pptx` in cwd. This preserves the original and gives a predictable name for all downstream scripts.
```bash
cp /path/to/user-provided.pptx template.pptx
```
```text
./
├── template.pptx # Copy of user-provided file (never modified)
├── template.md # markitdown extraction
├── unpacked/ # Editable XML tree
└── edited.pptx # Final repacked deck
```
Minimum expected deliverable: `edited.pptx`.
---
## Scripts
| Script | Purpose |
|--------|---------|
| `unpack.py` | Extract and pretty-print PPTX |
| `add_slide.py` | Duplicate slide or create from layout |
| `clean.py` | Remove orphaned files |
| `pack.py` | Repack with validation |
Removes slides not in `<p:sldIdLst>`, unreferenced media, orphaned rels.
Always write to `/tmp/` first, then copy to the final path. Python's `zipfile` module uses `seek` internally, which fails on some volume mounts (e.g. Docker bind mounts). Writing to a local temp path avoids this.
Validates, repairs, condenses XML, re-encodes smart quotes.
---
## Slide Operations
Slide order is in `ppt/presentation.xml` → `<p:sldIdLst>`.
**Reorder**: Rearrange `<p:sldId>` elements.
**Delete**: Remove `<p:sldId>`, then run `clean.py`.
**Add**: Use `add_slide.py`. Never manually copy slide files—the script handles notes references, Content_Types.xml, and relationship IDs that manual copying misses.
---
## Editing Content
**Subagents:** If available, use them here (after completing step 4). Each slide is a separate XML file, so subagents can edit in parallel. In your prompt to subagents, include:
- The slide file path(s) to edit
- **"Use the Edit tool for all changes"**
- The formatting rules and common pitfalls below
For each slide:
1. Read the slide's XML
2. Identify ALL placeholder content—text, images, charts, icons, captions
3. Replace each placeholder with final content
**Use the Edit tool, not sed or Python scripts.** The Edit tool forces specificity about what to replace and where, yielding better reliability.
### Formatting Rules
- **Bold all headers, subheadings, and inline labels**: Use `b="1"` on `<a:rPr>`. This includes:
- Slide titles
- Section headers within a slide
- Inline labels like (e.g.: "Status:", "Description:") at the start of a line
- **Never use unicode bullets (•)**: Use proper list formatting with `<a:buChar>` or `<a:buAutoNum>`
- **Bullet consistency**: Let bullets inherit from the layout. Only specify `<a:buChar>` or `<a:buNone>`.
---
## Common Pitfalls
### Template Adaptation
When source content has fewer items than the template:
- **Remove excess elements entirely** (images, shapes, text boxes), don't just clear text
- Check for orphaned visuals after clearing text content
- Run content QA with `markitdown` to catch mismatched counts
When replacing text with different length content:
- **Shorter replacements**: Usually safe
- **Longer replacements**: May overflow or wrap unexpectedly
- Verify with `markitdown` after text changes
- Consider truncating or splitting content to fit the template's design constraints
**Template slots ≠ Source items**: If template has 4 team members but source has 3 users, delete the 4th member's entire group (image + text boxes), not just the text.
### Multi-Item Content
If source has multiple items (numbered lists, multiple sections), create separate `<a:p>` elements for each — **never concatenate into one string**.
**❌ WRONG** — all items in one paragraph:
```xml
<a:p>
<a:r><a:rPr .../><a:t>Step 1: Do the first thing. Step 2: Do the second thing.</a:t></a:r>
</a:p>
```
**✅ CORRECT** — separate paragraphs with bold headers:
```xml
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 1</a:t></a:r>
</a:p>
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" .../><a:t>Do the first thing.</a:t></a:r>
</a:p>
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 2</a:t></a:r>
</a:p>
<!-- continue pattern -->
```
Copy `<a:pPr>` from the original paragraph to preserve line spacing. Use `b="1"` on headers.
### Smart Quotes
Handled automatically by unpack/pack. But the Edit tool converts smart quotes to ASCII.
**When adding new text with quotes, use XML entities:**
```xml
<a:t>the &#x201C;Agreement&#x201D;</a:t>
```
| Character | Name | Unicode | XML Entity |
|-----------|------|---------|------------|
| `"` | Left double quote | U+201C | `&#x201C;` |
| `"` | Right double quote | U+201D | `&#x201D;` |
| `'` | Left single quote | U+2018 | `&#x2018;` |
| `'` | Right single quote | U+2019 | `&#x2019;` |
### Other
- **Whitespace**: Use `xml:space="preserve"` on `<a:t>` with leading/trailing spaces
- **XML parsing**: Use `defusedxml.minidom`, not `xml.etree.ElementTree` (corrupts namespaces)

View File

@@ -0,0 +1,155 @@
---
name: ppt-orchestra-skill
description: "Plan and orchestrate multi-slide PowerPoint creation from scratch. Use before generating a full deck with subagents: classify each slide type, enforce visual variety, set typography/spacing rules, and run text-based QA to catch content issues."
license: Proprietary. LICENSE.txt has complete terms
---
# Slide Page Types (Standard)
For slide-by-slide generation (one JS file per slide), classify **every slide** as **exactly one** of these 5 page types. This keeps structure consistent and prevents "random layout drift".
1. **Cover Page**
- **Use for**: opening + tone setting
- **Content**: big title, subtitle/presenter, date/occasion, strong background/motif
2. **Table of Contents**
- **Use for**: navigation + expectation setting (35 sections)
- **Content**: section list (optional icons / page numbers)
3. **Section Divider**
- **Use for**: clear transitions between major parts
- **Content**: section number + title (+ optional 12 line intro)
4. **Content Page** (pick a subtype)
- **Text**: bullets/quotes/short paragraphs (still add icons/shapes)
- **Mixed media**: two-column / half-bleed image + text overlay
- **Data visualization**: chart + 13 key takeaways + **source**
- **Comparison**: side-by-side columns/cards (A vs B, pros/cons)
- **Timeline / process**: steps with arrows, journey, phases
- **Image showcase**: hero image, gallery, or visual-first layout
5. **Summary / Closing Page**
- **Use for**: wrap-up + action
- **Content**: key takeaways, CTA/next steps, contact/QR, thank-you
**Layout options:**
- Two-column (text left, illustration on right)
- Icon + text rows (icon in colored circle, bold header, description below)
- 2x2 or 2x3 grid (image on one side, grid of content blocks on other)
- Half-bleed image (full left or right side) with content overlay
**Data display:**
- Large stat callouts (big numbers 60-72pt with small labels below)
- Comparison columns (before/after, pros/cons, side-by-side options)
- Timeline or process flow (numbered steps, arrows)
**Visual polish:**
- Icons in small colored circles next to section headers
- Italic accent text for key stats or taglines
### Typography
**Choose an interesting font pairing** — don't default to Arial. Pick a header font with personality and pair it with a clean body font.
| Header Font | Body Font |
|-------------|-----------|
| Georgia | Calibri |
| Arial Black | Arial |
| Calibri | Calibri Light |
| Cambria | Calibri |
| Trebuchet MS | Calibri |
| Impact | Arial |
| Palatino | Garamond |
| Consolas | Calibri |
| Element | Size |
|---------|------|
| Slide title | 36-44pt bold |
| Section header | 20-24pt bold |
| Body text | 14-16pt |
| Captions | 10-12pt muted |
### Spacing
- 0.5" minimum margins
- 0.3-0.5" between content blocks
- Leave breathing room—don't fill every inch
### Avoid (Common Mistakes)
- **Don't repeat the same layout** — vary columns, cards, and callouts across slides
- **Don't center body text** — left-align paragraphs and lists; center only titles
- **Don't skimp on size contrast** — titles need 36pt+ to stand out from 14-16pt body
- **Don't default to blue** — pick colors that reflect the specific topic
- **Don't mix spacing randomly** — choose 0.3" or 0.5" gaps and use consistently
- **Don't style one slide and leave the rest plain** — commit fully or keep it simple throughout
- **Don't create text-only slides** — add images, icons, charts, or visual elements; avoid plain title + bullets
- **Don't forget text box padding** — when aligning lines or shapes with text edges, set `margin: 0` on the text box or offset the shape to account for padding
- **Don't use low-contrast elements** — icons AND text need strong contrast against the background; avoid light text on light backgrounds or dark text on dark backgrounds
- **NEVER use accent lines under titles** — these are a hallmark of AI-generated slides; use whitespace or background color instead
## Compiling Slides
After all slide JS files are generated in `slides/`, create `slides/compile.js` to compile them into a single PPTX:
```javascript
// slides/compile.js
const pptxgen = require('pptxgenjs');
const pres = new pptxgen();
pres.layout = 'LAYOUT_16x9';
const theme = {
primary: "22223b", // dark color for backgrounds/text
secondary: "4a4e69", // secondary accent
accent: "9a8c98", // highlight color
light: "c9ada7", // light accent
bg: "f2e9e4" // background color
};
for (let i = 1; i <= 12; i++) { // adjust count as needed
const num = String(i).padStart(2, '0');
const slideModule = require(`./slide-${num}.js`);
slideModule.createSlide(pres, theme);
}
pres.writeFile({ fileName: './output/presentation.pptx' });
```
Run with: `cd slides && node compile.js`
---
## QA (Required)
**Assume there are problems. Your job is to find them.**
Your first render is almost never correct. Approach QA as a bug hunt, not a confirmation step. If you found zero issues on first inspection, you weren't looking hard enough.
### Content QA
```bash
python -m markitdown output.pptx
```
Check for missing content, typos, wrong order.
**When using templates, check for leftover placeholder text:**
```bash
python -m markitdown output.pptx | grep -iE "xxxx|lorem|ipsum|this.*(page|slide).*layout"
```
If grep returns results, fix them before declaring success.
### Verification Loop
1. Generate slides → Extract text with `python -m markitdown output.pptx` → Review content
2. **List issues found** (if none found, look again more critically)
3. Fix issues
4. **Re-verify affected slides** — one fix often creates another problem
5. Repeat until a full pass reveals no new issues
**Do not declare success until you've completed at least one fix-and-verify cycle.**
---
## Dependencies
- `pip install "markitdown[pptx]"` - text extraction
- `npm install -g pptxgenjs` - creating from scratch

View File

@@ -0,0 +1,282 @@
---
name: slide-making-skill
description: "Implement single-slide PowerPoint pages with PptxGenJS. Use when writing or fixing slide JS files: dimensions, positioning, text/image/chart APIs, styling rules, and export expectations for native .pptx output."
---
# PptxGenJS Slide Making Skill
This skill teaches how to generate native .pptx slides using PptxGenJS (JavaScript).
## PptxGenJS Reference
**Read [pptxgenjs.md](pptxgenjs.md) for the complete PptxGenJS API reference**, including:
- Setup & basic structure
- Text & formatting
- Lists & bullets
- Shapes & shadows
- Images & icons
- Slide backgrounds
- Tables & charts
---
## Font Rules
### Font Family Standards
| Language | Default | Alternatives |
|----------|---------|--------------|
| **Chinese** | Microsoft YaHei (微软雅黑) | — |
| **English** | Arial | Georgia, Calibri, Cambria, Trebuchet MS |
```javascript
fontFace: "Microsoft YaHei" // Chinese text
fontFace: "Arial" // English text (or approved alternative)
```
Use system-safe fonts for cross-platform compatibility. Header/body can use different fonts (e.g., Georgia + Calibri).
### No Bold for Body Text
**Plain body text and caption/legend text must NOT use bold.**
- Body paragraphs, descriptions → normal weight
- Captions, legends, footnotes → normal weight
- Reserve bold for titles and headings only
```javascript
// ✅ Correct
slide.addText("Main Title", { bold: true, fontSize: 36, fontFace: "Arial" });
slide.addText("Body text here.", { bold: false, fontSize: 14, fontFace: "Arial" });
// ❌ Wrong
slide.addText("Body text here.", { bold: true, fontSize: 14 });
```
---
## Color Palette Rules (MANDATORY)
### Strict Palette Adherence
**Use ONLY the provided color palette. Do NOT create or modify colors.**
- All colors must come from the user-provided palette
- Do NOT use colors outside the palette
- Do NOT modify palette colors (brightness, saturation, mixing)
- **Only exception**: Add transparency using the `transparency` property (0-100)
```javascript
// ✅ Correct: Using palette colors
slide.addShape(pres.shapes.RECTANGLE, { fill: { color: theme.primary } });
slide.addText("Title", { color: theme.accent });
// ❌ Wrong: Colors outside palette
slide.addShape(pres.shapes.RECTANGLE, { fill: { color: "1a1a2e" } });
```
### No Gradients
**Gradients are prohibited. Use solid colors only.**
```javascript
// ✅ Correct: Solid colors
slide.background = { color: theme.bg };
// ✅ Correct: Solid + transparency for overlay
slide.addShape(pres.shapes.RECTANGLE, { fill: { color: theme.accent, transparency: 50 } });
```
### No Animations
**Animations and transitions are prohibited.** All slides must be static.
---
## Page Number Badge (REQUIRED)
All slides **except Cover Page** MUST include a page number badge in the bottom-right corner.
- **Position**: x: 9.3", y: 5.1"
- Show current number only (e.g. `3` or `03`), NOT "3/12"
- Use palette colors, keep subtle
### Circle Badge (Default)
```javascript
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: "Arial",
color: "FFFFFF", bold: true,
align: "center", valign: "middle"
});
```
### Pill Badge
```javascript
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: "Arial",
color: "FFFFFF", bold: true,
align: "center", valign: "middle"
});
```
---
## Theme Object Contract (MANDATORY)
The compile script passes a theme object with these **exact keys**:
| Key | Purpose | Example |
|-----|---------|---------|
| `theme.primary` | Darkest color, titles | `"22223b"` |
| `theme.secondary` | Dark accent, body text | `"4a4e69"` |
| `theme.accent` | Mid-tone accent | `"9a8c98"` |
| `theme.light` | Light accent | `"c9ada7"` |
| `theme.bg` | Background color | `"f2e9e4"` |
**NEVER use other key names** like `background`, `text`, `muted`, `darkest`, `lightest`.
---
## Subagent Output Format
Each subagent outputs a **complete, runnable JS file**:
```javascript
// slide-01.js
const pptxgen = require("pptxgenjs");
const slideConfig = {
type: 'cover',
index: 1,
title: 'Presentation Title'
};
// ⚠️ MUST be synchronous (not async)
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: "Arial", // English text uses Arial
color: theme.primary, bold: true, align: "center"
});
return slide;
}
// Standalone preview - use slide-specific filename (slide-XX-preview.pptx)
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);
// Replace XX with actual slide index (01, 02, etc.) to avoid conflicts
pres.writeFile({ fileName: "slide-01-preview.pptx" });
}
module.exports = { createSlide, slideConfig };
```
---
## Critical Pitfalls
### NEVER use async/await in createSlide()
```javascript
// ❌ WRONG - compile.js won't await
async function createSlide(pres, theme) { ... }
// ✅ CORRECT
function createSlide(pres, theme) { ... }
```
### NEVER use "#" with hex colors
```javascript
color: "FF0000" // ✅ CORRECT
color: "#FF0000" // ❌ CORRUPTS FILE
```
### NEVER encode opacity in hex strings
```javascript
shadow: { color: "00000020" } // ❌ CORRUPTS FILE
shadow: { color: "000000", opacity: 0.12 } // ✅ CORRECT
```
### Prevent text wrapping in titles
```javascript
// ✅ Use fit:'shrink' for long titles
slide.addText("Long Title Here", {
x: 0.5, y: 2, w: 9, h: 1,
fontSize: 48, fit: "shrink"
});
```
---
## Quick Reference
- **Dimensions**: 10" × 5.625" (LAYOUT_16x9)
- **Colors**: 6-char hex without # (e.g., `"FF0000"`)
- **English font**: Arial (default), or approved alternatives
- **Chinese font**: Microsoft YaHei
- **Page badge position**: x: 9.3", y: 5.1"
---
## QA (Required)
**Assume there are problems. Your job is to find them.**
Your first render is almost never correct. Approach QA as a bug hunt, not a confirmation step. If you found zero issues on first inspection, you weren't looking hard enough.
### Content QA
```bash
python -m markitdown slide-XX-preview.pptx
```
Check for missing content, typos, wrong order.
**Check for leftover placeholder text:**
```bash
python -m markitdown slide-XX-preview.pptx | grep -iE "xxxx|lorem|ipsum|placeholder"
```
If grep returns results, fix them before declaring success.
### Verification Loop
1. Generate slide → Extract text with `python -m markitdown slide-XX-preview.pptx` → Review content
2. **List issues found** (if none found, look again more critically)
3. Fix issues
4. **Re-verify** — one fix often creates another problem
5. Repeat until verification reveals no new issues
**Do not declare success until you've completed at least one fix-and-verify cycle.**
---

View File

@@ -0,0 +1,420 @@
# PptxGenJS Tutorial
## Setup & Basic Structure
```javascript
const pptxgen = require("pptxgenjs");
let pres = new pptxgen();
pres.layout = 'LAYOUT_16x9'; // or 'LAYOUT_16x10', 'LAYOUT_4x3', 'LAYOUT_WIDE'
pres.author = 'Your Name';
pres.title = 'Presentation Title';
let slide = pres.addSlide();
slide.addText("Hello World!", { x: 0.5, y: 0.5, fontSize: 36, color: "363636" });
pres.writeFile({ fileName: "Presentation.pptx" });
```
## Layout Dimensions
Slide dimensions (coordinates in inches):
- `LAYOUT_16x9`: 10" × 5.625" (default)
- `LAYOUT_16x10`: 10" × 6.25"
- `LAYOUT_4x3`: 10" × 7.5"
- `LAYOUT_WIDE`: 13.3" × 7.5"
---
## Text & Formatting
```javascript
// Basic text
slide.addText("Simple Text", {
x: 1, y: 1, w: 8, h: 2, fontSize: 24, fontFace: "Arial",
color: "363636", bold: true, align: "center", valign: "middle"
});
// Character spacing (use charSpacing, not letterSpacing which is silently ignored)
slide.addText("SPACED TEXT", { x: 1, y: 1, w: 8, h: 1, charSpacing: 6 });
// Rich text arrays
slide.addText([
{ text: "Bold ", options: { bold: true } },
{ text: "Italic ", options: { italic: true } }
], { x: 1, y: 3, w: 8, h: 1 });
// Multi-line text (requires breakLine: true)
slide.addText([
{ text: "Line 1", options: { breakLine: true } },
{ text: "Line 2", options: { breakLine: true } },
{ text: "Line 3" } // Last item doesn't need breakLine
], { x: 0.5, y: 0.5, w: 8, h: 2 });
// Text box margin (internal padding)
slide.addText("Title", {
x: 0.5, y: 0.3, w: 9, h: 0.6,
margin: 0 // Use 0 when aligning text with other elements like shapes or icons
});
```
**Tip:** Text boxes have internal margin by default. Set `margin: 0` when you need text to align precisely with shapes, lines, or icons at the same x-position.
---
## Lists & Bullets
```javascript
// ✅ CORRECT: Multiple bullets
slide.addText([
{ text: "First item", options: { bullet: true, breakLine: true } },
{ text: "Second item", options: { bullet: true, breakLine: true } },
{ text: "Third item", options: { bullet: true } }
], { x: 0.5, y: 0.5, w: 8, h: 3 });
// ❌ WRONG: Never use unicode bullets
slide.addText("• First item", { ... }); // Creates double bullets
// Sub-items and numbered lists
{ text: "Sub-item", options: { bullet: true, indentLevel: 1 } }
{ text: "First", options: { bullet: { type: "number" }, breakLine: true } }
```
---
## Shapes
```javascript
slide.addShape(pres.shapes.RECTANGLE, {
x: 0.5, y: 0.8, w: 1.5, h: 3.0,
fill: { color: "FF0000" }, line: { color: "000000", width: 2 }
});
slide.addShape(pres.shapes.OVAL, { x: 4, y: 1, w: 2, h: 2, fill: { color: "0000FF" } });
slide.addShape(pres.shapes.LINE, {
x: 1, y: 3, w: 5, h: 0, line: { color: "FF0000", width: 3, dashType: "dash" }
});
// With transparency
slide.addShape(pres.shapes.RECTANGLE, {
x: 1, y: 1, w: 3, h: 2,
fill: { color: "0088CC", transparency: 50 }
});
// Rounded rectangle (rectRadius only works with ROUNDED_RECTANGLE, not RECTANGLE)
// ⚠️ Don't pair with rectangular accent overlays — they won't cover rounded corners. Use RECTANGLE instead.
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, {
x: 1, y: 1, w: 3, h: 2,
fill: { color: "FFFFFF" }, rectRadius: 0.1
});
// With shadow
slide.addShape(pres.shapes.RECTANGLE, {
x: 1, y: 1, w: 3, h: 2,
fill: { color: "FFFFFF" },
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.15 }
});
```
Shadow options:
| Property | Type | Range | Notes |
|----------|------|-------|-------|
| `type` | string | `"outer"`, `"inner"` | |
| `color` | string | 6-char hex (e.g. `"000000"`) | No `#` prefix, no 8-char hex — see Common Pitfalls |
| `blur` | number | 0-100 pt | |
| `offset` | number | 0-200 pt | **Must be non-negative** — negative values corrupt the file |
| `angle` | number | 0-359 degrees | Direction the shadow falls (135 = bottom-right, 270 = upward) |
| `opacity` | number | 0.0-1.0 | Use this for transparency, never encode in color string |
To cast a shadow upward (e.g. on a footer bar), use `angle: 270` with a positive offset — do **not** use a negative offset.
**Note**: Gradient fills are not natively supported. Use a gradient image as a background instead.
---
## Images
### Image Sources
```javascript
// From file path
slide.addImage({ path: "images/chart.png", x: 1, y: 1, w: 5, h: 3 });
// From URL
slide.addImage({ path: "https://example.com/image.jpg", x: 1, y: 1, w: 5, h: 3 });
// From base64 (faster, no file I/O)
slide.addImage({ data: "image/png;base64,iVBORw0KGgo...", x: 1, y: 1, w: 5, h: 3 });
```
### Image Options
```javascript
slide.addImage({
path: "image.png",
x: 1, y: 1, w: 5, h: 3,
rotate: 45, // 0-359 degrees
rounding: true, // Circular crop
transparency: 50, // 0-100
flipH: true, // Horizontal flip
flipV: false, // Vertical flip
altText: "Description", // Accessibility
hyperlink: { url: "https://example.com" }
});
```
### Image Sizing Modes
```javascript
// Contain - fit inside, preserve ratio
{ sizing: { type: 'contain', w: 4, h: 3 } }
// Cover - fill area, preserve ratio (may crop)
{ sizing: { type: 'cover', w: 4, h: 3 } }
// Crop - cut specific portion
{ sizing: { type: 'crop', x: 0.5, y: 0.5, w: 2, h: 2 } }
```
### Calculate Dimensions (preserve aspect ratio)
```javascript
const origWidth = 1978, origHeight = 923, maxHeight = 3.0;
const calcWidth = maxHeight * (origWidth / origHeight);
const centerX = (10 - calcWidth) / 2;
slide.addImage({ path: "image.png", x: centerX, y: 1.2, w: calcWidth, h: maxHeight });
```
### Supported Formats
- **Standard**: PNG, JPG, GIF (animated GIFs work in Microsoft 365)
- **SVG**: Works in modern PowerPoint/Microsoft 365
---
## Icons
Use react-icons to generate SVG icons, then rasterize to PNG for universal compatibility.
### Setup
```javascript
const React = require("react");
const ReactDOMServer = require("react-dom/server");
const sharp = require("sharp");
const { FaCheckCircle, FaChartLine } = require("react-icons/fa");
function renderIconSvg(IconComponent, color = "#000000", size = 256) {
return ReactDOMServer.renderToStaticMarkup(
React.createElement(IconComponent, { color, size: String(size) })
);
}
async function iconToBase64Png(IconComponent, color, size = 256) {
const svg = renderIconSvg(IconComponent, color, size);
const pngBuffer = await sharp(Buffer.from(svg)).png().toBuffer();
return "image/png;base64," + pngBuffer.toString("base64");
}
```
### Add Icon to Slide
```javascript
const iconData = await iconToBase64Png(FaCheckCircle, "#4472C4", 256);
slide.addImage({
data: iconData,
x: 1, y: 1, w: 0.5, h: 0.5 // Size in inches
});
```
**Note**: Use size 256 or higher for crisp icons. The size parameter controls the rasterization resolution, not the display size on the slide (which is set by `w` and `h` in inches).
### Icon Libraries
Install: `npm install -g react-icons react react-dom sharp`
Popular icon sets in react-icons:
- `react-icons/fa` - Font Awesome
- `react-icons/md` - Material Design
- `react-icons/hi` - Heroicons
- `react-icons/bi` - Bootstrap Icons
---
## Slide Backgrounds
```javascript
// Solid color
slide.background = { color: "F1F1F1" };
// Color with transparency
slide.background = { color: "FF3399", transparency: 50 };
// Image from URL
slide.background = { path: "https://example.com/bg.jpg" };
// Image from base64
slide.background = { data: "image/png;base64,iVBORw0KGgo..." };
```
---
## Tables
```javascript
slide.addTable([
["Header 1", "Header 2"],
["Cell 1", "Cell 2"]
], {
x: 1, y: 1, w: 8, h: 2,
border: { pt: 1, color: "999999" }, fill: { color: "F1F1F1" }
});
// Advanced with merged cells
let tableData = [
[{ text: "Header", options: { fill: { color: "6699CC" }, color: "FFFFFF", bold: true } }, "Cell"],
[{ text: "Merged", options: { colspan: 2 } }]
];
slide.addTable(tableData, { x: 1, y: 3.5, w: 8, colW: [4, 4] });
```
---
## Charts
```javascript
// Bar chart
slide.addChart(pres.charts.BAR, [{
name: "Sales", labels: ["Q1", "Q2", "Q3", "Q4"], values: [4500, 5500, 6200, 7100]
}], {
x: 0.5, y: 0.6, w: 6, h: 3, barDir: 'col',
showTitle: true, title: 'Quarterly Sales'
});
// Line chart
slide.addChart(pres.charts.LINE, [{
name: "Temp", labels: ["Jan", "Feb", "Mar"], values: [32, 35, 42]
}], { x: 0.5, y: 4, w: 6, h: 3, lineSize: 3, lineSmooth: true });
// Pie chart
slide.addChart(pres.charts.PIE, [{
name: "Share", labels: ["A", "B", "Other"], values: [35, 45, 20]
}], { x: 7, y: 1, w: 5, h: 4, showPercent: true });
```
### Better-Looking Charts
Default charts look dated. Apply these options for a modern, clean appearance:
```javascript
slide.addChart(pres.charts.BAR, chartData, {
x: 0.5, y: 1, w: 9, h: 4, barDir: "col",
// Custom colors (match your presentation palette)
chartColors: ["0D9488", "14B8A6", "5EEAD4"],
// Clean background
chartArea: { fill: { color: "FFFFFF" }, roundedCorners: true },
// Muted axis labels
catAxisLabelColor: "64748B",
valAxisLabelColor: "64748B",
// Subtle grid (value axis only)
valGridLine: { color: "E2E8F0", size: 0.5 },
catGridLine: { style: "none" },
// Data labels on bars
showValue: true,
dataLabelPosition: "outEnd",
dataLabelColor: "1E293B",
// Hide legend for single series
showLegend: false,
});
```
**Key styling options:**
- `chartColors: [...]` - hex colors for series/segments
- `chartArea: { fill, border, roundedCorners }` - chart background
- `catGridLine/valGridLine: { color, style, size }` - grid lines (`style: "none"` to hide)
- `lineSmooth: true` - curved lines (line charts)
- `legendPos: "r"` - legend position: "b", "t", "l", "r", "tr"
---
## Slide Masters
```javascript
pres.defineSlideMaster({
title: 'TITLE_SLIDE', background: { color: '283A5E' },
objects: [{
placeholder: { options: { name: 'title', type: 'title', x: 1, y: 2, w: 8, h: 2 } }
}]
});
let titleSlide = pres.addSlide({ masterName: "TITLE_SLIDE" });
titleSlide.addText("My Title", { placeholder: "title" });
```
---
## Common Pitfalls
⚠️ These issues cause file corruption, visual bugs, or broken output. Avoid them.
1. **NEVER use "#" with hex colors** - causes file corruption
```javascript
color: "FF0000" // ✅ CORRECT
color: "#FF0000" // ❌ WRONG
```
2. **NEVER encode opacity in hex color strings** - 8-char colors (e.g., `"00000020"`) corrupt the file. Use the `opacity` property instead.
```javascript
shadow: { type: "outer", blur: 6, offset: 2, color: "00000020" } // ❌ CORRUPTS FILE
shadow: { type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.12 } // ✅ CORRECT
```
3. **Use `bullet: true`** - NEVER unicode symbols like "•" (creates double bullets)
4. **Use `breakLine: true`** between array items or text runs together
5. **Avoid `lineSpacing` with bullets** - causes excessive gaps; use `paraSpaceAfter` instead
6. **Each presentation needs fresh instance** - don't reuse `pptxgen()` objects
7. **NEVER reuse option objects across calls** - PptxGenJS mutates objects in-place (e.g. converting shadow values to EMU). Sharing one object between multiple calls corrupts the second shape.
```javascript
const shadow = { type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.15 };
slide.addShape(pres.shapes.RECTANGLE, { shadow, ... }); // ❌ second call gets already-converted values
slide.addShape(pres.shapes.RECTANGLE, { shadow, ... });
const makeShadow = () => ({ type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.15 });
slide.addShape(pres.shapes.RECTANGLE, { shadow: makeShadow(), ... }); // ✅ fresh object each time
slide.addShape(pres.shapes.RECTANGLE, { shadow: makeShadow(), ... });
```
8. **Don't use `ROUNDED_RECTANGLE` with accent borders** - rectangular overlay bars won't cover rounded corners. Use `RECTANGLE` instead.
```javascript
// ❌ WRONG: Accent bar doesn't cover rounded corners
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { x: 1, y: 1, w: 3, h: 1.5, fill: { color: "FFFFFF" } });
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 0.08, h: 1.5, fill: { color: "0891B2" } });
// ✅ CORRECT: Use RECTANGLE for clean alignment
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 3, h: 1.5, fill: { color: "FFFFFF" } });
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 0.08, h: 1.5, fill: { color: "0891B2" } });
```
---
## Quick Reference
- **Shapes**: RECTANGLE, OVAL, LINE, ROUNDED_RECTANGLE
- **Charts**: BAR, LINE, PIE, DOUGHNUT, SCATTER, BUBBLE, RADAR
- **Layouts**: LAYOUT_16x9 (10"×5.625"), LAYOUT_16x10, LAYOUT_4x3, LAYOUT_WIDE
- **Alignment**: "left", "center", "right"
- **Chart data labels**: "outEnd", "inEnd", "center"