How to Export Motion-Enabled HTML Diagrams in a Static State

Appending ?motion=static to the diagram URL freezes the animation before rasterization, ensuring the exported SVG or PNG contains all semantic elements while hiding motion controls.

The cathrynlavery/diagram-design repository treats diagrams as self-contained HTML files that may include optional motion controllers. When you need to export motion-enabled HTML diagrams in a static state for slides, Figma, or documentation, the repository enforces a strict contract that guarantees pixel-perfect fidelity and accessibility compliance.

Understanding the Motion Controller Architecture

Motion-enabled diagrams in this system rely on declarative attributes rather than imperative JavaScript playback.

The Template Structure

Every motion diagram starts from skills/diagram-design/assets/template-motion.html. This canonical controller must be copied verbatim into any diagram requiring animation support. The template establishes the root element with data-motion-mode attributes that define temporal behavior.

Motion Modes and Data Attributes

The Animation reference at skills/diagram-design/references/animation.md defines three motion modes:

  • step: Advance through states via discrete increments
  • reveal: Progressive disclosure of diagram layers
  • loop: Continuous cyclic animation

To freeze these animations for static export, the system asserts that the motion root carries data-frame="static" after loading the URL with ?motion=static. This attribute signals that all semantic elements are visible while decorative motion curves and control chrome are hidden.

Exporting Static SVG from Motion-Enabled HTML

The SVG export procedure follows the contract outlined in skills/diagram-design/references/export.md:

  1. Extract the first <svg> element using a multiline regex, deliberately dropping surrounding editorial markup (cards, headers, navigation)
  2. Ensure standalone XML compliance by injecting xmlns="http://www.w3.org/2000/svg" and preserving the original viewBox
  3. Maintain accessibility metadata by keeping <title> and <desc> elements
  4. Inject a <defs><style> block that imports Google Fonts with XML-escaped entities (&amp; instead of &)
  5. Prepend the XML declaration <?xml version="1.0" encoding="UTF-8"?>
  6. Write the output adjacent to the source (diagram.html → diagram.svg)

This extraction targets only the diagram itself, ensuring clean reusability across design tools.

Generating Static PNG with Playwright

For raster output, the exporter renders the original HTML rather than the extracted SVG to preserve exact font loading and CSS inheritance:

from playwright.sync_api import sync_playwright
import sys, pathlib

src, out = sys.argv[1], sys.argv[2]
scale = int(sys.argv[3]) if len(sys.argv) > 3 else 2

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(device_scale_factor=scale)
    page.goto(f"file://{pathlib.Path(src).resolve()}?motion=static")
    page.wait_for_load_state("networkidle")
    page.locator("svg").first.screenshot(path=out, omit_background=True)
    browser.close()

Key implementation details:

  • The ?motion=static query parameter triggers the static frame mode before document.fonts.ready resolves
  • omit_background=True ensures transparent backgrounds for overlay use
  • device_scale_factor supports --scale=1|2|3 for 1x, 2x, or 3x resolution outputs

Command-Line Interface

Invoke the export workflow via the slash command defined in commands/export-diagram.md:


# Export both SVG and PNG (default behavior)

/diagram-design:export-diagram path/to/diagram.html

# Export only SVG

/diagram-design:export-diagram path/to/diagram.html --svg-only

# Export high-resolution PNG only

/diagram-design:export-diagram path/to/diagram.html --png-only --scale=3

# Generate registry sidecar metadata

/diagram-design:export-diagram path/to/diagram.html --registry

The command validates prerequisites before execution. For PNG generation, it verifies Playwright installation and surfaces exact install instructions if missing (pip install playwright followed by playwright install chromium).

Verification and Quality Assurance

Before exporting motion-enabled diagrams, run the verification script to ensure static compliance:

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

This script checks that:

  • The data-motion-mode attribute exists on the root element
  • Loading ?motion=static correctly sets data-frame="static"
  • The reduced-motion fallback is properly declared

The verification guarantees that exported artifacts match the repository's accessible-SVG contract, preventing animated states from leaking into documentation assets.

Edge Cases and Constraints

The exporter refuses to process files that violate these constraints:

  • Gallery files: assets/index.html contains multiple diagrams and is explicitly excluded
  • Missing SVG blocks: Files lacking an <svg> element trigger an error
  • Registry-only exports without IDs: Requests for --registry require data-block-id attributes on diagram elements to generate valid metadata sidecars

Summary

  • Append ?motion=static to freeze animations and assert data-frame="static" before capture
  • SVG extraction isolates the first <svg> block, injects XML namespaces, and preserves Google Fonts with escaped entities
  • PNG rasterization uses Playwright with device_scale_factor scaling and omit_background=True for transparency
  • Run scripts/verify-motion.py to validate static compliance before batch exports
  • The export workflow is defined in skills/diagram-design/references/export.md and commands/export-diagram.md

Frequently Asked Questions

How does the exporter handle fonts in static SVG output?

The extractor parses the HTML's Google Fonts imports and injects them into a <defs><style> block within the SVG, ensuring text renders correctly even offline. Ampersands in font URLs are XML-escaped to &amp; to prevent parsing errors.

Why does PNG export load the HTML instead of the extracted SVG?

Rendering the original HTML guarantees that @font-face declarations and CSS custom properties resolve exactly as the author intended. This method waits for document.fonts.ready and networkidle, ensuring pixel-perfect fidelity that direct SVG rasterization might miss due to missing font contexts.

What motion modes support static export?

The step, reveal, and loop modes defined in skills/diagram-design/references/animation.md all support static export. When ?motion=static is present, the motion controller collapses temporal states into a single comprehensive frame marked by data-frame="static".

No. The exporter explicitly refuses to operate on assets/index.html or any file containing multiple diagram roots. You must target individual HTML files containing single <svg> elements to ensure clean, isolated static assets.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →