@heylemon/lemonade 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/package.json +1 -1
- package/skills/docx/SKILL.md +595 -22
- package/skills/docx/references/templates.md +669 -33
- package/skills/docx/scripts/create_doc.py +289 -52
- package/skills/docx/scripts/validate.py +237 -0
- package/skills/docx/scripts/validate_doc.py +103 -22
- package/skills/pptx/SKILL.md +169 -12
- package/skills/pptx/editing.md +270 -0
- package/skills/pptx/pptxgenjs.md +624 -0
- package/skills/pptx/references/spec-format.md +106 -31
- package/skills/pptx/scripts/create_pptx.js +419 -186
- package/skills/xlsx/SKILL.md +502 -14
- package/skills/xlsx/references/spec-format.md +238 -40
- package/skills/xlsx/scripts/create_xlsx.py +130 -54
- package/skills/xlsx/scripts/recalc.py +157 -147
- package/skills/xlsx/scripts/validate_xlsx.py +31 -6
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
# PptxGenJS API Tutorial
|
|
2
|
+
|
|
3
|
+
PptxGenJS is a JavaScript library for generating PowerPoint presentations programmatically. This guide covers the most practical patterns for building professional slides.
|
|
4
|
+
|
|
5
|
+
## Setup & Basic Structure
|
|
6
|
+
|
|
7
|
+
Create a new presentation and configure it:
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
const PptxGenJS = require("pptxgenjs");
|
|
11
|
+
const pres = new PptxGenJS();
|
|
12
|
+
|
|
13
|
+
pres.layout = "LAYOUT_16x9";
|
|
14
|
+
pres.author = "Your Name";
|
|
15
|
+
pres.title = "Presentation Title";
|
|
16
|
+
pres.subject = "Subtitle or description";
|
|
17
|
+
|
|
18
|
+
// Add slides
|
|
19
|
+
const slide1 = pres.addSlide();
|
|
20
|
+
|
|
21
|
+
// Save to file
|
|
22
|
+
pres.writeFile({ fileName: "output.pptx" });
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Key point: Always create a fresh `PptxGenJS()` instance per presentation. Don't reuse across multiple presentations.
|
|
26
|
+
|
|
27
|
+
## Layout Dimensions
|
|
28
|
+
|
|
29
|
+
Standard 16:9 layout is 10 inches wide by 5.625 inches tall. All positioning is in inches.
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
// Slide area
|
|
33
|
+
const W = 10; // Width
|
|
34
|
+
const H = 5.625; // Height
|
|
35
|
+
const M = 0.5; // Margin (standard)
|
|
36
|
+
const contentWidth = W - 2 * M; // 9 inches
|
|
37
|
+
|
|
38
|
+
// Common positioning
|
|
39
|
+
const titleY = M; // Top margin
|
|
40
|
+
const contentStartY = M + 0.8; // After title
|
|
41
|
+
const bottomY = H - 0.8; // Near bottom for footer
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Text & Formatting
|
|
45
|
+
|
|
46
|
+
### Basic Text
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
slide.addText("Hello World", {
|
|
50
|
+
x: 0.5, y: 1, w: 9, h: 0.5,
|
|
51
|
+
fontSize: 16,
|
|
52
|
+
fontFace: "Arial",
|
|
53
|
+
color: "000000",
|
|
54
|
+
bold: true,
|
|
55
|
+
align: "left",
|
|
56
|
+
valign: "top"
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Multi-line Text with Rich Formatting
|
|
61
|
+
|
|
62
|
+
Use an array to mix formatted segments:
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
slide.addText([
|
|
66
|
+
{ text: "This is bold", options: { bold: true } },
|
|
67
|
+
{ text: " and this is ", options: {} },
|
|
68
|
+
{ text: "italic", options: { italic: true } }
|
|
69
|
+
], {
|
|
70
|
+
x: 0.5, y: 2, w: 9, h: 1,
|
|
71
|
+
fontSize: 14,
|
|
72
|
+
fontFace: "Arial",
|
|
73
|
+
color: "1E293B",
|
|
74
|
+
align: "left"
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Bullets & Line Breaks
|
|
79
|
+
|
|
80
|
+
Always use `bullet: true` with `breakLine: true` between items:
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
slide.addText([
|
|
84
|
+
{ text: "First point", options: { bullet: true, breakLine: true } },
|
|
85
|
+
{ text: "Second point", options: { bullet: true, breakLine: true } },
|
|
86
|
+
{ text: "Third point", options: { bullet: true, breakLine: false } } // Last item
|
|
87
|
+
], {
|
|
88
|
+
x: 0.7, y: 2, w: 8.6, h: 2,
|
|
89
|
+
fontSize: 14,
|
|
90
|
+
fontFace: "Arial",
|
|
91
|
+
color: "1E293B",
|
|
92
|
+
paraSpaceAfter: 6, // Space after each paragraph
|
|
93
|
+
valign: "top"
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Never use Unicode bullets** like `•` or `◦`. Always use `bullet: true`.
|
|
98
|
+
|
|
99
|
+
### Text Block with Padding
|
|
100
|
+
|
|
101
|
+
Use `margin` to add internal padding:
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
slide.addText("This text has padding", {
|
|
105
|
+
x: 1, y: 1, w: 8, h: 2,
|
|
106
|
+
fontSize: 14,
|
|
107
|
+
margin: [0.2, 0.3, 0.2, 0.3], // [top, right, bottom, left]
|
|
108
|
+
align: "left"
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Shapes
|
|
113
|
+
|
|
114
|
+
### Rectangle
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
slide.addShape(pres.shapes.RECTANGLE, {
|
|
118
|
+
x: 1, y: 1, w: 4, h: 2,
|
|
119
|
+
fill: { color: "E74C3C" },
|
|
120
|
+
line: { color: "C0392B", width: 2 }, // Border
|
|
121
|
+
shadow: {
|
|
122
|
+
type: "outer",
|
|
123
|
+
color: "000000",
|
|
124
|
+
blur: 6,
|
|
125
|
+
offset: 2,
|
|
126
|
+
angle: 135,
|
|
127
|
+
opacity: 0.1
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Oval / Circle
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
slide.addShape(pres.shapes.OVAL, {
|
|
136
|
+
x: 1, y: 1, w: 1.5, h: 1.5, // Width and height equal = circle
|
|
137
|
+
fill: { color: "F5A623" }
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Rounded Rectangle
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, {
|
|
145
|
+
x: 1, y: 1, w: 4, h: 2,
|
|
146
|
+
fill: { color: "FFFFFF" },
|
|
147
|
+
rectRadius: 0.1, // Corner radius in inches
|
|
148
|
+
shadow: { type: "outer", color: "000000", blur: 4, offset: 1, angle: 135, opacity: 0.08 }
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Line
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
slide.addShape(pres.shapes.LINE, {
|
|
156
|
+
x: 1, y: 2, w: 4, h: 0, // Height 0 for horizontal line
|
|
157
|
+
line: { color: "F5A623", width: 3 }
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Shape Properties Reference
|
|
162
|
+
|
|
163
|
+
| Property | Type | Notes |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| `x, y, w, h` | number | Position (inches) and size |
|
|
166
|
+
| `fill` | object | `{ color: "HEX" }` or `{ type: "solid", color: "HEX", transparency: 0 }` |
|
|
167
|
+
| `line` | object | `{ color: "HEX", width: 2, dashType: "solid" \| "dash" }` |
|
|
168
|
+
| `shadow` | object | `{ type: "outer", color, blur, offset, angle, opacity }` |
|
|
169
|
+
| `transparency` | number | 0-100. Use `fill.transparency`, not color string. |
|
|
170
|
+
| `rotate` | number | Degrees (0-360) |
|
|
171
|
+
|
|
172
|
+
## Images
|
|
173
|
+
|
|
174
|
+
### From File Path
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
slide.addImage({
|
|
178
|
+
path: "/path/to/image.jpg",
|
|
179
|
+
x: 5, y: 1, w: 4, h: 2.5
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### From URL
|
|
184
|
+
|
|
185
|
+
```javascript
|
|
186
|
+
slide.addImage({
|
|
187
|
+
url: "https://example.com/logo.png",
|
|
188
|
+
x: 5, y: 1, w: 4, h: 2.5
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### From Base64
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
const base64Data = "data:image/png;base64,iVBORw0KGgo...";
|
|
196
|
+
slide.addImage({
|
|
197
|
+
data: base64Data,
|
|
198
|
+
x: 5, y: 1, w: 4, h: 2.5
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Sizing Modes
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
slide.addImage({
|
|
206
|
+
path: "/image.jpg",
|
|
207
|
+
x: 1, y: 1, w: 4, h: 2.5,
|
|
208
|
+
sizing: {
|
|
209
|
+
type: "cover", // "cover" = crop to fill, "contain" = fit inside
|
|
210
|
+
w: 4,
|
|
211
|
+
h: 2.5
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Icons
|
|
217
|
+
|
|
218
|
+
Convert React Icons to base64 PNG and embed:
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
// 1. Generate SVG from react-icons, save as .svg
|
|
222
|
+
// 2. Convert to PNG with sharp: sharp('icon.svg').png().toFile('icon.png')
|
|
223
|
+
// 3. Convert PNG to base64
|
|
224
|
+
const fs = require('fs');
|
|
225
|
+
const iconBase64 = fs.readFileSync('icon.png', 'base64');
|
|
226
|
+
const iconDataUri = `data:image/png;base64,${iconBase64}`;
|
|
227
|
+
|
|
228
|
+
// 4. Add to slide
|
|
229
|
+
slide.addShape(pres.shapes.OVAL, {
|
|
230
|
+
x: 1, y: 1, w: 0.4, h: 0.4,
|
|
231
|
+
fill: { color: "F5A623" }
|
|
232
|
+
});
|
|
233
|
+
slide.addImage({
|
|
234
|
+
data: iconDataUri,
|
|
235
|
+
x: 1.05, y: 1.05, w: 0.3, h: 0.3
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Slide Backgrounds
|
|
240
|
+
|
|
241
|
+
### Solid Color
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
const slide = pres.addSlide();
|
|
245
|
+
slide.background = { color: "1E2761" };
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Gradient
|
|
249
|
+
|
|
250
|
+
```javascript
|
|
251
|
+
slide.background = {
|
|
252
|
+
type: "solid",
|
|
253
|
+
fill: "F8FAFC"
|
|
254
|
+
};
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Tables
|
|
258
|
+
|
|
259
|
+
### Basic Table
|
|
260
|
+
|
|
261
|
+
```javascript
|
|
262
|
+
const tableData = [
|
|
263
|
+
[
|
|
264
|
+
{ text: "Header A", options: { bold: true, color: "FFFFFF", fill: { color: "1E2761" } } },
|
|
265
|
+
{ text: "Header B", options: { bold: true, color: "FFFFFF", fill: { color: "1E2761" } } }
|
|
266
|
+
],
|
|
267
|
+
[
|
|
268
|
+
{ text: "Row 1, Col A", options: {} },
|
|
269
|
+
{ text: "Row 1, Col B", options: { fill: { color: "F8FAFC" } } }
|
|
270
|
+
],
|
|
271
|
+
[
|
|
272
|
+
{ text: "Row 2, Col A", options: { fill: { color: "F8FAFC" } } },
|
|
273
|
+
{ text: "Row 2, Col B", options: {} }
|
|
274
|
+
]
|
|
275
|
+
];
|
|
276
|
+
|
|
277
|
+
slide.addTable(tableData, {
|
|
278
|
+
x: 0.5, y: 2, w: 9, h: 2,
|
|
279
|
+
colW: [4.5, 4.5], // Column widths
|
|
280
|
+
border: { pt: 1, color: "E2E8F0" },
|
|
281
|
+
fontFace: "Arial",
|
|
282
|
+
fontSize: 12
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Table with Merged Cells
|
|
287
|
+
|
|
288
|
+
```javascript
|
|
289
|
+
const tableData = [
|
|
290
|
+
[
|
|
291
|
+
{ text: "Merged", options: {}, colspan: 2 }, // Spans 2 columns
|
|
292
|
+
{ text: "Normal", options: {} }
|
|
293
|
+
]
|
|
294
|
+
];
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Charts
|
|
298
|
+
|
|
299
|
+
### Bar Chart
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
const barData = [
|
|
303
|
+
{
|
|
304
|
+
name: "Series 1",
|
|
305
|
+
labels: ["Q1", "Q2", "Q3", "Q4"],
|
|
306
|
+
values: [15, 22, 18, 25]
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
name: "Series 2",
|
|
310
|
+
labels: ["Q1", "Q2", "Q3", "Q4"],
|
|
311
|
+
values: [12, 20, 16, 23]
|
|
312
|
+
}
|
|
313
|
+
];
|
|
314
|
+
|
|
315
|
+
slide.addChart(pres.ChartTypes.bar, barData, {
|
|
316
|
+
x: 1, y: 1, w: 8, h: 3,
|
|
317
|
+
chartColors: ["2E86AB", "F5A623"],
|
|
318
|
+
showLegend: true,
|
|
319
|
+
dataLabelPosition: "outEnd" // Outside bars
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Line Chart
|
|
324
|
+
|
|
325
|
+
```javascript
|
|
326
|
+
const lineData = [
|
|
327
|
+
{
|
|
328
|
+
name: "Revenue",
|
|
329
|
+
labels: ["Jan", "Feb", "Mar", "Apr"],
|
|
330
|
+
values: [100, 120, 140, 160]
|
|
331
|
+
}
|
|
332
|
+
];
|
|
333
|
+
|
|
334
|
+
slide.addChart(pres.ChartTypes.line, lineData, {
|
|
335
|
+
x: 1, y: 1, w: 8, h: 3,
|
|
336
|
+
lineSize: 2,
|
|
337
|
+
chartColors: ["F5A623"],
|
|
338
|
+
dataLabelPosition: "outEnd"
|
|
339
|
+
});
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Pie Chart
|
|
343
|
+
|
|
344
|
+
```javascript
|
|
345
|
+
const pieData = [
|
|
346
|
+
{
|
|
347
|
+
name: "Category",
|
|
348
|
+
labels: ["Segment A", "Segment B", "Segment C"],
|
|
349
|
+
values: [30, 25, 45]
|
|
350
|
+
}
|
|
351
|
+
];
|
|
352
|
+
|
|
353
|
+
slide.addChart(pres.ChartTypes.pie, pieData, {
|
|
354
|
+
x: 1, y: 1, w: 4, h: 3,
|
|
355
|
+
chartColors: ["2E86AB", "F5A623", "E74C3C"],
|
|
356
|
+
dataLabelPosition: "ctr" // Center
|
|
357
|
+
});
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Chart Options
|
|
361
|
+
|
|
362
|
+
| Option | Values | Notes |
|
|
363
|
+
|---|---|---|
|
|
364
|
+
| `chartColors` | Array of hex colors | Controls bar/line/pie segment colors |
|
|
365
|
+
| `dataLabelPosition` | `"outEnd"`, `"ctr"`, `"inEnd"`, `"ctrH"` | Where labels appear |
|
|
366
|
+
| `dataLabelFontSize` | number | Font size of data labels |
|
|
367
|
+
| `gridLines` | object | `{ style: "solid", color: "E0E0E0", size: 1 }` |
|
|
368
|
+
| `showLegend` | boolean | Show legend on chart |
|
|
369
|
+
| `legendPos` | `"b"`, `"r"`, `"t"`, `"l"` | Legend position (bottom, right, top, left) |
|
|
370
|
+
|
|
371
|
+
## Slide Masters
|
|
372
|
+
|
|
373
|
+
Define a master slide template and reuse it:
|
|
374
|
+
|
|
375
|
+
```javascript
|
|
376
|
+
// Define master
|
|
377
|
+
pres.defineLayout({ name: "MASTER_CONTENT" }, (slide) => {
|
|
378
|
+
slide.background = { color: "F8FAFC" };
|
|
379
|
+
|
|
380
|
+
// Add a footer
|
|
381
|
+
slide.addText("© 2024 Company", {
|
|
382
|
+
x: 0.5, y: H - 0.4, w: 9, h: 0.3,
|
|
383
|
+
fontSize: 8,
|
|
384
|
+
color: "64748B",
|
|
385
|
+
align: "right"
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// Use master
|
|
390
|
+
const slide = pres.addSlide("MASTER_CONTENT");
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Common Pitfalls
|
|
394
|
+
|
|
395
|
+
### Colors
|
|
396
|
+
|
|
397
|
+
- **NEVER use `#` with hex colors** — `"#FF0000"` corrupts the file. Always use `"FF0000"`.
|
|
398
|
+
- **NEVER encode opacity in hex** — Don't try `"FF0000CC"`. Use `fill: { color: "FF0000", transparency: 50 }` instead.
|
|
399
|
+
|
|
400
|
+
### Bullets
|
|
401
|
+
|
|
402
|
+
- **Always use `bullet: true`** — Never try to build bullets manually with Unicode bullets.
|
|
403
|
+
- **Always use `breakLine: true` between items** — This is required for proper spacing.
|
|
404
|
+
- **Avoid `lineSpacing` with bullets** — Use `paraSpaceAfter: 6` instead for better control.
|
|
405
|
+
|
|
406
|
+
### Objects & Mutations
|
|
407
|
+
|
|
408
|
+
- **Create fresh option objects for each call** — PptxGenJS mutates option objects. Reusing the same object across multiple `addShape` or `addText` calls causes unexpected behavior.
|
|
409
|
+
|
|
410
|
+
```javascript
|
|
411
|
+
// WRONG: Shadow object reused
|
|
412
|
+
const shadow = { type: "outer", color: "000000", blur: 6, offset: 2, opacity: 0.1 };
|
|
413
|
+
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 2, h: 1, shadow });
|
|
414
|
+
slide.addShape(pres.shapes.RECTANGLE, { x: 4, y: 1, w: 2, h: 1, shadow });
|
|
415
|
+
|
|
416
|
+
// RIGHT: Fresh shadow for each shape
|
|
417
|
+
slide.addShape(pres.shapes.RECTANGLE, {
|
|
418
|
+
x: 1, y: 1, w: 2, h: 1,
|
|
419
|
+
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, opacity: 0.1 }
|
|
420
|
+
});
|
|
421
|
+
slide.addShape(pres.shapes.RECTANGLE, {
|
|
422
|
+
x: 4, y: 1, w: 2, h: 1,
|
|
423
|
+
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, opacity: 0.1 }
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Shadow Offsets
|
|
428
|
+
|
|
429
|
+
- **Shadow `offset` must be non-negative** — Negative values cause file corruption. Use positive values only.
|
|
430
|
+
- **Typical shadow: blur 6, offset 2, opacity 0.08-0.1** — This creates a subtle drop shadow.
|
|
431
|
+
|
|
432
|
+
### Rounded Rectangles
|
|
433
|
+
|
|
434
|
+
- **Don't pair rounded rectangles with accent borders** — Rounded rectangles with thick borders (> 2pt) look awkward. Use subtle shadows instead.
|
|
435
|
+
|
|
436
|
+
## Quick Reference
|
|
437
|
+
|
|
438
|
+
### Shape Types
|
|
439
|
+
```javascript
|
|
440
|
+
pres.shapes.RECTANGLE
|
|
441
|
+
pres.shapes.OVAL
|
|
442
|
+
pres.shapes.LINE
|
|
443
|
+
pres.shapes.ROUNDED_RECTANGLE
|
|
444
|
+
pres.shapes.DIAMOND
|
|
445
|
+
pres.shapes.TRIANGLE
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Chart Types
|
|
449
|
+
```javascript
|
|
450
|
+
pres.ChartTypes.bar
|
|
451
|
+
pres.ChartTypes.line
|
|
452
|
+
pres.ChartTypes.pie
|
|
453
|
+
pres.ChartTypes.doughnut
|
|
454
|
+
pres.ChartTypes.area
|
|
455
|
+
pres.ChartTypes.scatter
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Text Alignment
|
|
459
|
+
```javascript
|
|
460
|
+
align: "left" | "center" | "right"
|
|
461
|
+
valign: "top" | "middle" | "bottom"
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Common Font Faces
|
|
465
|
+
```javascript
|
|
466
|
+
"Arial"
|
|
467
|
+
"Arial Black"
|
|
468
|
+
"Calibri"
|
|
469
|
+
"Georgia"
|
|
470
|
+
"Trebuchet MS"
|
|
471
|
+
"Helvetica"
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Sizing Guidelines
|
|
475
|
+
|
|
476
|
+
| Element | Size (pt) |
|
|
477
|
+
|---|---|
|
|
478
|
+
| Slide title | 20-28 |
|
|
479
|
+
| Section heading | 18 |
|
|
480
|
+
| Body text | 14 |
|
|
481
|
+
| Bullet text | 14 |
|
|
482
|
+
| Captions | 10-11 |
|
|
483
|
+
| Stat numbers | 60 |
|
|
484
|
+
| Stat labels | 12 |
|
|
485
|
+
| Table header | 11-12 |
|
|
486
|
+
| Table body | 11 |
|
|
487
|
+
|
|
488
|
+
### Spacing Guidelines
|
|
489
|
+
|
|
490
|
+
| Element | Value |
|
|
491
|
+
|---|---|
|
|
492
|
+
| Slide margins | 0.5" |
|
|
493
|
+
| Content block gap | 0.3-0.5" |
|
|
494
|
+
| Line height multiplier | 1.3 |
|
|
495
|
+
| Bullet spacing | `paraSpaceAfter: 6` |
|
|
496
|
+
| Card shadow blur | 6 |
|
|
497
|
+
| Card shadow offset | 2 |
|
|
498
|
+
| Card shadow opacity | 0.08-0.1 |
|
|
499
|
+
| Accent bar height | 0.06" |
|
|
500
|
+
|
|
501
|
+
## Pattern: Professional Stat Card
|
|
502
|
+
|
|
503
|
+
```javascript
|
|
504
|
+
// Background card
|
|
505
|
+
slide.addShape(pres.shapes.RECTANGLE, {
|
|
506
|
+
x: 1, y: 1, w: 2.5, h: 2,
|
|
507
|
+
fill: { color: "FFFFFF" },
|
|
508
|
+
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, opacity: 0.08 }
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
// Color bar at top
|
|
512
|
+
slide.addShape(pres.shapes.RECTANGLE, {
|
|
513
|
+
x: 1, y: 1, w: 2.5, h: 0.06,
|
|
514
|
+
fill: { color: "F5A623" }
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// Large number
|
|
518
|
+
slide.addText("3x", {
|
|
519
|
+
x: 1, y: 1.4, w: 2.5, h: 0.8,
|
|
520
|
+
fontSize: 60,
|
|
521
|
+
fontFace: "Arial Black",
|
|
522
|
+
color: "F5A623",
|
|
523
|
+
bold: true,
|
|
524
|
+
align: "center"
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
// Label
|
|
528
|
+
slide.addText("User Growth", {
|
|
529
|
+
x: 1.2, y: 2.3, w: 2.1, h: 0.5,
|
|
530
|
+
fontSize: 12,
|
|
531
|
+
fontFace: "Arial",
|
|
532
|
+
color: "64748B",
|
|
533
|
+
align: "center"
|
|
534
|
+
});
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
## Pattern: Two-Column Layout
|
|
538
|
+
|
|
539
|
+
```javascript
|
|
540
|
+
const colW = (9 - 0.3) / 2; // Two equal columns
|
|
541
|
+
|
|
542
|
+
// Left column
|
|
543
|
+
slide.addText([
|
|
544
|
+
{ text: "Point 1", options: { bullet: true, breakLine: true } },
|
|
545
|
+
{ text: "Point 2", options: { bullet: true, breakLine: true } },
|
|
546
|
+
{ text: "Point 3", options: { bullet: true, breakLine: false } }
|
|
547
|
+
], {
|
|
548
|
+
x: 0.5, y: 1.5, w: colW, h: 3,
|
|
549
|
+
fontSize: 14,
|
|
550
|
+
fontFace: "Arial",
|
|
551
|
+
color: "1E293B",
|
|
552
|
+
valign: "top",
|
|
553
|
+
paraSpaceAfter: 6
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
// Right column
|
|
557
|
+
slide.addText([
|
|
558
|
+
{ text: "Benefit 1", options: { bullet: true, breakLine: true } },
|
|
559
|
+
{ text: "Benefit 2", options: { bullet: true, breakLine: true } },
|
|
560
|
+
{ text: "Benefit 3", options: { bullet: true, breakLine: false } }
|
|
561
|
+
], {
|
|
562
|
+
x: 0.5 + colW + 0.3, y: 1.5, w: colW, h: 3,
|
|
563
|
+
fontSize: 14,
|
|
564
|
+
fontFace: "Arial",
|
|
565
|
+
color: "1E293B",
|
|
566
|
+
valign: "top",
|
|
567
|
+
paraSpaceAfter: 6
|
|
568
|
+
});
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## Example: Complete Slide
|
|
572
|
+
|
|
573
|
+
```javascript
|
|
574
|
+
const PptxGenJS = require("pptxgenjs");
|
|
575
|
+
const pres = new PptxGenJS();
|
|
576
|
+
pres.layout = "LAYOUT_16x9";
|
|
577
|
+
pres.author = "Jane Doe";
|
|
578
|
+
pres.title = "Q4 Results";
|
|
579
|
+
|
|
580
|
+
const slide = pres.addSlide();
|
|
581
|
+
const W = 10, H = 5.625, M = 0.5, CW = 9;
|
|
582
|
+
|
|
583
|
+
// Background
|
|
584
|
+
slide.background = { color: "F8FAFC" };
|
|
585
|
+
|
|
586
|
+
// Title
|
|
587
|
+
slide.addText("Revenue Beat Target by 15%", {
|
|
588
|
+
x: M, y: M, w: CW, h: 0.6,
|
|
589
|
+
fontSize: 20,
|
|
590
|
+
fontFace: "Arial Black",
|
|
591
|
+
color: "1E293B",
|
|
592
|
+
bold: true
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
// Accent underline
|
|
596
|
+
slide.addShape(pres.shapes.RECTANGLE, {
|
|
597
|
+
x: M, y: M + 0.6, w: 0.8, h: 0.04,
|
|
598
|
+
fill: { color: "F5A623" }
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
// Body text
|
|
602
|
+
slide.addText("We exceeded quarterly targets across all regions.", {
|
|
603
|
+
x: M, y: M + 1, w: CW, h: 0.6,
|
|
604
|
+
fontSize: 14,
|
|
605
|
+
fontFace: "Arial",
|
|
606
|
+
color: "1E293B"
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
// Bullet points
|
|
610
|
+
slide.addText([
|
|
611
|
+
{ text: "Sales team landed 3 enterprise deals", options: { bullet: true, breakLine: true } },
|
|
612
|
+
{ text: "Product revenue grew 22% MoM", options: { bullet: true, breakLine: true } },
|
|
613
|
+
{ text: "Customer retention at 96%", options: { bullet: true, breakLine: false } }
|
|
614
|
+
], {
|
|
615
|
+
x: M + 0.2, y: M + 1.8, w: CW - 0.4, h: 2,
|
|
616
|
+
fontSize: 14,
|
|
617
|
+
fontFace: "Arial",
|
|
618
|
+
color: "1E293B",
|
|
619
|
+
paraSpaceAfter: 6,
|
|
620
|
+
valign: "top"
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
pres.writeFile({ fileName: "output.pptx" });
|
|
624
|
+
```
|