# How to Configure Optional Motion Animations with the Accessibility Contract in Diagram Design

> Learn to configure optional motion animations in Diagram Design using the accessibility contract. Ensure semantic content and reduced-motion fallbacks for all users.

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

---

**Diagram Design enforces a strict accessibility contract that requires all motion to start from a complete static diagram, preserve semantic content for assistive technology, and provide a reduced-motion fallback via `prefers-reduced-motion: reduce`.**

To configure optional motion animations with the accessibility contract in diagram design, developers implement a **static-first enhancement** pattern that validates against the motion verifier scripts in the cathrynlavery/diagram-design repository. This approach guarantees that every animated diagram remains fully accessible while supporting progressive disclosure, teaching sequences, and decorative flow hints.

## Understanding the Accessibility Contract

The accessibility contract is a binding specification that governs how motion may be added to diagrams. It is enforced by the **motion verifier** (`scripts/verify‑motion.py` and `scripts/verify‑semantic‑motion.py`), which checks for compliance before deployment.

### Static-First Requirement

Every animation must **start from a complete static diagram**. All semantic content—including labels, connectors, and statuses—must be present in the source HTML/SVG before any motion is applied. This ensures that if JavaScript fails or motion is disabled, the diagram remains fully readable.

### Semantic Preservation

Decorative elements must be hidden from assistive technology using `aria‑hidden="true"` and `focusable="false"`, while semantic text appears exactly once in the accessibility tree. The SVG `<title>` and `<desc>` elements must describe the full meaning of the diagram without requiring animation to understand the content.

### Reduced-Motion Guarantee

The contract mandates that `prefers‑reduced‑motion: reduce` forces the diagram into its final static frame, hides playback controls, and disables decorative motion. This media query also triggers for print media (`@media print`) and static exports (`?motion=static`).

## Motion Modes and Constraints

Diagram Design supports four distinct motion modes defined by the `data‑motion‑mode` attribute. Only the **`reveal`** mode may autoplay, and it must run **once** on load when motion is explicitly requested.

| Mode | Behavior | Implementation | Typical Use |
|------|----------|----------------|-------------|
| `none` | Fully static, no JavaScript | No controller, plain HTML | Default, print, screenshots |
| `reveal` | One deterministic autoplay run ending in final state | CSS-only (≤ 5 s) or scoped controller | Short ordered explanations |
| `step` | Paused semantic states with interactive controls | Minimal inline JS for Play/Pause | Teaching, policy traces |
| `loop` | Decorative token repeats without changing meaning | CSS-only default | Quiet flow hints (≥ 3 s cycle) |

The **reveal** mode never restarts on viewport re-entry and can be replayed only via the explicit **Replay** control. The **loop** mode is restricted to purely decorative tokens that do not convey semantic information.

## Required Markup Structure

