mdeck 2.3.0 → 3.0.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 (108) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/README.md +9 -9
  3. package/assets/base.css +4 -1
  4. package/assets/packs/academic/pack.toml +8 -0
  5. package/assets/packs/aurora/pack.toml +8 -0
  6. package/assets/packs/lagoon/pack.toml +8 -0
  7. package/assets/packs/minimal/minimal/extension.toml +45 -0
  8. package/assets/packs/minimal/minimal/styles.css +342 -0
  9. package/assets/packs/minimal/pack.toml +8 -0
  10. package/assets/packs/minimal/paper/extension.toml +27 -0
  11. package/assets/packs/neue/pack.toml +8 -0
  12. package/docs/reference/authoring.md +13 -18
  13. package/docs/reference/claude-skill.md +1 -1
  14. package/docs/reference/extensions.md +29 -20
  15. package/docs/reference/palettes.md +8 -12
  16. package/docs/reference/themes.md +8 -7
  17. package/docs/site/content/appearance.md +33 -49
  18. package/docs/site/content/commands.md +2 -2
  19. package/docs/site/content/theme-authoring.md +1 -1
  20. package/docs/site/content/theme-repository.md +19 -15
  21. package/docs/site/examples/first-talk.md +1 -1
  22. package/docs/site/images/themes/academic-dark.webp +0 -0
  23. package/docs/site/images/themes/academic-light.webp +0 -0
  24. package/docs/site/images/themes/academic.webp +0 -0
  25. package/docs/site/images/themes/aurora-dark.webp +0 -0
  26. package/docs/site/images/themes/aurora-light.webp +0 -0
  27. package/docs/site/images/themes/aurora.webp +0 -0
  28. package/docs/site/images/themes/minimal-dark.webp +0 -0
  29. package/docs/site/images/themes/minimal-light.webp +0 -0
  30. package/docs/site/images/themes/minimal.webp +0 -0
  31. package/docs/site/images/themes/neue-dark.webp +0 -0
  32. package/docs/site/images/themes/neue-light.webp +0 -0
  33. package/docs/site/images/themes/neue.webp +0 -0
  34. package/docs/site/pages.js +1 -1
  35. package/examples/custom-layouts/slides.md +1 -1
  36. package/examples/poll/slides.md +1 -1
  37. package/examples/python/slides.md +2 -2
  38. package/examples/showcase/slides.md +3 -3
  39. package/package.json +1 -1
  40. package/skills/write-slides/SKILL.md +2 -2
  41. package/src/build/check.js +0 -7
  42. package/src/build/editorPlugin.js +19 -11
  43. package/src/build/themeCheck.js +15 -5
  44. package/src/cli/args.js +1 -1
  45. package/src/cli/index.js +3 -3
  46. package/src/cli/themes.js +93 -64
  47. package/src/core/validateDeck.js +4 -2
  48. package/src/editor/api.js +9 -1
  49. package/src/editor/components/App.jsx +4 -2
  50. package/src/editor/components/DesignApp.jsx +12 -3
  51. package/src/editor/components/ExtensionEditor.jsx +15 -4
  52. package/src/editor/components/ExtensionsPanel.jsx +19 -21
  53. package/src/editor/designLink.js +18 -1
  54. package/src/editor/sampleDeck.js +3 -1
  55. package/src/extensions/appearance.js +2 -1
  56. package/src/extensions/discover.js +56 -16
  57. package/src/extensions/installed.js +63 -0
  58. package/src/extensions/moved.js +13 -0
  59. package/src/extensions/packs.js +135 -46
  60. package/src/home/Home.jsx +12 -6
  61. package/src/layouts/layoutApi.jsx +10 -2
  62. package/src/paths.js +2 -0
  63. package/src/runtime/themeLoader.js +5 -2
  64. package/assets/extensions/palettes/brand/extension.toml +0 -29
  65. package/assets/extensions/palettes/cobalt/extension.toml +0 -27
  66. package/assets/extensions/palettes/ember/extension.toml +0 -27
  67. package/assets/extensions/palettes/forest/extension.toml +0 -27
  68. package/assets/extensions/palettes/graphite/extension.toml +0 -27
  69. package/assets/extensions/palettes/pastel/extension.toml +0 -30
  70. package/assets/extensions/palettes/phosphor/extension.toml +0 -27
  71. package/assets/extensions/palettes/terra/extension.toml +0 -27
  72. package/assets/extensions/themes/duet/extension.toml +0 -46
  73. package/assets/extensions/themes/duet/styles.css +0 -573
  74. package/assets/extensions/themes/editorial/extension.toml +0 -46
  75. package/assets/extensions/themes/editorial/styles.css +0 -574
  76. package/assets/extensions/themes/fhnw/extension.toml +0 -61
  77. package/assets/extensions/themes/fhnw/styles.css +0 -604
  78. package/assets/extensions/themes/sketch/extension.toml +0 -48
  79. package/assets/extensions/themes/sketch/styles.css +0 -633
  80. package/assets/extensions/themes/terminal/extension.toml +0 -38
  81. package/assets/extensions/themes/terminal/styles.css +0 -550
  82. package/docs/site/images/themes/duet-dark.webp +0 -0
  83. package/docs/site/images/themes/duet-light.webp +0 -0
  84. package/docs/site/images/themes/duet.webp +0 -0
  85. package/docs/site/images/themes/editorial-dark.webp +0 -0
  86. package/docs/site/images/themes/editorial-light.webp +0 -0
  87. package/docs/site/images/themes/editorial.webp +0 -0
  88. package/docs/site/images/themes/fhnw.webp +0 -0
  89. package/docs/site/images/themes/sketch-dark.webp +0 -0
  90. package/docs/site/images/themes/sketch-light.webp +0 -0
  91. package/docs/site/images/themes/sketch.webp +0 -0
  92. package/docs/site/images/themes/terminal-dark.webp +0 -0
  93. package/docs/site/images/themes/terminal-light.webp +0 -0
  94. package/docs/site/images/themes/terminal.webp +0 -0
  95. package/examples/python/.mdeck-backups/slides.drawings-2026-10-06T08-36-47Z.json +0 -19
  96. package/examples/python/.mdeck-backups/slides.drawings-2026-10-06T11-27-30Z.json +0 -6
  97. package/examples/showcase/.mdeck-backups/slides.drawings-2026-10-06T08-08-30Z.json +0 -10
  98. package/examples/showcase/.mdeck-backups/slides.drawings-2026-10-06T11-41-35Z.json +0 -13
  99. /package/assets/{extensions/themes → packs/academic}/academic/extension.toml +0 -0
  100. /package/assets/{extensions/themes → packs/academic}/academic/styles.css +0 -0
  101. /package/assets/{extensions/palettes → packs/academic}/nordic/extension.toml +0 -0
  102. /package/assets/{extensions/themes → packs/aurora}/aurora/extension.toml +0 -0
  103. /package/assets/{extensions/themes → packs/aurora}/aurora/styles.css +0 -0
  104. /package/assets/{extensions/palettes → packs/aurora}/neon/extension.toml +0 -0
  105. /package/assets/{extensions/palettes → packs/lagoon}/lagoon/extension.toml +0 -0
  106. /package/assets/{extensions/themes → packs/neue}/neue/extension.toml +0 -0
  107. /package/assets/{extensions/themes → packs/neue}/neue/styles.css +0 -0
  108. /package/assets/{extensions/palettes → packs/neue}/swiss/extension.toml +0 -0
