# Pamphlet
[](https://hex.pm/packages/pamphlet)
[](https://hexdocs.pm/pamphlet/)
Render djot documents with custom elements and url schemes.
Rendering links, images, raw HTML, and symbols often need knowledge the document does
not have: asset fingerprints, CDN hosts, valid page routes, async manifests,
or build-time reports.
Pamphlet exposes those decisions as [continuations](https://crowdhailer.me/2026-07-15/abstracting-effects-with-continuations/).
## Targets
Pamphlet supports rendering back to djot/markdown, useful for `llm.txt` and `.md` pages and lustre for web pages and web apps.
## Front matter
Defines pages with frontmatter deliminated by `---`.
Currently parses frontmatter to string key and value list.
## Rendering
All these examples use symbol but the renderer also provides hooks for urls and raw blocks.
Building on continuations we can make custom renderers with their own control logic.
### Pure renderer
This renderer always succeeds and transforms thumbs down to thumbs up.
```gleam
import pamphlet
import pamphlet/djot
pub fn cheerful_symbol_render(text: String) -> String {
let renderer =
djot.Renderer(..djot.default(), resolve_symbol: fn(name) {
fn(callback) {
case name {
"-1" -> ":+1:"
name -> ":" <> name <> ":"
}
|> callback
}
})
let #(_frontmatter, doc) = pamphlet.parse(text)
djot.to_markup(doc, renderer)(fn(x) { x })
}
pub fn cheerful_render_test() {
let out =
":-1: and :+1:"
|> cheerful_symbol_render()
assert ":+1: and :+1:" == out
}
```
### Aborting renderer
This renderer will halt if anyone uses the turd symbol.
```gleam
import pamphlet
import pamphlet/djot
pub fn check_turd_symbol_render(text: String) -> Result(String, Nil) {
let renderer =
djot.Renderer(..djot.default(), resolve_symbol: fn(name) {
fn(callback) {
case name {
"turd" -> Error(Nil)
name -> callback(":" <> name <> ":")
}
}
})
let #(_frontmatter, doc) = pamphlet.parse(text)
djot.to_markup(doc, renderer)(Ok)
}
pub fn check_render_test() {
let out =
":-1: and :+1:"
|> check_turd_symbol_render()
assert Ok(":-1: and :+1:") == out
let out =
":turd: and :+1:"
|> check_turd_symbol_render()
assert Error(Nil) == out
}
```
### Stateful renderer
This renderer collects the set of all symbols used.
```gleam
import gleam/set
import pamphlet
import pamphlet/djot
pub fn list_symbols_render(text) {
let renderer =
djot.Renderer(..djot.default(), resolve_symbol: fn(name) {
fn(callback) {
let #(page, acc) = callback(":" <> name <> ":")
#(page, set.insert(acc, name))
}
})
let #(_frontmatter, doc) = pamphlet.parse(text)
djot.to_markup(doc, renderer)(fn(page) { #(page, set.new()) })
}
pub fn list_symbols_render_test() {
let #(page, symbols) =
":-1: and :+1:"
|> list_symbols_render()
assert ":-1: and :+1:" == page
assert set.from_list(["-1", "+1"]) == symbols
}
```
## Development
```sh
gleam run # Run the project
gleam test # Run the tests
```