# svg-animate

**svg-animate** turns your TikZ diagrams into step-by-step animations that
run natively in any web browser — no JavaScript, no plugins, no PDF viewer
required.

Write your diagram once.  Get two outputs from the same source file:

- an **animated SVG** for the web, embedded slides, or GitHub README previews
- a **static PDF** for print, with all steps stacked or collapsed to a single
  clean frame

The animation model maps directly onto the way you already think about
progressive diagram reveals:

- **`\begin{animate}`** — wraps your TikZ picture
- **`\reveal{...}`** — marks what appears at the current step
- **`\animstep`** — advances to the next step

That is all you need for a working animation.  Fine-grained control is there
when you need it: per-step durations, multi-step and range visibility,
blinking elements, one-shot or looping playback, and a `\noanimate` fallback
that controls what a PDF reader shows after the animation ends.

A LaTeX package for producing **animated SVG diagrams** with TikZ.

The animation model is simple: content is divided into discrete *steps*, and
only one step is fully visible at a time — like frames in a film.  Opacity
transitions are instantaneous (no cross-fades), implemented as SMIL keyframes
in the SVG output.

## Quick start

```latex
\documentclass{standalone}
\usepackage{svg-animate}

\begin{document}
\begin{tikzpicture}
  \begin{animate}[duration=1]
    \reveal{\node at (0,0) {Step 1};}
    \animstep
    \reveal{\node at (0,0) {Step 2};}
    \animstep
    \reveal{\node at (0,0) {Step 3};}
  \end{animate}
\end{tikzpicture}
\end{document}
```

## Compilation

```bash
# Animated SVG
latex diagram.tex && latex diagram.tex
dvisvgm --font-format=woff2 --optimize=all --bbox=min diagram.dvi -o diagram.svg

# Static PDF (animations ignored)
xelatex diagram.tex
```

Or simply run `make` inside the package directory to build `example.svg` and
`doc.pdf`.

## Example — traffic light

The included `example.tex` animates a traffic light.  Each coloured circle is
its own step; the amber light uses a shorter `duration`.

![Traffic light animation](example.svg)

> Open `example.svg` directly in a browser to see the animation.
> GitHub's Markdown renderer may display it as a static image.

## Feature showcase

The `test.tex` file exercises the main features side by side:

![Feature showcase](test.svg)

| Column | Setting | What it shows |
|---|---|---|
| **loop=true** | default | loops indefinitely |
| **loop=false** | `loop=false` + `\noanimate` | plays once, reverts to a static resting state |
| **static** | `inactive opacity=1` | all steps visible simultaneously |

Labels beside each light illustrate:

- **fr. 1** — standard `\reveal`, active only in step 1
- **fr. 2+4** / **fr. 3+4** — `step={2,4}` / `step={3,4}`, active in multiple non-consecutive steps
- **fr. 3 — blink** — `blink=0.3`, flashes during step 3; hidden between steps (default `blink off opacity=0`)
- **fr. 3 — dimmed blink** — `blink=0.3, inactive opacity=0, blink off opacity=0.25`, hidden between steps; blinks between 1 and 0.25 during step 3
- **step={1-3}** — range syntax, active in steps 1 through 3
- **step={1,2,3,4}** — always visible, active in every step

## Static PDF output

In PDF mode (`xelatex`, `pdflatex`) the package detects the output format and
adapts automatically:

- **No `\noanimate`** — `\reveal` elements are drawn at full opacity
  simultaneously (all steps stacked), which is useful for a quick overview.
- **`\noanimate{content}` present** — `\reveal` elements are suppressed and
  only the `\noanimate` content is drawn, giving a single clean static frame.
- **`\reveal[noanimate]{content}`** — forces this specific element to render
  in PDF even when `\noanimate` is active in the same environment.

`\noanimate` is completely ignored in SVG mode.

## Key interface

| Level | Syntax | Scope |
|---|---|---|
| Global | `\tikzset{/anim/duration=2}` | all diagrams |
| Environment | `\begin{animate}[duration=1, inactive opacity=0]` | this environment |
| Step | `\animstep[duration=0.5]` | following step |
| Element | `\reveal[inactive opacity=0.2]{...}` | this element |
| Static fallback | `\noanimate{...}` | PDF only, SVG ignored |

### `/anim/.cd` keys

