Rendro ships canonical recipes on the three-rung escape-hatch pattern
(document/2 → page_template/1 → sections/2). This guide includes five rendered gallery entries, including a branded invoice variant, so you can see the launch fixtures while still using canonical recipe defaults in code.
The capabilities claimed in this guide are bounded by priv/support_matrix.json.
Supported capabilities are backed by on-disk proof in the corresponding evidence
test files. Claims that exceed the support matrix are not made here.
Rendered Gallery
These previews are rendered by Rendro from curated deterministic recipe fixtures and recorded in assets/rendro/artifacts.json.
Source PDFs and the self-rendered manual are byte-checked by the required docs contract. PNG rasters are regenerated and hash-checked in the pinned pdfium-render advisory lane. pdfium-render rasters are render proof, not GUI-viewer proof. Launch fixtures may use opt-in table polish; canonical recipe defaults remain unchanged.
Invoice

Standard invoice from Elixir data through the canonical Invoice recipe.
- Source PDF SHA-256:
8808fcf899c5ac5897e5fa1bf7316924edca275ce85f8ec3410f5576f3d5fc22 - PNG SHA-256:
6a7dfd0c963c2bfaddf2bf3e8dedc7f7deef3848a5d91478dae40cc310f49a47
Branded Invoice

Branded invoice with registered font and logo assets.
- Source PDF SHA-256:
c6ce32b449060f8cd7b01744697ad8fe90ee779cae6c039415935fc239be3a64 - PNG SHA-256:
2b075ca9a95b63726863a388057895e7edcadbd09bb68f62a1d4fd184b1de804
Statement

Account statement with opening/closing balances and per-page numbering.
- Source PDF SHA-256:
d3380c80468ce7a384ac2a54c2b2500a6b8f14b65c3751c12d6b7bf406e445d5 - PNG SHA-256:
b0475e73540b93bcae88f925228a0c7fe31b17d25e1ccd154b62e699308cb31b
Receipt / Report

Itemized sales receipt with subtotal, tax, and total through the Receipt recipe.
- Source PDF SHA-256:
67902b82dcf1bbd597490ce0d701a040a82604bd19dd1ce3ff53352b0a0b15ad - PNG SHA-256:
38225439998b6944e309238894df7cf10bc4eef771164fd3018ee7837b89b122
Certificate

Landscape certificate with a Path-backed, geometry-derived border frame.
- Source PDF SHA-256:
9f004ab50efe37c45308ee51ff4dc90ffe252dba765e6c92c4604a0b9a2c0231 - PNG SHA-256:
d6ad49a6829936a81d271df029dad36bf5d2ab62d7af6558e408eded2fad643e
Payslip

Payslip with earnings, deductions, year-to-date figures, and a reconciled net pay.
- Source PDF SHA-256:
fe6943472202526c46647eb65275a3385e570b6d0fd8aee05d3ade4b5620425a - PNG SHA-256:
bf764cd92cc9775fdd9f03901dba47de0c2108769dbaf4e02dcbc699586f4274
Ticket

Event ticket with a placement grid and a quotable, human-readable reference code.
- Source PDF SHA-256:
d6dc6fa81d1a4884d4a47b7966d261e4da2adb9152c0085fd9c69ebd75324e91 - PNG SHA-256:
b67e1668a9c1cc659a5232220fbf07236f1c516d9dd9ef16662957f07346e990
Invoice (Dark)

Invoice in dark mode via Theme.dark/1 - screen-oriented, not print-recommended.
- Source PDF SHA-256:
e4b00000d86a1407f888aa7e5b445b2b0d249056e1590f05d14aaca901137f23 - PNG SHA-256:
49f5d8fafc8a375706b6dfae0ec996337d8283cf791baac6ec42437b761eaa10
Certificate (Dark)

Certificate in dark mode via Theme.dark/1 - screen-oriented, not for print.
- Source PDF SHA-256:
3d29d79189480e5b5c29a3ae9d40de88374ef999b22a46402ae8696398ca4517 - PNG SHA-256:
11344160431217ad4279adfa90351efd0a654cdd2e82c32f937db0b604fca3d7
Ticket (Dark)

Ticket in dark mode via Theme.dark/1 - screen-oriented, not print-recommended.
- Source PDF SHA-256:
d885fd259e1e20a15cdc3365a94101f6cd693f8e86ca9671f57d380d4089c11c - PNG SHA-256:
6801b88f27d55418c04d4fb38741b7fc90f4314319ba7dee8cc4562b108fc23d
Invoice (Branded Accent)

Invoice themed via from_brand(accent: "#0E7C76") - accent-only, no assets.
- Source PDF SHA-256:
5dc1eecd7e94e3db0e674bf937dfe678d3c283043cb6a4f157cf192d6348eec4 - PNG SHA-256:
444a532a42110943ebb0f2dc94bac0442447fe9c9d9a12b368dc71de1cd90a5c
Self-Rendered Manual
Rendro also renders its own compact launch manual: manual.pdf.
SHA-256: 0597045e4410719efe6db27005245b2a35544282e765629d7b6f667c7c68020b
Realistic Example Library
Rendro ships a small library of realistic, fictional business-document fixtures
under priv/examples/, one directory per family. These are the same curated
fixtures the Rendered Gallery above renders, so what the gallery shows is what
these fixtures produce — rendered deterministically and byte-checked by the
required source-PDF SHA-256 docs contract.
| Family | Fixture | Domain notes |
|---|---|---|
| Invoice | priv/examples/invoice/acme-phoenix-saas/invoice.json | priv/examples/invoice/DOMAIN.md |
| Statement | priv/examples/statement/northwind-ledger-co/statement.json | priv/examples/statement/DOMAIN.md |
| Receipt | priv/examples/receipt/harbor-and-oak-cafe/receipt.json | priv/examples/receipt/DOMAIN.md |
| Certificate | priv/examples/certificate/summit-training-institute/certificate.json | priv/examples/certificate/DOMAIN.md |
| Payslip | priv/examples/payslip/aurora-live/payslip.json | priv/examples/payslip/DOMAIN.md |
| Ticket | priv/examples/ticket/aurora-live/ticket.json | priv/examples/ticket/DOMAIN.md |
Each fixture is plain JSON: money is carried as a decimal string (never a float)
and dates as ISO-8601 strings. Internally, Rendro loads these fixtures through the
Rendro.Examples helper and coerces them to the atom-keyed, Decimal-faithful,
Date-typed shape each recipe expects through Rendro.ExamplesData. Both are
@moduledoc false internal helpers for the shipped demonstration set — in your own
app you build the recipe data map directly (as shown in each recipe section below)
and call the recipe's document/2.
These fixtures demonstrate each family rendered deterministically; they are not a
claim of visual polish, and Rendro makes no accessibility-standard claim about the
rendered output. Each family's supported capabilities are bounded by
priv/support_matrix.json and backed by the recipe's evidence test.
Loading a shipped fixture through the internal helpers looks like this:
raw = Rendro.Examples.load!("invoice/acme-phoenix-saas/invoice.json")
data = Rendro.ExamplesData.transform_invoice(raw)
doc = Rendro.Recipes.Invoice.document(data)
{:ok, _pdf} = Rendro.render(doc, deterministic: true)Statement
A multi-page billing statement with running "Page X of Y" footers and automatic carried-forward / brought-forward running balances.
Support matrix row: statement (backed by test/rendro/recipes/statement_test.exs)
Supported capabilities:
| Capability | Status |
|---|---|
| Multi-page table continuation (carried-forward / brought-forward rows) | supported |
| Running footer "Page X of Y" on every page | supported |
| Deterministic output | supported |
Zero-to-one
# docs-contract: recipes-statement-document
data = %{
period: %{from: ~D[2026-05-01], to: ~D[2026-05-31]},
account: %{name: "Acme Corp"},
opening_balance: Decimal.new("1000.00"),
lines: [
%{date: ~D[2026-05-02], description: "Invoice #1", amount: Decimal.new("500.00")},
%{date: ~D[2026-05-15], description: "Payment", amount: Decimal.new("-200.00")}
]
}
doc = Rendro.Recipes.Statement.document(data)
assert doc.page_template == :statement
assert %Rendro.Document{} = doc
{:ok, pdf} = Rendro.render(doc, deterministic: true)
assert binary_part(pdf, 0, 5) == "%PDF-"Escape-hatch (page_template + sections)
# docs-contract: recipes-statement-escape-hatch
data = %{
period: %{from: ~D[2026-06-01], to: ~D[2026-06-30]},
account: %{name: "Beta LLC"},
opening_balance: Decimal.new("500.00"),
lines: [
%{date: ~D[2026-06-05], description: "Service fee", amount: Decimal.new("150.00")}
]
}
template = Rendro.Recipes.Statement.page_template()
sections = Rendro.Recipes.Statement.sections(data)
assert template.name == :statement
assert is_list(sections)
assert length(sections) > 0Data contract
Required keys:
:period—%{from: Date.t(), to: Date.t()}:account—%{name: String.t()}:opening_balance—Decimal.t()(Float raises an instructiveArgumentError):lines—[%{date: Date.t(), description: String.t(), amount: Decimal.t()}]
Optional keys:
:closing_balance—Decimal.t()(validated against the running fold):summary— caller-supplied summary map
Receipt / Report
A payment receipt that scales from one page to N pages. Multi-page is just a receipt whose line items overflow — column headers repeat on every page via per-page table blocks; "Page X of Y" appears in the running footer.
Support matrix row: receipt_report (backed by test/rendro/recipes/receipt_test.exs)
Supported capabilities:
| Capability | Status |
|---|---|
| Multi-page table continuation with repeating column headers | supported |
| Running footer "Page X of Y" on every page | supported |
| Deterministic output | supported |
Zero-to-one
# docs-contract: recipes-receipt-document
data = %{
title: "Payment Receipt",
date: ~D[2026-05-29],
customer: %{name: "Acme Corp"},
lines: [
%{description: "Widget A", amount: Decimal.new("29.99")},
%{description: "Widget B", amount: Decimal.new("49.99")}
],
totals: %{subtotal: Decimal.new("79.98"), total: Decimal.new("79.98")}
}
doc = Rendro.Recipes.Receipt.document(data)
assert doc.page_template == :receipt
assert %Rendro.Document{} = doc
{:ok, pdf} = Rendro.render(doc, deterministic: true)
assert binary_part(pdf, 0, 5) == "%PDF-"Escape-hatch (page_template + sections)
# docs-contract: recipes-receipt-escape-hatch
data = %{
title: "Service Invoice",
date: ~D[2026-06-01],
customer: %{name: "Beta LLC"},
lines: [
%{description: "Consulting", amount: Decimal.new("1200.00")}
]
}
template = Rendro.Recipes.Receipt.page_template()
sections = Rendro.Recipes.Receipt.sections(data)
assert template.name == :receipt
assert is_list(sections)
assert length(sections) > 0Data contract
Required keys:
:title—String.t():date—Date.t():customer—%{name: String.t()}:lines—[%{description: String.t(), amount: Decimal.t()}]
Optional keys:
:totals—%{subtotal: Decimal.t(), total: Decimal.t()}(validated when present)
Certificate
A geometry-derived completion, compliance, or award certificate. All region
coordinates are computed from template geometry — zero hardcoded A4 numerics.
The default orientation is landscape A4 (classic diploma look). Portrait is
reachable via orientation: :portrait. Branding is optional.
Support matrix row: certificate (backed by test/rendro/recipes/certificate_test.exs)
Supported capabilities:
| Capability | Status |
|---|---|
| Geometry-derived layout (all coordinates from page dimensions) | supported |
| Multiple page sizes (A4 and US Letter via geometry) | supported |
| Branded output (optional font + logo registration) | supported |
| Deterministic output | supported |
Zero-to-one
# docs-contract: recipes-certificate-document
data = %{
title: "Certificate of Completion",
recipient: "Jane Smith",
date: ~D[2026-05-29],
body: "For outstanding contribution to deterministic PDF generation.",
seal_line: "Authorized Signature"
}
doc = Rendro.Recipes.Certificate.document(data)
assert doc.page_template == :certificate
assert %Rendro.Document{} = doc
{:ok, pdf} = Rendro.render(doc, deterministic: true)
assert binary_part(pdf, 0, 5) == "%PDF-"Escape-hatch (page_template + sections)
# docs-contract: recipes-certificate-escape-hatch
data = %{
title: "Award of Excellence",
recipient: "Alex Chen",
date: ~D[2026-06-15]
}
template = Rendro.Recipes.Certificate.page_template()
sections = Rendro.Recipes.Certificate.sections(data)
# Certificate uses geometry-derived layout with a single body region
assert template.name == :certificate
assert template.width > template.height
assert is_list(sections)
assert length(sections) > 0Data contract
Required keys:
:title—String.t():recipient—String.t():date—Date.t()
Optional keys:
:body—String.t()(body statement, default"", must be ≤ 2000 bytes):seal_line—String.t()(signature / seal line, default""):brand—%{font_name: atom(), logo_name: atom()}(branded output)
Payslip
A payslip with an earnings/deductions ledger and a reconciled net pay figure
rendered as the page's visual anchor. Money is Decimal-faithful, and the net pay
is validated to reconcile against earnings minus deductions. The realistic fixture
lives at priv/examples/payslip/aurora-live/payslip.json.
Support matrix row: payslip (backed by test/rendro/recipes/payslip_test.exs)
Supported capabilities:
| Capability | Status |
|---|---|
| Net pay visual anchor | supported |
| Multi-page ledger continuation | supported |
| Jurisdiction carried as data (no hardcoded tax logic) | supported |
| Deterministic output | supported |
Zero-to-one
data = %{
employer: %{name: "Aurora Live", address: "500 Harbor Blvd, Portland, OR"},
employee: %{name: "Jordan Reyes", id: "E-1042", tax_code: "1257L"},
period: %{from: ~D[2026-06-01], to: ~D[2026-06-30]},
pay_date: ~D[2026-07-05],
earnings: [
%{description: "Base salary", amount: Decimal.new("4200.00"), ytd: Decimal.new("25200.00")}
],
deductions: [
%{description: "Income tax", amount: Decimal.new("907.50"), ytd: Decimal.new("5445.00")}
],
net_pay: Decimal.new("3292.50")
}
doc = Rendro.Recipes.Payslip.document(data)
{:ok, _pdf} = Rendro.render(doc, deterministic: true)Data contract
Required keys:
:employer—%{name: String.t(), address: String.t()}:employee—%{name: String.t(), id: String.t(), tax_code: String.t()}:period—%{from: Date.t(), to: Date.t()}:pay_date—Date.t():earnings/:deductions—[%{description: String.t(), amount: Decimal.t(), ytd: Decimal.t()}]:net_pay—Decimal.t()(validated to reconcile: earnings − deductions)
Optional keys:
:payment_method— masked account string (e.g.···· 4321)
Ticket
An event ticket with a placement grid (section / row / seat / gate) and a quotable,
human-readable reference code. Rendro renders the caller-supplied reference text
as-is and never synthesizes a faux barcode; supply your own code image if you need
a scannable one. The realistic fixture lives at
priv/examples/ticket/aurora-live/ticket.json.
Support matrix row: ticket (backed by test/rendro/recipes/ticket_test.exs)
Supported capabilities:
| Capability | Status |
|---|---|
| Geometry-derived layout | supported |
| Caller-supplied code image | supported |
| No faux barcode (human-readable reference unless you supply an image) | supported |
| Deterministic output | supported |
Zero-to-one
data = %{
issuer: %{name: "Aurora Live"},
title: "Midsummer Night Concert",
placement: [
%{label: "Section", value: "GA"},
%{label: "Row", value: "H"},
%{label: "Seat", value: "24"},
%{label: "Gate", value: "B"}
],
code: %{reference: "AUR-88213-GA"}
}
doc = Rendro.Recipes.Ticket.document(data)
{:ok, _pdf} = Rendro.render(doc, deterministic: true)Data contract
Required keys:
:issuer—%{name: String.t()}:title—String.t():placement—[%{label: String.t(), value: String.t()}]:code—%{reference: String.t()}(optional:imageregisters a caller-supplied code asset as:ticket_code)
Optional keys:
:subtitle—String.t()(≤ 200 bytes):terms—String.t()(≤ 600 bytes)
Invoice and Branded Invoice
Invoice and BrandedInvoice are the foundational Rendro recipes covering standard invoice and branded invoice generation with a registered font and logo asset.
For full documentation on Invoice and BrandedInvoice — including font/asset
registration, the three-rung composition pattern, failure diagnostics, and
verified runnable examples — see guides/branding.md.
The support matrix has no separate invoice or branded_invoice rows because
the branding surface is already covered by the guide and recipe moduledocs.
Scope boundaries
None of the recipes in this guide claim:
- Signing or signing preparation — see
Rendro.Signfor the supported signing path - Blanket compliance or viewer-promotion narratives — see
priv/support_matrix.jsonfor the exact supported surface - Viewer-specific rendering guarantees — see
guides/viewer_evidence.mdfor recorded per-viewer behavior