How to Ensure Diagrams Are Accessible with Animation Constraints
Diagrams remain accessible under animation constraints by isolating motion as an optional layer that preserves complete semantic information in the static SVG, enforcing strict contracts via animation.md, and using the canonical motion controller from template-motion.html with automated verification through verify-semantic-motion.py and verify-motion.py.
The cathrynlavery/diagram-design repository treats animation as a progressive enhancement rather than a core requirement, ensuring that diagrams are accessible to screen readers, printable without artifacts, and compatible with reduced-motion preferences. By adhering to the static-first enhancement contract defined in skills/diagram-design/references/animation.md and utilizing the four sanctioned motion modes, you can ensure diagrams are accessible with animation constraints while still offering rich visual experiences.
Understand the Animation Contract Architecture
The repository enforces accessibility through a three-layer contract system that separates reference documentation, implementation, and verification.
Reference Contract (animation.md)
The canonical contract resides in skills/diagram-design/references/animation.md. This file defines the four allowed motion modes (none, reveal, step, loop) and mandates specific ARIA attributes, reduced-motion fallbacks, and keyboard controls. According to SKILL.md (lines 80‑132), the routing table loads this contract only when the user explicitly requests motion or when changes in order, accumulation, or containment cannot be explained statically.
Canonical Implementation (template-motion.html)
The executable contract lives in skills/diagram-design/assets/template-motion.html. All animated diagrams must import this file verbatim, preserving its script, IDs, and data-attributes. The README explicitly states this requirement (line 281), and any deviation triggers rejection by the linter.
Automated Verification
Two scripts enforce compliance:
scripts/verify-semantic-motion.py— Validates that every mode, primitive, and contract term fromanimation.mdappears in the implementation.scripts/verify-motion.py— Scans generated HTML for illegal infinite animations or missing scoped attributes.
Both scripts must exit with "OK" before merging, as enforced by the CI pipeline in .github/workflows/ci.yml.
Implement the Four Sanctioned Motion Modes
The contract restricts animation to four specific modes, each with distinct accessibility implications.
Mode none (Default)
By default, diagrams render with data-motion-mode="none". No JavaScript is shipped, and the figure remains fully accessible to screen readers, print layouts, and assistive technologies.
Mode reveal
Use reveal for short ordered explanations such as policy traces or flows. Autoplay runs once on load, then the diagram stays static. The complete figure remains present in the accessibility tree; only the visual progression is animated.
Mode step
Use step for teaching scenarios or multi-step policy traces. This mode requires explicit play/pause controls with the following ARIA implementation:
- Native buttons sized ≥ 44 × 44 px with
aria-pressedfor play/pause state - A live region with
role="status"andaria-live="polite"to announce step changes - Keyboard shortcuts (
ArrowRight,ArrowLeft) defined inanimation.md(lines 85‑90)
Mode loop
Reserve loop for purely decorative tokens (e.g., a moving indicator on a flow line) that do not change semantic meaning. The prefers-reduced-motion media query automatically disables these animations.
Enforce Static-First Rendering
Every semantic node, label, connector, and status must exist in the SVG before any CSS or JavaScript executes. The static-first enhancement contract requires capturing the static frame with data-frame="static" to ensure the diagram is printable and exportable without animation artifacts (animation.md, lines 22‑24).
Configure Reduced-Motion Fallbacks
When prefers-reduced-motion: reduce is active, the CSS block in animation.md (lines 68‑74) overrides all animation and transition durations to 0.001ms. This forces:
[data-motion-item] { opacity: 1 !important; transform: none !important; }
[data-motion-decorative] { display: none !important; }
[data-motion-controls] { display: none !important; }
Users see the complete static frame instantly, satisfying WCAG 1.4.3 (Contrast) and 2.2.2 (Pause, Stop, Hide).
Integrate the Canonical Motion Controller
Import template-motion.html verbatim into animated diagrams:
<link rel="import" href="../assets/template-motion.html">
<svg width="600" height="400"
data-motion-mode="step"
data-motion-root>
<title>Policy evaluation trace</title>
<desc>Three rules evaluated in order.</desc>
<g data-motion-item data-step="1">Rule 1 …</g>
<g data-motion-item data-step="2">Rule 2 …</g>
<g data-motion-item data-step="3">Rule 3 …</g>
<!-- Controls generated by the template -->
<div data-motion-controls>
<button data-motion-action="play" aria-pressed="false">Play</button>
<button data-motion-action="pause">Pause</button>
<button data-motion-action="prev">Prev</button>
<button data-motion-action="next">Next</button>
<button data-motion-action="replay">Replay</button>
<div role="status" aria-live="polite" aria-atomic="true"></div>
</div>
</svg>
The controller automatically generates ARIA-friendly controls and implements the keyboard navigation contract.
Avoid Forbidden Animation Patterns
The contract explicitly prohibits animating layout coordinates, viewBox properties, node dimensions, or using infinite loops outside loop mode (animation.md, line 46). The verify-motion.py script parses CSS for unscoped animation-iteration-count: infinite declarations and fails the build if detected.
Verify Accessibility Compliance Locally
Before submitting changes, run both verification scripts:
# Check contract term coverage
python3 scripts/verify-semantic-motion.py
# Validate motion rules and ARIA implementation
python3 scripts/verify-motion.py path/to/your/diagram.html
Both commands must output "OK" to pass the CI pipeline.
Summary
- Isolate animation as an optional layer using the static-first contract in
skills/diagram-design/references/animation.md. - Restrict motion to four sanctioned modes (
none,reveal,step,loop) with explicit accessibility impacts and ARIA requirements. - Import the canonical controller from
template-motion.htmlverbatim to ensure keyboard navigation and control accessibility. - Implement reduced-motion fallbacks via
prefers-reduced-motionmedia queries that force immediate static rendering. - Validate all diagrams using
verify-semantic-motion.pyandverify-motion.pyto detect illegal infinite animations or missing semantic terms.
Frequently Asked Questions
What happens if I modify the motion controller instead of using template-motion.html verbatim?
Any deviation from the canonical controller triggers the verify-semantic-motion.py linter, which rejects the diagram. The README (line 281) explicitly requires verbatim import because the controller serves as the executable accessibility contract; modifications risk breaking ARIA attributes, keyboard controls, or reduced-motion fallbacks required by the specification.
How does the system handle users with vestibular disorders or reduced-motion preferences?
The CSS in animation.md detects prefers-reduced-motion: reduce and immediately sets all animation durations to 0.001ms, displaying the complete static frame without playback controls. This ensures users see fully rendered diagrams instantly, satisfying WCAG guidelines while maintaining semantic integrity.
Can I use infinite animations for loading indicators or decorative elements?
Infinite animations are permitted only within data-motion-mode="loop" for purely decorative tokens that do not alter semantic meaning. The verify-motion.py script scans for unscoped animation-iteration-count: infinite CSS rules and fails the build if found outside loop mode, preventing distracting or inaccessible motion patterns.
Which verification script checks for missing ARIA attributes in step animations?
The verify-motion.py script inspects generated HTML for proper scoping and ARIA implementation, while verify-semantic-motion.py ensures all contract terms from animation.md—including required ARIA attributes like aria-pressed and role="status"—appear in the implementation. Together they validate that step-mode controls meet accessibility standards for screen readers and keyboard navigation.
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 →