Skip to content

Export

Inkflow can export your deck to a self-contained HTML file or a PDF. Both commands work from the same deck.py you use for live presenting.

Static HTML (inkflow build)

inkflow build produces a self-contained directory with an index.html that embeds all slides inline. No server required. Open it in any browser, put it on a USB drive, host it on any static file server.

inkflow build
# → build/index.html

Output to a custom location:

inkflow build --output ./dist

The build output is the same presenter you see during inkflow serve, packaged for offline use. All local assets referenced by the deck are copied into the output directory: Media zones plus images referenced from Markdown (![](...)) or SVG (<image href>). Remote (https://) and data: URIs are left untouched. Fonts are embedded directly into the HTML, so they need no separate files. To embed the assets too and get a single file, see --inline-assets.

Every reference is resolved relative to the file it was written in (see Images), and the source tree is mirrored inside the output directory, so the build stays self-contained wherever it is copied. A theme's own assets are copied under _theme/. A reference that resolves to no file is reported as a warning and skipped rather than dropped silently, and one that points outside both the project and the theme is reported when it is resolved.

One file instead of a directory (--inline-assets)

inkflow build --inline-assets embeds every referenced image and video in the HTML as a data: URI, so the whole deck is a single index.html with nothing beside it:

inkflow build --inline-assets
# → build/index.html (4.1 MB)

The trade-offs, in exchange:

  • Size. The file grows by roughly a third of each asset (base64 overhead), counted once per reference rather than once per file, so an asset that appears on ten slides is carried ten times.
  • Startup. Every asset is part of the HTML, so all of it loads before the first slide renders, rather than arriving per slide as the deck is presented. Inkflow warns when it inlines a large video, with its size, because a video that big is what blanks the screen while index.html loads.
  • Caching. A hosted deck re-downloads every asset on every load, since none of them are separate cacheable files.

Assets are inlined into the slides only; index.html itself is untouched, and fonts are embedded either way. An asset whose file extension names no known media type is copied out beside index.html as usual and reported.

Live demo in these docs

The interactive demo linked from this site was produced with inkflow build and served as a static build. See the Demo page.

PDF export (inkflow export)

inkflow export renders each slide to a PDF page via headless Chromium. One page per slide, no animations. A static snapshot suitable for sharing with conference organisers or archiving.

inkflow export
# → deck.pdf

Output to a custom path:

inkflow export --output my-talk.pdf

Chromium path

Inkflow auto-detects chromium, chromium-browser, and google-chrome on PATH. If your binary is elsewhere:

inkflow export --chromium /usr/bin/chromium-browser

Slide dimensions

The PDF page size is auto-detected from the first slide's viewBox. No configuration needed for standard decks.

To override — for example when mixing slide sizes or forcing a specific output resolution:

inkflow export --size 1280x720

Running as root or in Docker

Pass --no-sandbox when Chromium refuses to start due to sandbox restrictions:

inkflow export --no-sandbox

Requirements

PDF export requires a Chromium-based browser. It is not available in sandboxed environments that block subprocess execution.

Using the HTML export as a demo

The inkflow build output is a fully interactive presenter. Navigation, animations, and transitions all work. This makes it ideal for embedding in documentation.

To embed in an MkDocs page, place the built output in docs/demo/ and add an iframe:

<iframe
  src="../demo/index.html"
  width="100%"
  style="aspect-ratio: 16/9; border: none; border-radius: 8px;"
  allowfullscreen>
</iframe>

Build the deck into place before building the site, so the embedded demo is always current:

inkflow build --deck deck.py --output docs/demo
mkdocs build

Wire that pair into whichever task runner your project already uses. These docs do it with mise:

[tasks.docs-build]
run = [
  "uv run inkflow build --deck demo/deck.py --output docs/demo",
  "uv run mkdocs build",
]