Practical SVG - sgml/signature GitHub Wiki

Tools

Comparison

Cross-Platform SVG Tools with Spec Coverage, Limitations, and Release Notes

This table compares tools that support SVG import/export across Windows, macOS, Linux, Android, iOS, and web. It includes license type, estimated SVG spec coverage, limitations, GitHub links, and SVG-related release notes.

Tool License Type Platforms Supported SVG Import (%) SVG Export (%) Import Limitations Export Limitations GitHub URL SVG Release Notes URL
Figma Commercial SaaS Windows, macOS, Linux, Android, iOS, Web 75 70 No animation; filters stripped; external fonts/images ignored Text may be outlined; no animation; effects flattened; no embedded fonts N/A https://www.figma.com/blog/with-figmas-new-svg-exports-less-more/
Miro Commercial SaaS Windows, macOS, Linux, Android, iOS, Web 60 55 SVGs are flattened; no animation; no layer hierarchy Export only via frames; text not editable; no interactivity or animation N/A https://miro.com/whats-new/
Inkscape Open Source (GPL) Windows, macOS, Linux 95 90 Some CSS styles may not render identically; large SVGs may load slowly Filters may rasterize; export precision depends on DPI and text settings https://github.com/inkscape/inkscape https://inkscape.org/doc/release_notes/1.4.2/Inkscape_1.4.2.html
Penpot Open Source (AGPL) Web (all platforms) 80 75 No animation; limited support for advanced filters or embedded fonts No animation; export may flatten effects or simplify paths https://github.com/penpot/penpot https://community.penpot.app/t/penpot-2-9-the-wizard/9614
Boxy SVG Commercial + OSS Windows, macOS, Linux, Web 85 80 No scripting or animation; some filters unsupported No animation; export may simplify complex filters or blend modes https://github.com/boxy-svg/boxy-svg https://boxy-svg.com/blog/21/boxy-svg-4-released
SVG-Edit Open Source (MIT) Web (all platforms) 65 60 Limited to basic shapes and paths; no animation or scripting No layering; no animation; limited export fidelity for complex SVGs https://github.com/SVG-Edit/svgedit https://github.com/SVG-Edit/svgedit/releases
Draw.io Open Source (Apache 2.0) Windows, macOS, Linux, Web 70 65 Imports as diagram elements, not raw SVG layers Exports diagrams as SVG; not ideal for complex vector art https://github.com/jgraph/drawio https://github.com/jgraph/drawio/blob/dev/ChangeLog

Documentation

Import/Export

Figma

Import SVG
  • Open Figma (desktop or web)
    • Create or open a file
    • Drag and drop .svg onto canvas
    • Or:
      • Go to "File > Place Image"
      • Select SVG file and click "Open"
  • Optional:
    • Paste SVG code via "Edit > Paste"
Export SVG
  • Select object, group, or frame
    • Go to right-hand "Design panel"
    • Scroll to "Export" section
    • Click "+" to add export setting
    • Choose "SVG" format
    • Click "Export [Object Name]"
  • Optional:
    • Batch export by selecting multiple items with Shift

Miro

Import SVG
  • Open a Miro board
    • Drag and drop .svg onto canvas
    • Or:
      • Click "Upload" (paperclip icon in left toolbar)
      • Select SVG file and click "Open"
Export SVG
  • Select a frame or board region
    • Click "three-dot menu" in top-right of frame
    • Choose "Export as image"
    • Select "SVG" format
    • Click "Export"

Documentation Links

Wireframe-Only Video Games (1986–1996)

Grouped by release year. No polygonal fill, no texture mapping, no full 3D engines.

