diff --git a/DESCRIPTION b/DESCRIPTION
index f9bd8429..ed99c5b2 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,6 +1,6 @@
Package: vellumplot
Title: A Grammar of Graphics on the 'vellum' Backend
-Version: 0.8.0.9000
+Version: 0.9.0
Authors@R:
person("David", "Schoch", , "david.schoch@cynkra.com", role = c("aut", "cre"))
Description: A declarative, pipe-first grammar of graphics that compiles an
diff --git a/NEWS.md b/NEWS.md
index f1048411..a85ad2fb 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,4 +1,6 @@
-# vellumplot (development version)
+# vellumplot 0.9.0
+
+First tagged release. Everything below is included.
* **Merged choropleth regions.** `mark_sf(merge = TRUE)` dissolves adjacent
features that share a fill into one region, so the internal borders between
diff --git a/README.Rmd b/README.Rmd
index 82e3a2bd..1ff3ee05 100644
--- a/README.Rmd
+++ b/README.Rmd
@@ -37,19 +37,50 @@ compiled into a vellum scene and rendered.
The compile is a real pipeline (spec → resolve encodings → train scales → measure
layout → compile guides → compile marks → vellum scene) and it runs without a
-graphics device, because vellum measures text itself. Two consequences are the
-reason to pick this stack:
-
-* **Every mark keeps its identity through to the output.** A compiled plot *is* a
- vellum scene, so each drawn element carries its data key and its resolved
- device-pixel box (`vellum::scene_model()`). That is what
- [vellumwidget](https://github.com/r-vellum/vellumwidget) reads to add tooltips,
- brushing, and linked selection: the same marks you already declared, not
- `*_interactive()` twins of them, and no second engine re-drawing your plot.
-* **One spec, one solved layout, several destinations.** `render_plot()` writes
- PNG, SVG, or PDF from the *same* compiled scene instead of re-solving layout per
- device, and `as_widget()` hands that scene to the browser. The static figure and
- the interactive one cannot drift, because they are one scene.
+graphics device, because vellum measures text itself. If you already know
+ggplot2 the grammar will feel familiar; the reason to reach for this stack is
+what the retained vector scene underneath makes possible.
+
+### What is a little different here
+
+Most of these exist somewhere in R; having them in one grammar, from one spec, is
+what is unusual. None of it is a reason to switch on its own — but together they
+cover a few gaps.
+
+* **One spec, one solved layout, several destinations — including a *tagged*
+ PDF.** `render_plot()` writes PNG, SVG, or PDF from the *same* compiled scene
+ rather than re-solving the layout per device, and the PDF carries a real
+ structure tree and alt text, so a screen reader can navigate it. Accessible
+ (tagged) PDF output is uncommon for R graphics.
+* **Accessibility is checkable, not just aspirational.** Render through a
+ colour-vision-deficiency simulation (`render(cvd = "deutan")`) to see the figure
+ as a colour-blind reader would, and run `plot_lint()` to be told about tiny
+ text, low contrast, or a single-level legend *before* you publish it.
+* **The interactive widget uses the marks you declared.** A compiled plot *is* a
+ vellum scene, so each element keeps its data key and its resolved device-pixel
+ box (`vellum::scene_model()`).
+ [vellumwidget](https://github.com/r-vellum/vellumwidget)'s `as_widget()` reads
+ those for tooltips, brushing, and linked selection — no `*_interactive()` twins,
+ and no second engine (Vega, plotly) re-drawing the plot in the browser, so the
+ static and interactive figures cannot drift.
+* **Effects and regions stay vector where they can.** `glow()` / `shadow()` are
+ real Gaussian blur (and work on text); Venn/Euler diagrams and merged
+ choropleth regions are computed as boolean *geometry* rather than
+ alpha-composited overlaps, so they stay crisp in a PDF instead of being
+ flattened to pixels.
+* **Texture, not only hue.** `pattern_*()` hatch fills stay legible in greyscale
+ print and under colour-vision deficiency, and render on every backend including
+ PDF.
+* **Animation from the same grammar.** `transition_states()` + `animate()` compile
+ one keyframe per state (scales frozen, so the animation is non-reactive) and
+ `anim_save()` encodes a GIF, an APNG, or a resolution-independent **animated
+ SVG** that honours `prefers-reduced-motion`.
+* **A hand-drawn mode that is exact.** `theme_sketch()` (or a `sketch =` argument)
+ gives a plot a wobbly, hand-drawn look generated *natively* in the engine, so it
+ is identical across PNG, SVG, and PDF rather than a post-hoc filter.
+* **The spec is plain data.** `summary()` shows a plot's structure without drawing
+ it, and the spec round-trips, so a plot is something you can inspect, store, and
+ program against.
## Installation
@@ -173,8 +204,23 @@ render_plot(p, "cars.png")
`theme_classic()`, `theme_void()`, `theme_cyberpunk()`, `theme()` /
`set_theme()`) and multi-plot composition (`hconcat()`, `vconcat()`,
`concat()`, `wrap_plots()`, `inset()`, `repeat_()`).
-* Layer effects (`glow()`, `outline()`, `shadow()`) and gradient fills
- (`linear_gradient()`, `radial_gradient()`).
+* Layer effects (`glow()`, `outline()`, `shadow()`, `motion()`, `echo()`) and
+ gradient fills (`linear_gradient()`, `radial_gradient()`).
+* Pattern (hatch) fills: `pattern_stripe()`, `pattern_crosshatch()`,
+ `pattern_grid()`, `pattern_dot()`, `pattern_checker()`, mapped via
+ `scale_pattern()` — greyscale- and colour-vision-safe, on every backend.
+* Boolean marks: `vvenn()` draws 2-/3-set Venn/Euler diagrams as solid geometry,
+ and `mark_sf(merge = TRUE)` dissolves adjacent same-value regions into one.
+* SVG icon markers (`shape = ` a `d` path string or a `.svg` file) and repelled
+ labels (`mark_text_repel()`, over the engine's overlap solver).
+* Accessibility: tagged PDF output, `plot_lint()` for legibility/contrast
+ problems, colour-vision-deficiency simulation at render time, and font pinning
+ for reproducible text.
+* Animation: `transition_states()` / `transition_time()` / `transition_reveal()`,
+ `ease_aes()`, `animate()`, and `anim_save()` to GIF / APNG / animated SVG.
+* Output: `render_plot()` (PNG/SVG/PDF), `pdf_pages()` (multi-page reports or
+ one page per facet), `render_all()` (parallel batch), and `plot_svg()` for an
+ inline SVG string (e.g. a sparkline inside a `gt` table).
* Hand-drawn rendering: `sketch()` gives any geometry mark a wobbly, hachure-
filled [Rough.js](https://roughjs.com) look (a `sketch =` argument on marks, an
`element_line()` / `element_rect()` `sketch =` slot, or the plot-wide
diff --git a/README.md b/README.md
index 49cd9ad6..7e38bc83 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,84 @@
-
+
+
# vellumplot
-
[](https://github.com/r-vellum/vellumplot/actions/workflows/R-CMD-check.yaml)
+
+
vellumplot is a declarative, pipe-first grammar of graphics built on the
-[vellum](https://github.com/r-vellum/vellum) graphics backend. You
-describe a plot as an inspectable, serializable *spec*; nothing is drawn
-until the spec is compiled into a vellum scene and rendered.
-
-The compile is a real pipeline (spec → resolve encodings → train scales
-→ measure layout → compile guides → compile marks → vellum scene) and it
-runs without a graphics device, because vellum measures text itself. Two
-consequences are the reason to pick this stack:
-
-- **Every mark keeps its identity through to the output.** A compiled
- plot *is* a vellum scene, so each drawn element carries its data key
- and its resolved device-pixel box (`vellum::scene_model()`). That is
- what [vellumwidget](https://github.com/r-vellum/vellumwidget) reads to
- add tooltips, brushing, and linked selection: the same marks you
- already declared, not `*_interactive()` twins of them, and no second
- engine re-drawing your plot.
-- **One spec, one solved layout, several destinations.** `render_plot()`
- writes PNG, SVG, or PDF from the *same* compiled scene instead of
- re-solving layout per device, and `as_widget()` hands that scene to
- the browser. The static figure and the interactive one cannot drift,
- because they are one scene.
+[vellum](https://github.com/r-vellum/vellum) graphics backend. You describe a
+plot as an inspectable, serializable *spec*; nothing is drawn until the spec is
+compiled into a vellum scene and rendered.
+
+The compile is a real pipeline (spec → resolve encodings → train scales → measure
+layout → compile guides → compile marks → vellum scene) and it runs without a
+graphics device, because vellum measures text itself. If you already know
+ggplot2 the grammar will feel familiar; the reason to reach for this stack is
+what the retained vector scene underneath makes possible.
+
+### What is a little different here
+
+Most of these exist somewhere in R; having them in one grammar, from one spec, is
+what is unusual. None of it is a reason to switch on its own — but together they
+cover a few gaps.
+
+* **One spec, one solved layout, several destinations — including a *tagged*
+ PDF.** `render_plot()` writes PNG, SVG, or PDF from the *same* compiled scene
+ rather than re-solving the layout per device, and the PDF carries a real
+ structure tree and alt text, so a screen reader can navigate it. Accessible
+ (tagged) PDF output is uncommon for R graphics.
+* **Accessibility is checkable, not just aspirational.** Render through a
+ colour-vision-deficiency simulation (`render(cvd = "deutan")`) to see the figure
+ as a colour-blind reader would, and run `plot_lint()` to be told about tiny
+ text, low contrast, or a single-level legend *before* you publish it.
+* **The interactive widget uses the marks you declared.** A compiled plot *is* a
+ vellum scene, so each element keeps its data key and its resolved device-pixel
+ box (`vellum::scene_model()`).
+ [vellumwidget](https://github.com/r-vellum/vellumwidget)'s `as_widget()` reads
+ those for tooltips, brushing, and linked selection — no `*_interactive()` twins,
+ and no second engine (Vega, plotly) re-drawing the plot in the browser, so the
+ static and interactive figures cannot drift.
+* **Effects and regions stay vector where they can.** `glow()` / `shadow()` are
+ real Gaussian blur (and work on text); Venn/Euler diagrams and merged
+ choropleth regions are computed as boolean *geometry* rather than
+ alpha-composited overlaps, so they stay crisp in a PDF instead of being
+ flattened to pixels.
+* **Texture, not only hue.** `pattern_*()` hatch fills stay legible in greyscale
+ print and under colour-vision deficiency, and render on every backend including
+ PDF.
+* **Animation from the same grammar.** `transition_states()` + `animate()` compile
+ one keyframe per state (scales frozen, so the animation is non-reactive) and
+ `anim_save()` encodes a GIF, an APNG, or a resolution-independent **animated
+ SVG** that honours `prefers-reduced-motion`.
+* **A hand-drawn mode that is exact.** `theme_sketch()` (or a `sketch =` argument)
+ gives a plot a wobbly, hand-drawn look generated *natively* in the engine, so it
+ is identical across PNG, SVG, and PDF rather than a post-hoc filter.
+* **The spec is plain data.** `summary()` shows a plot's structure without drawing
+ it, and the spec round-trips, so a plot is something you can inspect, store, and
+ program against.
## Installation
-``` r
+```r
# install.packages("pak")
pak::pak("r-vellum/vellumplot")
```
-vellumplot needs the [vellum](https://github.com/r-vellum/vellum)
-backend, which compiles a Rust crate, so you also need a Rust toolchain
-(`cargo`/`rustc`); pak pulls vellum in automatically.
+vellumplot needs the [vellum](https://github.com/r-vellum/vellum) backend, which
+compiles a Rust crate, so you also need a Rust toolchain (`cargo`/`rustc`); pak
+pulls vellum in automatically.
## Usage
-Building a plot returns a spec; printing it draws into the Plots pane
-(and embeds in a knitr/Quarto chunk), like ggplot2. Use `render_plot()`
-to write a file.
+Building a plot returns a spec; printing it draws into the Plots pane (and
+embeds in a knitr/Quarto chunk), like ggplot2. Use `render_plot()` to write a
+file.
+
``` r
library(vellumplot)
@@ -57,20 +89,28 @@ vplot(mtcars) |>
scale_color_continuous()
```
-
+
+plot of chunk example
+
+
+plot of chunk layers
+
+
+plot of chunk facet
+
+
+plot of chunk sf
+
+
+plot of chunk network
+