@@ -213,30 +213,39 @@ writes the same files described above.
213
213
 
214
214
  ## Installed extensions and packs
215
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
216
+ Every theme and palette comes in a **pack**. mdeck looks for them in this
217
+ order: the packs that come with mdeck (`assets/packs/`, minus those removed
218
+ with `mdeck themes remove`, listed in `~/.mdeck/removed.json`), the user's
219
+ folder (`~/.mdeck/extensions`, or `$MDECK_HOME/extensions`), and the
220
+ `extensions/` folder beside the deck. For themes and palettes a later place
221
+ replaces an earlier one with the same id: an installed newer version replaces
222
+ the bundled one, and a deck's own copy replaces both (with a warning when it
223
+ replaces one installed for every deck). Layouts are built in and may not be
224
+ replaced; within one place an id may appear only once.
225
+
226
+ `mdeck themes install <pack>` installs a pack for every deck, into the user's
227
+ folder; given a slide file, a folder or `--local`, it installs into the
228
+ `extensions/` folder beside the deck. Installing a bundled pack for every deck
229
+ offers it again; beside a deck it is copied. A pack is a folder with a
225
230
  `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`
231
+ `license`, `homepage`, `mdeck = ">=X.Y.Z"`, the oldest mdeck it works with,
232
+ and `requires = [...]`, the packs it needs) and one folder per theme or
233
+ palette, each holding only `extension.toml` and, for a theme, `styles.css`. A
234
+ theme's palettes must be in its pack or in a pack it requires; installing a
235
+ pack installs those too, and `remove` refuses while another installed pack
236
+ needs one. Theme fonts must come from `https://fonts.googleapis.com/` or
237
+ `https://fonts.bunny.net/`, and `styles.css` may contain neither `@import`
230
238
  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`.
239
+ `.mdeck-pack.json` with the pack, its version, its requirements, its source
240
+ and a checksum of every file; `update` and `remove` refuse to touch files
241
+ changed since then unless given `--force`.
234
242
 
235
243
  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.
244
+ its ids, `requires`, `url`, `sha256`, `previews`, and `bundled` for the packs
245
+ that come with mdeck) and one JSON file per pack version holding the text of
246
+ its files. `mdeck themes build <packs> -o <out> [--check]` writes both from a
247
+ folder of packs and mdeck's bundled packs; `MDECK_THEMES_URL` points mdeck at
248
+ another index. Without a connection, mdeck offers its bundled packs.
240
249
 
241
250
  ## Listing what is available
242
251
 
@@ -9,7 +9,7 @@ Every palette is a family with two variants, **light** and **dark**. A deck choo
9
9
  ```yaml
10
10
  ---
11
11
  theme: neue
12
- palette: terra # optional; without it the theme's default palette
12
+ palette: nordic # optional; without it the theme's default palette
13
13
  appearance: dark # optional: light or dark; without it the theme's default
14
14
  ---
15
15
  ```
@@ -20,21 +20,17 @@ The presenter view and the reader view switch palette and light or dark without
20
20
 
21
21
  | Palette | Light | Dark |
22
22
  |---|---|---|
23
- | `lagoon` | teal on warm stone, orange second accent | deep teal-black, bright teal |
24
23
  | `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
24
  | `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
25
  | `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 |
26
+ | `lagoon` | teal on warm stone, orange second accent | deep teal-black, bright teal |
27
+ | `paper` | off-white paper and near-black ink with one orange accent | charcoal with a softer orange |
34
28
 
35
29
  `mdeck list palettes` lists them, with any of your own.
36
30
 
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.
31
+ Each theme names a default: neue uses `swiss`, academic `nordic`, aurora `neon`.
32
+
33
+ More palettes are in the [theme repository](https://github.com/tilman-schieber/mdeck-themes). The palettes cobalt, terra, phosphor, pastel, ember and forest, built in before mdeck 3.0, are there: cobalt in the `duet` pack, terra in `editorial`, phosphor in `terminal`, pastel in `sketch`, and ember and forest in `earth`. Install one with `mdeck themes install <pack> my-talk.md`.
38
34
 
39
35
  ## Colours
40
36
 
@@ -90,7 +86,7 @@ description = "Sea blue and rust on chalk white."
90
86
 
91
87
  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
88
 
93
- `theme = "my-theme"` makes a palette private: only that theme offers it, as FHNW does with `brand`.
89
+ `theme = "my-theme"` makes a palette private: only that theme offers it, as a corporate design theme does with its own colours.
94
90
 
95
91
  ## Readability
96
92
 
@@ -103,4 +99,4 @@ Colour names start with dashes, so quote them as TOML keys. A dark variant also
103
99
  | both accents on the background | 3 : 1 (large type) |
104
100
  | text on the accent | 3 : 1 |
105
101
 
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.
102
+ The built-in palettes meet these in both variants. A private palette may use its accent only as a surface (a corporate yellow, say), so its accents are not checked as text.
@@ -18,15 +18,16 @@ theme: neue
18
18
  |---|---|---|
19
19
  | `neue` | Swiss style: large flush-left type, rules, red on white | `swiss` |
20
20
  | `aurora` | Northern lights: curtains of light, night-sky chapters, frosted glass | `neon` |
21
- | `duet` | Two voices: heavy slab headings, split slides as two colour fields, diagonal chapters | `cobalt` |
22
- | `editorial` | Magazine spread: masthead rule, drop caps, pull quotes, Roman chapter numerals | `terra` |
23
- | `fhnw` | The FHNW corporate design | `brand` (the only one) |
24
- | `terminal` | A terminal session: prompts, a blinking cursor, a tmux status bar | `phosphor`, dark |
21
+ | `minimal` | Nothing but the content: system fonts, calm type, no decoration; works offline | `paper` |
25
22
  | `academic` | A lecture: compact type, the heading fixed at the top and the content centred below, theorem and definition blocks, booktabs tables, a footnote rule | `nordic` |
26
- | `sketch` | A sketchbook: handwriting on dotted paper, marker scribbles, sticky-note callouts, taped photos | `pastel` |
27
23
 
28
24
  `mdeck list my-talk.md` lists them with their descriptions.
29
25
 
26
+ More themes are in the [theme repository](https://github.com/tilman-schieber/mdeck-themes):
27
+ `mdeck themes search` lists them, and `mdeck themes install <pack> my-talk.md`
28
+ puts one beside the deck. The themes duet, editorial, fhnw, terminal and sketch,
29
+ built in before mdeck 3.0, are there as packs of the same name.
30
+
30
31
  ## Theme structure
31
32
 
32
33
  ```text
@@ -78,8 +79,8 @@ A parameter's default is its token's value. Unknown parameter names are
78
79
  reported by `mdeck check`.
79
80
 
80
81
  Optional settings: `description`, `appearance = "dark"` for a theme that starts
81
- dark, and `palettes = [...]` to offer only those palettes (the FHNW theme offers
82
- only `brand`). `[files] styles` may name one stylesheet or a list.
82
+ dark, and `palettes = [...]` to offer only those palettes (a corporate design
83
+ theme can offer only its own palette). `[files] styles` may name one stylesheet or a list.
83
84
 
84
85
  ### `styles.css`
85
86
 
@@ -27,14 +27,10 @@ If you already have a settings block there, change the existing lines rather tha
27
27
  |---|---|
28
28
  | `neue` | Swiss style: large type, clear lines, red on white |
29
29
  | `aurora` | Northern lights: curtains of light, night-sky chapters and glass |
30
- | `duet` | Two voices: two accent colours that take turns, slab headings |
31
- | `editorial` | A magazine spread: serif headlines, drop caps, pull quotes |
32
- | `fhnw` | The FHNW visual identity |
33
- | `terminal` | A terminal session: headings typed at a prompt, a blinking cursor, a status bar |
30
+ | `minimal` | Nothing but the content: system fonts, calm type, no decoration; works offline |
34
31
  | `academic` | A lecture: compact slides, theorem and definition boxes, tables like in a paper |
35
- | `sketch` | A sketchbook: handwriting, marker scribbles, sticky notes; a chalkboard in the dark |
36
32
 
37
- Each theme comes with colours that suit it, so you do not have to choose any.
33
+ Each theme comes with colours that suit it, so you do not have to choose any. More themes are in the theme repository (see “Themes that moved to the repository” below).
38
34
 
39
35
  ## See the themes
40
36
 
@@ -52,41 +48,17 @@ Default colours: `swiss`.
52
48
 
53
49
  Default colours: `neon`.
54
50
 
55
- ### Duet
56
-
57
- [![The tour's title slide in the Duet theme](images/themes/duet.webp)](images/themes/duet.webp)
58
-
59
- Default colours: `cobalt`.
60
-
61
- ### Editorial
62
-
63
- [![The tour's title slide in the Editorial theme](images/themes/editorial.webp)](images/themes/editorial.webp)
64
-
65
- Default colours: `terra`.
66
-
67
- ### FHNW
68
-
69
- [![The tour's title slide in the FHNW theme](images/themes/fhnw.webp)](images/themes/fhnw.webp)
70
-
71
- Default colours: its own FHNW colours.
72
-
73
- ### Terminal
74
-
75
- [![The tour's title slide in the Terminal theme](images/themes/terminal.webp)](images/themes/terminal.webp)
76
-
77
- Default colours: `phosphor`, dark.
78
-
79
51
  ### Academic
80
52
 
81
53
  [![The tour's title slide in the Academic theme](images/themes/academic.webp)](images/themes/academic.webp)
82
54
 
83
55
  Default colours: `nordic`.
84
56
 
85
- ### Sketch
57
+ ### Minimal
86
58
 
87
- [![The tour's title slide in the Sketch theme](images/themes/sketch.webp)](images/themes/sketch.webp)
59
+ [![The tour's title slide in the Minimal theme](images/themes/minimal.webp)](images/themes/minimal.webp)
88
60
 
89
- Default colours: `pastel`.
61
+ Default colours: `paper`. It uses the fonts already on the computer, so it needs no internet connection and looks plain on purpose.
90
62
 
91
63
  ## Choose colours
92
64
 
@@ -94,27 +66,19 @@ To use other colours, set `palette` to one of these:
94
66
 
95
67
  | Name to use | Colours |
96
68
  |---|---|
97
- | `lagoon` | Teal on warm stone |
98
69
  | `swiss` | White, black and signal red (neue's own) |
99
- | `cobalt` | Strong ultramarine on white |
100
- | `nordic` | Ice grey, deep navy and a cool steel blue |
101
- | `graphite` | Black and white with a steel-blue accent |
102
- | `terra` | Cream, deep navy and brick red |
103
- | `forest` | Deep green with moss and ochre |
104
- | `ember` | Sand and espresso with orange |
105
- | `neon` | Violet and magenta, loud |
106
- | `phosphor` | Green on black, like an old terminal screen |
107
- | `pastel` | Soft pastels, mauve and peach (in the style of Catppuccin) |
70
+ | `nordic` | Ice grey, deep navy and a cool steel blue (academic's own) |
71
+ | `neon` | Violet and magenta, loud (aurora's own) |
72
+ | `lagoon` | Teal on warm stone |
73
+ | `paper` | Off-white and near-black with one orange accent (minimal's own) |
108
74
 
109
75
  ```yaml
110
76
  ---
111
77
  theme: neue
112
- palette: terra
78
+ palette: paper
113
79
  ---
114
80
  ```
115
81
 
116
- The FHNW theme always uses the FHNW colours.
117
-
118
82
  ## Light or dark
119
83
 
120
84
  Every palette has a light and a dark version. Choose dark for a dark lecture hall, light for a bright room:
@@ -122,7 +86,7 @@ Every palette has a light and a dark version. Choose dark for a dark lecture hal
122
86
  ```yaml
123
87
  ---
124
88
  theme: neue
125
- palette: terra
89
+ palette: nordic
126
90
  appearance: dark
127
91
  ---
128
92
  ```
@@ -131,7 +95,7 @@ Some slides use the other version on purpose: neue's statement slides are dark i
131
95
 
132
96
  ## Every theme in every palette
133
97
 
134
- The first chapter slide of the tour in each palette a theme offers. Choose a theme above the pictures; click a sheet to see it larger. The FHNW theme has only its own colours, so it is not shown here.
98
+ The first chapter slide of the tour in each palette a theme offers. Choose a theme above the pictures; click a sheet to see it larger. A theme that offers only its own colours is not shown here.
135
99
 
136
100
  Some themes turn their chapter slides around on purpose: aurora's are a night sky in a light talk, and light in a dark one.
137
101
 
@@ -155,7 +119,27 @@ Its theme, palette and light or dark controls, under the notes, let you try othe
155
119
 
156
120
  ## More themes from other people
157
121
 
158
- The theme repository has themes and palettes others made. `mdeck themes search` lists them, and `mdeck themes install <pack> my-talk.md` puts one beside your slides; see [Install or share a theme](theme-repository.html).
122
+ The themes above come with mdeck as packs. The theme repository has more: `mdeck themes search` lists them, and `mdeck themes install <pack>` installs one for all your decks. You can also remove the ones you never use; see [Install, remove or share a theme](theme-repository.html).
123
+
124
+ ### Themes that moved to the repository
125
+
126
+ Earlier versions of mdeck came with more themes and palettes. They are now packs in the theme repository:
127
+
128
+ | Pack | What it holds |
129
+ |---|---|
130
+ | `duet` | The duet theme (two accent colours that take turns, slab headings) and the `cobalt` palette |
131
+ | `editorial` | The editorial theme (a magazine spread with serif headlines and pull quotes) and the `terra` palette |
132
+ | `fhnw` | The FHNW visual identity, with its own `brand` palette only |
133
+ | `terminal` | The terminal theme (headings typed at a prompt, a status bar) and the `phosphor` palette; it starts dark |
134
+ | `sketch` | The sketch theme (handwriting, marker scribbles, sticky notes) and the `pastel` palette |
135
+ | `earth` | The `ember` and `forest` palettes |
136
+ | `graphite` | The `graphite` palette: black and white with a steel-blue accent |
137
+
138
+ A deck that still names one of them stops with a message that tells you what to install, for example:
139
+
140
+ ```sh
141
+ mdeck themes install duet
142
+ ```
159
143
 
160
144
  ## Add your name and organization
161
145
 
@@ -12,7 +12,7 @@ For how the commands, the views and the servers fit together, see [Views, comman
12
12
  | `mdeck new` | Make a presentation with guided questions |
13
13
  | `mdeck run my-talk.md` | Open the launch page: present, edit, check and send from one place; slides reload when you save |
14
14
  | `mdeck edit my-talk.md` | Edit slides, colors and themes in the browser; saves to the file |
15
- | `mdeck themes search`, `install <pack>`, `remove`, `update`, `list` | Themes and palettes from the theme repository; see [Install or share a theme](theme-repository.html) |
15
+ | `mdeck themes search`, `install <pack>`, `remove`, `update`, `list` | Themes and palettes: install more, remove the ones you do not use; see [Install, remove or share a theme](theme-repository.html) |
16
16
  | `mdeck design [my-talk.md or folder]` | Look at themes and palettes on a sample deck and fine-tune them; saves to `extensions/` |
17
17
  | `mdeck migrate my-talk.md --dry-run` | Preview the changes needed for API 2.0 |
18
18
  | `mdeck check my-talk.md` | Check settings and look for missing local files |
@@ -31,7 +31,7 @@ For how the commands, the views and the servers fit together, see [Views, comman
31
31
 
32
32
  - **Preview:** a small live copy of the deck to flip through; click it to open the audience window at that slide.
33
33
  - **Present:** the presenter view, audience window and reader view, each in a new tab. The presenter view has notes, drawing controls, a timer and next-slide preview; switch to its slide-only layout for a single screen. The audience window shows slides without notes. Fullscreen is a control inside either view, not a separate view.
34
- - **Write and learn:** the visual editor and these guides. Each starts the first time you click it.
34
+ - **Write and learn:** the visual editor, the theme editor (themes and palettes on a sample deck, see [Install, remove or share a theme](theme-repository.html)) and these guides. Each starts the first time you click it.
35
35
  - **Send:** buttons that make the `dist` folder, one file to send, or a PDF, next to your slide file, and show them in your file manager.
36
36
  - **Polls:** for a deck with polls: the server (built in, or the `server` setting and whether it answers), the join link and session code for phones, and for a server of your own the key that lets your browser move the phones along and reset polls (see below).
37
37
  - **Check:** the same problems `mdeck check` reports, such as missing pictures.
@@ -14,7 +14,7 @@ The rest of this page is the reference for what it writes, and for anyone comfor
14
14
 
15
15
  To look at the result and fine-tune it, run `mdeck design my-talk.md` (or `mdeck design` in a folder without a deck). It shows the theme or palette on a sample deck with every kind of slide, light and dark, and has forms for colours, fonts, sizes and spacing; see [Edit slides in your browser](editing.html). The files it writes are the ones described here.
16
16
 
17
- Someone may already have made what you need: `mdeck themes search` lists the theme repository, and [Install or share a theme](theme-repository.html) explains how to install a pack or share yours.
17
+ Someone may already have made what you need: `mdeck themes search` lists the theme repository, and [Install, remove or share a theme](theme-repository.html) explains how to install a pack or share yours.
18
18
 
19
19
  Themes and palettes are **extensions**: each one is a folder with an `extension.toml` file that says what it is. Slide layouts use the same idea. Put the folder in `extensions/` beside your slide file and mdeck finds it automatically; there is nothing to register. The [extensions reference](extensions.html) has the complete list of settings.
20
20
 
@@ -1,6 +1,6 @@
1
- # Install or share a theme
1
+ # Install, remove or share a theme
2
2
 
3
- Besides the themes and palettes that come with mdeck, other people share theirs in the **theme repository**: <https://github.com/tilman-schieber/mdeck-themes>. A shared theme or palette comes as a **pack**: one theme with the palettes made for it, or a set of palettes.
3
+ Every theme and palette in mdeck comes in a **pack**: one theme with the palettes made for it, or a set of palettes. A few packs come with mdeck: `neue`, `academic`, `aurora` and `minimal`, each a theme with its own palette, and the palette `lagoon`. They work right away, also without an internet connection. More packs are in the **theme repository**; try them all on a sample deck at <https://gh.tschieber.de/mdeck-themes/>.
4
4
 
5
5
  ## Find and install one
6
6
 
@@ -11,35 +11,37 @@ mdeck themes search
11
11
  mdeck themes search warm
12
12
  ```
13
13
 
14
- Install a pack beside your slides:
14
+ Install a pack:
15
15
 
16
16
  ```sh
17
- mdeck themes install solarized my-talk.md
17
+ mdeck themes install duet
18
18
  ```
19
19
 
20
- It is copied into the `extensions` folder next to `my-talk.md`, like a theme you made yourself, so the slide folder keeps working on any computer. Then choose it in the deck settings (`palette: solarized`) or in the editor's **Deck** tab.
20
+ It is installed for every deck on this computer, in a folder in your home folder (`~/.mdeck/extensions`). Then choose it at the top of a slide file (`theme: duet`) or in the editor's **Deck** tab. Some packs need another pack, for example for a palette their theme uses; `install` brings that one along.
21
21
 
22
- The design page has the repository too: open it with `mdeck design my-talk.md`, and under **From the theme repository** press **Show what others made**. Each pack shows a picture and an **Install** button.
22
+ The design page has the same: open it with `mdeck design`, choose **Show what you can install**, and press **Install** under a pack.
23
23
 
24
- ## For every deck
24
+ ## Beside one deck
25
25
 
26
- With `--global`, a pack is installed once for all your decks, in a folder in your home folder (`~/.mdeck/extensions`):
26
+ Give a slide file (or the folder it is in) to put the pack into the `extensions` folder next to it instead:
27
27
 
28
28
  ```sh
29
- mdeck themes install solarized --global
29
+ mdeck themes install duet my-talk.md
30
30
  ```
31
31
 
32
- A slide file that uses it works only on your computer. `mdeck check` reminds you, and `mdeck themes install solarized my-talk.md` puts a copy beside the slides. When a deck has its own copy, that one is used.
32
+ The slide folder then carries the theme, so it works on a computer where the pack is not installed, for example when you send a colleague the folder. A deck's own copy is used before one installed for every deck. Files made with `mdeck send`, `mdeck build` or `mdeck pdf` always carry their theme, wherever it came from.
33
33
 
34
34
  ## Update and remove
35
35
 
36
36
  ```sh
37
- mdeck themes list my-talk.md # what is installed, here and for every deck
38
- mdeck themes update my-talk.md # newer versions of everything installed here
39
- mdeck themes remove solarized my-talk.md
37
+ mdeck themes list # what comes with mdeck, and what is installed
38
+ mdeck themes update # newer versions of everything installed
39
+ mdeck themes remove duet
40
40
  ```
41
41
 
42
- Add `--global` to work on the packs for every deck. If you changed an installed file by hand, `update` and `remove` stop and tell you which one, so your change is not lost; add `--force` to go ahead anyway.
42
+ Add a slide file, or `--local`, to work on the packs beside that deck. If you changed an installed file by hand, `update` and `remove` stop and tell you which one, so your change is not lost; add `--force` to go ahead anyway. A pack that another installed pack needs stays until that one is removed.
43
+
44
+ The packs that come with mdeck can be removed too: `mdeck themes remove aurora` hides it from every deck and from the lists. `mdeck themes install aurora` brings it back, without needing the internet. A deck that sets no theme uses `neue`; if you removed it, mdeck tells you to install it again or to choose another theme. The last theme cannot be removed: install another one first.
43
45
 
44
46
  ## What a pack may contain
45
47
 
@@ -69,8 +71,10 @@ description = "Navy and brass, with a serif for headings."
69
71
  version = "1.0.0"
70
72
  author = "Your Name"
71
73
  license = "MIT"
72
- mdeck = ">=2.3.0"
74
+ mdeck = ">=3.0.0"
73
75
  ```
74
76
 
77
+ A pack whose theme uses a palette from another pack names that pack: `requires = ["lagoon"]`.
78
+
75
79
  3. Check it the way the repository will: `mdeck themes build packs -o site --check` shows every theme and palette in the pack on every kind of slide, light and dark, and fails on text that does not fit or is hard to read.
76
80
  4. Open a pull request. Once it is merged, `mdeck themes search` lists it. For a new version, raise `version` in `pack.toml`.
@@ -1,5 +1,5 @@
1
1
  ---
2
- theme: editorial
2
+ theme: academic
3
3
  show:
4
4
  organization: none
5
5
  author: none
Binary file
Binary file
@@ -7,7 +7,7 @@ export const pages = [
7
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
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
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.' },
10
+ { slug: 'theme-repository', title: 'Install, remove or share a theme', group: 'Make your presentation', file: 'theme-repository.md', description: 'Packs of themes and palettes: those that come with mdeck, more from the theme repository, and how to share your own.' },
11
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
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
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.' },
@@ -1,5 +1,5 @@
1
1
  ---
2
- theme: terminal
2
+ theme: neue
3
3
  meta:
4
4
  title: Deck-local layouts
5
5
  ---
@@ -1,5 +1,5 @@
1
1
  ---
2
- theme: duet
2
+ theme: neue
3
3
  meta:
4
4
  title: "Ask the room"
5
5
  author: "Tilman Schieber"
@@ -1,11 +1,11 @@
1
1
  ---
2
- theme: sketch
2
+ theme: academic
3
3
  meta:
4
4
  title: "Introduction to Python"
5
5
  author: "Tilman Schieber"
6
6
  organization: "FHNW"
7
7
  date: "2026-05-19"
8
- palette: graphite
8
+ palette: paper
9
9
  ---
10
10
 
11
11
  ---
@@ -380,8 +380,8 @@ layout: split
380
380
  :::slot left
381
381
  ```markdown
382
382
  ---
383
- theme: editorial
384
- palette: terra
383
+ theme: aurora
384
+ palette: lagoon
385
385
  ---
386
386
  ```
387
387
  :::
@@ -392,7 +392,7 @@ To try them without changing the file, open the **reader view** and choose **Loo
392
392
  :::
393
393
 
394
394
  :::notes
395
- mdeck has six themes and ten palettes, each light or dark. `mdeck list` shows them all, including any kept in an `extensions` folder beside the deck.
395
+ mdeck has four built-in themes and five palettes, each light or dark. `mdeck list` shows them all, including any kept in an `extensions` folder beside the deck. `mdeck themes search` finds more in the theme repository.
396
396
  :::
397
397
 
398
398
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdeck",
3
- "version": "2.3.0",
3
+ "version": "3.0.0",
4
4
  "type": "module",
5
5
  "description": "Write slides as a plain text file, present them in the browser, share them as one HTML file or PDF.",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@ If `mdeck` is not installed, rely on the quick reference below.
34
34
  ```markdown
35
35
  ---
36
36
  theme: neue # theme id from `mdeck list themes`
37
- palette: terra # optional: lagoon, swiss, cobalt, nordic, graphite, terra, forest, ember, neon, phosphor, pastel
37
+ palette: nordic # optional: swiss, nordic, neon, lagoon, paper, or one installed from the theme repository (`mdeck themes search`)
38
38
  appearance: light # optional: light or dark
39
39
  meta:
40
40
  title: "Talk title"
@@ -135,7 +135,7 @@ Fix anything it reports. When you worked from source material, list what you lef
135
135
 
136
136
  ## 5. A new look: themes and palettes
137
137
 
138
- When the user wants a look the built-in themes and palettes do not give (their institute's colours, a font, the style of a poster or picture), first run `mdeck themes search` (with a word or two): someone may have shared it, and `mdeck themes install <pack> <deck>.md` puts it beside the deck. Otherwise make it as an extension in `extensions/` beside the deck, never as styling on single slides. Read `extensions.md` from the reference folder first; it lists every setting.
138
+ When the user wants a look the built-in themes and palettes do not give (their institute's colours, a font, the style of a poster or picture), first run `mdeck themes search` (with a word or two): someone may have shared it, and `mdeck themes install <pack> <deck>.md` puts it beside the deck, so the slide folder carries it. Otherwise make it as an extension in `extensions/` beside the deck, never as styling on single slides. Read `extensions.md` from the reference folder first; it lists every setting.
139
139
 
140
140
  - **Colours only: a palette.** `extensions/<id>/extension.toml` with `kind = "palette"`, and every colour role (`--bg`, `--surface`, `--ink`, `--ink-soft`, `--muted`, `--rule`, `--accent`, `--accent-2`, `--on-accent`) in both `[light]` and `[dark]`. Text colours must stay readable on `--bg` and `--surface` in both variants, because themes use the other variant for inverted slides.
141
141
  - **Fonts, sizes, spacing or arrangement: a theme.** Copy the folder of the closest built-in theme (`assets/extensions/themes/<id>/` in the mdeck repository or in `$(npm root -g)/mdeck/`) to `extensions/<new-id>/`, change `id` and `title`, then its tokens and `styles.css`. A theme takes no colours of its own: it names its default `palette`, and the colours come from palettes.
@@ -26,13 +26,6 @@ export function checkDeck(slidesPath, registry, source = readFileSync(slidesPath
26
26
  if (record.source !== 'local') continue
27
27
  for (const problem of paletteProblems(record.manifest)) diagnostics.push({ severity: 'warning', code: 'palette-contrast', message: `Palette "${record.id}", ${problem}`, line: 1, column: 1 })
28
28
  }
29
- // A theme or palette installed for this user only: the slide file needs it
30
- // beside it to work on another computer.
31
- const config = deck.deckConfig ?? {}
32
- for (const [kind, id] of [['theme', config.theme], ['palette', config.palette]]) {
33
- const record = id && registry[`${kind}s`][id]
34
- if (record?.source === 'user') diagnostics.push({ severity: 'warning', code: 'user-extension', message: `The ${kind} "${id}" is installed only on this computer (${dirname(record.dir)}); copy it into the deck's extensions folder, for example with mdeck themes install, so the slide file works elsewhere`, line: 1, column: 1 })
35
- }
36
29
  // The deck's drawings file: readable, and only for slides that still exist.
37
30
  const inkPath = inkFileFor(resolve(slidesPath))
38
31
  const renamed = drawingsDiagnostic(slidesPath)
@@ -5,8 +5,9 @@
5
5
  import { createHash } from 'node:crypto'
6
6
  import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, rmSync, unlinkSync } from 'node:fs'
7
7
  import { resolve, basename, dirname, relative } from 'node:path'
8
- import { builtInRegistry, loadRegistry, serializeRegistry } from '../extensions/discover.js'
9
- import { fetchIndex, findPack, installedPacks, installFromIndex, PackError } from '../extensions/packs.js'
8
+ import { bundledPacks, loadRegistry, removedPacks, serializeRegistry } from '../extensions/discover.js'
9
+ import { findPack, loadCatalogue, PackError } from '../extensions/packs.js'
10
+ import { installHere, packsAt, removeHere, target } from '../extensions/installed.js'
10
11
  import { createRequire } from 'node:module'
11
12
  import { ManifestError, KINDS, ID_RE, MANIFEST_FILENAME, parseManifestText, validateManifest } from '../extensions/manifest.js'
12
13
 
@@ -180,7 +181,6 @@ export function createExtensionStore(deckDir, { registryFor }) {
180
181
  }
181
182
 
182
183
  export function editorMiddleware(deckFile, { registryFor, extensions = createExtensionStore(dirname(deckFile.path), { registryFor }) }) {
183
- const extensionsDir = resolve(dirname(deckFile.path), 'extensions')
184
184
  return async (request, response, next) => {
185
185
  const pathname = new URL(request.url, 'http://localhost').pathname
186
186
  if (!isAllowedRequest(request)) return send(response, 403, { error: 'Requests are only accepted from this editor on this computer' })
@@ -201,18 +201,26 @@ export function editorMiddleware(deckFile, { registryFor, extensions = createExt
201
201
  response.setHeader('Allow', 'GET, PUT, DELETE')
202
202
  return send(response, 405, { error: 'Method not allowed' })
203
203
  }
204
- // The theme repository: what it offers, and installing a pack into the
205
- // deck's extensions folder.
204
+ // Packs: what the repository and mdeck offer, and installing one for
205
+ // every deck (as mdeck themes install does).
206
206
  if (pathname === '/themes/index' && request.method === 'GET') {
207
- const index = await fetchIndex()
208
- return send(response, 200, { ...index, installed: installedPacks(extensionsDir) })
207
+ const catalogue = await loadCatalogue({ bundled: bundledPacks({ all: true }) })
208
+ const removed = removedPacks()
209
+ const installed = Object.fromEntries(Object.entries(packsAt(target(null, false))).map(([id, pack]) => [id, { version: pack.version ?? null, bundled: Boolean(pack.bundled) }]))
210
+ return send(response, 200, { url: catalogue.url, offline: catalogue.offline, packs: catalogue.packs.map(({ dir, ...pack }) => ({ ...pack, removed: removed.includes(pack.id) })), installed })
209
211
  }
210
212
  if (pathname === '/themes/install' && request.method === 'POST') {
211
213
  const body = await readJson(request)
212
- const index = await fetchIndex()
213
- const registry = builtInRegistry()
214
- const result = await installFromIndex(index, findPack(index, String(body?.id ?? '')), { root: extensionsDir, known: { themes: registry.themes, palettes: registry.palettes }, mdeckVersion: VERSION })
215
- return send(response, 200, { ...result, registry: serializeRegistry(registryFor()) })
214
+ const catalogue = await loadCatalogue({ bundled: bundledPacks({ all: true }) })
215
+ findPack(catalogue, String(body?.id ?? ''))
216
+ const steps = await installHere(catalogue, String(body.id), target(null, false), { mdeckVersion: VERSION })
217
+ return send(response, 200, { steps, registry: serializeRegistry(registryFor()) })
218
+ }
219
+ if (pathname === '/themes/remove' && request.method === 'POST') {
220
+ const body = await readJson(request)
221
+ const catalogue = await loadCatalogue({ bundled: bundledPacks({ all: true }), online: false })
222
+ const removed = removeHere(catalogue, String(body?.id ?? ''), target(null, false))
223
+ return send(response, 200, { ...removed, registry: serializeRegistry(registryFor()) })
216
224
  }
217
225
  if (pathname === '/deck' && request.method === 'GET') {
218
226
  const registry = registryFor()