# How to Use Step Animation Mode for Teaching and Policy Traces in Diagram Design

> Master the step animation mode in diagram design for effective teaching and policy traces. Pause and inspect states for clear walkthroughs. Learn how now.

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

---

**The `step` animation mode pauses your diagram at each semantic step, letting viewers inspect state before advancing—ideal for tutorials and policy trace walkthroughs.**

In the **cathrynlavery/diagram-design** repository, `step` is the only interactive animation mode supported. It powers everything from three-step tutorials to complex five-stage policy evaluations. This guide shows you exactly how to implement it, with markup patterns drawn directly from the source code.

---

## Declare the Step Mode on Your Root Element

Every step-mode diagram needs a **motion root**—the container that triggers the controller. Add `data-motion-mode="step"` to the element carrying `data-motion-root`.

```html
<main data-motion-root data-motion-mode="step" data-step-count="5">

```

The `data-step-count` attribute is mandatory. It tells the controller how many semantic steps exist (range: 1–8). This pattern appears in [`example-policy-trace-animated.html`](https://github.com/cathrynlavery/diagram-design/blob/main/example-policy-trace-animated.html), the canonical reference implementation.

---

## Mark Semantic Items with Step Numbers

Each SVG group that should appear at a specific step gets two attributes:

- **`data-motion-item`** — enrolls the element in the animation system
- **`data-step="k"`** — reveals the element at step *k* and keeps it visible for all subsequent steps

Example from the policy trace file:

```html
<g data-motion-item data-step="3" aria-label="Rule 3: authentication required">
  <!-- SVG content for this step -->
</g>

```

Steps must be **contiguous** (1, 2, 3, 4, 5…). The [`verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/verify-motion.py) script rejects gaps or out-of-order declarations.

---

## Add Required Playback Controls

The controller wires buttons automatically, but the markup structure is strict. Use a container with `data-motion-controls` and buttons with specific `data-motion-action` values:

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

```

Missing actions won't break the diagram, but they frustrate keyboard users. Include all five for full accessibility compliance.

---

## Enable Keyboard Navigation

When focus is inside the motion root (set `tabindex="-1"` to make it focusable), these keys work as defined in [`animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/animation.md):

- **Left/Right arrows** — previous/next step
- **Space** — toggle play/pause (when not on a native button)
- **R** — replay from step 1
- **Home/End** — jump to first or last step

The controller in [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html) handles all key events. **Do not modify this file**—the [`lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/lint-skin.py) CI check will reject any changes.

---

## Handle Reduced Motion Preferences

Step mode automatically respects `prefers-reduced-motion`. When detected, the diagram:

- Renders the **static frame** (all steps visible simultaneously)
- Hides the control buttons
- Disables all animation

This behavior is contractually defined in **§ Static-first enhancement** of [`animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/animation.md). No extra markup required.

---

## Deep-Link to Specific Steps

For regression testing or documentation embeds, use the query string `?motion=step&step=K`:

```text
example-policy-trace-animated.html?motion=step&step=3

```

The controller renders steps 1 through 3 and stops. The `data-motion-status` element (if present) shows "Step 3 of 5."

---

## Complete Minimal Example

Here's a three-step teaching diagram following all repository conventions:

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Three-step tutorial</title>
  <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif&family=Geist&display=swap" rel="stylesheet">
</head>
<body>
<main data-motion-root data-motion-mode="step"
      data-step-count="3" tabindex="-1">

  <svg viewBox="0 0 800 200" role="img" aria-labelledby="title">
    <title id="title">Three-step tutorial</title>

    <g data-motion-item data-step="1">
      <rect x="50" y="50" width="200" height="80"/>
      <text x="150" y="95" text-anchor="middle">Introduction</text>
    </g>

    <g data-motion-item data-step="2">
      <rect x="300" y="50" width="200" height="80"/>
      <text x="400" y="95" text-anchor="middle">Core Concept</text>
    </g>

    <g data-motion-item data-step="3">
      <rect x="550" y="50" width="200" height="80"/>
      <text x="650" y="95" text-anchor="middle">Application</text>
    </g>
  </svg>

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

  <span data-motion-status role="status" aria-live="polite"></span>
</main>

<script data-diagram-controls src="assets/template-motion.html"></script>
</body>
</html>

```

---

## Validation and Enforcement

Two CI scripts guarantee compliance:

| Script | Purpose |
|--------|---------|
| [`scripts/verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-motion.py) | Checks contiguous step ranges, timing budgets, and accessibility attributes |
| [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py) | Verifies [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html) is unmodified and correctly referenced |

Run both before committing. Failures block merge.

---

## Summary

- **Step mode** is declared with `data-motion-mode="step"` on the motion root
- **Contiguous numbering** (1–N) is enforced by `data-step-count` and CI validators
- **Semantic items** use `data-motion-item` + `data-step="k"` for visibility control
- **Five control buttons** (prev, play, pause, next, replay) provide full interaction
- **Keyboard shortcuts** (arrows, space, R, home/end) work without extra JavaScript
- **Reduced motion** automatically falls back to static rendering
- **Query strings** (`?step=K`) enable direct frame access for testing

---

## Frequently Asked Questions

### What happens if I skip a step number?

The [`verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/verify-motion.py) validator fails with a non-contiguous step error. Steps must form an unbroken sequence from 1 to `data-step-count`. Fix by renumbering or adjusting the count.

### Can I use more than 8 steps?

No. The step-mode contract in [`animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/animation.md) caps step counts at 8 to preserve performance and cognitive load. For longer sequences, split into multiple diagrams or use static frames.

### Why does my controller not respond to keyboard input?

The motion root needs `tabindex="-1"` to accept focus. Without it, key events never reach the controller. Also verify [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html) is loaded via `<script data-diagram-controls>`.