Title Year Platforms MS-DOS Port Emulator Developer Publisher Programmer(s)
Elite 1986 C64, BBC Micro, Apple II Yes (DOSBox, VICE) David Braben, Ian Bell Acornsoft, Firebird David Braben, Ian Bell
Mercenary 1986 C64, Atari 8-bit Yes (VICE, Altirra) Novagen Software Novagen Software Paul Woakes
Cholo 1986 C64, ZX Spectrum No (VICE, Fuse) Solid Image Ltd Firebird Glyn Williams
Starglider 1986 Amiga, Atari ST Yes (FS-UAE, Hatari) Argonaut Software Rainbird Jez San
Sentinel 1986 C64, ZX Spectrum No (VICE, Fuse) Geoff Crammond Firebird Geoff Crammond
Driller 1987 C64, Amiga, Atari ST Yes (VICE, FS-UAE) Major Developments Incentive Software Chris Andrew, Ian Andrew
Stellar 7 1987 C64, DOS Yes (DOSBox, VICE) Damon Slye Penguin Software Damon Slye
Dark Side 1988 C64, Amiga, Atari ST Yes (VICE, FS-UAE) Major Developments Incentive Software Chris Andrew, Ian Andrew
Total Eclipse 1988 C64, Amiga, Atari ST Yes (VICE, FS-UAE) Major Developments Incentive Software Chris Andrew, Ian Andrew
Battle Command 1990 Amiga, Atari ST Yes (FS-UAE, Hatari) Realtime Games Ocean Software Realtime team
Hunter 1991 Amiga, Atari ST No (FS-UAE, Hatari) Activision Activision Paul Holmes
Tempest 1981/1994 Arcade, Jaguar No (MAME, A7800) Atari Inc Atari Dave Theurer
Battlezone 1980/1986 Arcade, DOS Yes (MAME, DOSBox) Atari Inc Atari Ed Rotberg

Editors

Comparison

title = "Open-source timeline+code vector animation tools (cross-platform) — SVG import/export only"
date = "2025-11-02"

[[tool]]
name = "Glaxnimate"
timeline_ui = true
scripting = "Expression-like parameters; JSON import/export"
platforms = "Linux; macOS; Windows"
license = "GPL"
github = "https://github.com/mbasaglia/glaxnimate"
site = "https://glaxnimate.org"
notes = "Vector-first timeline and layer editor; imports and exports SVG and Lottie/JSON; designed for programmatic workflows."
llm_notes = """
- Author prompts that produce SVGs structured for Glaxnimate: named layers, grouped vector parts, and anchor points positioned for rigging.
- Emit JSON/Lottie-aware vector generation guidance so exported SVGs convert to keyframeable shapes and paths without manual rework.
- Produce expression snippets or parameter maps for procedural motion (e.g., pathOffset, trim, morphable shapes) that Glaxnimate can interpret.
- Create batch import scripts to map external SVG layer names into Glaxnimate layer IDs and apply initial keyframes.
"""

[[tool]]
name = "Wick Editor"
timeline_ui = true
scripting = "JavaScript (in-editor)"
platforms = "Linux; macOS; Windows"
license = "MIT"
github = "https://github.com/Wicklets/wick-editor"
site = "https://www.wickeditor.com"
notes = "Browser-first editor with desktop/Electron builds; supports vector drawing and a timeline with inline JS; supports importing and exporting SVG assets for timeline-driven vector animation."
llm_notes = """
- Generate clean SVG vectors from prompts that target animation-friendly topology (separate closed paths for fill regions; simple stroke outlines).
- Produce SVG layer hierarchy and element IDs that map directly to timeline symbols and object instances.
- Create JS snippets that wire SVG elements to timeline events, symbol swaps, and parameterized transforms.
- Emit automated path simplification rules (tolerance, preserveCorners) and node reduction commands to reduce keyframe complexity.
- Generate Lint/QA checks for SVGs (missing viewBox, non-decimal transforms, embedded raster data) before import.
"""

[[tool]]
name = "Synfig Studio"
timeline_ui = true
scripting = "Python (extensions, batch processing)"
platforms = "Linux; macOS; Windows"
license = "GPL"
github = "https://github.com/synfig/synfig"
site = "https://www.synfig.org"
notes = "Vector tweening engine with timeline/keyframe workflow and parametric vector objects; supports importing SVGs and working with vector parts for animation workflows."
llm_notes = """
- Generate decomposed vector part plans from character prompts (head/torso/limbs/controls) with anchor placement optimized for Synfig bones and switches.
- Autogenerate Synfig .sif scene templates with prewired layers, parameters, and named bones ready for procedural animation.
- Produce Python scripts to retime vector parameters, bake motion from high-level easing descriptions, and convert AI SVGs into Synfig layer groups.
- Recommend path interpolation strategies (compatible with Synfig's spline handling) and vector clean-up rules to avoid undesirable tween artefacts.
"""

Animation

Example

