--- title: "CSS class hooks and animation" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{CSS class hooks and animation} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", eval = FALSE) ``` Two rpic extensions delegate presentation to the *host document* that embeds the SVG: `class` attaches CSS class names to shapes, and `animate` emits a timing manifest a player can drive. Neither changes rpic's own rendering — classic output stays byte-identical — but together they make diagrams that respond to the page they live in. ## `class`: CSS hooks on shapes `class` has two forms writing to the same hook — inline at creation, and a statement form that reuses pic's object references (labels, `last line`, `2nd box`), which also reaches shapes drawn inside macros: ```{r} library(rpic) svg <- rpic_svg(' boxht = 0.4; boxwid = 0.9 box class "service" "api" arrow box class "service hot" "billing" arrow box class "storage" "database" class last arrow "dataflow" ') ``` Each class lands on the shape's SVG group (``). The names are validated (`[A-Za-z_][A-Za-z0-9_-]*` only), so there is no attribute-injection surface. Styling happens in the host page. This very vignette embeds the SVG **inline** below and styles it with a `
```{r, echo = FALSE, eval = TRUE, results = "asis"} cat(readLines("figures/class.svg"), sep = "\n") ```
Note the delegation contract: CSS only reaches **inline-embedded** SVG. An `` reference isolates the document, and raster (PNG/PDF) output ignores classes entirely — there, the diagram renders exactly as if no class existed. ## `animate`: a timing manifest `animate` schedules an effect (`draw`, `fade`, `pop`) per shape, again without touching the static rendering: ```{r} bundle <- rpic_manifest(' boxht = 0.35; boxwid = 0.8 A: box "build" arrow box "test" arrow box "ship" animate A with "pop" animate 2nd box with "fade" animate 3rd box with "draw" for 0.8 ') ``` The drawing itself is the ordinary static SVG: ![three boxes labelled build, test and ship connected by arrows](figures/animate.svg) and the bundle carries an `animations` array — shape ids (the same stable `s` ids the class hooks ride on), effect names and a resolved timeline: ```{r, echo = FALSE, eval = TRUE, comment = ""} j <- paste(readLines("figures/animate.json"), collapse = "") m <- regmatches(j, regexpr('"animations":\\[[^]]*\\]', j)) cat(gsub("},", "},\n ", m)) ``` Playing it is the host's job. In the browser, the [`@strategicprojects/rpic`](https://www.npmjs.com/package/@strategicprojects/rpic) npm package ships a GSAP player: `animate(stage, animations, gsap)` builds the timeline (`draw` traces strokes, `pop` scales in, `fade` fades). The [animate extension page](https://rpic.dev/docs/extensions/animate/) shows it running live. Unknown effect names are accepted but reported: the bundle's `warnings` array flags them (`unknown_animation_effect`, with the supported list), the same structured-diagnostic shape used by compile errors. ## Both layers together Class hooks and animation target the same shape groups, so a diagram can be styled by the page *and* animated by the player at once — the classes ride on `` while the manifest addresses `sN`. Everything stays a plain, portable SVG for any consumer that ignores them.