@texuli/deck 0.0.0-stage → 0.4.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.
Files changed (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +182 -2
  3. package/dist/authoring/builder.d.ts +351 -0
  4. package/dist/authoring/builder.js +64 -0
  5. package/dist/authoring/index.d.ts +6 -0
  6. package/dist/authoring/index.js +6 -0
  7. package/dist/authoring/lint.d.ts +36 -0
  8. package/dist/authoring/lint.js +325 -0
  9. package/dist/authoring/outlines.d.ts +34 -0
  10. package/dist/authoring/outlines.js +255 -0
  11. package/dist/authoring/patch.d.ts +23 -0
  12. package/dist/authoring/patch.js +166 -0
  13. package/dist/authoring/select-layouts.d.ts +19 -0
  14. package/dist/authoring/select-layouts.js +90 -0
  15. package/dist/engine/auto-slide.d.ts +32 -0
  16. package/dist/engine/auto-slide.js +67 -0
  17. package/dist/engine/canvas.d.ts +56 -0
  18. package/dist/engine/canvas.js +48 -0
  19. package/dist/engine/controller.d.ts +126 -0
  20. package/dist/engine/controller.js +248 -0
  21. package/dist/engine/controls.d.ts +128 -0
  22. package/dist/engine/controls.js +460 -0
  23. package/dist/engine/hash.d.ts +42 -0
  24. package/dist/engine/hash.js +86 -0
  25. package/dist/engine/index.d.ts +88 -0
  26. package/dist/engine/index.js +88 -0
  27. package/dist/engine/messages.d.ts +138 -0
  28. package/dist/engine/messages.js +140 -0
  29. package/dist/engine/motion.d.ts +64 -0
  30. package/dist/engine/motion.js +112 -0
  31. package/dist/engine/navigation.d.ts +87 -0
  32. package/dist/engine/navigation.js +156 -0
  33. package/dist/engine/presenter.d.ts +58 -0
  34. package/dist/engine/presenter.js +157 -0
  35. package/dist/index.d.ts +9 -0
  36. package/dist/index.js +9 -0
  37. package/dist/markdown/attributes.d.ts +24 -0
  38. package/dist/markdown/attributes.js +94 -0
  39. package/dist/markdown/attrs-closed.d.ts +52 -0
  40. package/dist/markdown/attrs-closed.js +520 -0
  41. package/dist/markdown/blocks.d.ts +112 -0
  42. package/dist/markdown/blocks.js +766 -0
  43. package/dist/markdown/frontmatter.d.ts +30 -0
  44. package/dist/markdown/frontmatter.js +165 -0
  45. package/dist/markdown/index.d.ts +29 -0
  46. package/dist/markdown/index.js +29 -0
  47. package/dist/markdown/issues.d.ts +68 -0
  48. package/dist/markdown/issues.js +83 -0
  49. package/dist/markdown/json.d.ts +21 -0
  50. package/dist/markdown/json.js +236 -0
  51. package/dist/markdown/limits.d.ts +32 -0
  52. package/dist/markdown/limits.js +32 -0
  53. package/dist/markdown/parse.d.ts +31 -0
  54. package/dist/markdown/parse.js +283 -0
  55. package/dist/markdown/scan.d.ts +26 -0
  56. package/dist/markdown/scan.js +138 -0
  57. package/dist/markdown/slides.d.ts +32 -0
  58. package/dist/markdown/slides.js +854 -0
  59. package/dist/markdown/text.d.ts +76 -0
  60. package/dist/markdown/text.js +447 -0
  61. package/dist/markdown/twin.d.ts +41 -0
  62. package/dist/markdown/twin.js +374 -0
  63. package/dist/markdown/write.d.ts +17 -0
  64. package/dist/markdown/write.js +688 -0
  65. package/dist/math/index.d.ts +14 -0
  66. package/dist/math/index.js +14 -0
  67. package/dist/math/parse.d.ts +9 -0
  68. package/dist/math/parse.js +648 -0
  69. package/dist/math/symbols.d.ts +44 -0
  70. package/dist/math/symbols.js +333 -0
  71. package/dist/math/types.d.ts +59 -0
  72. package/dist/math/types.js +69 -0
  73. package/dist/model/backgrounds/contrast.d.ts +77 -0
  74. package/dist/model/backgrounds/contrast.js +186 -0
  75. package/dist/model/backgrounds/index.d.ts +7 -0
  76. package/dist/model/backgrounds/index.js +7 -0
  77. package/dist/model/backgrounds/resolve.d.ts +86 -0
  78. package/dist/model/backgrounds/resolve.js +215 -0
  79. package/dist/model/backgrounds/schema.d.ts +178 -0
  80. package/dist/model/backgrounds/schema.js +203 -0
  81. package/dist/model/codes.d.ts +73 -0
  82. package/dist/model/codes.js +67 -0
  83. package/dist/model/deck.d.ts +392 -0
  84. package/dist/model/deck.js +338 -0
  85. package/dist/model/index.d.ts +19 -0
  86. package/dist/model/index.js +19 -0
  87. package/dist/model/layouts/catalog.d.ts +433 -0
  88. package/dist/model/layouts/catalog.js +495 -0
  89. package/dist/model/layouts/index.d.ts +5 -0
  90. package/dist/model/layouts/index.js +5 -0
  91. package/dist/model/layouts/props.d.ts +302 -0
  92. package/dist/model/layouts/props.js +272 -0
  93. package/dist/model/loader.d.ts +37 -0
  94. package/dist/model/loader.js +317 -0
  95. package/dist/model/migrate.d.ts +34 -0
  96. package/dist/model/migrate.js +453 -0
  97. package/dist/model/motion/index.d.ts +6 -0
  98. package/dist/model/motion/index.js +6 -0
  99. package/dist/model/motion/transition.d.ts +96 -0
  100. package/dist/model/motion/transition.js +127 -0
  101. package/dist/model/parse.d.ts +57 -0
  102. package/dist/model/parse.js +307 -0
  103. package/dist/model/plain.d.ts +40 -0
  104. package/dist/model/plain.js +275 -0
  105. package/dist/model/shared.d.ts +63 -0
  106. package/dist/model/shared.js +86 -0
  107. package/dist/model/steps/index.d.ts +7 -0
  108. package/dist/model/steps/index.js +7 -0
  109. package/dist/model/steps/phase.d.ts +34 -0
  110. package/dist/model/steps/phase.js +50 -0
  111. package/dist/model/steps/slide-steps.d.ts +129 -0
  112. package/dist/model/steps/slide-steps.js +256 -0
  113. package/dist/model/style/index.d.ts +8 -0
  114. package/dist/model/style/index.js +8 -0
  115. package/dist/model/style/resolve.d.ts +87 -0
  116. package/dist/model/style/resolve.js +174 -0
  117. package/dist/model/style/schema.d.ts +85 -0
  118. package/dist/model/style/schema.js +53 -0
  119. package/dist/model/style/theme.d.ts +69 -0
  120. package/dist/model/style/theme.js +84 -0
  121. package/dist/schema/builders.d.ts +146 -0
  122. package/dist/schema/builders.js +285 -0
  123. package/dist/schema/diagnostics.d.ts +78 -0
  124. package/dist/schema/diagnostics.js +81 -0
  125. package/dist/schema/index.d.ts +15 -0
  126. package/dist/schema/index.js +14 -0
  127. package/dist/schema/internal.d.ts +40 -0
  128. package/dist/schema/internal.js +209 -0
  129. package/dist/schema/json-schema.d.ts +12 -0
  130. package/dist/schema/json-schema.js +213 -0
  131. package/dist/schema/types.d.ts +166 -0
  132. package/dist/schema/types.js +1 -0
  133. package/dist/schema/validate.d.ts +51 -0
  134. package/dist/schema/validate.js +765 -0
  135. package/dist/templates/index.d.ts +2 -0
  136. package/dist/templates/index.js +2 -0
  137. package/dist/templates/templates.d.ts +11 -0
  138. package/dist/templates/templates.js +47 -0
  139. package/package.json +60 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dailybot, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,183 @@
1
- # Temporary Holding Version
1
+ # @texuli/deck
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The framework-free, dependency-free deck engine for
4
+ [Texuli](https://texuli.com), an MIT-licensed Svelte 5 component library by
5
+ Dailybot, Inc. (*Small pieces. Infinite possibilities.*). One validated deck
6
+ model (model v2) that you write as JSON or as Markdown, with 20 catalog
7
+ layouts, backgrounds with a contrast guarantee, fragments and steps,
8
+ transitions, navigation with vertical stacks, hash routes, a controls
9
+ registry, canvas fit, auto-slide, a presenter protocol, lint, RFC 6902
10
+ patches, text twins, a typed builder, brief outlines and templates. It has no
11
+ Svelte and no DOM: the `@texuli/slides` stage presents its decks, and Node
12
+ tools and agents can use it on its own.
13
+
14
+ > **Status: in development (pre-1.0).** `@texuli/deck` is published on npm
15
+ > for the first time as `0.4.0`, with provenance. It was built in PLAN_008
16
+ > (ADR-009 in
17
+ > [DECISIONS](https://github.com/DailybotHQ/texuli/blob/main/docs/DECISIONS.md)).
18
+ > The `@texuli/slides` `0.4.0` stage renders it (`@texuli/slides` `0.3.0`
19
+ > has the previous deck model), and `@texuli/spec` `0.4.0` ships the
20
+ > blueprint spec `0.4.0` that encodes deck model v2. Under 0.x a new minor
21
+ > may contain breaking changes, so pin the exact version or use `^0.4.0`
22
+ > (see [RELEASE](https://github.com/DailybotHQ/texuli/blob/main/docs/RELEASE.md)).
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ npm install @texuli/deck
28
+ ```
29
+
30
+ It has **no runtime dependencies** and no
31
+ peer dependencies: no Svelte, no DOM framework, no schema library.
32
+
33
+ ## Quick start: JSON
34
+
35
+ `parseDeck` validates a deck and reports every issue at once, each with a
36
+ code, a JSON path, an RFC 6901 pointer and a fix. It never throws.
37
+
38
+ ```ts
39
+ import { parseDeck } from '@texuli/deck/model';
40
+ import { formatDiagnostic } from '@texuli/deck/schema';
41
+
42
+ const result = parseDeck({
43
+ formatVersion: 2,
44
+ meta: { title: 'Quarterly review', locale: 'en' },
45
+ style: { theme: 'nord', aspect: '16:9', transition: 'slide' },
46
+ slides: [
47
+ {
48
+ id: 'opening',
49
+ layout: 'title-hero',
50
+ props: { title: 'Quarterly review', subtitle: 'What shipped and what is next' },
51
+ notes: 'Welcome everyone and set the agenda for the next twenty minutes.',
52
+ },
53
+ {
54
+ id: 'adoption',
55
+ layout: 'big-stat',
56
+ props: { number: '87%', label: 'of releases shipped the day they merged' },
57
+ },
58
+ ],
59
+ });
60
+
61
+ if (result.ok) {
62
+ console.log(result.deck.slides.length); // 2
63
+ } else {
64
+ for (const issue of result.issues) console.log(formatDiagnostic(issue));
65
+ }
66
+ ```
67
+
68
+ Decks that arrive from somewhere untrusted (a share link, a pasted file, an
69
+ agent) go through `loadUntrustedDeck` instead: it bounds bytes, depth and
70
+ nodes before any deep work, migrates earlier deck shapes, then validates.
71
+
72
+ ## Quick start: Markdown
73
+
74
+ `parseDeckMarkdown` reads the deck Markdown dialect into the same validated
75
+ deck, with every issue located by line and column. Its syntax is inspired by
76
+ reveal.js Markdown but is its own closed dialect: there is no HTML, and it is
77
+ not compatible with reveal.js documents.
78
+
79
+ ```ts
80
+ import { parseDeckMarkdown } from '@texuli/deck/markdown';
81
+
82
+ const result = parseDeckMarkdown(`---
83
+ title: Quarterly review
84
+ transition: slide
85
+ ---
86
+
87
+ <!-- .slide: layout=title-hero -->
88
+
89
+ # Quarterly review
90
+
91
+ What shipped and what is next
92
+
93
+ ---
94
+
95
+ ## Priorities
96
+
97
+ - Ship smaller changes <!-- .element: fragment -->
98
+ - Measure every release <!-- .element: fragment -->
99
+
100
+ Note: Keep this slide short.
101
+ `);
102
+
103
+ console.log(result.ok, result.deck?.slides.map((slide) => slide.id));
104
+ // true [ 'quarterly-review', 'priorities' ]
105
+ ```
106
+
107
+ `deckToMarkdown(deck)` writes the canonical Markdown back; supported features
108
+ round-trip to the same deck.
109
+
110
+ ## Subpaths
111
+
112
+ | Import | What it gives you | Measured gzip |
113
+ | --- | --- | --- |
114
+ | `@texuli/deck` | The model and the schema kit (everything in `./model` and `./schema`) | 37,827 B |
115
+ | `@texuli/deck/model` | Deck model v2: schemas and types, `parseDeck`, the untrusted loader, migration, the 21-entry layout catalog, style and themes, backgrounds with contrast math, fragments and steps, transitions, the diagnostic code table and the JSON Schema export | 37,550 B |
116
+ | `@texuli/deck/schema` | The owned schema kit: combinators as data, all-issues validation, `Infer` types and JSON Schema 2020-12 | 8,980 B |
117
+ | `@texuli/deck/engine` | The controller with events and plugins, navigation with vertical stacks, hash routes, the controls registry and input decisions, canvas fit, motion, auto-slide, the presenter protocol and the stage messages | 24,156 B |
118
+ | `@texuli/deck/markdown` | The deck Markdown dialect to and from a deck, and the text and outline twins | 57,866 B |
119
+ | `@texuli/deck/math` | A TeX subset to a MathML node tree | 6,021 B |
120
+ | `@texuli/deck/authoring` | The typed builder, layout selection, brief outlines, quality lint and RFC 6902 patches | 30,740 B |
121
+ | `@texuli/deck/templates` | Deterministic starter templates | 27,361 B |
122
+
123
+ Sizes are the gzip measurements recorded on the final PLAN_008 code in
124
+ `texuli.budgets.json` (`pnpm size --filter @texuli/deck`); each subpath has
125
+ its own budget there.
126
+
127
+ The repository also keeps seven paired starter decks in `packages/deck/decks/`
128
+ (each as `<name>.json` and `<name>.md`), described in
129
+ [templates](https://github.com/DailybotHQ/texuli/blob/main/packages/deck/docs/templates.md).
130
+ They are fixtures, not an exported subpath.
131
+
132
+ ## Key guarantees
133
+
134
+ - **One model, two sources.** JSON and Markdown produce the same validated
135
+ `Deck`; `tests/authoring.test.ts` checks that every starter deck's JSON
136
+ and Markdown parse to equal decks and round-trip through `deckToMarkdown`.
137
+ - **All issues, never a throw.** Validation, the Markdown reader, the
138
+ loader, migration and lint report one `DeckDiagnostic` shape (code,
139
+ severity, path, JSON path, pointer, message, fix, slide id and, for
140
+ Markdown, line and column), capped at 200.
141
+ - **No HTML.** The model holds data only. The Markdown dialect refuses raw
142
+ HTML, iframes, `class`, `style` and `on*` attributes with a diagnostic;
143
+ math becomes a MathML node tree from a closed tag and attribute allowlist,
144
+ never a markup string.
145
+ - **Syntax here, policy at paint.** Media sources and links are checked for
146
+ syntax only. The deck never carries a trust tier: the stage applies
147
+ `@texuli/core/url-policy` at the host's tier when it paints.
148
+ - **Bounded on hostile input.** Size, depth, node, slide, step and issue
149
+ caps hold for JSON, Markdown, math and patches; prototype keys, accessors,
150
+ cycles and hidden characters are refused or stripped and reported.
151
+ - **Framework-free and DOM-free.** No `window`, `document` or
152
+ `BroadcastChannel` at import (`tests/engine-import-guard.test.ts`); the
153
+ engine imports nothing outside this package's `src/`.
154
+
155
+ ## Documentation
156
+
157
+ - [Model](https://github.com/DailybotHQ/texuli/blob/main/packages/deck/docs/model.md):
158
+ deck model v2, limits, slide kinds, layouts, backgrounds, style, steps,
159
+ transitions, diagnostics, `parseDeck`, the loader and migration
160
+ - [Schema kit](https://github.com/DailybotHQ/texuli/blob/main/packages/deck/docs/schema.md)
161
+ - [Engine](https://github.com/DailybotHQ/texuli/blob/main/packages/deck/docs/engine.md):
162
+ controller, navigation, routes, controls, canvas, motion, auto-slide,
163
+ presenter protocol and messages
164
+ - [Markdown dialect](https://github.com/DailybotHQ/texuli/blob/main/packages/deck/docs/markdown.md)
165
+ - [Math](https://github.com/DailybotHQ/texuli/blob/main/packages/deck/docs/math.md)
166
+ - [Authoring](https://github.com/DailybotHQ/texuli/blob/main/packages/deck/docs/authoring.md):
167
+ builder, outlines, layout selection, lint and patches
168
+ - [Templates](https://github.com/DailybotHQ/texuli/blob/main/packages/deck/docs/templates.md)
169
+ and the starter decks
170
+ - Decision: ADR-009 in
171
+ [DECISIONS](https://github.com/DailybotHQ/texuli/blob/main/docs/DECISIONS.md)
172
+ - The stage: [`@texuli/slides`](https://github.com/DailybotHQ/texuli/blob/main/packages/slides/README.md)
173
+ - Source: [github.com/DailybotHQ/texuli](https://github.com/DailybotHQ/texuli)
174
+ · Issues: [github.com/DailybotHQ/texuli/issues](https://github.com/DailybotHQ/texuli/issues)
175
+
176
+ ## Contributing
177
+
178
+ Contributions are welcome; start at the
179
+ [GitHub repository](https://github.com/DailybotHQ/texuli).
180
+
181
+ ## License
182
+
183
+ MIT © Dailybot, Inc. Powered by [Dailybot](https://www.dailybot.com?utm_source=dailybotopensource&utm_medium=texuli-deck).
@@ -0,0 +1,351 @@
1
+ import { DECK_LAYOUTS, type Deck, type DeckCatalogLayoutId, type DeckMeta, type DeckSlide, type FreeSlide, type LayoutProps } from '../model/index.js';
2
+ import type { DeckDiagnostic } from '../schema/index.js';
3
+ export type DeckBuildResult = {
4
+ ok: true;
5
+ deck: Deck;
6
+ diagnostics: DeckDiagnostic[];
7
+ } | {
8
+ ok: false;
9
+ diagnostics: DeckDiagnostic[];
10
+ };
11
+ export type SlideOptions = Pick<DeckSlide, 'id'> & Partial<Pick<DeckSlide, 'title' | 'notes'>>;
12
+ /** Typed slide constructors. All output is checked again by `deck(...).build()`. */
13
+ export declare const slide: Readonly<{
14
+ layout: <Id extends DeckCatalogLayoutId>(layout: Id, props: LayoutProps[Id], options: SlideOptions) => DeckSlide;
15
+ titleHero: (props: {
16
+ title: string;
17
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
18
+ subtitle?: string | undefined;
19
+ meta?: string | undefined;
20
+ step?: number | undefined;
21
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
22
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
23
+ }, options: SlideOptions) => DeckSlide;
24
+ sectionDivider: (props: {
25
+ title: string;
26
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
27
+ step?: number | undefined;
28
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
29
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
30
+ eyebrow?: string | undefined;
31
+ }, options: SlideOptions) => DeckSlide;
32
+ twoColumnSplit: (props: {
33
+ left: {
34
+ body: string;
35
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
36
+ step?: number | undefined;
37
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
38
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
39
+ heading?: string | undefined;
40
+ };
41
+ right: {
42
+ body: string;
43
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
44
+ step?: number | undefined;
45
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
46
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
47
+ heading?: string | undefined;
48
+ };
49
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
50
+ title?: string | undefined;
51
+ step?: number | undefined;
52
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
53
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
54
+ }, options: SlideOptions) => DeckSlide;
55
+ threeColumnCards: (props: {
56
+ cards: {
57
+ heading: string;
58
+ body: string;
59
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
60
+ step?: number | undefined;
61
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
62
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
63
+ icon?: string | undefined;
64
+ }[];
65
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
66
+ title?: string | undefined;
67
+ step?: number | undefined;
68
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
69
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
70
+ }, options: SlideOptions) => DeckSlide;
71
+ imageLeft: (props: {
72
+ image: {
73
+ alt: string;
74
+ src: string;
75
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
76
+ step?: number | undefined;
77
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
78
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
79
+ width?: number | undefined;
80
+ height?: number | undefined;
81
+ };
82
+ body: string;
83
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
84
+ title?: string | undefined;
85
+ step?: number | undefined;
86
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
87
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
88
+ heading?: string | undefined;
89
+ }, options: SlideOptions) => DeckSlide;
90
+ imageRight: (props: {
91
+ image: {
92
+ alt: string;
93
+ src: string;
94
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
95
+ step?: number | undefined;
96
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
97
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
98
+ width?: number | undefined;
99
+ height?: number | undefined;
100
+ };
101
+ body: string;
102
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
103
+ title?: string | undefined;
104
+ step?: number | undefined;
105
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
106
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
107
+ heading?: string | undefined;
108
+ }, options: SlideOptions) => DeckSlide;
109
+ imageCentered: (props: {
110
+ image: {
111
+ alt: string;
112
+ src: string;
113
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
114
+ step?: number | undefined;
115
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
116
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
117
+ width?: number | undefined;
118
+ height?: number | undefined;
119
+ };
120
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
121
+ title?: string | undefined;
122
+ step?: number | undefined;
123
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
124
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
125
+ caption?: string | undefined;
126
+ }, options: SlideOptions) => DeckSlide;
127
+ imageFullBleed: (props: {
128
+ image: {
129
+ alt: string;
130
+ src: string;
131
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
132
+ step?: number | undefined;
133
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
134
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
135
+ width?: number | undefined;
136
+ height?: number | undefined;
137
+ };
138
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
139
+ overlay?: "none" | "dark" | "light" | undefined;
140
+ step?: number | undefined;
141
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
142
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
143
+ caption?: string | undefined;
144
+ credit?: string | undefined;
145
+ }, options: SlideOptions) => DeckSlide;
146
+ quote: (props: {
147
+ quote: string;
148
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
149
+ step?: number | undefined;
150
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
151
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
152
+ cite?: string | undefined;
153
+ }, options: SlideOptions) => DeckSlide;
154
+ codeWithCallout: (props: {
155
+ code: {
156
+ lang: string;
157
+ source: string;
158
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
159
+ step?: number | undefined;
160
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
161
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
162
+ highlights?: string[] | undefined;
163
+ };
164
+ bullets: string[];
165
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
166
+ title?: string | undefined;
167
+ step?: number | undefined;
168
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
169
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
170
+ heading?: string | undefined;
171
+ }, options: SlideOptions) => DeckSlide;
172
+ bigStat: (props: {
173
+ number: string;
174
+ label: string;
175
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
176
+ step?: number | undefined;
177
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
178
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
179
+ source?: string | undefined;
180
+ context?: string | undefined;
181
+ }, options: SlideOptions) => DeckSlide;
182
+ comparisonTable: (props: {
183
+ columns: string[];
184
+ rows: {
185
+ label: string;
186
+ values: (string | boolean | null)[];
187
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
188
+ step?: number | undefined;
189
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
190
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
191
+ }[];
192
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
193
+ title?: string | undefined;
194
+ step?: number | undefined;
195
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
196
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
197
+ }, options: SlideOptions) => DeckSlide;
198
+ processSteps: (props: {
199
+ steps: {
200
+ title: string;
201
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
202
+ step?: number | undefined;
203
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
204
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
205
+ body?: string | undefined;
206
+ }[];
207
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
208
+ title?: string | undefined;
209
+ step?: number | undefined;
210
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
211
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
212
+ }, options: SlideOptions) => DeckSlide;
213
+ timeline: (props: {
214
+ events: {
215
+ text: string;
216
+ time: string;
217
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
218
+ step?: number | undefined;
219
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
220
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
221
+ }[];
222
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
223
+ title?: string | undefined;
224
+ step?: number | undefined;
225
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
226
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
227
+ }, options: SlideOptions) => DeckSlide;
228
+ teamAvatars: (props: {
229
+ people: {
230
+ name: string;
231
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
232
+ step?: number | undefined;
233
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
234
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
235
+ avatar?: string | undefined;
236
+ role?: string | undefined;
237
+ }[];
238
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
239
+ title?: string | undefined;
240
+ step?: number | undefined;
241
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
242
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
243
+ }, options: SlideOptions) => DeckSlide;
244
+ closingCta: (props: {
245
+ title: string;
246
+ cta: {
247
+ label: string;
248
+ href: string;
249
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
250
+ step?: number | undefined;
251
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
252
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
253
+ };
254
+ text?: string | undefined;
255
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
256
+ step?: number | undefined;
257
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
258
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
259
+ footnote?: string | undefined;
260
+ }, options: SlideOptions) => DeckSlide;
261
+ videoCentered: (props: {
262
+ video: {
263
+ src: string;
264
+ muted?: boolean | undefined;
265
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
266
+ step?: number | undefined;
267
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
268
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
269
+ width?: number | undefined;
270
+ height?: number | undefined;
271
+ label?: string | undefined;
272
+ autoplay?: boolean | undefined;
273
+ loop?: boolean | undefined;
274
+ };
275
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
276
+ title?: string | undefined;
277
+ step?: number | undefined;
278
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
279
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
280
+ caption?: string | undefined;
281
+ }, options: SlideOptions) => DeckSlide;
282
+ videoLeft: (props: {
283
+ video: {
284
+ src: string;
285
+ muted?: boolean | undefined;
286
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
287
+ step?: number | undefined;
288
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
289
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
290
+ width?: number | undefined;
291
+ height?: number | undefined;
292
+ label?: string | undefined;
293
+ autoplay?: boolean | undefined;
294
+ loop?: boolean | undefined;
295
+ };
296
+ body: string;
297
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
298
+ title?: string | undefined;
299
+ step?: number | undefined;
300
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
301
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
302
+ heading?: string | undefined;
303
+ }, options: SlideOptions) => DeckSlide;
304
+ videoRight: (props: {
305
+ video: {
306
+ src: string;
307
+ muted?: boolean | undefined;
308
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
309
+ step?: number | undefined;
310
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
311
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
312
+ width?: number | undefined;
313
+ height?: number | undefined;
314
+ label?: string | undefined;
315
+ autoplay?: boolean | undefined;
316
+ loop?: boolean | undefined;
317
+ };
318
+ body: string;
319
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
320
+ title?: string | undefined;
321
+ step?: number | undefined;
322
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
323
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
324
+ heading?: string | undefined;
325
+ }, options: SlideOptions) => DeckSlide;
326
+ chart: (props: {
327
+ spec: string | number | boolean | import("../index.js").JsonValue[] | {
328
+ [key: string]: import("../index.js").JsonValue;
329
+ } | null;
330
+ tone?: "accent" | "info" | "success" | "warning" | "danger" | undefined;
331
+ title?: string | undefined;
332
+ step?: number | undefined;
333
+ fragment?: "in" | "fade-up" | "out" | "in-then-out" | "grow" | "shrink" | "highlight" | "strike" | undefined;
334
+ reveal?: "fade-up" | "grow" | "highlight" | "strike" | "fade" | undefined;
335
+ height?: "sm" | "md" | "lg" | undefined;
336
+ showTable?: boolean | undefined;
337
+ }, options: SlideOptions) => DeckSlide;
338
+ free(options: SlideOptions & Pick<FreeSlide, "blocks"> & Partial<Pick<FreeSlide, "master">>): FreeSlide;
339
+ component(component: string, props: Record<string, unknown>, options: SlideOptions): DeckSlide;
340
+ }>;
341
+ export interface DeckBuilderOptions extends Pick<Deck, 'style' | 'navigation' | 'outline'> {
342
+ }
343
+ /** Start a typed immutable-by-convention deck builder for the v2 model. */
344
+ export declare function deck(meta: DeckMeta, options?: DeckBuilderOptions): {
345
+ slide: (value: DeckSlide) => /*elided*/ any;
346
+ add: (value: DeckSlide) => /*elided*/ any;
347
+ build(): DeckBuildResult;
348
+ };
349
+ /** Catalog order is the stable order used by generated capability output. */
350
+ export declare const authoringLayoutIds: readonly DeckCatalogLayoutId[];
351
+ export { DECK_LAYOUTS };
@@ -0,0 +1,64 @@
1
+ import { DECK_CATALOG_LAYOUT_IDS, DECK_FORMAT_VERSION, DECK_LAYOUTS, parseDeck, } from "../model/index.js";
2
+ function catalogSlide(layout, props, options) {
3
+ return { ...options, layout, props };
4
+ }
5
+ function sl(layout) {
6
+ return (props, options) => catalogSlide(layout, props, options);
7
+ }
8
+ /** Typed slide constructors. All output is checked again by `deck(...).build()`. */
9
+ export const slide = Object.freeze({
10
+ layout: (layout, props, options) => catalogSlide(layout, props, options),
11
+ titleHero: sl('title-hero'),
12
+ sectionDivider: sl('section-divider'),
13
+ twoColumnSplit: sl('two-column-split'),
14
+ threeColumnCards: sl('three-column-cards'),
15
+ imageLeft: sl('image-left'),
16
+ imageRight: sl('image-right'),
17
+ imageCentered: sl('image-centered'),
18
+ imageFullBleed: sl('image-full-bleed'),
19
+ quote: sl('quote'),
20
+ codeWithCallout: sl('code-with-callout'),
21
+ bigStat: sl('big-stat'),
22
+ comparisonTable: sl('comparison-table'),
23
+ processSteps: sl('process-steps'),
24
+ timeline: sl('timeline'),
25
+ teamAvatars: sl('team-avatars'),
26
+ closingCta: sl('closing-cta'),
27
+ videoCentered: sl('video-centered'),
28
+ videoLeft: sl('video-left'),
29
+ videoRight: sl('video-right'),
30
+ chart: sl('chart'),
31
+ free(options) {
32
+ return { ...options, layout: 'free', blocks: options.blocks };
33
+ },
34
+ component(component, props, options) {
35
+ return { ...options, layout: 'component', component: { component, props } };
36
+ },
37
+ });
38
+ /** Start a typed immutable-by-convention deck builder for the v2 model. */
39
+ export function deck(meta, options = {}) {
40
+ const slides = [];
41
+ const add = (value) => {
42
+ slides.push(value);
43
+ return api;
44
+ };
45
+ const api = {
46
+ slide: add,
47
+ add,
48
+ build() {
49
+ const parsed = parseDeck({
50
+ formatVersion: DECK_FORMAT_VERSION,
51
+ meta,
52
+ ...options,
53
+ slides: structuredClone(slides),
54
+ });
55
+ return parsed.ok && parsed.deck
56
+ ? { ok: true, deck: parsed.deck, diagnostics: parsed.issues }
57
+ : { ok: false, diagnostics: parsed.issues };
58
+ },
59
+ };
60
+ return api;
61
+ }
62
+ /** Catalog order is the stable order used by generated capability output. */
63
+ export const authoringLayoutIds = DECK_CATALOG_LAYOUT_IDS;
64
+ export { DECK_LAYOUTS };
@@ -0,0 +1,6 @@
1
+ /** @texuli/deck/authoring: typed builders, deterministic outlines, quality lint and JSON Patch. */
2
+ export { authoringLayoutIds, type DeckBuilderOptions, type DeckBuildResult, deck, type SlideOptions, slide, } from './builder.js';
3
+ export { DECK_AUTHORING_LIMITS, DECK_LINT_MAX_ISSUES, DECK_LINT_RULES, type DeckLintIssue, type DeckLintReport, type DeckLintRule, lintDeck, } from './lint.js';
4
+ export { DECK_OUTLINE_IDS, DECK_OUTLINES, type DeckOutlineId, type DeckOutlineTemplate, type DeckPacing, type GenerateBriefOptions, type GeneratedDeck, generateDeckFromBrief, type OutlineSlide, } from './outlines.js';
5
+ export { applyDeckPatch, type JsonPatchOperation, type JsonPatchResult, MAX_DECK_PATCH_OPERATIONS, } from './patch.js';
6
+ export { type LayoutChoice, type LayoutRequest, selectDeckLayouts } from './select-layouts.js';
@@ -0,0 +1,6 @@
1
+ /** @texuli/deck/authoring: typed builders, deterministic outlines, quality lint and JSON Patch. */
2
+ export { authoringLayoutIds, deck, slide, } from "./builder.js";
3
+ export { DECK_AUTHORING_LIMITS, DECK_LINT_MAX_ISSUES, DECK_LINT_RULES, lintDeck, } from "./lint.js";
4
+ export { DECK_OUTLINE_IDS, DECK_OUTLINES, generateDeckFromBrief, } from "./outlines.js";
5
+ export { applyDeckPatch, MAX_DECK_PATCH_OPERATIONS, } from "./patch.js";
6
+ export { selectDeckLayouts } from "./select-layouts.js";