mdeck 2.3.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 (268) hide show
  1. package/CHANGELOG.md +259 -0
  2. package/LICENSE +21 -0
  3. package/README.md +156 -0
  4. package/assets/base.css +196 -0
  5. package/assets/extensions/layouts/chapter/extension.toml +26 -0
  6. package/assets/extensions/layouts/chapter/layout.jsx +21 -0
  7. package/assets/extensions/layouts/chapter/starter.md +8 -0
  8. package/assets/extensions/layouts/focus/extension.toml +8 -0
  9. package/assets/extensions/layouts/focus/layout.jsx +10 -0
  10. package/assets/extensions/layouts/focus/starter.md +4 -0
  11. package/assets/extensions/layouts/full-bleed-image/extension.toml +31 -0
  12. package/assets/extensions/layouts/full-bleed-image/layout.jsx +19 -0
  13. package/assets/extensions/layouts/full-bleed-image/starter.md +6 -0
  14. package/assets/extensions/layouts/generic/extension.toml +8 -0
  15. package/assets/extensions/layouts/generic/layout.jsx +8 -0
  16. package/assets/extensions/layouts/generic/starter.md +4 -0
  17. package/assets/extensions/layouts/image-text/extension.toml +25 -0
  18. package/assets/extensions/layouts/image-text/layout.jsx +17 -0
  19. package/assets/extensions/layouts/image-text/starter.md +6 -0
  20. package/assets/extensions/layouts/split/extension.toml +25 -0
  21. package/assets/extensions/layouts/split/layout.jsx +19 -0
  22. package/assets/extensions/layouts/split/starter.md +14 -0
  23. package/assets/extensions/layouts/title/extension.toml +26 -0
  24. package/assets/extensions/layouts/title/layout.jsx +14 -0
  25. package/assets/extensions/layouts/title/starter.md +5 -0
  26. package/assets/extensions/palettes/brand/extension.toml +29 -0
  27. package/assets/extensions/palettes/cobalt/extension.toml +27 -0
  28. package/assets/extensions/palettes/ember/extension.toml +27 -0
  29. package/assets/extensions/palettes/forest/extension.toml +27 -0
  30. package/assets/extensions/palettes/graphite/extension.toml +27 -0
  31. package/assets/extensions/palettes/lagoon/extension.toml +27 -0
  32. package/assets/extensions/palettes/neon/extension.toml +27 -0
  33. package/assets/extensions/palettes/nordic/extension.toml +27 -0
  34. package/assets/extensions/palettes/pastel/extension.toml +30 -0
  35. package/assets/extensions/palettes/phosphor/extension.toml +27 -0
  36. package/assets/extensions/palettes/swiss/extension.toml +27 -0
  37. package/assets/extensions/palettes/terra/extension.toml +27 -0
  38. package/assets/extensions/themes/academic/extension.toml +53 -0
  39. package/assets/extensions/themes/academic/styles.css +631 -0
  40. package/assets/extensions/themes/aurora/extension.toml +37 -0
  41. package/assets/extensions/themes/aurora/styles.css +644 -0
  42. package/assets/extensions/themes/duet/extension.toml +46 -0
  43. package/assets/extensions/themes/duet/styles.css +573 -0
  44. package/assets/extensions/themes/editorial/extension.toml +46 -0
  45. package/assets/extensions/themes/editorial/styles.css +574 -0
  46. package/assets/extensions/themes/fhnw/extension.toml +61 -0
  47. package/assets/extensions/themes/fhnw/styles.css +604 -0
  48. package/assets/extensions/themes/neue/extension.toml +46 -0
  49. package/assets/extensions/themes/neue/styles.css +489 -0
  50. package/assets/extensions/themes/sketch/extension.toml +48 -0
  51. package/assets/extensions/themes/sketch/styles.css +633 -0
  52. package/assets/extensions/themes/terminal/extension.toml +38 -0
  53. package/assets/extensions/themes/terminal/styles.css +550 -0
  54. package/assets/logo/avatar.png +0 -0
  55. package/assets/logo/logo-dark.svg +10 -0
  56. package/assets/logo/logo-light.svg +10 -0
  57. package/assets/logo/mark.svg +15 -0
  58. package/bin/mdeck.js +2 -0
  59. package/docs/README.md +8 -0
  60. package/docs/reference/authoring.md +795 -0
  61. package/docs/reference/claude-skill.md +96 -0
  62. package/docs/reference/extensions.md +250 -0
  63. package/docs/reference/layouts.md +153 -0
  64. package/docs/reference/palettes.md +106 -0
  65. package/docs/reference/structured-slides.md +120 -0
  66. package/docs/reference/themes.md +133 -0
  67. package/docs/site/assets/favicon.svg +15 -0
  68. package/docs/site/assets/github-logo.svg +1 -0
  69. package/docs/site/assets/site.css +162 -0
  70. package/docs/site/assets/site.js +123 -0
  71. package/docs/site/build.js +148 -0
  72. package/docs/site/content/appearance.md +203 -0
  73. package/docs/site/content/audience.md +178 -0
  74. package/docs/site/content/commands.md +153 -0
  75. package/docs/site/content/components.md +134 -0
  76. package/docs/site/content/drawing.md +72 -0
  77. package/docs/site/content/editing.md +59 -0
  78. package/docs/site/content/getting-started.md +103 -0
  79. package/docs/site/content/layouts.md +126 -0
  80. package/docs/site/content/media.md +107 -0
  81. package/docs/site/content/more-content.md +130 -0
  82. package/docs/site/content/presenting.md +93 -0
  83. package/docs/site/content/reusable-layouts.md +74 -0
  84. package/docs/site/content/sharing.md +88 -0
  85. package/docs/site/content/theme-authoring.md +144 -0
  86. package/docs/site/content/theme-repository.md +76 -0
  87. package/docs/site/content/troubleshooting.md +92 -0
  88. package/docs/site/content/views.md +56 -0
  89. package/docs/site/content/welcome.md +71 -0
  90. package/docs/site/content/writing.md +121 -0
  91. package/docs/site/examples/first-talk.md +88 -0
  92. package/docs/site/examples/notebook.svg +58 -0
  93. package/docs/site/images/themes/academic-dark.webp +0 -0
  94. package/docs/site/images/themes/academic-light.webp +0 -0
  95. package/docs/site/images/themes/academic.webp +0 -0
  96. package/docs/site/images/themes/aurora-dark.webp +0 -0
  97. package/docs/site/images/themes/aurora-light.webp +0 -0
  98. package/docs/site/images/themes/aurora.webp +0 -0
  99. package/docs/site/images/themes/duet-dark.webp +0 -0
  100. package/docs/site/images/themes/duet-light.webp +0 -0
  101. package/docs/site/images/themes/duet.webp +0 -0
  102. package/docs/site/images/themes/editorial-dark.webp +0 -0
  103. package/docs/site/images/themes/editorial-light.webp +0 -0
  104. package/docs/site/images/themes/editorial.webp +0 -0
  105. package/docs/site/images/themes/fhnw.webp +0 -0
  106. package/docs/site/images/themes/neue-dark.webp +0 -0
  107. package/docs/site/images/themes/neue-light.webp +0 -0
  108. package/docs/site/images/themes/neue.webp +0 -0
  109. package/docs/site/images/themes/sketch-dark.webp +0 -0
  110. package/docs/site/images/themes/sketch-light.webp +0 -0
  111. package/docs/site/images/themes/sketch.webp +0 -0
  112. package/docs/site/images/themes/terminal-dark.webp +0 -0
  113. package/docs/site/images/themes/terminal-light.webp +0 -0
  114. package/docs/site/images/themes/terminal.webp +0 -0
  115. package/docs/site/package.json +9 -0
  116. package/docs/site/pages.js +27 -0
  117. package/docs/site/server.js +58 -0
  118. package/examples/custom-layouts/extensions/comparison/extension.toml +35 -0
  119. package/examples/custom-layouts/extensions/comparison/layout.jsx +15 -0
  120. package/examples/custom-layouts/extensions/comparison/starter.md +17 -0
  121. package/examples/custom-layouts/extensions/comparison/styles.css +4 -0
  122. package/examples/custom-layouts/slides.md +60 -0
  123. package/examples/poll/slides.md +127 -0
  124. package/examples/python/.mdeck-backups/slides.drawings-2026-10-06T08-36-47Z.json +19 -0
  125. package/examples/python/.mdeck-backups/slides.drawings-2026-10-06T11-27-30Z.json +6 -0
  126. package/examples/python/slides.drawings.json +6 -0
  127. package/examples/python/slides.md +493 -0
  128. package/examples/showcase/.mdeck-backups/slides.drawings-2026-10-06T08-08-30Z.json +10 -0
  129. package/examples/showcase/.mdeck-backups/slides.drawings-2026-10-06T11-41-35Z.json +13 -0
  130. package/examples/showcase/img/image.jpg +0 -0
  131. package/examples/showcase/img/mdeck.svg +66 -0
  132. package/examples/showcase/slides.drawings.json +11 -0
  133. package/examples/showcase/slides.md +427 -0
  134. package/package.json +75 -0
  135. package/skills/write-slides/SKILL.md +144 -0
  136. package/src/build/check.js +49 -0
  137. package/src/build/chrome.js +130 -0
  138. package/src/build/components.js +44 -0
  139. package/src/build/config.js +61 -0
  140. package/src/build/drawings.js +14 -0
  141. package/src/build/editorPlugin.js +272 -0
  142. package/src/build/editorServer.js +36 -0
  143. package/src/build/fonts.js +84 -0
  144. package/src/build/homePlugin.js +208 -0
  145. package/src/build/inkPlugin.js +192 -0
  146. package/src/build/ownWrites.js +18 -0
  147. package/src/build/pairing.js +81 -0
  148. package/src/build/pdf.js +34 -0
  149. package/src/build/relayAccess.js +85 -0
  150. package/src/build/slidesPlugin.js +371 -0
  151. package/src/build/themeCheck.js +151 -0
  152. package/src/build/tunnelClient.js +184 -0
  153. package/src/cli/args.js +76 -0
  154. package/src/cli/index.js +758 -0
  155. package/src/cli/migrate.js +123 -0
  156. package/src/cli/skill.js +40 -0
  157. package/src/cli/themes.js +140 -0
  158. package/src/components/CodeBlock.jsx +168 -0
  159. package/src/components/ConnectedViews.jsx +25 -0
  160. package/src/components/Icon.jsx +8 -0
  161. package/src/components/Poll.jsx +67 -0
  162. package/src/components/QrCode.jsx +29 -0
  163. package/src/components/QrCodeTag.jsx +27 -0
  164. package/src/components/Question.jsx +28 -0
  165. package/src/components/Scale.jsx +47 -0
  166. package/src/components/VideoPlayer.jsx +108 -0
  167. package/src/components/WordCloud.jsx +106 -0
  168. package/src/components/activity.jsx +35 -0
  169. package/src/components/callout.css +78 -0
  170. package/src/components/code-block.css +123 -0
  171. package/src/components/columns.css +11 -0
  172. package/src/components/poll.css +81 -0
  173. package/src/components/video-player.css +14 -0
  174. package/src/core/devPath.js +4 -0
  175. package/src/core/editDeck.js +230 -0
  176. package/src/core/icons.js +69 -0
  177. package/src/core/ink.js +221 -0
  178. package/src/core/labels.js +144 -0
  179. package/src/core/outline.js +33 -0
  180. package/src/core/parseSlides.js +152 -0
  181. package/src/core/source.js +137 -0
  182. package/src/core/urls.js +34 -0
  183. package/src/core/validateDeck.js +139 -0
  184. package/src/editor/api.js +67 -0
  185. package/src/editor/components/App.jsx +75 -0
  186. package/src/editor/components/ConflictBanner.jsx +10 -0
  187. package/src/editor/components/DeckSettings.jsx +108 -0
  188. package/src/editor/components/DesignApp.jsx +252 -0
  189. package/src/editor/components/Diagnostics.jsx +10 -0
  190. package/src/editor/components/ExtensionEditor.jsx +66 -0
  191. package/src/editor/components/ExtensionForms.jsx +134 -0
  192. package/src/editor/components/ExtensionsPanel.jsx +114 -0
  193. package/src/editor/components/Field.jsx +24 -0
  194. package/src/editor/components/Inspector.jsx +36 -0
  195. package/src/editor/components/LayoutPicker.jsx +23 -0
  196. package/src/editor/components/LayoutSelect.jsx +25 -0
  197. package/src/editor/components/LookThumbnail.jsx +8 -0
  198. package/src/editor/components/MetaFields.jsx +24 -0
  199. package/src/editor/components/Outline.jsx +28 -0
  200. package/src/editor/components/PalettePicker.jsx +32 -0
  201. package/src/editor/components/Preview.jsx +63 -0
  202. package/src/editor/components/PropsForm.jsx +46 -0
  203. package/src/editor/components/RawSlideEditor.jsx +9 -0
  204. package/src/editor/components/RegionEditor.jsx +15 -0
  205. package/src/editor/components/Resizer.jsx +18 -0
  206. package/src/editor/designLink.js +19 -0
  207. package/src/editor/editor.css +139 -0
  208. package/src/editor/extensions.js +86 -0
  209. package/src/editor/keyboard.js +21 -0
  210. package/src/editor/model.js +38 -0
  211. package/src/editor/sampleDeck.js +165 -0
  212. package/src/editor/saveQueue.js +47 -0
  213. package/src/editor/schema.js +36 -0
  214. package/src/editor/state.js +92 -0
  215. package/src/editor/useDeckDocument.js +67 -0
  216. package/src/extensions/appearance.js +79 -0
  217. package/src/extensions/contrast.js +57 -0
  218. package/src/extensions/discover.js +126 -0
  219. package/src/extensions/manifest.js +209 -0
  220. package/src/extensions/packs.js +268 -0
  221. package/src/extensions/tokens.js +25 -0
  222. package/src/home/Home.jsx +362 -0
  223. package/src/home/home.css +148 -0
  224. package/src/layouts/layoutApi.jsx +205 -0
  225. package/src/layouts/layoutProps.js +30 -0
  226. package/src/layouts/renderSlide.jsx +17 -0
  227. package/src/live/answer/answer.css +34 -0
  228. package/src/live/answer/answer.html +14 -0
  229. package/src/live/answer/answer.js +130 -0
  230. package/src/live/client.js +290 -0
  231. package/src/live/code.js +19 -0
  232. package/src/live/follow.js +17 -0
  233. package/src/live/pairing.js +34 -0
  234. package/src/live/presence.js +33 -0
  235. package/src/live/roomTag.js +38 -0
  236. package/src/live/rooms.js +249 -0
  237. package/src/live/server.js +82 -0
  238. package/src/live/tunnel.js +180 -0
  239. package/src/paths.js +9 -0
  240. package/src/runtime/ReaderView.jsx +193 -0
  241. package/src/runtime/SlideErrorBoundary.jsx +28 -0
  242. package/src/runtime/chrome.jsx +55 -0
  243. package/src/runtime/deck-stage.js +1533 -0
  244. package/src/runtime/design.html +12 -0
  245. package/src/runtime/design.jsx +5 -0
  246. package/src/runtime/editor.html +12 -0
  247. package/src/runtime/editor.jsx +5 -0
  248. package/src/runtime/editorBridge.js +58 -0
  249. package/src/runtime/fit.js +149 -0
  250. package/src/runtime/home.html +13 -0
  251. package/src/runtime/home.jsx +5 -0
  252. package/src/runtime/index.html +15 -0
  253. package/src/runtime/ink/InkLayer.jsx +17 -0
  254. package/src/runtime/ink/Toolbar.jsx +145 -0
  255. package/src/runtime/ink/attach.js +69 -0
  256. package/src/runtime/ink/bus.js +126 -0
  257. package/src/runtime/ink/controller.js +132 -0
  258. package/src/runtime/ink/room.js +101 -0
  259. package/src/runtime/ink/select.js +124 -0
  260. package/src/runtime/ink/server.js +75 -0
  261. package/src/runtime/ink/store.js +55 -0
  262. package/src/runtime/ink/toolbar.css +79 -0
  263. package/src/runtime/main.jsx +863 -0
  264. package/src/runtime/markedSetup.js +147 -0
  265. package/src/runtime/reader.css +59 -0
  266. package/src/runtime/registry.jsx +26 -0
  267. package/src/runtime/syncOrder.js +32 -0
  268. package/src/runtime/themeLoader.js +68 -0
