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,27 @@
1
+ export const pages = [
2
+ { slug: 'index', title: 'Welcome to mdeck', group: 'Start here', file: 'welcome.md', description: 'Turn your existing slides, documents and notes into a deck with an AI assistant, then present and share it.', preview: 'first-talk' },
3
+ { slug: 'getting-started', title: 'Make your first presentation', group: 'Start here', file: 'getting-started.md', description: 'Set up mdeck and your AI assistant, hand over your material, and open the deck it makes.' },
4
+ { slug: 'claude-skill', title: 'Work with an AI assistant', group: 'Start here', source: '../reference/claude-skill.md', description: 'Set up Claude Code, Codex, Cursor, Copilot or Gemini, turn PowerPoint, PDF, Word or notes into a deck, and change it by asking.' },
5
+ { slug: 'writing', title: 'Read and adjust your slides', group: 'Make your presentation', file: 'writing.md', description: 'The simple marks in a slide file, so you can read what your assistant wrote and fix small things.' },
6
+ { slug: 'editing', title: 'Edit slides in your browser', group: 'Make your presentation', file: 'editing.md', description: 'Change text, layouts, colors and themes with a visual editor that saves to your slide file.' },
7
+ { slug: 'layouts', title: 'Choose a slide layout', group: 'Make your presentation', file: 'layouts.md', description: 'Choose a title slide, a big statement, a picture, or two columns.', preview: 'first-talk' },
8
+ { slug: 'pictures-and-video', title: 'Add pictures and video', group: 'Make your presentation', file: 'media.md', description: 'Put an image or a video into your talk and keep its files together.' },
9
+ { slug: 'appearance', title: 'Change the look', group: 'Make your presentation', file: 'appearance.md', description: 'Choose fonts and colors with themes and palettes.' },
10
+ { slug: 'theme-repository', title: 'Install or share a theme', group: 'Make your presentation', file: 'theme-repository.md', description: 'Themes and palettes other people made, installed with one command, and how to share your own.' },
11
+ { slug: 'notes-and-presenting', title: 'Add notes and present', group: 'Present and share', file: 'presenting.md', description: 'See your notes, reveal points one at a time, and open the audience screen.' },
12
+ { slug: 'audience', title: 'Ask your audience', group: 'Present and share', file: 'audience.md', description: 'Polls that people answer on their phones, with live results on the slide.' },
13
+ { slug: 'drawing', title: 'Draw on your slides', group: 'Present and share', file: 'drawing.md', description: 'Mark up slides with a pen or an iPad, live or ahead of time, and keep the drawings with the talk.' },
14
+ { slug: 'sharing', title: 'Send, host or print your slides', group: 'Present and share', file: 'sharing.md', description: 'Make a shareable folder, a single file, or a PDF.' },
15
+ { slug: 'more-content', title: 'Tables, tips, and more', group: 'Keep learning', file: 'more-content.md', description: 'Add tables, helpful callouts, QR codes, formulas, and code examples.' },
16
+ { slug: 'reusable-layouts', title: 'Use a reusable layout', group: 'Keep learning', file: 'reusable-layouts.md', description: 'Use a layout someone has made for you, including the comparison example.', preview: 'custom-layouts' },
17
+ { slug: 'commands', title: 'Command guide', group: 'Help and reference', file: 'commands.md', description: 'What each mdeck command does and when to use it.' },
18
+ { slug: 'views', title: 'Views, commands and servers', group: 'Help and reference', file: 'views.md', description: 'Which view is which, how to switch, and what needs a server.' },
19
+ { slug: 'troubleshooting', title: 'When something goes wrong', group: 'Help and reference', file: 'troubleshooting.md', description: 'Find a missing picture, fix a typing mistake, or recover a command that will not run.' },
20
+ { slug: 'custom-layouts', title: 'Create a custom layout', group: 'Advanced customization', source: '../reference/layouts.md', description: 'The files behind a layout, its content areas, and its settings, as an assistant or a JavaScript author writes them.' },
21
+ { slug: 'components', title: 'Create interactive content', group: 'Advanced customization', file: 'components.md', description: 'Interactive slide content as Preact components, written by your assistant or by hand.' },
22
+ { slug: 'theme-authoring', title: 'Create a theme or palette', group: 'Advanced customization', file: 'theme-authoring.md', description: 'The files behind a visual identity for a whole deck, as an assistant or a CSS author writes them.' },
23
+ { slug: 'extensions', title: 'Extension manifests', group: 'Advanced customization', source: '../reference/extensions.md', description: 'The one manifest format shared by templates, themes and palettes.' },
24
+ { slug: 'source-model', title: 'Build tools around mdeck', group: 'Advanced customization', source: '../reference/structured-slides.md', description: 'The source-preserving document model and editing helpers for tool authors.' },
25
+ ]
26
+
27
+ export const pageFor = slug => pages.find(page => page.slug === slug)
@@ -0,0 +1,58 @@
1
+ import { createServer } from 'node:http'
2
+ import { readFile, mkdtemp, rm, stat } from 'node:fs/promises'
3
+ import { tmpdir } from 'node:os'
4
+ import { resolve, relative, extname, isAbsolute } from 'node:path'
5
+ import { spawn } from 'node:child_process'
6
+ import { buildDocs } from './build.js'
7
+ import { pageFor } from './pages.js'
8
+
9
+ const MIME = { '.html': 'text/html; charset=utf-8', '.css': 'text/css; charset=utf-8', '.js': 'text/javascript; charset=utf-8', '.json': 'application/json', '.svg': 'image/svg+xml', '.webp': 'image/webp', '.png': 'image/png', '.md': 'text/plain; charset=utf-8' }
10
+
11
+ export function docsHandler(root) {
12
+ return async (request, response) => {
13
+ if (!['GET', 'HEAD'].includes(request.method)) { response.writeHead(405, { Allow: 'GET, HEAD' }); response.end(); return }
14
+ try {
15
+ const pathname = decodeURIComponent(new URL(request.url, 'http://localhost').pathname)
16
+ const file = resolve(root, '.' + (pathname === '/' ? '/index.html' : pathname))
17
+ const rel = relative(root, file)
18
+ if (rel.startsWith('..') || isAbsolute(rel) || !(await stat(file)).isFile()) throw new Error('Not found')
19
+ const content = await readFile(file)
20
+ response.writeHead(200, { 'Content-Type': MIME[extname(file)] ?? 'application/octet-stream', 'Content-Length': content.length, 'X-Content-Type-Options': 'nosniff', 'Cache-Control': 'no-cache' })
21
+ response.end(request.method === 'HEAD' ? undefined : content)
22
+ } catch {
23
+ response.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' })
24
+ response.end(request.method === 'HEAD' ? undefined : '<!doctype html><html lang="en"><title>Guide not found</title><h1>That guide could not be found.</h1><p><a href="/">Go back to the mdeck guide.</a></p></html>')
25
+ }
26
+ }
27
+ }
28
+
29
+ export async function startDocs({ page = 'index', port = 4174, open = true } = {}) {
30
+ if (!pageFor(page)) throw new Error(`There is no guide named "${page}". Try "getting-started", "sharing", or "commands".`)
31
+ const outDir = await mkdtemp(resolve(tmpdir(), 'mdeck-docs-'))
32
+ let server
33
+ try {
34
+ await buildDocs({ outDir })
35
+ server = createServer(docsHandler(outDir))
36
+ for (let attempt = 0; ; attempt++) {
37
+ try {
38
+ await new Promise((resolve, reject) => { server.once('error', reject); server.listen(port, '127.0.0.1', () => { server.removeListener('error', reject); resolve() }) })
39
+ break
40
+ } catch (error) {
41
+ if (error.code !== 'EADDRINUSE' || attempt >= 20 || port >= 65535) throw error
42
+ port++
43
+ }
44
+ }
45
+ const url = `http://127.0.0.1:${server.address().port}/${page === 'index' ? '' : `${page}.html`}`
46
+ if (open) {
47
+ const [command, args] = process.platform === 'darwin' ? ['open', [url]] : process.platform === 'win32' ? ['rundll32', ['url.dll,FileProtocolHandler', url]] : ['xdg-open', [url]]
48
+ const opener = spawn(command, args, { stdio: 'ignore' })
49
+ opener.on('error', () => console.log(`Open ${url} in your browser.`))
50
+ opener.unref()
51
+ }
52
+ return { server, url, outDir, async close() { await new Promise(resolve => server.close(resolve)); await rm(outDir, { recursive: true, force: true }) } }
53
+ } catch (error) {
54
+ server?.close()
55
+ await rm(outDir, { recursive: true, force: true })
56
+ throw error
57
+ }
58
+ }
@@ -0,0 +1,35 @@
1
+ schema = 1
2
+ kind = "layout"
3
+ id = "comparison"
4
+ title = "Side-by-side comparison"
5
+ description = "Two options next to each other, with one of them optionally highlighted."
6
+
7
+ # layout.jsx, styles.css and starter.md are picked up from this folder by default.
8
+
9
+ [regions.body]
10
+ description = "Shared heading and introduction"
11
+
12
+ [regions.left]
13
+ required = true
14
+ description = "First option"
15
+
16
+ [regions.right]
17
+ required = true
18
+ description = "Second option"
19
+
20
+ [properties.ratio]
21
+ type = "array"
22
+ description = "Relative widths of the two options"
23
+ minItems = 2
24
+ maxItems = 2
25
+ default = [1, 1]
26
+
27
+ [properties.ratio.items]
28
+ type = "number"
29
+ minimum = 0.01
30
+
31
+ [properties.emphasis]
32
+ type = "string"
33
+ description = "Which option gets the highlighted border"
34
+ enum = ["none", "left", "right"]
35
+ default = "none"
@@ -0,0 +1,15 @@
1
+ import { h } from 'preact'
2
+ import { MarkdownRegion } from 'mdeck/layout'
3
+
4
+ export default function Comparison({ regions, props }) {
5
+ return <div class="slide-body comparison-body">
6
+ <MarkdownRegion region={regions.body} />
7
+ <div class="comparison-options" style={{ gridTemplateColumns: `${props.ratio[0]}fr ${props.ratio[1]}fr` }}>
8
+ {['left', 'right'].map(name => <MarkdownRegion
9
+ key={name}
10
+ region={regions[name]}
11
+ class={`comparison-option${props.emphasis === name ? ' is-emphasized' : ''}`}
12
+ />)}
13
+ </div>
14
+ </div>
15
+ }
@@ -0,0 +1,17 @@
1
+ :::meta
2
+ layout: comparison
3
+ props:
4
+ ratio: [1, 1]
5
+ emphasis: none
6
+ :::
7
+ # Compare two options
8
+
9
+ :::slot left
10
+ ## First option
11
+ Describe it here.
12
+ :::
13
+
14
+ :::slot right
15
+ ## Second option
16
+ Describe it here.
17
+ :::
@@ -0,0 +1,4 @@
1
+ .slide--comparison .comparison-body { gap: 40px; }
2
+ .slide--comparison .comparison-options { display: grid; gap: 40px; min-height: 0; }
3
+ .slide--comparison .comparison-option { min-width: 0; padding: 28px; border: 2px solid var(--rule); }
4
+ .slide--comparison .comparison-option.is-emphasized { border-color: var(--accent); }
@@ -0,0 +1,60 @@
1
+ ---
2
+ theme: terminal
3
+ meta:
4
+ title: Deck-local layouts
5
+ ---
6
+
7
+ ---
8
+ :::meta
9
+ layout: comparison
10
+ id: deployment-options
11
+ props:
12
+ ratio: [2, 3]
13
+ emphasis: right
14
+ :::
15
+ # Deployment options
16
+
17
+ :::slot left
18
+ ## Directory bundle
19
+
20
+ - Separate media files
21
+ - Suitable for large videos
22
+ :::
23
+
24
+ :::slot right
25
+ ## Single HTML file
26
+
27
+ :::tip
28
+ Useful when transferring one file is operationally important.
29
+ :::
30
+
31
+ - All local assets embedded
32
+ - Larger video payloads
33
+ :::
34
+
35
+ :::notes
36
+ This layout is loaded from extensions/comparison beside this deck.
37
+ :::
38
+
39
+ ---
40
+ :::meta
41
+ layout: split
42
+ id: built-in-regions
43
+ props:
44
+ ratio: [1, 2]
45
+ :::
46
+ # Built-in layouts use the same region model
47
+
48
+ :::slot left
49
+ ```js
50
+ const template = 'comparison'
51
+ ```
52
+ :::
53
+
54
+ :::slot right
55
+ :::steps
56
+ - Define a manifest.
57
+ - Write a Preact layout.
58
+ - Use it from Markdown.
59
+ :::
60
+ :::
@@ -0,0 +1,127 @@
1
+ ---
2
+ theme: duet
3
+ meta:
4
+ title: "Ask the room"
5
+ author: "Tilman Schieber"
6
+ organization: "FHNW"
7
+ date: "2026-09-30"
8
+ ---
9
+
10
+ ---
11
+ :::meta
12
+ layout: title
13
+ :::
14
+ # Ask the room.
15
+ ## Live questions in a plain slide file.
16
+
17
+ :::notes
18
+ Start this deck with `mdeck run slides.md --network` so phones in the same network can answer.
19
+
20
+ The deck shows every kind of question mdeck has: a poll, a scale, a word cloud and open answers. The QR code appears once, on the next slide.
21
+ :::
22
+
23
+ ---
24
+ # Take out your phone.
25
+
26
+ <qrcode join />
27
+
28
+ :::notes
29
+ Leave this up until most people have scanned. The code is the same for the whole talk: phones that joined now follow along, and each question appears on them when its slide comes up.
30
+
31
+ Come back to this slide for latecomers, or leave the join code on the last question too.
32
+ :::
33
+
34
+ ---
35
+ :::meta
36
+ title: "Poll: how do you make slides?"
37
+ :::
38
+ # How do you make slides today?
39
+
40
+ <poll room="tools" options="PowerPoint|Keynote|Google Slides|LaTeX Beamer|Markdown" qr="false" />
41
+
42
+ :::notes
43
+ A poll: one button per answer. Give people half a minute and read out the leader once the bars settle.
44
+
45
+ Anyone can change their answer: only the latest vote from each phone counts.
46
+
47
+ Before the talk, hover over the results and click Reset to clear test votes.
48
+ :::
49
+
50
+ ---
51
+ :::meta
52
+ title: "Scale: Markdown"
53
+ :::
54
+ # How well do you know Markdown?
55
+
56
+ <scale room="markdown" min="1" max="5" low="Never used it" high="Every day" qr="false" />
57
+
58
+ :::notes
59
+ A scale: phones show the numbers from 1 to 5, the slide counts each one and shows the average.
60
+
61
+ A high average means the rest of the talk can go faster.
62
+ :::
63
+
64
+ ---
65
+ :::meta
66
+ title: "Word cloud: slides"
67
+ :::
68
+ # One word for your last presentation?
69
+
70
+ <wordcloud room="mood" placeholder="One word" qr="false" />
71
+
72
+ :::notes
73
+ A word cloud: people may send as many words as they like. The more often a word comes in, the larger it gets, packed around the middle; capitals do not matter.
74
+
75
+ Pick out the largest word and one surprising small one.
76
+ :::
77
+
78
+ ---
79
+ :::meta
80
+ title: "Open question"
81
+ :::
82
+ # What would you like to ask?
83
+
84
+ <question room="ask" placeholder="Your question" qr="false" />
85
+
86
+ :::notes
87
+ Open answers: the newest eight appear as cards, and people can send several.
88
+
89
+ Answer one or two now, and promise to go through the rest afterwards; the room keeps them until you reset it.
90
+ :::
91
+
92
+ ---
93
+ # Each question is one line.
94
+
95
+ ```markdown
96
+ <qrcode join />
97
+ <poll room="tools" options="PowerPoint|Keynote|Markdown" />
98
+ <scale room="markdown" min="1" max="5" low="Never" high="Daily" />
99
+ <wordcloud room="mood" />
100
+ <question room="ask" placeholder="Your question" />
101
+ ```
102
+
103
+ - **room** — a short name, different for every question in the deck.
104
+ - **qr="false"** — leave out the code when `<qrcode join />` showed it earlier.
105
+ - **question** — optional; without it, phones show the slide heading.
106
+
107
+ :::notes
108
+ Point at the lines that made the previous slides. That is all the author writes.
109
+
110
+ The QR code takes the slide's colours, so it fits every theme; phone cameras read light-on-dark codes too.
111
+ :::
112
+
113
+ ---
114
+ # Try it on your own computer.
115
+
116
+ ```sh
117
+ mdeck run slides.md --network
118
+ ```
119
+
120
+ - **Same network** — phones must be able to reach your computer.
121
+ - **Lecture hall** — run `mdeck server` on a web server; the slides stay on your laptop.
122
+
123
+ :::notes
124
+ For a lecture hall, run `mdeck server` on a web server once and point the deck's `server` setting at it. The phones only talk to that server; the slides never leave this laptop. The "Ask your audience" guide has the details.
125
+
126
+ Many university networks keep devices apart. If phones cannot open the page, use a phone hotspot or a server on the internet.
127
+ :::
@@ -0,0 +1,19 @@
1
+ {
2
+ "version": 1,
3
+ "width": 1920,
4
+ "height": 1080,
5
+ "slides": {
6
+ "the-tools-your-field-uses-are-written-in": [
7
+ {"id":"63zmhi:muvocmul6","tool":"pen","color":"#f59e0b","size":6,"points":[[531,278,0.5],[502,280,0.5],[481,280,0.5],[482,282,0.5],[493,284,0.5],[532,286,0.5],[859,286,0.5],[925,293,0.5],[977,298,0.5],[1013,302,0.5],[1146,312,0.5],[1204,317,0.5],[1281,322,0.5],[1299,324,0.5],[1451,332,0.5],[1470,334,0.5],[1507,336,0.5],[1525,338,0.5],[1544,339,0.5],[1579,343,0.5],[1597,344,0.5],[1682,355,0.5],[1747,360,0.5]]}
8
+ ],
9
+ "variables-and-data-types": [
10
+ {"id":"63zmhi:muvocong7","tool":"pen","color":"#f59e0b","size":6,"points":[[734,266,0.5],[699,289,0.5],[690,298,0.5],[678,315,0.5],[673,326,0.5],[665,347,0.5],[659,369,0.5],[658,382,0.5],[658,439,0.5],[662,450,0.5],[677,470,0.5],[686,481,0.5],[706,498,0.5],[718,507,0.5],[742,519,0.5],[753,524,0.5],[765,528,0.5],[777,529,0.5],[805,529,0.5],[812,528,0.5],[818,521,0.5],[823,512,0.5],[827,502,0.5],[830,490,0.5],[836,451,0.5],[838,412,0.5],[838,369,0.5],[837,362,0.5],[835,356,0.5],[831,350,0.5],[826,345,0.5],[811,342,0.5],[805,343,0.5],[793,343,0.5],[787,344,0.5],[781,347,0.5],[775,352,0.5],[760,377,0.5],[755,393,0.5],[755,420,0.5],[760,429,0.5],[768,432,0.5],[787,436,0.5],[884,436,0.5],[900,435,0.5],[915,432,0.5],[931,428,0.5],[961,416,0.5],[975,409,0.5],[986,401,0.5],[999,393,0.5],[1020,377,0.5],[1043,355,0.5],[1052,343,0.5],[1055,335,0.5],[1055,332,0.5],[1054,332,0.5],[1051,337,0.5],[1046,348,0.5],[1045,354,0.5],[1045,392,0.5],[1048,398,0.5],[1058,408,0.5],[1071,416,0.5],[1080,417,0.5],[1096,421,0.5],[1149,421,0.5],[1158,419,0.5],[1175,412,0.5],[1199,393,0.5],[1217,377,0.5],[1232,360,0.5],[1247,345,0.5],[1251,342,0.5],[1263,336,0.5],[1275,332,0.5],[1282,331,0.5],[1324,331,0.5],[1347,338,0.5],[1396,363,0.5],[1411,368,0.5],[1424,371,0.5],[1440,373,0.5],[1456,373,0.5]]}
11
+ ],
12
+ "variables-store-data": [
13
+ {"id":"63zmhi:muvocqi48","tool":"pen","color":"#f59e0b","size":6,"points":[[831,368,0.5],[793,362,0.5],[788,366,0.5],[793,375,0.5],[793,437,0.5],[798,461,0.5],[803,471,0.5],[811,483,0.5],[820,491,0.5],[830,499,0.5],[841,507,0.5],[854,513,0.5],[883,519,0.5],[898,521,0.5],[913,522,0.5],[1010,522,0.5],[1026,519,0.5],[1053,510,0.5],[1075,493,0.5],[1083,484,0.5],[1091,472,0.5],[1098,460,0.5],[1104,445,0.5],[1110,416,0.5],[1112,385,0.5],[1111,370,0.5],[1111,344,0.5],[1109,322,0.5],[1106,313,0.5],[1092,300,0.5],[1080,293,0.5],[1059,290,0.5],[1057,291,0.5],[1052,291,0.5],[1051,292,0.5],[1051,331,0.5],[1060,345,0.5],[1076,360,0.5],[1084,366,0.5],[1117,383,0.5],[1129,387,0.5],[1140,390,0.5],[1164,392,0.5],[1186,392,0.5],[1195,391,0.5],[1204,391,0.5],[1211,384,0.5],[1216,375,0.5],[1220,364,0.5],[1225,340,0.5],[1228,293,0.5],[1228,251,0.5],[1228,255,0.5],[1230,258,0.5],[1235,268,0.5],[1240,273,0.5],[1258,291,0.5],[1282,310,0.5],[1299,321,0.5],[1322,330,0.5],[1334,334,0.5],[1360,340,0.5],[1387,344,0.5],[1414,345,0.5],[1499,345,0.5],[1510,344,0.5],[1520,340,0.5],[1547,331,0.5],[1570,325,0.5],[1587,323,0.5],[1641,323,0.5],[1661,328,0.5],[1718,352,0.5],[1742,360,0.5],[1755,363,0.5]]}
14
+ ],
15
+ "four-types-cover-most-biology-data": [
16
+ {"id":"63zmhi:muvocsxn9","tool":"pen","color":"#f59e0b","size":6,"points":[[1110,277,0.5],[1072,262,0.5],[1059,259,0.5],[1050,260,0.5],[1026,256,0.5],[1002,254,0.5],[935,254,0.5],[923,255,0.5],[900,261,0.5],[851,281,0.5],[838,289,0.5],[824,297,0.5],[795,314,0.5],[779,323,0.5],[747,342,0.5],[731,350,0.5],[716,359,0.5],[669,382,0.5],[654,390,0.5],[642,395,0.5],[592,422,0.5],[587,427,0.5],[583,431,0.5],[582,434,0.5],[582,445,0.5],[591,455,0.5],[610,464,0.5],[622,467,0.5],[662,477,0.5],[679,479,0.5],[716,481,0.5],[889,481,0.5],[907,479,0.5],[922,475,0.5],[948,465,0.5],[958,459,0.5],[964,453,0.5],[970,444,0.5],[974,437,0.5],[975,427,0.5],[975,393,0.5],[968,367,0.5],[962,354,0.5],[941,328,0.5],[919,305,0.5],[896,284,0.5],[883,275,0.5],[856,262,0.5],[841,257,0.5],[814,252,0.5],[800,252,0.5],[787,251,0.5],[773,252,0.5],[749,252,0.5],[738,256,0.5],[728,263,0.5],[711,278,0.5],[697,296,0.5],[687,314,0.5],[684,324,0.5],[682,343,0.5],[683,352,0.5],[683,369,0.5],[686,379,0.5],[699,396,0.5],[721,413,0.5],[745,427,0.5],[773,438,0.5],[803,446,0.5],[834,453,0.5],[865,455,0.5],[881,455,0.5],[896,456,0.5],[910,455,0.5],[939,455,0.5],[966,450,0.5],[980,444,0.5],[1003,433,0.5],[1022,418,0.5],[1033,412,0.5],[1040,404,0.5],[1055,390,0.5],[1066,377,0.5],[1073,367,0.5],[1081,356,0.5],[1082,353,0.5],[1085,348,0.5],[1091,344,0.5],[1132,344,0.5],[1145,351,0.5],[1161,360,0.5],[1190,376,0.5],[1212,384,0.5],[1237,392,0.5],[1279,399,0.5],[1310,401,0.5],[1498,401,0.5],[1509,400,0.5],[1559,398,0.5],[1568,396,0.5],[1631,396,0.5],[1649,400,0.5],[1654,403,0.5],[1664,407,0.5],[1684,412,0.5],[1690,413,0.5],[1707,414,0.5],[1725,414,0.5]]}
17
+ ]
18
+ }
19
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 1,
3
+ "width": 1920,
4
+ "height": 1080,
5
+ "slides": {}
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 1,
3
+ "width": 1920,
4
+ "height": 1080,
5
+ "slides": {}
6
+ }