# CSS class hooks and animation

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:

    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 (`<g id="sN" class="…">`). 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 `<style>` block — the “billing” box is hot, services get a blue border, and the last arrow is dashed. That is live CSS, not something rpic drew:

Note the delegation contract: CSS only reaches inline-embedded SVG. An `<img src="…svg">` 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:

    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

and the bundle carries an `animations` array — shape ids (the same stable `s<N>` ids the class hooks ride on), effect names and a resolved timeline:

    "animations":[{"id":"s0","effect":"pop","start":0,"duration":0.6},
     {"id":"s2","effect":"fade","start":0.6,"duration":0.6},
     {"id":"s4","effect":"draw","start":1.2,"duration":0.8}]

Playing it is the host’s job. In the browser, the `@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 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 `<g id="sN" class="…">` while the manifest addresses `sN`. Everything stays a plain, portable SVG for any consumer that ignores them.