Changelog

Version history.

0

0.7

Read the Gribouille 0.7 announcement

0.7.0 (2026-08-24)

Breaking changes
  • feat!: geom-text, geom-label, and geom-typst take an arrow() specification on arrow in place of a boolean, and their arrow-length parameter is gone. arrow: true becomes arrow: arrow(), and arrow-length: 6pt becomes arrow: arrow(length: 6pt). (#249GitHub)
  • feat!: guide-axis(angle:), guide-axis-logticks(angle:), and the angle of an axis-text theme element are bounded to -90 to 90 degrees and fail outside it. Past a quarter turn the tick labels read upside down and ran off the canvas. (#238GitHub)
  • fix!: guide-axis-theta(angle:) is bounded to -90 to 90 degrees and fails outside it, as every other tick-label rotation already is. Past a quarter turn the labels read upside down. (#286GitHub)
  • fix!: the theta axis of a coord-radial() plot reads its tick marks and its arc off the scale that carries the sweep, y on a pie in place of x. The minor ticks of guide-axis-theta(minor-ticks: true) move from the axis-line surface to axis-ticks-minor, so a theme that styled the angular axis through axis-line alone must now set axis-ticks too. (#270GitHub)
  • fix!: a faceted plot whose strip label holds a word wider than its panel now fails with the room that word needs. Shorten the level names with a labeller, break the word with \, or give the plot more room with width/height. (#262GitHub)
  • fix!: a plot whose tick labels cannot fit the canvas fails with the room they need instead of drawing past its edge. Give the plot more room, rotate the labels with guides(x: guide-axis(angle: 45)), shorten them with a labels: function on the scale, or shrink them with theme(axis-text: element-text(size: ...)). (#259GitHub)
  • fix!: a legend placed on a plot side, or one compose() hoists out of its panels, fits the width/height it was asked for, and fails with the room it needs when it cannot. Give the plot more room, move the legend to a shorter side, or shrink it with guide-legend(nrow:/ncolumn:). (#255GitHub)
Changes
  • feat: breaks-log(n:, base:) places the breaks of a log scale on powers of the base. When too few powers fall inside the data range, sub-decade steps fill in, the way scales::breaks_log() fills them in. The base is independent of the scale transform, so base: 2 places powers of two. (#272GitHub)
  • feat: format-log(base:, digits:) writes a tick label as a power with a real superscript, for example 10^3. A break that is not an exact power keeps a mantissa, because an automatic log axis breaks on one, two, and five times a power. (#272GitHub)
  • feat: guide-axis-logticks() draws two tick tiers below the labelled decades. The tick at five times a power moves to the new axis-ticks-mid theme surface and is longer than the other sub-decade ticks. Set axis-ticks-mid: (length: 50%) for the previous look. (#272GitHub)
  • feat: a coord-radial() plot draws major tick marks on its angular axis, from the axis-ticks theme surface, as a cartesian axis does. The circle gives up the radius they need, so the figure still fits the width/height it was asked for. (#270GitHub)
  • feat: a plot draws at any size that leaves it room to draw, so a figure can be small enough to sit in a table cell or a line of prose. Only an empty or inverted canvas fails now. (#252GitHub)
  • feat: theme-brand() builds a theme from a parsed _brand.yml, so a document’s plots follow the same brand as its prose. brand.yml is a tool-independent standard, read by Quarto and by Shiny for R and Python, not a Quarto feature. It takes the dictionary yaml() produces rather than a path, maps foreground, background, and primary onto ink, paper, and accent, and turns the remaining data-ink roles into a discrete palette, with mode: "light" or mode: "dark" choosing the variant. (#250GitHub)
  • feat: a theme carries a palette of colours that discrete colour and fill scales fall back to, so a whole document can be recoloured without repeating scale-colour-manual() on every plot. A scale’s own palette: still wins, continuous scales keep viridis, and auto uses the Okabe-Ito palette as before. (#250GitHub)
  • feat: the line geoms draw arrowheads. geom-segment, geom-curve, geom-spoke, geom-path, geom-line, and geom-step take an arrow specification built with the new arrow() helper, which sets the head length, its half-opening angle, which end carries it, and whether it is an open V or a filled triangle. (#249GitHub)
  • fix: the band a horizontal colour bar reserves below its strip is the lead the renderer draws plus the row its labels are measured to occupy. It was one fixed 0.45 cm covering both, which is about 0.03 cm more than the default theme draws. (#301GitHub)
  • fix: a vertical colour bar reserves the room its turned break labels need. A theme(legend-text: element-text(angle: ...)) turned each label into a box the flank never measured, so the labels drew past the width the legend was given. (#300GitHub)
  • fix: a discrete scale censors a level whose name looks like a number. A scale limited to ("10", "20") with oob: "drop" used to keep a "90" row and place it at position 90, far outside the panel. (#297GitHub)
  • fix: a vertical colour bar reserves the gap it draws between its strip and its tick labels. It reserved 0.3 cm and drew 0.18 cm, so a plot whose bar labels set the legend width gains up to 0.12 cm of panel back. (#296GitHub)
  • fix: a discrete scale with no levels draws no legend. It used to reserve a box beside the panel that held its title and no keys, which took width from the plot. A scale has no levels when limits: () pins it empty, or when the column it reads holds nothing but empty values. (#292GitHub)
  • fix: a discrete scale says what is wrong with numeric limits, such as scale-discrete(limits: (1, 2, 3)). It used to fail with a raw Typst error saying a string was expected. A discrete scale reads a bare number as a position rather than as a level, so the levels must be quoted. (#291GitHub)
  • fix: a radial panel gives up radius only for the tick marks it draws. An angular axis with no breaks used to shrink the circle by the themed tick length all the same. (#286GitHub)
  • fix: each label row of a guide-axis-stack() clears the row above it. A row started a fixed step out, which crowded a row under turned labels and left a gap under short ones. (#285GitHub)
  • fix: an axis reserves the tick weights it draws. A theme that lengthens axis-ticks-mid no longer takes that room on an axis with no sub-decade ticks, which gives the panel the difference back. (#285GitHub)
  • fix: a legend that does not fit names what the guide at fault can change. A colour bar and a guide-custom() block were told to use guide-legend(nrow:/ncolumn:), which neither one takes. (#285GitHub)
  • fix: a guide-custom() block sits on the side a guides(default: ...) entry or a theme(legend-position:) sets, as every other guide does. It stayed on the right whatever those asked for, and position: auto failed with a raw error instead of inheriting a side. A theme or a default: entry that hides its legends now hides a custom block with them; give the block its own position to keep it. (#278GitHub)
  • fix: an order set on a guides(default: ...) entry reaches the guides that inherit from it. A placement built from a side alone carries no order, and spreading it over the entry dropped the one the entry set. (#278GitHub)
  • fix: a log axis draws one minor gridline between adjacent decades. It drew a line at every sub-decade position, which banded the panel grey. n-minor sets that count on a log axis, as it does on every other continuous axis, and n-minor: 0 removes the lines. The sub-decade positions stay on the tick marks of guide-axis-logticks(). (#272GitHub)
  • fix: an axis reserves the depth of its longest tick tier. A theme that made a sub-decade tick longer than the major tick used to draw it past the axis band. (#272GitHub)
  • fix: the log tick tiers of guide-axis-logticks() read the visible domain. A log scale that carries no view expansion used to place its sub-decade ticks against the transformed domain, which put them outside the panel. (#272GitHub)
  • fix: every panel of a faceted coord-radial() plot keeps its own angular and radial tick labels. A radial panel rings them inside its own circle rather than on an edge it shares with a neighbour, so an interior panel used to be left with no scale to read against, and a coord-radial(theta: "y") pie lost the wrong set. (#271GitHub)
  • fix: a discrete axis draws the gridlines a theme asks for. It still draws none from panel-grid alone, because its ticks already mark every level, and now draws them when the theme sets panel-grid-major, panel-grid-major-x, or panel-grid-major-y. The grid circles of a coord-radial() plot follow the same rule, but read panel-grid-major only, since a radial panel draws one grid weight for both its circles and its spokes. (#268GitHub)
  • fix: a geom hides the seam between its marks only where they touch, so the whitespace it was asked for survives. A geom-tile grid below its full slot, a bar that neither stacks nor fills, and an unstacked geom-ribbon now paint at exactly the size they were given, where each used to spread half the seam width past it. A waffle chart gains back most of its grid gap. Stacked bars and areas, tiles at their full slot, hexes, and iso-band cells keep their seams sealed. (#266GitHub)
  • fix: dodged marks keep a gap between them, so a bar no longer paints over the one to its left. position-dodge(padding:) sets that gap and now applies when every mark shares a width, where it was accepted and then ignored. Bars, boxes, violins, crossbars, and error bars all narrow by the padding, and their centres do not move. (#265GitHub)
  • fix: compose() builds the legend it hoists out of its panels under the composition theme. Its key size, its side, and its text all follow the composition, and a panel theme now styles that panel alone. (#260GitHub, #261GitHub)
  • fix: a plot fits the width/height it was asked for when its outermost tick label reaches past the panel edge. The panel shrinks by the reach, most visibly under expand: false, where a break sits flush on the panel edge. (#258GitHub)
  • fix: a faceted plot fits the width/height it was asked for. Strip bands are budgeted against the panel grid, a label too wide for the panel it names wraps into it, and labels that cannot fit at all fail with the room they need. (#256GitHub)
  • fix: a stripped axis reserves no room outside the panel, so a theme-void() figure gives its panel the whole canvas. A coord-radial() panel still reserves the gap, since its theta labels ring the inside of the panel edge. (#252GitHub)
  • fix: a coord-radial() plot reserves the room its theta tick labels need per angle instead of insetting all four sides of the circle by the widest one, so radial plots draw larger in the same canvas. (#248GitHub)
  • fix: a legend reserves the box its title and entry labels are drawn in, measured on their resolved surfaces rather than estimated from a character count. Measured labels are tighter than the old estimate, so legends give a little width back to the panel. (#247GitHub)
  • fix: a legend reserves the width its title needs, measured at the legend-title size rather than the legend-text size the entry labels use. A guide-custom block now reserves room for its own title too. (#245GitHub)
  • fix: a legend reserves the title band it draws, resolved from the legend-title surface instead of estimated from legend-text, so a scaled legend-title no longer crops the last key and a legend-title margin override is honoured. (#244GitHub)
  • fix: a legend placed on a plot side fits the width/height it was asked for. The painted backdrop, rather than the guide stack, sits a legend-gap off the panel, and a left or bottom legend honours its outset as canvas-edge whitespace. (#243GitHub)
  • fix: the shared legend compose() hoists out of its panels shows its legend-background whole, border, stroke, and outset included, instead of having them clipped away. (#242GitHub)
  • fix: a coord-radial() plot whose sweep wraps fits the width/height it was asked for, reserving the width of the merged first-and-last label such as Hour-24/Hour-0. A labels callback returning none for a break no longer reserves a band for a label it hides. (#241GitHub)
  • fix: a faceted plot places its shared axis titles at the band the chrome reserved, so a title cannot land outside its own margin and stretch the figure past the requested width/height. (#241GitHub)
  • fix: a faceted plot draws its secondary axis ticks and labels where they can be read, reserving the axis depth between the panel and its strip band. This covers the secondary x under facet-grid and facet-wrap, and the secondary y against a facet-grid row strip. (#239GitHub)
  • fix: a coord-radial() plot fits the width/height it was asked for, the circle shrinking by the band its theta tick labels need. guides(theta: none) and a blank axis-text give that room back. (#237GitHub)
  • fix: a coord-radial() plot whose scale carries a secondary: spec keeps the panel area the secondary axis used to be given. A radial panel draws no secondary axis, so nothing is reserved for one. (#236GitHub)
  • fix: a faceted plot names its secondary axes once for the whole panel grid, the way it already does for the primary axes, and wraps those titles to the room the plot leaves them. (#235GitHub)
  • fix: the axis titles a faceted plot draws once for the whole grid follow the themed axis-title align, pinning to the ends of the panel grid rather than staying centred over it. (#235GitHub)
  • fix: an axis title longer than the panel it labels wraps onto further lines instead of stretching the canvas past the requested width/height. A title that still cannot fit fails with the room it needs. (#234GitHub)
  • fix: an inside-panel legend background keeps its painted inset inside the panel at an edge-flush alignment, and legend-background’s outset now spaces the backdrop off the panel edge instead of being silently ignored. (#232GitHub)
  • perf: a faceted plot resolves each limited scale once for the whole render. A plot with twenty panels used to resolve it twenty-one times, because the out-of-range pre-pass rebuilt its plans on every panel. (#298GitHub)
  • perf: a binned plot no longer collects the values of each group for a bin grid the panel has already computed. (#291GitHub)
  • perf: a plot whose discrete scale carries user limits drops its out-of-range rows in time that no longer grows with the number of levels. At two thousand levels the pre-pass is about three times faster. (#291GitHub)
  • perf: a plot that groups its rows builds those groups in linear time, where the cost used to grow with the square of the row count. A boxplot of thirty thousand rows draws about seven times faster. (#289GitHub)
  • perf: a plot with many rows draws in near-linear time, where the cost used to grow with the square of the row count. At ten thousand points the draw is about three times faster, and at thirty thousand about seven. (#288GitHub)
  • perf: a plot lays its chrome out faster. Each axis title, tick label, and legend title is measured once per pass, and a compose() panel is probed for its guides and its shared margin without drawing a canvas that is then thrown away. (#260GitHub)
  • docs: the benchmarks page plots against the row count, and attributes compile cost to the number of marks a chart draws, which is what the refreshed measurements show. It states that a line or a polygon carrying one hundred thousand points compiles inside the budget, where the same number of separate markers does not, and both figures and their alt text describe the eight cases now measured. The guide-custom() row of the feature matrix no longer claims right-side placement only, which #278GitHub made false. (#295GitHub)
  • docs: the benchmarks page reports the library as it stands. Its dataset was measured before the two quadratic defects closed, so every figure on it described those defects. The sweep also gains a polygon case, which carries many vertices on few marks, the shape a boundary layer has and the one no case covered. (#294GitHub)
  • docs: the gallery hub cards show a focus ring for keyboard users, and their text can be selected under the whole-card link. The hub also states that the per-example anchors of the old /examples/ page are gone, and sends readers to the intent pages instead. (#269GitHub)
  • docs: the Typst-markup examples on typst() and element-typst() write a mean as $macron(x)$. They used $bar(x)$, the vertical-bar symbol rather than the overbar their alt text described. (#253GitHub)
  • docs: a reference page no longer opens with the release that introduced the function. The version was typed by hand and drifted, and the changelog already records when a function landed. (#251GitHub)
  • docs: docs site footer links read as ink rather than the muted grey Quarto paints them, and pick up the site-wide hover colour. (#246GitHub)
  • docs: sec-axis and dup-axis say that a secondary axis degrades to a no-op under coord-radial, and the feature matrix lists it alongside geom-rug among the combinations that do not translate to polar. (#236GitHub)
  • docs: the examples are organised by what a reader wants to show rather than by which part of the API they exercise, replacing the single feature-ordered page. A card hub routes to six story pages and six feature pages, each card carries a data-shape badge, and eighteen new plots on the bundled datasets demonstrate the practice. (#201GitHub)
  • docs: tighten prose and apply consistent British spelling across the README, contributor docs, docs site guides, and the AI-assistant skill. (ba66650GitHub)
  • build: the package compiles against Typst 0.15.0. Use Typst 0.15.0 or newer. (#282GitHub)

0.6

Read the Gribouille 0.6 announcement

0.6.0 (2026-07-28)

Breaking changes
  • feat!: axis ticks are themed through the single axis-ticks family, where the new element-tick(colour:, stroke:, length:) carries the mark length. tick-length and its per-axis and per-side variants are removed, tick-labels gives way to hiding labels per side with axis-text: element-blank(), and axis-ticks: element-blank() is the one switch that turns marks off, reserving no depth either. (#150GitHub)
  • feat!: the summary-dispatch kernel summarise(name, values) leaves the public API as the internal _apply-summary, freeing the summarise name for the new wrangle verb. The fun: argument of stat-summary and stat-summary-bin, a name string or callable, is unchanged. (#198GitHub)
Changes
  • feat: automatic continuous breaks come from the extended Wilkinson search (Talbot, Lin, and Hanrahan 2010), which scores candidate tick sequences on simplicity, coverage of the data, and tick count, replacing the fixed 1/2/5 ladder on axes and continuous guides. Most plots gain rounder ticks that sit closer to the data, and breaks-extended(n:) exposes the search for a different target count. (#217GitHub)
  • feat: breaks: and minor-breaks: on a continuous scale accept a closure called with the vector of values the scale trained on, once per panel, so free-scale facets each get their own. Unlike an explicit array, closure breaks are clipped to the trained domain rather than widening it. (#216GitHub)
  • feat: breaks-width(width, offset:), breaks-pretty(n:), and breaks-quantile(probs:) build that closure for the common placements: a fixed step, round positions at a target count, and sample quantiles of the data. (#216GitHub)
  • feat: summarise(data, ..aggregations, by:) and count(data, ..cols, sort:) bring grouped aggregation to the row-store data model: one output row per group, named rows => value aggregation closures, and first-appearance group order. Both accept column-store input and feed #plot directly. (#198GitHub)
  • feat: as-numeric(data, col, na:) takes a list of sentinel values, or a bare value. Cells equal to a sentinel, string cells compared trimmed, become none before parsing, so missing-value placeholders such as "NA" or "-99" do not survive as spurious numbers. (#198GitHub)
  • feat: column and row selection verbs select(data, ..names), rename(data, ..renames), relocate(data, ..cols, before:, after:), drop-na(data, ..cols), distinct(data, ..cols), and slice-max/slice-min(data, col, n: 1, by:) reshape, dedup, and rank a row-store, sorting non-numeric or missing values last. They accept column-store input and feed #plot directly. (#198GitHub)
  • feat: reshaping verbs pivot-longer(data, cols, names-to:, values-to:) and pivot-wider(data, names-from:, values-from:) melt columns into a name/value pair and spread them back, round-tripping modulo column order. Absent combinations are filled with none, an ambiguous duplicate spread fails, and the as-factor tag is carried on surviving identifier columns. (#198GitHub)
  • feat: join verbs left-join/inner-join/full-join/semi-join/anti-join(x, y, by:) combine two row-stores on shared key columns, taking a natural join on the common columns when by: none and failing on a non-key column present in both. bind-rows(..datasets) and bind-cols(..datasets) stack or glue datasets, unioning columns with none-fill or zipping them by row position. (#198GitHub)
  • feat: the bundled mpg dataset carries a drv column ("4", "f", "r"), so drive train can be faceted, coloured, or grouped on without substituting cyl. (#226GitHub)
  • feat: minor tick marks are themable through axis-ticks-minor and its per-axis variants, replacing the hardcoded half-length, major-stroke sub-decade ticks drawn by guide-axis-logticks(). They inherit the major tick record, so the default rendering is unchanged. (#150GitHub)
  • fix: a numeric nudge-x/nudge-y on geom-text, geom-label, and geom-typst no longer fails the compile when a positional scale is discrete. The offset shifts in level units there, matching position-nudge, and a nudge on the continuous axis of such a plot now applies instead of erroring. (#225GitHub)
  • fix: dup-axis(breaks:, labels:) and sec-axis(breaks:, labels:) are honoured. The secondary axis drew the primary grid with the primary formatting whatever these were set to. (#216GitHub)
  • fix: a continuous scale trained on whole numbers only (years, counts, epoch days) keeps whole automatic breaks on axes and on continuous legends, so a narrow range such as 2020 to 2023 no longer labels half-steps. (#213GitHub)
  • fix: legend entry labels, vertical colourbar tick labels, and y-axis tick labels centre on the cap-height/baseline band instead of the glyph bounds, so a label carrying a descender (Chinstrap) no longer sits higher than one without (Adelie). (#208GitHub, #209GitHub)
  • docs: footer links are legible in light mode, where they were painted the page colour, and the footer top rule reads in dark mode instead of being 8% black on dark paper. The copy-to-clipboard button no longer hangs past the bottom border of a one-line code block. (#222GitHub)
  • docs: the theming guide gains a “Ticks and their labels” section showing element-tick, ratio lengths, minor marks, and per-side label hiding. (#219GitHub)
  • docs: reference pages link every cross-reference instead of printing a bare @geom-line when the reference closes a parenthetical, and links no longer run into the preceding word or comma. (#215GitHub)
  • docs: every scale-* reference page lists the keys its ..args accepts with their type, accepted values, and default, including the previously undocumented oob, instead of naming a few of them in prose. (#214GitHub)
  • docs: in the collapsed navbar, the colour-scheme toggle and the search button group at the right edge, separated by the same gap as the rest of the navbar-right controls, and the brand centres. The toggle used to sit beside the brand with the search alone at the far right. (#210GitHub)
  • docs: the navbar GitHub icon becomes a widget showing live star and fork counts and a project menu (repository, issues, pull requests, releases, star, fork, Typst Universe, sponsor), replacing the separate Typst Universe, source-code, releases, and sponsor links. The version switcher, GitHub widget, search button, and colour-scheme toggle share one pill button style. (#205GitHub)
  • docs: add a “Wrangling data” guide walking a dataset from coercion through grouped aggregation, reshaping, and joining into #plot, with guidance on when native Typst suffices. (#198GitHub)
  • docs: the News page and the changelog link the Gribouille 0.6 release announcement. (#227GitHub)
  • docs: the stable site is rendered wholly from the release tag instead of taking its pages from main against a pinned src, so each site documents the API it ships with. A documentation fix now reaches the stable site at the next release rather than immediately. (336b698GitHub)
  • docs: the navbar is dark in both light and dark schemes, matching the other project sites. Add scheme-aware scrollbars, an accessible skip link and focus outline, and fix the tabset panel border that was indistinguishable from the background in dark mode. (d21e005GitHub)
  • docs: in the collapsed navbar, opening a menu such as Guides overlays on top instead of growing the navbar and pushing the other items down, matching the GitHub widget menu. (930fb21GitHub)

0.5

Read the Gribouille 0.5 announcement

0.5.0 (2026-07-13)

Breaking changes
  • feat!: linetype on geom-segment, geom-curve, geom-spoke, geom-errorbar, geom-errorbarh, geom-linerange, and geom-pointrange defaults to auto and honours a mapped linetype scale instead of pinning "solid". (#169GitHub)
  • feat!: every constructor dict stores its concrete type under a single name: key. The per-family fields geom: (layers), coord:, facet:, family: (scale stubs), labeller:, and key: (draw keys) are renamed, guide-custom() returns kind: "guide", name: "custom", and position-fill()/position-identity()/position-stack() carry an explicit params: (:). Only code that pattern-matches the returned dicts is affected. (#168GitHub)
  • feat!: the per-aesthetic scale-* constructors collapse into an aesthetic-agnostic set keyed through scales(), so scale-colour-viridis-d() becomes scales(colour: scale-viridis-d()) and scale-x-log10() becomes scales(x: scale-log10()). plot(scales:) takes only the scales() dictionary, with no positional array, and expand-limits() returns an aesthetic-keyed dictionary. (#158GitHub)
Changes
  • feat: geom-beeswarm, position-jitter, and position-jitterdodge swarm or jitter a discrete x directly, like geom-violin, so as-factor is needed only to force a numeric column onto a discrete axis. Level positions follow the sorted axis domain, so the swarm aligns regardless of row order. (#196GitHub)
  • feat: facet-wrap and facet-grid gain a gutter argument and honour a new theme(panel-spacing:) default, a length for both axes or a (x:, y:) dictionary. The fixed 0.4/0.3cm panel gaps become a shared 0.5cm default. (#191GitHub)
  • feat: compose gutter accepts a (x:, y:) dictionary for independent column and row spacing alongside the existing scalar length. (#191GitHub)
  • feat: stat-waffle turns per-group counts, one per row or the rounded weight sum, into unit cells on an integer grid, column-major from the bottom-left with groups tiling consecutive runs. Render waffle charts with geom-tile. (#189GitHub)
  • feat: stat-connect gains connection: "sigmoid", a logistic S-curve connector rescaled through both observations with smooth and n control. Paired with geom-line and a reversed y scale it draws bump charts. (#188GitHub)
  • feat: position-stack gains streamgraph baseline offsets: offset: "silhouette" centres each stack on zero and offset: "wiggle" uses the Byron-Wattenberg wiggle-minimising baseline, turning stacked geom-area into a streamgraph. (#187GitHub)
  • feat: stat-difference shades the band between two series by which one is on top. Exact linear crossovers are inserted as shared vertices so ribbon segments meet cleanly, and each run carries a _sign level, named through levels:, for fill: after-stat("_sign"). (#186GitHub)
  • feat: fills accept native Typst tiling paints, both as fixed fill: values and through scale-manual(values:), with legend swatches rendering the patterns. Per-row alpha and seam sealing skip non-colour paints. (#182GitHub)
  • feat: position-beeswarm and geom-beeswarm arrange overplotted points into a deterministic density-shaped swarm (van der Corput walk scaled by each point’s kernel density), a reproducible alternative to position-jitter. (#181GitHub)
  • feat: geom-density-ridges and stat-density-ridges draw overlapping ridgeline plots from raw observations: one Gaussian-KDE ridge per y bucket with heights normalised across buckets, a scale parameter in y-level units, and a new height aesthetic channel. (#180GitHub)
  • feat: geom-density-2d/geom-density-2d-filled and their stats trace iso-lines or shade iso-bands of a native 2D Gaussian kernel density estimate of the raw (x, y) sample, with per-axis bandwidth and grid control. (#178GitHub)
  • feat: geom-smooth/stat-smooth gain method: "loess" with span and degree control: native tricube-weighted local polynomial fits with a pointwise confidence band on n − trace(L) degrees of freedom. (#177GitHub)
  • feat: geom-violin and stat-ydensity draw mirrored per-bucket density silhouettes with scale: "area"/"count"/"width" normalisation, trim control, and dodge support, sharing the native Gaussian KDE core with stat-density. (#176GitHub)
  • feat: geom-density and stat-density bring native 1D kernel density estimation: Gaussian kernels evaluated directly on an n-point grid, Silverman (bw.nrd0) bandwidth with adjust and trim control, weight support, and _density/_count/_scaled/_n after-stat columns. (#175GitHub)
  • feat: every geom exposes key:, a legend glyph override, and, where meaningful, stat: and position:. Stat-backed geoms take stat: auto to build their default stat from the geom parameters. (#169GitHub)
  • feat: a keyed scales() constructor, mirroring guides(), binds scale overrides to aesthetics as named arguments, for example scales(x: scale-continuous(), colour: scale-viridis-d()), instead of a positional array. (#157GitHub)
  • feat: an installable Agent Skill teaches coding agents to author Gribouille plots, confirming every argument against the site’s .llms.md reference. The repository doubles as a Claude Code plugin marketplace, so the skill installs through /plugin install or npx skills add. (#154GitHub)
  • feat: geom and theme-element stroke: accept the native Typst 1.3pt + accent form, writing thickness and paint together. An explicit colour: still wins over the embedded paint. (#153GitHub)
  • fix: support explicit as-factor() on x for geom-violin, geom-boxplot, and other per-group stats when a grouping aesthetic reuses the same column. (#195GitHub)
  • fix: geom-density with a mapped fill aesthetic shades the curves instead of rendering a blank panel. The default is unfilled through a fill role rather than a hard fill: none. (#192GitHub)
  • fix: non-identity positions (jitter, beeswarm) over an as-factor positional column that is also mapped to colour/fill draw the mapped scale colours instead of the default. The 1-indexed positions go to a synthetic column, so the source column keeps its levels. (#192GitHub)
  • fix: pre-stat grouping skips late-binding markers without a source column, such as fill: after-stat("_sign") and colour: after-stat("_level"), instead of crashing on the marker dict. The stat-output column groups the rows once the stat has run. (#186GitHub)
  • fix: annotate forwards a none or auto value on an aesthetic keyword, such as annotate("rect", fill: none), to the geom as a layer parameter instead of storing it as a data cell. The disable and scale-resolve sentinel then applies, and the shape is drawn unfilled. (#183GitHub)
  • fix: fill opacity defaults to 1 on geom-area, geom-ribbon, geom-polygon, geom-ellipse, and geom-mark instead of an implicit 0.3-0.6 translucency. Explicit alpha: values and mapped alpha aesthetics are unaffected. (#179GitHub)
  • fix: abutting opaque fills (tiles, hexes, stacked bars and areas, iso-band cells) are stroked with their own fill colour, removing the hairline background seams that antialiasing bled through between adjacent shapes. (#178GitHub)
  • fix: stat-quantile replaces the O(n³) pair enumeration with an exact O(n² log n) breakpoint search, scaling geom-quantile to thousands of rows with identical fits on unique optima. (#174GitHub)
  • fix: an unknown scale-* constructor argument fails at scales() binding with the valid keys for that scale and aesthetic, and stray positional arguments are rejected instead of ignored. (#172GitHub)
  • fix: an unknown stat, scale transform, or oob name fails with a clear error instead of silently rendering as identity or dropping rows. (#162GitHub)
  • fix: theme() rejects unknown or misspelled element keys and positional arguments instead of storing a key the renderer never reads. (#162GitHub)
  • fix: aes() rejects unknown aesthetic names, such as the US spelling color, with a message listing the valid channels. (#162GitHub)
  • fix: plot() validates the mapping, layers, and coord arguments up front with a named error instead of a cryptic renderer failure. (#162GitHub)
  • fix: data-ingestion and from-theme path errors show the offending value. (#162GitHub)
  • fix: mapping an aesthetic or a facet variable to a column absent from the data fails with a clear error naming the aesthetic, the unknown column, and the available columns, instead of rendering a misleading all-none plot. (#156GitHub)
  • fix: numeric values on a discrete scale (a polygon vertex set between level centres, a jittered point) are kept as fractional level positions instead of being dropped when the scale carries explicit limits. (#151GitHub)
  • docs: the published Typst Universe README drops the repo-only “Ask DeepWiki” badge and keeps the “AI assistants” section. (#194GitHub)
  • docs: add streamgraph, bump chart, difference band, and waffle chart gallery examples. (#193GitHub)
  • docs: a Recipes guide shows chart types and effects built by composing layers and native Typst, with no dedicated geom: lollipop and dumbbell charts, group highlighting, zoom insets, marginal panels, irregular grid layouts, and trend-line casing. (#185GitHub)
  • docs: the agent skill covers the current API: the aesthetic-agnostic scales() constructors, the density and pattern-fill idioms, and a symbol inventory regenerated from lib.typ and checked in CI. (#184GitHub)
  • docs: each scale constructor reference page carries a runnable example in the keyed scales() form. (#160GitHub)
  • docs: an AI Assistants guide explains how to use Gribouille with large language models through the llms.txt machine-readable documentation and the installable skill. (#154GitHub)
  • docs: a Benchmarks guide measures how compile time and output size grow with element count, drawn from a committed dataset with Gribouille itself, and shows where per-row geoms become impractical for large data. (#149GitHub)

0.4

Read the Gribouille 0.4 announcement

0.4.1 (2026-06-23)

  • fix: position: "dodge" shifts point-based geoms (text, label, point, linerange, and others) on continuous x-axes by inferring the slot width from the minimum gap between unique positions. (#145GitHub)
  • fix: string values such as "0" are no longer inferred as numeric for scale type, and only Typst int/float values produce a continuous scale. CSV users relying on string-numeric x-columns being treated as continuous must call as-numeric(data, "col") first. (#145GitHub)
  • docs: the News page links the Gribouille 0.4 release announcement and shows a featured image for each release. (#141GitHub)

0.4.0 (2026-06-22)

Breaking changes
  • feat!: coord-cartesian() and coord-radial() take clip as a boolean (true/false) instead of the strings "on"/"off". (#134GitHub)
  • feat!: labs() is renamed to labels(), and the plot() and compose() labs: argument to labels:. There is no labs alias. (#131GitHub)
  • feat!: coord-cartesian(), stat-function(), and geom-function() rename the xlim/ylim arguments to x-limits/y-limits. (#131GitHub)
  • feat!: the col-mix() colour helper is renamed to colour-mix(), with arguments colour1/colour2. (#131GitHub)
  • feat!: geom-text, geom-label, and geom-typst drop the dx/dy parameters. Offsets now use the nudge-x/nudge-y aesthetics, where a number shifts in data units and a Typst length shifts in canvas units. (#131GitHub)
Changes
  • feat: continuous scale limits and geom-abline intercepts accept ISO-8601 date/datetime/time strings under a temporal scale, completing the temporal-string contract. (#137GitHub)
  • feat: geom-vline/geom-hline intercepts and continuous scale breaks accept ISO-8601 date/datetime/time strings under a temporal scale, matching how geom data is already parsed. (#136GitHub)
  • feat: geom-area() accepts a direction parameter ("hv" or "vh") that steps the filled top edge like geom-step(). none, the default, keeps the smooth area. (#135GitHub)
  • feat: element-text() and element-typst() angle is honoured on axis titles, strip text, and legend title and entry labels, where before it reached only tick labels and the plot title, subtitle, and caption. Axis titles default to 0deg on x and 90deg on y, and reserve the correct space at any angle. (#134GitHub)
  • feat: geom-text(), geom-label(), and geom-typst() accept an angle parameter, a Typst angle defaulting to 0deg, rotating each label. (#134GitHub)
  • feat: every aesthetic key can be pinned as a constant directly on any geom, for example geom-label(nudge-x: 0.5), not only through aes(). Declared parameters still bind first, and unknown or positional arguments are rejected. (#133GitHub)
  • feat: scale expand accepts auto on one side, for example expand: (0%, auto), keeping the per-scale default for that side. (#132GitHub)
  • feat: geom-vline, geom-hline, and geom-abline read their intercept channels from aes(). Binding xintercept/yintercept/slope/intercept together with data draws one line per row with per-row colour/alpha/linewidth/linetype, and a mapped xintercept/yintercept extends the panel to keep the lines in view. The scalar or array parameter still draws shared lines when nothing is mapped. (#129GitHub)
  • feat: a font set in theme(text: ...) reaches literal-glyph point markers, such as shape: sym.star, for both plot markers and legend keys, instead of falling back to the document font. (#126GitHub)
  • feat: geom-text, geom-label, and geom-typst accept a font: parameter. auto uses the theme text font, then the document font. (#126GitHub)
  • feat: panel gridlines split into a ggplot2-style cascade, panel-grid -> panel-grid-major / panel-grid-minor -> -x / -y, so the x and y and the major and minor lines are styled independently. Minor defaults to half the major weight in the same colour, and a blank panel-grid blanks both weights. (#125GitHub)
  • feat: continuous axes draw minor gridlines, visible by default: midpoints between majors for linear, sqrt, and reverse, and sub-decade lines for log10. scale-*-continuous, including log10, sqrt, and reverse, accept minor-breaks and n-minor to position them. (#125GitHub)
  • feat: the legend-position theme entry sets a global side for every legend, as theme(legend-position: "bottom") or through theme-sub-legend(position:), accepting the same values as guide-legend(position:). Any explicit guides() placement still wins. (#123GitHub)
  • feat: discrete swatch legend key glyphs are resizable through guide-legend(key-size: <length>) per legend, or the legend-key theme entry for every swatch legend. The row spacing and label offset grow with the glyph, so enlarged keys do not overlap. (#122GitHub)
  • feat: the shape aesthetic accepts any character as the marker symbol. A value outside the eight built-in keywords renders as a literal glyph, so letters or emoji work as markers across scale-shape, scale-shape-manual, scale-shape-identity, scale-shape-binned, the geom-point(shape: ...) pin, and legend keys. (#120GitHub)
  • feat: scale limits accept auto on one side, for example limits: (auto, 60), keeping the trained bound for the other side. (#116GitHub)
  • feat: binned position scales (scale-x-binned / scale-y-binned) accept breaks as bin edges. Ticks sit at interval midpoints, and n-breaks is ignored when breaks is set. (#116GitHub)
  • feat: binned colour, fill, shape, linetype, size, linewidth, stroke, and alpha scales accept breaks as bin edges. Colour, fill, shape, and linetype bin per row by the edges, and the others bin their legend. (#116GitHub)
  • feat: bundled datasets (penguins, economics, mpg) ship as row-store arrays, so penguins.filter(...) and .map(...) work directly. plot() still accepts them. (#116GitHub)
  • fix: scalar and Typst-length nudge-x/nudge-y values apply to geom-text, geom-label, and geom-typst, where they used to be a silent no-op. (#131GitHub)
  • fix: setting the base line/rect stroke in theme() cascades to every line and rect surface: panel grid, axis line, ticks, legend ticks, and legend bar. element-line/element-rect stroke accepts a ratio, such as 80%, to scale the parent surface thickness, while an absolute length still pins a surface. (#124GitHub)
  • fix: setting the base text size in theme() cascades to every text surface: axis titles, tick labels, legend, strip, and plot title. element-text/element-typst size accepts a ratio, such as 80%, to scale the parent surface size, while an absolute length still pins a surface. (#121GitHub)
  • fix: position: "dodge" shifts geom-text/geom-label/geom-typst, geom-point, geom-line/geom-path/geom-step, geom-pointrange, and geom-linerange marks side by side, matching the dodged bars instead of staying on the category centre. (#119GitHub)
  • fix: theme-grey() matches ggplot2 theme_grey() with white grid lines and no axis lines. (#116GitHub)
  • fix: explicit continuous breaks expand the axis range so requested ticks stay visible, unless a side is pinned by an explicit limit. (#116GitHub)
  • docs: a News page lists the release announcement posts, and each changelog version links to its announcement. (#139GitHub)

0.3

Read the Gribouille 0.3 announcement

0.3.0 (2026-06-14)

Breaking changes
  • feat!: compose() panels are built with the new defer() helper, defer(plot, ...), or defer(compose, ...) to nest, replacing plot(..., defer: true). Panels omit their own width/height, and the composition sizes each cell. (#81GitHub)
Changes
  • feat: the published package ships Tinymist-friendly docstrings, so hovering a gribouille function in an editor shows formatted parameters, returns, and examples instead of the raw @-tag comments. Variadic sinks list their accepted keys: guides() its aesthetics, and theme() and the theme presets their element surfaces. (#108GitHub)
  • feat: under coord-radial, guides(theta: none) hides the angular axis, its arc, minor ticks, and tick labels, and guides(r: none) hides the radial tick labels, leaving the spokes and circles. guides(theta: none) used to add a theta arc instead of hiding the axis. (#106GitHub)
  • feat: guides(x: none) and guides(y: none) hide that axis’s tick marks and tick labels, including any log minor ticks, and reclaim the freed space. The axis line, grid, and title stay, and the title is removed with labs(x: none). (#105GitHub)
  • feat: guides() accepts none to hide a guide and auto for the default, guides(default: none) hides every legend without its own override, and any other non-guide value fails with a clear message. This replaces the removed guide-none(), where none is passed instead. (#104GitHub)
  • feat: annotate() gains a clip argument, true by default. Set clip: false to let an annotation overflow the panel, such as a corner inset or a mark placed past the axis limits. (#93GitHub)
  • feat: compose() accepts theme:. An explicit theme styles the composition chrome (title, hoisted legend, panel tags) and propagates into panels with no theme of their own, otherwise a theme shared by every panel is used. (#82GitHub)
  • feat: geom-area() defaults to stat: "align" and position: "stack". Groups with mismatched x values are resampled onto a shared grid and stacked without an explicit stat: stat-align(). (#77GitHub)
  • fix: stat-bin-2d and stat-bin-hex _density is the cell’s fraction of the total count (count / sum(count)), matching ggplot2, instead of an undocumented count-per-cell-area value. (#109GitHub)
  • fix: data outside a sqrt or log10 transform’s domain, negative, or zero and negative for log10, panics with a clear scale message instead of a raw Typst error. The sqrt inverse clamps padded view bounds at zero, so sqrt axes stay monotone and show the 0 break. (#109GitHub)
  • fix: a horizontal legend (position: "top" or "bottom") with guide-legend(align: center) or align: right centres or right-justifies its key graphic (colourbar bar, key row, or size band) under the title, instead of leaving the graphic pinned at the left edge while the title moved. A centred colourbar also keeps its end labels inside the legend block. (#103GitHub)
  • fix: the theme legend-background inherits the base rect element like every other *-background surface, so theme(rect: ...) cascades to it instead of being ignored. (#101GitHub)
  • fix: guide-legend(nrow:) and guide-legend(ncolumn:) lay a continuous size legend (scale-size-*) out in a grid, like the discrete swatch legend, instead of being ignored. A continuous colourbar stays a single bar and ignores them. (#99GitHub)
  • fix: guide-legend(align:) also aligns the legend title, not just the entry labels, and a string such as align: "left" fails with a clear message instead of a vague panic or silence. align is a Typst alignment: left, center, or right. (#98GitHub)
  • fix: annotate(clip: false) placed outside the scale limits draws instead of being dropped by the out-of-range pre-pass, so a corner inset or a mark parked past the axis range is kept. (#97GitHub)
  • fix: a left or right legend that would overrun the caption, or a hoisted compose() legend that leaves no room for the panels, fails with a clear layout hint instead of silently overprinting. (#96GitHub)
  • fix: continuous scale-size-* legends reserve row height and stride for the resolved key glyph, so a wide size range no longer overlaps the keys and labels. (#95GitHub)
  • fix: the out-of-range filter respects scale expand, keeping points and annotations that sit inside the expansion headroom instead of dropping them. Reversed limits, a flipped axis, no longer drop every row. (#92GitHub)
  • fix: geom-linerange() honours its alpha parameter, where the line used to be drawn fully opaque. (#85GitHub)
  • fix: geom-area(position: "stack") stacks bands correctly. Each polygon’s lower edge sits at the cumulated top of the group below rather than always closing at y = 0. (#77GitHub)
  • fix: stat-align() expands its shared grid by a small offset on either side of every breakpoint, so a group that starts or ends mid-range steps cleanly down to the baseline instead of leaving a wedge below the neighbouring group. (#77GitHub)
  • docs: the theming guide notes relative (%) versus absolute text sizing, and element-text gains an example contrasting the two. (#121GitHub)
  • docs: the guides() reference lists each accepted key (colour, fill, ) as a sub-list under the ..args parameter, sharing one description template. (#108GitHub)
  • docs: reference pages for forwarding functions such as the scale-* colour wrappers list their real parameters instead of an opaque ..args row, and a mixed signature like annotate(geom, ..fields) also lists clip. (#102GitHub)
  • docs: the theme() reference table lists every theme key, adding plot-tag, legend-ticks, legend-background, legend-bar, and geom. (#100GitHub)

0.2

Read the Gribouille 0.2 announcement

0.2.1 (2026-06-03)

  • feat: compose() gains align-panels, false by default. When true, panels share margins grid-wise, left and right per column and top and bottom per row, so their plot areas line up across rows and columns, like patchwork and cowplot panel alignment. (#71GitHub)
  • fix: compose() panel tags (tag-levels) reserve their own band so they no longer overlap the panel content. (#70GitHub)
  • fix: geom-segment/geom-curve/geom-ribbon/geom-area render on discrete scales instead of silently drawing nothing. (#69GitHub)

0.2.0 (2026-06-01)

  • feat: a layer’s data accepts a function applied to the plot data, returning that layer’s frame, such as geom-point(data: rows => rows.filter(...)), for subsetting or per-layer transforms without a separate dataset. (#62GitHub)
  • feat: facet-grid(scales:) supports free scales: "free_x" frees x per column, "free_y" frees y per row, and "free" both. Non-positional scales stay shared and panels keep equal size. (#60GitHub)
  • feat: legend entry labels honour the legend-text text align, and guide-legend() gains an align argument. Horizontal legends default to centred labels and vertical legends to left. (#34GitHub)
  • feat: compose() accepts defer: true to return a spec usable as a panel of another compose, enabling nested compositions. tag-levels accepts a per-depth array, with tag-sep, so nested panels continue the numbering, such as B.1 and B.2. (#24GitHub)
  • feat: compose() can number panels with a tag pattern (tag-levels "A"/"a"/"1"/"I"/"i", plus tag-prefix/tag-suffix/tag-corner), styled by the new plot-tag theme element. (#23GitHub)
  • feat: compose() accepts composition-level labs (title, subtitle, caption) and alt, and controls the collected legend’s side through guides, such as guides(default: guide-legend(position: "bottom")). The guides-placement parameter is removed. (#22GitHub)
  • feat: guides() accepts a default entry that sets fallback guide options, such as the legend side, inherited by every aesthetic without its own override, in both plot() and compose(). guide-legend’s position defaults to auto and inherits from it. (#21GitHub)
  • feat: compose() gains width/height, filling a bounded container by default, and relative widths/heights to set panel proportions relative to one another. (#20GitHub)
  • feat: element-text() and element-typst() gain an align parameter setting per-surface text alignment, independent of the container. Title and subtitle default to left, caption to right, and axis titles and strip text to centred. (#13GitHub)
  • feat: labs() fields default to auto. Pass none to suppress an axis or legend title and reclaim the space it reserved. (#12GitHub)
  • feat: element-blank() on a text surface (axis, plot, or legend title) collapses the space the text would reserve. (#12GitHub)
  • feat: width/height accept auto to fill the available space of a bounded container. (#10GitHub)
  • fix: a standalone plot no longer reserves a fixed empty margin on its top and right edges, letting the panel fill that space. (c9d53acGitHub)
  • fix: a plot with no x-axis title reclaims the empty space the title would have reserved below the panel, matching the y-axis side. (#61GitHub)
  • fix: element-text(angle:)/element-typst(angle:) rotate axis tick labels, seeding the guide-axis(angle:) default, and the plot title, subtitle, and caption, instead of being ignored. (#59GitHub)
  • fix: labs(tag:) draws the figure tag above the title on a standalone plot, styled by the plot-tag theme element, instead of being ignored. (#58GitHub)
  • fix: labs(alt:) fills in the figure’s accessibility alt text when plot(alt:) is unset, instead of being stored and ignored. (#57GitHub)
  • fix: geom-qq()/geom-qq-line() honour the distribution argument (uniform/exponential) instead of always plotting against the normal reference. (#56GitHub)
  • fix: the font set on element-text/element-typst/element-geom is applied to every text surface and to the text-drawing geoms, inheriting the base text font when unset. (#54GitHub)
  • fix: a stage/after-scale channel trains its scale on the marker’s source column, so the closure receives the channel’s scale-resolved value as documented. (#52GitHub)
  • fix: grouped geoms such as geom-smooth no longer panic when a grouping aesthetic is mapped through after-scale or stage. (#51GitHub)
  • fix: facet-grid legends reserve space for a secondary x-axis so a top legend no longer overlaps its ticks. (#46GitHub)
  • fix: geom-errorbar()/geom-errorbarh()/geom-rug() resolve an after-scale/stage colour mapping instead of panicking. (#45GitHub)
  • fix: continuous legends fall back to computed breaks when every user-supplied break falls outside the domain. (#44GitHub)
  • fix: coord-cartesian(xlim:/ylim:) zooms continuous axes instead of being ignored. (#43GitHub)
  • fix: coord-flip(reverse: true) preserves a log10/sqrt axis transform instead of overwriting it. (#42GitHub)
  • fix: geom-col() on a continuous x with a single distinct value no longer panics when inferring the bar width. (#41GitHub)
  • fix: log10/sqrt scales validate user limits and report a clear error for non-positive bounds. (#40GitHub)
  • fix: geom-smooth() honours the level argument when sizing the confidence band instead of always using 95%. (#39GitHub)
  • fix: binning geoms reject a non-positive bins with a clear error instead of dividing by zero. (#38GitHub)
  • fix: contour stats skip incomplete cells when the (x, y, z) grid is sparse instead of panicking. (#37GitHub)
  • fix: scale-*-manual() with an empty values array reports a clear error instead of an opaque divide-by-zero. (#36GitHub)
  • fix: number formatters carry a fraction that rounds up to a whole unit, so 0.9999995 no longer renders as 0.1, and format-scientific keeps its mantissa in [1, 10). (#35GitHub)
  • fix: legend guides reserve space for multi-line labels, measuring the resolved custom labels: for both width and line count across swatch, size-ladder, and colourbar guides, so two-line content no longer clips or overlaps. (#33GitHub)
  • fix: a column mapped to both a positional aesthetic (x/y) and a grouping aesthetic (fill, colour, group, and others), for example aes(x: "class", fill: "class"), resolves the grouping aesthetic across aggregating stats (boxplot, summary, count/sum, histograms). It used to draw every mark in the ink colour with an empty guide. (#31GitHub)
  • fix: continuous scales honour an explicit breaks argument for axis ticks and continuous legend guides instead of ignoring it. Breaks outside the domain are dropped. (#30GitHub)
  • fix: geom-ribbon() draws one band per discrete fill/colour/group instead of merging every group into a single ribbon. (#29GitHub)
  • fix: plot(width: auto, height: auto) is allowed on an unbounded page, falling back to the default 10cm by 7cm instead of panicking. (#27GitHub)
  • fix: compose() panels fill their cells instead of being letterboxed. Their own width/height are discarded once the composition has a size, and the composition size falls back to 16cm by 12cm when the container is unbounded. (#26GitHub)
  • fix: legend labels wider than 2 cm no longer overlap the next swatch. Each legend column reserves the label’s full width, most visible in horizontal legends. (#25GitHub)
  • fix: the compose collected legend placed on top or bottom no longer clips its first swatch and is centred under the panels. (#19GitHub)
  • fix: width/height bound the whole image, including title, subtitle, caption, and plot-background padding. The data panel shrinks to fit and long titles wrap. (b53fab2GitHub)
  • docs: callout headers sit on the type tint as a distinct band while the body uses the plain surface, and caution gets its own deeper mustard so it no longer matches warning. (#16GitHub)
  • docs: tabset (panel-tabset) labels follow the light/dark theme, and the active tab label uses the brand primary colour in both schemes. (#15GitHub)
  • docs: the development version is downloadable from the dev documentation site and installable as a local package, and the release, Typst Universe, and development archives share an identical payload. (#14GitHub)

0.1

Read the Grammar of Graphics for Typst announcement

0.1.1 (2026-05-22)

  • fix: centre collected compose side legends against the panel grid. (994c9e8GitHub)
  • fix: apply plot background inset/outset even without a fill. (2f24982GitHub)
  • docs: enable llms.txt output for the documentation site. (6b05d6aGitHub)
  • docs: add a navbar version switcher between the stable and development docs. (95c3d9bGitHub)

0.1.0 (2026-05-20)

  • feat: initial version of Gribouille.

Looking for a specific change? Browse the full commit history or the list of releases on GitHub.

Back to top