Markdown in, presentation out.
The slides sibling of mdstack. Point it
at a folder — mdslides scaffolds a starter slides.md, then presents it in a
dev server or builds a self-contained dist/ you can host anywhere static.
Status: pre-1.0, provisional. CLI flags and markdown conventions may change before
0.x → 1.0.
npx @exor404/mdslides@latestNo install step. It asks for a name, scaffolds <name>/<name>.md (three
sample slides — a title page, a list, and a help slide) plus a
mdslides.config.js, and opens the dev server. The name defaults to the current
folder, so pressing Enter at Name your presentation (chemistry): gives you
chemistry/chemistry.md. That file is your deck — edit it and the slides
live-reload.
Point it at a folder for the other commands:
npx @exor404/mdslides ./chemistry # present (dev server, live-reload)
npx @exor404/mdslides build ./chemistry # static build → ./chemistry/dist/
npx @exor404/mdslides preview ./chemistry # serve the built dist/
npx @exor404/mdslides export ./chemistry # → chemistry.pdf (one page per slide)Already have a deck? Point straight at the file: npx @exor404/mdslides ./chemistry.md.
Heads-up:
npm install @exor404/mdslidesonly installs the package — running the CLI (vianpx, as above) is what scaffolds and presents. Usingnpxalso keeps the engine's dependencies in npx's cache instead of bloating a project'snode_modules.
Prefer a global command? npm i -g @exor404/mdslides makes mdslides available
directly (mdslides ./chemistry).
Try the bundled example from a clone:
npm install
npm run dev # opens ./exampleThe package is published on the public npm registry as
@exor404/mdslides. Pick the
option that suits you:
No install (recommended). npx fetches and caches the latest version, then
runs it — nothing is added to your project:
npx @exor404/mdslides@latest # prompts for a name, scaffolds + presentsGlobal install. Puts an mdslides command on your PATH:
npm install -g @exor404/mdslides
mdslides ./chemistry # then use it anywhere
mdslides --help # (or run with no folder to start fresh)Update later with npm update -g @exor404/mdslides; remove with
npm uninstall -g @exor404/mdslides.
As a project dependency. Add it to a repo so collaborators get the same
version via npm install:
npm install -D @exor404/mdslides
npx mdslides ./chemistry # resolves from local node_modulesRequires Node 18+. Installing the package pulls in its rendering engine (Astro, Shiki, KaTeX) — that's why
npxis the lightest way to try it: those dependencies stay in npx's cache instead of your project'snode_modules.
One markdown file is the whole deck. Every # (H1) heading starts a new
slide — write plain markdown in between. A standalone --- line is an
explicit break (for a slide with no heading, or to split one section).
# Presentation title
## A subtitle
**Your Name** · {{date}}
# Second slide
- a point
- another (bullets reveal one at a time)The first slide is the title slide automatically: the # renders large,
## is the subtitle, and the last line becomes a byline pinned to the bottom —
write your presenter name(s) in markdown there. The {{date}} token resolves to
today's date. Opt a slide out with <!-- slide: plain -->, or mark another
slide as a title with <!-- slide: title -->.
Only what slides actually need:
- Headings, paragraphs, bold, italic,
strike, ==highlight== - Lists (reveal one item at a time — see Reveal & motion), tables, blockquotes
inline codeand fenced code blocks (syntax-highlighted via Shiki)- Math —
$inline$and$$block$$via KaTeX - Images (relative paths resolve from the deck folder)
Fence a block with a language for syntax highlighting:
```js
export default { theme: 'angular' };
```| Key | Action |
|---|---|
→ space PageDn |
next slide / reveal next fragment |
← PageUp |
previous |
Home / End |
first / last slide |
O |
overview grid (click a slide to jump) |
F |
fullscreen |
. |
black screen |
? |
help |
The URL hash tracks the current slide (#/3) so deep links work.
Slides build themselves as you talk:
- Content fades in when a slide opens — headings, paragraphs, images, code, tables and quotes rise into place with a light stagger.
- Lists reveal step by step. Every list item is hidden when the slide opens
and appears one at a time on
→/space;←steps back. Once all items are shown, the next press advances to the following slide. This is automatic — you don't need to mark anything. - Manual fragments. Append
{.fragment}to any other line (a paragraph, a heading) to hold it back and reveal it on a later press, in document order alongside the list items.
In the overview grid and PDF export, everything is shown at once. Motion respects the OS "reduce motion" setting.
A leading comment configures one slide:
# A slide
<!-- slide: center bg=#1a0b2e -->center— vertically + horizontally centeredbg=<color|url(...)>— slide background
First run drops a mdslides.config.js next to your deck:
export default {
brand: { text: 'mdslides' }, // bottom-left wordmark; '' to hide
theme: 'angular', // built-in: 'angular'
transition: 'fade', // 'fade' | 'slide' | 'none'
};mdslides export renders the /print route (one slide per page, all
fragments shown). It uses Playwright if installed
(npm i -D playwright && npx playwright install chromium); otherwise open
/print in a browser and use Save as PDF.
Node 18+.
Maintainer and technical docs live in docs/:
- Releasing & publishing — the npm publish pipeline, the
NPM_TOKENsecret, and how to cut a release.
MIT