mkdeck
Minimal HTML slide decks from Markdown or Python, served like mkdocs.
Write your slides in a Markdown file and run one command. mkdeck serves the deck on a local port, and the page reloads when you save the file. reveal.js, KaTeX and the fonts all travel inside the package, so there is no Node toolchain to set up. Mermaid is the one exception: a slide that holds a diagram loads a pinned release of it from a CDN, so that slide needs a network connection (or a local copy of Mermaid that you point the diagram at).
Install
To try it once, with nothing installed:
uvx mkdeck new talk
uvx mkdeck serve talk
To use it regularly, install the command:
uv tool install mkdeck # or: pip install mkdeck
Inside a project that has a pyproject.toml, add it as a dependency with
uv add mkdeck (uv add --group slides mkdeck keeps it out of your runtime
dependencies).
Quickstart
mkdeck new talk # writes talk/deck.md, talk/deck.yml and talk/assets/
mkdeck serve talk # serves http://127.0.0.1:5020 and reloads when you save
Add --open to mkdeck serve to open the deck in your browser, and --port
to pick another port. Without a global install, put uvx mkdeck or
uv run mkdeck in front of the same commands.
What a slide looks like
Slides are separated by ---. Say one thing per slide, then show the evidence.
This is a whole deck file of one slide; a later slide follows a --- line:
<!--
id: departure
-->
Five of five seeds cross the wall at 22 N m.

Point a slide at an HTML file and mkdeck frames it. That is how a Brax viewer,
a Plotly chart or any other interactive page ends up running inside a slide,
next to the sentence that explains it. Point it at a PNG or a GIF instead and
you get a picture. Numbers such as 22 N m come out in a darker ink, because
that is what people look for first.
Math is KaTeX. mkdeck leaves a placeholder for each formula, and the KaTeX that ships in the package draws it in the browser, so math works offline. Diagrams are Mermaid fences, and they load Mermaid from a CDN (see above). Tables are ordinary Markdown pipes.
Or build it from Python
Handy when the slides report numbers you already compute, since nobody has to retype a value that changed:
from mkdeck import Deck, Embed, Slide
deck = Deck(title="Vault runs", date="2026-09-18")
for run in runs:
deck.slides.append(
Slide(
sentence=f"{run.crossings} of 5 seeds cross at {run.cap} N m.",
embeds=[Embed(f"assets/{run.name}.html", label=run.label)],
)
)
deck.build("site/")
An embed such as assets/run3.html is resolved relative to the deck's
source folder, which is the current directory unless you pass source=. Run
the script from the folder that holds assets/, or pass
deck.build("site/", source="slides/"). mkdeck copies the files into site/.
Markdown and Python produce the same slide objects and render through the same
code, so the two ways of writing a deck stay in step. load_source reads a
Markdown deck into an object with the same two methods, build and serve:
from mkdeck import load_source
load_source("talk").build("site/")
mkdeck, mkdeck.errors and mkdeck.rollout are the public API; every other
module is an implementation detail.
Commands
| Command | What it does |
|---|---|
mkdeck new FOLDER |
Start a deck |
mkdeck serve PATH |
Serve it, and reload when you save |
mkdeck build PATH |
Write it to a folder, or to one HTML file |
mkdeck rollout PAGES |
Turn Brax playback pages into rollouts that play offline |
mkdeck check PATH |
Tell you which slides overflow the screen (--strict exits with an error, for CI) |
mkdeck export PATH |
Print it to a PDF (rollouts print as a still frame) |
check and export drive headless Chromium through Playwright. Install the
check extra (pip install "mkdeck[check]") and run python -m playwright install chromium first. With uv tool install, install "mkdeck[check]" and
run uvx playwright install chromium. The extra has that name because mkdeck check was the first command to need it; mkdeck export uses it too. Check and
export only decks you trust: raw HTML in a slide runs in that browser.
Documentation
The docs cover the Markdown format,
the Python API, and how to bring your own colours, fonts and components to a
deck. To read them from a checkout, run make docs.
Contributing
Bug reports and pull requests are welcome. See CONTRIBUTING.md for the local checks and the release flow.
License
mkdeck is MIT licensed. The package also carries reveal.js, KaTeX, three.js and the KaTeX and Roboto fonts under their own licenses; see THIRD_PARTY_NOTICES.md.
Metadata
Release files for mkdeck 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mkdeck-0.1.0.tar.gz | 893.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mkdeck-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.7 MB
Release files / mkdeck-0.1.0.tar.gz
| Download URL | mkdeck-0.1.0.tar.gz |
|---|---|
| Size | 893.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5ad293d2565d5627307f4f07b7419b1b8031a5a2dddd421e0827ab13c3a6cafc
|
|
BLAKE2b-256 checksum How to use checksums |
283f6caff38dce2791333cce24391df0a9789aebb43ea38dcb5a307552bf2c06
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / mkdeck-0.1.0-py3-none-any.whl
| Download URL | mkdeck-0.1.0-py3-none-any.whl |
|---|---|
| Size | 847.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e51f7f35d4632040f6b00745a4f6fa3dc7d84954ca83682a845147aa69eb9748
|
|
BLAKE2b-256 checksum How to use checksums |
53a183f6b0e101d563c7e063239729eb687daba82775f59ffcbed0ff2c5bc9e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency log