slotdeck 0.1.1 → 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 +94 -8
- 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 +44 -6
- package/dist/deck/validate.js.map +1 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/llm/gemini.d.ts +4 -0
- package/dist/llm/gemini.js +43 -7
- package/dist/llm/gemini.js.map +1 -1
- package/dist/llm/provider.d.ts +12 -0
- package/dist/node.d.ts +7 -0
- package/dist/node.js +29 -0
- package/dist/node.js.map +1 -1
- package/dist/plan/catalog.d.ts +11 -1
- package/dist/plan/catalog.js +23 -8
- package/dist/plan/catalog.js.map +1 -1
- package/dist/plan/edit.js +14 -6
- package/dist/plan/edit.js.map +1 -1
- package/dist/plan/plan.d.ts +26 -2
- package/dist/plan/plan.js +58 -17
- 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 +13 -1
- package/dist/plan/write.js +40 -7
- 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 +32 -12
- 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 +19 -1
- package/dist/template/change.js +45 -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 +15 -7
- package/dist/template/instruct.js.map +1 -1
- package/dist/template/manifest.d.ts +38 -0
- package/dist/template/manifest.js +43 -1
- package/dist/template/manifest.js.map +1 -1
- package/dist/template/sample.d.ts +17 -0
- package/dist/template/sample.js +31 -5
- 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 +38 -6
- package/dist/tools.js.map +1 -1
- package/docs/README.md +16 -5
- package/docs/api-reference.md +291 -9
- package/docs/changelog.md +242 -0
- package/docs/chat-tools.md +26 -5
- package/docs/deck-format.md +6 -0
- package/docs/design-checks.md +216 -0
- package/docs/generating.md +43 -4
- package/docs/layout-freedom.md +278 -3
- package/docs/manifest-format.md +20 -3
- package/docs/preview.md +217 -0
- package/docs/providers.md +49 -4
- package/docs/rendering.md +8 -0
- package/docs/template-studio.md +121 -12
- package/docs/text-fit.md +456 -0
- package/docs/troubleshooting.md +21 -2
- package/package.json +7 -1
package/docs/api-reference.md
CHANGED
|
@@ -16,10 +16,11 @@ every field.
|
|
|
16
16
|
### `loadTemplate`
|
|
17
17
|
|
|
18
18
|
```ts
|
|
19
|
-
function loadTemplate(pptx: Uint8Array, manifest: TemplateManifest): Template;
|
|
19
|
+
function loadTemplate(pptx: Uint8Array, manifest: TemplateManifest, options?: TemplateOptions): Template;
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Unzips a template once. Reuse the result.
|
|
22
|
+
Unzips a template once. Reuse the result. `options.fonts` gives it font metrics, which turns on text measuring
|
|
23
|
+
everywhere the template is used (see "Measuring text" below).
|
|
23
24
|
|
|
24
25
|
### `renderDeck`
|
|
25
26
|
|
|
@@ -45,6 +46,26 @@ function extractAssets(template: Template, deck: DeckSpec, pptx: Uint8Array): Re
|
|
|
45
46
|
|
|
46
47
|
Reads a deck's pictures back from a pptx rendered from it, by asset id.
|
|
47
48
|
|
|
49
|
+
### `slideAlternatives`
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
function slideAlternatives(manifest: TemplateManifest, deck: DeckSpec, slide: number, options?: AlternativesOptions): SlideAlternative[];
|
|
53
|
+
|
|
54
|
+
interface AlternativesOptions { layout?: LayoutMode; patterns?: string[] }
|
|
55
|
+
interface SlideAlternative {
|
|
56
|
+
pattern: string; // a pattern that has a place for everything the slide says
|
|
57
|
+
description: string; // what that pattern is for
|
|
58
|
+
slide: SlideSpec; // the slide written for that pattern
|
|
59
|
+
changes: string[]; // what was done where the content was not copied slot for slot
|
|
60
|
+
dropped: string[]; // slots of the original whose photo or icon has no place
|
|
61
|
+
warnings: Issue[]; // what validateDeck says about the new slide
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The other patterns that can hold what slide number `slide` (from 1) of a deck says, with the slide written for
|
|
66
|
+
each. Synchronous, no model, no words changed. Throws a `RangeError` when the deck has no such slide. See
|
|
67
|
+
"Another layout for the same slide" in [layout-freedom.md](layout-freedom.md).
|
|
68
|
+
|
|
48
69
|
### `DeckValidationError`
|
|
49
70
|
|
|
50
71
|
```ts
|
|
@@ -66,13 +87,18 @@ Tell the kinds of slot value apart when walking a deck.
|
|
|
66
87
|
### Types
|
|
67
88
|
|
|
68
89
|
```ts
|
|
69
|
-
interface Template { pkg: PptxPackage; manifest: TemplateManifest }
|
|
90
|
+
interface Template { pkg: PptxPackage; manifest: TemplateManifest; fonts?: FontMetrics }
|
|
91
|
+
interface TemplateOptions { fonts?: FontMetrics }
|
|
70
92
|
|
|
71
93
|
interface RenderOptions { assets?: Record<string, Uint8Array>; layout?: LayoutMode }
|
|
72
|
-
interface RenderResult {
|
|
94
|
+
interface RenderResult {
|
|
95
|
+
pptx: Uint8Array;
|
|
96
|
+
warnings: Issue[];
|
|
97
|
+
shrunk: Array<{ slide: number; slot: string; size: number; scale: number }>; // texts set smaller to fit; empty without shrinkText
|
|
98
|
+
}
|
|
73
99
|
|
|
74
100
|
type LayoutMode = 'strict' | 'adaptive';
|
|
75
|
-
interface ValidateOptions { layout?: LayoutMode; assets?: Iterable<string
|
|
101
|
+
interface ValidateOptions { layout?: LayoutMode; assets?: Iterable<string>; measure?: TextMeasurer }
|
|
76
102
|
interface Issue { severity: 'error' | 'warning'; slide?: number; slot?: string; message: string }
|
|
77
103
|
|
|
78
104
|
interface DeckSpec {
|
|
@@ -172,6 +198,14 @@ function directionOf(language: string): Direction;
|
|
|
172
198
|
|
|
173
199
|
The reading direction of a BCP 47 language tag.
|
|
174
200
|
|
|
201
|
+
### `isPlainText`
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
function isPlainText(pattern: PatternDef): boolean;
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Whether a slide made from the pattern is running text and nothing else: the patterns a text-only deck may use.
|
|
208
|
+
|
|
175
209
|
### `PlanError`
|
|
176
210
|
|
|
177
211
|
```ts
|
|
@@ -199,6 +233,7 @@ interface Brief {
|
|
|
199
233
|
instructions?: string;
|
|
200
234
|
fields?: Record<string, string>;
|
|
201
235
|
textSize?: TextSize;
|
|
236
|
+
textOnly?: boolean; // every slide plain text: only the template's plain text patterns are offered
|
|
202
237
|
}
|
|
203
238
|
type ImageDensity = 'none' | 'low' | 'medium' | 'high';
|
|
204
239
|
|
|
@@ -210,6 +245,7 @@ interface PlanOptions {
|
|
|
210
245
|
patterns?: string[];
|
|
211
246
|
numberPatterns?: 'from-brief' | 'always' | 'never';
|
|
212
247
|
maxRepairs?: number;
|
|
248
|
+
review?: DeckReview; // a second look at every draft; see "Design checks and reviews"
|
|
213
249
|
onProgress?: (event: PlanProgress) => void;
|
|
214
250
|
signal?: AbortSignal;
|
|
215
251
|
}
|
|
@@ -287,6 +323,7 @@ const storeKeys: {
|
|
|
287
323
|
deck(id: string): string; // 'deck/<id>.json'
|
|
288
324
|
pptx(id: string): string; // 'pptx/<id>.pptx'
|
|
289
325
|
asset(id: string): string; // 'asset/<id>'
|
|
326
|
+
preview(id: string, slide: number, extension: string): string; // 'preview/<id>/slide-03.svg'
|
|
290
327
|
};
|
|
291
328
|
```
|
|
292
329
|
|
|
@@ -322,7 +359,9 @@ interface PresentationToolsOptions {
|
|
|
322
359
|
layout?: LayoutMode;
|
|
323
360
|
fields?: Record<string, string>;
|
|
324
361
|
numberPatterns?: 'from-brief' | 'always' | 'never';
|
|
362
|
+
review?: DeckReview; // a second look at every draft the tools write
|
|
325
363
|
thumbnail?: (patternId: string) => string | undefined;
|
|
364
|
+
preview?: PreviewProvider; // draws every presentation the tools create or change
|
|
326
365
|
newId?: (kind: 'plan' | 'deck') => string;
|
|
327
366
|
onProgress?: (event: GenerateProgress, tool: string) => void;
|
|
328
367
|
}
|
|
@@ -331,7 +370,7 @@ interface PresentationTools {
|
|
|
331
370
|
call(name: string, args: unknown, context?: { signal?: AbortSignal }): Promise<ToolResult>;
|
|
332
371
|
}
|
|
333
372
|
interface ToolDefinition { name: string; description: string; parameters: JsonSchema }
|
|
334
|
-
interface ToolResult { output: Record<string, unknown>; plan?: DeckPlan; deck?: DeckSpec; pptx?: Uint8Array }
|
|
373
|
+
interface ToolResult { output: Record<string, unknown>; plan?: DeckPlan; deck?: DeckSpec; pptx?: Uint8Array; previews?: SlidePreview[] }
|
|
335
374
|
```
|
|
336
375
|
|
|
337
376
|
## Providers
|
|
@@ -366,6 +405,8 @@ interface JsonRequest {
|
|
|
366
405
|
system: string;
|
|
367
406
|
prompt: string;
|
|
368
407
|
schema: JsonSchema;
|
|
408
|
+
maxOutputTokens?: number; // a ceiling on the answer's size, reasoning not counted; pass it on as an output limit
|
|
409
|
+
effort?: 'low'; // a short structural request: use light reasoning if the model has a setting for it
|
|
369
410
|
images?: Array<{ mimeType: string; data: Uint8Array }>;
|
|
370
411
|
signal?: AbortSignal;
|
|
371
412
|
}
|
|
@@ -428,6 +469,17 @@ function changeManifest(template: Template, changes: ManifestChange[]): ChangeRe
|
|
|
428
469
|
function editManifest(template: Template, instruction: string, options: ManifestEditOptions): Promise<ManifestEditResult>;
|
|
429
470
|
```
|
|
430
471
|
|
|
472
|
+
### `patternVariants`, `VARIANTS`
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
function patternVariants(template: Template, pattern: string): VariantOption[];
|
|
476
|
+
const VARIANTS: readonly ['mirror', 'text-only', 'without'];
|
|
477
|
+
type PatternVariant = (typeof VARIANTS)[number];
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
The variants of a pattern that `changeManifest` can derive with `{ op: 'derivePattern' }`, each with whether
|
|
481
|
+
the pattern's slide allows it. See [template-studio.md](template-studio.md).
|
|
482
|
+
|
|
431
483
|
### `describeManifest`, `describeSlot`
|
|
432
484
|
|
|
433
485
|
```ts
|
|
@@ -482,6 +534,7 @@ interface DraftOptions {
|
|
|
482
534
|
name?: string;
|
|
483
535
|
slideImage?: (slide: number) => SlidePicture | undefined | Promise<SlidePicture | undefined>;
|
|
484
536
|
slides?: number[];
|
|
537
|
+
variants?: Array<'mirror' | 'text-only'>; // also add these variants of every pattern that allows them
|
|
485
538
|
concurrency?: number;
|
|
486
539
|
onProgress?: (event: { done: number; total: number; slide: number }) => void;
|
|
487
540
|
signal?: AbortSignal;
|
|
@@ -489,18 +542,19 @@ interface DraftOptions {
|
|
|
489
542
|
interface DraftResult { manifest: TemplateManifest; skipped: Array<{ slide: number; reason: string }>; issues: ManifestIssue[] }
|
|
490
543
|
|
|
491
544
|
interface ManifestIssue { severity: 'error' | 'warning'; pattern?: string; slot?: string; message: string }
|
|
492
|
-
interface SampleOptions { fill?: number; items?: 'drawn' | 'max' | 'min' }
|
|
545
|
+
interface SampleOptions { fill?: number; items?: 'drawn' | 'max' | 'min'; fit?: 'budget' | 'box' }
|
|
493
546
|
|
|
494
547
|
type ManifestChange =
|
|
495
|
-
| { op: 'setManifest'; name?: string; language?: string; direction?: Direction; alignOnDirectionChange?: AlignPolicy }
|
|
548
|
+
| { op: 'setManifest'; name?: string; language?: string; direction?: Direction; alignOnDirectionChange?: AlignPolicy; textScale?: number | null }
|
|
496
549
|
| { op: 'addPattern'; slide: number; id: string; description?: string }
|
|
497
550
|
| { op: 'copyPattern'; pattern: string; id: string; description?: string }
|
|
551
|
+
| { op: 'derivePattern'; pattern: string; variant: PatternVariant; slot?: string; id?: string; description?: string }
|
|
498
552
|
| { op: 'removePattern'; pattern: string }
|
|
499
553
|
| { op: 'setPattern'; pattern: string; id?: string; description?: string; figures?: boolean }
|
|
500
554
|
| { op: 'addSlot'; pattern: string; shape: string; role: Role; name?: string; optional?: boolean }
|
|
501
555
|
| { op: 'removeSlot'; pattern: string; slot: string }
|
|
502
556
|
| ({ op: 'setSlot'; pattern: string; slot: string } & SlotPatch)
|
|
503
|
-
| { op: 'setRepeat'; pattern: string; min?: number; max?: number; item?: string; span?: { left: number; right: number } | null }
|
|
557
|
+
| { op: 'setRepeat'; pattern: string; min?: number; max?: number; item?: string; span?: { left: number; right: number } | null; widen?: number | null }
|
|
504
558
|
| { op: 'removeRepeat'; pattern: string };
|
|
505
559
|
|
|
506
560
|
interface SlotPatch {
|
|
@@ -536,6 +590,7 @@ interface ChangeResult {
|
|
|
536
590
|
rejected: Array<{ index: number; change: ManifestChange; reason: string }>;
|
|
537
591
|
issues: ManifestIssue[];
|
|
538
592
|
}
|
|
593
|
+
interface VariantOption { variant: PatternVariant; slot?: string; available: boolean; note: string }
|
|
539
594
|
interface ManifestEditOptions { llm: LlmProvider; signal?: AbortSignal }
|
|
540
595
|
interface ManifestEditResult extends ChangeResult { note: string }
|
|
541
596
|
|
|
@@ -571,6 +626,230 @@ interface SlideInfo { number: number; part: string; layout: string; shapes: Shap
|
|
|
571
626
|
interface TemplateInfo { slideWidth: number; slideHeight: number; defaultFontSize: number; slides: SlideInfo[] }
|
|
572
627
|
```
|
|
573
628
|
|
|
629
|
+
## Design checks and reviews
|
|
630
|
+
|
|
631
|
+
Explained in [design-checks.md](design-checks.md). Both need a template loaded with fonts.
|
|
632
|
+
|
|
633
|
+
### `checkDesign`
|
|
634
|
+
|
|
635
|
+
```ts
|
|
636
|
+
function checkDesign(template: Template, deck: DeckSpec, options?: DesignOptions): DesignIssue[];
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
Lists design problems that follow from measurement alone: text that runs over its box, boxes and cards left
|
|
640
|
+
mostly empty, headings that end in a lone word. Synchronous, no model, no picture.
|
|
641
|
+
|
|
642
|
+
### `designReview`
|
|
643
|
+
|
|
644
|
+
```ts
|
|
645
|
+
function designReview(template: Template, options?: DesignOptions): DeckReview;
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
The design checks as a review for the planner's `review` option. Reports `empty`, `uneven` and `orphan`.
|
|
649
|
+
|
|
650
|
+
### `visionReview`
|
|
651
|
+
|
|
652
|
+
```ts
|
|
653
|
+
function visionReview(options: VisionReviewOptions): DeckReview;
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
A review by a model that looks at pictures of the draft's slides, drawn by a `PreviewProvider` that gives
|
|
657
|
+
bitmap pictures. Not run against a live model; see the cautions in [design-checks.md](design-checks.md).
|
|
658
|
+
|
|
659
|
+
### Types
|
|
660
|
+
|
|
661
|
+
```ts
|
|
662
|
+
type DesignKind = 'overflow' | 'empty' | 'uneven' | 'orphan';
|
|
663
|
+
interface DesignIssue { severity: 'warning'; slide: number; slot: string; kind: DesignKind; message: string } // an Issue with a kind
|
|
664
|
+
interface DesignOptions {
|
|
665
|
+
layout?: LayoutMode;
|
|
666
|
+
kinds?: DesignKind[]; // default: all four
|
|
667
|
+
emptyBelow?: number; // default 1/3
|
|
668
|
+
headingSize?: number; // points; default 20
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// A second look at a draft deck: problems to send back to the writing model.
|
|
672
|
+
type DeckReview = (deck: DeckSpec, context: { signal?: AbortSignal }) => Issue[] | Promise<Issue[]>;
|
|
673
|
+
|
|
674
|
+
interface VisionReviewOptions {
|
|
675
|
+
template: Template;
|
|
676
|
+
llm: LlmProvider; // a model that accepts pictures
|
|
677
|
+
preview: PreviewProvider; // must give PNG, JPEG, WebP or GIF
|
|
678
|
+
icons?: IconDef[];
|
|
679
|
+
assets?: AssetDef[];
|
|
680
|
+
layout?: LayoutMode; // default 'adaptive'
|
|
681
|
+
slidesPerRequest?: number; // default 6
|
|
682
|
+
}
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
## Slide previews
|
|
686
|
+
|
|
687
|
+
Explained in [preview.md](preview.md). slotdeck draws nothing itself: a `PreviewProvider` is a renderer you plug in.
|
|
688
|
+
|
|
689
|
+
### `pagusPreviews`
|
|
690
|
+
|
|
691
|
+
```ts
|
|
692
|
+
function pagusPreviews(core: PagusCore, renderer: PagusRenderer, options?: PagusOptions): PreviewProvider;
|
|
693
|
+
|
|
694
|
+
interface PagusCore { parse(data: ArrayBuffer): Promise<{ slides: readonly unknown[]; slideSize: unknown }> } // the `@pagus-kit/core` module
|
|
695
|
+
interface PagusRenderer { renderSlide(slide: never, slideSize: never, options?: never): { svg: string; width: number; height: number } } // the `@pagus-kit/renderer` module
|
|
696
|
+
interface PagusOptions { scale?: number; fontSubstitutes?: Record<string, string>; fontCss?: string }
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
A provider that draws slides with the Pagus library, which you install and pass in:
|
|
700
|
+
`pagusPreviews(pagusCore, pagusRenderer)` after `import * as pagusCore from '@pagus-kit/core'` and
|
|
701
|
+
`import * as pagusRenderer from '@pagus-kit/renderer'`. One SVG for each slide, with the text as real text for a
|
|
702
|
+
browser to set. Paragraphs that start with a right-to-left letter are marked as running right to left.
|
|
703
|
+
|
|
704
|
+
### `previewDeck`
|
|
705
|
+
|
|
706
|
+
```ts
|
|
707
|
+
function previewDeck(template: Template, deck: DeckSpec, preview: PreviewProvider, options?: PreviewDeckOptions): Promise<{ pptx: Uint8Array; previews: SlidePreview[] }>;
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
`renderDeck`, then the provider: the pptx and a picture of each of its slides.
|
|
711
|
+
|
|
712
|
+
### `patternPreviews`
|
|
713
|
+
|
|
714
|
+
```ts
|
|
715
|
+
function patternPreviews(template: Template, preview: PreviewProvider, options?: SampleOptions & { signal?: AbortSignal }): Promise<Record<string, SlidePreview>>;
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
A picture of every pattern, by pattern id: each pattern's slide of the template's sample deck.
|
|
719
|
+
|
|
720
|
+
### `previewExtension`
|
|
721
|
+
|
|
722
|
+
```ts
|
|
723
|
+
function previewExtension(preview: { mimeType: string }): string; // 'svg', 'png', 'jpg', ...
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
The file extension for a preview's type, for naming it in a store or on disk.
|
|
727
|
+
|
|
728
|
+
### Types
|
|
729
|
+
|
|
730
|
+
```ts
|
|
731
|
+
// What slotdeck needs from a slide renderer. Implement it to plug in any renderer.
|
|
732
|
+
interface PreviewProvider {
|
|
733
|
+
renderSlides(request: PreviewRequest): Promise<SlidePreview[]>; // one picture for each slide asked for, in slide order
|
|
734
|
+
}
|
|
735
|
+
interface PreviewRequest {
|
|
736
|
+
pptx: Uint8Array;
|
|
737
|
+
slides?: number[]; // 1-based; every slide when left out
|
|
738
|
+
signal?: AbortSignal;
|
|
739
|
+
}
|
|
740
|
+
interface SlidePreview {
|
|
741
|
+
slide: number; // 1-based
|
|
742
|
+
mimeType: string; // 'image/svg+xml', 'image/png'
|
|
743
|
+
data: Uint8Array; // SVG as UTF-8 text, or the bitmap's bytes
|
|
744
|
+
width?: number; // pixels
|
|
745
|
+
height?: number;
|
|
746
|
+
}
|
|
747
|
+
interface PreviewDeckOptions { assets?: Record<string, Uint8Array>; layout?: LayoutMode; signal?: AbortSignal }
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
## Measuring text
|
|
751
|
+
|
|
752
|
+
Explained in [text-fit.md](text-fit.md). All of it is optional: without fonts nothing here is used.
|
|
753
|
+
|
|
754
|
+
### `fontkitMetrics`
|
|
755
|
+
|
|
756
|
+
```ts
|
|
757
|
+
function fontkitMetrics(fontkit: FontkitModule, files: FontFiles): FontMetrics;
|
|
758
|
+
|
|
759
|
+
type FontFiles = Record<string, Uint8Array | Uint8Array[]>; // typeface name as the template states it -> its font files
|
|
760
|
+
interface FontkitModule { create(buffer: never, postscriptName?: string): unknown } // the `fontkit` module itself
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
Font metrics from font files, read with the `fontkit` library, which you install and pass in:
|
|
764
|
+
`fontkitMetrics(fontkit, { Calibri: [regularBytes, boldBytes] })` after `import * as fontkit from 'fontkit'`.
|
|
765
|
+
Reads TrueType, OpenType, collections, WOFF and WOFF2.
|
|
766
|
+
|
|
767
|
+
### `fontFiles` (from `slotdeck/node`)
|
|
768
|
+
|
|
769
|
+
```ts
|
|
770
|
+
function fontFiles(fontkit: FontkitModule, directory: string, typefaces: Iterable<string>): FontFiles;
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
Finds the font files of the given typefaces in a folder, such as the system's font folder, by the family name
|
|
774
|
+
each file states. Typefaces with no file there are left out.
|
|
775
|
+
|
|
776
|
+
### `templateFonts`
|
|
777
|
+
|
|
778
|
+
```ts
|
|
779
|
+
function templateFonts(template: Template, language?: string): TemplateFont[];
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
The typefaces a template's text slots are set in, with the weights and slants used: the font files to supply.
|
|
783
|
+
`language` (default: the manifest's) adds the typeface that text of that language is set in.
|
|
784
|
+
|
|
785
|
+
### `textMeasurer`
|
|
786
|
+
|
|
787
|
+
```ts
|
|
788
|
+
function textMeasurer(template: Template, fonts?: FontMetrics): TextMeasurer;
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
A measurer for a template. `fonts` defaults to the fonts the template was loaded with; it throws when there
|
|
792
|
+
are none. Pass the result to `validateDeck` as `measure`, or call `fit` yourself.
|
|
793
|
+
|
|
794
|
+
### `measuredBudgets`
|
|
795
|
+
|
|
796
|
+
```ts
|
|
797
|
+
function measuredBudgets(template: Template, options?: BudgetOptions): MeasuredBudget[];
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
How many characters each text slot's box holds, as measured, with a budget to set. The template must have
|
|
801
|
+
fonts.
|
|
802
|
+
|
|
803
|
+
### Types
|
|
804
|
+
|
|
805
|
+
```ts
|
|
806
|
+
// What slotdeck needs from a font library. Implement it to use a library other than fontkit.
|
|
807
|
+
interface FontMetrics {
|
|
808
|
+
face(typeface: string, style: FontStyle): FontFace | undefined; // undefined: the typeface was not supplied
|
|
809
|
+
fallback?(codePoint: number, style: FontStyle): FontFace | undefined; // a face for a character the chosen one lacks
|
|
810
|
+
}
|
|
811
|
+
interface FontStyle { bold: boolean; italic: boolean }
|
|
812
|
+
interface FontFace {
|
|
813
|
+
has(codePoint: number): boolean;
|
|
814
|
+
advances(text: string, kerning: boolean): number[]; // the advance of each glyph after shaping, in ems
|
|
815
|
+
substitute?: boolean; // stands in for a weight or slant that was not supplied
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
interface TemplateFont { typeface: string; bold: boolean; italic: boolean }
|
|
819
|
+
|
|
820
|
+
interface TextMeasurer {
|
|
821
|
+
fit(pattern: string | PatternDef, slot: string | TextSlotDef, text: string | string[], options?: FitOptions): TextFit | undefined;
|
|
822
|
+
missingFonts(): TemplateFont[];
|
|
823
|
+
}
|
|
824
|
+
interface FitOptions {
|
|
825
|
+
textScale?: number; // the factor on body text the deck is rendered with; default 1
|
|
826
|
+
shrink?: ShrinkLimit; // allow the text to be set smaller when it does not fit
|
|
827
|
+
items?: number; // for a slot of a row of items: how many items the slide has
|
|
828
|
+
}
|
|
829
|
+
interface ShrinkLimit { to: number; minSize?: number } // the shape of the manifest's shrinkText
|
|
830
|
+
interface TextFit {
|
|
831
|
+
fits: boolean;
|
|
832
|
+
lines: number; // lines the text takes
|
|
833
|
+
capacity: number; // lines of this text the box holds
|
|
834
|
+
overflow: number; // lines that do not fit
|
|
835
|
+
height: number; // points the text takes
|
|
836
|
+
room: number; // points the box gives
|
|
837
|
+
widthRatio: number; // for a box that does not wrap: longest line / box width
|
|
838
|
+
size: number; // font size of the first paragraph, in points
|
|
839
|
+
sizes: number[]; // font size of each paragraph
|
|
840
|
+
scale: number; // the factor the text was shrunk by; 1 when it was not
|
|
841
|
+
fitsChars: number; // about how many characters of such text the box holds
|
|
842
|
+
paragraphs: string[][]; // the lines of each paragraph
|
|
843
|
+
widths: number[][]; // the width of each of those lines, in points
|
|
844
|
+
lineRoom: number[]; // the width a line of each paragraph may take, in points
|
|
845
|
+
sampleLines: number; // lines the template's own sample text takes in the slot; 0 when there is none to compare with
|
|
846
|
+
approximate: boolean; // a typeface, weight or outline was stood in for
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
interface BudgetOptions { sample?: string; margin?: number } // margin defaults to 0.9
|
|
850
|
+
interface MeasuredBudget { pattern: string; slot: string; maxChars?: number; fits: number; suggested: number }
|
|
851
|
+
```
|
|
852
|
+
|
|
574
853
|
## Manifest types
|
|
575
854
|
|
|
576
855
|
Described field by field in [manifest-format.md](manifest-format.md).
|
|
@@ -589,6 +868,8 @@ interface TemplateManifest {
|
|
|
589
868
|
language?: string;
|
|
590
869
|
direction: Direction;
|
|
591
870
|
alignOnDirectionChange?: AlignPolicy;
|
|
871
|
+
textScale?: number; // enlarges body text in every deck made from the template
|
|
872
|
+
shrinkText?: { to: number; minSize?: number }; // lets text that does not fit be set smaller; needs fonts
|
|
592
873
|
patterns: PatternDef[];
|
|
593
874
|
}
|
|
594
875
|
interface PatternDef {
|
|
@@ -608,6 +889,7 @@ interface RepeatDef {
|
|
|
608
889
|
max?: number;
|
|
609
890
|
span?: { left: number; right: number };
|
|
610
891
|
columns?: number;
|
|
892
|
+
widen?: number; // fewer items on a line than drawn grow up to this factor to fill the row
|
|
611
893
|
}
|
|
612
894
|
type SlotDef = TextSlotDef | ImageSlotDef | TableSlotDef | ChartSlotDef;
|
|
613
895
|
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
What changed in each version, newest first, with what to do when upgrading. The version you have installed is
|
|
4
|
+
in `node_modules/slotdeck/package.json`.
|
|
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
|
+
|
|
141
|
+
## 0.1.2
|
|
142
|
+
|
|
143
|
+
### Added
|
|
144
|
+
|
|
145
|
+
- **Text-only decks.** `textOnly: true` on a brief, or `text_only: true` in the `plan_presentation` tool, plans
|
|
146
|
+
every slide as plain text: a title with paragraphs or a list, and no pictures, icons, cards, figures, tables
|
|
147
|
+
or charts. The planner is then offered only the template's plain text patterns, so no other kind can be
|
|
148
|
+
chosen. See "Asking for a kind of slide" in [generating.md](generating.md).
|
|
149
|
+
- **Wishes about the kind of slides are honoured.** A wish stated in words in the brief or in an edit
|
|
150
|
+
instruction ("text only", "no tables", "only cards") now decides which patterns may be used and comes before
|
|
151
|
+
variety. It works when planning, when changing a plan, and when changing a finished deck. The pattern list
|
|
152
|
+
the model reads marks each plain text pattern with "Plain text.".
|
|
153
|
+
- **`isPlainText(pattern)`** tells whether a pattern is plain text, for an app that wants to show or check
|
|
154
|
+
which layouts a text-only deck can use.
|
|
155
|
+
- **Larger body text for a whole template.** `textScale` on the manifest enlarges the body text of every deck
|
|
156
|
+
made from the template (`1.3` turns 9 pt into about 12 pt). Budgets shrink to match in validation, in what
|
|
157
|
+
the planner shows the model, and in `sampleDeck`. Set it by hand or with
|
|
158
|
+
`changeManifest(template, [{ op: 'setManifest', textScale: 1.3 }])`; `editManifest` understands requests such
|
|
159
|
+
as "make body text 20 percent larger". See "Larger text for a whole template" in
|
|
160
|
+
[layout-freedom.md](layout-freedom.md).
|
|
161
|
+
- **`maxOutputTokens` on requests to the model.** The planner passes a ceiling for each answer with every
|
|
162
|
+
request it makes. See "Runaway answers" in [providers.md](providers.md).
|
|
163
|
+
- **`effort: 'low'` on planning requests.** Calls that choose and arrange rather than write (the outline, a
|
|
164
|
+
change to a plan, the first step of an edit) ask for light reasoning.
|
|
165
|
+
|
|
166
|
+
### Changed
|
|
167
|
+
|
|
168
|
+
- **Table text and chart labels follow the text scale**, where the manifest states their size
|
|
169
|
+
(`bodyText.size`, `headerText.size`, `text.size`). This applies to a deck's own text size (`textScale`,
|
|
170
|
+
`textSize`, `text_size`) as well as to the new template scale, and a table cell then holds fewer characters.
|
|
171
|
+
Before, tables and charts kept their size when a deck asked for larger text.
|
|
172
|
+
- **The Gemini adapter limits the output of every request.** The limit is the request's estimate plus 8,192
|
|
173
|
+
tokens for reasoning, or 24,576 when the request has none, or the adapter's `maxOutputTokens` when set.
|
|
174
|
+
Before, a request had no limit unless `maxOutputTokens` was set.
|
|
175
|
+
- **The Gemini adapter sends a request once more** when the answer was cut off at the limit, after a server
|
|
176
|
+
error (500 to 504), and when the service's recitation filter blocks an ordinary answer. A bad key, a quota or
|
|
177
|
+
a bad request is not repeated.
|
|
178
|
+
- **The Gemini adapter uses thinking level `low` for requests with `effort: 'low'`**, unless `thinkingLevel`
|
|
179
|
+
is set on the adapter. Planning calls became several times faster: a plan takes about 5 seconds.
|
|
180
|
+
- The per-slide sentence of a plan is asked for as "a single sentence of at most 25 words".
|
|
181
|
+
|
|
182
|
+
### Fixed
|
|
183
|
+
|
|
184
|
+
- **A request for a text-only presentation gave cards and tables.** The planner was told to vary the layouts
|
|
185
|
+
and nothing said that a wish about the kind of slides comes first; and "no pictures" was the most that
|
|
186
|
+
reached it. Fixed by the two additions above.
|
|
187
|
+
- **A model call could hang for minutes.** With its default reasoning the model sometimes ran away inside one
|
|
188
|
+
text field of a planning answer and wrote tens of thousands of tokens. Measured on a text-only plan: 6 of 24
|
|
189
|
+
calls with default reasoning, none of 18 with light reasoning. Planning calls now use light reasoning, every
|
|
190
|
+
call has an output limit, and a cut-off answer is asked for once more.
|
|
191
|
+
|
|
192
|
+
### Upgrading from 0.1.1
|
|
193
|
+
|
|
194
|
+
No code has to change. To benefit:
|
|
195
|
+
|
|
196
|
+
- **Chat assistants:** `plan_presentation` has a new optional argument, `text_only`. It is in
|
|
197
|
+
`tools.definitions`, so it reaches the chat model when the definitions are passed as before. If your system
|
|
198
|
+
prompt lists the tool's arguments, add it, and tell the model that "no pictures" (`image_density: "none"`)
|
|
199
|
+
still allows cards, tables and charts.
|
|
200
|
+
- **Small body text:** if decks from your template have body text that is too small, add `"textScale": 1.3`
|
|
201
|
+
(or another factor) to the manifest, render `sampleDeck` once to see that everything still fits, and keep the
|
|
202
|
+
manifest. A manifest with `textScale` is ignored by 0.1.1 and earlier, which show the designed size.
|
|
203
|
+
- **Your own `LlmProvider`:** requests now carry two optional fields, `maxOutputTokens` and `effort`. A provider
|
|
204
|
+
that ignores them keeps working. To get the protection and the speed, pass `maxOutputTokens` on as your
|
|
205
|
+
model's output limit (adding room for reasoning tokens if your model counts them in the same limit), use
|
|
206
|
+
light reasoning when `effort` is `'low'`, and retry once when an answer is cut off. See "Runaway answers" in
|
|
207
|
+
[providers.md](providers.md).
|
|
208
|
+
- **Tables with larger text:** a deck that asks for larger text now enlarges table text too, where the
|
|
209
|
+
manifest states its size, and gives cells a smaller budget. A deck stored with `textScale` renders with
|
|
210
|
+
larger table text than before.
|
|
211
|
+
|
|
212
|
+
## 0.1.1
|
|
213
|
+
|
|
214
|
+
### Added
|
|
215
|
+
|
|
216
|
+
- **Documentation inside the package.** The `docs/` folder ships with the npm package
|
|
217
|
+
(`node_modules/slotdeck/docs/`), in plain Markdown with no links to the internet, so it can be read where
|
|
218
|
+
there is no network access. Start at [README.md](README.md).
|
|
219
|
+
|
|
220
|
+
### Changed
|
|
221
|
+
|
|
222
|
+
- **Unknown chart format.** `validateDeck` warns about a chart `format` other than `"number"` or `"percent"`
|
|
223
|
+
(`chart format "x" is not known and is ignored`). Before, it was ignored silently.
|
|
224
|
+
|
|
225
|
+
### Upgrading from 0.1.0
|
|
226
|
+
|
|
227
|
+
Nothing to change.
|
|
228
|
+
|
|
229
|
+
## 0.1.0
|
|
230
|
+
|
|
231
|
+
First release.
|
|
232
|
+
|
|
233
|
+
- **Renderer:** `loadTemplate`, `renderDeck`, `validateDeck`, `extractAssets`. Text, pictures, tables and
|
|
234
|
+
native charts; rows and grids with a variable number of items; larger text on request; derived patterns.
|
|
235
|
+
- **Planner and editor:** `generateDeck`, `planDeck`, `planOutline`, `editPlan`, `writeDeck`, `editDeck`,
|
|
236
|
+
`planEdit`, `resolveAssets`, with any model through `LlmProvider` and `ImageProvider`.
|
|
237
|
+
- **Chat tools:** `presentationTools` with `plan_presentation`, `edit_presentation_plan`,
|
|
238
|
+
`create_presentation` and `edit_presentation`, and stores (`memoryStore`, `directoryStore`).
|
|
239
|
+
- **Gemini adapters:** `gemini`, `geminiImages`, `vertexEndpoint`.
|
|
240
|
+
- **Reading direction:** right-to-left decks on left-to-right templates and the reverse.
|
|
241
|
+
- **Template studio:** `draftManifest`, `checkManifest`, `sampleDeck`, `changeManifest`, `editManifest`,
|
|
242
|
+
`studioView`, `describeManifest`, `inspectTemplate`.
|