PDF export¶
"Send me the deck" used to mean a manual ritual: start the server, open Chrome, append ?print-pdf, print to file, check the margins. The kslides-export module turns that into one command.
One command¶
./gradlew exportPdf # every presentation -> build/pdf/<deck>.pdf
./gradlew exportPdf -Pdeck=demo # just one presentation
or, in the kslides repo itself:
Under the hood, exportPdf() builds the presentations with buildKSlides, serves them from the same Ktor server HTTP mode uses (on an ephemeral port), and drives headless Chromium through Playwright: each deck is loaded with reveal.js' ?print-pdf parameter, the export waits for reveal's pdf-ready event (plus any Mermaid diagrams), and prints the page with the deck's own print stylesheet controlling the page size.
Configuration¶
PDF export is configured in the pdf { } block inside output { }:
fun pdfConfiguration() {
kslides {
output {
enableFileSystem = true
pdf {
outputDir = "build/pdf" // where the exported files land (default)
previewPng = true // also capture a first-slide PNG per deck
browserChannel = "chrome" // use installed Chrome; skips the Chromium download
exclude("scratch") // leave a deck out of "export everything"
}
}
presentation {
markdownSlide { content { "# My Deck" } }
}
}
}
All settings are optional. By default the page size comes from the presentation's own print CSS (reveal.js sizes pages to match the slide dimensions); set pageWidth / pageHeight (e.g. "11in", "297mm") to force a paper size instead.
Two timing knobs are available for decks that need them:
readyTimeoutMillis(default 30 s) caps how long the export waits for a deck to become printable — reveal.js initialized and every Mermaid diagram rendered. Raise it for very large decks.settleMillis(default 1 s) is an extra pause after those checks pass, giving asynchronous content such asplayground { }iframes time to finish. Set it to0to skip the pause on decks that have none.
Wiring it into a deck project¶
Add the dependency and a small entry point that reuses your deck definition:
fun KSlides.myDeck() {
presentation {
markdownSlide { content { "# My Deck" } }
}
}
fun exportAll() {
exportPdf { myDeck() } // every presentation -> one PDF each
}
fun exportOne() {
exportPdf("demo") { myDeck() } // just the presentation at /demo.html
}
exportPdf() accepts the same block as kslides { }, so the cleanest setup is to extract your deck definition into a function that both main() and the export entry point call — see Export.kt in kslides-examples, which also keeps the Playwright dependency in a separate source set so it stays out of the runnable fat JAR.
Browsers¶
On first use Playwright downloads its own browsers (cached per user, so this happens once). Two ways to avoid the download entirely:
- Set
browserChannel = "chrome"(or"msedge") to drive an installed browser. - Pre-install just Chromium in CI:
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install chromium"(or the Gradle equivalent).
Caveats¶
- Content fetched at render time still needs its backing service: Kroki
diagram { }slides need the configured Kroki server (the kslides example decks use the local docker-compose server frommake kroki-start), andplayground { }iframes need network access. Nativemermaid()diagrams render offline. - A deck that fails to render is reported (with the failing deck named) after the remaining decks have been attempted.