How PNG and SVG Exports Handle Sizing, Scaling, and Static Capture in Diagram Design
SVG exports preserve the original viewBox dimensions exactly as vector, while PNG exports rasterize the same diagram using Playwright with a configurable device scale factor (default 2×) for pixel-perfect control.
The cathrynlavery/diagram-design repository provides a sophisticated export pipeline that converts generated diagram HTML into production-ready SVG and PNG formats. Understanding how each format handles sizing, scaling, and static capture is essential for integrating diagrams into documentation, presentations, and web applications.
SVG Export: Vector-First Preservation
The SVG export path in skills/diagram-design/references/export.md prioritizes fidelity and accessibility over manipulation.
Extraction and Isolation
The exporter parses the source HTML and extracts the first <svg> element it encounters:
# Conceptual flow from export.md#L29-L33
svg_element = html.find_first("svg") # Extraction point
Most diagram outputs contain a single SVG, making this approach reliable. The exporter aborts with a clear error message if no SVG is found.
Self-Contained SVG Construction
The raw SVG is transformed into a standalone document through several normalization steps:
xmlnsdeclaration — Ensuresxmlns="http://www.w3.org/2000/svg"is present for XML compliance- Original
viewBoxpreservation — No transformation or scaling applied - Accessibility metadata — Retains
role="img",aria-labelledby,<title>, and<desc>elements unchanged
Font Embedding for Portability
Google Fonts referenced in the original HTML are injected via @import inside a <defs><style> block:
<defs>
<style>
@import url('https://fonts.googleapis.com/css2?family=...&display=swap');
</style>
</defs>
Note the XML-escaped ampersands (&) — required because SVGs are parsed as strict XML, not HTML.
Final Output Format
An XML declaration is prepended to guarantee well-formedness:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Standalone SVG follows -->
Sizing Behavior
The SVG's dimensions are determined exclusively by its viewBox, which is set by the Size dial defined in output-spec.md. Common presets include:
| Preset | viewBox |
|---|---|
doc-inline |
0 0 960 600 |
slide-full |
0 0 1920 1080 |
No additional scaling occurs. The SVG displays at any size without quality loss because it remains vector-based.
PNG Export: Rasterization with Scale Control
The PNG export path uses browser-based rendering to ensure font fidelity and accurate CSS application.
Rendering Architecture
Unlike SVG export, PNG generation renders the complete HTML document (not the extracted SVG) and screenshots the SVG element's bounding box:
# From export.md#L74-L89 — Playwright rasterization
page = playwright.firefox.launch().new_page()
page.goto(f"file://{input_path}")
page.wait_for_load_state("networkidle")
svg_element = page.locator("svg").first
svg_element.screenshot(path=output_path, omit_background=True)
This approach guarantees that:
- Fonts load via
<link>tags in the HTML<head> - CSS animations complete before capture
- The visual output matches browser rendering exactly
Scale Factor and Pixel Dimensions
PNG dimensions are calculated as:
width_px = viewBox_width × device_scale_factor
height_px = viewBox_height × device_scale_factor
The default device scale factor is 2, producing crisp output suitable for high-DPI displays. Users control this via the --scale parameter:
# Default: scale 2 (2× pixel density)
/export-diagram diagram.html --png-only
# Higher resolution for print or large displays
/export-diagram diagram.html --png-only --scale=3
# Smaller file size for web thumbnails
/export-diagram diagram.html --png-only --scale=1
Per commands/export-diagram.md, allowed values are strictly 1, 2, or 3 — the command rejects other inputs.
Transparent Background Support
The omit_background=True parameter yields PNGs with transparent canvases, eliminating the white halo effect when placing diagrams on colored backgrounds or image overlays.
Static Capture for Animated Diagrams
When diagrams include motion (query parameter ?motion=static), the export pipeline performs additional synchronization:
# From export.md#L60-L63 — Static frame guarantee
page.goto(f"file://{input_path}?motion=static")
page.wait_for_function("document.fonts.ready")
page.wait_for_selector("[data-frame='static']")
This sequence ensures:
- Animation is frozen at a static frame
- All web fonts are fully loaded and rendered
- The
data-frame="static"attribute confirms readiness before screenshot
Format Comparison: Sizing and Scaling
| Aspect | SVG Export | PNG Export |
|---|---|---|
| Size basis | Original viewBox from output-spec.md presets |
viewBox × device_scale_factor |
| Scaling control | None — scales infinitely as vector | --scale=1|2|3 (default 2) |
| File type | XML-based vector | Raster bitmap |
| Background | Transparent by default | Transparent (omit_background=True) |
| Font handling | Inlined via @import in <defs> |
Rendered by browser, fonts loaded via HTML |
| Accessibility | Preserves aria-*, <title>, <desc> |
Must be added via surrounding document |
Edge Cases and Validation Guardrails
The export system includes defensive checks per skills/diagram-design/references/export.md:
- Gallery files (
assets/index.html) — Export refuses when multiple SVGs are detected, requiring explicit single-diagram selection - Missing Playwright — Surfaces exact installation command rather than auto-installing:
pip install playwright && playwright install firefox - Scale validation — Rejects
--scalevalues outside 1-3 range with clear error messaging
Command Reference
Complete examples for common export scenarios:
# Both formats, default settings
/export-diagram path/to/diagram.html
# SVG only — smallest file, infinitely scalable
/export-diagram path/to/diagram.html --svg-only
# High-resolution PNG for print (scale 3)
/export-diagram path/to/diagram.html --png-only --scale=3 --output=print-ready.png
# Quick web thumbnail (scale 1)
/export-diagram path/to/diagram.html --png-only --scale=1 --output=thumb.png
Summary
- SVG exports extract and sanitize the first
<svg>element, preserving exactviewBoxdimensions with embedded fonts for standalone use - PNG exports use Playwright to rasterize the full HTML document, applying a configurable scale factor (1-3×) to control pixel density
- Static capture for animated diagrams uses
?motion=staticwith font readiness verification - Transparent backgrounds are default for both formats, with PNG using
omit_background=True - Validation guardrails prevent ambiguous exports and surface clear error messages for missing dependencies
Frequently Asked Questions
Why does PNG export render the full HTML instead of the extracted SVG?
PNG export renders the complete HTML document to ensure font loading works correctly. Fonts referenced via <link> tags in the HTML <head> must be parsed and loaded by a browser engine — extracting only the SVG would break this chain. Playwright's svg.first.screenshot() then isolates just the diagram's bounding box.
Can I export a PNG at arbitrary scale factors like 1.5× or 4×?
No. The export-diagram command enforces scale values of 1, 2, or 3 only per commands/export-diagram.md. This constraint prevents unexpected file sizes and ensures predictable output quality. For non-standard dimensions, export SVG and rasterize externally.
How do I verify my animated diagram will export as a static PNG correctly?
Include ?motion=static in your workflow. The export pipeline automatically appends this query, waits for document.fonts.ready, and verifies data-frame="static" exists before capturing. You can test this locally by adding the parameter to your diagram URL and confirming motion freezes.
What happens if my diagram HTML contains multiple SVG elements?
The export command rejects gallery files (assets/index.html) and exits with an error requesting a single-diagram file. This prevents ambiguity about which diagram to export. Split multi-diagram pages into individual HTML files before export.
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 →