How to Use Step Animation Mode for Teaching and Policy Traces in Diagram Design
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.
<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, 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 systemdata-step="k"— reveals the element at step k and keeps it visible for all subsequent steps
Example from the policy trace file:
<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 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:
<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:
- 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 handles all key events. Do not modify this file—the 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. No extra markup required.
Deep-Link to Specific Steps
For regression testing or documentation embeds, use the query string ?motion=step&step=K:
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:
<!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 |
Checks contiguous step ranges, timing budgets, and accessibility attributes |
scripts/lint-skin.py |
Verifies 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-countand 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 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 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 is loaded via <script data-diagram-controls>.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →