Hello Reveal.js + MkDocs — From Zero to Expert
Today we are going to empower your content with MkDocs & Reveal.js for great Presentations from a Single Markdown Source. Keeping docs and slides in sync is hard. You update a code sample in the docs, forget the deck, and… hello drift. Let’s fix that. In this post, you’ll author one Markdown file and publish it as both:
- A page in your MkDocs site.
- An interactive Reveal.js presentation (plus a PDF export). All of this will be automated using Pandoc, a Makefile, and a GitHub Actions workflow. We’ll use IBM watsonx Agentic AI for the example topic, but the pipeline works for anything.
What you’ll build (Level 0)
A workflow where one Markdown file renders in three places:
- MkDocs page
- Reveal.js HTML deck
- PDF (via DeckTape)
All generated from the same source and deployed by GitHub Actions.
Prerequisites
- Python 3.11+ (the project uses
uvfor fast virtualenv & dependency management) - Pandoc (Markdown → Reveal.js conversion)
- Docker (for DeckTape → PDF export)
- Optional: Node.js + npm (only if you want to run reveal’s dev server; not required for this flow)
Tip:
make installruns a bootstrap to help install system tools and prepares the Python env viauv.
Repository structure
.
├─ docs/
│ ├─ index.md
│ ├─ watsonx-agentic-ai.md # single source of truth (Markdown)
│ └─ slides/ # generated artifacts
│ ├─ watsonx-agentic-ai.html # generated by Pandoc
│ └─ watsonx-agentic-ai.pdf # generated by DeckTape
├─ mkdocs.yml
├─ scripts/
│ ├─ generate_slides.sh
│ ├─ export_pdf.sh
│ └─ bootstrap.sh # optional helper to install tools
├─ Makefile
└─ .github/workflows/deploy.yml
Why docs/slides/? Because mkdocs build copies everything under docs/ into site/. Generating into site/ first is risky — the next mkdocs build would delete your custom files.
Level 1 — Author the single Markdown
Pandoc+Reveal support header attributes right on the heading line. MkDocs happily ignores/keeps those as HTML attributes.
Create docs/watsonx-agentic-ai.md:
---
title: "IBM watsonx & Agentic AI"
author: "Ruslan Magana Vsevolodovna"
date: "2025-11-12"
---
# Introduction to Agentic AI
This document/presentation explores the emerging field of Agentic AI, with a focus on IBM watsonx capabilities.
## What is Agentic AI? {data-transition="slide"}
Agentic AI refers to systems designed to autonomously perceive, reason, plan, and act in complex environments to achieve specific goals.
- Autonomy
- Goal-oriented behavior
- Adaptability & learning
**Key idea:** Beyond prompt→response; agents can proactively plan & act.
## IBM watsonx.ai for Agents {data-transition="fade"}
IBM watsonx.ai provides foundational models and tooling to build, deploy, and govern Agentic AI solutions.
- Foundation models
- Prompt tooling
- Governance (data, risk, policies)
```python
# Illustrative code — check IBM docs for the latest SDKs & model IDs
# from ibm_watsonx_ai import Model
# model = Model(model_id="...") # configure auth & project first
# print(model.generate("Explain Agentic AI in one sentence."))
```
::: notes
Speaker note: call out governance and evaluation early for enterprise readers.
:::
## Building an Agent {data-background-color="#0f172a" data-transition="convex" data-background-transition="zoom"}
1. Define the goal (task & success metrics)
2. Select tools (APIs, DB, search, calculator, internal services)
3. Orchestrate control flow (tool choice, planning, retries)
4. Evaluate, observe, iterate (offline & online)
```bash
# Conceptual CLI flow (placeholder)
agent-builder create my-wx-agent --goal "answer customer queries" --llm "..."
agent-builder deploy my-wx-agent --env production
```
## Ethical Considerations {data-transition="fade"}
- Transparency & observability
- Bias & fairness checks
- Accountability & human oversight
Tips
##creates a new slide with--slide-level=2;###makes a vertical sub-slide.- Speaker notes: wrap content in
::: notes ... :::. - Fragments: wrap bullet text in
<span class="fragment">…</span>or use a class.
Level 2 — Generate the Reveal.js HTML
Use a small helper script that auto-picks the right Reveal version depending on your Pandoc version (v3 CDN for older Pandoc, v4 CDN for modern Pandoc). This is the standard, low-friction approach.
scripts/generate_slides.sh:
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.."; pwd -P)"
SOURCE_MD="${SOURCE_MD:-${ROOT}/docs/watsonx-agentic-ai.md}"
OUT_DIR="${OUT_DIR:-${ROOT}/docs/slides}"
DECK_NAME="${DECK_NAME:-$(basename "${SOURCE_MD%.*}")}"
HTML_OUT="${OUT_DIR}/${DECK_NAME}.html"
command -v pandoc >/dev/null 2>&1 || { echo "Pandoc not found: https://pandoc.org/installing.html" >&2; exit 1; }
PANDOC_VER="$(pandoc -v | head -n1 | awk '{print $2}')"
ver_ge(){ [ "$(printf '%s\n' "$2" "$1" | sort -V | head -n1)" = "$2" ]; }
mkdir -p "${OUT_DIR}"
if pandoc --help | grep -q -- "--embed-resources"; then EMBED_FLAG="--embed-resources"; else EMBED_FLAG="--self-contained"; fi
REVEAL_THEME="${REVEAL_THEME:-league}"
REVEAL_TRANSITION="${REVEAL_TRANSITION:-slide}"
if ver_ge "${PANDOC_VER}" "2.12"; then
REVEAL_VERSION="${REVEAL_VERSION:-4.6.0}"
REVEAL_URL="https://cdn.jsdelivr.net/npm/reveal.js@${REVEAL_VERSION}"
echo "Using Reveal v4 CDN (${REVEAL_URL}) with Pandoc ${PANDOC_VER}"
else
REVEAL_URL="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.9.2"
echo "Using Reveal v3 CDN (${REVEAL_URL}) with Pandoc ${PANDOC_VER}"
fi
echo "Generating Reveal.js slides → ${HTML_OUT}"
pandoc \
--standalone \
--to=revealjs \
--slide-level=2 \
${EMBED_FLAG} \
--variable "revealjs-url=${REVEAL_URL}" \
--variable "theme=${REVEAL_THEME}" \
--variable "transition=${REVEAL_TRANSITION}" \
--variable slideNumber=true \
--variable hash=true \
--metadata=pagetitle:"IBM watsonx & Agentic AI" \
-o "${HTML_OUT}" \
"${SOURCE_MD}"
echo "✅ Slides generated at ${HTML_OUT}"
Run it:
make slides
Level 3 — Export the deck to PDF (DeckTape)
DeckTape renders your HTML in a headless browser.
scripts/export_pdf.sh:
#!/usr/bin/env bash
set -euo pipefail
DECKTAPE_IMAGE="${DECKTAPE_IMAGE:-astefanutti/decktape:latest}"
SLIDE_SIZE="${SLIDE_SIZE:-1920x1080}"
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.."; pwd -P)"
HTML_REL="docs/slides/watsonx-agentic-ai.html"
PDF_REL="docs/slides/watsonx-agentic-ai.pdf"
HTML_HOST="${ROOT}/${HTML_REL}"
PDF_HOST="${ROOT}/${PDF_REL}"
command -v docker >/dev/null 2>&1 || { echo "Docker required for PDF export" >&2; exit 1; }
[ -f "${HTML_HOST}" ] || { echo "Missing HTML: ${HTML_HOST}. Run generate_slides.sh first." >&2; exit 1; }
docker image inspect "${DECKTAPE_IMAGE}" >/dev/null 2>&1 || docker pull "${DECKTAPE_IMAGE}"
MOUNT_POINT="/work"
HTML_URL="file://${MOUNT_POINT}/${HTML_REL}?print-pdf"
PDF_PATH="${MOUNT_POINT}/${PDF_REL}"
mkdir -p "$(dirname "${PDF_HOST}")"
echo "Exporting PDF → ${PDF_HOST}"
docker run --rm -t \
-v "${ROOT}:${MOUNT_POINT}" \
"${DECKTAPE_IMAGE}" \
reveal \
--size "${SLIDE_SIZE}" \
--slides 1- \
--load-pause 1500 \
"${HTML_URL}" \
"${PDF_PATH}"
echo "✅ PDF generated at ${PDF_HOST}"
Run it:
make pdf
DeckTape opens your deck with
?print-pdfso Reveal’s print stylesheet applies.
Level 4 — Minimal MkDocs config
mkdocs.yml:
site_name: Hello Reveal.js + MkDocs
site_url: https://<YOUR_USERNAME>.github.io/<YOUR_REPO_NAME>/
theme:
name: material
nav:
- Home: index.md
- IBM watsonx & Agentic AI: watsonx-agentic-ai.md
- Slides:
- HTML Deck: slides/watsonx-agentic-ai.html
- PDF Deck: slides/watsonx-agentic-ai.pdf
markdown_extensions:
- attr_list
- admonition
- toc:
permalink: true
Local preview:
make serve
# → http://127.0.0.1:8000/
Level 5 — CI/CD with GitHub Actions
This builds slides, exports PDF, builds MkDocs, and deploys to GitHub Pages on every push.
.github/workflows/deploy.yml:
name: Build & Deploy — MkDocs + Reveal.js + PDF
on:
push:
branches:
- main
- master
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
build:
name: Build site, slides & PDF
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure Pages
uses: actions/configure-pages@v5
# --- Slides (Pandoc) ---
- name: Install Pandoc
run: |
sudo apt-get update
sudo apt-get install -y pandoc
- name: Generate Reveal.js HTML slides
run: bash scripts/generate_slides.sh
# --- PDF (DeckTape via Docker) ---
# Run container with the same UID:GID as the runner to avoid EACCES on bind mount
- name: Export PDF with DeckTape
run: |
mkdir -p docs/slides
uid="$(id -u)"; gid="$(id -g)"
docker run --rm -t \
-u "${uid}:${gid}" \
-v "$PWD":/work \
astefanutti/decktape \
reveal \
--size 1920x1080 \
--slides 1- \
"file:///work/docs/slides/watsonx-agentic-ai.html?print-pdf" \
"/work/docs/slides/watsonx-agentic-ai.pdf"
# --- MkDocs (via uv) ---
- name: Install uv (Python env)
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Add uv to PATH
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Install Python 3.11 and deps
run: |
uv python install 3.11
uv sync
- name: Build MkDocs site
run: uv run mkdocs build --strict
# --- Upload built site to the Pages artifact bucket ---
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: site
deploy:
name: Deploy to GitHub Pages
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: $
steps:
- name: Deploy
id: deployment
uses: actions/deploy-pages@v4
After the workflow finishes, your content is available at:
https://<YOUR_USERNAME>.github.io/<YOUR_REPO_NAME>/(site)…/slides/watsonx-agentic-ai.html(deck)…/slides/watsonx-agentic-ai.pdf(PDF)
Level 6 — Power‑ups
- Slide numbers & deep links:
-V slideNumber=true -V hash=true(already in the script) - Vertical stacks: Use
###under a## - Code highlight: Pandoc ships highlight styles; you can add
--highlight-style=pygments. - Math: add
--mathjaxto Pandoc; then use$…$or$$…$$. - Images: regular Markdown images work in both docs & slides. Prefer relative paths under
docs/. - Backgrounds / transitions: header attributes, e.g.
{data-background-color="#111827" data-transition="fade"}.
Troubleshooting
PDF is blank / styling off
Ensure ?print-pdf is appended in the DeckTape URL and that your deck loads over the CDN (not local node_modules).
“File …/css/reset.css not found”
Your Pandoc template expects Reveal v3. Use the version-aware generate_slides.sh above (it selects a v3 CDN for older Pandoc).
Assets 404 in CI
Don’t rely on a local path. Use CDN revealjs-url as shown.
MkDocs can’t find slides
Verify the files exist under docs/slides/ before mkdocs build, and that mkdocs.yml nav: paths match.
Local workflow recap
make install # bootstrap tools + uv env
make slides # generate HTML deck
make pdf # export PDF via DeckTape (Docker)
make serve # run MkDocs locally (http://127.0.0.1:8000)
This is the standard, low-maintenance setup: one Markdown → docs page + slides + PDF, locally and in CI, with minimal moving parts.
Leave a comment