# How Optional Animation Works in Diagram-Design: Understanding Motion Modes

> Explore optional animation in Diagram-Design. Learn about the four motion modes none reveal step and loop implemented via data-motion-mode for accessible static fallbacks.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: internals
- Published: 2026-08-15

---

**Diagram-Design implements optional animation through a canonical controller in [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html) that supports four distinct motion modes—none, reveal, step, and loop—activated via the `data-motion-mode` attribute while preserving static fallbacks and full accessibility support.**

The `cathrynlavery/diagram-design` repository treats animation as a strictly opt-in enhancement rather than a default behavior. Every diagram begins as a completely static asset, with optional animation layered on only when authors explicitly include the canonical controller and declare a motion mode. This architecture ensures diagrams remain functional for print, screenshots, and users with motion sensitivity while providing rich interactive experiences when desired.

## Understanding the Optional Animation Architecture

The optional animation system centers on a single, byte-for-byte canonical controller located at [`skills/diagram-design/assets/template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/assets/template-motion.html). Authors must include this controller verbatim to enable animation; the repository enforces this through linting and verification scripts that reject modified controllers.

The animation contract is formally defined in [`skills/diagram-design/references/animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md). This document specifies that animation activates only when the `data-motion-mode` attribute is present on the root element, which must also carry `data-motion-root`. Without these attributes, the diagram remains script-free and static.

## The Four Motion Modes in Diagram-Design

The repository supports four mutually exclusive motion modes, each designed for specific use cases and technical constraints.

### none (Static Fallback)

The `none` mode produces a completely static figure with no JavaScript execution. When `data-motion-mode="none"` is set, authors omit the `<script data-diagram-controls>` block entirely, creating a script-free page suitable for print media, screenshots, and environments where JavaScript is disabled. This mode serves as the default state and the reduced-motion fallback.

### reveal (Single Autoplay)

The `reveal` mode executes a single deterministic autoplay sequence that concludes in a complete static frame. For sequences shorter than five seconds, the implementation uses CSS-only animations. Longer sequences utilize the scoped controller from [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html) to manage timing. This mode is ideal for short ordered explanations such as quick flowcharts or process overviews where the animation supplements but does not replace the final diagram.

### step (Interactive Stepping)

The `step` mode presents paused semantic states that users navigate via play, pause, next, and previous controls. The controller maintains state variables—including `step`, `count`, `playing`, `timer`, `stepBeforeReduce`, and `resumeAfterReduce`—to track position and timing. Minimal inline JavaScript handles step counters, timers, and ARIA live-region announcements for screen reader compatibility. This mode suits teaching scenarios, policy-trace walkthroughs, and complex comparison diagrams requiring user-paced exploration.

### loop (Decorative Motion)

The `loop` mode applies to decorative elements that repeat indefinitely without conveying semantic meaning. Implementation uses pure CSS animation scoped specifically to `data-motion-mode="loop"` elements, while the controller remains present primarily to expose the static frame when needed. Typical applications include quiet visual hints for long-running processes with cycles of three seconds or more, such as loading indicators or background activity tokens.

## How the Animation Controller Works

The controller embedded in [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html) serves as the JavaScript engine powering all interactive motion modes. It exposes query parameter parsing for `motion=static|step|…` and respects the `prefers-reduced-motion` media query.

Core functionality resides in several key functions located between lines 74 and 124: `render()` updates the visual state, `play()` initiates sequences, `pause()` halts execution, `tick()` advances frames, and `finish()` completes animations. Lines 56 through 70 implement reduced-motion handling by detecting `prefers-reduced-motion: reduce`, disabling playback, rendering the final static frame, and applying the `data-motion-state="reduced"` attribute.

The controller handles multiple input methods: click events on `[data-motion-action]` buttons, keyboard navigation including `ArrowLeft/Right`, `Home/End`, `Space`, and `R` keys, and the `visibilitychange` event to pause animations when the user switches browser tabs.

## Implementing Motion Modes in Your Diagrams

To create a static diagram without animation:

```html
<link rel="stylesheet" href="style.css">
<main data-motion-root data-motion-mode="none">
  <!-- SVG content here – complete static source -->
</main>

```

To implement a stepped, interactive diagram with controls:

```html
<link rel="stylesheet" href="style.css">
<!-- Copy the controller verbatim from template-motion.html -->
<script data-diagram-controls src="template-motion.html"></script>

<main data-motion-root data-motion-mode="step"
      data-step-count="5" data-step-current="0" data-frame="static">
  <!-- SVG with data-motion-item elements for each step -->
</main>

```

For a reveal autoplay that runs once and stops:

```html
<main data-motion-root data-motion-mode="reveal">
  <!-- SVG items marked with data-motion-item; controller is included -->
</main>

```

For a decorative looping element:

```html
<main data-motion-root data-motion-mode="loop">
  <!-- SVG includes a decorative element with class="flow-token"
       and data-motion-decorative; controller is present -->
</main>

```

## Verification and Quality Assurance

The repository enforces animation consistency through [`scripts/verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-motion.py) and [`scripts/test-verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/test-verify-motion.py). These scripts validate that:

- Only one `<script data-diagram-controls>` block exists per diagram
- The controller body exactly matches the canonical [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html) source
- The `data-motion-mode` attribute contains one of the four allowed values: `none`, `reveal`, `step`, or `loop`
- Infinite CSS animations are scoped exclusively to `data-motion-mode="loop"` elements

This verification ensures that optional animation remains deterministic, accessible, and strictly controlled across all diagrams in the project.

## Summary

- Diagram-Design uses a **canonical controller** in [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html) that must be included verbatim to enable animation.
- **Four motion modes** control behavior: `none` (static), `reveal` (autoplay once), `step` (interactive), and `loop` (decorative infinite).
- The system is **opt-in by default**; diagrams remain completely static unless `data-motion-mode` is explicitly declared.
- **Accessibility features** include `prefers-reduced-motion` support, ARIA live regions, and full keyboard navigation.
- **Verification scripts** enforce controller integrity and mode validity through automated linting.

## Frequently Asked Questions

### What happens if a user has reduced motion preferences enabled?

When the browser reports `prefers-reduced-motion: reduce`, the controller detects this state (lines 56-70) and immediately disables playback, renders the final static frame, and applies `data-motion-state="reduced"`. This ensures users with vestibular disorders or motion sensitivity receive equivalent information without animation.

### Can I modify the animation controller to customize behavior?

No. The [`verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/verify-motion.py) script enforces byte-for-byte equality between your controller and the canonical [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html). Any modification causes verification to fail. This strict policy ensures consistency, predictability, and accessibility compliance across all diagrams in the repository.

### Which motion mode should I use for a tutorial diagram with multiple stages?

Use the `step` mode. This mode provides play/pause/next/previous controls and maintains semantic state through the `step` and `count` variables. It supports keyboard navigation and screen reader announcements via ARIA live regions, making it ideal for educational content where users control the pacing.

### How does the loop mode differ from reveal mode?

The `loop` mode uses pure CSS animation on decorative elements that repeat indefinitely without changing meaning, while `reveal` runs once and stops at a complete static frame. Additionally, `reveal` may use JavaScript timing for longer sequences, whereas `loop` relies on CSS alone and is restricted to non-semantic decorative tokens.