@hirokisakabe/pom 0.1.10 → 0.1.12
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/README.md +198 -177
- package/dist/inputSchema.d.ts +14 -0
- package/dist/inputSchema.d.ts.map +1 -1
- package/dist/inputSchema.js +4 -1
- package/dist/parsePptx/convertChart.d.ts +8 -0
- package/dist/parsePptx/convertChart.d.ts.map +1 -0
- package/dist/parsePptx/convertChart.js +78 -0
- package/dist/parsePptx/convertImage.d.ts +8 -0
- package/dist/parsePptx/convertImage.d.ts.map +1 -0
- package/dist/parsePptx/convertImage.js +13 -0
- package/dist/parsePptx/convertShape.d.ts +7 -0
- package/dist/parsePptx/convertShape.d.ts.map +1 -0
- package/dist/parsePptx/convertShape.js +137 -0
- package/dist/parsePptx/convertTable.d.ts +7 -0
- package/dist/parsePptx/convertTable.d.ts.map +1 -0
- package/dist/parsePptx/convertTable.js +46 -0
- package/dist/parsePptx/convertText.d.ts +7 -0
- package/dist/parsePptx/convertText.d.ts.map +1 -0
- package/dist/parsePptx/convertText.js +32 -0
- package/dist/parsePptx/index.d.ts +23 -0
- package/dist/parsePptx/index.d.ts.map +1 -0
- package/dist/parsePptx/index.js +114 -0
- package/dist/parsePptx/parseHtml.d.ts +22 -0
- package/dist/parsePptx/parseHtml.d.ts.map +1 -0
- package/dist/parsePptx/parseHtml.js +53 -0
- package/dist/parsePptx/types.d.ts +15 -0
- package/dist/parsePptx/types.d.ts.map +1 -0
- package/dist/parsePptx/types.js +1 -0
- package/dist/parsePptx/units.d.ts +13 -0
- package/dist/parsePptx/units.d.ts.map +1 -0
- package/dist/parsePptx/units.js +19 -0
- package/dist/renderPptx/renderPptx.d.ts.map +1 -1
- package/dist/renderPptx/renderPptx.js +15 -2
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +12 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
# pom
|
|
2
2
|
|
|
3
|
-
**pom (PowerPoint Object Model)**
|
|
3
|
+
**pom (PowerPoint Object Model)** is a library for declaratively describing PowerPoint presentations (pptx) in TypeScript. It is designed for use cases where JSON in POM format generated by AI is converted into PowerPoint files.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Requirements
|
|
6
6
|
|
|
7
|
-
- Node.js 18
|
|
7
|
+
- Node.js 18 or higher
|
|
8
8
|
|
|
9
9
|
> [!NOTE]
|
|
10
|
-
> PPTX
|
|
10
|
+
> The PPTX generation feature (`buildPptx`) only works in Node.js environments. However, if you only need the input schema, you can import it from `@hirokisakabe/pom/schema` for use in browser environments.
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Table of Contents
|
|
13
13
|
|
|
14
|
-
- [
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
21
|
-
- [LLM
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
14
|
+
- [Requirements](#requirements)
|
|
15
|
+
- [Installation](#installation)
|
|
16
|
+
- [Quick Start](#quick-start)
|
|
17
|
+
- [Features](#features)
|
|
18
|
+
- [Nodes](#nodes)
|
|
19
|
+
- [Master Slide](#master-slide)
|
|
20
|
+
- [Serverless Environments](#serverless-environments)
|
|
21
|
+
- [LLM Integration](#llm-integration)
|
|
22
|
+
- [Input Validation in Browser Environments](#input-validation-in-browser-environments)
|
|
23
|
+
- [License](#license)
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Installation
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
28
|
npm install @hirokisakabe/pom
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## Quick Start
|
|
32
32
|
|
|
33
33
|
```typescript
|
|
34
34
|
import { buildPptx, POMNode } from "@hirokisakabe/pom";
|
|
@@ -43,13 +43,13 @@ const slide: POMNode = {
|
|
|
43
43
|
children: [
|
|
44
44
|
{
|
|
45
45
|
type: "text",
|
|
46
|
-
text: "
|
|
46
|
+
text: "Presentation Title",
|
|
47
47
|
fontPx: 48,
|
|
48
48
|
bold: true,
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
type: "text",
|
|
52
|
-
text: "
|
|
52
|
+
text: "Subtitle",
|
|
53
53
|
fontPx: 24,
|
|
54
54
|
color: "666666",
|
|
55
55
|
},
|
|
@@ -60,21 +60,21 @@ const pptx = await buildPptx([slide], { w: 1280, h: 720 });
|
|
|
60
60
|
await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
##
|
|
63
|
+
## Features
|
|
64
64
|
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
- **PowerPoint
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
- **AI
|
|
65
|
+
- **Type-safe**: Strict type definitions with TypeScript
|
|
66
|
+
- **Declarative**: Describe slides with JSON-like objects
|
|
67
|
+
- **PowerPoint First**: Native support for Shape features
|
|
68
|
+
- **Flexible Layout**: Automatic layout with VStack/HStack/Box
|
|
69
|
+
- **Pixel Units**: Intuitive pixel-based sizing (internally converted to inches)
|
|
70
|
+
- **Master Slide**: Automatically insert common headers, footers, and page numbers across all pages
|
|
71
|
+
- **AI Friendly**: Simple structure that makes it easy for LLMs to generate code
|
|
72
72
|
|
|
73
|
-
##
|
|
73
|
+
## Nodes
|
|
74
74
|
|
|
75
|
-
###
|
|
75
|
+
### Common Properties
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
Layout attributes that all nodes can have.
|
|
78
78
|
|
|
79
79
|
```typescript
|
|
80
80
|
{
|
|
@@ -91,17 +91,19 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
91
91
|
width?: number;
|
|
92
92
|
dashType?: "solid" | "dash" | "dashDot" | "lgDash" | "lgDashDot" | "lgDashDotDot" | "sysDash" | "sysDot";
|
|
93
93
|
};
|
|
94
|
+
borderRadius?: number;
|
|
94
95
|
}
|
|
95
96
|
```
|
|
96
97
|
|
|
97
|
-
- `backgroundColor`
|
|
98
|
-
- `border.width`
|
|
98
|
+
- `backgroundColor` applies a fill to the entire node (e.g., `"F8F9FA"`).
|
|
99
|
+
- `border.width` is specified in px and can be combined with color and `dashType` to control the border.
|
|
100
|
+
- `borderRadius` specifies the corner radius in px. When specified, the background/border shape becomes a rounded rectangle.
|
|
99
101
|
|
|
100
|
-
###
|
|
102
|
+
### Node List
|
|
101
103
|
|
|
102
104
|
#### 1. Text
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
A node for displaying text.
|
|
105
107
|
|
|
106
108
|
```typescript
|
|
107
109
|
{
|
|
@@ -115,79 +117,79 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
115
117
|
lineSpacingMultiple?: number;
|
|
116
118
|
bullet?: boolean | BulletOptions;
|
|
117
119
|
|
|
118
|
-
//
|
|
120
|
+
// Common properties
|
|
119
121
|
w?: number | "max" | `${number}%`;
|
|
120
122
|
h?: number | "max" | `${number}%`;
|
|
121
123
|
...
|
|
122
124
|
}
|
|
123
125
|
```
|
|
124
126
|
|
|
125
|
-
- `color`
|
|
126
|
-
- `bold`
|
|
127
|
-
- `fontFamily`
|
|
128
|
-
- `lineSpacingMultiple`
|
|
129
|
-
- `bullet`
|
|
127
|
+
- `color` specifies the text color as a hex color code (e.g., `"FF0000"`).
|
|
128
|
+
- `bold` enables bold text.
|
|
129
|
+
- `fontFamily` specifies the font family (default: `"Noto Sans JP"`).
|
|
130
|
+
- `lineSpacingMultiple` specifies the line spacing multiplier (default: `1.3`).
|
|
131
|
+
- `bullet` enables bullet points. Use `true` for default bullets, or an object for detailed settings.
|
|
130
132
|
|
|
131
133
|
**BulletOptions:**
|
|
132
134
|
|
|
133
135
|
```typescript
|
|
134
136
|
{
|
|
135
|
-
type?: "bullet" | "number"; // "bullet":
|
|
136
|
-
indent?: number; //
|
|
137
|
+
type?: "bullet" | "number"; // "bullet": symbol, "number": numbered
|
|
138
|
+
indent?: number; // Indent level
|
|
137
139
|
numberType?: "alphaLcParenBoth" | "alphaLcParenR" | "alphaLcPeriod" |
|
|
138
140
|
"alphaUcParenBoth" | "alphaUcParenR" | "alphaUcPeriod" |
|
|
139
141
|
"arabicParenBoth" | "arabicParenR" | "arabicPeriod" | "arabicPlain" |
|
|
140
142
|
"romanLcParenBoth" | "romanLcParenR" | "romanLcPeriod" |
|
|
141
143
|
"romanUcParenBoth" | "romanUcParenR" | "romanUcPeriod";
|
|
142
|
-
numberStartAt?: number; //
|
|
144
|
+
numberStartAt?: number; // Starting number
|
|
143
145
|
}
|
|
144
146
|
```
|
|
145
147
|
|
|
146
|
-
|
|
148
|
+
**Usage Examples:**
|
|
147
149
|
|
|
148
150
|
```typescript
|
|
149
|
-
//
|
|
151
|
+
// Simple bullet list
|
|
150
152
|
{
|
|
151
153
|
type: "text",
|
|
152
|
-
text: "
|
|
154
|
+
text: "Item 1\nItem 2\nItem 3",
|
|
153
155
|
bullet: true,
|
|
154
156
|
}
|
|
155
157
|
|
|
156
|
-
//
|
|
158
|
+
// Numbered list
|
|
157
159
|
{
|
|
158
160
|
type: "text",
|
|
159
|
-
text: "
|
|
161
|
+
text: "Step 1\nStep 2\nStep 3",
|
|
160
162
|
bullet: { type: "number" },
|
|
161
163
|
}
|
|
162
164
|
|
|
163
|
-
//
|
|
165
|
+
// Lowercase alphabet (a. b. c.)
|
|
164
166
|
{
|
|
165
167
|
type: "text",
|
|
166
|
-
text: "
|
|
168
|
+
text: "Item A\nItem B\nItem C",
|
|
167
169
|
bullet: { type: "number", numberType: "alphaLcPeriod" },
|
|
168
170
|
}
|
|
169
171
|
|
|
170
|
-
// 5
|
|
172
|
+
// Numbered list starting from 5
|
|
171
173
|
{
|
|
172
174
|
type: "text",
|
|
173
|
-
text: "
|
|
175
|
+
text: "Fifth\nSixth\nSeventh",
|
|
174
176
|
bullet: { type: "number", numberStartAt: 5 },
|
|
175
177
|
}
|
|
176
178
|
```
|
|
177
179
|
|
|
178
180
|
#### 2. Image
|
|
179
181
|
|
|
180
|
-
|
|
182
|
+
A node for displaying images.
|
|
181
183
|
|
|
182
|
-
- `w`
|
|
183
|
-
-
|
|
184
|
+
- If `w` and `h` are not specified, the actual image size is automatically used
|
|
185
|
+
- If size is specified, the image is displayed at that size (aspect ratio is not preserved)
|
|
184
186
|
|
|
185
187
|
```typescript
|
|
186
188
|
{
|
|
187
189
|
type: "image";
|
|
188
|
-
src: string; //
|
|
190
|
+
src: string; // Image path (local path, URL, or base64 data)
|
|
189
191
|
|
|
190
|
-
//
|
|
192
|
+
// Common properties
|
|
191
193
|
w?: number | "max" | `${number}%`;
|
|
192
194
|
h?: number | "max" | `${number}%`;
|
|
193
195
|
...
|
|
@@ -196,7 +198,7 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
196
198
|
|
|
197
199
|
#### 3. Table
|
|
198
200
|
|
|
199
|
-
|
|
201
|
+
A node for drawing tables. Column widths and row heights are declared in px, with fine-grained control over cell decoration.
|
|
200
202
|
|
|
201
203
|
```typescript
|
|
202
204
|
{
|
|
@@ -215,27 +217,27 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
215
217
|
}[];
|
|
216
218
|
defaultRowHeight?: number;
|
|
217
219
|
|
|
218
|
-
//
|
|
220
|
+
// Common properties
|
|
219
221
|
w?: number | "max" | `${number}%`;
|
|
220
222
|
h?: number | "max" | `${number}%`;
|
|
221
223
|
...
|
|
222
224
|
}
|
|
223
225
|
```
|
|
224
226
|
|
|
225
|
-
- `columns[].width`
|
|
226
|
-
- `columns`
|
|
227
|
-
- `rows`
|
|
228
|
-
-
|
|
227
|
+
- If `columns[].width` is omitted, columns are evenly distributed across the table width.
|
|
228
|
+
- The sum of `columns` becomes the natural width of the table (can be overridden with `w` if needed).
|
|
229
|
+
- If `rows` `height` is omitted, `defaultRowHeight` is applied (32px if unspecified).
|
|
230
|
+
- Cell background and font decoration can be specified individually for each element in `cells`.
|
|
229
231
|
|
|
230
232
|
#### 4. Shape
|
|
231
233
|
|
|
232
|
-
|
|
234
|
+
A node for drawing shapes. Different representations are possible with or without text, supporting complex visual effects.
|
|
233
235
|
|
|
234
236
|
```typescript
|
|
235
237
|
{
|
|
236
238
|
type: "shape";
|
|
237
|
-
shapeType: PptxGenJS.SHAPE_NAME; //
|
|
238
|
-
text?: string; //
|
|
239
|
+
shapeType: PptxGenJS.SHAPE_NAME; // e.g., "roundRect", "ellipse", "cloud", "star5"
|
|
240
|
+
text?: string; // Text to display inside the shape (optional)
|
|
239
241
|
fill?: {
|
|
240
242
|
color?: string;
|
|
241
243
|
transparency?: number;
|
|
@@ -257,36 +259,36 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
257
259
|
color?: string;
|
|
258
260
|
alignText?: "left" | "center" | "right";
|
|
259
261
|
|
|
260
|
-
//
|
|
262
|
+
// Common properties
|
|
261
263
|
w?: number | "max" | `${number}%`;
|
|
262
264
|
h?: number | "max" | `${number}%`;
|
|
263
265
|
...
|
|
264
266
|
}
|
|
265
267
|
```
|
|
266
268
|
|
|
267
|
-
|
|
269
|
+
**Common Shape Types:**
|
|
268
270
|
|
|
269
|
-
- `roundRect`:
|
|
270
|
-
- `ellipse`:
|
|
271
|
-
- `cloud`:
|
|
272
|
-
- `wedgeRectCallout`:
|
|
273
|
-
- `cloudCallout`:
|
|
274
|
-
- `star5`: 5
|
|
275
|
-
- `downArrow`:
|
|
271
|
+
- `roundRect`: Rounded rectangle (title boxes, category displays)
|
|
272
|
+
- `ellipse`: Ellipse/circle (step numbers, badges)
|
|
273
|
+
- `cloud`: Cloud shape (comments, key points)
|
|
274
|
+
- `wedgeRectCallout`: Callout with arrow (annotations)
|
|
275
|
+
- `cloudCallout`: Cloud callout (comments)
|
|
276
|
+
- `star5`: 5-pointed star (emphasis, decoration)
|
|
277
|
+
- `downArrow`: Down arrow (flow diagrams)
|
|
276
278
|
|
|
277
279
|
#### 5. Box
|
|
278
280
|
|
|
279
|
-
|
|
281
|
+
A generic container that wraps a single child element.
|
|
280
282
|
|
|
281
|
-
-
|
|
282
|
-
- padding
|
|
283
|
+
- Only **one** child element
|
|
284
|
+
- Used for grouping with padding or fixed size
|
|
283
285
|
|
|
284
286
|
```typescript
|
|
285
287
|
{
|
|
286
288
|
type: "box";
|
|
287
289
|
children: POMNode;
|
|
288
290
|
|
|
289
|
-
//
|
|
291
|
+
// Common properties
|
|
290
292
|
w?: number | "max" | `${number}%`;
|
|
291
293
|
h?: number | "max" | `${number}%`;
|
|
292
294
|
...
|
|
@@ -295,7 +297,7 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
295
297
|
|
|
296
298
|
#### 6. VStack
|
|
297
299
|
|
|
298
|
-
|
|
300
|
+
Arranges child elements **vertically**.
|
|
299
301
|
|
|
300
302
|
```typescript
|
|
301
303
|
{
|
|
@@ -305,7 +307,7 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
305
307
|
justifyContent: "start" | "center" | "end" | "spaceBetween";
|
|
306
308
|
gap?: number;
|
|
307
309
|
|
|
308
|
-
//
|
|
310
|
+
// Common properties
|
|
309
311
|
w?: number | "max" | `${number}%`;
|
|
310
312
|
h?: number | "max" | `${number}%`;
|
|
311
313
|
...
|
|
@@ -314,7 +316,7 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
314
316
|
|
|
315
317
|
#### 7. HStack
|
|
316
318
|
|
|
317
|
-
|
|
319
|
+
Arranges child elements **horizontally**.
|
|
318
320
|
|
|
319
321
|
```typescript
|
|
320
322
|
{
|
|
@@ -324,7 +326,7 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
324
326
|
justifyContent: "start" | "center" | "end" | "spaceBetween";
|
|
325
327
|
gap?: number;
|
|
326
328
|
|
|
327
|
-
//
|
|
329
|
+
// Common properties
|
|
328
330
|
w?: number | "max" | `${number}%`;
|
|
329
331
|
h?: number | "max" | `${number}%`;
|
|
330
332
|
...
|
|
@@ -333,33 +335,34 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
333
335
|
|
|
334
336
|
#### 8. Chart
|
|
335
337
|
|
|
336
|
-
|
|
338
|
+
A node for drawing charts. Supports bar charts, line charts, pie charts, area charts, doughnut charts, and radar charts.
|
|
337
339
|
|
|
338
340
|
```typescript
|
|
339
341
|
{
|
|
340
342
|
type: "chart";
|
|
341
|
-
chartType: "bar" | "line" | "pie";
|
|
343
|
+
chartType: "bar" | "line" | "pie" | "area" | "doughnut" | "radar";
|
|
342
344
|
data: {
|
|
343
|
-
name?: string; //
|
|
344
|
-
labels: string[]; //
|
|
345
|
-
values: number[]; //
|
|
345
|
+
name?: string; // Series name
|
|
346
|
+
labels: string[]; // Category labels
|
|
347
|
+
values: number[]; // Values
|
|
346
348
|
}[];
|
|
347
|
-
showLegend?: boolean; //
|
|
348
|
-
showTitle?: boolean; //
|
|
349
|
-
title?: string; //
|
|
350
|
-
chartColors?: string[]; //
|
|
349
|
+
showLegend?: boolean; // Show legend (default: false)
|
|
350
|
+
showTitle?: boolean; // Show title (default: false)
|
|
351
|
+
title?: string; // Title string
|
|
352
|
+
chartColors?: string[]; // Data color array (hex color codes)
|
|
353
|
+
radarStyle?: "standard" | "marker" | "filled"; // Radar-only: chart style
|
|
351
354
|
|
|
352
|
-
//
|
|
355
|
+
// Common properties
|
|
353
356
|
w?: number | "max" | `${number}%`;
|
|
354
357
|
h?: number | "max" | `${number}%`;
|
|
355
358
|
...
|
|
356
359
|
}
|
|
357
360
|
```
|
|
358
361
|
|
|
359
|
-
|
|
362
|
+
**Usage Examples:**
|
|
360
363
|
|
|
361
364
|
```typescript
|
|
362
|
-
//
|
|
365
|
+
// Bar chart
|
|
363
366
|
{
|
|
364
367
|
type: "chart",
|
|
365
368
|
chartType: "bar",
|
|
@@ -367,23 +370,23 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
367
370
|
h: 400,
|
|
368
371
|
data: [
|
|
369
372
|
{
|
|
370
|
-
name: "
|
|
371
|
-
labels: ["
|
|
373
|
+
name: "Sales",
|
|
374
|
+
labels: ["Jan", "Feb", "Mar", "Apr"],
|
|
372
375
|
values: [100, 200, 150, 300],
|
|
373
376
|
},
|
|
374
377
|
{
|
|
375
|
-
name: "
|
|
376
|
-
labels: ["
|
|
378
|
+
name: "Profit",
|
|
379
|
+
labels: ["Jan", "Feb", "Mar", "Apr"],
|
|
377
380
|
values: [30, 60, 45, 90],
|
|
378
381
|
},
|
|
379
382
|
],
|
|
380
383
|
showLegend: true,
|
|
381
384
|
showTitle: true,
|
|
382
|
-
title: "
|
|
385
|
+
title: "Monthly Sales & Profit",
|
|
383
386
|
chartColors: ["0088CC", "00AA00"],
|
|
384
387
|
}
|
|
385
388
|
|
|
386
|
-
//
|
|
389
|
+
// Pie chart
|
|
387
390
|
{
|
|
388
391
|
type: "chart",
|
|
389
392
|
chartType: "pie",
|
|
@@ -391,21 +394,39 @@ await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
|
391
394
|
h: 300,
|
|
392
395
|
data: [
|
|
393
396
|
{
|
|
394
|
-
name: "
|
|
395
|
-
labels: ["
|
|
397
|
+
name: "Market Share",
|
|
398
|
+
labels: ["Product A", "Product B", "Product C", "Others"],
|
|
396
399
|
values: [40, 30, 20, 10],
|
|
397
400
|
},
|
|
398
401
|
],
|
|
399
402
|
showLegend: true,
|
|
400
403
|
chartColors: ["0088CC", "00AA00", "FF6600", "888888"],
|
|
401
404
|
}
|
|
405
|
+
|
|
406
|
+
// Radar chart
|
|
407
|
+
{
|
|
408
|
+
type: "chart",
|
|
409
|
+
chartType: "radar",
|
|
410
|
+
w: 400,
|
|
411
|
+
h: 300,
|
|
412
|
+
data: [
|
|
413
|
+
{
|
|
414
|
+
name: "Skill Assessment",
|
|
415
|
+
labels: ["Technical", "Design", "PM", "Sales", "Support"],
|
|
416
|
+
values: [80, 60, 70, 50, 90],
|
|
417
|
+
},
|
|
418
|
+
],
|
|
419
|
+
showLegend: true,
|
|
420
|
+
radarStyle: "filled",
|
|
421
|
+
chartColors: ["0088CC"],
|
|
422
|
+
}
|
|
402
423
|
```
|
|
403
424
|
|
|
404
|
-
##
|
|
425
|
+
## Master Slide
|
|
405
426
|
|
|
406
|
-
|
|
427
|
+
You can automatically insert common headers, footers, and page numbers across all pages.
|
|
407
428
|
|
|
408
|
-
###
|
|
429
|
+
### Basic Usage
|
|
409
430
|
|
|
410
431
|
```typescript
|
|
411
432
|
import { buildPptx } from "@hirokisakabe/pom";
|
|
@@ -425,7 +446,7 @@ const pptx = await buildPptx(
|
|
|
425
446
|
children: [
|
|
426
447
|
{
|
|
427
448
|
type: "text",
|
|
428
|
-
text: "
|
|
449
|
+
text: "Company Name",
|
|
429
450
|
fontPx: 14,
|
|
430
451
|
color: "FFFFFF",
|
|
431
452
|
},
|
|
@@ -460,50 +481,50 @@ const pptx = await buildPptx(
|
|
|
460
481
|
],
|
|
461
482
|
},
|
|
462
483
|
date: {
|
|
463
|
-
format: "YYYY/MM/DD", //
|
|
484
|
+
format: "YYYY/MM/DD", // or "locale"
|
|
464
485
|
},
|
|
465
486
|
},
|
|
466
487
|
},
|
|
467
488
|
);
|
|
468
489
|
```
|
|
469
490
|
|
|
470
|
-
###
|
|
491
|
+
### Master Slide Options
|
|
471
492
|
|
|
472
493
|
```typescript
|
|
473
494
|
type MasterSlideOptions = {
|
|
474
|
-
header?: POMNode; //
|
|
475
|
-
footer?: POMNode; //
|
|
495
|
+
header?: POMNode; // Header (any POMNode can be specified)
|
|
496
|
+
footer?: POMNode; // Footer (any POMNode can be specified)
|
|
476
497
|
pageNumber?: {
|
|
477
|
-
position: "left" | "center" | "right"; //
|
|
498
|
+
position: "left" | "center" | "right"; // Page number position
|
|
478
499
|
};
|
|
479
500
|
date?: {
|
|
480
|
-
format: "YYYY/MM/DD" | "locale"; //
|
|
501
|
+
format: "YYYY/MM/DD" | "locale"; // Date format
|
|
481
502
|
};
|
|
482
503
|
};
|
|
483
504
|
```
|
|
484
505
|
|
|
485
|
-
###
|
|
506
|
+
### Placeholders
|
|
486
507
|
|
|
487
|
-
|
|
508
|
+
The following placeholders can be used in text within headers and footers:
|
|
488
509
|
|
|
489
|
-
- `{{page}}`:
|
|
490
|
-
- `{{totalPages}}`:
|
|
491
|
-
- `{{date}}`:
|
|
510
|
+
- `{{page}}`: Current page number
|
|
511
|
+
- `{{totalPages}}`: Total number of pages
|
|
512
|
+
- `{{date}}`: Date (in the format specified by `date.format`)
|
|
492
513
|
|
|
493
|
-
###
|
|
514
|
+
### Features
|
|
494
515
|
|
|
495
|
-
-
|
|
496
|
-
-
|
|
497
|
-
-
|
|
498
|
-
-
|
|
516
|
+
- **Flexibility**: Headers and footers can use any POMNode (VStack, HStack, Box, etc.)
|
|
517
|
+
- **Automatic Composition**: Headers and footers are automatically added to each page's content
|
|
518
|
+
- **Dynamic Replacement**: Placeholders are automatically replaced per page
|
|
519
|
+
- **Backward Compatibility**: The master option is optional and has no impact on existing code
|
|
499
520
|
|
|
500
|
-
##
|
|
521
|
+
## Serverless Environments
|
|
501
522
|
|
|
502
|
-
pom
|
|
523
|
+
pom uses the `canvas` package by default to measure text width and determine line break positions. However, in serverless environments like Vercel or AWS Lambda, Japanese fonts (such as Noto Sans JP) are not installed, which may cause text line breaks to be misaligned.
|
|
503
524
|
|
|
504
|
-
|
|
525
|
+
To address this issue, you can specify the text measurement method using the `textMeasurement` option.
|
|
505
526
|
|
|
506
|
-
### textMeasurement
|
|
527
|
+
### textMeasurement Option
|
|
507
528
|
|
|
508
529
|
```typescript
|
|
509
530
|
const pptx = await buildPptx(
|
|
@@ -515,48 +536,48 @@ const pptx = await buildPptx(
|
|
|
515
536
|
);
|
|
516
537
|
```
|
|
517
538
|
|
|
518
|
-
|
|
|
519
|
-
| ------------ |
|
|
520
|
-
| `"canvas"` |
|
|
521
|
-
| `"fallback"` |
|
|
522
|
-
| `"auto"` |
|
|
539
|
+
| Value | Description |
|
|
540
|
+
| ------------ | -------------------------------------------------------------------------------------- |
|
|
541
|
+
| `"canvas"` | Always use canvas for text width measurement (for environments with fonts installed) |
|
|
542
|
+
| `"fallback"` | Always use fallback calculation (CJK characters = 1em, alphanumeric = 0.5em estimated) |
|
|
543
|
+
| `"auto"` | Auto-detect font availability and fall back if unavailable (default) |
|
|
523
544
|
|
|
524
|
-
###
|
|
545
|
+
### Recommended Settings
|
|
525
546
|
|
|
526
|
-
-
|
|
527
|
-
-
|
|
528
|
-
-
|
|
547
|
+
- **Local development / Docker**: Default (`"auto"`) works fine
|
|
548
|
+
- **Serverless environments**: Default `"auto"` will automatically fall back
|
|
549
|
+
- **Environments with fonts installed**: Explicitly specifying `"canvas"` enables more accurate measurement
|
|
529
550
|
|
|
530
|
-
## LLM
|
|
551
|
+
## LLM Integration
|
|
531
552
|
|
|
532
|
-
pom
|
|
553
|
+
pom supports use cases where slides are created from JSON generated by LLMs (GPT-4o, Claude, etc.).
|
|
533
554
|
|
|
534
|
-
### LLM
|
|
555
|
+
### LLM Specification Guide
|
|
535
556
|
|
|
536
|
-
[`llm-guide.md`](./llm-guide.md)
|
|
557
|
+
[`llm-guide.md`](./llm-guide.md) is a compact specification document for having LLMs generate JSON in pom format. Include it in your system prompt.
|
|
537
558
|
|
|
538
|
-
|
|
559
|
+
**Contents:**
|
|
539
560
|
|
|
540
|
-
-
|
|
541
|
-
-
|
|
542
|
-
-
|
|
543
|
-
-
|
|
561
|
+
- Node list and main properties
|
|
562
|
+
- Standard settings (slide size, padding, gap, font size guidelines)
|
|
563
|
+
- Pattern examples (basic structure, 2-column, table, shapes, charts, etc.)
|
|
564
|
+
- Common mistakes and correct usage
|
|
544
565
|
|
|
545
|
-
###
|
|
566
|
+
### Input Schema
|
|
546
567
|
|
|
547
|
-
`inputPomNodeSchema`
|
|
568
|
+
Use `inputPomNodeSchema` to validate JSON generated by LLMs.
|
|
548
569
|
|
|
549
570
|
```typescript
|
|
550
571
|
import { inputPomNodeSchema, buildPptx, InputPOMNode } from "@hirokisakabe/pom";
|
|
551
572
|
|
|
552
|
-
// LLM
|
|
573
|
+
// Validate JSON output from LLM
|
|
553
574
|
const jsonFromLLM = `{
|
|
554
575
|
"type": "vstack",
|
|
555
576
|
"padding": 48,
|
|
556
577
|
"gap": 24,
|
|
557
578
|
"children": [
|
|
558
|
-
{ "type": "text", "text": "
|
|
559
|
-
{ "type": "text", "text": "
|
|
579
|
+
{ "type": "text", "text": "Title", "fontPx": 32, "bold": true },
|
|
580
|
+
{ "type": "text", "text": "Body text", "fontPx": 16 }
|
|
560
581
|
]
|
|
561
582
|
}`;
|
|
562
583
|
|
|
@@ -564,61 +585,61 @@ const parsed = JSON.parse(jsonFromLLM);
|
|
|
564
585
|
const result = inputPomNodeSchema.safeParse(parsed);
|
|
565
586
|
|
|
566
587
|
if (result.success) {
|
|
567
|
-
//
|
|
588
|
+
// Validation successful - generate PPTX
|
|
568
589
|
const pptx = await buildPptx([result.data], { w: 1280, h: 720 });
|
|
569
590
|
await pptx.writeFile({ fileName: "output.pptx" });
|
|
570
591
|
} else {
|
|
571
|
-
//
|
|
592
|
+
// Validation failed - check error details
|
|
572
593
|
console.error("Validation failed:", result.error.format());
|
|
573
594
|
}
|
|
574
595
|
```
|
|
575
596
|
|
|
576
|
-
###
|
|
597
|
+
### Available Input Schemas
|
|
577
598
|
|
|
578
|
-
|
|
|
579
|
-
| ------------------------------- |
|
|
580
|
-
| `inputPomNodeSchema` |
|
|
581
|
-
| `inputTextNodeSchema` |
|
|
582
|
-
| `inputImageNodeSchema` |
|
|
583
|
-
| `inputTableNodeSchema` |
|
|
584
|
-
| `inputShapeNodeSchema` |
|
|
585
|
-
| `inputChartNodeSchema` |
|
|
586
|
-
| `inputBoxNodeSchema` | Box
|
|
587
|
-
| `inputVStackNodeSchema` | VStack
|
|
588
|
-
| `inputHStackNodeSchema` | HStack
|
|
589
|
-
| `inputMasterSlideOptionsSchema` |
|
|
599
|
+
| Schema | Description |
|
|
600
|
+
| ------------------------------- | ------------------------------------------ |
|
|
601
|
+
| `inputPomNodeSchema` | Main node schema (includes all node types) |
|
|
602
|
+
| `inputTextNodeSchema` | For text nodes |
|
|
603
|
+
| `inputImageNodeSchema` | For image nodes |
|
|
604
|
+
| `inputTableNodeSchema` | For table nodes |
|
|
605
|
+
| `inputShapeNodeSchema` | For shape nodes |
|
|
606
|
+
| `inputChartNodeSchema` | For chart nodes |
|
|
607
|
+
| `inputBoxNodeSchema` | For Box nodes |
|
|
608
|
+
| `inputVStackNodeSchema` | For VStack nodes |
|
|
609
|
+
| `inputHStackNodeSchema` | For HStack nodes |
|
|
610
|
+
| `inputMasterSlideOptionsSchema` | For master slide settings |
|
|
590
611
|
|
|
591
|
-
###
|
|
612
|
+
### Input Validation in Browser Environments
|
|
592
613
|
|
|
593
|
-
|
|
614
|
+
If you want to validate LLM output in browser environments (SPAs like React, Vue, Svelte), you can import schemas from `@hirokisakabe/pom/schema`. This subpath exports only schemas without Node.js dependencies, so it works in browsers.
|
|
594
615
|
|
|
595
616
|
```typescript
|
|
596
|
-
//
|
|
617
|
+
// Available in browser environments
|
|
597
618
|
import { inputPomNodeSchema } from "@hirokisakabe/pom/schema";
|
|
598
619
|
|
|
599
|
-
// LLM
|
|
620
|
+
// Validate response from LLM
|
|
600
621
|
const result = inputPomNodeSchema.safeParse(llmResponse);
|
|
601
622
|
|
|
602
623
|
if (result.success) {
|
|
603
|
-
//
|
|
624
|
+
// Validation successful - send to server for PPTX generation
|
|
604
625
|
await fetch("/api/generate-pptx", {
|
|
605
626
|
method: "POST",
|
|
606
627
|
headers: { "Content-Type": "application/json" },
|
|
607
628
|
body: JSON.stringify(result.data),
|
|
608
629
|
});
|
|
609
630
|
} else {
|
|
610
|
-
//
|
|
631
|
+
// Validation failed - show error to user
|
|
611
632
|
console.error("Validation failed:", result.error.format());
|
|
612
633
|
}
|
|
613
634
|
```
|
|
614
635
|
|
|
615
|
-
|
|
636
|
+
**Difference between `@hirokisakabe/pom` and `@hirokisakabe/pom/schema`:**
|
|
616
637
|
|
|
617
|
-
|
|
|
618
|
-
| -------------------------- |
|
|
619
|
-
| `@hirokisakabe/pom` | Node.js
|
|
620
|
-
| `@hirokisakabe/pom/schema` |
|
|
638
|
+
| Import Path | Environment | Included Features |
|
|
639
|
+
| -------------------------- | --------------- | -------------------------------------------- |
|
|
640
|
+
| `@hirokisakabe/pom` | Node.js | Everything (PPTX generation, schemas, types) |
|
|
641
|
+
| `@hirokisakabe/pom/schema` | Browser-capable | Schemas and types only (no PPTX generation) |
|
|
621
642
|
|
|
622
|
-
##
|
|
643
|
+
## License
|
|
623
644
|
|
|
624
645
|
MIT
|