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