Every hero starts with a problem nobody else will fix.
The scars every figure carried, workflow after workflow.
Before the powers, the ordinary day job.
With Typst Render I can render any Typst content straight into Quarto.
But, why do I still need to use R or Python to draw a plot?
What if one engine compiled the figure and the prose?
A grammar of graphics… inside a database?
Why not inside a document compiler.
Last year, ggsql brought the grammar into SQL.
Gribouille was born of necessity, not ambition.
Wilkinson’s grammar, native to Typst.
One line to import. No R session, no Python environment.
It is a Typst Universe package.
Typst has no lazy evaluation, so defer() captures the plot spec without rendering it yet.
Pure Typst content — no new API needed.
Same grammar, different runtime.
Faithful to ggplot2
aes() mapping.geom* / stat*.scale*, facet*, coord*.guides(), theme*.Departs by necessity
geom-point, stat-identity.+ operator: one plot() call with named args (layers, scales, facet).fill, outline is colour.labels() not labs(); avoid abbreviations.The vocabulary is stable. The question was never “what should the API look like?” It was “how do I wire it to Typst?”
The departures are not arbitrary. They reflect how Typst works.
plot(), aes(), geom-*, scale-* — builds a spec dict.render.typ walks a fixed pipeline:Each stage receives dicts, transforms them, passes dicts forward. The final stage emits a CeTZ canvas.
The figure stops being a tourist.
The integration an SVG import can never close
Figure and prose are compiled by the same engine, in one pass. Switch the document theme and the figures follow. Annotate, caption, and cross-reference the plot like any other element.
Same Engine!
Porting a grammar with agentic tools.
Manual first. AI later, once it was safe to.
Plan, then hand-build
cetz as the drawing layer.Then accelerate
1. Hand-build
Core grammar coded, edited, and reviewed manually. No AI on an unstable foundation.
2. Harden
Tests, snapshots, documentation: the guardrails that make change safe.
3. Accelerate
Only then bring in LLMs, to speed up well-bounded work.
What carried, what didn’t
Stable vocabulary ported cleanly, a good LLM target.
AI stumbled on Typst’s no-lazy-eval model, cetz primitives, and scale/stat edge cases.
Human review caught it.
Not there (yet)
Feedback is welcome:
m.canouil.dev/tidytuesdayGribouille is an unfunded spare-time project, and parts of the API are still settling.
Pull requests are not being accepted for now.
Gribouille is a scribble today.
The grammar is stable enough to build on.
@preview/gribouille:0.4.1m.canouil.dev/gribouillegithub.com/mcanouil/gribouillehttps://m.canouil.dev/2026-ggplot2-extenders-gribouille/m.canouil.dev/tidytuesdayThank you.