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,795 @@
1
+ # Authoring slides
2
+
3
+ Decks are plain Markdown files. You can version them in git, open them in any text editor, and diff them like code.
4
+
5
+ ---
6
+
7
+ ## Deck structure
8
+
9
+ A deck is a single `.md` file. The first block is the **deck frontmatter** — it configures the whole presentation. Each subsequent `---` separator starts a new slide.
10
+
11
+ ```markdown
12
+ ---
13
+ theme: neue
14
+ palette: swiss
15
+ meta:
16
+ title: "My Talk"
17
+ author: "Jane Smith"
18
+ organization: "Acme"
19
+ date: "2026-05-19"
20
+ logo: ./img/logo.png
21
+ width: 1920
22
+ height: 1080
23
+ ---
24
+
25
+ ---
26
+ layout: title
27
+ ---
28
+ # First slide.
29
+ ## A short subtitle.
30
+
31
+ ---
32
+ # Second slide.
33
+
34
+ Some body text here. No frontmatter needed for plain content slides.
35
+ ```
36
+
37
+ Each `---` line starts a new slide. Frontmatter is only needed when you want a specific layout or slide metadata (`section`, `note`, `image`, etc.). Plain content slides can follow the `---` separator directly with their markdown content.
38
+
39
+ ### Deck frontmatter fields
40
+
41
+ | Field | Default | Description |
42
+ |---|---|---|
43
+ | `theme` | `neue` | Theme name |
44
+ | `palette` | _(theme default)_ | Colour palette: `lagoon`, `swiss`, `cobalt`, `nordic`, `graphite`, `terra`, `forest`, `ember`, `neon`, `phosphor`, `pastel`, or one of your own |
45
+ | `appearance` | _(theme default)_ | `light` or `dark`: which variant of the palette the slides use |
46
+ | `meta.title` | — | Deck title (shown in footer) |
47
+ | `meta.author` | — | Author name (shown in footer) |
48
+ | `meta.organization` | — | Organization name (shown in header) |
49
+ | `meta.date` | — | Date string (shown in footer) |
50
+ | `meta.logo` | — | Path to logo image |
51
+ | `width` / `height` | `1920` / `1080` | Slide canvas dimensions in px |
52
+ | `show.organization` | `title` | When to show the organization name: `title`, `all`, or `none` |
53
+ | `show.author` | `title` | When to show the author and date line: `title`, `all`, or `none` |
54
+ | `show.numbers` | `slides` | Slide numbers: `slides` (all except title), `all`, or `none` |
55
+ | `show.sections` | `all` | Whether to show section labels in the header: `all` or `none` |
56
+ | `lang` | `en` | Language of the deck, such as `en`, `de` or `de-CH`: sets the page language and the words the audience sees (see below) |
57
+ | `labels` | — | Replace single words the audience sees (see below) |
58
+ | `callouts` | — | Override individual callout titles (see below) |
59
+ | `server` | the dev server | Your own server for polls, other audience activities and presenting from an iPad, e.g. `https://rooms.example.org` |
60
+ | `session.id` | from the title | Name the session code is derived from |
61
+ | `session.code` | from `session.id` | The session code itself, 4 to 8 digits; phones join at `<server>/<code>` |
62
+ | `components` | — | Extra folders of Preact components shared between decks, relative to the deck or starting with `~/` |
63
+ | `params` | — | Theme-specific color/font overrides (see below) |
64
+ | `reader.themes` | `true` | Whether the reader view offers a switch between light and dark (see below) |
65
+ | `reader.notes` | `false` | Whether the reader view shows speaker notes under each slide in Read mode |
66
+
67
+ ### Theme params
68
+
69
+ Some themes expose their fonts as settings. Set them under `params:`:
70
+
71
+ ```yaml
72
+ params:
73
+ fontDisplay: "Georgia, serif"
74
+ ```
75
+
76
+ Available params depend on the theme; `mdeck list themes` shows them. Colours
77
+ are not params: they come from the palette.
78
+
79
+ ---
80
+
81
+ ### Reader settings
82
+
83
+ ```yaml
84
+ reader:
85
+ themes: false # no light/dark switch in the reader view
86
+ notes: true # show speaker notes under each slide in Read mode
87
+ ```
88
+
89
+ Views are chosen with one address parameter: `?view=deck`, `?view=reader`,
90
+ `?view=presenter` or `?view=audience`. `mdeck send` produces a file that opens
91
+ in the reader view (outline, Read mode, a light/dark switch, PDF download).
92
+ The file carries only the deck's own theme and palette, with that theme's
93
+ fonts, so readers see the deck as it was made; they can switch between its
94
+ light and dark version. `reader.themes: false` removes that switch too.
95
+ `mdeck build --reader` bundles the same way. Speaker notes are
96
+ removed from `mdeck send` files unless the command uses `--notes`, and even
97
+ then the reader shows them only when `reader.notes` is `true`, so a file can
98
+ carry notes for the presenter view without showing them to readers. The same
99
+ view is reachable in any build through `?view=reader`.
100
+
101
+ ## Available themes
102
+
103
+ | Key | Description |
104
+ |---|---|
105
+ | `neue` | Swiss style: Inter Tight and Inter, large flush-left type, a rule across the top, square accent markers, red on white |
106
+ | `aurora` | Northern lights: Plus Jakarta Sans, curtains of light in the palette's accents, night-sky chapter slides, frosted glass |
107
+ | `duet` | Two voices: heavy Zilla Slab headings, DM Sans body; the two accents take turns (split fields, diagonal chapters, alternating markers) |
108
+ | `editorial` | Magazine spread: Newsreader headlines, Lora body, drop caps and pull quotes |
109
+ | `fhnw` | The FHNW corporate design: Inter, black on white, yellow accent areas |
110
+ | `terminal` | A terminal session: JetBrains Mono, headings at a prompt, a blinking cursor on the title, log-line callouts, a tmux status bar; dark by default |
111
+ | `academic` | A lecture: Source Sans and Source Serif, compact type with the heading fixed at the top and the content centred below, theorem and definition blocks, booktabs tables, a footnote rule |
112
+ | `sketch` | A sketchbook: Caveat and Patrick Hand on dotted paper, marker scribbles, circled numbers, sticky-note callouts, taped photos; a chalkboard in the dark |
113
+
114
+ `mdeck list <deck>.md` lists these together with any themes kept beside
115
+ the deck.
116
+
117
+ ---
118
+
119
+ ## Available palettes
120
+
121
+ Each palette has a light and a dark variant; `appearance:` picks one.
122
+
123
+ | Key | Light | Dark |
124
+ |---|---|---|
125
+ | `lagoon` | Teal on warm stone | Bright teal on teal-black |
126
+ | `swiss` | White, black, signal red (neue's default) | Black, white, red |
127
+ | `cobalt` | White, ultramarine, orange (duet's default) | Deep navy, luminous blue |
128
+ | `nordic` | Ice grey, navy, steel blue | Polar night, ice blue |
129
+ | `graphite` | Black and white, steel blue | Charcoal, light steel blue |
130
+ | `terra` | Cream, navy, brick red (editorial's default) | Navy, cream, coral |
131
+ | `forest` | Deep green, moss, ochre | Forest night, light green |
132
+ | `ember` | Sand, espresso, orange | Dark brown, glowing orange |
133
+ | `neon` | White, violet, magenta (aurora's default) | Black, neon violet and pink |
134
+ | `phosphor` | Paper printout, green, ochre (terminal's default) | Phosphor green on black, amber |
135
+ | `pastel` | Catppuccin Latte: mauve and peach (sketch's default) | Catppuccin Mocha: pastel mauve and peach |
136
+
137
+ The FHNW theme uses its own palette, `brand`, and no other.
138
+
139
+ ---
140
+
141
+ ## Slide frontmatter
142
+
143
+ Each slide can have its own frontmatter block immediately after the `---` separator. Frontmatter is only needed when a slide has specific metadata — layout, image, explicit section label, etc. Plain content slides can omit it entirely.
144
+
145
+ ```markdown
146
+ ---
147
+ layout: chapter
148
+ number: 1
149
+ part: Part One
150
+ description: A short description shown under the title.
151
+ ---
152
+ # Chapter title.
153
+ ```
154
+
155
+ ### Common slide fields
156
+
157
+ | Field | Description |
158
+ |---|---|
159
+ | `layout` | Slide layout (see below) |
160
+ | `section` | Section label shown in the slide header (auto-propagated — see below) |
161
+ | `title` | Name in the outline and reader navigation, for slides without a heading (not shown on the slide) |
162
+
163
+ ### Section labels
164
+
165
+ The `section:` field labels the top-right corner of the slide header. It auto-propagates: once set on a slide, all subsequent slides inherit it until a new `section:` is declared or a new chapter starts.
166
+
167
+ `chapter` slides automatically set the current section to their `part:` value, so slides within a chapter inherit the chapter name without needing explicit `section:` fields.
168
+
169
+ ```markdown
170
+ ---
171
+ layout: chapter
172
+ number: 1
173
+ part: Methodology
174
+ ---
175
+ # Chapter title.
176
+
177
+ ---
178
+ # First slide.
179
+ This slide automatically shows "Methodology" in the header.
180
+
181
+ ---
182
+ section: Results
183
+ ---
184
+ # Second slide.
185
+ This slide shows "Results" — and so does every slide after it until the next chapter or section override.
186
+ ```
187
+
188
+ ### Speaker notes
189
+
190
+ Speaker notes are only visible in the presenter view. Use a `:::notes` fenced block anywhere in the slide body — typically at the end:
191
+
192
+ ```markdown
193
+ ---
194
+ layout: focus
195
+ eyebrow: Key point
196
+ ---
197
+ # The main statement.
198
+
199
+ :::notes
200
+ This is the central idea. Pause here.
201
+
202
+ - Bullet one
203
+ - Bullet two
204
+ :::
205
+ ```
206
+
207
+ Notes support full Markdown and are written only in `:::notes` blocks in the slide body.
208
+
209
+ ---
210
+
211
+ ## Layouts
212
+
213
+ ### `title` — Opening slide
214
+
215
+ Centered headline and subtitle. The `h1` becomes the display headline; `h2` becomes the italic subtitle.
216
+
217
+ ```markdown
218
+ ---
219
+ layout: title
220
+ ---
221
+ # A clean presentation framework.
222
+ ## Markdown-driven slides with *swappable* design systems.
223
+ ```
224
+
225
+ ---
226
+
227
+ ### `chapter` — Section divider
228
+
229
+ Ghost numeral, a short accent rule, chapter label, title, and optional description.
230
+
231
+ ```markdown
232
+ ---
233
+ layout: chapter
234
+ number: 1
235
+ part: Part One
236
+ description: How content, design, and components fit together.
237
+ ---
238
+ # The three-part architecture.
239
+ ```
240
+
241
+ | Field | Description |
242
+ |---|---|
243
+ | `number` | The large ghost numeral |
244
+ | `part` | Small uppercase label above the title |
245
+ | `description` | Italic description below the title |
246
+
247
+ ---
248
+
249
+ ### `focus` — Statement or quote
250
+
251
+ Left-aligned large statement with an optional eyebrow label and attribution line.
252
+
253
+ ```markdown
254
+ ---
255
+ layout: focus
256
+ eyebrow: Core principle
257
+ attribution: Tilman Schieber
258
+ ---
259
+ # Separate *content* from *design* from behaviour.
260
+ ```
261
+
262
+ | Field | Description |
263
+ |---|---|
264
+ | `eyebrow` | Small uppercase label above the statement |
265
+ | `attribution` | Small italic credit below |
266
+
267
+ ---
268
+
269
+ ### `image-text` — Image beside text
270
+
271
+ Left image pane, right text pane.
272
+
273
+ ```markdown
274
+ ---
275
+ layout: image-text
276
+ image: ./img/diagram.jpg
277
+ section: Architecture
278
+ ---
279
+ ## Tokens all the way down.
280
+
281
+ Change one value and the *whole deck* repaints.
282
+ ```
283
+
284
+ | Field | Description |
285
+ |---|---|
286
+ | `image` | Path to image file |
287
+ | `section` | Header label |
288
+
289
+ ---
290
+
291
+ ### `full-bleed-image` — Photograph edge-to-edge
292
+
293
+ The `h1` appears as a caption over a dark gradient at the bottom of the image.
294
+
295
+ ```markdown
296
+ ---
297
+ layout: full-bleed-image
298
+ image: ./img/photo.jpg
299
+ ---
300
+ # A caption over the photograph.
301
+ ```
302
+
303
+ ---
304
+
305
+ ### `split` — Component beside text
306
+
307
+ The first block element in the body (any component, image, or paragraph) goes to the left pane; everything else flows to the right.
308
+
309
+ ```markdown
310
+ ---
311
+ layout: split
312
+ ---
313
+ ```js
314
+ const fib = n => n < 2 ? n : fib(n - 1) + fib(n - 2)
315
+ ```
316
+
317
+ # Split layout.
318
+ The code block goes left. This heading and text go right.
319
+ ```
320
+
321
+ ---
322
+
323
+ ### Generic (no layout) — Content slide
324
+
325
+ No `layout:` field renders a standard content slide. `h1` is the heading; everything below is body content. Frontmatter is optional — omit it entirely for slides that need no metadata:
326
+
327
+ ```markdown
328
+ ---
329
+ # Three key principles
330
+
331
+ 1. **Simplicity** — one idea per slide
332
+ 2. **Contrast** — separate layers
333
+ 3. **Rhythm** — consistent spacing
334
+ ```
335
+
336
+ Add frontmatter only when you need slide-level metadata:
337
+
338
+ ```markdown
339
+ ---
340
+ section: Content
341
+ ---
342
+ # Three key principles
343
+
344
+ 1. **Simplicity** — one idea per slide
345
+ 2. **Contrast** — separate layers
346
+ 3. **Rhythm** — consistent spacing
347
+ ```
348
+
349
+ ---
350
+
351
+ ## Markdown elements
352
+
353
+ ### Headings
354
+
355
+ `h1` is the slide heading. `h2` is a subheading. Avoid going deeper — slide typography is not designed for `h3`–`h6`.
356
+
357
+ ### Emphasis
358
+
359
+ - `*italic*` or `_italic_` → italic, colored in the accent color
360
+ - `**bold**` or `__bold__` → bold, in the primary ink color
361
+
362
+ ### Lists
363
+
364
+ Unordered lists render with a short accent rule as the bullet. Ordered lists use large ghost numerals.
365
+
366
+ ```markdown
367
+ - First item
368
+ - Second item
369
+
370
+ 1. First step
371
+ 2. Second step
372
+ ```
373
+
374
+ ### Footnotes
375
+
376
+ Define footnotes inline. They render as a small block above the slide footer.
377
+
378
+ ```markdown
379
+ This claim needs a source.[^1]
380
+
381
+ [^1]: The source citation goes here.
382
+ ```
383
+
384
+ ---
385
+
386
+ ## Code blocks
387
+
388
+ Fenced code blocks are syntax-highlighted. Add flags after the language name for extra behavior:
389
+
390
+ ````markdown
391
+ ```js live editable copy
392
+ const fib = n => n < 2 ? n : fib(n - 1) + fib(n - 2)
393
+ console.log(fib(10))
394
+ ```
395
+ ````
396
+
397
+ | Flag | Effect |
398
+ |---|---|
399
+ | `live` | Adds a Run button; shows the output (`console.log`, `print`) below the block, on the slide: the code gets smaller or scrolls to make room, and long output scrolls |
400
+ | `editable` | Makes the block editable in-browser |
401
+ | `copy` | Adds a clipboard copy button |
402
+
403
+ Supported languages include `js`, `python`, `css`, `html`, `json`, `bash`, and any other Prism-supported language.
404
+
405
+ > Python requires Pyodide, which loads on first run (~10 MB); packages the code imports, such as `numpy` or `pandas`, load with it. JavaScript runs instantly in a sandboxed `Function`.
406
+
407
+ ---
408
+
409
+ ## Tables
410
+
411
+ Standard GFM table syntax:
412
+
413
+ ```markdown
414
+ | Layer | Format | Who owns it |
415
+ |-----------|----------|-------------|
416
+ | Content | Markdown | Author |
417
+ | Design | CSS | Designer |
418
+ | Behaviour | Preact | Developer |
419
+ ```
420
+
421
+ ---
422
+
423
+ ## Math
424
+
425
+ Inline math: `$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$`
426
+
427
+ Block math:
428
+
429
+ ```markdown
430
+ $$
431
+ \int_0^\infty e^{-x^2}\,dx = \frac{\sqrt{\pi}}{2}
432
+ $$
433
+ ```
434
+
435
+ ---
436
+
437
+ ## Callouts
438
+
439
+ Use `:::` fences with a type keyword. An optional custom title follows the type on the same line.
440
+
441
+ ```markdown
442
+ ::: note
443
+ Use callouts sparingly — one per slide at most.
444
+ :::
445
+
446
+ ::: tip Combine with code
447
+ Place next to a code block for step-by-step instructions.
448
+ :::
449
+
450
+ ::: warning
451
+ Callouts interrupt reading flow.
452
+ :::
453
+ ```
454
+
455
+ Available types: `note`, `tip`, `important`, `warning`, `caution`.
456
+
457
+ For lectures there are also `definition`, `theorem`, `lemma`, `corollary`, `proof`, `example` and `remark`. Every theme tells them apart: theorems, lemmas and corollaries in the accent with the statement in italics, definitions in the second accent, examples and remarks plain, and a proof without a box, opening with *Proof.* and ending with ∎. Each theme does this in its own style; the academic theme sets them like lecture notes. Number them in the title:
458
+
459
+ ```markdown
460
+ ::: theorem Theorem 2.4 (Lagrange)
461
+ If $H$ is a subgroup of a finite group $G$, then $|H|$ divides $|G|$.
462
+ :::
463
+
464
+ ::: proof
465
+ The cosets of $H$ partition $G$ and all have $|H|$ elements.
466
+ :::
467
+ ```
468
+
469
+ ### Callout titles
470
+
471
+ Without a custom title, a callout is labelled after its type. Set `lang: de` in the deck frontmatter to get German defaults (`Hinweis`, `Tipp`, `Wichtig`, `Achtung`, `Vorsicht`, and `Satz`, `Beweis`, `Beispiel`, `Bemerkung` …), or override individual titles:
472
+
473
+ ```yaml
474
+ lang: de
475
+ callouts:
476
+ warning: "Vorsicht, Falle"
477
+ ```
478
+
479
+ A title written after the type on the `:::` line still wins over both.
480
+
481
+ `mdeck check` warns about other type names, which are usually typos (`::: warnign`). A type of your own, styled with your own CSS as `.callout-<type>`, is fine once it has a title under `callouts:`.
482
+
483
+ ---
484
+
485
+ ## Language
486
+
487
+ `lang` is the language of the whole deck. The page is marked with it, so screen readers pronounce the slides correctly and browsers hyphenate them. It also picks the words mdeck itself shows the audience: the reader view's buttons, the deck's control bar, polls on the slide and on phones, and callout titles. German (`de`) and English (`en`) are built in; for any other language the words stay English. A regional code such as `de-CH` uses the German words.
488
+
489
+ The presenter view, the launch page and the editor are tools for the author and always stay English.
490
+
491
+ To change single words, name them under `labels`:
492
+
493
+ ```yaml
494
+ lang: de
495
+ labels:
496
+ poll.scan: "Jetzt abstimmen"
497
+ reader.present: "Vollbild"
498
+ ```
499
+
500
+ `mdeck check` warns about names that do not exist. `{n}`, `{choice}`, `{command}` and `{setting}` are filled in by mdeck.
501
+
502
+ | Label | English | German |
503
+ |---|---|---|
504
+ | `reader.outline` | Outline | Gliederung |
505
+ | `reader.untitled` | Slides | Folien |
506
+ | `reader.slides` | Slides | Folien |
507
+ | `reader.read` | Read | Lesen |
508
+ | `reader.appearance` | Light or dark | Hell oder dunkel |
509
+ | `reader.light` | Light | Hell |
510
+ | `reader.dark` | Dark | Dunkel |
511
+ | `reader.downloadPdf` | Download PDF | PDF herunterladen |
512
+ | `reader.savePdf` | Save as PDF… | Als PDF sichern… |
513
+ | `reader.savePdfHint` | Opens the browser's print dialog; choose Save as PDF | Öffnet den Druckdialog des Browsers; dort „Als PDF sichern“ wählen |
514
+ | `reader.present` | Present | Präsentieren |
515
+ | `reader.previous` | Previous | Zurück |
516
+ | `reader.next` | Next | Weiter |
517
+ | `reader.copyLink` | Copy link to this slide | Link zu dieser Folie kopieren |
518
+ | `reader.linkCopied` | Link copied | Link kopiert |
519
+ | `reader.slide` | Slide {n} | Folie {n} |
520
+ | `deck.overview` | Overview | Übersicht |
521
+ | `slide.chapter` | Chapter (above a chapter slide's title; `label:` on the slide replaces it) | Kapitel |
522
+ | `deck.controls` | Deck controls | Foliensteuerung |
523
+ | `deck.previous` | Previous slide | Vorherige Folie |
524
+ | `deck.next` | Next slide | Nächste Folie |
525
+ | `deck.reset` | Reset | Neustart |
526
+ | `deck.resetHint` | Reset to first slide | Zurück zur ersten Folie |
527
+ | `poll.scan` | Scan to vote | Scannen und abstimmen |
528
+ | `poll.answer` | 1 answer | 1 Antwort |
529
+ | `poll.answers` | {n} answers | {n} Antworten |
530
+ | `poll.reset` | Reset | Zurücksetzen |
531
+ | `poll.live` | Live | Live |
532
+ | `poll.offline` | Not connected to the server | Keine Verbindung zum Server |
533
+ | `poll.unreachable` | Phones cannot reach this computer. Start with {command}, or set {setting}. | Handys erreichen diesen Computer nicht. Mit {command} starten oder {setting} setzen. |
534
+ | `poll.tryHere` | Try the answer page here | Antwortseite hier ausprobieren |
535
+ | `poll.pick` | Tap one answer. | Eine Antwort antippen. |
536
+ | `poll.thanks` | Thanks! You chose “{choice}”. Tap another to change. | Danke! Gewählt: „{choice}“. Zum Ändern eine andere antippen. |
537
+ | `respond.waiting` | The next question will appear here. | Die nächste Frage erscheint hier. |
538
+ | `respond.send` | Send | Senden |
539
+ | `respond.sent` | Sent. Thank you! | Gesendet. Danke! |
540
+ | `join.scan` | Scan to join | Scannen und mitmachen |
541
+ | `question.empty` | Answers appear here. | Hier erscheinen die Antworten. |
542
+ | `scale.average` | Average {n} | Durchschnitt {n} |
543
+
544
+ ---
545
+
546
+ ## Speaker notes
547
+
548
+ Use a `:::notes` fenced block in the slide body. Notes support Markdown and are only visible in the presenter view:
549
+
550
+ ```markdown
551
+ ---
552
+ layout: focus
553
+ eyebrow: Key point
554
+ ---
555
+ # The main idea.
556
+
557
+ :::notes
558
+ This is the central design decision. Pause here.
559
+
560
+ - **Content** is readable without tooling
561
+ - **Design** is just a CSS file
562
+ - Ask: *"what breaks if you swap the theme?"*
563
+ :::
564
+ ```
565
+
566
+ The `:::notes` block can appear anywhere in the body, but placing it last keeps it visually separate from slide content.
567
+
568
+ ---
569
+
570
+ ## Columns
571
+
572
+ Place content side by side using `:::columns` with `+++` as the column separator:
573
+
574
+ ```markdown
575
+ :::columns
576
+
577
+ Left column content here.
578
+
579
+ +++
580
+
581
+ Right column content here.
582
+
583
+ +++
584
+
585
+ A third column, if needed.
586
+
587
+ :::
588
+ ```
589
+
590
+ Each column is an equal-width flex child, so three `+++` separators give four equal columns. Use `:::columns` inside any layout that has a body area — `GenericSlide`, `focus`, etc.
591
+
592
+ ---
593
+
594
+ ## Images
595
+
596
+ Reference images with standard Markdown syntax or the `image:` frontmatter field. Paths are relative to the deck file.
597
+
598
+ ```markdown
599
+ ![Alt text](./img/diagram.png)
600
+ ```
601
+
602
+ A local SVG whose source contains `var(--…)` is drawn inline instead of as an
603
+ `<img>`, both in slide text (`![…](./img/drawing.svg)` or `<img src>`) and as a
604
+ layout's `image` (`title`, `chapter`, `image-text`, `full-bleed-image`, and
605
+ local layouts that render it with `Picture` from `mdeck/layout`). It can use the
606
+ palette's custom properties (`--bg`, `--surface`, `--ink`, `--ink-soft`,
607
+ `--muted`, `--rule`, `--accent`, `--accent-2`, `--on-accent`) and follows the
608
+ theme, palette and appearance. Give each a fallback (`var(--accent, #1f3fd1)`)
609
+ for places that show the file on its own, set `fit: contain` to keep the whole
610
+ drawing, prefix class names in its `<style>` because inline styles apply to the
611
+ page, and avoid `id`s, since a slide can be shown more than once. Such SVGs stay
612
+ files in single-file builds and travel inside the deck's code instead.
613
+
614
+ A normal build copies referenced local images, video, and audio next to the HTML
615
+ while preserving their deck-relative paths. This is the recommended distribution
616
+ format for decks containing substantial video.
617
+
618
+ To embed all local images and media in a single offline-ready HTML file, use:
619
+
620
+ ```bash
621
+ mdeck build slides.md --single-file -o slides.html
622
+ ```
623
+
624
+ The theme's web fonts are embedded too (Latin character sets), so the file and
625
+ its PDF look like the slides on the presenter's screen, offline as well. They are
626
+ fetched once and kept in a cache (`~/.cache/mdeck/fonts`, or `MDECK_CACHE_DIR`);
627
+ without network and cache the build uses the fallback fonts and says so.
628
+ Self-contained video is base64-encoded and is therefore roughly 33% larger than
629
+ the source file; loading, memory use, and seeking can also be worse than with a
630
+ separate media file.
631
+
632
+ To add target-computer launchers to a directory bundle, build with
633
+ `--launchers`. The generated `present.sh` (macOS/Linux),
634
+ `present.bat`, and `present.ps1` (Windows) require Python 3, start a local server
635
+ bound to `127.0.0.1`, and open the presenter view in the default browser.
636
+
637
+ ---
638
+
639
+ ## Video
640
+
641
+ Embed video with the `<videoplayer>` component. It accepts local files and web video URLs.
642
+
643
+ ```markdown
644
+ <!-- Local file — click to play (default) -->
645
+ <videoplayer src="./demo.mp4" />
646
+
647
+ <!-- Autoplay when slide becomes active (muted, as required by browsers) -->
648
+ <videoplayer src="./demo.mp4" play="auto" />
649
+
650
+ <!-- YouTube, Vimeo, or SwitchTube URL -->
651
+ <videoplayer url="https://youtu.be/dQw4w9WgXcQ" />
652
+ <videoplayer url="https://tube.switch.ch/videos/abc123" play="auto" />
653
+ ```
654
+
655
+ | Attribute | Default | Description |
656
+ |---|---|---|
657
+ | `src` | — | Path to a local video file |
658
+ | `url` | — | Web video URL (YouTube, Vimeo, SwitchTube, or direct embed URL) |
659
+ | `play` | `click` | `click` — user controls playback; `auto` — plays when slide activates, pauses when leaving |
660
+ | `aspect` | `16/9` | CSS `aspect-ratio` value, e.g. `4/3` |
661
+ | `muted` | — | Mute the video (always muted in `auto` mode) |
662
+
663
+ For `play="auto"` the video pauses and resets to the beginning when you navigate away. Local videos also pause automatically on slide leave in `click` mode to avoid unexpected audio.
664
+
665
+ ---
666
+
667
+ ## Polls
668
+
669
+ `<poll>` asks the audience a question they answer on their phones:
670
+
671
+ ```markdown
672
+ # Where do we eat?
673
+
674
+ <poll room="lunch" options="Mensa|Thai|Pizza|Salad" />
675
+ ```
676
+
677
+ | Attribute | Default | Description |
678
+ |---|---|---|
679
+ | `room` | `poll` | Name of the room that collects the answers; unique per poll in a deck. Letters, digits, `.`, `-`, `_` |
680
+ | `options` | — | Answers separated by `\|` |
681
+ | `question` | — | Question text; phones fall back to the slide heading |
682
+ | `qr` | `true` | `false` leaves out the QR code (shown earlier with `<qrcode join />`) |
683
+ | `answer` | — | The right answer (several separated by `\|`): a button with a tick outlines its label, bar and count in green, also in the audience window and on paired devices. `--poll-correct` sets the colour |
684
+
685
+ Three more activities take the same `room`, `question` and `qr`:
686
+
687
+ | Tag | Attributes | Phones | Slide |
688
+ |---|---|---|---|
689
+ | `<scale>` | `min` (1), `max` (5), `low`, `high` | One button per number, `low`/`high` as labels | Count per number and the average; latest answer per device |
690
+ | `<wordcloud>` | `placeholder`, `limit` (60), `height` (520) | Text field, up to 40 characters, repeatable | A packed word cloud (d3-cloud): size by frequency, some words upright, case-insensitive |
691
+ | `<question>` | `placeholder`, `limit` (8) | Text field, up to 200 characters, repeatable | The newest answers as cards |
692
+
693
+ `<qrcode join />` shows the deck's join code large with its link (`size`, default 420), for a slide that invites everyone once; activities after it can use `qr="false"`. QR codes (`<qrcode>`, activities) are SVG in the slide's `--ink` on a transparent background; `--qr-ink` and `--qr-bg` override the colours.
694
+
695
+ The slide shows live bars, the number of answers, a QR code and a short link. Phones never load the deck: they open the server's own answer page at `<server>/<code>`, where the six-digit session code is the same for every poll in the deck. The presenter's screen (the presenter view or a full deck window, never an embedded preview) announces the poll on the current slide with what the phones should show and the deck's look; the server only accepts that from the presenter. Between polls the phones wait. Each device's latest vote counts. The presenter can reset the room (hover over the results).
696
+
697
+ Rooms run inside `mdeck run` (add `--network` so phones can reach it) or on a server started with `mdeck server`, set in the deck:
698
+
699
+ ```yaml
700
+ server: https://rooms.example.org # your server; phones join at https://rooms.example.org/<code>
701
+ session:
702
+ id: talk # optional: name the code is derived from, defaults to the title
703
+ code: 482113 # optional: the code itself
704
+ ```
705
+
706
+ A deck's rooms are named `<code>.<room>` on the server, so decks sharing a server stay apart. See the [Ask your audience](../site/content/audience.md) guide for hosting, and [Create interactive content](../site/content/components.md) for writing other activities with `useRoom` and a `phone` description.
707
+
708
+ ---
709
+
710
+ ## Drawings (ink)
711
+
712
+ Drawings on slides live in `<deck>.drawings.json` beside `<deck>.md` and are part of every view, build and PDF (`--no-drawings` leaves them out). `mdeck run` saves them as they are drawn; the guide [Draw on your slides](../site/content/drawing.md) covers drawing and presenting from an iPad.
713
+
714
+ ```json
715
+ {
716
+ "version": 1,
717
+ "width": 1920,
718
+ "height": 1080,
719
+ "slides": {
720
+ "the-important-part": [
721
+ {"id":"k3f9a2:lq1x0","tool":"pen","color":"#e11d48","size":6,"points":[[412,630,0.52],[598,641,0.61]]}
722
+ ]
723
+ }
724
+ }
725
+ ```
726
+
727
+ - Keys under `slides` are slide ids. A slide without an `id:` gets one from its heading when it receives its first drawing, written into its settings.
728
+ - `points` are `[x, y, pressure]` in the deck's design pixels (`width` × `height`); if the deck's size changes, strokes are scaled. `tool` is `pen` or `highlighter`.
729
+ - Drawings belong to a slide, not to a step of it.
730
+ - `mdeck check` reports a broken drawings file and drawings for slide ids that are not in the deck.
731
+ - Keys: `D` draw, `I` hide or show drawings, `F` full screen, `Delete` removes the selected strokes.
732
+ - The laser pointer and selections are never saved; moving strokes saves them in their new place, with the same ids.
733
+
734
+ ## Deck-local components
735
+
736
+ Components registered in `src/runtime/registry.jsx` are part of *every* deck. When a
737
+ widget is only needed by one talk, put it in a `components/` folder next to the
738
+ deck file instead:
739
+
740
+ ```
741
+ my-talk/
742
+ my-talk.md
743
+ components/
744
+ Tokenizer.jsx
745
+ ```
746
+
747
+ Each `*.jsx` file's default export is registered automatically under its
748
+ lowercased filename, so `Tokenizer.jsx` becomes `<tokenizer>`:
749
+
750
+ ```markdown
751
+ <tokenizer text="Donaudampfschifffahrt" />
752
+ ```
753
+
754
+ Attributes arrive as props, exactly like built-in components. Deck-local
755
+ components override a built-in of the same name.
756
+
757
+ To reuse components across decks, list their folders in the deck settings:
758
+
759
+ ```yaml
760
+ components:
761
+ - ../shared-components
762
+ - ~/mdeck-components
763
+ ```
764
+
765
+ The deck's own `components/` folder is searched first, then the listed folders
766
+ in order, then the built-ins. `mdeck check` reports listed folders that do not
767
+ exist.
768
+
769
+ In PDFs, printouts and the reader's Read mode, every slide is shown at once.
770
+ There mdeck reveals all steps and places the slide inside an element with the
771
+ `data-deck-static` attribute; a component that builds up step by step should
772
+ render its finished state inside `[data-deck-static]`, and follow the stage's
773
+ `printchange` event for printing started from an open deck. A slide that holds
774
+ only a component can be named for the outline with a `title:` setting.
775
+
776
+ Because they are only pulled in by the deck that ships them, a heavy dependency
777
+ stays out of every other deck's bundle. Install such dependencies in a
778
+ `node_modules` next to the deck, or in the framework itself.
779
+
780
+ > Deck components are `.jsx` only, and are written against Preact — import
781
+ > hooks from `preact/hooks`. The build resolves those imports back to the
782
+ > framework's own Preact, so the deck folder needs no Preact install.
783
+
784
+ ---
785
+
786
+ ## Inline HTML
787
+
788
+ You can write HTML directly in slide bodies. It inherits the theme's body text styles automatically. Use it for structural layouts the framework doesn't provide out of the box:
789
+
790
+ ```markdown
791
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 48px;">
792
+ <div>Left column content</div>
793
+ <div>Right column content</div>
794
+ </div>
795
+ ```