@@ -0,0 +1,427 @@
1
+ ---
2
+ theme: aurora
3
+ meta:
4
+ title: "A tour of mdeck"
5
+ author: "Tilman Schieber"
6
+ organization: "FHNW"
7
+ date: "2026-10-06"
8
+ ---
9
+
10
+ ---
11
+ :::meta
12
+ layout: title
13
+ image: ./img/mdeck.svg
14
+ fit: contain
15
+ alt: "A Markdown file turning into a stack of slides"
16
+ id: a-talk-in-a-text-file
17
+ :::
18
+ # A talk in a text file.
19
+ ## A tour of mdeck: each slide shows *what is written* and what it becomes.
20
+
21
+ :::notes
22
+ This deck teaches mdeck by example. Most slides show the Markdown beside what it becomes. Open `slides.md` next to it: every slide here is written exactly as shown.
23
+
24
+ Go through it with the arrow keys or the space bar. These notes are only for you; open the presenter view from the launch page to see them beside the slide.
25
+ :::
26
+
27
+ ---
28
+ :::meta
29
+ layout: chapter
30
+ number: 1
31
+ part: Writing
32
+ description: Plain Markdown, the format AI assistants already write. You can read and change every word.
33
+ :::
34
+ # Write it.
35
+
36
+ :::notes
37
+ In practice an AI assistant usually writes this file from your own material: old slides, a document, your notes. The `write-slides` skill teaches it mdeck. The next slides show what it writes, so you can read and adjust it.
38
+ :::
39
+
40
+ ---
41
+ :::meta
42
+ layout: split
43
+ :::
44
+ # Words become slides
45
+ :::slot left
46
+ ```markdown
47
+ # Our next adventure
48
+
49
+ A paragraph of ordinary text.
50
+
51
+ ---
52
+
53
+ # The next idea
54
+ ```
55
+ :::
56
+ :::slot right
57
+ ## Our next adventure
58
+
59
+ A paragraph of ordinary text.
60
+
61
+ Three dashes on a line of their own start the next slide.
62
+ :::
63
+
64
+ :::notes
65
+ `#` is the slide's heading. A blank line separates paragraphs.
66
+
67
+ Try it: change a heading in `slides.md` and save. The slide updates while it is open.
68
+ :::
69
+
70
+ ---
71
+ :::meta
72
+ layout: split
73
+ :::
74
+ # Lists and emphasis
75
+ :::slot left
76
+ ```markdown
77
+ - Bring a notebook.
78
+ - Ask **one good question**.
79
+ - Share what *you* learn.
80
+
81
+ 1. Listen
82
+ 2. Summarize
83
+ ```
84
+ :::
85
+ :::slot right
86
+ - Bring a notebook.
87
+ - Ask **one good question**.
88
+ - Share what *you* learn.
89
+
90
+ 1. Listen
91
+ 2. Summarize
92
+ :::
93
+
94
+ :::notes
95
+ `**bold**` and `*emphasis*`; the theme decides how emphasis looks. In this theme it takes the accent colour.
96
+ :::
97
+
98
+ ---
99
+ # Reveal points one at a time
100
+
101
+ :::columns
102
+ ```markdown
103
+ :::steps
104
+ - First, a question.
105
+ - Then, a pause.
106
+ - Then, the answer.
107
+ :::
108
+ ```
109
+ +++
110
+ :::steps
111
+ - First, a question.
112
+ - Then, a pause.
113
+ - Then, the answer.
114
+ :::
115
+ :::
116
+
117
+ :::notes
118
+ Press the next key: each press reveals one point, then moves on. Printed slides and the PDF show all the points.
119
+
120
+ This slide has no layout: `:::columns` puts the source and the result side by side, and `+++` starts the second column.
121
+ :::
122
+
123
+ ---
124
+ :::meta
125
+ layout: chapter
126
+ number: 2
127
+ part: Layouts and content
128
+ description: Layouts, pictures, code, tables and callouts. Pick a layout per slide; the theme does the rest.
129
+ :::
130
+ # Lay it out.
131
+
132
+ ---
133
+ :::meta
134
+ layout: split
135
+ props:
136
+ ratio: [3, 2]
137
+ :::
138
+ # Choose a layout
139
+ :::slot left
140
+ ```markdown
141
+ :::meta
142
+ layout: focus
143
+ attribution: "A teacher"
144
+ :::
145
+ # Good questions make
146
+ # better conversations.
147
+ ```
148
+ :::
149
+ :::slot right
150
+ A `:::meta` block at the top of a slide holds its settings.
151
+
152
+ `layout: focus` makes one large statement. The next slide is exactly this.
153
+ :::
154
+
155
+ :::notes
156
+ Without a layout, a slide is an ordinary heading with content. This slide is `layout: split`, with the two sides written as `:::slot left` and `:::slot right`; `ratio: [3, 2]` gives the code more room.
157
+
158
+ The built-in layouts are `title`, `chapter`, `focus`, `split`, `image-text` and `full-bleed-image`.
159
+ :::
160
+
161
+ ---
162
+ :::meta
163
+ layout: focus
164
+ attribution: "A teacher"
165
+ :::
166
+ # Good questions make better conversations.
167
+
168
+ ---
169
+ :::meta
170
+ layout: image-text
171
+ image: ./img/image.jpg
172
+ alt: "Contour lines like those on a map"
173
+ :::
174
+ # A picture beside your words
175
+
176
+ ```markdown
177
+ :::meta
178
+ layout: image-text
179
+ image: ./img/image.jpg
180
+ alt: "Contour lines"
181
+ :::
182
+ ```
183
+
184
+ `alt` describes the picture for people who cannot see it.
185
+
186
+ :::notes
187
+ Keep pictures in a folder beside the slides, here `img/`. The next slide uses the same picture with `layout: full-bleed-image`.
188
+ :::
189
+
190
+ ---
191
+ :::meta
192
+ layout: full-bleed-image
193
+ image: ./img/image.jpg
194
+ alt: "Contour lines like those on a map"
195
+ overlay: true
196
+ :::
197
+ # Or let the picture fill the slide.
198
+
199
+ :::notes
200
+ This slide is written as:
201
+
202
+ ```markdown
203
+ :::meta
204
+ layout: full-bleed-image
205
+ image: ./img/image.jpg
206
+ overlay: true
207
+ :::
208
+ # Or let the picture fill the slide.
209
+ ```
210
+
211
+ `overlay: true` darkens the picture so the heading stays readable.
212
+ :::
213
+
214
+ ---
215
+ :::meta
216
+ layout: split
217
+ :::
218
+ # Code you can run
219
+ :::slot left
220
+ ````markdown
221
+ ```python live editable
222
+ squares = [x**2 for x in range(1, 6)]
223
+ print(squares)
224
+ ```
225
+ ````
226
+ :::
227
+ :::slot right
228
+ ```python live editable
229
+ squares = [x**2 for x in range(1, 6)]
230
+ print(squares)
231
+ ```
232
+ :::
233
+
234
+ :::notes
235
+ Press Run. `live` adds the button, `editable` lets you change the code while presenting, `copy` adds a copy button. JavaScript works the same way.
236
+
237
+ Live Python downloads its runtime the first time, so it needs an internet connection.
238
+ :::
239
+
240
+ ---
241
+ :::meta
242
+ layout: split
243
+ :::
244
+ # Tables and formulas
245
+ :::slot left
246
+ ```markdown
247
+ | Layer | Who owns it |
248
+ |---|---|
249
+ | Words | You |
250
+ | Look | The theme |
251
+
252
+ $$
253
+ A = \pi r^2
254
+ $$
255
+ ```
256
+ :::
257
+ :::slot right
258
+ | Layer | Who owns it |
259
+ |---|---|
260
+ | Words | You |
261
+ | Look | The theme |
262
+
263
+ $$
264
+ A = \pi r^2
265
+ $$
266
+ :::
267
+
268
+ :::notes
269
+ Formulas use LaTeX. Single dollar signs put a formula inside a sentence; two dollar signs above and below put it on its own line.
270
+ :::
271
+
272
+ ---
273
+ :::meta
274
+ layout: split
275
+ :::
276
+ # Tips and warnings
277
+ :::slot left
278
+ ```markdown
279
+ :::tip
280
+ One tip per slide is plenty.
281
+ :::
282
+
283
+ :::warning
284
+ Check the room's projector.
285
+ :::
286
+ ```
287
+ :::
288
+ :::slot right
289
+ :::tip
290
+ One tip per slide is plenty.
291
+ :::
292
+
293
+ :::warning
294
+ Check the room's projector.
295
+ :::
296
+ :::
297
+
298
+ :::notes
299
+ The other callouts are `note`, `important` and `caution`. Add your own label after the type, for example `:::tip Before the talk`.
300
+ :::
301
+
302
+ ---
303
+ :::meta
304
+ layout: chapter
305
+ number: 3
306
+ part: Presenting
307
+ description: Notes for you, drawing on the slides, and questions for the room.
308
+ id: give-the-talk
309
+ :::
310
+ # Give the talk.
311
+
312
+ ---
313
+ :::meta
314
+ layout: split
315
+ :::
316
+ # Notes only you can see
317
+ :::slot left
318
+ ```markdown
319
+ :::notes
320
+ Pause here. Ask who has
321
+ tried this before.
322
+ :::
323
+ ```
324
+ :::
325
+ :::slot right
326
+ Notes go below the slide's content. They appear in the **presenter view**, never on the projector.
327
+
328
+ Open it from the launch page, and move the **audience window** onto the projector. The two follow each other.
329
+ :::
330
+
331
+ :::notes
332
+ Pause here. Ask who has tried this before.
333
+
334
+ This is what the presenter view shows for this slide. Its header also shows what is connected: other presenter views, audience windows and phones.
335
+ :::
336
+
337
+ ---
338
+ :::meta
339
+ id: draw-on-any-slide
340
+ :::
341
+ # Draw on any slide
342
+
343
+ Press **D** now, or the pen button. Draw with a pen, a highlighter, or a marker that fades after a moment. **Escape** stops.
344
+
345
+ Drawings are kept in `slides.drawings.json` beside the slides, and appear in the PDF.
346
+
347
+ :::notes
348
+ The underline and the circle on this slide were drawn with the pen and saved; they show in every view and in the PDF.
349
+
350
+ On an iPad, pair it from the launch page: you draw and steer there while the laptop drives the projector.
351
+ :::
352
+
353
+ ---
354
+ # Which part will you try first?
355
+
356
+ <poll room="tour" options="Writing|Layouts|Drawing|Polls" />
357
+
358
+ :::notes
359
+ One line makes a poll; the heading is the question:
360
+
361
+ `<poll room="tour" options="Writing|Layouts|Drawing|Polls" />`
362
+
363
+ Phones join with the QR code. They can reach this computer when you start `mdeck run slides.md --network`. The poll example shows scales, word clouds and open questions.
364
+ :::
365
+
366
+ ---
367
+ :::meta
368
+ layout: chapter
369
+ number: 4
370
+ part: Sharing
371
+ description: One file to send, a PDF, or a folder for a website.
372
+ :::
373
+ # Share it.
374
+
375
+ ---
376
+ :::meta
377
+ layout: split
378
+ :::
379
+ # Change the whole look
380
+ :::slot left
381
+ ```markdown
382
+ ---
383
+ theme: editorial
384
+ palette: terra
385
+ ---
386
+ ```
387
+ :::
388
+ :::slot right
389
+ Two lines at the top of the file choose the theme and colours for every slide at once.
390
+
391
+ To try them without changing the file, open the **reader view** and choose **Look**.
392
+ :::
393
+
394
+ :::notes
395
+ mdeck has six themes and ten palettes, each light or dark. `mdeck list` shows them all, including any kept in an `extensions` folder beside the deck.
396
+ :::
397
+
398
+ ---
399
+ :::meta
400
+ layout: split
401
+ :::
402
+ # Send it, print it, host it
403
+ :::slot left
404
+ ```sh
405
+ mdeck send slides.md
406
+ mdeck pdf slides.md
407
+ mdeck build slides.md
408
+ ```
409
+ :::
410
+ :::slot right
411
+ `send` makes one HTML file without your notes, with a PDF inside. People open it in a browser.
412
+
413
+ `pdf` makes one page per slide. `build` makes a folder for a web server.
414
+ :::
415
+
416
+ ---
417
+ :::meta
418
+ layout: title
419
+ :::
420
+ # Now make your own.
421
+ ## Hand your slides, documents or notes to an *AI assistant*.
422
+
423
+ :::notes
424
+ `mdeck skill --install claude` (or codex, cursor, copilot, gemini) installs the `write-slides` skill, which teaches the assistant mdeck. Then point it at your material: “Rebuild lecture-03.pptx as a 20-minute talk.”
425
+
426
+ Without an assistant, `mdeck new` asks a few questions and starts a deck.
427
+ :::
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "mdeck",
3
+ "version": "2.3.0",
4
+ "type": "module",
5
+ "description": "Write slides as a plain text file, present them in the browser, share them as one HTML file or PDF.",
6
+ "license": "MIT",
7
+ "author": "Tilman Schieber",
8
+ "homepage": "https://gh.tschieber.de/mdeck/",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/tilman-schieber/mdeck.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/tilman-schieber/mdeck/issues"
15
+ },
16
+ "keywords": [
17
+ "markdown",
18
+ "slides",
19
+ "presentation",
20
+ "deck",
21
+ "pdf",
22
+ "teaching"
23
+ ],
24
+ "engines": {
25
+ "node": ">=22"
26
+ },
27
+ "bin": {
28
+ "mdeck": "./bin/mdeck.js"
29
+ },
30
+ "files": [
31
+ "bin",
32
+ "src",
33
+ "assets",
34
+ "docs/README.md",
35
+ "docs/reference",
36
+ "docs/site",
37
+ "!docs/site/dist",
38
+ "examples",
39
+ "skills",
40
+ "CHANGELOG.md"
41
+ ],
42
+ "scripts": {
43
+ "test": "node --test",
44
+ "test:browser": "node tools/browser-check.mjs",
45
+ "test:server": "node tools/server-check.mjs",
46
+ "test:docs": "node tools/docs-check.mjs",
47
+ "test:themes": "node tools/theme-check.mjs",
48
+ "docs": "node bin/mdeck.js docs",
49
+ "docs:build": "node docs/site/build.js",
50
+ "start": "node bin/mdeck.js run",
51
+ "edit": "node bin/mdeck.js edit",
52
+ "build": "node bin/mdeck.js build",
53
+ "preview": "node bin/mdeck.js preview",
54
+ "playground": "vite --config playground/vite.config.js",
55
+ "playground:build": "vite build --config playground/vite.config.js",
56
+ "readme-images": "node tools/readme-images.mjs",
57
+ "theme-images": "node tools/theme-images.mjs"
58
+ },
59
+ "dependencies": {
60
+ "@preact/preset-vite": "^2.10.6",
61
+ "d3-cloud": "^1.2.9",
62
+ "js-yaml": "^4.3.2",
63
+ "katex": "^0.18.9",
64
+ "marked": "^18.0.14",
65
+ "marked-katex-extension": "^5.1.13",
66
+ "perfect-freehand": "^1.2.3",
67
+ "preact": "^10.29.8",
68
+ "prismjs": "^1.30.0",
69
+ "qrcode": "^1.5.4",
70
+ "smol-toml": "^1.9.0",
71
+ "vite": "^8.3.1",
72
+ "vite-plugin-singlefile": "^2.3.3",
73
+ "ws": "^8.22.0"
74
+ }
75
+ }
@@ -0,0 +1,144 @@
1
+ ---
2
+ name: write-slides
3
+ description: Write a complete mdeck slide deck. Use when the user asks to create slides, a presentation, or a talk using the mdeck framework, including turning existing PowerPoint, PDF, Word documents or notes into a deck, and when they want a new look for mdeck slides (a theme or colour palette, for example in their institute's colours).
4
+ license: MIT
5
+ compatibility: Best with the mdeck command installed (npm install -g mdeck); works without it using the quick reference.
6
+ allowed-tools: Read Write Bash(mdeck:*) Bash(npm root:*) Bash(ls:*)
7
+ metadata:
8
+ argument-hint: "[source files, audience, length, language]"
9
+ homepage: https://gh.tschieber.de/mdeck/
10
+ ---
11
+
12
+ You are writing a presentation for mdeck, a slide framework that turns one Markdown file into slides with swappable themes and palettes.
13
+
14
+ ## 1. Find the reference material
15
+
16
+ The mdeck docs are the source of truth for syntax, layouts and looks. Look for them in this order and read `authoring.md`, `themes.md` and `palettes.md` from the first place that exists:
17
+
18
+ 1. `docs/reference/` in the current folder (you are inside the mdeck repository).
19
+ 2. `$(npm root -g)/mdeck/docs/reference/` (mdeck is installed globally).
20
+
21
+ Read `examples/showcase/slides.md` from the same place as a complete working deck.
22
+
23
+ Then ask the installed mdeck what this deck can use, because a deck may ship its own layouts, themes and palettes in an `extensions/` folder:
24
+
25
+ ```sh
26
+ mdeck list layouts <deck>.md --json # every layout with its regions, settings and starter text
27
+ mdeck list <deck>.md # layouts, themes and palettes, built-in and local
28
+ ```
29
+
30
+ If `mdeck` is not installed, rely on the quick reference below.
31
+
32
+ ## 2. Quick reference
33
+
34
+ ```markdown
35
+ ---
36
+ theme: neue # theme id from `mdeck list themes`
37
+ palette: terra # optional: lagoon, swiss, cobalt, nordic, graphite, terra, forest, ember, neon, phosphor, pastel
38
+ appearance: light # optional: light or dark
39
+ meta:
40
+ title: "Talk title"
41
+ author: "Name"
42
+ organization: "FHNW"
43
+ date: "2026-09-16"
44
+ ---
45
+
46
+ ---
47
+ :::meta
48
+ layout: title
49
+ props:
50
+ image: ./img/cover.jpg
51
+ :::
52
+ # Headline
53
+ ## Subtitle
54
+
55
+ ---
56
+ :::meta
57
+ layout: chapter
58
+ number: 1
59
+ part: Part One
60
+ :::
61
+ # Chapter title
62
+
63
+ ---
64
+ # A content slide
65
+
66
+ - One point
67
+ - Another point
68
+
69
+ :::notes
70
+ What to say, what to skip, where to pause.
71
+ :::
72
+
73
+ ---
74
+ :::meta
75
+ layout: split
76
+ props:
77
+ ratio: [1, 2]
78
+ :::
79
+ # Shared heading
80
+
81
+ :::slot left
82
+ Left column
83
+ :::
84
+
85
+ :::slot right
86
+ Right column
87
+ :::
88
+ ```
89
+
90
+ - Slides are separated by `---` on its own line. Settings go in a `:::meta` block at the top of a slide.
91
+ - Built-in layouts: `title`, `chapter`, `focus` (one big statement), `image-text`, `split`, `full-bleed-image`, and plain content slides without a `layout:`.
92
+ - Named areas use `:::slot name … :::`; the layout's regions and settings come from `mdeck list layouts --json`.
93
+ - `:::notes … :::` holds speaker notes. `:::steps … :::` reveals list items one at a time. `:::note`, `:::tip`, `:::important`, `:::warning` and `:::caution` are callouts (`mdeck check` warns about other names); for lectures, `:::definition`, `:::theorem`, `:::lemma`, `:::proof`, `:::example` and `:::remark`, numbered in the title (`::: theorem Theorem 2.4 (Lagrange)`). `:::columns … +++ … :::` makes columns inside a slide.
94
+ - Code fences get syntax highlighting; `$…$` and `$$…$$` render math.
95
+ - `<poll room="lunch" options="Mensa|Thai|Pizza" />` lets the audience vote on their phones through a QR code on the slide; each poll needs its own `room`. `<scale room="pace" min="1" max="5" low="Too slow" high="Too fast" />`, `<wordcloud room="mood" />` and `<question room="ask" />` ask for a rating, short words or open answers the same way. With several of them, put `<qrcode join />` (the deck's join code) on an early slide to show the QR code once, and add `qr="false"` to the questions. It works when the deck is presented with `mdeck run <deck>.md --network` or with a server set as `server:` in the deck settings.
96
+
97
+ ## 3. Write the deck
98
+
99
+ The request is the message that invoked this skill: usually source material to turn into a deck, plus audience, length and language. If any of those are missing and matter, ask once, then write a complete deck.
100
+
101
+ **Source material**
102
+ - Most requests point at existing material: a `.pptx` or `.key` deck, a PDF (slides, a paper, a report), a `.docx`, Markdown or plain-text notes, spreadsheets. Read all of it before writing. If the request names no files, look in the deck's folder and ask whether to use what is there.
103
+ - Reuse the material's pictures: copy the ones you use into `./img/` with descriptive names. If you cannot open a file, say so.
104
+ - The material is the content. Keep its argument, order, facts, numbers, examples, terminology and citations; do not add claims, data or examples it does not contain. Your job is the deck: one idea per slide, statement headings, fitting layouts, detail moved from crowded slides into the notes, and notes written from the material's own text.
105
+ - Follow the requested degree of faithfulness. "Keep my wording" means light edits only; "tighten" or a time limit means cutting, and the cuts go into the notes or into your summary, not silently away.
106
+ - When rebuilding an old deck, keep its sequence unless asked otherwise, split slides that carry several ideas, and turn text-heavy slides into a few points with the rest in notes.
107
+ - Without any material, write the content yourself from the brief, and say clearly that it needs checking.
108
+
109
+ **Structure**
110
+ - Start with the deck settings: pick a `theme` and, if it suits the subject, a `palette` from the lists you gathered; fill in `meta.title`, `meta.author`, `meta.organization`, `meta.date`. For a talk that is not in English, set `lang` (for example `lang: de`).
111
+ - The first slide is `layout: title` with an `h1` headline and an `h2` subtitle.
112
+ - Use `layout: chapter` slides to divide major sections. End with a closing focus or title slide.
113
+
114
+ **Content**
115
+ - One idea per slide; if a third bullet is tempting, make it a new slide.
116
+ - Headings are statements, not labels ("Tokens decouple design from content", not "Design tokens").
117
+ - Use `layout: focus` for principles, quotes and conclusions; `layout: split` to pair code or an image with an explanation; `layout: full-bleed-image` only when a strong photograph carries the point.
118
+ - Add speaker notes to every content slide: context, transitions, what to emphasise.
119
+ - When the brief asks for audience interaction, add one or two polls at natural pauses, not more, and say in the notes how to present them.
120
+
121
+ **Formatting**
122
+ - `*italic*` renders in the accent colour; use it for key terms, not decoration.
123
+ - Keep lists to three to five items; prefer a short bold label plus one sentence over long bullets.
124
+ - Reference pictures under `./img/` and say which files the user still needs to add.
125
+
126
+ ## 4. Check and hand over
127
+
128
+ Save the deck as a `.md` file named after the topic (for example `enzyme-kinetics.md`), then run:
129
+
130
+ ```sh
131
+ mdeck check <deck>.md
132
+ ```
133
+
134
+ Fix anything it reports. When you worked from source material, list what you left out or moved to notes, and anything you added that is not in the material. Finish by telling the user the two commands they will want next: `mdeck run <deck>.md` for the launch page (preview, presenting, editor, builds and checks), and `mdeck send <deck>.md` for a file to send around (a reader view with a PDF; notes are removed unless `--notes` is added).
135
+
136
+ ## 5. A new look: themes and palettes
137
+
138
+ When the user wants a look the built-in themes and palettes do not give (their institute's colours, a font, the style of a poster or picture), first run `mdeck themes search` (with a word or two): someone may have shared it, and `mdeck themes install <pack> <deck>.md` puts it beside the deck. Otherwise make it as an extension in `extensions/` beside the deck, never as styling on single slides. Read `extensions.md` from the reference folder first; it lists every setting.
139
+
140
+ - **Colours only: a palette.** `extensions/<id>/extension.toml` with `kind = "palette"`, and every colour role (`--bg`, `--surface`, `--ink`, `--ink-soft`, `--muted`, `--rule`, `--accent`, `--accent-2`, `--on-accent`) in both `[light]` and `[dark]`. Text colours must stay readable on `--bg` and `--surface` in both variants, because themes use the other variant for inverted slides.
141
+ - **Fonts, sizes, spacing or arrangement: a theme.** Copy the folder of the closest built-in theme (`assets/extensions/themes/<id>/` in the mdeck repository or in `$(npm root -g)/mdeck/`) to `extensions/<new-id>/`, change `id` and `title`, then its tokens and `styles.css`. A theme takes no colours of its own: it names its default `palette`, and the colours come from palettes.
142
+ - **Use it:** set `theme:` and `palette:` in the deck settings. `mdeck list <deck>.md` must show it as local, and `mdeck check <deck>.md` reports any mistake in its `extension.toml`.
143
+ - **Hand over:** tell the user to run `mdeck design <deck>.md` (or `mdeck design <folder>` when there is no deck yet). It shows the look on a sample deck with every kind of slide, light and dark, and lets them fine-tune colours, fonts and sizes there.
144
+
@@ -0,0 +1,49 @@
1
+ // Deck validation shared by `mdeck check` and the launch page: source
2
+ // diagnostics plus local files the deck refers to but that are missing.
3
+ import { existsSync, readFileSync } from 'node:fs'
4
+ import { resolve, dirname } from 'node:path'
5
+ import { drawingsDiagnostic } from './drawings.js'
6
+ import { parseSlides } from '../core/parseSlides.js'
7
+ import { validateDeck } from '../core/validateDeck.js'
8
+ import { manifestsOf } from '../extensions/discover.js'
9
+ import { paletteProblems } from '../extensions/contrast.js'
10
+ import { collectLocalAssetRefs } from './slidesPlugin.js'
11
+ import { componentFolders, isFolder } from './components.js'
12
+ import { inkFileFor, validateInk, normalizeInk, orphanIds } from '../core/ink.js'
13
+
14
+ export function checkDeck(slidesPath, registry, source = readFileSync(slidesPath, 'utf8')) {
15
+ const deck = parseSlides(source)
16
+ const diagnostics = validateDeck(deck, { layouts: manifestsOf(registry, 'layout'), themes: manifestsOf(registry, 'theme'), palettes: manifestsOf(registry, 'palette') })
17
+ for (const ref of collectLocalAssetRefs(source)) {
18
+ if (!existsSync(resolve(dirname(resolve(slidesPath)), ref))) diagnostics.push({ severity: 'error', code: 'missing-asset', message: `Missing local asset: ${ref}`, line: 1, column: 1 })
19
+ }
20
+ for (const folder of componentFolders(slidesPath, source).filter(folder => folder.source === 'shared')) {
21
+ if (!isFolder(folder.dir)) diagnostics.push({ severity: 'error', code: 'missing-components', message: `Components folder not found: ${folder.path} (${folder.dir})`, line: 1, column: 1 })
22
+ }
23
+ // The deck's own palettes: colours too close to read are worth knowing
24
+ // before the talk (the built-in ones are held to this by the tests).
25
+ for (const record of Object.values(registry.palettes)) {
26
+ if (record.source !== 'local') continue
27
+ for (const problem of paletteProblems(record.manifest)) diagnostics.push({ severity: 'warning', code: 'palette-contrast', message: `Palette "${record.id}", ${problem}`, line: 1, column: 1 })
28
+ }
29
+ // A theme or palette installed for this user only: the slide file needs it
30
+ // beside it to work on another computer.
31
+ const config = deck.deckConfig ?? {}
32
+ for (const [kind, id] of [['theme', config.theme], ['palette', config.palette]]) {
33
+ const record = id && registry[`${kind}s`][id]
34
+ if (record?.source === 'user') diagnostics.push({ severity: 'warning', code: 'user-extension', message: `The ${kind} "${id}" is installed only on this computer (${dirname(record.dir)}); copy it into the deck's extensions folder, for example with mdeck themes install, so the slide file works elsewhere`, line: 1, column: 1 })
35
+ }
36
+ // The deck's drawings file: readable, and only for slides that still exist.
37
+ const inkPath = inkFileFor(resolve(slidesPath))
38
+ const renamed = drawingsDiagnostic(slidesPath)
39
+ if (renamed) diagnostics.push(renamed)
40
+ if (existsSync(inkPath)) {
41
+ let raw = null
42
+ try { raw = JSON.parse(readFileSync(inkPath, 'utf8')) } catch (error) { diagnostics.push({ severity: 'error', code: 'invalid-ink', message: `The drawings file is not valid JSON: ${error.message}`, line: 1, column: 1 }) }
43
+ if (raw) {
44
+ for (const problem of validateInk(raw)) diagnostics.push({ severity: 'warning', code: 'invalid-ink', message: `Drawings file: ${problem.message}`, line: 1, column: 1 })
45
+ for (const id of orphanIds(normalizeInk(raw), deck.slides)) diagnostics.push({ severity: 'warning', code: 'ink-orphan', message: `The drawings file has drawings for slide "${id}", which is not in the deck`, line: 1, column: 1 })
46
+ }
47
+ }
48
+ return { deck, diagnostics }
49
+ }