@lofcz/pptist 2.0.2 → 2.0.4

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.
@@ -1,93 +1,196 @@
1
1
  {
2
- "schemaVersion": 1,
2
+ "schemaVersion": 2,
3
3
  "package": "@lofcz/pptist",
4
- "packageVersion": "2.0.1",
5
- "generatedAt": "2026-05-31T12:03:02.499Z",
6
- "commandCount": 168,
4
+ "packageVersion": "2.0.4",
5
+ "generatedAt": "2026-06-01T01:20:10.387Z",
6
+ "summary": "Authoring guidance for the PPTist agentic bridge: the coordinate system, a default design system, per-domain and per-command notes, and reusable slide composition recipes. Pair this with the machine schema (command payload/return types) in the same manifest.",
7
+ "commandCount": 169,
8
+ "designSystem": {
9
+ "summary": "PPTist lays elements out in a fixed pixel coordinate space, not inches. Design against these tokens for clean, readable decks.",
10
+ "coordinateSystem": {
11
+ "summary": "The default 16:9 canvas is 1000 x 562.5 px (viewport.size = 1000, viewport.ratio = 0.5625). Origin (0,0) is the top-left corner. Every element has left, top, width, height in px and rotate in degrees.",
12
+ "notes": [
13
+ "Canvas width = viewport.size; canvas height = viewport.size * viewport.ratio. For the default 16:9 deck that is 1000 x 562.5 px.",
14
+ "Keep a 40px safe margin from every edge (left/top >= 40, and left+width <= 960, top+height <= 522 on the default canvas).",
15
+ "Coordinates are absolute px, NOT inches/points. To port an inches-based layout, multiply inches by 100 (10in wide deck -> 1000px).",
16
+ "rotate is clockwise degrees about the element center. Lines use start/end points instead of width/height/rotate.",
17
+ "Text size is controlled by inline styles inside the element's HTML content (e.g. <span style=\"font-size:40px\">), not by a top-level fontSize field. defaultColor/defaultFontName are only fallbacks."
18
+ ]
19
+ },
20
+ "tokens": {
21
+ "summary": "A neutral, presentation-safe default palette and type scale (px). Override per deck via deck.setTheme.",
22
+ "colors": {
23
+ "background": "#FFFFFF",
24
+ "primary": "#1F4E79",
25
+ "accent": "#2E75B6",
26
+ "body": "#2D2D2D",
27
+ "muted": "#777777",
28
+ "rule": "#CCCCCC",
29
+ "highlight": "#FFF2CC"
30
+ },
31
+ "fontFamily": "Arial",
32
+ "fontSizePx": {
33
+ "display": 64,
34
+ "title": 40,
35
+ "sectionHeader": 30,
36
+ "body": 24,
37
+ "label": 18,
38
+ "caption": 14
39
+ },
40
+ "spacingPx": {
41
+ "margin": 40,
42
+ "gutter": 24,
43
+ "ruleThickness": 3
44
+ }
45
+ }
46
+ },
7
47
  "domains": [
8
48
  {
9
49
  "id": "deck",
10
- "commandCount": 7
50
+ "commandCount": 7,
51
+ "title": "Deck",
52
+ "summary": "Whole-document state: title, theme, viewport, templates, plus full get/set/patch.",
53
+ "whenToUse": "Set the deck theme and viewport once up front; use whole-document import/export at persistence boundaries."
11
54
  },
12
55
  {
13
56
  "id": "import",
14
- "commandCount": 3
57
+ "commandCount": 3,
58
+ "title": "Import",
59
+ "summary": "Replace the deck from a JSON-safe document (json / pptist / pptxSafe).",
60
+ "whenToUse": "Load a whole deck the host already reduced to a serializable payload."
15
61
  },
16
62
  {
17
63
  "id": "export",
18
- "commandCount": 1
64
+ "commandCount": 1,
65
+ "title": "Export",
66
+ "summary": "Serializable JSON snapshot of the deck.",
67
+ "whenToUse": "Persist/autosave from documentChanged events."
19
68
  },
20
69
  {
21
70
  "id": "slides",
22
- "commandCount": 17
71
+ "commandCount": 17,
72
+ "title": "Slides",
73
+ "summary": "Create, read, update, delete, duplicate, move, select slides; set background, transition and speaker remark.",
74
+ "whenToUse": "Add one slide per idea; capture the returned slide id and reuse it for every element you place on that slide."
23
75
  },
24
76
  {
25
77
  "id": "elements",
26
- "commandCount": 33
78
+ "commandCount": 33,
79
+ "title": "Elements",
80
+ "summary": "Generic element CRUD plus transform, ordering, grouping, lock/hide, and shared styling (outline, shadow, fill, link).",
81
+ "whenToUse": "Use the generic create/update when you want one call across element types, or the typed sub-domains (text/shapes/charts/...) for richer helpers."
27
82
  },
28
83
  {
29
84
  "id": "latex",
30
- "commandCount": 3
85
+ "commandCount": 3,
86
+ "title": "LaTeX",
87
+ "summary": "Formula elements rendered from LaTeX.",
88
+ "whenToUse": "Equations and math notation."
31
89
  },
32
90
  {
33
91
  "id": "text",
34
- "commandCount": 10
92
+ "commandCount": 11,
93
+ "title": "Text",
94
+ "summary": "Text element create/update plus content helpers. Accepts Markdown via text.create({ markdown }) and text.setMarkdown.",
95
+ "whenToUse": "Place titles, body copy and captions. Author content as HTML, or pass Markdown and let the bridge convert it."
35
96
  },
36
97
  {
37
98
  "id": "lines",
38
- "commandCount": 6
99
+ "commandCount": 6,
100
+ "title": "Lines",
101
+ "summary": "Straight/curved connectors with arrowheads and direction.",
102
+ "whenToUse": "Draw rules, arrows, and connectors. Lines use start/end points, not width/height."
39
103
  },
40
104
  {
41
105
  "id": "richText",
42
- "commandCount": 3
106
+ "commandCount": 3,
107
+ "title": "Rich text",
108
+ "summary": "Document-model edits to a text element's prose: set content, run styles and paragraph attributes.",
109
+ "whenToUse": "Use when you need paragraph alignment / inline run styling beyond raw HTML replacement."
43
110
  },
44
111
  {
45
112
  "id": "animations",
46
- "commandCount": 9
113
+ "commandCount": 9,
114
+ "title": "Animations",
115
+ "summary": "Per-slide entrance/emphasis/exit animations; list, catalog, create, reorder, trigger and duration.",
116
+ "whenToUse": "Reveal content progressively. Read animations.catalog for valid effect keys first."
47
117
  },
48
118
  {
49
119
  "id": "tables",
50
- "commandCount": 10
120
+ "commandCount": 10,
121
+ "title": "Tables",
122
+ "summary": "Table create and cell/row/column edits, styling, merge/split.",
123
+ "whenToUse": "Comparison grids and small data tables. Keep them small enough to read at body size."
51
124
  },
52
125
  {
53
126
  "id": "charts",
54
- "commandCount": 10
127
+ "commandCount": 10,
128
+ "title": "Charts",
129
+ "summary": "Chart element create plus type/data/labels/legends/series/options.",
130
+ "whenToUse": "Show one quantitative finding per slide. Set data with labels + series, then annotate the takeaway in text."
55
131
  },
56
132
  {
57
133
  "id": "images",
58
- "commandCount": 14
134
+ "commandCount": 14,
135
+ "title": "Images",
136
+ "summary": "Image element styling: source, clip/crop, radius, filters, flip, shadow, color mask, set-as-background.",
137
+ "whenToUse": "Place and style raster art. Resolve media to a URL/data URL before calling the bridge."
59
138
  },
60
139
  {
61
140
  "id": "media",
62
- "commandCount": 4
141
+ "commandCount": 4,
142
+ "title": "Media",
143
+ "summary": "JSON-safe image/video/audio source assignment with mime/ext inference.",
144
+ "whenToUse": "Attach already-resolved media URLs to elements."
63
145
  },
64
146
  {
65
147
  "id": "videos",
66
- "commandCount": 8
148
+ "commandCount": 8,
149
+ "title": "Videos",
150
+ "summary": "Video element source, poster, playback, autoplay, size, position.",
151
+ "whenToUse": "Embed a video clip with a poster frame."
67
152
  },
68
153
  {
69
154
  "id": "audio",
70
- "commandCount": 7
155
+ "commandCount": 7,
156
+ "title": "Audio",
157
+ "summary": "Audio element create plus source, playback, icon, transform.",
158
+ "whenToUse": "Add narration or sound; style the speaker icon."
71
159
  },
72
160
  {
73
161
  "id": "notes",
74
- "commandCount": 4
162
+ "commandCount": 4,
163
+ "title": "Notes",
164
+ "summary": "Slide comment threads: notes and replies.",
165
+ "whenToUse": "Author review comments; not the same as the speaker remark (slides.setRemark)."
75
166
  },
76
167
  {
77
168
  "id": "sections",
78
- "commandCount": 7
169
+ "commandCount": 7,
170
+ "title": "Sections",
171
+ "summary": "Group slides into named sections for long decks.",
172
+ "whenToUse": "Add a section per major part of a long talk."
79
173
  },
80
174
  {
81
175
  "id": "search",
82
- "commandCount": 2
176
+ "commandCount": 2,
177
+ "title": "Search",
178
+ "summary": "Find/replace across text, shape text and table cells.",
179
+ "whenToUse": "Bulk rename or correct terminology across the deck."
83
180
  },
84
181
  {
85
182
  "id": "history",
86
- "commandCount": 3
183
+ "commandCount": 3,
184
+ "title": "History",
185
+ "summary": "Commit, undo, redo against the shared history stack.",
186
+ "whenToUse": "Group a multi-step edit into one undo via executeBatch, or commit/undo manually."
87
187
  },
88
188
  {
89
189
  "id": "view",
90
- "commandCount": 7
190
+ "commandCount": 7,
191
+ "title": "View",
192
+ "summary": "Zoom, locale, slide navigation, enter/exit presentation.",
193
+ "whenToUse": "Drive presentation playback and the active slide."
91
194
  }
92
195
  ],
93
196
  "commands": [
@@ -143,13 +246,60 @@
143
246
  "name": "deck.setTheme",
144
247
  "domain": "deck",
145
248
  "payload": "{ theme: PptistSlideThemePatch }",
146
- "returns": "SlideTheme"
249
+ "returns": "SlideTheme",
250
+ "doc": {
251
+ "summary": "Replace named theme properties (colors, fonts, background, outline, shadow) for the whole deck.",
252
+ "details": "Set the design tokens once before building slides so element defaults inherit them. Accepts a partial patch; only provided keys change.",
253
+ "params": [
254
+ {
255
+ "name": "theme.themeColors",
256
+ "type": "string[]",
257
+ "description": "Accent palette used by charts and pickers."
258
+ },
259
+ {
260
+ "name": "theme.fontColor",
261
+ "type": "string",
262
+ "description": "Default body text color."
263
+ },
264
+ {
265
+ "name": "theme.fontName",
266
+ "type": "string",
267
+ "description": "Default font family."
268
+ },
269
+ {
270
+ "name": "theme.backgroundColor",
271
+ "type": "string",
272
+ "description": "Default slide background."
273
+ }
274
+ ],
275
+ "examples": [
276
+ "controller.deck.setTheme({ themeColors: ['#2E75B6','#ED7D31','#70AD47'], fontColor: '#2D2D2D', fontName: 'Arial', backgroundColor: '#FFFFFF' })"
277
+ ],
278
+ "tips": [
279
+ "Set the theme before creating elements so defaultColor/defaultFontName inherit it."
280
+ ],
281
+ "related": [
282
+ "deck.setViewport",
283
+ "slides.setBackground",
284
+ "slides.applyBackground"
285
+ ]
286
+ }
147
287
  },
148
288
  {
149
289
  "name": "deck.setViewport",
150
290
  "domain": "deck",
151
291
  "payload": "{ size?: number; ratio?: number }",
152
- "returns": "PptistBridgeState"
292
+ "returns": "PptistBridgeState",
293
+ "doc": {
294
+ "summary": "Set the canvas size/aspect ratio. size is the canvas width in px; ratio is height/width.",
295
+ "details": "Default is { size: 1000, ratio: 0.5625 } (16:9, 1000 x 562.5 px). Use ratio 0.75 for 4:3.",
296
+ "examples": [
297
+ "controller.deck.setViewport({ size: 1000, ratio: 0.5625 })"
298
+ ],
299
+ "related": [
300
+ "deck.setTheme"
301
+ ]
302
+ }
153
303
  },
154
304
  {
155
305
  "name": "deck.setTemplates",
@@ -188,13 +338,58 @@
188
338
  "domain": "slides",
189
339
  "payload": "{ slide?: Partial<Slide>; index?: number; select?: boolean }",
190
340
  "returns": "Slide",
191
- "optional": true
341
+ "optional": true,
342
+ "doc": {
343
+ "summary": "Create and append a new slide; returns the created slide (use its id for element placement).",
344
+ "details": "Pass a partial slide. Omit id to get a generated one. background defaults to the theme. Set select:true to make it the active slide. Use slides.insert to control the position.",
345
+ "params": [
346
+ {
347
+ "name": "slide",
348
+ "type": "Partial<Slide>",
349
+ "required": false,
350
+ "description": "Slide fields. elements may be provided inline, or added later with elements/text/shapes.create."
351
+ },
352
+ {
353
+ "name": "index",
354
+ "type": "number",
355
+ "required": false,
356
+ "description": "Insert position; appends when omitted or non-finite."
357
+ },
358
+ {
359
+ "name": "select",
360
+ "type": "boolean",
361
+ "required": false,
362
+ "description": "Select the new slide (default true)."
363
+ }
364
+ ],
365
+ "examples": [
366
+ "const res = await controller.slides.create({ slide: { background: { type: 'solid', color: '#1F4E79' } }, select: true })",
367
+ "const slideId = res.data.id // reuse for every element on this slide"
368
+ ],
369
+ "tips": [
370
+ "Always read result.data.id and pass it as meta.slideId / payload.slideId for subsequent element commands.",
371
+ "Group the slide + its elements in one executeBatch so the whole slide is a single undo step."
372
+ ],
373
+ "related": [
374
+ "slides.insert",
375
+ "elements.create",
376
+ "text.create",
377
+ "shapes.create"
378
+ ]
379
+ }
192
380
  },
193
381
  {
194
382
  "name": "slides.insert",
195
383
  "domain": "slides",
196
384
  "payload": "PptistInsertSlidesInput",
197
- "returns": "PptistInsertSlidesResult"
385
+ "returns": "PptistInsertSlidesResult",
386
+ "doc": {
387
+ "summary": "Insert a slide at a specific index (same payload as slides.create plus index).",
388
+ "related": [
389
+ "slides.create",
390
+ "slides.move"
391
+ ]
392
+ }
198
393
  },
199
394
  {
200
395
  "name": "slides.update",
@@ -231,7 +426,17 @@
231
426
  "name": "slides.setBackground",
232
427
  "domain": "slides",
233
428
  "payload": "{ slideId: string; background?: Slide['background'] }",
234
- "returns": "Slide"
429
+ "returns": "Slide",
430
+ "doc": {
431
+ "summary": "Set one slide's background (solid color, gradient, or image).",
432
+ "examples": [
433
+ "controller.slides.setBackground(slideId, { type: 'solid', color: '#1F4E79' })"
434
+ ],
435
+ "related": [
436
+ "slides.applyBackground",
437
+ "deck.setTheme"
438
+ ]
439
+ }
235
440
  },
236
441
  {
237
442
  "name": "slides.applyBackground",
@@ -263,7 +468,16 @@
263
468
  "name": "slides.setRemark",
264
469
  "domain": "slides",
265
470
  "payload": "{ slideId: string; remark: string }",
266
- "returns": "Slide"
471
+ "returns": "Slide",
472
+ "doc": {
473
+ "summary": "Set the speaker notes (remark) for a slide. Content is HTML.",
474
+ "examples": [
475
+ "controller.slides.setRemark(slideId, '<p>Pause here and ask the audience.</p>')"
476
+ ],
477
+ "related": [
478
+ "notes.create"
479
+ ]
480
+ }
267
481
  },
268
482
  {
269
483
  "name": "elements.list",
@@ -282,7 +496,43 @@
282
496
  "name": "elements.create",
283
497
  "domain": "elements",
284
498
  "payload": "{ slideId?: string; index?: number; element: Partial<PPTElement> & { type: PPTElement['type'] }; select?: boolean }",
285
- "returns": "PPTElement"
499
+ "returns": "PPTElement",
500
+ "doc": {
501
+ "summary": "Create any element type on a slide. payload.element.type is required.",
502
+ "details": "Generic creator across all element types. For text you can use { type:'text', content } (HTML). Prefer the typed creators (text.create, shapes.create, charts.create, tables.create) for richer, validated input. Provide left/top/width/height in canvas px and rotate in degrees.",
503
+ "params": [
504
+ {
505
+ "name": "slideId",
506
+ "type": "string",
507
+ "required": false,
508
+ "description": "Target slide; defaults to the current slide."
509
+ },
510
+ {
511
+ "name": "element",
512
+ "type": "Partial<PPTElement> & { type }",
513
+ "required": true,
514
+ "description": "Element fields; type is mandatory."
515
+ },
516
+ {
517
+ "name": "index",
518
+ "type": "number",
519
+ "required": false,
520
+ "description": "Z-order insert index."
521
+ }
522
+ ],
523
+ "examples": [
524
+ "controller.elements.create({ slideId, element: { type:'text', left:40, top:40, width:920, height:90, rotate:0, content:'<p><span style=\"font-size:40px;color:#1F4E79\"><strong>Action title</strong></span></p>', defaultFontName:'Arial', defaultColor:'#1F4E79' } })"
525
+ ],
526
+ "tips": [
527
+ "Text font size lives in inline HTML styles inside content, not in a fontSize field."
528
+ ],
529
+ "related": [
530
+ "text.create",
531
+ "shapes.create",
532
+ "charts.create",
533
+ "tables.create"
534
+ ]
535
+ }
286
536
  },
287
537
  {
288
538
  "name": "elements.insert",
@@ -498,9 +748,51 @@
498
748
  {
499
749
  "name": "text.create",
500
750
  "domain": "text",
501
- "payload": "{ slideId?: string; index?: number; content?: string; element?: Partial<PPTTextElement>; select?: boolean }",
751
+ "payload": "PptistCreateTextInput | undefined",
502
752
  "returns": "PPTTextElement",
503
- "optional": true
753
+ "doc": {
754
+ "summary": "Create a text element. Accepts HTML via content, or Markdown via markdown (converted to HTML).",
755
+ "details": "If element.content or content (HTML) is given it wins; otherwise markdown is converted to HTML. Size text via inline styles in the HTML; use defaultColor for the fallback color.",
756
+ "params": [
757
+ {
758
+ "name": "slideId",
759
+ "type": "string",
760
+ "required": false,
761
+ "description": "Target slide."
762
+ },
763
+ {
764
+ "name": "content",
765
+ "type": "string",
766
+ "required": false,
767
+ "description": "HTML content (wins over markdown)."
768
+ },
769
+ {
770
+ "name": "markdown",
771
+ "type": "string",
772
+ "required": false,
773
+ "description": "Markdown content; converted to HTML."
774
+ },
775
+ {
776
+ "name": "element",
777
+ "type": "Partial<PPTTextElement>",
778
+ "required": false,
779
+ "description": "Geometry/styling: left, top, width, height, rotate, defaultColor, defaultFontName, lineHeight, wordSpace, fill."
780
+ }
781
+ ],
782
+ "examples": [
783
+ "controller.text.create({ slideId, markdown: '**Key finding:** treated group improved 18%', element: { left:520, top:130, width:440, height:300, rotate:0, defaultColor:'#2D2D2D' } })",
784
+ "controller.text.create({ slideId, content:'<p><span style=\"font-size:40px;color:#1F4E79\"><strong>Methods</strong></span></p>', element:{ left:40, top:40, width:920, height:90, rotate:0 } })"
785
+ ],
786
+ "tips": [
787
+ "Flavor: markdown-it + markdown-it-texmath (KaTeX)."
788
+ ],
789
+ "related": [
790
+ "text.setMarkdown",
791
+ "text.setContent",
792
+ "richText.setContent",
793
+ "elements.create"
794
+ ]
795
+ }
504
796
  },
505
797
  {
506
798
  "name": "text.update",
@@ -524,7 +816,30 @@
524
816
  "name": "text.setContent",
525
817
  "domain": "text",
526
818
  "payload": "{ elementId: string; slideId?: string; content: string }",
527
- "returns": "PPTTextElement"
819
+ "returns": "PPTTextElement",
820
+ "doc": {
821
+ "summary": "Replace a text element's HTML content verbatim.",
822
+ "related": [
823
+ "text.setMarkdown",
824
+ "richText.setContent"
825
+ ]
826
+ }
827
+ },
828
+ {
829
+ "name": "text.setMarkdown",
830
+ "domain": "text",
831
+ "payload": "{ elementId: string; slideId?: string; markdown: string }",
832
+ "returns": "PPTTextElement",
833
+ "doc": {
834
+ "summary": "Replace a text element's content from a Markdown string (converted to HTML).",
835
+ "examples": [
836
+ "controller.text.setMarkdown(elementId, '- First point\\n- Second point\\n- Third point')"
837
+ ],
838
+ "related": [
839
+ "text.setContent",
840
+ "text.create"
841
+ ]
842
+ }
528
843
  },
529
844
  {
530
845
  "name": "text.updateContent",
@@ -622,7 +937,20 @@
622
937
  "name": "animations.create",
623
938
  "domain": "animations",
624
939
  "payload": "{ slideId: string; animation: Partial<PPTAnimation> & { elId: string; effect: string; type: PPTAnimation['type'] } }",
625
- "returns": "PPTAnimation"
940
+ "returns": "PPTAnimation",
941
+ "doc": {
942
+ "summary": "Add an animation to an element on a slide. Read animations.catalog for valid effect keys.",
943
+ "details": "type is 'in' (entrance), 'out' (exit) or 'attention' (emphasis). effect must be a key from animations.catalog. trigger is 'click', 'meantime' or 'auto'.",
944
+ "examples": [
945
+ "const cat = controller.animations.catalog()",
946
+ "controller.animations.create(slideId, { elId: elementId, type:'in', effect:'fadeIn', trigger:'click', duration:600 })"
947
+ ],
948
+ "related": [
949
+ "animations.catalog",
950
+ "animations.reorder",
951
+ "animations.setTrigger"
952
+ ]
953
+ }
626
954
  },
627
955
  {
628
956
  "name": "animations.update",
@@ -659,7 +987,19 @@
659
987
  "domain": "tables",
660
988
  "payload": "PptistCreateTableInput",
661
989
  "returns": "PPTTableElement",
662
- "optional": true
990
+ "optional": true,
991
+ "doc": {
992
+ "summary": "Create a table with rows x columns of cells.",
993
+ "details": "Supply data as a 2D array of cells. Edit cells with tables.setCell, style with tables.setCellStyle, and grow/shrink with insert/delete row/column.",
994
+ "examples": [
995
+ "controller.tables.create({ slideId, element:{ left:40, top:140, width:920, height:300, rotate:0, colWidths:[0.5,0.5], data:[[{ text:'Metric' },{ text:'Value' }],[{ text:'N' },{ text:'2,400' }]] } })"
996
+ ],
997
+ "related": [
998
+ "tables.setCell",
999
+ "tables.setCellStyle",
1000
+ "tables.insertRow"
1001
+ ]
1002
+ }
663
1003
  },
664
1004
  {
665
1005
  "name": "tables.update",
@@ -720,7 +1060,42 @@
720
1060
  "domain": "charts",
721
1061
  "payload": "PptistCreateChartInput",
722
1062
  "returns": "PPTChartElement",
723
- "optional": true
1063
+ "optional": true,
1064
+ "doc": {
1065
+ "summary": "Create a chart element with type + data (labels, legends, series).",
1066
+ "details": "One chart per slide. Provide labels (category axis), legends (series names) and series (arrays of numbers). State the takeaway in an adjacent text element rather than relying on the chart alone.",
1067
+ "params": [
1068
+ {
1069
+ "name": "slideId",
1070
+ "type": "string",
1071
+ "required": false,
1072
+ "description": "Target slide."
1073
+ },
1074
+ {
1075
+ "name": "chartType",
1076
+ "type": "ChartType",
1077
+ "required": false,
1078
+ "description": "bar, column, line, pie, ring, area, radar, scatter."
1079
+ },
1080
+ {
1081
+ "name": "data",
1082
+ "type": "ChartData",
1083
+ "required": false,
1084
+ "description": "{ labels: string[], legends: string[], series: number[][] }."
1085
+ }
1086
+ ],
1087
+ "examples": [
1088
+ "controller.charts.create({ slideId, chartType:'bar', data:{ labels:['Q1','Q2','Q3','Q4'], legends:['Effect %'], series:[[28,22,15,8]] }, element:{ left:40, top:130, width:540, height:360, rotate:0 } })"
1089
+ ],
1090
+ "tips": [
1091
+ "Put the interpretive text on the right (~520px) and the chart on the left (~40px)."
1092
+ ],
1093
+ "related": [
1094
+ "charts.setData",
1095
+ "charts.setType",
1096
+ "charts.setOptions"
1097
+ ]
1098
+ }
724
1099
  },
725
1100
  {
726
1101
  "name": "charts.update",
@@ -1113,6 +1488,142 @@
1113
1488
  "returns": "{ locale: Locales }"
1114
1489
  }
1115
1490
  ],
1491
+ "guides": [
1492
+ {
1493
+ "id": "getting-started",
1494
+ "title": "How to build a deck",
1495
+ "summary": "The read -> theme -> per-slide batch -> review loop the bridge is designed for.",
1496
+ "body": [
1497
+ "1. Read the current deck (controller.export.json() or deck.get) and the design tokens (controller.docs().designSystem).",
1498
+ "2. Set the deck theme once with deck.setTheme so element defaults inherit your palette and font.",
1499
+ "3. For each slide: create the slide, capture result.data.id, then add its elements in a single executeBatch so the slide is one undo step.",
1500
+ "4. Place elements in canvas px (default 1000 x 562.5). Keep a 40px margin and a clear visual hierarchy: title row, content area, footer/citation.",
1501
+ "5. Author body text in Markdown (text.create({ markdown }) / text.setMarkdown) or HTML; use inline font-size styles in HTML when you need exact sizes.",
1502
+ "6. Review and iterate. Use meta.dryRun to validate a risky payload before applying it."
1503
+ ]
1504
+ },
1505
+ {
1506
+ "id": "coordinate-system",
1507
+ "title": "Coordinate system & sizing",
1508
+ "summary": "Everything is absolute pixels on a 1000 x 562.5 canvas.",
1509
+ "body": [
1510
+ "Canvas = viewport.size wide by viewport.size * viewport.ratio tall. Default 16:9 -> 1000 x 562.5 px. Origin is top-left.",
1511
+ "Element box: left, top, width, height (px) and rotate (clockwise degrees about the center). Lines use start/end points instead.",
1512
+ "Safe area: keep left/top >= 40 and right/bottom edges <= 960 / 522 on the default canvas.",
1513
+ "Porting an inches layout (e.g. pptxgenjs 10in x 5.625in): multiply inches by 100. 0.5in margin -> 50px; a 5.4in-wide chart -> 540px.",
1514
+ "Text size is set by inline HTML styles inside content, e.g. <span style=\"font-size:40px\">. defaultColor/defaultFontName are only fallbacks for unsized runs."
1515
+ ]
1516
+ },
1517
+ {
1518
+ "id": "title-slide",
1519
+ "title": "Title slide",
1520
+ "summary": "Dark background, large statement title, subtitle, author/affiliation, accent rule.",
1521
+ "body": [
1522
+ "Slide: background solid primary (#1F4E79).",
1523
+ "Title text: left 70, top 150, width 860, height 180. content uses ~64px bold white, framed as a statement or question.",
1524
+ "Subtitle text: left 70, top 330, width 860, height 40. ~18px in a light tint (#A0BBDD).",
1525
+ "Author/affiliation text: left 70, top 380, width 860, height 60. ~16px (#CADCFC).",
1526
+ "Accent rule: a shape at left 70, top 360, width 200, height 4, fill accent (#2E75B6).",
1527
+ "Avoid: clip art, logos (unless requested), decorative images."
1528
+ ]
1529
+ },
1530
+ {
1531
+ "id": "section-divider",
1532
+ "title": "Section divider",
1533
+ "summary": "Orient the audience at the start of each major part of a long deck.",
1534
+ "body": [
1535
+ "Slide: dark background (a slightly lighter navy, e.g. #1A3A5C, for variety).",
1536
+ "Eyebrow text: 'Part 2' at left 40, top 180, ~18px (#7BAFD4).",
1537
+ "Section title text: left 40, top 220, width 920, ~40px bold white.",
1538
+ "Accent rule: shape left 40, top 330, width 250, height 6, fill accent."
1539
+ ]
1540
+ },
1541
+ {
1542
+ "id": "content-bullets",
1543
+ "title": "Content slide (action title + bullets)",
1544
+ "summary": "An action title that states the takeaway, a thin divider, and concise body bullets.",
1545
+ "body": [
1546
+ "Action title text: left 40, top 30, width 920, height 90. ~40px bold primary. Write a full sentence that states the point, not just a topic.",
1547
+ "Divider: shape left 40, top 120, width 920, height 3, fill rule (#CCCCCC).",
1548
+ "Body text: left 40, top 140, width 920, height 360. Author with Markdown bullets (text.create({ markdown })). Keep <= ~40 words; body >= 24px.",
1549
+ "Optional citation: text left 40, top 520, ~14px muted."
1550
+ ]
1551
+ },
1552
+ {
1553
+ "id": "two-column",
1554
+ "title": "Two-column layout",
1555
+ "summary": "A header per column with aligned body blocks; good for design vs. outcomes.",
1556
+ "body": [
1557
+ "Left column header: text left 40, top 130, width 440, ~30px accent bold.",
1558
+ "Left body: text left 40, top 175, width 440, height 300, Markdown bullets.",
1559
+ "Right column header: text left 520, top 130, width 440, ~30px accent bold.",
1560
+ "Right body: text left 520, top 175, width 440, height 300, Markdown bullets.",
1561
+ "Keep the same top for both columns so headers align."
1562
+ ]
1563
+ },
1564
+ {
1565
+ "id": "results-with-chart",
1566
+ "title": "Results slide (chart + interpretation)",
1567
+ "summary": "One exhibit, one finding. Chart left, interpretive text right, takeaway in the title.",
1568
+ "body": [
1569
+ "Action title text: left 40, top 30, width 920, height 90. State the result (e.g. 'Treated group earns 18% more').",
1570
+ "Divider: shape left 40, top 120, width 920, height 3, fill rule.",
1571
+ "Chart: charts.create at left 40, top 135, width 540, height 360 with labels + one series.",
1572
+ "Interpretation header: text left 620, top 135, width 330, ~30px accent bold.",
1573
+ "Interpretation bullets: text left 620, top 180, width 330, height 250, Markdown.",
1574
+ "Source citation: text left 40, top 520, ~14px muted.",
1575
+ "Annotate the single key number directly with a small highlight shape (#FFF2CC) + label over the chart."
1576
+ ]
1577
+ },
1578
+ {
1579
+ "id": "conclusions",
1580
+ "title": "Conclusions slide",
1581
+ "summary": "Mirror the title slide; numbered takeaways that stay on screen during Q&A.",
1582
+ "body": [
1583
+ "Slide: dark background primary (matches the title slide for a 'sandwich' structure).",
1584
+ "Eyebrow text: 'Conclusions' at left 40, top 25, ~20px light tint.",
1585
+ "Accent rule: shape left 40, top 70, width 920, height 4, fill accent.",
1586
+ "Takeaways text: left 40, top 90, width 920, height 350. Numbered Markdown list, ~26px white, with the lead clause of each point bold.",
1587
+ "Contact/link text: left 40, top 480, ~14px light tint."
1588
+ ]
1589
+ },
1590
+ {
1591
+ "id": "shapes-howto",
1592
+ "title": "Working with shapes",
1593
+ "summary": "How to build dividers, rules, callout boxes and color blocks from presets or raw paths.",
1594
+ "body": [
1595
+ "Start from a preset: const presets = controller.shapes.presets('rect'); then spread one into shapes.create and override geometry/fill.",
1596
+ "Raw path: provide viewBox (e.g. [200,200]) and an SVG path in that box; PPTist scales it to width/height. A filled rectangle path is 'M 0 0 L 200 0 L 200 200 L 0 200 Z'.",
1597
+ "Accent rule / divider: a wide, low-height filled rectangle (height 3-6px) in the rule or accent color.",
1598
+ "Callout box: a rounded-rect preset with a light fill (#EBF3FA or #FFF2CC) and a 1.5-2px outline in accent; add centered inner text via element.text or shapes.setText.",
1599
+ "Background band: a full-width shape with a low z-order (send it to back with elements.sendToBack) sitting behind text.",
1600
+ "Use opacity and gradient (shapes.setGradient) sparingly for depth; keep contrast high enough to read body text."
1601
+ ]
1602
+ },
1603
+ {
1604
+ "id": "markdown",
1605
+ "title": "Authoring text in Markdown",
1606
+ "summary": "The bridge converts Markdown to the HTML PPTist stores. Use it for fast, readable copy.",
1607
+ "body": [
1608
+ "Flavor: markdown-it + markdown-it-texmath (KaTeX).",
1609
+ "Use text.create({ markdown }) / text.setMarkdown(elementId, markdown), or await controller.markdownToHtml(md)."
1610
+ ]
1611
+ },
1612
+ {
1613
+ "id": "quality-checklist",
1614
+ "title": "Pre-delivery checklist",
1615
+ "summary": "Quick checks before declaring a deck done.",
1616
+ "body": [
1617
+ "Every content slide has an action title that states the takeaway (a full sentence, not a topic).",
1618
+ "Reading the titles alone tells the complete argument.",
1619
+ "Results slides show one exhibit each, with the key number annotated.",
1620
+ "Body text >= 24px; no slide has more than ~40 words of body text.",
1621
+ "Borrowed figures/data carry an in-slide citation.",
1622
+ "A 40px margin is respected on every edge; nothing is clipped off-canvas.",
1623
+ "Title and conclusions slides share the dark treatment (sandwich structure)."
1624
+ ]
1625
+ }
1626
+ ],
1116
1627
  "helperTypes": {
1117
1628
  "ImageFilterKey": "type ImageFilterKey = keyof NonNullable<PPTImageElement['filters']>",
1118
1629
  "PptistAnimationCatalog": "export interface PptistAnimationCatalog { enter: PptistAnimationPresetGroup[]; exit: PptistAnimationPresetGroup[]; attention: PptistAnimationPresetGroup[]; slide: PptistSlideAnimationPreset[] }",
@@ -1129,6 +1640,7 @@
1129
1640
  "PptistCreateLatexElementInput": "export interface PptistCreateLatexElementInput { slideId?: string; index?: number; element: PptistLatexElementInput; select?: boolean }",
1130
1641
  "PptistCreateLineElementInput": "export interface PptistCreateLineElementInput { slideId?: string; index?: number; element: PptistLineElementInput; select?: boolean }",
1131
1642
  "PptistCreateTableInput": "export type PptistCreateTableInput = PptistTableElementPatch & { id?: string; slideId?: string; index?: number; select?: boolean; element?: Partial<PPTTableElement> }",
1643
+ "PptistCreateTextInput": "export interface PptistCreateTextInput { slideId?: string; index?: number; content?: string; markdown?: string; element?: Partial<PPTTextElement>; select?: boolean }",
1132
1644
  "PptistDeckDocument": "export type PptistDeckDocument = Omit<PptistDocument, 'theme'> & { theme: SlideTheme; viewport: PptistDeckViewport; templates: SlideTemplate[] }",
1133
1645
  "PptistDeckInput": "export type PptistDeckInput = Omit<PptistDocument, 'theme'> & { theme?: PptistSlideThemePatch; viewport?: Partial<PptistDeckViewport>; templates?: SlideTemplate[] }",
1134
1646
  "PptistDeckPatch": "export interface PptistDeckPatch { title?: string; slides?: Slide[]; theme?: PptistSlideThemePatch; viewport?: Partial<PptistDeckViewport>; templates?: SlideTemplate[] }",