A Markdown Presentation about Lua Filters

For setup, phase guidance, and bundled filters, see the main Lua filters guide.

This page is itself a demo of two things at once: a custom slides.lua filter that turns a ::: slides div into a navigable deck, and a tour of what Pandoc Lua filters look like inside Markdown notes. Use the numbered nav above the deck (or the / keys, after clicking inside the deck) to step through.

Why filters?

Pandoc parses your Markdown into a typed AST — paragraphs, headings, links, code blocks. A Lua filter is a function that walks that tree and rewrites it before Emanote renders to HTML.

Anything you can say about a node in Lua, you can transform.

Adding one to your notebook

  1. Drop a .lua file anywhere in your notebook layer (convention: a filters/ folder).
  2. Reference it from the note’s frontmatter:
pandoc:
  filters:
    render:
      html:
        - filters/slides.lua
  1. Save. Emanote resolves the path against every -L’d Layer system.

What this page does

This page declares pandoc.filters.render.html: [filters/slides.lua]. Each ## heading inside a ::: slides div becomes one slide; the filter wraps them in <section> elements, prepends a nav strip, and emits CSS + a tiny arrow-key handler.

See the source: docs/filters/slides.lua.

Hot-reload

Edit filters/slides.lua — change a colour, tweak the layout, add a feature — and every note that references it refreshes on the next save. No touch of the .md required, no live-server restart.

The reverse index from filter path → dependent notes is maintained inside Emanote’s model; an edit invalidates exactly the affected notes, and the render-time filter runs again with FORMAT == "html".

A second example: word count

Pure-Lua filters compose cleanly. The main guide page chains list-table.lua with wordcount.lua:

pandoc:
  filters:
    parse:
      - lua-filters/list-table.lua
      - lua-filters/wordcount.lua

Both are bundled in Emanote’s default layer and run on every save; the order matches the array.

Writer-specific filters

Many Pandoc Lua filters branch on Pandoc’s FORMAT variable to emit HTML or LaTeX. Put Markdown-agnostic AST rewrites under pandoc.filters.parse, and put HTML-specific filters under pandoc.filters.render.html.

This deck uses the render-time slot because slides.lua emits raw HTML, CSS, and JavaScript.

Where to find more

The pattern is always the same: drop the .lua in, name it in frontmatter, save.

This deck is rendered by slides.lua. If you view source, you’ll see it is plain Markdown inside one fenced div — the filter does the HTML-specific structural work at render time.