format: apply repo prettier (3.8.1) to the folded skills tree

963 markdown files reformatted with the repository's pinned prettier so
pnpm format:check covers the folded tree like every other repo file.

The formatter's embedded-language pass also normalized code fences
(TS semicolons, closed HTML tags in examples, lowercased CSS hex colors,
one renumbered list that skipped an index). Alphanumeric token deltas vs
the fold commit were audited file-by-file; all are formatter-equivalent
markup normalizations plus the four sanitized skills.
This commit is contained in:
fargo
2026-08-19 14:37:17 -05:00
parent d2eeb64433
commit 1a822493ba
962 changed files with 29594 additions and 27188 deletions
+37 -34
View File
@@ -1,6 +1,6 @@
---
name: pptx
description: "Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, 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, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill."
description: 'Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, 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, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill.'
license: Proprietary. LICENSE.txt has complete terms
---
@@ -8,11 +8,11 @@ license: Proprietary. LICENSE.txt has complete terms
## Quick Reference
| Task | Guide |
|------|-------|
| Read/analyze content | `python -m markitdown presentation.pptx` |
| Edit or create from template | Read [editing.md](editing.md) |
| Create from scratch | Read [pptxgenjs.md](pptxgenjs.md) |
| Task | Guide |
| ---------------------------- | ---------------------------------------- |
| Read/analyze content | `python -m markitdown presentation.pptx` |
| Edit or create from template | Read [editing.md](editing.md) |
| Create from scratch | Read [pptxgenjs.md](pptxgenjs.md) |
---
@@ -63,35 +63,38 @@ Use when no template or reference presentation is available.
Choose colors that match your topic — don't default to generic blue. Use these palettes as inspiration:
| Theme | Primary | Secondary | Accent |
|-------|---------|-----------|--------|
| **Midnight Executive** | `1E2761` (navy) | `CADCFC` (ice blue) | `FFFFFF` (white) |
| **Forest & Moss** | `2C5F2D` (forest) | `97BC62` (moss) | `F5F5F5` (cream) |
| **Coral Energy** | `F96167` (coral) | `F9E795` (gold) | `2F3C7E` (navy) |
| **Warm Terracotta** | `B85042` (terracotta) | `E7E8D1` (sand) | `A7BEAE` (sage) |
| **Ocean Gradient** | `065A82` (deep blue) | `1C7293` (teal) | `21295C` (midnight) |
| **Charcoal Minimal** | `36454F` (charcoal) | `F2F2F2` (off-white) | `212121` (black) |
| **Teal Trust** | `028090` (teal) | `00A896` (seafoam) | `02C39A` (mint) |
| **Berry & Cream** | `6D2E46` (berry) | `A26769` (dusty rose) | `ECE2D0` (cream) |
| **Sage Calm** | `84B59F` (sage) | `69A297` (eucalyptus) | `50808E` (slate) |
| **Cherry Bold** | `990011` (cherry) | `FCF6F5` (off-white) | `2F3C7E` (navy) |
| Theme | Primary | Secondary | Accent |
| ---------------------- | --------------------- | --------------------- | ------------------- |
| **Midnight Executive** | `1E2761` (navy) | `CADCFC` (ice blue) | `FFFFFF` (white) |
| **Forest & Moss** | `2C5F2D` (forest) | `97BC62` (moss) | `F5F5F5` (cream) |
| **Coral Energy** | `F96167` (coral) | `F9E795` (gold) | `2F3C7E` (navy) |
| **Warm Terracotta** | `B85042` (terracotta) | `E7E8D1` (sand) | `A7BEAE` (sage) |
| **Ocean Gradient** | `065A82` (deep blue) | `1C7293` (teal) | `21295C` (midnight) |
| **Charcoal Minimal** | `36454F` (charcoal) | `F2F2F2` (off-white) | `212121` (black) |
| **Teal Trust** | `028090` (teal) | `00A896` (seafoam) | `02C39A` (mint) |
| **Berry & Cream** | `6D2E46` (berry) | `A26769` (dusty rose) | `ECE2D0` (cream) |
| **Sage Calm** | `84B59F` (sage) | `69A297` (eucalyptus) | `50808E` (slate) |
| **Cherry Bold** | `990011` (cherry) | `FCF6F5` (off-white) | `2F3C7E` (navy) |
### For Each Slide
**Every slide needs a visual element** — image, chart, icon, or shape. Text-only slides are forgettable.
**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
@@ -99,23 +102,23 @@ Choose colors that match your topic — don't default to generic blue. Use these
**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 |
| 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 |
| Element | Size |
| -------------- | ------------- |
| Slide title | 36-44pt bold |
| Section header | 20-24pt bold |
| Body text | 14-16pt |
| Captions | 10-12pt muted |
### Spacing
@@ -5,10 +5,12 @@
When using an existing presentation as a template:
1. **Analyze existing slides**:
```bash
python scripts/thumbnail.py template.pptx
python -m markitdown template.pptx
```
Review `thumbnails.jpg` to see layouts, and markitdown output to see placeholder text.
2. **Plan slide mapping**: For each content section, choose a template slide.
@@ -45,13 +47,13 @@ When using an existing presentation as a template:
## Scripts
| Script | Purpose |
|--------|---------|
| `unpack.py` | Extract and pretty-print PPTX |
| 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 |
| `thumbnail.py` | Create visual grid of slides |
| `clean.py` | Remove orphaned files |
| `pack.py` | Repack with validation |
| `thumbnail.py` | Create visual grid of slides |
### unpack.py
@@ -113,11 +115,13 @@ Slide order is in `ppt/presentation.xml` → `<p:sldIdLst>`.
## 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
@@ -140,11 +144,13 @@ For each slide:
### 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 visual QA to catch mismatched counts
When replacing text with different length content:
- **Shorter replacements**: Usually safe
- **Longer replacements**: May overflow or wrap unexpectedly
- Test with visual QA after text changes
@@ -157,6 +163,7 @@ When replacing text with different length 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>
@@ -164,6 +171,7 @@ If source has multiple items (numbered lists, multiple sections), create separat
```
**✅ CORRECT** — separate paragraphs with bold headers:
```xml
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
@@ -192,12 +200,12 @@ Handled automatically by unpack/pack. But the Edit tool converts smart quotes to
<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;` |
| 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
+219 -108
View File
@@ -3,22 +3,23 @@
## Setup & Basic Structure
```javascript
const pptxgen = require("pptxgenjs");
const pptxgen = require('pptxgenjs');
let pres = new pptxgen();
pres.layout = 'LAYOUT_16x9'; // or 'LAYOUT_16x10', 'LAYOUT_4x3', 'LAYOUT_WIDE'
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" });
slide.addText('Hello World!', { x: 0.5, y: 0.5, fontSize: 36, color: '363636' });
pres.writeFile({ fileName: "Presentation.pptx" });
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"
@@ -30,31 +31,48 @@ Slide dimensions (coordinates in inches):
```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"
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 });
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 });
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 });
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
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
});
```
@@ -86,47 +104,65 @@ slide.addText("• First item", { ... }); // Creates double bullets
```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 }
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.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" }
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 }
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
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 }
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 |
| 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.
@@ -140,28 +176,31 @@ To cast a shadow upward (e.g. on a footer bar), use `angle: 270` with a positive
```javascript
// From file path
slide.addImage({ path: "images/chart.png", x: 1, y: 1, w: 5, h: 3 });
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 });
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 });
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" }
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' },
});
```
@@ -181,11 +220,13 @@ slide.addImage({
### Calculate Dimensions (preserve aspect ratio)
```javascript
const origWidth = 1978, origHeight = 923, maxHeight = 3.0;
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 });
slide.addImage({ path: 'image.png', x: centerX, y: 1.2, w: calcWidth, h: maxHeight });
```
### Supported Formats
@@ -202,32 +243,35 @@ Use react-icons to generate SVG icons, then rasterize to PNG for universal compa
### Setup
```javascript
const React = require("react");
const ReactDOMServer = require("react-dom/server");
const sharp = require("sharp");
const { FaCheckCircle, FaChartLine } = require("react-icons/fa");
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) {
function renderIconSvg(IconComponent, color = '#000000', size = 256) {
return ReactDOMServer.renderToStaticMarkup(
React.createElement(IconComponent, { color, size: String(size) })
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");
return 'image/png;base64,' + pngBuffer.toString('base64');
}
```
### Add Icon to Slide
```javascript
const iconData = await iconToBase64Png(FaCheckCircle, "#4472C4", 256);
const iconData = await iconToBase64Png(FaCheckCircle, '#4472C4', 256);
slide.addImage({
data: iconData,
x: 1, y: 1, w: 0.5, h: 0.5 // Size in inches
x: 1,
y: 1,
w: 0.5,
h: 0.5, // Size in inches
});
```
@@ -238,6 +282,7 @@ slide.addImage({
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
@@ -249,16 +294,16 @@ Popular icon sets in react-icons:
```javascript
// Solid color
slide.background = { color: "F1F1F1" };
slide.background = { color: 'F1F1F1' };
// Color with transparency
slide.background = { color: "FF3399", transparency: 50 };
slide.background = { color: 'FF3399', transparency: 50 };
// Image from URL
slide.background = { path: "https://example.com/bg.jpg" };
slide.background = { path: 'https://example.com/bg.jpg' };
// Image from base64
slide.background = { data: "image/png;base64,iVBORw0KGgo..." };
slide.background = { data: 'image/png;base64,iVBORw0KGgo...' };
```
---
@@ -266,18 +311,25 @@ 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" }
});
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 } }]
[{ 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] });
```
@@ -288,22 +340,51 @@ slide.addTable(tableData, { x: 1, y: 3.5, w: 8, colW: [4, 4] });
```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'
});
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 });
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 });
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
@@ -312,26 +393,30 @@ 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",
x: 0.5,
y: 1,
w: 9,
h: 4,
barDir: 'col',
// Custom colors (match your presentation palette)
chartColors: ["0D9488", "14B8A6", "5EEAD4"],
chartColors: ['0D9488', '14B8A6', '5EEAD4'],
// Clean background
chartArea: { fill: { color: "FFFFFF" }, roundedCorners: true },
chartArea: { fill: { color: 'FFFFFF' }, roundedCorners: true },
// Muted axis labels
catAxisLabelColor: "64748B",
valAxisLabelColor: "64748B",
catAxisLabelColor: '64748B',
valAxisLabelColor: '64748B',
// Subtle grid (value axis only)
valGridLine: { color: "E2E8F0", size: 0.5 },
catGridLine: { style: "none" },
valGridLine: { color: 'E2E8F0', size: 0.5 },
catGridLine: { style: 'none' },
// Data labels on bars
showValue: true,
dataLabelPosition: "outEnd",
dataLabelColor: "1E293B",
dataLabelPosition: 'outEnd',
dataLabelColor: '1E293B',
// Hide legend for single series
showLegend: false,
@@ -339,6 +424,7 @@ slide.addChart(pres.charts.BAR, chartData, {
```
**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)
@@ -351,14 +437,17 @@ slide.addChart(pres.charts.BAR, chartData, {
```javascript
pres.defineSlideMaster({
title: 'TITLE_SLIDE', background: { color: '283A5E' },
objects: [{
placeholder: { options: { name: 'title', type: 'title', x: 1, y: 2, w: 8, h: 2 } }
}]
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" });
let titleSlide = pres.addSlide({ masterName: 'TITLE_SLIDE' });
titleSlide.addText('My Title', { placeholder: 'title' });
```
---
@@ -368,12 +457,14 @@ titleSlide.addText("My Title", { placeholder: "title" });
⚠️ 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
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
@@ -388,6 +479,7 @@ titleSlide.addText("My Title", { placeholder: "title" });
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
@@ -399,14 +491,33 @@ titleSlide.addText("My Title", { placeholder: "title" });
```
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" } });
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" } });
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' },
});
```
---