slotdeck 0.1.0 → 0.1.2

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.
Files changed (51) hide show
  1. package/README.md +16 -1
  2. package/dist/deck/validate.js +12 -5
  3. package/dist/deck/validate.js.map +1 -1
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +1 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/llm/gemini.d.ts +4 -0
  8. package/dist/llm/gemini.js +43 -7
  9. package/dist/llm/gemini.js.map +1 -1
  10. package/dist/llm/provider.d.ts +12 -0
  11. package/dist/plan/catalog.d.ts +11 -1
  12. package/dist/plan/catalog.js +20 -7
  13. package/dist/plan/catalog.js.map +1 -1
  14. package/dist/plan/edit.js +9 -5
  15. package/dist/plan/edit.js.map +1 -1
  16. package/dist/plan/plan.d.ts +16 -2
  17. package/dist/plan/plan.js +50 -17
  18. package/dist/plan/plan.js.map +1 -1
  19. package/dist/plan/write.d.ts +8 -1
  20. package/dist/plan/write.js +29 -3
  21. package/dist/plan/write.js.map +1 -1
  22. package/dist/render/render.js +4 -4
  23. package/dist/render/render.js.map +1 -1
  24. package/dist/template/change.d.ts +1 -0
  25. package/dist/template/change.js +12 -0
  26. package/dist/template/change.js.map +1 -1
  27. package/dist/template/instruct.js +4 -2
  28. package/dist/template/instruct.js.map +1 -1
  29. package/dist/template/manifest.d.ts +16 -0
  30. package/dist/template/manifest.js +26 -0
  31. package/dist/template/manifest.js.map +1 -1
  32. package/dist/template/sample.js +4 -3
  33. package/dist/template/sample.js.map +1 -1
  34. package/dist/tools.js +6 -0
  35. package/dist/tools.js.map +1 -1
  36. package/docs/README.md +77 -0
  37. package/docs/api-reference.md +680 -0
  38. package/docs/changelog.md +107 -0
  39. package/docs/chat-tools.md +257 -0
  40. package/docs/concepts.md +126 -0
  41. package/docs/deck-format.md +225 -0
  42. package/docs/generating.md +254 -0
  43. package/docs/getting-started.md +139 -0
  44. package/docs/languages.md +83 -0
  45. package/docs/layout-freedom.md +136 -0
  46. package/docs/manifest-format.md +208 -0
  47. package/docs/providers.md +281 -0
  48. package/docs/rendering.md +172 -0
  49. package/docs/template-studio.md +379 -0
  50. package/docs/troubleshooting.md +174 -0
  51. package/package.json +3 -2
