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,96 @@
1
+ # Work with an AI assistant
2
+
3
+ The usual way to make an mdeck presentation is to give an AI assistant the
4
+ material you already have (old slides, a PDF, a Word document, a paper, a page
5
+ of notes) and let it turn that into a deck. The content stays yours; the
6
+ assistant shapes it into slides, chooses layouts, writes speaker notes from
7
+ your text, and checks its work with mdeck.
8
+
9
+ mdeck ships a skill, `write-slides`, for this. It reads the mdeck reference
10
+ docs, asks the installed `mdeck` command which layouts, themes and palettes the
11
+ deck can use (including designs kept in the deck's `extensions/` folder),
12
+ writes the file, and runs `mdeck check` on the result.
13
+
14
+ The skill is written in the [Agent Skills](https://agentskills.io) format, a
15
+ `SKILL.md` file that Claude Code, OpenAI Codex and other assistants read
16
+ directly. For tools with their own conventions, `mdeck skill` writes the same
17
+ instructions in their format.
18
+
19
+ ## Install it
20
+
21
+ ```sh
22
+ mdeck skill # list the supported assistants
23
+ mdeck skill --install claude # Claude Code, personal (~/.claude/skills/)
24
+ mdeck skill --install codex # OpenAI Codex, personal (~/.codex/skills/)
25
+ mdeck skill --install cursor # Cursor rule in this project (.cursor/rules/)
26
+ mdeck skill --install copilot # GitHub Copilot prompt file (.github/prompts/)
27
+ mdeck skill --install gemini # Gemini CLI command (.gemini/commands/)
28
+ mdeck skill --install claude codex --project # into this project instead of your home folder
29
+ mdeck skill --print # the skill as text, for any other tool
30
+ ```
31
+
32
+ Run the command in the folder of the deck you are working on when installing
33
+ project-level files. Re-run it after updating mdeck to pick up changes.
34
+
35
+ ## Start a deck
36
+
37
+ Copy your material into the talk's folder, open the assistant there, and say
38
+ what to make from it: for whom, how long, in which language, and how closely
39
+ to keep to the original.
40
+
41
+ ```prompt
42
+ /write-slides Rebuild kinetics-2023.pptx as a 45-minute lecture for
43
+ second-year biology students, in German, FHNW theme. Keep the order
44
+ and the figures, split the crowded slides, and add what is new in
45
+ notes/2026-changes.md.
46
+ ```
47
+
48
+ | Assistant | How to start |
49
+ |---|---|
50
+ | Claude Code, Gemini CLI | `/write-slides` followed by your request |
51
+ | Codex | Ask for slides; the skill is picked up by its description |
52
+ | Cursor | Mention `@write-slides` or ask for an mdeck deck |
53
+ | GitHub Copilot | Run the `write-slides` prompt from the prompt picker |
54
+ | Anything else | Paste the output of `mdeck skill --print` followed by your request |
55
+
56
+ The assistant writes a `.md` file named after the topic, checks it, and tells
57
+ you what it left out or added. Open the preview and leave it running while you
58
+ work; it reloads every time the file changes:
59
+
60
+ ```sh
61
+ mdeck run <deck>.md
62
+ ```
63
+
64
+ ## Change it by asking
65
+
66
+ Keep talking to the assistant and watch the slides follow:
67
+
68
+ ```prompt
69
+ You dropped the comparison table from page 12 of the PDF. Put it back
70
+ after the methods slide, and turn "Why it matters" into a big statement.
71
+ ```
72
+
73
+ The assistant can also make what would otherwise need CSS or JavaScript: a
74
+ colour palette, a theme, a slide layout, or an interactive component. They are
75
+ kept as small folders in `extensions/` or `components/` beside the slide file,
76
+ so they travel with the talk. For a theme or palette, it asks you to look at
77
+ the result with `mdeck design <deck>.md`, which shows it on a sample deck with
78
+ every kind of slide, light and dark, and lets you fine-tune colours, fonts and
79
+ sizes yourself.
80
+
81
+ For a word or a number, it is often faster to edit the file yourself; see
82
+ [Read and adjust your slides](writing.html).
83
+
84
+ ## Check what it wrote
85
+
86
+ `mdeck check` finds missing pictures and settings mistakes. It does not know
87
+ whether the talk is right, or whether the text fits on each slide. Before
88
+ presenting, compare the deck with your material, look at every slide in the
89
+ preview, and try any polls with a phone.
90
+
91
+ ## What the skill knows
92
+
93
+ It carries a short quick reference of the file format so it can work even
94
+ without the docs, finds the full reference docs in the repository or the
95
+ installed package, and prefers the live answers from `mdeck list layouts --json`
96
+ and `mdeck list` over its own memory.
@@ -0,0 +1,250 @@
1
+ # Extensions: layouts, themes and palettes
2
+
3
+ mdeck can be extended in three ways, and all three follow the same rules.
4
+
5
+ - A **layout** is an arrangement for a slide: which content areas it has, which
6
+ settings it accepts, and how it is arranged. The built-in layouts such as
7
+ `title` and `split` are extensions too.
8
+ - A **theme** is the overall look: fonts, spacing, the slide frame and the
9
+ default colours. A deck picks one with `theme:`.
10
+ - A **palette** is a family of colours, light and dark, that repaints any
11
+ theme. A deck picks one with `palette:` and the variant with `appearance:`.
12
+
13
+ Every extension is a folder with an `extension.toml` file inside. The manifest
14
+ says which kind it is and describes its supporting files and settings. The
15
+ folder name is the identifier used in slide files.
16
+
17
+ ```text
18
+ extensions/
19
+ comparison/ a layout
20
+ extension.toml
21
+ layout.jsx
22
+ styles.css
23
+ starter.md
24
+ my-theme/ a theme
25
+ extension.toml
26
+ styles.css
27
+ my-colors/ a palette
28
+ extension.toml
29
+ ```
30
+
31
+ mdeck looks in two places, in this order: its own built-in collection under
32
+ `assets/extensions/` and an `extensions/` folder beside the slide file. Inside
33
+ either place, a folder that contains `extension.toml` is an extension; any other
34
+ folder is simply a group and is searched further, so `extensions/colors/ocean/`
35
+ works just as well as `extensions/ocean/`. Identifiers must be unique within
36
+ their kind across both places. A local extension cannot quietly replace a
37
+ built-in one; a duplicate stops the command with a message naming both files.
38
+
39
+ The same registry backs `mdeck check`, `mdeck list`, `mdeck list layouts`,
40
+ the `mdeck new` wizard, the dev server and builds, so what a check accepts is
41
+ what a build can load.
42
+
43
+ ## Shared settings
44
+
45
+ ```toml
46
+ schema = 1 # manifest format version; always 1 for now
47
+ kind = "palette" # layout, theme or palette
48
+ id = "ocean" # must equal the folder name
49
+ title = "Ocean" # readable name shown in lists and controls
50
+ description = "Deep blue with a warm highlight." # optional
51
+ ```
52
+
53
+ - `id` uses lowercase letters, digits and hyphens and starts with a letter.
54
+ - Unknown settings are errors, so a typo is reported rather than ignored.
55
+ - File references are relative to the extension folder and may not leave it.
56
+ - Manifests are [TOML 1.0](https://toml.io/en/v1.0.0). CSS custom property
57
+ names start with dashes, so quote them as keys: `"--accent" = "#ff0000"`.
58
+
59
+ Problems are reported with the file, the setting and, for syntax errors, the
60
+ line and column:
61
+
62
+ ```text
63
+ extensions/ocean/extension.toml: light.accent: token names look like "--accent"
64
+ extensions/ocean/extension.toml:7:12: incomplete declaration: value expected
65
+ ```
66
+
67
+ ## Palette
68
+
69
+ ```toml
70
+ schema = 1
71
+ kind = "palette"
72
+ id = "ocean"
73
+ title = "Ocean"
74
+ description = "Deep blue with a warm highlight."
75
+ # theme = "my-theme" # only this theme may use it
76
+
77
+ [light]
78
+ "--bg" = "#f4f8fb"
79
+ "--surface" = "#e6eef4"
80
+ "--ink" = "#0b1d2a"
81
+ "--ink-soft" = "#22394a"
82
+ "--muted" = "#4f6474"
83
+ "--rule" = "#c9d7e2"
84
+ "--accent" = "#0a6aa8"
85
+ "--accent-2" = "#b45309"
86
+ "--on-accent" = "#ffffff"
87
+
88
+ [dark]
89
+ "--bg" = "#102030"
90
+ "--surface" = "#17293b"
91
+ "--ink" = "#eef4f8"
92
+ "--ink-soft" = "#c8d6e0"
93
+ "--muted" = "#8ea3b3"
94
+ "--rule" = "#24384b"
95
+ "--accent" = "#ffbd69"
96
+ "--accent-2" = "#7cc4ff"
97
+ "--on-accent" = "#102030"
98
+ ```
99
+
100
+ `[light]` and `[dark]` each set all nine colours, the shared vocabulary every
101
+ theme uses; see [palettes](palettes.md) for what each one does. The deck's
102
+ `appearance` picks one for the slides; themes use the other for inverted
103
+ slides, as `--inverse-*`. The dark variant also gets dark code colours and an
104
+ inverted logo. `theme` makes the palette private to one theme.
105
+
106
+ ## Layout
107
+
108
+ ```toml
109
+ schema = 1
110
+ kind = "layout"
111
+ id = "comparison"
112
+ title = "Side-by-side comparison"
113
+ description = "Two options next to each other."
114
+ frame = "standard" # standard, title, chapter or none
115
+
116
+ [files]
117
+ layout = "layout.jsx" # default; may be omitted
118
+ styles = "styles.css" # optional; picked up automatically when present
119
+ starter = "starter.md" # optional; picked up automatically when present
120
+
121
+ [regions.body]
122
+ description = "Heading and introduction"
123
+
124
+ [regions.left]
125
+ required = true
126
+
127
+ [regions.right]
128
+ required = true
129
+
130
+ [properties.emphasis]
131
+ type = "string"
132
+ enum = ["none", "left", "right"]
133
+ default = "none"
134
+ ```
135
+
136
+ `regions` must include `body`. `properties` describe values under a slide's
137
+ `props:` and support `type` (`string`, `number`, `integer`, `boolean`, `array`,
138
+ `object`), `default`, `enum`, `required`, `minimum`, `maximum`, `minItems`,
139
+ `maxItems`, `items`, plus `title` and `description` for editors. Nested
140
+ settings use TOML sub-tables:
141
+
142
+ ```toml
143
+ [properties.ratio]
144
+ type = "array"
145
+ minItems = 2
146
+ maxItems = 2
147
+ default = [1, 1]
148
+
149
+ [properties.ratio.items]
150
+ type = "number"
151
+ minimum = 0.01
152
+ ```
153
+
154
+ The layout file is Preact JSX that imports from `mdeck/layout`. See
155
+ [layouts](layouts.md) for the renderer contract. Layout code runs as part
156
+ of the deck: it is trusted code, not sandboxed data.
157
+
158
+ ## Theme
159
+
160
+ ```toml
161
+ schema = 1
162
+ kind = "theme"
163
+ id = "my-theme"
164
+ title = "My theme"
165
+ description = "Calm sans-serif slides."
166
+ palette = "lagoon" # the default palette; colours come only from palettes
167
+ # palettes = ["lagoon"] # offer only these palettes
168
+ # appearance = "dark" # start dark
169
+ fonts = [
170
+ "https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap",
171
+ ]
172
+
173
+ [files]
174
+ styles = "styles.css" # one stylesheet or a list of them
175
+
176
+ [tokens]
177
+ "--fs-body" = "34px"
178
+ "--font-body" = "\"Inter\", system-ui, sans-serif"
179
+
180
+ [params.fontBody]
181
+ token = "--font-body"
182
+ title = "Body font"
183
+ ```
184
+
185
+ - `palette` names the palette the theme uses unless the deck sets one. A theme
186
+ has no colours of its own; `tokens` may not set the nine palette colours.
187
+ - `palettes` limits the palettes a theme offers, for a corporate design; it
188
+ must include the default. Without it, every palette not private to another
189
+ theme is offered.
190
+ - `appearance = "dark"` makes the theme start dark.
191
+ - `tokens` are the theme's type, spacing and font values. mdeck generates the
192
+ `:root` block from them, so the stylesheet only contains rules.
193
+ - `params` name the settings authors may change under `params:` in the deck.
194
+ Each points at a token; its default is the token's value, so nothing is
195
+ written twice.
196
+ - `fonts` are stylesheet URLs. Normal builds load them; single files (`mdeck send`,
197
+ `--single-file`) and PDFs embed their Latin character sets, so they look the
198
+ same offline. The fallbacks named in the token values apply when a font
199
+ cannot be fetched.
200
+
201
+ Values are applied in this order: the palette's colours (the deck's variant,
202
+ and the other as `--inverse-*`), the theme's tokens, then deck `params`.
203
+
204
+ ## Editing in the browser
205
+
206
+ `mdeck design my-talk.md` (also *Design themes* in `mdeck edit`) opens a
207
+ design page for themes and palettes: forms with a live preview on a sample
208
+ deck that has every built-in layout, or on the deck itself. `mdeck design
209
+ <folder>` does the same without a deck and writes to `<folder>/extensions/`.
210
+ Built-in extensions cannot be changed; copy one under a new id to change it.
211
+ New themes always start as a copy. Layouts are not edited there. The page
212
+ writes the same files described above.
213
+
214
+ ## Installed extensions and packs
215
+
216
+ mdeck looks for extensions in three places, in this order: the built-in ones,
217
+ the user's folder (`~/.mdeck/extensions`, or `$MDECK_HOME/extensions`), and the
218
+ `extensions/` folder beside the deck. An id may appear only once, except that a
219
+ deck's own extension replaces a user one with the same id (with a warning).
220
+ `mdeck check` warns when a deck uses a theme or palette from the user's folder,
221
+ because the slide file then works only on that computer.
222
+
223
+ `mdeck themes install <pack>` copies a pack from the theme repository into the
224
+ deck's folder, or with `--global` into the user's. A pack is a folder with a
225
+ `pack.toml` (`schema`, `id`, `title`, `description`, `version`, `author`,
226
+ `license`, `homepage`, and `mdeck = ">=X.Y.Z"`, the oldest mdeck it works with)
227
+ and one folder per theme or palette, each holding only `extension.toml` and,
228
+ for a theme, `styles.css`. Theme fonts must come from `https://fonts.googleapis.com/`
229
+ or `https://fonts.bunny.net/`, and `styles.css` may contain neither `@import`
230
+ nor `url()` other than `data:` URLs. Each installed folder gets a
231
+ `.mdeck-pack.json` with the pack, its version, its source and a checksum of
232
+ every file; `update` and `remove` refuse to touch files changed since then
233
+ unless given `--force`.
234
+
235
+ The repository serves `index.json` (`{ schema: 1, packs: [...] }`, each with
236
+ its ids, `url`, `sha256` and `previews`) and one JSON file per pack version
237
+ holding the text of its files. `mdeck themes build <packs> -o <out> [--check]`
238
+ writes both from a folder of packs; `MDECK_THEMES_URL` points mdeck at another
239
+ index.
240
+
241
+ ## Listing what is available
242
+
243
+ ```sh
244
+ mdeck list my-talk.md
245
+ mdeck list my-talk.md --json
246
+ ```
247
+
248
+ The JSON form carries every manifest's title, description, tokens, parameters,
249
+ region requirements and property definitions, so other tools can build
250
+ controls from the same data mdeck uses.
@@ -0,0 +1,153 @@
1
+ # User-created slide layouts
2
+
3
+ Layouts define slide structure; themes supply typography and colors. Every
4
+ built-in layout and every deck-local layout uses the same registry, manifest,
5
+ property resolver, and slide frame. A local layout requires no framework edit.
6
+
7
+ ```text
8
+ my-talk/
9
+ slides.md
10
+ extensions/
11
+ comparison/
12
+ extension.toml
13
+ layout.jsx
14
+ styles.css optional
15
+ starter.md optional
16
+ ```
17
+
18
+ A layout is one kind of [extension](extensions.md); themes and palettes use
19
+ the same folder and manifest rules. The folder name is the `layout:` value.
20
+ Names must be lowercase letters, digits and hyphens, beginning with a letter.
21
+ A local layout cannot use a built-in's name. Manifests are checked when
22
+ loading, building, listing or validating a deck. The dev server reloads when
23
+ extension files are changed, added or removed.
24
+
25
+ ## Manifest
26
+
27
+ ```toml
28
+ schema = 1
29
+ kind = "layout"
30
+ id = "comparison"
31
+ title = "Side-by-side comparison"
32
+
33
+ [regions.body]
34
+ description = "Shared heading"
35
+
36
+ [regions.left]
37
+ required = true
38
+
39
+ [regions.right]
40
+ required = true
41
+
42
+ [properties.emphasis]
43
+ type = "string"
44
+ enum = ["none", "left", "right"]
45
+ default = "none"
46
+ ```
47
+
48
+ `regions` must include `body`, which contains unassigned slide Markdown.
49
+ Authors fill additional regions using `:::slot left`, etc. A region can declare
50
+ `required: true` and a human-readable `description`. Unknown region names and
51
+ missing required content are validation errors.
52
+
53
+ `properties` describes values under slide metadata `props:`. Supported types:
54
+ `string`, `number`, `integer`, `boolean`, `array`, `object`. The schema supports
55
+ `required`, `default`, `enum`, numeric `minimum`/`maximum`, array `items`
56
+ (a `[properties.name.items]` sub-table), `minItems`/`maxItems`, and `title`
57
+ and `description` for editors. This is a small schema subset, not full JSON Schema.
58
+ Defaults are copied for each slide. Unknown properties and invalid values are
59
+ errors. Built-ins also accept their legacy top-level properties such as `image:`.
60
+
61
+ An optional `frame` selects `standard` (default), `title`, `chapter`, or `none`.
62
+ The last omits header/footer chrome; it still retains the slide container,
63
+ footnotes, ID, and navigation behavior.
64
+
65
+ ## Renderer
66
+
67
+ `layout.jsx` default-exports a Preact component. It renders the slide body:
68
+
69
+ ```jsx
70
+ import { h } from 'preact'
71
+ import { MarkdownRegion } from 'mdeck/layout'
72
+
73
+ export default function Comparison({ regions, props }) {
74
+ return <div class="slide-body">
75
+ <MarkdownRegion region={regions.body} />
76
+ <div class="comparison-options">
77
+ <MarkdownRegion region={regions.left} />
78
+ <MarkdownRegion region={regions.right}
79
+ class={props.emphasis === 'right' ? 'is-emphasized' : ''} />
80
+ </div>
81
+ </div>
82
+ }
83
+ ```
84
+
85
+ The component receives `regions`, resolved typed `props`, slide `meta`, `id`,
86
+ default-body `content`, `deckConfig`, `index`, `total`, and `manifest`.
87
+ Use `preact/hooks` for interactive layouts. `MarkdownRegion` renders Markdown
88
+ and hydrates both built-in and deck-local components. It exposes a `data-region`
89
+ attribute for integrations. Footnotes are numbered across all regions and placed
90
+ in the shared frame.
91
+
92
+ For a picture from a property, render `<Picture src={props.image} alt={props.alt}
93
+ fit={props.fit} position={props.position} class="…" />` instead of an `<img>`.
94
+ It is an `<img>` for ordinary pictures; an SVG that uses the palette's colours
95
+ (`var(--accent)` …) is drawn inline so it follows the theme. `themedSvg(src)`
96
+ returns that SVG's markup, or nothing, for layouts that place it themselves.
97
+
98
+ The framework wraps the result in `SlideFrame`; do not add a second `<section>`
99
+ or frame in your renderer. `SlideFrame`, `MarkdownRegion`, and `HtmlContent` are
100
+ also exported from `mdeck/layout` for integrations, and so is `t(key)`, which
101
+ returns a word the audience sees in the deck's language (`t('slide.chapter')`
102
+ is "Chapter", or "Kapitel" with `lang: de`). The API import resolves
103
+ through mdeck's build plugin, including when the deck is outside the framework.
104
+
105
+ Keep CSS scoped to `.slide--comparison` and use theme variables:
106
+
107
+ ```css
108
+ .slide--comparison .comparison-options {
109
+ display: grid;
110
+ grid-template-columns: 1fr 1fr;
111
+ gap: 40px;
112
+ }
113
+ .slide--comparison .is-emphasized { color: var(--accent); }
114
+ ```
115
+
116
+ JSX imports of assets and dependencies follow the same build rules as deck-local
117
+ components. Layout CSS is included in both bundle and self-contained builds.
118
+ Local paths in Markdown images, media `src`, and `image:`/`props.image` are handled
119
+ by asset packaging. For other custom asset properties, import assets in JSX so
120
+ Vite can track them; arbitrary string properties are not treated as file paths.
121
+ Renderers must consume their declared regions; the framework validates the
122
+ manifest and authored values, but cannot prove what arbitrary JSX renders.
123
+
124
+ ## Starters and discovery
125
+
126
+ `starter.md` is an editable slide preset. It should contain explicit `:::meta`
127
+ and placeholder region content, without a leading slide separator. `layout.jsx`,
128
+ `styles.css` and `starter.md` are picked up automatically from the layout
129
+ folder; use a `[files]` table in the manifest to point at different names.
130
+ `mdeck new` lists built-in and local starters found beside the requested output deck.
131
+
132
+ ```sh
133
+ mdeck list layouts slides.md
134
+ mdeck list layouts slides.md --json
135
+ mdeck list layouts slides.md --starter comparison
136
+ mdeck list slides.md
137
+ mdeck check slides.md --strict
138
+ ```
139
+
140
+ The JSON listing is the serializable manifest registry, suitable for completion,
141
+ layout galleries, or future editor inspectors. Listing and validation do not
142
+ execute layout JSX. Packages and a visual editor are not implemented here.
143
+
144
+ Built-in layouts are ordinary layouts under the framework's
145
+ `assets/extensions/layouts/` folder and use the same `mdeck/layout`
146
+ import, so they double as worked examples.
147
+
148
+ See the runnable [custom layout example](../../examples/custom-layouts/slides.md):
149
+
150
+ ```sh
151
+ mdeck run examples/custom-layouts/slides.md
152
+ mdeck build examples/custom-layouts/slides.md
153
+ ```
@@ -0,0 +1,106 @@
1
+ # Palettes
2
+
3
+ A palette gives a deck its colours. It is the only place colours come from: themes set type, spacing and layout, and leave colour to the palette, so any palette fits any theme.
4
+
5
+ Every palette is a family with two variants, **light** and **dark**. A deck chooses the family with `palette:` and the variant with `appearance:`. Themes use the *other* variant for inverted slides, such as neue's statement slides, so those stay readable and in tune.
6
+
7
+ ## Using a palette
8
+
9
+ ```yaml
10
+ ---
11
+ theme: neue
12
+ palette: terra # optional; without it the theme's default palette
13
+ appearance: dark # optional: light or dark; without it the theme's default
14
+ ---
15
+ ```
16
+
17
+ The presenter view and the reader view switch palette and light or dark without changing the file. Choose dark for a dark lecture hall, light for a bright seminar room.
18
+
19
+ ## Built-in palettes
20
+
21
+ | Palette | Light | Dark |
22
+ |---|---|---|
23
+ | `lagoon` | teal on warm stone, orange second accent | deep teal-black, bright teal |
24
+ | `swiss` | white, black and signal red | black, white and red |
25
+ | `cobalt` | ultramarine on white, vivid orange second accent | deep navy with a luminous blue |
26
+ | `nordic` | ice grey, deep navy and a cool steel blue | polar night with ice blue |
27
+ | `graphite` | black and white with a steel-blue accent | charcoal with light steel blue |
28
+ | `terra` | cream, deep navy and brick red | deep navy, cream and coral |
29
+ | `forest` | deep green with moss and ochre | forest night with light green |
30
+ | `ember` | sand and espresso with orange | dark brown with glowing orange |
31
+ | `neon` | white with violet and magenta | black with neon violet and pink |
32
+ | `phosphor` | a printout: near-black on paper, green and ochre | a terminal screen: phosphor green on black, amber |
33
+ | `pastel` | Catppuccin Latte: soft grey-blue paper, mauve and peach | Catppuccin Mocha: dusk blue with pastel mauve and peach |
34
+
35
+ `mdeck list palettes` lists them, with any of your own.
36
+
37
+ Each theme names a default: neue uses `swiss`, editorial `terra`, duet `cobalt`, aurora `neon`, terminal `phosphor` (dark), academic `nordic`, sketch `pastel`. The FHNW theme uses its own palette `brand` (FHNW yellow, black and white) and offers no other.
38
+
39
+ ## Colours
40
+
41
+ Every variant sets all nine:
42
+
43
+ | Colour | Role |
44
+ |---|---|
45
+ | `--bg` | Slide background |
46
+ | `--surface` | Raised surfaces: code blocks, image panes, cards |
47
+ | `--ink` | Headings and primary text |
48
+ | `--ink-soft` | Body text |
49
+ | `--muted` | Small labels: headers, footers, captions |
50
+ | `--rule` | Lines and dividers |
51
+ | `--accent` | The highlight: emphasis, markers, chapter slides |
52
+ | `--accent-2` | A second highlight for themes that pair two |
53
+ | `--on-accent` | Text set on the accent, such as a chapter slide's title |
54
+
55
+ Themes may mix them (for example a light tint of the accent), and read the other variant as `--inverse-bg`, `--inverse-ink`, `--inverse-accent` and so on.
56
+
57
+ ## Making a palette
58
+
59
+ A palette is an [extension](extensions.md): a folder named after it with an `extension.toml`, in `extensions/` beside a deck.
60
+
61
+ ```toml
62
+ schema = 1
63
+ kind = "palette"
64
+ id = "harbour"
65
+ title = "Harbour"
66
+ description = "Sea blue and rust on chalk white."
67
+
68
+ [light]
69
+ "--bg" = "#f7f9fa"
70
+ "--surface" = "#e9eef1"
71
+ "--ink" = "#0b1d2a"
72
+ "--ink-soft" = "#22394a"
73
+ "--muted" = "#4f6474"
74
+ "--rule" = "#c9d7e2"
75
+ "--accent" = "#0a6aa8"
76
+ "--accent-2" = "#b45309"
77
+ "--on-accent" = "#ffffff"
78
+
79
+ [dark]
80
+ "--bg" = "#0d1a24"
81
+ "--surface" = "#152635"
82
+ "--ink" = "#eef4f8"
83
+ "--ink-soft" = "#c8d6e0"
84
+ "--muted" = "#8ea3b3"
85
+ "--rule" = "#24384b"
86
+ "--accent" = "#5fb3f0"
87
+ "--accent-2" = "#f59e5b"
88
+ "--on-accent" = "#0d1a24"
89
+ ```
90
+
91
+ Colour names start with dashes, so quote them as TOML keys. A dark variant also gets dark code colours and an inverted logo; set `--logo-filter` or the `--token-*` code colours in `[dark]` to change that.
92
+
93
+ `theme = "my-theme"` makes a palette private: only that theme offers it, as FHNW does with `brand`.
94
+
95
+ ## Readability
96
+
97
+ `mdeck check` measures the contrast of your palette's colours and warns when they are too close to read from the back of a room:
98
+
99
+ | Pair | At least |
100
+ |---|---|
101
+ | text (`--ink`) on the background | 7 : 1 |
102
+ | body text and muted text on the background | 4.5 : 1 |
103
+ | both accents on the background | 3 : 1 (large type) |
104
+ | text on the accent | 3 : 1 |
105
+
106
+ The built-in palettes meet these in both variants. A private palette may use its accent only as a surface (FHNW's yellow), so its accents are not checked as text.