To configure optional motion animations with the accessibility contract in diagram design, apply the following data attributes exactly as specified in [[`skills/diagram-design/references/animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md)](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md):

1. **Single root container**: One element with `data‑motion‑root` and a valid `data‑motion‑mode` (`none|reveal|step|loop`).
2. **Motion items**: Each animated element requires `data‑motion‑item` and an integer `data‑step` attribute defining its sequence.
3. **Decorative markers**: Purely visual items must include `data‑motion‑decorative`.
4. **Live region**: A container with `role="status"` and `aria‑live="polite"` must exist outside the controls to announce step changes (e.g., “Step 3 of 5: first divergence”).

## Accessibility Implementation

Semantic motion requires specific ARIA markup and keyboard interaction patterns defined in the contract.

### Decorative Overlays

Decorative elements carry `aria‑hidden="true"` and `focusable="false"` (see lines 95‑99 of the reference documentation). The verifier automatically checks for these attributes on items marked with `data‑motion‑decorative`.

### Keyboard Controls

Interactive diagrams must use native `<button>` elements with `data‑motion‑action` attributes (`play`, `pause`, `prev`, `next`, `replay`). These buttons must expose focus, `aria‑pressed`, and disabled states. Arrow keys, Home/End, Space, and `R` (replay) operate on the motion root without stealing focus.

### Live Status Region

The status container announces meaningful step changes but not every frame. Place this element outside the control block to prevent interference with assistive technology navigation.

## Reduced-Motion and Print Fallbacks

The contract requires CSS that responds to user preferences and output media:

- **Reduced motion**: `@media (prefers-reduced-motion: reduce)` forces all items to `opacity: 1` and `transform: none`, hides decorative elements with `display: none`, and removes playback controls.
- **Print**: `@media print` applies the same static presentation as reduced motion.
- **Export**: Static exports use the query parameter `?motion=static` to trigger the final frame view.

## Verification Workflow

Before deploying an animated diagram, run the verification scripts to confirm compliance with the accessibility contract.

**Basic motion verification**:

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

```

**Semantic and accessibility verification**:

```bash
python3 scripts/verify-semantic-motion.py path/to/diagram.html

```

These scripts validate:
- Single `data‑motion‑root` element and valid `data‑motion‑mode`.
- Correctly scoped `data‑motion‑item` elements with integer `data‑step` attributes.
- Proper ARIA markup for decorative items.
- Presence of live status region.
- Reduced-motion CSS that makes every item fully visible.

## Code Examples

The canonical controller implementation lives in [`assets/template‑motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/assets/template-motion.html) and must be used verbatim for any animated diagram.

### Step Animation Implementation

This example demonstrates a minimal `step` mode animation with semantic items and accessible controls:

```html
<div data-motion-root data-motion-mode="step" data-frame="static">
  <!-- Semantic items -->
  <g data-motion-item data-step="1" class="is-visible">
    <text>Step 1 Label</text>
  </g>
  <g data-motion-item data-step="2">
    <text>Step 2 Label</text>
  </g>

  <!-- Controls (copied from template-motion.html) -->
  <div data-motion-controls>
    <button data-motion-action="play"   aria-pressed="false">▶︎</button>
    <button data-motion-action="pause"  disabled>‖</button>
    <button data-motion-action="prev"   disabled>←</button>
    <button data-motion-action="next"   disabled>→</button>
    <button data-motion-action="replay" disabled>↺</button>
  </div>

  <!-- Live status region -->
  <div role="status" aria-live="polite" aria-atomic="true"></div>
</div>

```

All attributes are defined exactly as required by the contract; the diagram starts static, then steps through the two items when the user clicks **Play**.

### Reveal Animation with CSS Timing

For deterministic autoplay that ends in a static state, use `reveal` mode with CSS-only timing:

```html
<div data-motion-root data-motion-mode="reveal">
  <g data-motion-item data-step="1" class="is-visible">
    <text>First item</text>
  </g>
  <g data-motion-item data-step="2">
    <text>Second item</text>
  </g>
  <style>
    .motion-ready [data-motion-item] {
      transition: opacity var(--motion-step) var(--motion-ease),
                  transform var(--motion-step) var(--motion-ease);
    }
    .motion-ready [data-motion-item].is-visible { 
      opacity: 1; 
      transform: none; 
    }
  </style>
</div>

```

Because the mode is `reveal`, the CSS automatically animates the two items once on load and then remains at the final static frame.

### Decorative Tokens

Mark purely visual animations with `data‑motion‑decorative` to ensure they are hidden from assistive technology when reduced motion is preferred:

```html
<g data-motion-decorative data-motion-item data-step="1">
  <path d="M10 10 L90 90" stroke="orange" pathLength="1"
        stroke-dasharray="1" stroke-dashoffset="1"></path>
</g>

```

The token is hidden from assistive tech (`aria‑hidden` added by the verifier) and will be removed when the user’s system prefers reduced motion.

## Key Files in the Repository

- **[`skills/diagram-design/references/animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md)**: Full specification of the optional animation contract, modes, CSS variables (`--motion-fast`, `--motion-step`), and accessibility rules.
- **[`skills/diagram-design/assets/template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/assets/template-motion.html)**: Canonical controller containing the JavaScript that wires up controls, live regions, and state handling. Must be used verbatim.
- **[`scripts/verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-motion.py)**: Linter checking the static-first enhancement contract (single root, mode validity, step ordering).
- **[`scripts/verify-semantic-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-semantic-motion.py)**: Extended verifier validating ARIA markup, reduced-motion CSS, and keyboard interaction requirements.
- **[`commands/doctor.md`](https://github.com/cathrynlavery/diagram-design/blob/main/commands/doctor.md)**: Documentation for running the motion verifier via the `diagram-design doctor` command.

## Summary

- **Configure optional motion animations with the accessibility contract in diagram design** by applying the static-first enhancement pattern and validating with [`verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/verify-motion.py).
- Always include a single `data-motion-root` with a valid mode (`none`, `reveal`, `step`, or `loop`) and sequential `data-step` attributes on items.
- Preserve accessibility by hiding decorative elements with `aria-hidden`, maintaining semantic text in the SVG title/desc, and implementing a live status region.
- Enforce reduced-motion compliance through `@media (prefers-reduced-motion: reduce)` that forces final-frame visibility and hides controls.
- Use the canonical controller from [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html) verbatim to ensure consistent keyboard navigation and ARIA behavior.

## Frequently Asked Questions

### What is the accessibility contract in Diagram Design?

The accessibility contract is a binding specification that guarantees all motion starts from a complete static diagram, preserves semantic content for assistive technology, and provides a reduced-motion fallback. It is enforced by the motion verifier scripts ([`verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/verify-motion.py) and [`verify-semantic-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/verify-semantic-motion.py)) which validate markup structure, ARIA attributes, and CSS fallbacks before deployment.

### How do I verify that my diagram meets the motion accessibility requirements?

Run `python3 scripts/verify-motion.py path/to/diagram.html` to check for structural compliance (single root, valid modes, step ordering). For comprehensive accessibility validation including ARIA markup and reduced-motion CSS, run `python3 scripts/verify-semantic-motion.py`. Both scripts exit with error codes if the accessibility contract is violated.

### Which motion mode should I use for teaching materials?

Use **`step`** mode for teaching and policy traces. This mode presents paused semantic states with interactive Play/Pause/Previous/Next controls, allowing learners to navigate through complex diagrams at their own pace while maintaining full keyboard accessibility and screen reader compatibility via the live status region.

### How does the reduced-motion fallback work?

When a user has `prefers-reduced-motion: reduce` enabled, the diagram immediately renders in its final static state with all items fully visible (`opacity: 1`, `transform: none`), decorative elements hidden (`display: none`), and playback controls removed. The same presentation applies to print media and static exports (`?motion=static`), ensuring no information is lost when motion cannot be perceived.