diff --git a/pptx-generator/SKILL.md b/pptx-generator/SKILL.md new file mode 100644 index 0000000..1739a22 --- /dev/null +++ b/pptx-generator/SKILL.md @@ -0,0 +1,242 @@ +--- +name: pptx-generator +description: "Generate, edit, and read PowerPoint presentations. Create from scratch with PptxGenJS (cover, TOC, content, section divider, summary slides), edit existing PPTX via XML workflows, or extract text with markitdown. Triggers: PPT, PPTX, PowerPoint, presentation, slide, 幻灯片, 演示文稿." +--- + +# PPTX Generator & Editor + +## Overview + +This skill handles all PowerPoint tasks: reading/analyzing existing presentations, editing template-based decks via XML manipulation, and creating presentations from scratch using PptxGenJS. It includes a complete design system (color palettes, fonts, style recipes) and detailed guidance for every slide type. + +## Quick Reference + +| Task | Approach | +|------|----------| +| Read/analyze content | `python -m markitdown presentation.pptx` | +| Edit or create from template | See [Editing Presentations](editing.md) | +| Create from scratch | See [Creating from Scratch](#creating-from-scratch-workflow) below | + +| Item | Value | +|------|-------| +| **Dimensions** | 10" x 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" | +| **Theme keys** | `primary`, `secondary`, `accent`, `light`, `bg` | +| **Shapes** | RECTANGLE, OVAL, LINE, ROUNDED_RECTANGLE | +| **Charts** | BAR, LINE, PIE, DOUGHNUT, SCATTER, BUBBLE, RADAR | + +## Reference Files + +| File | Contents | +|------|----------| +| [slide-types.md](slide-types.md) | 5 slide page types (Cover, TOC, Section Divider, Content, Summary) + additional layout patterns | +| [design-system.md](design-system.md) | Color palettes, font reference, style recipes (Sharp/Soft/Rounded/Pill), typography & spacing | +| [editing.md](editing.md) | Template-based editing workflow, XML manipulation, formatting rules, common pitfalls | +| [pitfalls.md](pitfalls.md) | QA process, common mistakes, critical PptxGenJS pitfalls | +| [pptxgenjs.md](pptxgenjs.md) | Complete PptxGenJS API reference | + +--- + +## Reading Content + +```bash +# Text extraction +python -m markitdown presentation.pptx +``` + +--- + +## Creating from Scratch — Workflow + +**Use when no template or reference presentation is available.** + +### Step 1: Research & Requirements + +Search to understand user requirements — topic, audience, purpose, tone, content depth. + +### Step 2: Select Color Palette & Fonts + +Use the [Color Palette Reference](design-system.md#color-palette-reference) to select a palette matching the topic and audience. Use the [Font Reference](design-system.md#font-reference) to choose a font pairing. + +### Step 3: Select Design Style + +Use the [Style Recipes](design-system.md#style-recipes--视觉风格系统) to choose a visual style (Sharp, Soft, Rounded, or Pill) matching the presentation tone. + +### Step 4: Plan Slide Outline + +Classify **every slide** as exactly one of the [5 page types](slide-types.md). Plan the content and layout for each slide. Ensure visual variety — do NOT repeat the same layout across slides. + +### Step 5: Generate Slide JS Files + +Create one JS file per slide in `slides/` directory. Each file must export a synchronous `createSlide(pres, theme)` function. Follow the [Slide Output Format](#slide-output-format) and the type-specific guidance in [slide-types.md](slide-types.md). Generate up to 5 slides concurrently using subagents if available. + +**Tell each subagent:** +1. File naming: `slides/slide-01.js`, `slides/slide-02.js`, etc. +2. Images go in: `slides/imgs/` +3. Final PPTX goes in: `slides/output/` +4. Dimensions: 10" x 5.625" (LAYOUT_16x9) +5. Fonts: Chinese = Microsoft YaHei, English = Arial (or approved alternative) +6. Colors: 6-char hex without # (e.g. `"FF0000"`) +7. Must use the theme object contract (see [Theme Object Contract](#theme-object-contract)) +8. Must follow the [PptxGenJS API reference](pptxgenjs.md) + +### Step 6: Compile into Final PPTX + +Create `slides/compile.js` to combine all slide modules: + +```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` + +### Step 7: QA (Required) + +See [QA Process](pitfalls.md#qa-process). + +### Output Structure + +``` +slides/ +├── slide-01.js # Slide modules +├── slide-02.js +├── ... +├── imgs/ # Images used in slides +└── output/ # Final artifacts + └── presentation.pptx +``` + +--- + +## Slide Output Format + +Each slide is 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", + color: theme.primary, bold: true, align: "center" + }); + + return slide; +} + +// Standalone preview - use slide-specific filename +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); + pres.writeFile({ fileName: "slide-01-preview.pptx" }); +} + +module.exports = { createSlide, slideConfig }; +``` + +--- + +## 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`. + +--- + +## 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" +}); +``` + +--- + +## Dependencies + +- `pip install "markitdown[pptx]"` — text extraction +- `npm install -g pptxgenjs` — creating from scratch +- `npm install -g react-icons react react-dom sharp` — icons (optional) diff --git a/pptx-generator/design-system.md b/pptx-generator/design-system.md new file mode 100644 index 0000000..15bb557 --- /dev/null +++ b/pptx-generator/design-system.md @@ -0,0 +1,392 @@ +# Design System + +## Color Palette Reference + +| # | 名称 | 色值 | 风格 | 适用场景 | 建议 | +|---|------|------|------|----------|------| +| 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` | 弹窗 | + +--- + +## 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.** + +### No Animations + +**Animations and transitions are prohibited.** All slides must be static. + +--- + +## Font Reference + +### 推荐字体 + +| 语言 | 默认字体 | 可选字体 | +|------|----------|----------| +| **中文** | 微软雅黑 (Microsoft YaHei) | — | +| **英文** | Arial | Georgia, Calibri, Cambria, Trebuchet MS | + +- 中英文混排时:中文使用微软雅黑,英文使用所选字体 +- 优先使用系统自带字体,确保跨平台兼容 +- 标题和正文可使用不同字体配对(如 Georgia + Calibri) + +### Recommended Font Pairings + +| Header Font | Body Font | +|-------------|-----------| +| Georgia | Calibri | +| Arial Black | Arial | +| Calibri | Calibri Light | +| Cambria | Calibri | +| Trebuchet MS | Calibri | +| Impact | Arial | +| Palatino | Garamond | +| Consolas | Calibri | + +**Choose an interesting font pairing** — don't default to Arial for everything. Pick a header font with personality and pair it with a clean body font. + +### 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 }); +``` + +--- + +## Style Recipes — 视觉风格系统 + +同一套设计可通过调整圆角(rectRadius)和间距呈现4种不同风格。根据场景选择合适的风格配方。 + +> **单位说明**: PptxGenJS 使用英寸(inch)作为单位。幻灯片尺寸为 10" x 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(锐利紧凑) + +**视觉特征**: 方正、信息密度高、专业严肃感。 + +| 类别 | 值 (英寸) | 说明 | +|---|---|---| +| 圆角-小 | 0" | 完全直角 | +| 圆角-中 | 0.03" | 微圆角 | +| 圆角-大 | 0.05" | 小圆角 | +| 元素内边距 | 0.1" ~ 0.15" | 紧凑 | +| 元素间距 | 0.1" ~ 0.2" | 紧凑 | +| 页面边距 | 0.3" | 较窄 | +| 区块间距 | 0.25" ~ 0.35" | 紧凑 | + +### Soft & Balanced(柔和均衡) + +**视觉特征**: 适中的圆角、舒适的留白、专业又不失亲和。 + +| 类别 | 值 (英寸) | 说明 | +|---|---|---| +| 圆角-小 | 0.05" | 小圆角 | +| 圆角-中 | 0.08" | 中等圆角 | +| 圆角-大 | 0.12" | 较大圆角 | +| 元素内边距 | 0.15" ~ 0.2" | 适中 | +| 元素间距 | 0.15" ~ 0.25" | 适中 | +| 页面边距 | 0.4" | 标准 | +| 区块间距 | 0.35" ~ 0.5" | 适中 | + +### Rounded & Spacious(圆润宽松) + +**视觉特征**: 大圆角、充裕留白、友好亲切、现代感。 + +| 类别 | 值 (英寸) | 说明 | +|---|---|---| +| 圆角-小 | 0.1" | 中等圆角 | +| 圆角-中 | 0.15" | 大圆角 | +| 圆角-大 | 0.25" | 很大圆角 | +| 元素内边距 | 0.2" ~ 0.3" | 宽松 | +| 元素间距 | 0.25" ~ 0.4" | 宽松 | +| 页面边距 | 0.5" | 较宽 | +| 区块间距 | 0.5" ~ 0.7" | 宽松 | + +### Pill & Airy(胶囊通透) + +**视觉特征**: 全圆角胶囊形、大量留白、轻盈通透、品牌展示感强。 + +| 类别 | 值 (英寸) | 说明 | +|---|---|---| +| 圆角-小 | 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" x 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 | 专业,信息清晰 | diff --git a/pptx-generator/editing.md b/pptx-generator/editing.md new file mode 100644 index 0000000..ab2e9ca --- /dev/null +++ b/pptx-generator/editing.md @@ -0,0 +1,162 @@ +# Editing Existing 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**: Extract the PPTX into an editable XML tree using Python's `zipfile` module. Pretty-print the XML for readability. + +4. **Build presentation** (do this yourself, not with subagents): + - Delete unwanted slides (remove from ``) + - Duplicate slides you want to reuse (copy slide XML, relationships, and update `Content_Types.xml` and `presentation.xml`) + - Reorder slides in `` + - **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**: Remove orphaned files — slides not in ``, unreferenced media, orphaned rels. + +7. **Pack**: Repack the XML tree into a PPTX file. Validate, repair, condense XML, re-encode smart quotes. + + 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. + +## Output Structure + +Copy the user-provided file to `template.pptx` in cwd. This preserves the original and gives a predictable name for all downstream operations. + +```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`. + +## Slide Operations + +Slide order is in `ppt/presentation.xml` -> ``. + +**Reorder**: Rearrange `` elements. + +**Delete**: Remove ``, then clean orphaned files. + +**Add**: Copy the source slide's XML file, its `.rels` file, and update `Content_Types.xml` and `presentation.xml`. Never manually copy slide files without updating all references — this causes broken notes references and missing relationship IDs. + +## 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 ``. 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 `` or `` +- **Bullet consistency**: Let bullets inherit from the layout. Only specify `` or ``. + +## Common Pitfalls — Template Editing + +### 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 `` elements for each — **never concatenate into one string**. + +**WRONG** — all items in one paragraph: +```xml + + Step 1: Do the first thing. Step 2: Do the second thing. + +``` + +**CORRECT** — separate paragraphs with bold headers: +```xml + + + Step 1 + + + + Do the first thing. + + + + Step 2 + + +``` + +Copy `` from the original paragraph to preserve line spacing. Use `b="1"` on headers. + +### Smart Quotes + +The Edit tool converts smart quotes to ASCII. **When adding new text with quotes, use XML entities:** + +```xml +the “Agreement” +``` + +| Character | Name | Unicode | XML Entity | +|-----------|------|---------|------------| +| \u201c | Left double quote | U+201C | `“` | +| \u201d | Right double quote | U+201D | `”` | +| \u2018 | Left single quote | U+2018 | `‘` | +| \u2019 | Right single quote | U+2019 | `’` | + +### Other + +- **Whitespace**: Use `xml:space="preserve"` on `` with leading/trailing spaces +- **XML parsing**: Use `defusedxml.minidom`, not `xml.etree.ElementTree` (corrupts namespaces) diff --git a/pptx-generator/pitfalls.md b/pptx-generator/pitfalls.md new file mode 100644 index 0000000..cb6eefc --- /dev/null +++ b/pptx-generator/pitfalls.md @@ -0,0 +1,112 @@ +# QA Process & Common Pitfalls + +## QA Process + +**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. + +**Check for leftover placeholder text:** + +```bash +python -m markitdown output.pptx | grep -iE "xxxx|lorem|ipsum|placeholder|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.** + +### Per-Slide QA (for from-scratch creation) + +```bash +python -m markitdown slide-XX-preview.pptx +``` + +Check for missing content, placeholder text, missing page number badge. + +--- + +## Common Mistakes to Avoid + +- **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 +- **NEVER use accent lines under titles** — these are a hallmark of AI-generated slides; use whitespace or background color instead +- **NEVER use "#" with hex colors** — causes file corruption in PptxGenJS +- **NEVER encode opacity in hex strings** — use the `opacity` property instead +- **NEVER use async/await in createSlide()** — compile.js won't await +- **NEVER reuse option objects across PptxGenJS calls** — PptxGenJS mutates objects in-place + +--- + +## Critical Pitfalls — PptxGenJS + +### 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" +}); +``` + +### NEVER reuse option objects across calls + +```javascript +// WRONG +const shadow = { type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.15 }; +slide.addShape(pres.shapes.RECTANGLE, { shadow, ... }); +slide.addShape(pres.shapes.RECTANGLE, { shadow, ... }); + +// CORRECT - factory function +const makeShadow = () => ({ type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.15 }); +slide.addShape(pres.shapes.RECTANGLE, { shadow: makeShadow(), ... }); +slide.addShape(pres.shapes.RECTANGLE, { shadow: makeShadow(), ... }); +``` diff --git a/pptx-generator/pptxgenjs.md b/pptx-generator/pptxgenjs.md new file mode 100644 index 0000000..f649516 --- /dev/null +++ b/pptx-generator/pptxgenjs.md @@ -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" x 5.625" (default) +- `LAYOUT_16x10`: 10" x 6.25" +- `LAYOUT_4x3`: 10" x 7.5" +- `LAYOUT_WIDE`: 13.3" x 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 "o" (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"x5.625"), LAYOUT_16x10, LAYOUT_4x3, LAYOUT_WIDE +- **Alignment**: "left", "center", "right" +- **Chart data labels**: "outEnd", "inEnd", "center" diff --git a/pptx-generator/slide-types.md b/pptx-generator/slide-types.md new file mode 100644 index 0000000..eb295ca --- /dev/null +++ b/pptx-generator/slide-types.md @@ -0,0 +1,413 @@ +# Slide Page Types + +Classify **every slide** as **exactly one** of these 5 types: + +## 1. Cover Page + +- **Use for**: Opening + tone setting +- **Content**: Big title, subtitle/presenter, date/occasion, strong background/motif + +### Layout Options + +**Asymmetric Left-Right Layout** +- Text concentrated on one side, image on the opposite +- Best for: Corporate presentations, product launches, professional reports +``` +| Title & Subtitle | Visual/Image | +| Description | | +``` + +**Center-Aligned Layout** +- Content centered with background image +- Best for: Inspirational talks, event presentations, creative pitches +``` +| | +| [Background Image] | +| MAIN TITLE | +| Subtitle | +| | +``` + +### Font Size Hierarchy + +| Element | Recommended Size | Ratio to Base | +|---------|-----------------|---------------| +| Main Title | 72-120px | 3x-5x | +| Subtitle | 28-40px | 1.5x-2x | +| Supporting Text | 18-24px | 1x (base) | +| Meta Info (date, name) | 14-18px | 0.7x-1x | + +**Key Principles:** +1. **Dramatic Contrast**: Main title should be at least 2-3x larger than subtitle +2. **Visual Anchor**: The largest text becomes the focal point +3. **Readable Hierarchy**: Viewers should instantly understand what's most important +4. **Avoid Similarity**: Never let adjacent text elements be within 20% of each other's size + +### Content Elements + +1. **Main Title** — Always required, largest font +2. **Subtitle** — When additional context is needed (clearly smaller than title) +3. **Icons** — When they reinforce the theme +4. **Date/Event Info** — When relevant (smallest text) +5. **Company/Brand Logo** — When representing an organization +6. **Presenter Name** — For keynotes (small, subtle) + +### Design Decisions + +Consider: Purpose (corporate/educational/creative), Audience, Tone, Content Volume, Visual Assets needed. + +### Workflow + +1. **Analyze**: Understand topic, audience, purpose +2. **Choose Layout**: Select based on content +3. **Write Slide**: Use PptxGenJS. Use shapes and SVG elements for visual interest. +4. **Verify**: Generate preview as `slide-XX-preview.pptx`. Extract text with `python -m markitdown slide-XX-preview.pptx`, verify all content present and no placeholder text remains. + +--- + +## 2. Table of Contents + +- **Use for**: Navigation + expectation setting (3-5 sections) +- **Content**: Section list (optional icons / page numbers) + +### Layout Options + +**Numbered Vertical List** — Best for 3-5 sections, straightforward presentations +``` +| TABLE OF CONTENTS | +| | +| 01 Section Title One | +| 02 Section Title Two | +| 03 Section Title Three | +``` + +**Two-Column Grid** — Best for 4-6 sections, content-rich presentations +``` +| TABLE OF CONTENTS | +| | +| 01 Section One 02 Section Two | +| Description Description | +| 03 Section Three 04 Section Four | +``` + +**Sidebar Navigation** — Best for 3-5 sections, modern/corporate +``` +| ▌01 | Section Title One | +| ▌02 | Section Title Two | +| ▌03 | Section Title Three | +``` + +**Card-Based** — Best for 3-4 sections, creative/modern +``` +| TABLE OF CONTENTS | +| ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ | +| │ 01 │ │ 02 │ │ 03 │ │ 04 │ | +| │Title│ │Title│ │Title│ │Title│ | +| └─────┘ └─────┘ └─────┘ └─────┘ | +``` + +### Font Size Hierarchy + +| Element | Recommended Size | Ratio to Base | +|---------|-----------------|---------------| +| Page Title ("Table of Contents" / "Agenda") | 36-44px | 2.5x-3x | +| Section Number | 28-36px | 2x-2.5x | +| Section Title | 20-28px | 1.5x-2x | +| Section Description | 14-16px | 1x (base) | + +**Key Principles:** +1. **Clear Numbering**: Section numbers should be visually prominent — bold, accent color, or larger size +2. **Scannable Structure**: Viewer should scan all sections in 2-3 seconds +3. **Consistent Spacing**: Equal vertical spacing between sections +4. **Visual Markers**: Colored dots, lines, numbers, or icons to anchor each section +5. **Avoid Clutter**: Descriptions one line max or omit entirely + +### Content Elements + +1. **Page Title** — Always required ("Table of Contents", "Agenda", "Overview") +2. **Section Numbers** — Consistent format (01, 02... or I, II...) +3. **Section Titles** — Clear and concise +4. **Section Descriptions** — Optional one-line summaries +5. **Visual Separators** — SVG dividers or spacing +6. **Decorative Elements** — Subtle accent shapes +7. **Page Number Badge (角标)** — **MANDATORY** + +### Design Decisions + +1. **Section Count**: 3 → vertical list; 4-6 → grid or compact; 7+ → multi-column +2. **Description Length**: Long → vertical list; None → compact grid/cards +3. **Tone**: Corporate → numbered list; Creative → card-based; Academic → Roman numerals +4. **Consistency**: Match visual style of cover page + +### Workflow + +1. **Analyze**: Section list, count, presentation context +2. **Choose Layout**: Based on section count and content +3. **Plan Visual Hierarchy**: Numbering style, font sizes, spacing +4. **Write Slide**: Use PptxGenJS. Use shapes for decorative elements. **MUST include page number badge.** +5. **Verify**: Generate preview, extract text with markitdown, verify content and badge. + +--- + +## 3. Section Divider + +- **Use for**: Clear transitions between major parts +- **Content**: Section number + title (+ optional 1-2 line intro) + +### Layout Options + +**Bold Center** — Best for minimal, modern presentations +``` +| 02 | +| SECTION TITLE | +| Optional intro line | +``` + +**Left-Aligned with Accent Block** — Best for corporate, structured presentations +``` +| ████ | 02 | +| ████ | SECTION TITLE | +| ████ | Optional intro line | +``` + +**Split Background** — Best for high-contrast, dramatic transitions +``` +| ██████████ | SECTION TITLE | +| ██ 02 ██ | Optional intro | +| ██████████ | | +``` + +**Full-Bleed Background with Overlay** — Best for creative, bold presentations +``` +| ████████████████████████████████████ | +| ████ large 02 █████████ | +| ████ SECTION TITLE █████████ | +| ████████████████████████████████████ | +``` + +### Font Size Hierarchy + +| Element | Recommended Size | Notes | +|---------|-----------------|-------| +| Section Number | 72-120px | Bold, accent color or semi-transparent | +| Section Title | 36-48px | Bold, clear, primary text color | +| Intro Text | 16-20px | Light weight, muted color, optional | + +**Key Principles:** +1. **Dramatic Number**: Section number = most prominent visual element +2. **Strong Title**: Large but clearly secondary to the number +3. **Minimal Content**: Just number + title + optional one-liner +4. **Breathing Room**: Leave generous whitespace — dividers are pause moments + +### Content Elements + +1. **Section Number** — Always required. Format: `01`, `02`... or `I`, `II`... Match TOC style. +2. **Section Title** — Always required. Clear, concise. +3. **Intro Text** — Optional 1-2 line description. +4. **Decorative Elements** — SVG accent shapes (bars, lines, geometric blocks). +5. **Page Number Badge (角标)** — **MANDATORY**. + +### Design Decisions + +1. **Tone**: Corporate → accent block; Creative → full-bleed; Minimal → bold center +2. **Color**: Strong palette color for background/accent; high-contrast text +3. **Consistency**: Same divider style across all dividers in one presentation +4. **Contrast with content slides**: Visually distinct (different background color, more whitespace) + +### Workflow + +1. **Analyze**: Section number, title, optional intro +2. **Choose Layout**: Based on content and tone +3. **Write Slide**: Use PptxGenJS. Use shapes for decorative elements. **MUST include page number badge.** +4. **Verify**: Generate preview, extract text, verify content and badge. + +--- + +## 4. Content Page + +Pick a subtype based on the content. Each content slide belongs to exactly ONE subtype: + +### Subtypes + +**Text** — Bullets, quotes, or short paragraphs +- Must still include icons or SVG shapes — never plain text only +``` +| SLIDE TITLE | +| * Bullet point one | +| * Bullet point two | +| * Bullet point three | +``` + +**Mixed Media** — Two-column or half-bleed image + text +``` +| SLIDE TITLE | +| Text content | [Image/Visual] | +| and bullets | | +``` + +**Data Visualization** — Chart (SVG bar/progress/ring) + takeaways +- Must include data source +``` +| SLIDE TITLE | +| [SVG Chart] | Key Takeaway 1 | +| | Key Takeaway 2 | +| Source: xxx | +``` + +**Comparison** — Side-by-side columns or cards (A vs B, pros/cons) +``` +| SLIDE TITLE | +| ┌─ Option A ─┐ ┌─ Option B ─┐ | +| │ Detail 1 │ │ Detail 1 │ | +| └────────────┘ └────────────┘ | +``` + +**Timeline / Process** — Steps with arrows, journey, phases +``` +| SLIDE TITLE | +| [1] ──→ [2] ──→ [3] ──→ [4] | +| Step Step Step Step | +``` + +**Image Showcase** — Hero image, gallery, visual-first layout +``` +| SLIDE TITLE | +| ┌────────────────────────────────┐ | +| │ [Hero Image] │ | +| └────────────────────────────────┘ | +| Caption or supporting text | +``` + +### Font Size Hierarchy + +| Element | Recommended Size | Notes | +|---------|-----------------|-------| +| Slide Title | 36-44px | Bold, top of slide | +| Section Header | 20-24px | Bold, for sub-sections within slide | +| Body Text | 14-16px | Regular weight, left-aligned | +| Captions / Source | 10-12px | Muted color, smallest text | +| Stat Callout | 60-72px | Large bold numbers for key statistics | + +**Key Principles:** +1. **Left-align body text** — never center paragraphs or bullet lists +2. **Size contrast** — title must be 36pt+ to stand out from 14-16pt body +3. **Visual elements required** — every content slide must have at least one non-text element +4. **Breathing room** — 0.5" minimum margins, 0.3-0.5" between content blocks + +### Content Elements + +1. **Slide Title** — Always required, top of slide +2. **Body Content** — Text, bullets, data, or comparisons based on subtype +3. **Visual Element** — Image, chart, icon, or SVG shape — always required +4. **Source / Caption** — When showing data or external content +5. **Page Number Badge (角标)** — **MANDATORY** + +### Design Decisions + +1. **Subtype**: Determine first — drives the entire layout +2. **Content Volume**: Dense → multi-column or smaller font; Light → larger elements with more whitespace +3. **Data vs Narrative**: Data-heavy → charts + stat callouts; Story-driven → images + quotes +4. **Variety**: Each content slide should use a different layout from the previous one +5. **Consistency**: Typography, colors, and spacing must match the rest of the presentation + +### Workflow + +1. **Analyze**: Content, determine subtype, plan layout +2. **Choose Layout**: Best fit for subtype and content volume +3. **Write Slide**: Use PptxGenJS. Use shapes for charts, decorative elements, icons. **MUST include page number badge.** +4. **Verify**: Generate preview as `slide-XX-preview.pptx`. Extract text with markitdown, verify all content present, no placeholder text, badge included. + +--- + +## 5. Summary / Closing Page + +- **Use for**: Wrap-up + action +- **Content**: Key takeaways, CTA/next steps, contact/QR, thank-you + +### Layout Options + +**Key Takeaways** — Best for educational, corporate, data-driven presentations +``` +| KEY TAKEAWAYS | +| ✓ Takeaway one | +| ✓ Takeaway two | +| ✓ Takeaway three | +``` + +**CTA / Next Steps** — Best for sales pitches, proposals, project kick-offs +``` +| NEXT STEPS | +| [1] Action item one | +| [2] Action item two | +| Contact: email@example.com | +``` + +**Thank You / Contact** — Best for conference talks, keynotes +``` +| THANK YOU | +| name@company.com | +| @handle | website.com | +``` + +**Split Recap** — Best for presentations needing both recap and action +``` +| SUMMARY | NEXT STEPS | +| * Point one | Contact us at | +| * Point two | email@co.com | +| * Point three | [QR Code] | +``` + +### Font Size Hierarchy + +| Element | Recommended Size | Notes | +|---------|-----------------|-------| +| Closing Title ("Thank You" / "Summary") | 48-72px | Bold, commanding | +| Takeaway / Action Item | 18-24px | Clear, scannable | +| Supporting Text | 14-16px | Regular weight | +| Contact Info | 14-16px | Muted color | + +**Key Principles:** +1. **Strong closing statement**: Main message should be largest, most prominent +2. **Scannable items**: Takeaways/action items concise (one line each) +3. **Contact clarity**: Legible but not dominant +4. **Memorable finish**: Confident, polished ending + +### Content Elements + +1. **Closing Title** — Always required +2. **Takeaway Points** — 3-5 concise summary points (if applicable) +3. **Call to Action** — Clear next steps (if applicable) +4. **Contact Info** — Email, website, social handles (if provided) +5. **Decorative Elements** — SVG accents for visual consistency +6. **Page Number Badge (角标)** — **MANDATORY** + +### Design Decisions + +1. **Closing Type**: Recap, CTA, thank-you, or combination +2. **Content Volume**: Many takeaways → list; Simple closing → centered thank-you +3. **Audience Action**: Audience needs to do something → CTA; Informational → takeaways +4. **Tone Consistency**: Match energy of cover page +5. **Visual Distinction**: Special but not disconnected from the rest + +### Workflow + +1. **Analyze**: Closing content — takeaways, CTA, contact, thank-you +2. **Choose Layout**: Based on content type +3. **Write Slide**: Use PptxGenJS. Use shapes for decorative elements. **MUST include page number badge.** +4. **Verify**: Generate preview, extract text, verify content and badge. + +--- + +## Additional Layout Patterns + +Use these across content slides for visual variety: + +- **Two-column** (text left, illustration 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 +- **Large stat callouts** (big numbers 60-72pt with small labels below) +- **Comparison columns** (before/after, pros/cons) +- **Timeline or process flow** (numbered steps, arrows) +- **Icons in small colored circles** next to section headers +- **Italic accent text** for key stats or taglines