@@ -0,0 +1,680 @@
1
+ # API reference
2
+
3
+ Every export of the package, grouped by what it is for. Types are written as TypeScript. Everything is imported
4
+ from `slotdeck` unless noted.
5
+
6
+ ```ts
7
+ import { renderDeck /* ... */ } from 'slotdeck';
8
+ import { directoryStore } from 'slotdeck/node';
9
+ ```
10
+
11
+ The package ships its own type declarations (`dist/*.d.ts`), which carry the same information with comments on
12
+ every field.
13
+
14
+ ## Rendering
15
+
16
+ ### `loadTemplate`
17
+
18
+ ```ts
19
+ function loadTemplate(pptx: Uint8Array, manifest: TemplateManifest): Template;
20
+ ```
21
+
22
+ Unzips a template once. Reuse the result.
23
+
24
+ ### `renderDeck`
25
+
26
+ ```ts
27
+ function renderDeck(template: Template, deck: DeckSpec, options?: RenderOptions): RenderResult;
28
+ ```
29
+
30
+ Deck JSON to pptx bytes. Synchronous, no model. Throws `DeckValidationError` when the deck has errors.
31
+
32
+ ### `validateDeck`
33
+
34
+ ```ts
35
+ function validateDeck(manifest: TemplateManifest, deck: DeckSpec, options?: ValidateOptions): Issue[];
36
+ ```
37
+
38
+ Checks a deck against a manifest with the renderer's own rules.
39
+
40
+ ### `extractAssets`
41
+
42
+ ```ts
43
+ function extractAssets(template: Template, deck: DeckSpec, pptx: Uint8Array): Record<string, Uint8Array>;
44
+ ```
45
+
46
+ Reads a deck's pictures back from a pptx rendered from it, by asset id.
47
+
48
+ ### `DeckValidationError`
49
+
50
+ ```ts
51
+ class DeckValidationError extends Error {
52
+ readonly issues: Issue[];
53
+ }
54
+ ```
55
+
56
+ ### `isImageRef`, `isTableValue`, `isChartValue`
57
+
58
+ ```ts
59
+ function isImageRef(value: unknown): value is ImageRef;
60
+ function isTableValue(value: unknown): value is TableValue;
61
+ function isChartValue(value: unknown): value is ChartValue;
62
+ ```
63
+
64
+ Tell the kinds of slot value apart when walking a deck.
65
+
66
+ ### Types
67
+
68
+ ```ts
69
+ interface Template { pkg: PptxPackage; manifest: TemplateManifest }
70
+
71
+ interface RenderOptions { assets?: Record<string, Uint8Array>; layout?: LayoutMode }
72
+ interface RenderResult { pptx: Uint8Array; warnings: Issue[] }
73
+
74
+ type LayoutMode = 'strict' | 'adaptive';
75
+ interface ValidateOptions { layout?: LayoutMode; assets?: Iterable<string> }
76
+ interface Issue { severity: 'error' | 'warning'; slide?: number; slot?: string; message: string }
77
+
78
+ interface DeckSpec {
79
+ version: 1;
80
+ title?: string;
81
+ brief?: string;
82
+ language?: string;
83
+ direction?: Direction;
84
+ fields?: Record<string, string>;
85
+ textScale?: number;
86
+ slides: SlideSpec[];
87
+ }
88
+ interface SlideSpec { pattern: string; items?: number; slots: Record<string, SlotValue> }
89
+ type SlotValue = string | string[] | ImageRef | TableValue | ChartValue | null;
90
+ interface ImageRef { asset: string; alt?: string; prompt?: string }
91
+ interface TableValue { header: string[]; rows: string[][] }
92
+ type ChartType = 'column' | 'bar' | 'line' | 'pie';
93
+ interface ChartValue {
94
+ type: ChartType;
95
+ categories: string[];
96
+ series: Array<{ name: string; values: number[] }>;
97
+ format?: 'number' | 'percent';
98
+ }
99
+ ```
100
+
101
+ ## Generating and editing
102
+
103
+ ### `generateDeck`
104
+
105
+ ```ts
106
+ function generateDeck(template: Template, brief: Brief, options: GenerateOptions): Promise<GenerateResult>;
107
+ ```
108
+
109
+ Brief to pptx: plans, gathers pictures, renders.
110
+
111
+ ### `editDeck`
112
+
113
+ ```ts
114
+ function editDeck(template: Template, deck: DeckSpec, instruction: string, options: EditDeckOptions): Promise<EditDeckResult>;
115
+ ```
116
+
117
+ Applies an instruction to a deck, gathers pictures, renders.
118
+
119
+ ### `planDeck`
120
+
121
+ ```ts
122
+ function planDeck(template: Template, brief: Brief, options: PlanOptions): Promise<PlanResult>;
123
+ ```
124
+
125
+ Brief to deck JSON: `planOutline` then `writeDeck`.
126
+
127
+ ### `planOutline`
128
+
129
+ ```ts
130
+ function planOutline(template: Template, brief: Brief, options: PlanOptions): Promise<DeckPlan>;
131
+ ```
132
+
133
+ Decides which pattern each slide uses and the point it makes. One model call.
134
+
135
+ ### `editPlan`
136
+
137
+ ```ts
138
+ function editPlan(template: Template, plan: DeckPlan, instruction: string, options: PlanOptions): Promise<{ plan: DeckPlan; summary: string }>;
139
+ ```
140
+
141
+ Changes a plan by instruction. One model call.
142
+
143
+ ### `writeDeck`
144
+
145
+ ```ts
146
+ function writeDeck(template: Template, plan: DeckPlan, options: PlanOptions): Promise<PlanResult>;
147
+ ```
148
+
149
+ Writes the content of a plan's slides. One model call plus repairs.
150
+
151
+ ### `planEdit`
152
+
153
+ ```ts
154
+ function planEdit(template: Template, deck: DeckSpec, instruction: string, options: EditOptions): Promise<EditResult>;
155
+ ```
156
+
157
+ Applies an instruction to a deck and returns the new deck JSON, without pictures or rendering.
158
+
159
+ ### `resolveAssets`
160
+
161
+ ```ts
162
+ function resolveAssets(template: Template, deck: DeckSpec, options?: ResolveOptions): Promise<Record<string, Uint8Array>>;
163
+ ```
164
+
165
+ Collects the bytes of every picture a deck refers to.
166
+
167
+ ### `directionOf`
168
+
169
+ ```ts
170
+ function directionOf(language: string): Direction;
171
+ ```
172
+
173
+ The reading direction of a BCP 47 language tag.
174
+
175
+ ### `isPlainText`
176
+
177
+ ```ts
178
+ function isPlainText(pattern: PatternDef): boolean;
179
+ ```
180
+
181
+ Whether a slide made from the pattern is running text and nothing else: the patterns a text-only deck may use.
182
+
183
+ ### `PlanError`
184
+
185
+ ```ts
186
+ class PlanError extends Error {}
187
+ ```
188
+
189
+ Thrown when no usable plan can be made. The message says why.
190
+
191
+ ### `TEXT_SIZES`
192
+
193
+ ```ts
194
+ const TEXT_SIZES: { normal: 1; large: 1.25; 'x-large': 1.5 };
195
+ type TextSize = 'normal' | 'large' | 'x-large';
196
+ ```
197
+
198
+ ### Types
199
+
200
+ ```ts
201
+ interface Brief {
202
+ prompt: string;
203
+ slideCount?: number | { min: number; max: number };
204
+ language?: string;
205
+ direction?: Direction;
206
+ imageDensity?: ImageDensity;
207
+ instructions?: string;
208
+ fields?: Record<string, string>;
209
+ textSize?: TextSize;
210
+ textOnly?: boolean; // every slide plain text: only the template's plain text patterns are offered
211
+ }
212
+ type ImageDensity = 'none' | 'low' | 'medium' | 'high';
213
+
214
+ interface PlanOptions {
215
+ llm: LlmProvider;
216
+ layout?: LayoutMode;
217
+ icons?: IconDef[];
218
+ assets?: AssetDef[];
219
+ patterns?: string[];
220
+ numberPatterns?: 'from-brief' | 'always' | 'never';
221
+ maxRepairs?: number;
222
+ onProgress?: (event: PlanProgress) => void;
223
+ signal?: AbortSignal;
224
+ }
225
+ type PlanProgress = { stage: 'outline' } | { stage: 'write'; slides: number } | { stage: 'repair'; attempt: number; issues: number };
226
+
227
+ interface IconDef { id: string; description: string; data: Uint8Array }
228
+ interface AssetDef { id: string; kind: 'photo' | 'graphic'; description: string; data: Uint8Array }
229
+
230
+ interface OutlineEntry { pattern: string; purpose: string; items?: number }
231
+ interface DeckPlan { version: 1; title: string; brief: Brief; slides: OutlineEntry[] }
232
+ interface PlanResult { deck: DeckSpec; warnings: Issue[]; outline: OutlineEntry[] }
233
+
234
+ interface EditOptions extends PlanOptions {
235
+ fields?: Record<string, string>;
236
+ direction?: Direction;
237
+ imageDensity?: ImageDensity;
238
+ }
239
+ interface EditResult { deck: DeckSpec; summary: string; rewritten: number[]; warnings: Issue[] }
240
+
241
+ // generateDeck and editDeck add picture handling to the options above:
242
+ interface GenerateOptions extends Omit<PlanOptions, 'onProgress'> {
243
+ images?: ImageProvider;
244
+ cache?: Map<string, Uint8Array>;
245
+ imageConcurrency?: number;
246
+ onProgress?: (event: GenerateProgress) => void;
247
+ }
248
+ interface EditDeckOptions extends Omit<EditOptions, 'onProgress'> {
249
+ images?: ImageProvider;
250
+ cache?: Map<string, Uint8Array>;
251
+ imageConcurrency?: number;
252
+ onProgress?: (event: GenerateProgress) => void;
253
+ }
254
+ type GenerateProgress = PlanProgress | { stage: 'images'; done: number; total: number } | { stage: 'render' };
255
+
256
+ interface GenerateResult { pptx: Uint8Array; deck: DeckSpec; assets: Record<string, Uint8Array>; warnings: Issue[]; outline: OutlineEntry[] }
257
+ interface EditDeckResult { pptx: Uint8Array; deck: DeckSpec; assets: Record<string, Uint8Array>; warnings: Issue[]; summary: string; rewritten: number[] }
258
+
259
+ interface ResolveOptions {
260
+ images?: ImageProvider;
261
+ icons?: IconDef[];
262
+ assets?: AssetDef[];
263
+ cache?: Map<string, Uint8Array>;
264
+ concurrency?: number;
265
+ onProgress?: (event: { stage: 'images'; done: number; total: number }) => void;
266
+ signal?: AbortSignal;
267
+ }
268
+ ```
269
+
270
+ ## Chat tools and storage
271
+
272
+ ### `presentationTools`
273
+
274
+ ```ts
275
+ function presentationTools(options: PresentationToolsOptions): PresentationTools;
276
+ ```
277
+
278
+ Builds the four tools for a chat model.
279
+
280
+ ### `TOOL_NAMES`
281
+
282
+ ```ts
283
+ const TOOL_NAMES: {
284
+ plan: 'plan_presentation';
285
+ editPlan: 'edit_presentation_plan';
286
+ create: 'create_presentation';
287
+ edit: 'edit_presentation';
288
+ };
289
+ ```
290
+
291
+ ### `storeKeys`
292
+
293
+ ```ts
294
+ const storeKeys: {
295
+ plan(id: string): string; // 'plan/<id>.json'
296
+ deck(id: string): string; // 'deck/<id>.json'
297
+ pptx(id: string): string; // 'pptx/<id>.pptx'
298
+ asset(id: string): string; // 'asset/<id>'
299
+ };
300
+ ```
301
+
302
+ ### `memoryStore`
303
+
304
+ ```ts
305
+ function memoryStore(): BlobStore & { keys(): string[] };
306
+ ```
307
+
308
+ ### `directoryStore` (from `slotdeck/node`)
309
+
310
+ ```ts
311
+ function directoryStore(directory: string): BlobStore;
312
+ ```
313
+
314
+ A store backed by a folder. Keys become file paths under it.
315
+
316
+ ### Types
317
+
318
+ ```ts
319
+ interface BlobStore {
320
+ get(key: string): Promise<Uint8Array | undefined>;
321
+ set(key: string, data: Uint8Array): Promise<void>;
322
+ }
323
+
324
+ interface PresentationToolsOptions {
325
+ template: Template;
326
+ llm: LlmProvider;
327
+ store: BlobStore;
328
+ images?: ImageProvider;
329
+ icons?: IconDef[];
330
+ assets?: AssetDef[];
331
+ layout?: LayoutMode;
332
+ fields?: Record<string, string>;
333
+ numberPatterns?: 'from-brief' | 'always' | 'never';
334
+ thumbnail?: (patternId: string) => string | undefined;
335
+ newId?: (kind: 'plan' | 'deck') => string;
336
+ onProgress?: (event: GenerateProgress, tool: string) => void;
337
+ }
338
+ interface PresentationTools {
339
+ definitions: ToolDefinition[];
340
+ call(name: string, args: unknown, context?: { signal?: AbortSignal }): Promise<ToolResult>;
341
+ }
342
+ interface ToolDefinition { name: string; description: string; parameters: JsonSchema }
343
+ interface ToolResult { output: Record<string, unknown>; plan?: DeckPlan; deck?: DeckSpec; pptx?: Uint8Array }
344
+ ```
345
+
346
+ ## Providers
347
+
348
+ ### `gemini`, `geminiImages`
349
+
350
+ ```ts
351
+ function gemini(options: GeminiOptions): LlmProvider;
352
+ function geminiImages(options: GeminiImageOptions): ImageProvider;
353
+ ```
354
+
355
+ ### `vertexEndpoint`, `GEMINI_DEVELOPER_ENDPOINT`
356
+
357
+ ```ts
358
+ function vertexEndpoint(project: string, location?: string): string; // location defaults to 'global'
359
+ const GEMINI_DEVELOPER_ENDPOINT: string;
360
+ ```
361
+
362
+ ### `GeminiError`
363
+
364
+ ```ts
365
+ class GeminiError extends Error {
366
+ readonly status: number | undefined;
367
+ }
368
+ ```
369
+
370
+ ### Types
371
+
372
+ ```ts
373
+ type JsonSchema = { [key: string]: unknown };
374
+ interface JsonRequest {
375
+ system: string;
376
+ prompt: string;
377
+ schema: JsonSchema;
378
+ maxOutputTokens?: number; // a ceiling on the answer's size, reasoning not counted; pass it on as an output limit
379
+ effort?: 'low'; // a short structural request: use light reasoning if the model has a setting for it
380
+ images?: Array<{ mimeType: string; data: Uint8Array }>;
381
+ signal?: AbortSignal;
382
+ }
383
+ interface LlmProvider { generateJson(request: JsonRequest): Promise<unknown> }
384
+
385
+ interface ImageRequest { prompt: string; kind: ImageKind; aspectRatio: number; signal?: AbortSignal }
386
+ interface ImageProvider { generateImage(request: ImageRequest): Promise<Uint8Array> }
387
+
388
+ interface GeminiOptions {
389
+ model: string;
390
+ apiKey?: string;
391
+ endpoint?: string;
392
+ headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
393
+ fetch?: typeof fetch;
394
+ timeoutMs?: number;
395
+ thinkingLevel?: 'minimal' | 'low' | 'medium' | 'high';
396
+ maxOutputTokens?: number;
397
+ }
398
+ interface GeminiImageOptions {
399
+ model: string;
400
+ apiKey?: string;
401
+ endpoint?: string;
402
+ headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
403
+ fetch?: typeof fetch;
404
+ timeoutMs?: number;
405
+ imageSize?: '512' | '1K' | '2K' | '4K';
406
+ style?: string;
407
+ }
408
+ ```
409
+
410
+ ## Template studio
411
+
412
+ ### `draftManifest`
413
+
414
+ ```ts
415
+ function draftManifest(pptx: Uint8Array | PptxPackage, options: DraftOptions): Promise<DraftResult>;
416
+ ```
417
+
418
+ ### `checkManifest`
419
+
420
+ ```ts
421
+ function checkManifest(template: Template): ManifestIssue[];
422
+ ```
423
+
424
+ ### `sampleDeck`
425
+
426
+ ```ts
427
+ function sampleDeck(template: Template, options?: SampleOptions): { deck: DeckSpec; assets: Record<string, Uint8Array> };
428
+ ```
429
+
430
+ ### `changeManifest`
431
+
432
+ ```ts
433
+ function changeManifest(template: Template, changes: ManifestChange[]): ChangeResult;
434
+ ```
435
+
436
+ ### `editManifest`
437
+
438
+ ```ts
439
+ function editManifest(template: Template, instruction: string, options: ManifestEditOptions): Promise<ManifestEditResult>;
440
+ ```
441
+
442
+ ### `describeManifest`, `describeSlot`
443
+
444
+ ```ts
445
+ function describeManifest(template: Template): string;
446
+ function describeSlot(slot: SlotDef): string;
447
+ ```
448
+
449
+ ### `studioView`
450
+
451
+ ```ts
452
+ function studioView(template: Template): StudioView;
453
+ ```
454
+
455
+ ### `inspectTemplate`
456
+
457
+ ```ts
458
+ function inspectTemplate(pkg: PptxPackage): TemplateInfo;
459
+ ```
460
+
461
+ ### `ROLES`
462
+
463
+ ```ts
464
+ const ROLES: readonly ['title', 'subtitle', 'text', 'list', 'number', 'caption', 'photo', 'icon', 'graphic', 'chart', 'table', 'decoration', 'fixed'];
465
+ type Role = (typeof ROLES)[number];
466
+ ```
467
+
468
+ ### `PptxPackage`
469
+
470
+ ```ts
471
+ class PptxPackage {
472
+ static load(bytes: Uint8Array): PptxPackage;
473
+ clone(): PptxPackage;
474
+ has(partPath: string): boolean;
475
+ paths(): string[];
476
+ read(partPath: string): Uint8Array;
477
+ readText(partPath: string): string;
478
+ write(partPath: string, data: Uint8Array | string): void;
479
+ delete(partPath: string): void;
480
+ save(): Uint8Array;
481
+ }
482
+ ```
483
+
484
+ The unzipped parts of a pptx. Needed directly only for `inspectTemplate` and for reading a part such as a
485
+ picture out of a template (`template.pkg.read('ppt/media/image1.png')`).
486
+
487
+ ### Types
488
+
489
+ ```ts
490
+ interface SlidePicture { mimeType: string; data: Uint8Array }
491
+ interface DraftOptions {
492
+ llm: LlmProvider;
493
+ name?: string;
494
+ slideImage?: (slide: number) => SlidePicture | undefined | Promise<SlidePicture | undefined>;
495
+ slides?: number[];
496
+ concurrency?: number;
497
+ onProgress?: (event: { done: number; total: number; slide: number }) => void;
498
+ signal?: AbortSignal;
499
+ }
500
+ interface DraftResult { manifest: TemplateManifest; skipped: Array<{ slide: number; reason: string }>; issues: ManifestIssue[] }
501
+
502
+ interface ManifestIssue { severity: 'error' | 'warning'; pattern?: string; slot?: string; message: string }
503
+ interface SampleOptions { fill?: number; items?: 'drawn' | 'max' | 'min' }
504
+
505
+ type ManifestChange =
506
+ | { op: 'setManifest'; name?: string; language?: string; direction?: Direction; alignOnDirectionChange?: AlignPolicy; textScale?: number | null }
507
+ | { op: 'addPattern'; slide: number; id: string; description?: string }
508
+ | { op: 'copyPattern'; pattern: string; id: string; description?: string }
509
+ | { op: 'removePattern'; pattern: string }
510
+ | { op: 'setPattern'; pattern: string; id?: string; description?: string; figures?: boolean }
511
+ | { op: 'addSlot'; pattern: string; shape: string; role: Role; name?: string; optional?: boolean }
512
+ | { op: 'removeSlot'; pattern: string; slot: string }
513
+ | ({ op: 'setSlot'; pattern: string; slot: string } & SlotPatch)
514
+ | { op: 'setRepeat'; pattern: string; min?: number; max?: number; item?: string; span?: { left: number; right: number } | null }
515
+ | { op: 'removeRepeat'; pattern: string };
516
+
517
+ interface SlotPatch {
518
+ name?: string;
519
+ description?: string | null;
520
+ empty?: EmptyPolicy;
521
+ maxChars?: number;
522
+ maxParagraphs?: number | null;
523
+ deckField?: string | null;
524
+ alignOnDirectionChange?: AlignPolicy | null;
525
+ styleRun?: 'first' | 'last' | null;
526
+ fontSize?: number | null;
527
+ paragraphGap?: number | null;
528
+ scales?: boolean | null;
529
+ box?: SlideBox | null;
530
+ imageKind?: ImageKind;
531
+ fit?: 'cover' | 'contain' | null;
532
+ maxColumns?: number;
533
+ maxRows?: number;
534
+ maxCellChars?: number;
535
+ headerText?: TableTextStyle | null;
536
+ bodyText?: TableTextStyle | null;
537
+ maxCategories?: number;
538
+ maxSeries?: number;
539
+ colors?: string[] | null;
540
+ text?: TableTextStyle | null;
541
+ lineColor?: string | null;
542
+ }
543
+
544
+ interface ChangeResult {
545
+ manifest: TemplateManifest;
546
+ applied: Array<{ index: number; change: ManifestChange; message: string }>;
547
+ rejected: Array<{ index: number; change: ManifestChange; reason: string }>;
548
+ issues: ManifestIssue[];
549
+ }
550
+ interface ManifestEditOptions { llm: LlmProvider; signal?: AbortSignal }
551
+ interface ManifestEditResult extends ChangeResult { note: string }
552
+
553
+ interface StudioView { aspectRatio: number; slides: StudioSlide[] }
554
+ interface StudioSlide { slide: number; patterns: string[]; shapes: StudioShape[] }
555
+ interface StudioShape {
556
+ id: string;
557
+ kind: ShapeKind;
558
+ box: Box;
559
+ groupId?: string;
560
+ text?: string;
561
+ fontSize?: number;
562
+ frame: boolean;
563
+ roles: Role[];
564
+ slots: Array<{ pattern: string; name: string; kind: 'text' | 'image' | 'table' | 'chart'; empty: EmptyPolicy; summary: string }>;
565
+ }
566
+
567
+ type ShapeKind = 'text' | 'picture' | 'shape' | 'line' | 'group' | 'table' | 'other';
568
+ interface Box { x: number; y: number; w: number; h: number } // fractions of the slide
569
+ interface ShapeInfo {
570
+ id: string;
571
+ name: string;
572
+ kind: ShapeKind;
573
+ box: Box;
574
+ groupId?: string;
575
+ placeholder?: string;
576
+ paragraphs?: string[];
577
+ fontSizes?: number[];
578
+ image?: { part: string; width?: number; height?: number; cropped: boolean; geometry: string };
579
+ table?: { columns: number; rows: number };
580
+ }
581
+ interface SlideInfo { number: number; part: string; layout: string; shapes: ShapeInfo[] }
582
+ interface TemplateInfo { slideWidth: number; slideHeight: number; defaultFontSize: number; slides: SlideInfo[] }
583
+ ```
584
+
585
+ ## Manifest types
586
+
587
+ Described field by field in [manifest-format.md](manifest-format.md).
588
+
589
+ ```ts
590
+ type Direction = 'rtl' | 'ltr';
591
+ type AlignPolicy = 'flip' | 'keep';
592
+ type EmptyPolicy = 'error' | 'remove' | 'keep' | 'drop';
593
+ type ImageKind = 'photo' | 'icon' | 'graphic';
594
+ interface SlideBox { x: number; y: number; w: number; h: number }
595
+ interface TableTextStyle { size?: number; bold?: boolean; color?: string; font?: string }
596
+
597
+ interface TemplateManifest {
598
+ version: 1;
599
+ name: string;
600
+ language?: string;
601
+ direction: Direction;
602
+ alignOnDirectionChange?: AlignPolicy;
603
+ textScale?: number; // enlarges body text in every deck made from the template
604
+ patterns: PatternDef[];
605
+ }
606
+ interface PatternDef {
607
+ id: string;
608
+ sourceSlide: number;
609
+ description: string;
610
+ slots: SlotDef[];
611
+ figures?: boolean;
612
+ sequences?: string[][][];
613
+ repeat?: RepeatDef;
614
+ }
615
+ interface RepeatDef {
616
+ item: string;
617
+ slots: string[];
618
+ shapes: string[][];
619
+ min?: number;
620
+ max?: number;
621
+ span?: { left: number; right: number };
622
+ columns?: number;
623
+ }
624
+ type SlotDef = TextSlotDef | ImageSlotDef | TableSlotDef | ChartSlotDef;
625
+
626
+ // Every slot kind has: name, shapeId, description?, empty?
627
+ interface TextSlotDef {
628
+ kind: 'text';
629
+ name: string;
630
+ shapeId: string;
631
+ description?: string;
632
+ empty?: EmptyPolicy;
633
+ maxChars?: number;
634
+ maxParagraphs?: number;
635
+ deckField?: string;
636
+ alignOnDirectionChange?: AlignPolicy;
637
+ styleRun?: 'first' | 'last';
638
+ size?: number;
639
+ fontSize?: number;
640
+ box?: SlideBox;
641
+ paragraphGap?: number;
642
+ scales?: boolean;
643
+ }
644
+ interface ImageSlotDef {
645
+ kind: 'image';
646
+ name: string;
647
+ shapeId: string;
648
+ description?: string;
649
+ empty?: EmptyPolicy;
650
+ imageKind: ImageKind;
651
+ fit?: 'cover' | 'contain';
652
+ box?: SlideBox;
653
+ copyOf?: string; // set by the engine on slots of copied items
654
+ }
655
+ interface TableSlotDef {
656
+ kind: 'table';
657
+ name: string;
658
+ shapeId: string;
659
+ description?: string;
660
+ empty?: EmptyPolicy;
661
+ maxColumns?: number;
662
+ maxRows?: number;
663
+ maxCellChars?: number;
664
+ headerText?: TableTextStyle;
665
+ bodyText?: TableTextStyle;
666
+ }
667
+ interface ChartSlotDef {
668
+ kind: 'chart';
669
+ name: string;
670
+ shapeId: string;
671
+ description?: string;
672
+ empty?: EmptyPolicy;
673
+ box?: SlideBox;
674
+ maxCategories?: number;
675
+ maxSeries?: number;
676
+ colors?: string[];
677
+ text?: TableTextStyle;
678
+ lineColor?: string;
679
+ }
680
+ ```