<svg width="200" height="400" xmlns="http://www.w3.org/2000/svg">
  <!-- Head -->
  <circle cx="100" cy="50" r="30" stroke="black" stroke-width="2" fill="none" />

  <!-- Body -->
  <line x1="100" y1="80" x2="100" y2="200" stroke="black" stroke-width="2" />

  <!-- Left Arm -->
  <line x1="100" y1="120" x2="60" y2="150" stroke="black" stroke-width="2" />

  <!-- Right Arm (Animated) -->
  <line x1="100" y1="120" x2="140" y2="150" stroke="black" stroke-width="2">
    <animateTransform
      attributeName="transform"
      attributeType="XML"
      type="rotate"
      from="270 100 120"
      to="-30 100 120"
      dur="1s"
      repeatCount="indefinite"
      begin="0s"
      fill="freeze"
    />
  </line>

  <!-- Left Leg -->
  <line x1="100" y1="200" x2="70" y2="300" stroke="black" stroke-width="2" />

  <!-- Right Leg -->
  <line x1="100" y1="200" x2="130" y2="300" stroke="black" stroke-width="2" />
</svg>

References

Programmatic Vector Art

Namespace Idioms

References

Sample Code

<svg width="200" height="400" xmlns="http://www.w3.org/2000/svg">
  <!-- Head -->
  <circle cx="100" cy="50" r="20" stroke="black" stroke-width="2" fill="none" />
  
  <!-- Body -->
  <line x1="100" y1="70" x2="100" y2="150" stroke="black" stroke-width="2" />
  
  <!-- Arms -->
  <line x1="100" y1="90" x2="60" y2="120" stroke="black" stroke-width="2" />
  <line x1="100" y1="90" x2="140" y2="120" stroke="black" stroke-width="2" />
  
  <!-- Legs -->
  <line x1="100" y1="150" x2="70" y2="200" stroke="black" stroke-width="2" />
  <line x1="100" y1="150" x2="130" y2="200" stroke="black" stroke-width="2" />
</svg>

Form Validation

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>SVG Text Validation with handleEvent</title>
  <style>
    body {
      font-family: sans-serif;
    }
    svg {
      border: 1px solid #ccc;
      display: block;
      margin: 20px auto;
    }
  </style>
</head>
<body>
  <svg width="500" height="200">
    <!-- Draw a border rectangle -->
    <rect x="10" y="10" width="480" height="180" fill="none" stroke="#000" />
    
    <!-- Editable text element -->
    <text id="editableText" x="20" y="50" font-size="20" fill="black">
      Click to edit me
    </text>

    <!-- Validation message text element (hidden by default) -->
    <text id="validationMsg" x="20" y="100" font-size="16" fill="red" visibility="hidden"></text>
  </svg>

  <script>
    // Get references to SVG elements.
    const textElement = document.getElementById('editableText');
    const validationMsg = document.getElementById('validationMsg');
    
    // The text node contained in <text>. (Assuming a single direct text node.)
    const textNode = textElement.firstChild;

    // Create an event handler object that implements handleEvent.
    const validationHandler = {
      handleEvent: function(event) {
        // Retrieve the updated text.
        const newText = textNode.nodeValue;

        // Validation: input text must be at least 5 characters long.
        if (newText.length < 5) {
          textElement.setAttribute('fill', 'red');
          validationMsg.textContent = 'Text must be at least 5 characters long.';
          validationMsg.setAttribute('visibility', 'visible');
        } else {
          textElement.setAttribute('fill', 'green');
          validationMsg.textContent = '';
          validationMsg.setAttribute('visibility', 'hidden');
        }
      }
    };

    // Attach the event handler to the text node for DOMCharacterDataModified.
    // Note: Although DOM mutation events are deprecated in favor of MutationObserver,
    // we use them here per your request.
    textNode.addEventListener('DOMCharacterDataModified', validationHandler, false);

    // Set up a click event to simulate text editing.
    textElement.addEventListener('click', function() {
      // Prompt the user for new text.
      const newText = prompt('Edit the text:', textNode.nodeValue);
      if (newText !== null) {
        // Directly update the text node; this change will trigger the mutation event.
        textNode.nodeValue = newText;
      }
    });
  </script>
</body>
</html>

SVG Scaling Stylesheet

To multiply or divide all dimensions by a variable, use this stylesheet

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- Parameter: scale factor -->
  <xsl:param name="scale" select="3"/>

  <!-- Identity transform: copy everything by default -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- Scale numeric attributes -->
  <xsl:template match="@x|@y|@width|@height|@font-size|@stroke-width|
                       @markerWidth|@markerHeight|@refX|@refY|
                       @x1|@y1|@x2|@y2">
    <xsl:attribute name="{name()}">
      <xsl:value-of select="number(.) * $scale"/>
    </xsl:attribute>
  </xsl:template>

</xsl:stylesheet>
⚠️ **GitHub.com Fallback** ⚠️