| Key | Default | Description |
|---|---|---|
| `duration` | `2` | seconds per step |
| `active opacity` | `1` | opacity when step is active |
| `inactive opacity` | `0` | opacity when step is inactive (`0`=hidden, `>0`=dimmed) |
| `loop` | `true` | `false` = play once and freeze on last frame |
| `noanimate` | — | force this `\reveal` to render in PDF even when `\noanimate` is present |
| `step=<spec>` | — | show element during specific steps (see below) |
| `blink=<seconds>` | — | blink at given period during the active step (see below) |
| `blink on opacity` | `1` | opacity during blink "on" half-periods within the active step |
| `blink off opacity` | `0` | opacity during blink "off" half-periods within the active step (between steps the element uses `inactive opacity`) |
| `static` | — | render all `\reveal` at full opacity (no animation); shorthand for the "show all steps simultaneously" idiom |

### One-shot animation with `loop=false`

By default animations loop indefinitely.  Set `loop=false` to play through
all steps once and freeze on the last frame:

```latex
\begin{animate}[duration=1, loop=false]
  \reveal{\node {Step 1};}
  \animstep
  \reveal{\node {Step 2};}
  \animstep
  \reveal{\node {Step 3};}
\end{animate}
```

The global default can be changed with `\tikzset{/anim/loop=false}`.

When the animation ends, the SVG browser reverts each element to its base
opacity (fully visible).  If a `\noanimate` fallback is present it therefore
becomes visible at that point, giving the diagram a natural static resting
state after the animation completes.

### Multi-step visibility with `step=`

By default `\reveal` makes an element visible only during the **current step**.
The `step=` key overrides this: the element becomes visible during every step
in the specification, regardless of where `\reveal` is placed.

```latex
\begin{animate}[inactive opacity=0.08]
  \reveal[step={1,3}]{\node[red]  at (4,1) {visible in steps 1 and 3};}
  \reveal[step=2-4]{  \node[blue] at (4,0) {visible in steps 2 through 4};}
  \reveal[step={1,3-5}]{\node at (4,-1) {steps 1, 3, 4, 5};}
\end{animate}
```

**Syntax:**

- Single step — `step=2`
- Range — `step=2-5` (steps 2, 3, 4, 5)
- List — `step={1,3}` (braces required when listing multiple values)
- Mix — `step={1,3-5}` (braces required)

Consecutive steps in the specification are automatically merged into one
animation window (no redundant keyframe at the shared boundary).

### Blinking elements with `blink=`

The `blink=` key makes an element flash on and off during its active step.
The value is the **full blink period** in seconds: the element is visible for
`period/2` seconds, hidden for `period/2` seconds, and repeats.

```latex
\begin{animate}[duration=2, inactive opacity=0.15]
  \reveal{\node at (0,1) {Step 1 — static};}
  \animstep
  \reveal[blink=0.4]{\node[fill=yellow] at (0,0) {Step 2 — blinks};}
  \animstep
  \reveal{\node at (0,-1) {Step 3 — static};}
\end{animate}
```

If the step duration is not an exact multiple of `period/2`, the last
partial half-period is shown up to the step boundary.

`blink=` and `step=` are mutually exclusive; when both are given, `blink=`
takes priority.

The blink amplitude is controlled via `blink on opacity` (default `1`) and
`blink off opacity` (default `0`).  These keys govern **only** the intra-step
oscillation; between steps the element uses `inactive opacity` as normal.

To hide a blink element between steps, set `inactive opacity=0` explicitly.
Because the static column now uses `\begin{animate}[static]`, this does not
affect the static display:

```latex
%% Hidden between steps; blinks between 1 and 0.25 during step 2.
\reveal[blink=0.4, inactive opacity=0, blink off opacity=0.25]{
  \node[fill=yellow] at (0,0) {Step 2};
}
```

### Static display with `static`

To render all steps simultaneously at full opacity (for a printed handout or
overview), use the `static` key on the `animate` environment:

```latex
\begin{animate}[static]
  \stepOne \animstep \stepTwo \animstep \stepThree
\end{animate}
```

All `\reveal` elements are drawn at their natural opacity regardless of
`inactive opacity`, `blink on/off opacity`, or any other per-element setting.
This is cleaner than setting four opacity keys to `1`.

## Requirements

- PGF/TikZ ≥ 3.1.9 (for `\usetikzlibrary{animations}`)
- `dvisvgm` ≥ 2.9 for SVG output
- Any modern LaTeX distribution (TeX Live 2022+, MiKTeX 22+)

## Documentation

```bash
make doc.pdf
```

Full documentation with key reference and examples: `svg-animate.pdf`.

## Copyright

`svg-animate` is copyright 2026 Sébastien Gross and distributed under
the terms of the GNU Affero General Public License v3.0 or later.
