slotdeck 0.1.0 → 0.1.1
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 +9 -0
- package/dist/deck/validate.js +5 -0
- package/dist/deck/validate.js.map +1 -1
- package/docs/README.md +76 -0
- package/docs/api-reference.md +668 -0
- package/docs/chat-tools.md +253 -0
- package/docs/concepts.md +126 -0
- package/docs/deck-format.md +225 -0
- package/docs/generating.md +218 -0
- package/docs/getting-started.md +139 -0
- package/docs/languages.md +83 -0
- package/docs/layout-freedom.md +113 -0
- package/docs/manifest-format.md +207 -0
- package/docs/providers.md +236 -0
- package/docs/rendering.md +172 -0
- package/docs/template-studio.md +369 -0
- package/docs/troubleshooting.md +166 -0
- package/package.json +3 -2
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
# Template studio
|
|
2
|
+
|
|
3
|
+
The studio functions cover everything needed to turn a new `.pptx` into a usable template: drafting its
|
|
4
|
+
manifest with a model, checking it, seeing whether its budgets hold, and changing it by hand or by instruction.
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import {
|
|
8
|
+
draftManifest, checkManifest, sampleDeck, changeManifest, editManifest,
|
|
9
|
+
studioView, describeManifest, describeSlot, inspectTemplate, ROLES, PptxPackage, loadTemplate, renderDeck,
|
|
10
|
+
} from 'slotdeck';
|
|
11
|
+
import type { ManifestChange, SlotPatch, ChangeResult, ManifestIssue, Role, StudioView } from 'slotdeck';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## The workflow
|
|
15
|
+
|
|
16
|
+
1. **Draft** with `draftManifest`. A model labels the shapes; the code measures everything.
|
|
17
|
+
2. **Check** with `checkManifest`. It should report nothing.
|
|
18
|
+
3. **Look** at a sample: `sampleDeck` then `renderDeck`, and open the file. Every slot is filled to its budget,
|
|
19
|
+
so text that overflows here will overflow in real decks, and shapes that should not be there are easy to see.
|
|
20
|
+
4. **Change** what is wrong: `changeManifest` with operations, or `editManifest` with an instruction.
|
|
21
|
+
5. Repeat 2 to 4 until the sample looks right. Store the manifest as JSON next to the pptx.
|
|
22
|
+
|
|
23
|
+
A draft is a starting point for review, not a finished manifest. What a draft does not contain, and a person
|
|
24
|
+
adds: budgets tuned by eye, derived patterns (a text-only variant, a native chart), wider rows, picture areas,
|
|
25
|
+
chart colours, and alignment choices for decks that read the other way.
|
|
26
|
+
|
|
27
|
+
## `draftManifest(pptx, options)`
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
const { manifest, skipped, issues } = await draftManifest(pptxBytes, {
|
|
31
|
+
llm, // required: an LlmProvider
|
|
32
|
+
name: 'marketing', // optional name for the manifest; default 'template'
|
|
33
|
+
slideImage: (slide) => thumbnails.get(slide), // optional: { mimeType, data } of a picture of slide N (1-based); may be async
|
|
34
|
+
slides: [1, 2, 5], // optional: only these slides; default all
|
|
35
|
+
concurrency: 4, // optional: slides sent to the model at once; default 4
|
|
36
|
+
onProgress: ({ done, total, slide }) => {}, // optional
|
|
37
|
+
signal, // optional
|
|
38
|
+
});
|
|
39
|
+
// manifest: TemplateManifest
|
|
40
|
+
// skipped: [{ slide, reason }] slides that did not become patterns, and why
|
|
41
|
+
// issues: ManifestIssue[] what checkManifest finds in the draft
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Model calls: one about the deck as a whole, then one per slide.
|
|
45
|
+
|
|
46
|
+
What the code works out without the model:
|
|
47
|
+
|
|
48
|
+
- Every shape's id, kind, position, size, font size and sample text.
|
|
49
|
+
- **Frame elements**: whatever sits in the same place on many slides (a logo, a rule), and page-number, date,
|
|
50
|
+
footer and header placeholders. They are left alone and not shown to the model. (Spotting what repeats needs
|
|
51
|
+
a template of at least six slides; with fewer, only the placeholders are treated as frame.)
|
|
52
|
+
- **Deck fields**: texts that appear on many slides become one value for the whole deck.
|
|
53
|
+
- The reading direction, from the letters of the sample text.
|
|
54
|
+
- A character budget for each text box, from its size and font size, and never less than its sample text.
|
|
55
|
+
- A table's columns and rows, and how many characters fit a cell before the table leaves the slide.
|
|
56
|
+
- Rows and grids of like items, from numbered slot names (`card1Heading`, `card2Heading`).
|
|
57
|
+
|
|
58
|
+
What the model decides, for each slide:
|
|
59
|
+
|
|
60
|
+
- Whether the slide is a reusable layout at all. A sheet of brand assets or a broken slide is skipped, with a
|
|
61
|
+
reason.
|
|
62
|
+
- An id and a description for the pattern, and whether it is built around numbers.
|
|
63
|
+
- A role, a name and "optional or not" for each shape.
|
|
64
|
+
|
|
65
|
+
A label for a shape that is not on the slide is discarded, so the model cannot make the manifest point at
|
|
66
|
+
something that does not exist.
|
|
67
|
+
|
|
68
|
+
`slideImage` is optional. With it, the model sees the slide; without it, it judges from the measurements alone.
|
|
69
|
+
Any PNG or JPEG of the slide works; 480 pixels wide is enough.
|
|
70
|
+
|
|
71
|
+
To redo one slide after changing the pptx, call `draftManifest` with `slides: [n]` and add the pattern it
|
|
72
|
+
returns to your manifest.
|
|
73
|
+
|
|
74
|
+
### Roles
|
|
75
|
+
|
|
76
|
+
`ROLES` lists them. A role says what a shape is for and decides the kind of slot it becomes.
|
|
77
|
+
|
|
78
|
+
| Role | For | Becomes |
|
|
79
|
+
| --- | --- | --- |
|
|
80
|
+
| `title`, `subtitle` | The headings of the slide | Text slot |
|
|
81
|
+
| `text` | A paragraph, or a short label | Text slot |
|
|
82
|
+
| `list` | A bulleted or multi-line list, one paragraph per item | Text slot with `maxParagraphs` |
|
|
83
|
+
| `number` | A large figure | Text slot whose budget is its sample's length |
|
|
84
|
+
| `caption` | A few words under a figure, icon or picture | Text slot |
|
|
85
|
+
| `photo` | A photograph to replace | Image slot, `imageKind: "photo"` |
|
|
86
|
+
| `icon` | A small pictogram to replace | Image slot, `imageKind: "icon"` |
|
|
87
|
+
| `graphic` | A chart, diagram or screenshot picture to replace | Image slot, `imageKind: "graphic"` |
|
|
88
|
+
| `chart` | A native chart in place of a picture (not offered by the drafter; set it yourself) | Chart slot |
|
|
89
|
+
| `table` | A table | Table slot |
|
|
90
|
+
| `decoration` | Something drawn for the sample content, to remove from every slide made with the pattern | Slot with `empty: "drop"` |
|
|
91
|
+
| `fixed` | Part of the design that stays exactly as it is | No slot |
|
|
92
|
+
|
|
93
|
+
Which roles a shape can take depends on what it is: a text box can be any text role or a decoration; a picture
|
|
94
|
+
can be `photo`, `icon`, `graphic`, `chart` or `decoration`; a table only `table`; a line, a group or a drawn shape
|
|
95
|
+
without text only `decoration`.
|
|
96
|
+
|
|
97
|
+
## `checkManifest(template)`
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const issues = checkManifest(loadTemplate(pptxBytes, manifest));
|
|
101
|
+
// [{ severity: 'error' | 'warning', pattern?: string, slot?: string, message: string }]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
No model. It verifies that the manifest matches the pptx: slides and shapes exist, slots point at the right
|
|
105
|
+
kind of shape, names are unique, rows are consistent. The rules are listed in
|
|
106
|
+
[manifest-format.md](manifest-format.md). Run it when a template is loaded, so a template that someone changed
|
|
107
|
+
shows up there and not in the middle of a render.
|
|
108
|
+
|
|
109
|
+
## `sampleDeck(template, options?)`
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const { deck, assets } = sampleDeck(template, { fill: 0.95, items: 'max' });
|
|
113
|
+
const { pptx } = renderDeck(template, deck, { assets, layout: 'adaptive' });
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Builds a deck that uses every pattern once and fills every slot close to its limit, with the template's own
|
|
117
|
+
filler words and plain coloured rectangles for pictures.
|
|
118
|
+
|
|
119
|
+
| Option | Default | Meaning |
|
|
120
|
+
| --- | --- | --- |
|
|
121
|
+
| `fill` | `0.95` | How full to make each text slot, as a share of its budget. |
|
|
122
|
+
| `items` | `'drawn'` | For patterns with a row or grid: `'drawn'` uses the template's number, `'max'` the most allowed, `'min'` the fewest. |
|
|
123
|
+
|
|
124
|
+
## `changeManifest(template, changes)`
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
const result = changeManifest(template, [
|
|
128
|
+
{ op: 'setSlot', pattern: 'cover', slot: 'title', maxChars: 40 },
|
|
129
|
+
{ op: 'setRepeat', pattern: 'icon-cards', max: 5 },
|
|
130
|
+
]);
|
|
131
|
+
// result.manifest the new manifest; the template that was passed in is not touched
|
|
132
|
+
// result.applied [{ index, change, message }] what was done, each with a sentence saying what is now true
|
|
133
|
+
// result.rejected [{ index, change, reason }] what was refused, and why
|
|
134
|
+
// result.issues checkManifest on the result
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
No model. Changes are applied in order. One that cannot be made, or that would leave the manifest pointing at
|
|
138
|
+
something the pptx does not have, is refused with a reason and skipped; the rest are still applied. To continue
|
|
139
|
+
from the result, load it: `loadTemplate(pptxBytes, result.manifest)` or `{ pkg: template.pkg, manifest: result.manifest }`.
|
|
140
|
+
|
|
141
|
+
### Operations
|
|
142
|
+
|
|
143
|
+
Every change is an object with `op`. `pattern` is a pattern id, `slot` a slot name, `shape` a shape id (string).
|
|
144
|
+
|
|
145
|
+
#### `setManifest`
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
{ op: 'setManifest', name?: string, language?: string, direction?: 'ltr' | 'rtl', alignOnDirectionChange?: 'flip' | 'keep' }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### `addPattern`
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
{ op: 'addPattern', slide: number, id: string, description?: string }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Makes a slide a pattern with no content slots yet. Texts that other patterns already treat as deck fields are
|
|
158
|
+
filled in as deck-field slots. Follow it with `addSlot` operations, or use `draftManifest` with `slides: [n]`
|
|
159
|
+
instead to get a complete pattern.
|
|
160
|
+
|
|
161
|
+
#### `copyPattern`
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
{ op: 'copyPattern', pattern: string, id: string, description?: string }
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
A second pattern from the same slide, to turn into a variant with further operations.
|
|
168
|
+
|
|
169
|
+
#### `removePattern`
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
{ op: 'removePattern', pattern: string }
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The last pattern cannot be removed.
|
|
176
|
+
|
|
177
|
+
#### `setPattern`
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
{ op: 'setPattern', pattern: string, id?: string, description?: string, figures?: boolean }
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`id` renames the pattern. `figures: true` offers it only for briefs that contain numbers.
|
|
184
|
+
|
|
185
|
+
#### `addSlot`
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
{ op: 'addSlot', pattern: string, shape: string, role: Role, name?: string, optional?: boolean }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Makes a shape a slot in a role, with limits measured from the shape (budget from the box and font, table limits
|
|
192
|
+
from the table). On a shape that already is a slot, it replaces that slot, keeping its name unless `name` is
|
|
193
|
+
given: this is how a role is changed. Role `fixed` removes the slot. `name` defaults to the role.
|
|
194
|
+
|
|
195
|
+
#### `removeSlot`
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
{ op: 'removeSlot', pattern: string, slot: string }
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The shape goes back to being part of the design.
|
|
202
|
+
|
|
203
|
+
#### `setSlot`
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
{ op: 'setSlot', pattern: string, slot: string, ...SlotPatch }
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
`SlotPatch` properties (all optional; `null` clears an optional setting):
|
|
210
|
+
|
|
211
|
+
| Property | Applies to | Meaning |
|
|
212
|
+
| --- | --- | --- |
|
|
213
|
+
| `name` | any | Renames the slot. |
|
|
214
|
+
| `description` | any | Guidance for the planning model. |
|
|
215
|
+
| `empty` | any | `error` (required), `remove` (optional), `keep`, `drop`. |
|
|
216
|
+
| `maxChars`, `maxParagraphs` | text | Budgets. |
|
|
217
|
+
| `deckField` | text | Ties the text to a deck-level field. |
|
|
218
|
+
| `alignOnDirectionChange` | text | `flip` or `keep` for this slot. |
|
|
219
|
+
| `styleRun` | text | `first` or `last`. |
|
|
220
|
+
| `fontSize` | text | A font size in points other than the template's. |
|
|
221
|
+
| `paragraphGap` | text | Space after each paragraph, in points. |
|
|
222
|
+
| `scales` | text | Whether a deck's text size applies. |
|
|
223
|
+
| `box` | text, image, chart | Another area for the shape: `{ x, y, w, h }` as fractions of the slide. |
|
|
224
|
+
| `imageKind`, `fit` | image | `photo`, `icon` or `graphic`; `cover` or `contain`. |
|
|
225
|
+
| `maxColumns`, `maxRows`, `maxCellChars` | table | Limits. |
|
|
226
|
+
| `headerText`, `bodyText` | table | `{ size?, bold?, color?, font? }`, merged into what is already set. |
|
|
227
|
+
| `maxCategories`, `maxSeries`, `colors`, `text`, `lineColor` | chart | Limits and styling. |
|
|
228
|
+
|
|
229
|
+
A property that does not apply to the slot's kind is refused (`"title" is a text slot; maxColumns does not apply to it`).
|
|
230
|
+
|
|
231
|
+
#### `setRepeat`
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
{ op: 'setRepeat', pattern: string, min?: number, max?: number, item?: string, span?: { left: number, right: number } | null }
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Sets how many items a row or grid takes. When the pattern has no row yet, it is found from numbered slot names:
|
|
238
|
+
name the slots of each item alike with a number (`card1Heading`, `card1Text`, `card2Heading`, `card2Text`) and
|
|
239
|
+
they become a row.
|
|
240
|
+
|
|
241
|
+
#### `removeRepeat`
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
{ op: 'removeRepeat', pattern: string }
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
The items stop being a row whose number can change.
|
|
248
|
+
|
|
249
|
+
### What the code adds to each change
|
|
250
|
+
|
|
251
|
+
- **Budgets follow.** After a new `fontSize` or `box` on a text slot, or a new text size, column count or row
|
|
252
|
+
count on a table, the character budget is worked out again, unless the same change states one. The message
|
|
253
|
+
says so: `maxChars follows at 324`.
|
|
254
|
+
- **Rows are checked for room.** Asking for more items than the row draws widens the row as far as the slide
|
|
255
|
+
allows: out to the slide's margin, or to the next shape beside the row. Asking for more than fit is refused
|
|
256
|
+
with the most that do: `5 cards do not fit side by side: each is 21% of the slide wide and the row has 93%. The most is 4`.
|
|
257
|
+
- **Row items stay alike.** A `setSlot` on one item's slot (`card1Icon`) is made to that slot of every item.
|
|
258
|
+
Slots of a row cannot be renamed, moved or removed one by one; remove the row first.
|
|
259
|
+
- **Nothing is left broken.** After each change the manifest is checked against the pptx. A change that
|
|
260
|
+
introduces a new error is refused.
|
|
261
|
+
|
|
262
|
+
### Recipes
|
|
263
|
+
|
|
264
|
+
The pattern ids, slot names and shape ids below are those of the demo template in the package's repository;
|
|
265
|
+
with your template, use your own.
|
|
266
|
+
|
|
267
|
+
Remove a shape from every slide made with a pattern (a sticker, a stray page number, an ornament):
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
{ op: 'addSlot', pattern: 'quote', shape: '5', role: 'decoration' }
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
A native chart in place of a sample chart picture, as a second pattern:
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
[
|
|
277
|
+
{ op: 'copyPattern', pattern: 'chart-with-takeaway', id: 'chart-native', description: 'A native, editable chart with a short explanation.' },
|
|
278
|
+
{ op: 'addSlot', pattern: 'chart-native', shape: '6', role: 'chart', name: 'chart' },
|
|
279
|
+
{ op: 'setSlot', pattern: 'chart-native', slot: 'chart', colors: ['0E7C7B', 'F4A259'], text: { size: 12, color: '5C6B73' } },
|
|
280
|
+
]
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
A text-only slide from a slide with a photo:
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
[
|
|
287
|
+
{ op: 'copyPattern', pattern: 'text-and-photo', id: 'text-only' },
|
|
288
|
+
{ op: 'addSlot', pattern: 'text-only', shape: '2', role: 'decoration' }, // the photo
|
|
289
|
+
{ op: 'setSlot', pattern: 'text-only', slot: 'body', box: { x: 0.04, y: 0.49, w: 0.72, h: 0.39 }, fontSize: 20, maxParagraphs: 3 },
|
|
290
|
+
]
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Smaller table text and fewer columns (the cell budget is measured for you):
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
{ op: 'setSlot', pattern: 'table', slot: 'table', maxColumns: 5, bodyText: { size: 9 }, headerText: { size: 10, bold: true } }
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Mirror alignment for right-to-left decks, but keep the line beside the logo where it is:
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
[
|
|
303
|
+
{ op: 'setManifest', alignOnDirectionChange: 'flip' },
|
|
304
|
+
{ op: 'setSlot', pattern: 'cover', slot: 'organizationDepartment', alignOnDirectionChange: 'keep' },
|
|
305
|
+
]
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## `editManifest(template, instruction, options)`
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
const result = await editManifest(template, 'Let the cards take up to six and make the subtitle optional everywhere', { llm, signal });
|
|
312
|
+
// the same fields as changeManifest's result, plus:
|
|
313
|
+
// result.note what the model could not do or needs to know, in the person's language; often ''
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The model reads the manifest next to the measured shapes of each pattern's slide and answers with operations
|
|
317
|
+
for `changeManifest`. It writes no manifest itself, so its answer goes through the same checks as a change made
|
|
318
|
+
by hand. One model call, and a second when some operations were refused, so the model can correct them.
|
|
319
|
+
|
|
320
|
+
- Instructions can be in any language.
|
|
321
|
+
- A person may refer to a slide by number or to a pattern by id.
|
|
322
|
+
- The model cannot set positions: `box` and `span` exist only for changes made by hand.
|
|
323
|
+
- An operation the model got wrong shows up in `rejected` with the reason; nothing of it is applied.
|
|
324
|
+
|
|
325
|
+
`describeManifest(template)` returns the text the model reads: every pattern with its slots and limits, and the
|
|
326
|
+
shapes of its slide that are not slots. An app can show it to its own chat model, or print it for review.
|
|
327
|
+
|
|
328
|
+
## `studioView(template)`
|
|
329
|
+
|
|
330
|
+
For a screen that edits a manifest by hand.
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
const view = studioView(template);
|
|
334
|
+
// view.aspectRatio slide width divided by height
|
|
335
|
+
// view.slides[i].slide 1-based slide number
|
|
336
|
+
// view.slides[i].patterns ids of the patterns made from this slide ([] when unused)
|
|
337
|
+
// view.slides[i].shapes[j]:
|
|
338
|
+
// id the id a change names the shape by
|
|
339
|
+
// kind 'text' | 'picture' | 'shape' | 'line' | 'group' | 'table' | 'other'
|
|
340
|
+
// box { x, y, w, h } as fractions of the slide: lay it over a picture of the slide
|
|
341
|
+
// groupId the group the shape sits in, when it does
|
|
342
|
+
// text sample text, when it has some
|
|
343
|
+
// fontSize largest font size of the sample text, in points
|
|
344
|
+
// frame true when the shape repeats across slides (logo, page number): rarely content
|
|
345
|
+
// roles the roles addSlot accepts for this shape
|
|
346
|
+
// slots [{ pattern, name, kind, empty, summary }] slots that point at the shape
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
A typical screen draws a picture of the slide, lays a rectangle over each shape from `box`, colours the ones
|
|
350
|
+
that are slots, and on a click offers the shape's `roles` (sending `addSlot`) or the slot's settings (sending
|
|
351
|
+
`setSlot`). Nothing is stored in the view: call it again after every change.
|
|
352
|
+
|
|
353
|
+
`describeSlot(slot)` gives a slot in a few words, such as `text, up to 40 characters, required`.
|
|
354
|
+
|
|
355
|
+
## `inspectTemplate(pkg)`
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
const info = inspectTemplate(PptxPackage.load(pptxBytes));
|
|
359
|
+
// info.slideWidth, info.slideHeight in EMU (914400 per inch)
|
|
360
|
+
// info.defaultFontSize points
|
|
361
|
+
// info.slides[i] = { number, part, layout, shapes: ShapeInfo[] }
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
The raw list of shapes, without a manifest. `studioView` is this joined with a manifest.
|
|
365
|
+
|
|
366
|
+
## Storing a manifest
|
|
367
|
+
|
|
368
|
+
A manifest is plain JSON. Keep it next to the pptx it describes, and keep the two in step: if the pptx is
|
|
369
|
+
edited in PowerPoint, shape ids can change, and `checkManifest` will say which slots no longer match.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Every message slotdeck produces, what it means, and what to do. Then the known limits.
|
|
4
|
+
|
|
5
|
+
## Setup problems
|
|
6
|
+
|
|
7
|
+
| Symptom | Cause | Fix |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| `ERR_REQUIRE_ESM`, or `require() of ES Module` | The package is ESM only. | Use `import`. Set `"type": "module"` in your `package.json`, or use `.mjs` files, or `await import('slotdeck')` from CommonJS. |
|
|
10
|
+
| `Cannot find module 'slotdeck/node'` in a bundler | `slotdeck/node` uses `node:fs` and is for Node only. | Import it only in server code. Everything else is in `slotdeck`. |
|
|
11
|
+
| `Not an Office Open XML package: [Content_Types].xml is missing` | The bytes passed to `loadTemplate` are not a `.pptx` (an old `.ppt`, a PDF, an HTML error page saved as a file). | Pass the bytes of a real `.pptx`. Save a `.ppt` as `.pptx` in PowerPoint first. |
|
|
12
|
+
| Types are not found | TypeScript module resolution is too old for package `exports`. | Use `"moduleResolution": "bundler"`, `"node16"` or `"nodenext"`. |
|
|
13
|
+
|
|
14
|
+
## Deck errors
|
|
15
|
+
|
|
16
|
+
These make `renderDeck` throw `DeckValidationError` and are returned by `validateDeck` with `severity: 'error'`.
|
|
17
|
+
Each has the slide number and usually the slot name.
|
|
18
|
+
|
|
19
|
+
| Message | Meaning | Fix |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| `the deck has no slides` | `slides` is missing or empty. | Give at least one slide. |
|
|
22
|
+
| `unknown pattern "x" (available: a, b, c)` | The slide names a pattern the manifest does not have. | Use one of the listed ids. |
|
|
23
|
+
| `pattern "x" takes 2 to 4 cards, not 5` | `items` is outside the pattern's range. | Use a count in the range, or raise `max` in the manifest if the template has room. |
|
|
24
|
+
| `this slot is required` | A required slot has no value (or an empty string), or a required deck field was not given. | Give the slot a value, or add the field to `deck.fields`. |
|
|
25
|
+
| `leaving this slot empty needs layout: 'adaptive'` | An optional slot was left out in `strict` layout. | Render with `layout: 'adaptive'`, or fill the slot. |
|
|
26
|
+
| `expected text` | A text slot got a picture, table or chart value. | Give a string or an array of strings. |
|
|
27
|
+
| `expected an image reference such as { "asset": "id" }` | An image slot got something else. | Give `{ "asset": "<id>" }`. |
|
|
28
|
+
| `expected a table such as { "header": [...], "rows": [[...]] }` | A table slot got something else. | Give a `header` array and a `rows` array of arrays. |
|
|
29
|
+
| `the table has no columns` | `header` is empty. | Give at least one column heading. |
|
|
30
|
+
| `row 2 has 3 cells; the table has 4 columns` | A row's length differs from the header's. | Give every row one cell per column. Use `""` for an empty cell. |
|
|
31
|
+
| `expected a chart such as { "type": "column", ... }` | A chart slot got something else. | Give `type`, `categories` and `series`. |
|
|
32
|
+
| `unknown chart type "x"` | `type` is not `column`, `bar`, `line` or `pie`. | Use one of the four. |
|
|
33
|
+
| `the chart has no categories` / `the chart has no series` | An empty array. | Give at least one of each. |
|
|
34
|
+
| `series "x" has 3 values; the chart has 4 categories` | A series' length differs from the categories'. | One value per category. |
|
|
35
|
+
| `series "x" has a value that is not a number` | A value is `null`, a string that is not a number, or missing. | Give numbers. |
|
|
36
|
+
| `a pie chart takes exactly one series` | A pie with several series. | Give one series, or use another type. |
|
|
37
|
+
| `asset "x" was not provided` | The deck refers to a picture whose bytes were not passed. | Add it to `options.assets` under that id. With the planner, pass the same `icons` and `assets` to rendering as to planning, or use `resolveAssets`. |
|
|
38
|
+
|
|
39
|
+
## Deck warnings
|
|
40
|
+
|
|
41
|
+
These do not stop rendering. `renderDeck` and the planner return them.
|
|
42
|
+
|
|
43
|
+
| Message | Meaning | What to do |
|
|
44
|
+
| --- | --- | --- |
|
|
45
|
+
| `text is 230 characters; the slot fits about 211` | Text over the slot's `maxChars`. It is rendered and may overflow its box. | Shorten the text, or raise the budget in the manifest if the sample deck shows room. |
|
|
46
|
+
| `text has 5 paragraphs; the slot fits 4` | Over `maxParagraphs`. | Fewer paragraphs. |
|
|
47
|
+
| `the table has 6 columns; the slot fits 5` (also rows) | Over the table's limits. The table may leave the slide. | A smaller table. |
|
|
48
|
+
| `a cell is 40 characters; cells fit about 22` | A long cell makes its row taller. | Shorter cells. |
|
|
49
|
+
| `the chart has 12 categories; the slot fits 8` (also series) | Over the chart's limits. Labels may crowd. | Fewer categories. |
|
|
50
|
+
| `pattern "x" has no such slot; ignored` | The slide gives a slot name the pattern does not have. | Check the name against the manifest. With `items`, slots of items beyond the count are reported this way. |
|
|
51
|
+
| `pattern "x" has a fixed number of items; "items" is ignored` | `items` on a pattern without a `repeat`. | Remove `items`. |
|
|
52
|
+
| `chart format "x" is not known and is ignored; use "number" or "percent"` | An unknown `format`. | Use one of the two, or leave it out. |
|
|
53
|
+
| `chart values not stated in the brief: 89` | (Planner only.) The model charted a number the brief does not contain. It may be invented, or worked out from the brief. | Check the number. Put the figures you want charted into the brief. |
|
|
54
|
+
|
|
55
|
+
## Planner errors (`PlanError`)
|
|
56
|
+
|
|
57
|
+
| Message | Meaning | Fix |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| `No pattern of template "x" can be used: ...` | Nothing in the manifest can be filled with what was supplied. The reasons follow. | See the reasons below. |
|
|
60
|
+
| `The model did not produce a usable outline: ...` | The model's answer did not have the expected shape. | Retry. If it repeats, check that your provider returns parsed JSON that follows the schema. |
|
|
61
|
+
| `The plan uses patterns that cannot be filled with what was supplied: a, b` | A plan was made with icons, assets or fields that are not passed now. | Pass the same `icons`, `assets`, `fields` and `layout` to every step. |
|
|
62
|
+
| `Slide 3: pattern "x" needs icons, and no icon set was supplied` | The same, for an edit. | As above. |
|
|
63
|
+
|
|
64
|
+
Reasons a pattern is not offered:
|
|
65
|
+
|
|
66
|
+
| Reason | Fix |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| `is built around numbers, and the brief gives none` | Put figures in the brief, or set `numberPatterns: 'always'`. |
|
|
69
|
+
| `needs a photo, and images are turned off` | Give an `ImageProvider` or photo assets, and an `imageDensity` other than `none`. |
|
|
70
|
+
| `needs icons, and no icon set was supplied` | Pass `icons`. |
|
|
71
|
+
| `needs a graphic asset, and none was supplied` | Pass an asset of kind `graphic`. |
|
|
72
|
+
| `needs the deck field "x"` | Add it to `brief.fields`. |
|
|
73
|
+
|
|
74
|
+
## Manifest problems (`checkManifest`)
|
|
75
|
+
|
|
76
|
+
| Message | Fix |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| `points at slide 9, but the template has 5 slides` | Correct `sourceSlide`, or the pptx lost slides. |
|
|
79
|
+
| `points at shape #99, which is not on slide 1` | The shape id is wrong, or the slide was edited. List ids with `inspectTemplate` or `studioView`. |
|
|
80
|
+
| `is an image slot, but shape #6 is a text box` (and similar) | The slot's kind does not match the shape. Change the kind or the shape id. |
|
|
81
|
+
| `another pattern has the same id` / `another slot of the pattern has the same name` | Rename one. |
|
|
82
|
+
| `has a box, but its shape is inside a group` | A `box` only works for a shape placed directly on the slide. Remove the `box`, or ungroup in the template. |
|
|
83
|
+
| `is a chart slot, but its shape is inside a group` | A native chart cannot replace a picture inside a group. Ungroup in the template. |
|
|
84
|
+
| `repeat expects a slot named "card1Text"` | A row's name template has no matching slot for one of the drawn items. Add the slot or correct the template name. |
|
|
85
|
+
| `repeat item 2 points at shape #77, which is not on slide 4` | Correct the shape ids in `repeat.shapes`. |
|
|
86
|
+
| `repeat items must all sit directly on the slide, or all in the same group` | Items in different groups cannot be laid out together. |
|
|
87
|
+
| `repeat range 3 to 2 is not valid` | `min` must be at least 1 and not more than `max`. |
|
|
88
|
+
| warning: `has no character budget, so nothing stops text that does not fit` | Add `maxChars`. |
|
|
89
|
+
| warning: `points at the same shape as "x"` | Two slots on one shape: usually a mistake. |
|
|
90
|
+
| warning: `a grid cannot hold more items than it draws` | Lower `max` to the number drawn. |
|
|
91
|
+
|
|
92
|
+
## Refusals from `changeManifest`
|
|
93
|
+
|
|
94
|
+
`rejected[i].reason` is one of the manifest messages above, or one of these:
|
|
95
|
+
|
|
96
|
+
| Reason | Meaning |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `there is no pattern "x"` / `"p" has no slot "x"` / `slide 4 has no shape #99` | The change names something that does not exist. |
|
|
99
|
+
| `5 cards do not fit side by side: each is 21% of the slide wide and the row has 93%. The most is 4` | The row cannot hold that many. Use the stated maximum. |
|
|
100
|
+
| `a grid holds at most the 6 cards it draws; 8 would need a new line of them` | A grid's `max` is the number drawn. |
|
|
101
|
+
| `"title" is a text slot; maxColumns does not apply to it` | A setting for another kind of slot. |
|
|
102
|
+
| `maxChars must be a whole number of 1 or more` | A budget of zero, a fraction or a negative number. |
|
|
103
|
+
| `"card1Text" is part of the row of cards, so it cannot be renamed, moved or tied to a deck field; remove the row first` | Row slots must stay alike. Use `removeRepeat` first if you really need to. |
|
|
104
|
+
| `shape #4 is a picture; it can be photo, icon, graphic, chart, decoration` | The role does not suit the shape. |
|
|
105
|
+
| `"x" has no row of like items. Name the slots of each item alike with a number ...` | `setRepeat` found no numbered slots to make a row from. |
|
|
106
|
+
| `another pattern is already called "x"` | Choose another id. |
|
|
107
|
+
| `a template needs at least one pattern` | The last pattern cannot be removed. |
|
|
108
|
+
|
|
109
|
+
## Rendering errors that are not about the deck
|
|
110
|
+
|
|
111
|
+
Plain `Error`s from `renderDeck`. They mean the manifest and the pptx disagree, or a picture is not usable.
|
|
112
|
+
`checkManifest` catches the first group ahead of time.
|
|
113
|
+
|
|
114
|
+
| Message | Fix |
|
|
115
|
+
| --- | --- |
|
|
116
|
+
| `Pattern "x": slot "y" points at shape #12, which is not on template slide 3` | Fix the manifest (see above). |
|
|
117
|
+
| `Pattern "x" points at slide 9, but the template has 5 slides` | Fix `sourceSlide`. |
|
|
118
|
+
| `Unsupported image format: expected PNG, JPEG or GIF` | Convert the picture (WebP, SVG, HEIC and others are not supported). |
|
|
119
|
+
| `sample tables with merged cells are not supported` | The template's sample table has merged cells. Unmerge them in the template. |
|
|
120
|
+
| `a chart slot must point at a shape that is not inside a group` | Ungroup the sample picture in the template. |
|
|
121
|
+
|
|
122
|
+
## Gemini adapter errors (`GeminiError`)
|
|
123
|
+
|
|
124
|
+
| Message | Meaning |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `Gemini request failed (401): ...` | The key or token is wrong or missing. `error.status` has the HTTP status. |
|
|
127
|
+
| `Gemini request failed (429): ...` | Rate limit or quota. Retry later. |
|
|
128
|
+
| `Gemini request failed (400): The specified schema produces a constraint that has too many states for serving` | The service rejected a schema as too complex. This was seen during development with length limits on nested arrays, which the shipped schemas do not use. If it appears with a long deck, asking for fewer slides may help. |
|
|
129
|
+
| `Gemini did not answer within 180 seconds` | The request hung. Retry, or raise `timeoutMs`. |
|
|
130
|
+
| `Gemini did not return valid JSON: ...` | The model's text was not JSON. Retry. |
|
|
131
|
+
| `Gemini interaction ended with status "..."` | The service did not complete the request; the reason follows when it gives one. |
|
|
132
|
+
| `Gemini returned no image` | The image model answered without a picture, often because the prompt was refused. |
|
|
133
|
+
|
|
134
|
+
## The result looks wrong
|
|
135
|
+
|
|
136
|
+
| Observation | Likely cause | Fix |
|
|
137
|
+
| --- | --- | --- |
|
|
138
|
+
| Text runs out of its box or over a neighbour | The slot's budget is too generous, or the deck ignored a budget warning. | Render `sampleDeck` to see every slot at its budget, then lower `maxChars` with `changeManifest`. |
|
|
139
|
+
| A leftover sample element appears (a sticker, a second page number, a sample caption) | The shape is not a slot, so it is copied as it is. | Mark it as a decoration: `{ op: 'addSlot', pattern, shape, role: 'decoration' }`. |
|
|
140
|
+
| A picture is cropped badly | `cover` crops to the frame. | Supply a picture closer to the frame's proportions, or set `fit: 'contain'` on the slot. |
|
|
141
|
+
| Cards are in reverse order in a right-to-left deck | The pattern's items are not declared as a row. | Add a `repeat` (`setRepeat`) or `sequences`. |
|
|
142
|
+
| Hebrew or Arabic text is left-aligned | The manifest keeps alignment. | Set `alignOnDirectionChange: 'flip'` on the manifest or the slot. |
|
|
143
|
+
| A font changes for another script | The template's font lacks that script. | Set a complex-script font in the template. |
|
|
144
|
+
| The planner never uses a pattern | It is not offered. | See "Reasons a pattern is not offered". Also check the pattern's `description`: the model chooses by it. |
|
|
145
|
+
| A slide states a number or contact detail that nobody gave | The model invented it. | Figures are guarded only for patterns marked `figures` and for charts. State details in the brief and review the deck. |
|
|
146
|
+
|
|
147
|
+
## Known limits
|
|
148
|
+
|
|
149
|
+
- **Shapes need their own position.** The engine measures the shapes on a slide. A shape that takes its position
|
|
150
|
+
and font size from a layout placeholder, without stating them on the slide, is filled correctly but measured
|
|
151
|
+
as empty: a drafted budget for it is only as long as its sample text, and `box` cannot be applied to it. Decks
|
|
152
|
+
exported from Google Slides and decks built from free-standing text boxes work as they are.
|
|
153
|
+
- **Budgets are estimates.** A character budget cannot see lines lost to wrapping. Leave room in budgets for
|
|
154
|
+
slots with several paragraphs.
|
|
155
|
+
- **Text boxes do not resize.** Text longer than its box overflows.
|
|
156
|
+
- **Charts:** `column`, `bar`, `line` and `pie` only. No stacked or combined charts.
|
|
157
|
+
- **Tables:** the sample table must not have merged cells.
|
|
158
|
+
- **Pictures:** PNG, JPEG and GIF only.
|
|
159
|
+
- **Not carried over from the template:** speaker notes, named sections and revision history.
|
|
160
|
+
- **Animations** on template slides were not tested. A slide whose animated shape is removed may make PowerPoint
|
|
161
|
+
offer to repair the file; use templates without animations, or keep animated shapes out of optional slots.
|
|
162
|
+
- **Not read back:** changes made to a rendered file in PowerPoint. The deck JSON is the source of truth.
|
|
163
|
+
- **Not possible:** swapping the side of a photo; positioning a shape from a deck.
|
|
164
|
+
- **What was tested.** Output was checked by rendering in PowerPoint on Windows. Other programs that open pptx
|
|
165
|
+
files were not tested. The Gemini adapters were run against the Gemini Developer API; the Vertex AI endpoint
|
|
166
|
+
is supported but was not run live.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slotdeck",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Turn a PowerPoint template into new decks: a model plans the slides, the code clones the template's own slides and fills them.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pptx",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
"files": [
|
|
46
|
-
"dist"
|
|
46
|
+
"dist",
|
|
47
|
+
"docs/*.md"
|
|
47
48
|
],
|
|
48
49
|
"scripts": {
|
|
49
50
|
"build": "tsc -p tsconfig.build.json",
|