# How to Add Optional Animation to a Diagram in cathrynlavery/diagram-design

> Easily add optional animation to your diagrams in cathrynlavery/diagram-design. Learn to declare attributes, import controllers, and validate your animated diagrams.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: how-to-guide
- Published: 2026-08-19

---

**In the `cathrynlavery/diagram-design` repository, you add optional animation to a diagram by declaring a `data-motion-mode` attribute on the root element, tagging items with `data-motion-item` and `data-step`, importing the canonical controller, and validating with the provided Python scripts.**

The `cathrynlavery/diagram-design` skill treats **optional animation** as a presentation layer that never changes the underlying static meaning of a diagram. When you add optional animation to a diagram, the complete diagram must already exist in the DOM before any motion runs. The rules that govern this behavior are defined in [`skills/diagram-design/references/animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md).

## Choose an Animation Mode

The first step is declaring how the motion behaves. Add the **`data-motion-mode`** attribute to the root element of the diagram—typically the `<svg>` or a wrapper `<div>`.

The [`skills/diagram-design/references/animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md) reference file defines four valid values:

- `none` — Renders a static diagram with no scripts. This is the default.
- `reveal` — Plays a single deterministic autoplay run that stops on completion.
- `step` — Enables a pause-able, step-wise animation with explicit playback controls.
- `loop` — Runs a decorative token that repeats indefinitely without changing meaning.

## Load the Animation Controller On Demand

The repository loads motion assets only when a diagram requests them. The **canonical controller** lives in [`skills/diagram-design/assets/template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/assets/template-motion.html) and serves as the HTML scaffold and script bundle for all animated diagrams.

If the root element carries a mode other than `none`, the skill loader pulls in [`animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/animation.md) and the controller template. Otherwise, the diagram remains script-free and static.

## Tag Elements with Semantic Motion Primitives

Every animated element must be tagged with **`data-motion-item`** and assigned a numeric **`data-step="N"`** where **N** is between `1` and `8`. The [`animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/animation.md) reference lists the allowed **semantic primitives**—such as *Path draw*, *Staggered reveal*, and *Queue counter*—along with their limits.

Only elements that carry the **`.motion-ready`** class are permitted to hide or transform during playback. This constraint keeps the animation predictable and scoped.

```html
<div class="diagram" data-motion-mode="reveal" data-motion-root>
  <svg viewBox="0 0 400 300">
    <g data-motion-item data-step="1" class="motion-ready">
      <!-- First element to appear -->
    </g>
    <g data-motion-item data-step="2" class="motion-ready">
      <!-- Second element -->
    </g>
  </svg>
</div>

<script src="skills/diagram-design/assets/template-motion.html"></script>

```

## Honor the Static-First Contract

Before any animation runs, the complete diagram—including all labels, connectors, and outcomes—must already be present in the HTML or SVG. The animation layer is strictly additive; it cannot introduce nodes that do not exist in the static markup.

CSS selectors scoped under `.motion-ready` are the only elements allowed to change visibility or geometry during playback. This **static-first contract** ensures that if scripts fail or motion is disabled, the diagram remains fully readable.

## Provide Accessible Playback Controls

When you use `data-motion-mode="step"`, you must supply native `<button>` controls for **Play**, **Pause**, **Replay**, **Previous**, and **Next**. Each button uses a **`data-motion-action`** attribute with values such as `play`, `pause`, `replay`, `prev`, or `next`.

These **accessible controls** must be keyboard-accessible and include proper ARIA labeling so users can navigate the step-wise animation without relying on a mouse.

```html
<div class="diagram" data-motion-mode="step" data-motion-root>
  <svg viewBox="0 0 400 300">
    <!-- Static content plus ordered motion items -->
  </svg>

  <div data-motion-controls>
    <button data-motion-action="play" aria-pressed="false">Play</button>
    <button data-motion-action="pause" aria-pressed="false">Pause</button>
    <button data-motion-action="prev">Previous</button>
    <button data-motion-action="next">Next</button>
    <button data-motion-action="replay">Replay</button>
  </div>
</div>

<script src="skills/diagram-design/assets/template-motion.html"></script>

```

## Validate with the Built-In Verification Scripts

After you add optional animation to a diagram, run the verification suite to confirm the contract is honored. The repository provides three scripts in the `scripts/` directory:

1. `python3 scripts/verify-motion.py path/to/diagram.html` — Checks mode declarations, step continuity, timing budgets, and accessibility.
2. `python3 scripts/test-verify-motion.py` — Exercises the verifier against adversarial modifications.
3. `python3 scripts/lint-skin.py path/to/diagram.html` — Validates that the controller matches the canonical template and catches disallowed skin changes.

```bash
python3 scripts/verify-motion.py path/to/diagram.html
python3 scripts/test-verify-motion.py
python3 scripts/lint-skin.py path/to/diagram.html

```

## Respect Reduced-Motion and Export Fallbacks

When a user prefers **reduced motion**, the CSS defined in [`skills/diagram-design/references/animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md) forces a static frame by collapsing animation durations and hiding all playback controls. The same static frame is used when printing or exporting to PNG and SVG.

To explicitly disable animation and keep a diagram static, set `data-motion-mode="none"` and omit the controller script:

```html
<div class="diagram" data-motion-mode="none">
  <svg viewBox="0 0 400 300">…</svg>
</div>

```

## Summary

- Add optional animation to a diagram by choosing one of four motion modes in **`data-motion-mode`**: `none`, `reveal`, `step`, or `loop`.
- Tag animated elements with **`data-motion-item`** and **`data-step="1"`** through **`data-step="8"`**, and restrict visual changes to the **`.motion-ready`** class.
- Load the canonical **[`skills/diagram-design/assets/template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/assets/template-motion.html)** controller only when motion is required.
- For `step` mode, include native buttons with **`data-motion-action`** attributes and ARIA labels.
- Validate your work with **[`scripts/verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-motion.py)**, **[`scripts/test-verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/test-verify-motion.py)**, and **[`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py)**.
- Honor reduced-motion preferences automatically through the CSS contract in **[`animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/animation.md)**.

## Frequently Asked Questions

### What is the maximum number of animation steps allowed per diagram?

The [`skills/diagram-design/references/animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md) contract allows steps numbered `1` through `8`. Each animated element must declare its order with a `data-step` attribute inside that range.

### Can I write a custom animation controller instead of using the canonical template?

No. The [`skills/diagram-design/assets/template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/assets/template-motion.html) file is the canonical controller, and [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py) checks for disallowed deviations. Using a custom controller would break the repository’s static-first contract and fail verification.

### How does the diagram behave if JavaScript is disabled or the controller fails to load?

Because the complete diagram is rendered in the static markup before any animation runs, a missing controller or disabled JavaScript leaves the user with a fully readable static diagram. The `.motion-ready` class is the only scope permitted to alter visibility, so the baseline content remains intact.

### What happens when a user has prefers-reduced-motion enabled?

The CSS in [`skills/diagram-design/references/animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md) forces an immediate static frame by collapsing animation durations and hiding all motion controls. This same static frame is also used for print and raster exports, ensuring the diagram is accessible and deterministic across all environments.