slotdeck 0.1.2 → 0.2.0
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 +86 -6
- package/dist/deck/alternatives.d.ts +34 -0
- package/dist/deck/alternatives.js +370 -0
- package/dist/deck/alternatives.js.map +1 -0
- package/dist/deck/design.d.ts +40 -0
- package/dist/deck/design.js +112 -0
- package/dist/deck/design.js.map +1 -0
- package/dist/deck/validate.d.ts +18 -0
- package/dist/deck/validate.js +38 -2
- package/dist/deck/validate.js.map +1 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +7 -0
- package/dist/node.js +29 -0
- package/dist/node.js.map +1 -1
- package/dist/plan/catalog.js +3 -1
- package/dist/plan/catalog.js.map +1 -1
- package/dist/plan/edit.js +6 -2
- package/dist/plan/edit.js.map +1 -1
- package/dist/plan/plan.d.ts +10 -0
- package/dist/plan/plan.js +8 -0
- package/dist/plan/plan.js.map +1 -1
- package/dist/plan/review.d.ts +43 -0
- package/dist/plan/review.js +141 -0
- package/dist/plan/review.js.map +1 -0
- package/dist/plan/write.d.ts +5 -0
- package/dist/plan/write.js +11 -4
- package/dist/plan/write.js.map +1 -1
- package/dist/preview/pagus.d.ts +30 -0
- package/dist/preview/pagus.js +45 -0
- package/dist/preview/pagus.js.map +1 -0
- package/dist/preview/patterns.d.ts +27 -0
- package/dist/preview/patterns.js +35 -0
- package/dist/preview/patterns.js.map +1 -0
- package/dist/preview/provider.d.ts +30 -0
- package/dist/preview/provider.js +11 -0
- package/dist/preview/provider.js.map +1 -0
- package/dist/render/render.d.ts +18 -1
- package/dist/render/render.js +28 -8
- package/dist/render/render.js.map +1 -1
- package/dist/render/repeat.d.ts +17 -2
- package/dist/render/repeat.js +150 -4
- package/dist/render/repeat.js.map +1 -1
- package/dist/render/text.d.ts +6 -0
- package/dist/render/text.js +24 -0
- package/dist/render/text.js.map +1 -1
- package/dist/template/budgets.d.ts +33 -0
- package/dist/template/budgets.js +38 -0
- package/dist/template/budgets.js.map +1 -0
- package/dist/template/change.d.ts +18 -1
- package/dist/template/change.js +33 -3
- package/dist/template/change.js.map +1 -1
- package/dist/template/check.d.ts +3 -0
- package/dist/template/check.js +53 -3
- package/dist/template/check.js.map +1 -1
- package/dist/template/derive.d.ts +54 -0
- package/dist/template/derive.js +402 -0
- package/dist/template/derive.js.map +1 -0
- package/dist/template/draft.d.ts +7 -0
- package/dist/template/draft.js +17 -1
- package/dist/template/draft.js.map +1 -1
- package/dist/template/instruct.js +11 -5
- package/dist/template/instruct.js.map +1 -1
- package/dist/template/manifest.d.ts +22 -0
- package/dist/template/manifest.js +17 -1
- package/dist/template/manifest.js.map +1 -1
- package/dist/template/sample.d.ts +17 -0
- package/dist/template/sample.js +27 -2
- package/dist/template/sample.js.map +1 -1
- package/dist/text/fontkit.d.ts +18 -0
- package/dist/text/fontkit.js +91 -0
- package/dist/text/fontkit.js.map +1 -0
- package/dist/text/fonts.d.ts +45 -0
- package/dist/text/fonts.js +59 -0
- package/dist/text/fonts.js.map +1 -0
- package/dist/text/layout.d.ts +12 -0
- package/dist/text/layout.js +104 -0
- package/dist/text/layout.js.map +1 -0
- package/dist/text/measure.d.ts +85 -0
- package/dist/text/measure.js +369 -0
- package/dist/text/measure.js.map +1 -0
- package/dist/text/styles.d.ts +123 -0
- package/dist/text/styles.js +417 -0
- package/dist/text/styles.js.map +1 -0
- package/dist/tools.d.ts +12 -0
- package/dist/tools.js +32 -6
- package/dist/tools.js.map +1 -1
- package/docs/README.md +15 -5
- package/docs/api-reference.md +278 -8
- package/docs/changelog.md +135 -0
- package/docs/chat-tools.md +22 -5
- package/docs/deck-format.md +6 -0
- package/docs/design-checks.md +216 -0
- package/docs/generating.md +4 -1
- package/docs/layout-freedom.md +255 -3
- package/docs/manifest-format.md +19 -3
- package/docs/preview.md +217 -0
- package/docs/providers.md +1 -1
- package/docs/rendering.md +8 -0
- package/docs/template-studio.md +110 -11
- package/docs/text-fit.md +456 -0
- package/docs/troubleshooting.md +13 -2
- package/package.json +7 -1
package/docs/changelog.md
CHANGED
|
@@ -3,6 +3,141 @@
|
|
|
3
3
|
What changed in each version, newest first, with what to do when upgrading. The version you have installed is
|
|
4
4
|
in `node_modules/slotdeck/package.json`.
|
|
5
5
|
|
|
6
|
+
## 0.2.0
|
|
7
|
+
|
|
8
|
+
Two groups of additions. The first is about seeing and checking a deck: text measured with the template's
|
|
9
|
+
fonts, pictures of slides without PowerPoint, and design checks. The second is about more layouts from the
|
|
10
|
+
same template: variants the studio derives by itself, rows that fill their line, and other layouts for a
|
|
11
|
+
slide. Everything new is off until it is asked for.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Text is measured with the template's fonts.** Load a template with font metrics
|
|
16
|
+
(`loadTemplate(pptx, manifest, { fonts })`) and text is broken into lines at each slot's typeface and size,
|
|
17
|
+
the way PowerPoint sets it. Validation and `renderDeck` then warn by the lines a text runs over
|
|
18
|
+
(`text takes 7 lines at 18 pt; the box holds 5 (2 lines too many). Text of about 290 characters fits.`), and
|
|
19
|
+
the planner sends a draft back to the model with that sentence. On the demo template every line broke at
|
|
20
|
+
the same word as in PowerPoint in all 1,153 text slots checked at the designed sizes, in English and in
|
|
21
|
+
Hebrew, and 699 of 700 slots had PowerPoint's line count with every font size halved. See
|
|
22
|
+
[text-fit.md](text-fit.md).
|
|
23
|
+
- **`fontkitMetrics(fontkit, files)`** builds the metrics from font files with the `fontkit` library, which
|
|
24
|
+
you install yourself: slotdeck does not depend on it. `FontMetrics` is the small interface behind it, for
|
|
25
|
+
using another library.
|
|
26
|
+
- **`templateFonts(template)`** lists the typefaces, weights and slants a template's text is set in, and
|
|
27
|
+
**`fontFiles(fontkit, folder, typefaces)`** from `slotdeck/node` finds their files in a font folder.
|
|
28
|
+
- **Shrinking text to fit.** `shrinkText: { to: 0.85, minSize: 10 }` on the manifest lets text that does not
|
|
29
|
+
fit be set smaller, in half points, down to the stated limit. `renderDeck` returns what it shrank in `shrunk`.
|
|
30
|
+
- **`textMeasurer(template)`** measures any text in any text slot: lines, capacity, overflow, the lines
|
|
31
|
+
themselves. `validateDeck` takes it as the `measure` option.
|
|
32
|
+
- **`measuredBudgets(template)`** says how many characters each text slot's box really holds and suggests a
|
|
33
|
+
budget, to set with `changeManifest`.
|
|
34
|
+
- **`checkManifest`** tries every text budget out when the template has fonts, and warns about a budget that
|
|
35
|
+
lets text run over its box. It also names typefaces that were not supplied.
|
|
36
|
+
- **`sampleDeck(template, { fit: 'box' })`** fills every text slot to what its box holds by measurement.
|
|
37
|
+
- **Slide previews.** `PreviewProvider` is a new interface for a renderer that turns a pptx into one picture
|
|
38
|
+
for each slide. slotdeck draws nothing itself and depends on no renderer. `pagusPreviews(core, renderer)` is
|
|
39
|
+
an adapter for the Pagus library, which you install yourself; it gives SVG for a browser to show, with
|
|
40
|
+
Hebrew and Arabic paragraphs marked right to left. `previewDeck` renders a deck and draws it,
|
|
41
|
+
`patternPreviews` makes a thumbnail for every pattern of a template, and `presentationTools` takes a
|
|
42
|
+
`preview` option: the pictures of every presentation it makes go to the store under `preview/<id>/` and to
|
|
43
|
+
the app in `ToolResult.previews`. No renderer tried reproduces PowerPoint exactly; what was found, for
|
|
44
|
+
English, Hebrew, tables and native charts, is in [preview.md](preview.md).
|
|
45
|
+
- **Design checks.** `checkDesign(template, deck)` lists problems of a deck that fits and still looks wrong,
|
|
46
|
+
from measurement alone: a box left almost empty, a card far shorter than its neighbours, a heading that ends
|
|
47
|
+
with one word on a line of its own. Every message says what length of text would put it right. See
|
|
48
|
+
[design-checks.md](design-checks.md).
|
|
49
|
+
- **Reviews.** The planner takes a `review` option: a second look at every draft, whose findings go back to
|
|
50
|
+
the writing model in the repair rounds. `designReview(template)` is the design checks as a review.
|
|
51
|
+
`visionReview({ template, llm, preview })` shows a model pictures of the slides; it needs a preview provider
|
|
52
|
+
that gives bitmap pictures, and it has been tested with a scripted model only, not run against a live one.
|
|
53
|
+
Nothing reviews a draft unless `review` is set. `presentationTools` takes the same option.
|
|
54
|
+
- **Variants the studio derives by itself.** A new `changeManifest` operation,
|
|
55
|
+
`{ op: 'derivePattern', pattern, variant }`, makes a second pattern from a pattern's slide and works out every
|
|
56
|
+
position and budget from the shapes of the slide. Variants: `mirror` (the picture and what sits beside it
|
|
57
|
+
change sides, including a photo that runs off the edge of the slide), `text-only` (the picture is left out
|
|
58
|
+
and the text widens over the room it leaves) and `without` (an optional text named in `slot` is left out and
|
|
59
|
+
what sits under it moves up). A variant the slide does not allow is refused with the reason. See "Variants
|
|
60
|
+
the code works out" in [layout-freedom.md](layout-freedom.md) and `derivePattern` in
|
|
61
|
+
[template-studio.md](template-studio.md).
|
|
62
|
+
- **`editManifest` understands requests for a variant**, such as "add a mirrored version of the photo slides".
|
|
63
|
+
The model names the variant; it still never sets a position.
|
|
64
|
+
- **`patternVariants(template, pattern)`** lists the variants a pattern allows, with the reason for each one it
|
|
65
|
+
does not, for a studio screen that offers them as buttons. `VARIANTS` is the list of variant names.
|
|
66
|
+
- **`variants` on `draftManifest`** adds the mirror image and the text-only version of every drafted pattern
|
|
67
|
+
that allows one. Off by default: see "Variants in a draft" in [template-studio.md](template-studio.md).
|
|
68
|
+
- **A slot can show a part of the design in another place.** A slot with `"empty": "keep"` and a `box` keeps
|
|
69
|
+
its shape's content and puts the shape at the box, and may point at any shape that is not inside a group,
|
|
70
|
+
a group as a whole included. `derivePattern` adds such slots (`moved1`, `moved2`, ...) for the shapes of a
|
|
71
|
+
variant that are not slots. See [manifest-format.md](manifest-format.md).
|
|
72
|
+
- **The demo template has mirrored photo patterns**: `text-and-photo-mirrored`, `photo-stat-mirrored` and
|
|
73
|
+
`list-with-photo-mirrored`, made with the new operation.
|
|
74
|
+
- **Rows that fill their line.** `widen` on a `repeat` lets the items of a row or grid grow wider when a line
|
|
75
|
+
holds fewer of them than the template draws, up to the factor given (`"widen": 1.5`), so that two or three
|
|
76
|
+
cards fill a row drawn for four. Backgrounds and text boxes widen; icons, pictures and circles keep their
|
|
77
|
+
size and their side of the item, also inside a group. The character budgets of the row's texts grow with
|
|
78
|
+
the items, in validation, in what the planner shows the model, and in `sampleDeck`. Set it by hand or with
|
|
79
|
+
`changeManifest(template, [{ op: 'setRepeat', pattern: '<id>', widen: 1.5 }])`; `editManifest` understands
|
|
80
|
+
requests such as "let two cards fill the row". See "Fewer items that fill the row" in
|
|
81
|
+
[layout-freedom.md](layout-freedom.md).
|
|
82
|
+
- **The demo template's `icon-cards` and `stat-cards` use `widen`**, so the example decks with three cards
|
|
83
|
+
or four figures fill their rows.
|
|
84
|
+
- **`slideAlternatives(manifest, deck, slide)`** lists the other patterns that can hold what one slide of a deck
|
|
85
|
+
says and returns the slide written for each: a row of cards as a list or as columns, a slide as its mirror
|
|
86
|
+
image, a list as paragraphs. Code only: no model call, and no word is changed. A photo or an icon the new
|
|
87
|
+
pattern has no place for is reported, and so is a text that is over its new budget. The chat tools do not
|
|
88
|
+
offer it yet. See "Another layout for the same slide" in [layout-freedom.md](layout-freedom.md).
|
|
89
|
+
|
|
90
|
+
- **Measuring follows the layout.** With fonts, the text of a row that widens its items is measured in the
|
|
91
|
+
box the renderer gives it at the slide's number of items, so validation, shrinking and the design checks
|
|
92
|
+
agree with the slide: text that fits two wide cards is accepted there and reported in four narrow ones. On
|
|
93
|
+
the demo template all 22 texts in widened cards and figures broke where PowerPoint broke them, in English
|
|
94
|
+
and in Hebrew. `checkManifest` tries the larger budgets of such a row in the wider boxes, and
|
|
95
|
+
`sampleDeck(template, { fit: 'box', items: 'min' })` fills them. A mirrored pattern, whose boxes only move
|
|
96
|
+
their shapes, is checked for empty boxes against the template's own text like the pattern it mirrors.
|
|
97
|
+
|
|
98
|
+
### Changed
|
|
99
|
+
|
|
100
|
+
- `renderDeck` returns `shrunk` next to `pptx` and `warnings`. It is an empty array unless the manifest has
|
|
101
|
+
`shrinkText` and the template has fonts.
|
|
102
|
+
- `loadTemplate` takes a third, optional argument. `Template` has an optional `fonts` field.
|
|
103
|
+
- `storeKeys` has a `preview` key builder. With a `preview` provider the outputs of `create_presentation`
|
|
104
|
+
and `edit_presentation` gain `previews`, or `preview_error` when the pictures could not be made.
|
|
105
|
+
- **A slot with `"empty": "keep"` and a `box` now moves its shape.** Before, the `box` of such a slot was
|
|
106
|
+
ignored unless a deck gave the slot a value. `checkManifest` no longer reports that such a slot points at a
|
|
107
|
+
shape of another kind, or that it has no character budget.
|
|
108
|
+
|
|
109
|
+
### Upgrading from 0.1.2
|
|
110
|
+
|
|
111
|
+
- A dependency range written for 0.1, such as `"slotdeck": "^0.1.2"`, does not take 0.2.0. Install it by
|
|
112
|
+
version: `npm install slotdeck@0.2.0`. The package itself has no new dependency; `fontkit` and the Pagus
|
|
113
|
+
packages are installed only by an app that wants measuring or previews.
|
|
114
|
+
- Nothing has to change. With a manifest made before and a template loaded without fonts, every result is the
|
|
115
|
+
same as in 0.1.2: character budgets, the same warnings, the same files. There is one exception: a manifest
|
|
116
|
+
that already had a slot with both `"empty": "keep"` and a `box` now shows that shape at the box. Remove the
|
|
117
|
+
`box` to keep the shape where the template drew it.
|
|
118
|
+
- To turn measuring on: `npm install fontkit`, build metrics with `fontkitMetrics`, and pass them to
|
|
119
|
+
`loadTemplate`. Code that builds a `Template` object by hand (`{ pkg, manifest }`) keeps working; add
|
|
120
|
+
`fonts` to it to measure.
|
|
121
|
+
- Once a template has fonts, a text longer than its `maxChars` that fits its box is no longer reported, and a
|
|
122
|
+
text within `maxChars` that does not fit is. Code that looks for the words `characters; the slot fits` in a
|
|
123
|
+
warning should also expect `lines`.
|
|
124
|
+
- Previews are off unless you pass a `preview` provider. To turn them on with Pagus:
|
|
125
|
+
`npm install @pagus-kit/core @pagus-kit/renderer` and `pagusPreviews(pagusCore, pagusRenderer)`.
|
|
126
|
+
- Design checks and reviews are off unless you call `checkDesign` or pass `review`. A review can make the
|
|
127
|
+
planner use more writing calls, since a draft within its limits may now be sent back.
|
|
128
|
+
- Budgets drafted without fonts are cautious. `measuredBudgets` usually suggests larger ones; setting them
|
|
129
|
+
lets the planning model write more per slide.
|
|
130
|
+
- To get mirrored layouts from your own template, run
|
|
131
|
+
`changeManifest(template, [{ op: 'derivePattern', pattern: '<id>', variant: 'mirror' }])` for each pattern with
|
|
132
|
+
a picture beside its text, render `sampleDeck` to look at the result, and store the new manifest.
|
|
133
|
+
`patternVariants(template, '<id>')` says which patterns allow it.
|
|
134
|
+
- A planner that is offered a pattern and its mirror image chooses between them by their descriptions. Give
|
|
135
|
+
each a description that says where the picture is.
|
|
136
|
+
- Rows and grids keep the size of their items unless the manifest opts in with `widen`, and decks made from
|
|
137
|
+
a manifest without it render byte for byte as before. After opting in, a slide with fewer items than drawn
|
|
138
|
+
looks different (its items are wider) and its text budgets are larger; text that fitted before still fits.
|
|
139
|
+
Render `sampleDeck(template, { items: 'min' })` to look at it before using the manifest.
|
|
140
|
+
|
|
6
141
|
## 0.1.2
|
|
7
142
|
|
|
8
143
|
### Added
|
package/docs/chat-tools.md
CHANGED
|
@@ -38,7 +38,9 @@ const tools = presentationTools({
|
|
|
38
38
|
layout: 'adaptive', // optional; default 'strict'
|
|
39
39
|
fields: { organizationDepartment: 'Acme | Operations' }, // optional deck-level values every deck gets
|
|
40
40
|
numberPatterns: 'from-brief', // optional
|
|
41
|
+
review, // optional DeckReview: a second look at every draft (design-checks.md)
|
|
41
42
|
thumbnail: (patternId) => `/static/thumbnails/${patternId}.png`, // optional address of a picture of each layout
|
|
43
|
+
preview, // optional PreviewProvider: draws every presentation the tools make
|
|
42
44
|
newId: (kind) => `${kind}_${crypto.randomUUID()}`, // optional; default is a short random id
|
|
43
45
|
onProgress: (event, tool) => console.log(tool, event.stage), // optional
|
|
44
46
|
});
|
|
@@ -141,6 +143,10 @@ Output:
|
|
|
141
143
|
|
|
142
144
|
`file` is the store key of the rendered pptx. `warnings` is present only when there are any.
|
|
143
145
|
|
|
146
|
+
With the `preview` option set, the output also has `"previews"`: the store keys of the pictures of the slides,
|
|
147
|
+
such as `["preview/deck_851fbb9677/slide-01.svg", ...]`. If the pictures could not be made, it has
|
|
148
|
+
`"preview_error"` with the reason instead, and the presentation is created all the same.
|
|
149
|
+
|
|
144
150
|
### `edit_presentation`
|
|
145
151
|
|
|
146
152
|
Arguments: `presentation_id` (string, required), `instruction` (string, required).
|
|
@@ -177,9 +183,10 @@ interface BlobStore {
|
|
|
177
183
|
| `deck/<id>.json` | A deck: all text, and for each picture its id and description | 4 KB |
|
|
178
184
|
| `asset/<id>` | One generated picture | tens of KB to 1 MB |
|
|
179
185
|
| `pptx/<id>.pptx` | The rendered file | hundreds of KB and up |
|
|
186
|
+
| `preview/<id>/slide-01.svg` | A picture of one slide, when the tools have a `preview` provider. The extension follows the provider: `svg`, `png` | tens of KB each |
|
|
180
187
|
|
|
181
|
-
`storeKeys.plan(id)`, `storeKeys.deck(id)`, `storeKeys.asset(id)
|
|
182
|
-
your app can read what the tools saved:
|
|
188
|
+
`storeKeys.plan(id)`, `storeKeys.deck(id)`, `storeKeys.asset(id)`, `storeKeys.pptx(id)` and
|
|
189
|
+
`storeKeys.preview(id, slide, extension)` build these keys, so your app can read what the tools saved:
|
|
183
190
|
|
|
184
191
|
```ts
|
|
185
192
|
const pptx = await store.get(storeKeys.pptx(presentationId)); // to serve a download later
|
|
@@ -219,9 +226,19 @@ const store: BlobStore = {
|
|
|
219
226
|
|
|
220
227
|
## Showing a plan visually
|
|
221
228
|
|
|
222
|
-
A plan lists a layout per slide. To show layouts as pictures,
|
|
223
|
-
|
|
224
|
-
|
|
229
|
+
A plan lists a layout per slide. To show layouts as pictures, make one picture for each pattern once, name it
|
|
230
|
+
after the pattern, and return its address from the `thumbnail` option. The address is passed through to the
|
|
231
|
+
chat model's output and is not fetched by slotdeck.
|
|
232
|
+
|
|
233
|
+
`patternPreviews(template, preview)` makes those pictures without PowerPoint, through a preview provider; see
|
|
234
|
+
[preview.md](preview.md). Pictures of the template's own slides from any other tool work as well.
|
|
235
|
+
|
|
236
|
+
## Showing a presentation
|
|
237
|
+
|
|
238
|
+
Set the `preview` option to a `PreviewProvider` and every presentation the tools create or change is drawn.
|
|
239
|
+
The pictures go to the store under `preview/<presentation id>/`, their keys are in the tool's output, and the
|
|
240
|
+
`ToolResult` carries the pictures themselves in `previews` for your app to show. How to get a provider, and how
|
|
241
|
+
close its pictures are to PowerPoint, is in [preview.md](preview.md).
|
|
225
242
|
|
|
226
243
|
## A complete loop
|
|
227
244
|
|
package/docs/deck-format.md
CHANGED
|
@@ -223,3 +223,9 @@ const issues = validateDeck(manifest, deck, { layout: 'adaptive', assets: ['phot
|
|
|
223
223
|
|
|
224
224
|
Errors make `renderDeck` throw. Warnings do not. Every message is listed in
|
|
225
225
|
[troubleshooting.md](troubleshooting.md).
|
|
226
|
+
|
|
227
|
+
## Another pattern for a slide
|
|
228
|
+
|
|
229
|
+
`slideAlternatives(manifest, deck, slideNumber)` lists the other patterns that can hold what a slide says, and
|
|
230
|
+
returns the slide written for each: cards as a list, a slide as its mirror image. It changes no words and
|
|
231
|
+
calls no model. See "Another layout for the same slide" in [layout-freedom.md](layout-freedom.md).
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Design checks and reviews
|
|
2
|
+
|
|
3
|
+
Validation (`validateDeck`) says whether a deck can be rendered and whether its text fits. This page is about
|
|
4
|
+
what comes after that: a deck that renders and fits can still look wrong. A body of two words in a box drawn
|
|
5
|
+
for a paragraph, one short card in a row of full ones, a title whose last word sits alone on a second line.
|
|
6
|
+
|
|
7
|
+
There are two tools:
|
|
8
|
+
|
|
9
|
+
- **`checkDesign`** finds such problems by measurement alone. No picture is made and no model is called.
|
|
10
|
+
- **A review** is a second look at each draft while a deck is being written. What it finds goes back to the
|
|
11
|
+
writing model in the same repair round as the limits the draft broke. A review can be the design checks, a
|
|
12
|
+
model that looks at pictures of the slides, or a function of your own. Nothing reviews a draft unless you ask.
|
|
13
|
+
|
|
14
|
+
Both need a template loaded with its fonts: see [text-fit.md](text-fit.md).
|
|
15
|
+
|
|
16
|
+
## `checkDesign(template, deck, options?)`
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { checkDesign } from 'slotdeck';
|
|
20
|
+
|
|
21
|
+
const problems = checkDesign(template, deck, { layout: 'adaptive' });
|
|
22
|
+
// [
|
|
23
|
+
// { severity: 'warning', slide: 1, slot: 'title', kind: 'orphan',
|
|
24
|
+
// message: 'the last of its 2 lines holds one word, "Share". Text of about 24 characters ends a line sooner; a few words more fill the line.' },
|
|
25
|
+
// ]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
It is synchronous and takes a fraction of a second for a deck. It throws when the template has no fonts.
|
|
29
|
+
|
|
30
|
+
### What it finds
|
|
31
|
+
|
|
32
|
+
| `kind` | Problem | Message |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| `overflow` | Text runs over its box. The same finding, with the same words, as the warning of `validateDeck` with fonts. | `text takes 7 lines at 18 pt; the box holds 5 (2 lines too many). Text of about 290 characters fits.` |
|
|
35
|
+
| `empty` | Text takes a third or less of the lines the template's own text takes in that box, so the box looks empty. | `text takes 1 line where the template's own text takes 5, so its box will look empty. Text of about 45 characters fills it as designed.` |
|
|
36
|
+
| `uneven` | In a row of cards, one card's text takes a third or less of the lines of its fullest neighbour. | `text takes 1 line where "card1Text" beside it takes 5, so the row will look uneven. Text of about 66 characters or more evens it out.` |
|
|
37
|
+
| `orphan` | A heading ends with one word on a line of its own. | `the last of its 2 lines holds one word, "Share". Text of about 24 characters ends a line sooner; a few words more fill the line.` |
|
|
38
|
+
|
|
39
|
+
Every message says what to do about it, with a length in characters. That is what the writing model can act
|
|
40
|
+
on, so a message can be sent to it as it is.
|
|
41
|
+
|
|
42
|
+
### The result
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
interface DesignIssue {
|
|
46
|
+
severity: 'warning';
|
|
47
|
+
slide: number; // 1-based
|
|
48
|
+
slot: string; // the slot name as the deck uses it
|
|
49
|
+
kind: 'overflow' | 'empty' | 'uneven' | 'orphan';
|
|
50
|
+
message: string;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
A `DesignIssue` is an `Issue` with a `kind`, so the list can be shown or stored together with the warnings of
|
|
55
|
+
`validateDeck` and `renderDeck`.
|
|
56
|
+
|
|
57
|
+
### Options
|
|
58
|
+
|
|
59
|
+
| Option | Default | Meaning |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| `layout` | `'strict'` | As for `renderDeck`: with `'adaptive'`, optional slots may be left out. |
|
|
62
|
+
| `kinds` | all four | Which problems to look for, e.g. `['empty', 'orphan']`. |
|
|
63
|
+
| `emptyBelow` | `1/3` | A text is `empty` when it takes this share or less of the lines the template's own text takes; a card is `uneven` at this share or less of its fullest neighbour. |
|
|
64
|
+
| `headingSize` | `20` | The font size in points from which a single paragraph counts as a heading, for `orphan`. |
|
|
65
|
+
|
|
66
|
+
### How each check decides
|
|
67
|
+
|
|
68
|
+
**`overflow`.** The measured text needs more height than its box gives. If the manifest has `shrinkText`, a
|
|
69
|
+
text that fits once it is set smaller is not reported.
|
|
70
|
+
|
|
71
|
+
**`empty`.** The reference is the template itself: the lines its own sample text takes in the slot. A slot is
|
|
72
|
+
looked at only when that is three lines or more, so a title or a one-line caption is never "empty". A slot that
|
|
73
|
+
the manifest resized (`box`, `fontSize`: a derived pattern) has no sample to compare with; its box is
|
|
74
|
+
then taken to be meant half full. A `box` that only moves the shape, as in a mirrored pattern, keeps the
|
|
75
|
+
comparison. In a row that widens its items, the reference is the item as drawn: a short text in a wide card
|
|
76
|
+
takes fewer lines, so it is reported sooner, with the length that fills the wider card. A slot fed by a deck field is not checked, because that text is the app's.
|
|
77
|
+
|
|
78
|
+
**`uneven`.** The slots of one kind across a row are compared: every card's text with every other card's text,
|
|
79
|
+
every heading with every heading. Rows come from the pattern's `repeat` or its `sequences`. A row is looked at
|
|
80
|
+
only when its fullest item takes three lines or more. Items whose text overflows are left out of the
|
|
81
|
+
comparison.
|
|
82
|
+
|
|
83
|
+
**`orphan`.** A text of one paragraph, set at `headingSize` or larger, on two lines or more, whose last line
|
|
84
|
+
is a single word no wider than two fifths of the widest line. An address (`name@example.org`, a web address)
|
|
85
|
+
on its own line is not reported: it is meant to stand there.
|
|
86
|
+
|
|
87
|
+
### What it does not see
|
|
88
|
+
|
|
89
|
+
- Tables, charts and pictures. Only text slots are measured.
|
|
90
|
+
- Slots set in a typeface that was not supplied. They are passed over (see `missingFonts` in
|
|
91
|
+
[text-fit.md](text-fit.md)).
|
|
92
|
+
- Anything that needs a picture to judge: colours, contrast, a photo that does not suit the text.
|
|
93
|
+
- Whether a line break looks good in the middle of a heading. Only the last line is looked at.
|
|
94
|
+
|
|
95
|
+
On this project's hand-written example deck the checks report two things, both real: the cover title ends with
|
|
96
|
+
"Share" on a second line, and the title of slide 4 with "trip". PowerPoint's own picture of the deck shows
|
|
97
|
+
both.
|
|
98
|
+
|
|
99
|
+
## Reviews: a second look while a deck is written
|
|
100
|
+
|
|
101
|
+
The planner writes a draft, validates it, and sends a draft that breaks the template's limits back to the
|
|
102
|
+
model (see "How planning works" in [generating.md](generating.md)). A review adds its own findings to that
|
|
103
|
+
round.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { designReview, planDeck } from 'slotdeck';
|
|
107
|
+
|
|
108
|
+
const { deck, warnings } = await planDeck(template, brief, {
|
|
109
|
+
llm,
|
|
110
|
+
review: designReview(template), // empty boxes, uneven cards, orphan words
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The `review` option is accepted wherever a deck is written: `planDeck`, `writeDeck`, `generateDeck`,
|
|
115
|
+
`planEdit`, `editDeck`, and `presentationTools`.
|
|
116
|
+
|
|
117
|
+
How it works:
|
|
118
|
+
|
|
119
|
+
1. After each draft, validation runs as always. If the draft has no errors, the review is called with it.
|
|
120
|
+
2. What validation and the review found on the slides just written goes back to the model, each as one line:
|
|
121
|
+
`- s3.title: the last of its 2 lines holds one word, ...`.
|
|
122
|
+
3. This repeats up to `maxRepairs` times (2 by default). A review therefore runs up to three times for a deck.
|
|
123
|
+
4. Whatever is still found after the last round is returned in `warnings`, next to the validation warnings.
|
|
124
|
+
|
|
125
|
+
A review can make the planner use more model calls: a draft that was within its limits may now be sent back.
|
|
126
|
+
With `designReview` the review itself costs nothing; each repair it causes is one writing call.
|
|
127
|
+
|
|
128
|
+
### `designReview(template, options?)`
|
|
129
|
+
|
|
130
|
+
The code-only checks as a review. It reports `empty`, `uneven` and `orphan`; `overflow` is left to validation,
|
|
131
|
+
which reports it anyway. `options` are those of `checkDesign`.
|
|
132
|
+
|
|
133
|
+
### A review of your own
|
|
134
|
+
|
|
135
|
+
A review is a function from a draft deck to problems:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import type { DeckReview, Issue } from 'slotdeck';
|
|
139
|
+
|
|
140
|
+
const review: DeckReview = async (deck, { signal }) => {
|
|
141
|
+
const problems: Issue[] = [];
|
|
142
|
+
deck.slides.forEach((slide, index) => {
|
|
143
|
+
if (typeof slide.slots.title === 'string' && slide.slots.title.endsWith(':')) {
|
|
144
|
+
problems.push({ severity: 'warning', slide: index + 1, slot: 'title', message: 'a title must not end with a colon' });
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
return problems;
|
|
148
|
+
};
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Each problem is an `Issue`: `severity`, a 1-based `slide`, a `slot` when it is about one, and a `message`
|
|
152
|
+
written for the model. A problem without a `slide`, or on a slide the model was not asked to write, is not
|
|
153
|
+
sent back; it is returned in `warnings` all the same.
|
|
154
|
+
|
|
155
|
+
### `visionReview(options)`: a model that looks at the slides
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { planDeck, visionReview } from 'slotdeck';
|
|
159
|
+
|
|
160
|
+
const review = visionReview({
|
|
161
|
+
template,
|
|
162
|
+
llm: visionModel, // an LlmProvider whose model can look at pictures
|
|
163
|
+
preview, // a PreviewProvider that gives PNG or JPEG
|
|
164
|
+
icons, // optional: the app's icons and supplied pictures, drawn as they are
|
|
165
|
+
assets,
|
|
166
|
+
});
|
|
167
|
+
const { deck, warnings } = await planDeck(template, brief, { llm, review });
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
For each draft it:
|
|
171
|
+
|
|
172
|
+
1. renders the deck, with a plain grey rectangle for every picture that does not exist yet (photos are
|
|
173
|
+
generated after planning);
|
|
174
|
+
2. asks the preview provider for a picture of each slide;
|
|
175
|
+
3. shows the model the pictures, six slides to a request, with the text of each slide's slots, and asks only
|
|
176
|
+
for what can be seen and fixed by changing text: text cut off or lying over something, text too small to
|
|
177
|
+
read, a box or slide left mostly empty, a heading that ends in a lone word;
|
|
178
|
+
4. returns what the model reports, each as `seen in the picture of the slide: ...`, with the slot when the
|
|
179
|
+
model named one that the slide has.
|
|
180
|
+
|
|
181
|
+
| Option | Default | Meaning |
|
|
182
|
+
| --- | --- | --- |
|
|
183
|
+
| `template` | required | The template the deck is made from. |
|
|
184
|
+
| `llm` | required | A provider whose model accepts pictures (`JsonRequest.images`). It can be another model than the one that writes. |
|
|
185
|
+
| `preview` | required | Draws the draft. It must give bitmap pictures: PNG, JPEG, WebP or GIF. |
|
|
186
|
+
| `icons`, `assets` | none | Pictures the deck may use, drawn as they are instead of as rectangles. |
|
|
187
|
+
| `layout` | `'adaptive'` | As for `renderDeck`. |
|
|
188
|
+
| `slidesPerRequest` | `6` | How many slides are shown to the model in one request. |
|
|
189
|
+
|
|
190
|
+
Each request is capped at 300 output tokens plus 200 for each slide in it. A draft that cannot be rendered is
|
|
191
|
+
not looked at: its errors are validation's to report.
|
|
192
|
+
|
|
193
|
+
**Read this before turning it on.**
|
|
194
|
+
|
|
195
|
+
- **It is only as good as the pictures.** A model that is shown a preview which differs from PowerPoint will
|
|
196
|
+
report problems that are not there. The Pagus adapter that comes with slotdeck gives SVG, which a model
|
|
197
|
+
cannot read, and `visionReview` refuses it with an error. Use a provider whose pictures can be trusted, such
|
|
198
|
+
as PowerPoint's own export on a machine that has it. See "How close the pictures are" in
|
|
199
|
+
[preview.md](preview.md).
|
|
200
|
+
- **It has not been run against a live model, or against faithful pictures.** It was built and tested with a
|
|
201
|
+
scripted model and made-up pictures: what is sent, how the answer is read, how it takes part in the repair
|
|
202
|
+
round. How well a real model judges real slides with this prompt is not known. Try it on your own decks
|
|
203
|
+
before relying on it.
|
|
204
|
+
- **It costs model calls with pictures:** one request for every six slides, for every draft, so up to three
|
|
205
|
+
times a deck with the default `maxRepairs`.
|
|
206
|
+
- The code-only checks already cover overflow, empty boxes, uneven cards and orphan words, exactly and at no
|
|
207
|
+
cost. A vision review is for what measurement cannot see.
|
|
208
|
+
|
|
209
|
+
### Reviews in the chat tools
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
const tools = presentationTools({ template, llm, store, review: designReview(template) });
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The review then runs for every deck `create_presentation` writes and for the slides `edit_presentation`
|
|
216
|
+
rewrites. What it leaves unfixed is in the tool's `warnings`.
|
package/docs/generating.md
CHANGED
|
@@ -50,6 +50,7 @@ It runs `planDeck`, then `resolveAssets`, then `renderDeck`.
|
|
|
50
50
|
| `patterns` | string[] | all | Restrict the deck to these pattern ids. |
|
|
51
51
|
| `numberPatterns` | `"from-brief"`, `"always"`, `"never"` | `from-brief` | When patterns marked `figures` may be used. `from-brief` offers them only if the brief contains digits. |
|
|
52
52
|
| `maxRepairs` | number | 2 | How many times a draft that breaks the template's limits is sent back to the model. |
|
|
53
|
+
| `review` | `DeckReview` | none | A second look at every draft: design checks, a model that looks at pictures of the slides, or a function of your own. What it finds goes back to the model in the repair rounds. See [design-checks.md](design-checks.md). |
|
|
53
54
|
| `cache` | `Map<string, Uint8Array>` | none | Generated pictures by asset id. Pass the same map on later calls and pictures whose description did not change are reused. |
|
|
54
55
|
| `imageConcurrency` | number | 3 | How many pictures to generate at once. |
|
|
55
56
|
| `onProgress` | function | none | Called with `{ stage: 'outline' }`, `{ stage: 'write', slides }`, `{ stage: 'repair', attempt, issues }`, `{ stage: 'images', done, total }`, `{ stage: 'render' }`. |
|
|
@@ -88,7 +89,9 @@ const { pptx, deck, warnings } = await generateDeck(
|
|
|
88
89
|
2. **Write** (one model call). The model fills a JSON schema built for exactly that sequence of slides, so it
|
|
89
90
|
cannot invent patterns or slots.
|
|
90
91
|
3. **Repair** (up to `maxRepairs` more calls). The draft is validated against the manifest. Errors and
|
|
91
|
-
over-budget text go back to the model with the list of problems.
|
|
92
|
+
over-budget text go back to the model with the list of problems. For a template loaded with fonts the
|
|
93
|
+
text is measured, and the problems are stated in lines ([text-fit.md](text-fit.md)). With a `review`, what
|
|
94
|
+
the review finds on a draft goes back in the same list ([design-checks.md](design-checks.md)).
|
|
92
95
|
|
|
93
96
|
Which patterns are offered depends on what you supplied:
|
|
94
97
|
|