PPTX Skill
Quick Reference
| Task |
Approach |
| Read/analyze content |
python3 -m markitdown presentation.pptx |
| Generate structured presentation |
Use generate_report.js — see below |
| Create custom from scratch |
Use pptxgenjs directly (see pptxgenjs section) |
Generating Presentations (Recommended)
For structured presentations with cover slide, auto-generated TOC, content slides, and closing, use the pre-built template:
Step 1: Copy the generator script
cp /builtin-skills/pptx/scripts/generate_report.js ./generate_pptx.js
Step 2: Build slides_data.json via Python script
Two phases: write slide content files, then assemble into JSON.
CRITICAL: NEVER write or edit .json files directly. Use a Python script with json.dump() to guarantee valid JSON output.
Phase 1 — Write each slide's content as a plain text file using write_file:
For each major topic, read_file the relevant research data, then write_file the slide content directly:
read_file("research_data/literature.md") # refresh data in context
write_file("slides/slide_01_intro.txt", "...") # write slide body
write_file("slides/slide_02_analysis.txt", "...") # next slide
...
Each content slide body should be concise but substantive (3-6 bullet points or 2-4 sentences with specific data and citations).
NEVER write a Python script that contains slide text as string literals. The slide content goes directly into .txt files via write_file, not into Python code.
Language (CRITICAL):
- All presentation content (title, subtitle, slide headings, body text, chart labels, speaker notes) MUST be written in the user's configured language as specified in the system prompt's
## Language section.
- If the user's language is Chinese (
zh), write the entire presentation in Chinese; if English (en), write in English. Do NOT mix languages unless quoting a proper noun or technical term that has no standard translation.
Phase 2 — Assemble into JSON using a standard assembler script:
import json, glob, os
SLIDES_DIR = "slides"
TITLE = "Presentation Title"
SUBTITLE = "Subtitle or tagline"
# Slide config: (file_pattern, type, title, extra_fields_or_None)
SLIDE_MAP = [
("slide_01_*.txt", "section", "Introduction", None),
("slide_02_*.txt", "bullets", "Key Findings", None),
("slide_03_*.txt", "content", "Market Overview", {"layout": "text-image", "image": "chart.png"}),
("slide_04_*.txt", "stat", "Key Metrics", {
"stats": [
{"value": "25%", "label": "Revenue Growth"},
{"value": "15%", "label": "Cost Reduction"},
{"value": "32%", "label": "Market Share"},
]
}),
("slide_05_*.txt", "content", "Trend Analysis", None),
(None, "chart_pie", "Distribution", {
"labels": ["Type A", "Type B", "Type C", "Other"],
"values": [35, 30, 20, 15],
}),
(None, "chart_line", "Yearly Trends", {
"x_labels": ["2020", "2021", "2022", "2023", "2024"],
"series": [{"name": "Metric", "values": [40, 55, 62, 70, 78]}],
}),
]
data = {
"title": TITLE, "subtitle": SUBTITLE,
"author": "ScienceClaw", "date": "2026-03-09",
"theme": "midnight", "toc": True, "slides": [],
}
for entry in SLIDE_MAP:
pattern, stype, title, extra = entry
slide = {"type": stype, "title": title}
if pattern:
matches = sorted(glob.glob(os.path.join(SLIDES_DIR, pattern)))
if matches:
body = open(matches[0], encoding="utf-8").read().strip()
if stype == "bullets":
slide["items"] = [line.strip() for line in body.split("\n") if line.strip()]
else:
slide["body"] = body
if extra:
slide.update(extra)
data["slides"].append(slide)
# Closing slide
data["slides"].append({"type": "closing", "title": "Thank You", "subtitle": "Questions?"})
with open("slides_data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"Generated slides_data.json ({len(data['slides'])} slides)")
Step 3: Generate the PPTX
python3 build_slides_data.py # outputs slides_data.json
node generate_pptx.js slides_data.json output.pptx
Supported slide types
| Type |
Required Fields |
Optional Fields |
title |
(auto from top-level) |
title, subtitle, author, date |
agenda |
items (string array) |
title (default: "Agenda") |
section |
title |
subtitle |
content |
title |
body, layout, image |
bullets |
title, items |
subtitle |
two_column |
title, left, right |
each column: {heading, body} or {heading, items} |
table |
title, headers, rows |
caption |
stat |
title, stats |
stats: [{value, label}] (2-4 items) |
image |
title, image |
caption |
chart_bar |
title, categories, series |
series: [{name, values}] |
chart_pie |
title, labels, values |
— |
chart_line |
title, x_labels, series |
series: [{name, values}] |
quote |
text |
author, title |
closing |
title |
subtitle, contact |
Chart types for data visualization (use 2-4 per presentation, mix types):
chart_bar — for comparisons, rankings (e.g. drug efficacy scores)
chart_pie — for proportions, distributions (e.g. mutation type breakdown)
chart_line — for trends over time (e.g. yearly incidence rates)
Top-level JSON keys
| Key |
Required |
Description |
title |
Yes |
Presentation title (cover slide) |
subtitle |
No |
Subtitle on cover slide |
author |
No |
Author name |
date |
No |
Date string |
theme |
No |
Color theme (see below) |
toc |
No |
Auto-generate Table of Contents slide (default: true) |
slides |
Yes |
Array of slide objects |
Available themes
| Theme |
Primary |
Secondary |
Accent |
Style |
midnight |
1E2761 |
CADCFC |
408EC6 |
Dark navy, professional |
forest |
2C5F2D |
97BC62 |
F5F5F5 |
Green, nature |
coral |
F96167 |
F9E795 |
2F3C7E |
Warm, energetic |
ocean |
065A82 |
1C7293 |
21295C |
Deep blue, calm |
charcoal |
36454F |
F2F2F2 |
212121 |
Minimal, modern |
teal |
028090 |
00A896 |
02C39A |
Fresh, trustworthy |
berry |
6D2E46 |
A26769 |
ECE2D0 |
Elegant, warm |
Design guidelines
- Every slide needs a visual element — avoid text-only slides
- Vary layouts — don't repeat the same layout across slides
- Use section slides to separate major topics — these also populate the auto-generated TOC
- Use stat slides for key numbers (big number + label format)
- Mix chart types — aim for 2-4 charts per presentation (bar for comparisons, pie for distributions, line for trends)
- Keep bullet points concise — 3-6 items per slide, 1-2 lines each
- Content quality: Each slide body should contain specific data, not vague summaries. Include numbers, percentages, dates, and source references where possible.
Writing guidelines for long presentations
- Use the two-phase workflow: Write slide content as separate text files first, then assemble into JSON. This avoids context loss and allows iterative refinement.
- Be specific: Slide bodies should contain concrete data, not generic statements. "Revenue grew 25% to $4.2B in Q3 2025" beats "Revenue increased significantly".
- Use section slides as dividers: They auto-populate the TOC and give the audience clear navigation.
- Balance text and visuals: For every 2-3 text/bullet slides, include a chart, stat, or image slide.
- End with a closing slide: Include contact info or next steps.
- No page/slide count on cover: Do NOT include total page count or slide count on the cover slide or subtitle — the count is unknown at assembly time and produces inaccurate information.
Reading Content
python3 -m markitdown presentation.pptx
Creating Custom Presentations (pptxgenjs)
For fully custom presentations beyond the template's capabilities, use pptxgenjs directly:
const pptxgen = require("pptxgenjs");
let pres = new pptxgen();
pres.layout = "LAYOUT_16x9";
let slide = pres.addSlide();
slide.addText("Hello World!", { x: 0.5, y: 0.5, fontSize: 36, color: "363636" });
pres.writeFile({ fileName: "output.pptx" });
Key rules for pptxgenjs
- NEVER use "#" with hex colors —
color: "FF0000" not color: "#FF0000"
- Use
bullet: true — NEVER unicode symbols like "•"
- Use
breakLine: true between array items for multi-line text
- NEVER reuse option objects — pptxgenjs mutates them in-place; create fresh objects each time
- Coordinates are in inches;
LAYOUT_16x9 = 10" × 5.625"
Converting to Images (for QA)
python3 /builtin-skills/pptx/scripts/office/soffice.py --headless --convert-to pdf output.pptx
pdftoppm -jpeg -r 150 output.pdf slide
Dependencies
npm install -g pptxgenjs — creating presentations
pip install "markitdown[pptx]" — text extraction
pip install Pillow — image processing
- LibreOffice (
soffice) — PDF conversion
- Poppler (
pdftoppm) — PDF to images
1---2name: pptx3description: Use this skill any time a .pptx file is involved — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading or extracting text from .pptx files; editing or updating existing presentations; combining or splitting slide files; working with templates, layouts, speaker notes, or comments. Trigger whenever the user mentions 'deck', 'slides', 'presentation', or references a .pptx filename. If a .pptx file needs to be opened, created, or touched, use this skill.4license: Proprietary. LICENSE.txt has complete terms5---67# PPTX Skill89## Quick Reference1011| Task | Approach |12|------|----------|13| Read/analyze content | `python3 -m markitdown presentation.pptx` |14| **Generate structured presentation** | **Use `generate_report.js` — see below** |15| Create custom from scratch | Use pptxgenjs directly (see pptxgenjs section) |1617---1819## Generating Presentations (Recommended)2021For structured presentations with cover slide, auto-generated TOC, content slides, and closing, use the pre-built template:2223### Step 1: Copy the generator script2425```bash26cp /builtin-skills/pptx/scripts/generate_report.js ./generate_pptx.js27```2829### Step 2: Build `slides_data.json` via Python script3031**Two phases: write slide content files, then assemble into JSON.**3233**CRITICAL**: NEVER write or edit `.json` files directly. Use a Python script with `json.dump()` to guarantee valid JSON output.3435**Phase 1 — Write each slide's content as a plain text file** using `write_file`:3637For each major topic, `read_file` the relevant research data, then `write_file` the slide content directly:38```39read_file("research_data/literature.md") # refresh data in context40write_file("slides/slide_01_intro.txt", "...") # write slide body41write_file("slides/slide_02_analysis.txt", "...") # next slide42...43```44Each content slide body should be concise but substantive (3-6 bullet points or 2-4 sentences with specific data and citations).4546**NEVER write a Python script that contains slide text as string literals.** The slide content goes directly into .txt files via `write_file`, not into Python code.4748**Language (CRITICAL):**49- All presentation content (title, subtitle, slide headings, body text, chart labels, speaker notes) MUST be written in the **user's configured language** as specified in the system prompt's `## Language` section.50- If the user's language is Chinese (`zh`), write the entire presentation in Chinese; if English (`en`), write in English. Do NOT mix languages unless quoting a proper noun or technical term that has no standard translation.5152**Phase 2 — Assemble into JSON** using a standard assembler script:5354```python55import json, glob, os5657SLIDES_DIR = "slides"58TITLE = "Presentation Title"59SUBTITLE = "Subtitle or tagline"6061# Slide config: (file_pattern, type, title, extra_fields_or_None)62SLIDE_MAP = [63 ("slide_01_*.txt", "section", "Introduction", None),64 ("slide_02_*.txt", "bullets", "Key Findings", None),65 ("slide_03_*.txt", "content", "Market Overview", {"layout": "text-image", "image": "chart.png"}),66 ("slide_04_*.txt", "stat", "Key Metrics", {67 "stats": [68 {"value": "25%", "label": "Revenue Growth"},69 {"value": "15%", "label": "Cost Reduction"},70 {"value": "32%", "label": "Market Share"},71 ]72 }),73 ("slide_05_*.txt", "content", "Trend Analysis", None),74 (None, "chart_pie", "Distribution", {75 "labels": ["Type A", "Type B", "Type C", "Other"],76 "values": [35, 30, 20, 15],77 }),78 (None, "chart_line", "Yearly Trends", {79 "x_labels": ["2020", "2021", "2022", "2023", "2024"],80 "series": [{"name": "Metric", "values": [40, 55, 62, 70, 78]}],81 }),82]8384data = {85 "title": TITLE, "subtitle": SUBTITLE,86 "author": "ScienceClaw", "date": "2026-03-09",87 "theme": "midnight", "toc": True, "slides": [],88}8990for entry in SLIDE_MAP:91 pattern, stype, title, extra = entry92 slide = {"type": stype, "title": title}9394 if pattern:95 matches = sorted(glob.glob(os.path.join(SLIDES_DIR, pattern)))96 if matches:97 body = open(matches[0], encoding="utf-8").read().strip()98 if stype == "bullets":99 slide["items"] = [line.strip() for line in body.split("\n") if line.strip()]100 else:101 slide["body"] = body102103 if extra:104 slide.update(extra)105 data["slides"].append(slide)106107# Closing slide108data["slides"].append({"type": "closing", "title": "Thank You", "subtitle": "Questions?"})109110with open("slides_data.json", "w", encoding="utf-8") as f:111 json.dump(data, f, ensure_ascii=False, indent=2)112print(f"Generated slides_data.json ({len(data['slides'])} slides)")113```114115### Step 3: Generate the PPTX116117```bash118python3 build_slides_data.py # outputs slides_data.json119node generate_pptx.js slides_data.json output.pptx120```121122### Supported slide types123124| Type | Required Fields | Optional Fields |125|------|----------------|-----------------|126| `title` | (auto from top-level) | `title`, `subtitle`, `author`, `date` |127| `agenda` | `items` (string array) | `title` (default: "Agenda") |128| `section` | `title` | `subtitle` |129| `content` | `title` | `body`, `layout`, `image` |130| `bullets` | `title`, `items` | `subtitle` |131| `two_column` | `title`, `left`, `right` | each column: `{heading, body}` or `{heading, items}` |132| `table` | `title`, `headers`, `rows` | `caption` |133| `stat` | `title`, `stats` | stats: `[{value, label}]` (2-4 items) |134| `image` | `title`, `image` | `caption` |135| `chart_bar` | `title`, `categories`, `series` | series: `[{name, values}]` |136| `chart_pie` | `title`, `labels`, `values` | — |137| `chart_line` | `title`, `x_labels`, `series` | series: `[{name, values}]` |138| `quote` | `text` | `author`, `title` |139| `closing` | `title` | `subtitle`, `contact` |140141**Chart types for data visualization (use 2-4 per presentation, mix types):**142- `chart_bar` — for comparisons, rankings (e.g. drug efficacy scores)143- `chart_pie` — for proportions, distributions (e.g. mutation type breakdown)144- `chart_line` — for trends over time (e.g. yearly incidence rates)145146### Top-level JSON keys147148| Key | Required | Description |149|-----|----------|-------------|150| `title` | Yes | Presentation title (cover slide) |151| `subtitle` | No | Subtitle on cover slide |152| `author` | No | Author name |153| `date` | No | Date string |154| `theme` | No | Color theme (see below) |155| `toc` | No | Auto-generate Table of Contents slide (default: true) |156| `slides` | Yes | Array of slide objects |157158### Available themes159160| Theme | Primary | Secondary | Accent | Style |161|-------|---------|-----------|--------|-------|162| `midnight` | `1E2761` | `CADCFC` | `408EC6` | Dark navy, professional |163| `forest` | `2C5F2D` | `97BC62` | `F5F5F5` | Green, nature |164| `coral` | `F96167` | `F9E795` | `2F3C7E` | Warm, energetic |165| `ocean` | `065A82` | `1C7293` | `21295C` | Deep blue, calm |166| `charcoal` | `36454F` | `F2F2F2` | `212121` | Minimal, modern |167| `teal` | `028090` | `00A896` | `02C39A` | Fresh, trustworthy |168| `berry` | `6D2E46` | `A26769` | `ECE2D0` | Elegant, warm |169170### Design guidelines171172- **Every slide needs a visual element** — avoid text-only slides173- **Vary layouts** — don't repeat the same layout across slides174- **Use section slides** to separate major topics — these also populate the auto-generated TOC175- **Use stat slides** for key numbers (big number + label format)176- **Mix chart types** — aim for 2-4 charts per presentation (bar for comparisons, pie for distributions, line for trends)177- **Keep bullet points concise** — 3-6 items per slide, 1-2 lines each178- **Content quality**: Each slide body should contain specific data, not vague summaries. Include numbers, percentages, dates, and source references where possible.179180### Writing guidelines for long presentations1811821. **Use the two-phase workflow**: Write slide content as separate text files first, then assemble into JSON. This avoids context loss and allows iterative refinement.1832. **Be specific**: Slide bodies should contain concrete data, not generic statements. "Revenue grew 25% to $4.2B in Q3 2025" beats "Revenue increased significantly".1843. **Use section slides as dividers**: They auto-populate the TOC and give the audience clear navigation.1854. **Balance text and visuals**: For every 2-3 text/bullet slides, include a chart, stat, or image slide.1865. **End with a closing slide**: Include contact info or next steps.1876. **No page/slide count on cover**: Do NOT include total page count or slide count on the cover slide or subtitle — the count is unknown at assembly time and produces inaccurate information.188189---190191## Reading Content192193```bash194python3 -m markitdown presentation.pptx195```196197---198199## Creating Custom Presentations (pptxgenjs)200201For fully custom presentations beyond the template's capabilities, use pptxgenjs directly:202203```javascript204const pptxgen = require("pptxgenjs");205let pres = new pptxgen();206pres.layout = "LAYOUT_16x9";207208let slide = pres.addSlide();209slide.addText("Hello World!", { x: 0.5, y: 0.5, fontSize: 36, color: "363636" });210211pres.writeFile({ fileName: "output.pptx" });212```213214### Key rules for pptxgenjs215216- **NEVER use "#" with hex colors** — `color: "FF0000"` not `color: "#FF0000"`217- **Use `bullet: true`** — NEVER unicode symbols like "•"218- **Use `breakLine: true`** between array items for multi-line text219- **NEVER reuse option objects** — pptxgenjs mutates them in-place; create fresh objects each time220- Coordinates are in inches; `LAYOUT_16x9` = 10" × 5.625"221222---223224## Converting to Images (for QA)225226```bash227python3 /builtin-skills/pptx/scripts/office/soffice.py --headless --convert-to pdf output.pptx228pdftoppm -jpeg -r 150 output.pdf slide229```230231---232233## Dependencies234235- `npm install -g pptxgenjs` — creating presentations236- `pip install "markitdown[pptx]"` — text extraction237- `pip install Pillow` — image processing238- LibreOffice (`soffice`) — PDF conversion239- Poppler (`pdftoppm`) — PDF to images