| name | svg-export |
| description | Finalize a rendered SVG for production: run SVGO optimization, add
accessibility metadata (<title>, <desc>), verify viewBox sanity, and
copy to a user-specified destination. Use when the user says "ship it",
"optimize and export", "make it production-ready", "minify this SVG",
"copy the final SVG to <path>", "export <slug> for the website", or
asks for the byte-size after optimization. Always run after /svg-animate
produces a passing verdict and before the SVG is committed or shared.
|
| allowed-tools | Read, Write, Bash(npx svgo*), Bash(node*), Bash(Copy-Item*), Bash(cp*) |
| argument-hint | <preset-slug> [--out=<path>] |
You finalize an SVG that's already been rendered and visually verified.
You're the last step before the file leaves the repo. Your job: make it
small, accessible, and well-named.
What was passed in
$ARGUMENTS[0] is the preset slug (must exist in output/).
$ARGUMENTS[1..N] may include --out=<path> to copy the final file
somewhere outside output/.
If no slug, return:
usage: /svg-export <preset-slug> [--out=<path>]
If output/<slug>.svg doesn't exist, ask the caller to run
/svg-animate (or node lib/render-cli.js <slug>) first.
Step 1 — Verify the source
Read output/<slug>.svg. Sanity-check:
- Contains
<svg opening tag and </svg> closing tag.
- Has a
viewBox attribute (otherwise scaling is broken).
- Has a
<title> element (presets emit it via composeSVG's title opt).
If missing, fall back to the slug. Log a warning — presets should set
title and desc explicitly.
If structural checks fail, return:
EXPORT FAILED:
Source: output/.svg
Re-render via /svg-animate or node lib/render-cli.js <slug>.
Step 2 — Optimize with SVGO
The repo ships an animation-safe svgo.config.mjs at its root, which SVGO
picks up automatically. Just point at input + output:
npx svgo -i output/<slug>.svg -o output/<slug>.min.svg
DO NOT pass --enable/--disable (those are SVGO v2; this repo runs v3, where
they're config-only) and DO NOT run stock preset-default. Stock SVGO is built
for static icons and silently breaks animations: it collapses the group
nesting that carries animation transforms (relocating transform-box: fill-box
origins — e.g. a blink's eyes jump to the corner), minifies <style> (dropping
@keyframes), and converts shape elements that are animation targets. The repo
config disables exactly those plugins while still compressing path data. See
docs/embedding-animated-svg.md.
Capture before/after sizes. Typical savings: 35–40% on an animated preset. If
savings are < 5%, the file is already small — that's fine, not a problem.
Always re-verify the minified file animates (Step 3) — a size win that
broke the motion is a regression, not an optimization.
Step 3 — Verify minified file still composes AND animates
Parse check — the file must contain <svg and </svg> and be non-empty.
For an animated source, ALSO confirm the motion survived:
- The
<style> block and every @keyframes still present (grep count matches
the source). A 0 here means SVGO dropped the animation.
- If the source has
transform-box, it's still there.
- Ideally, render the minified file as an
<img> (see svg-verify's <img>
step) and confirm it still moves — not just that it parses.
If any check fails, abort and keep the unminified version as authoritative:
WARNING: SVGO altered the animation (e.g. @keyframes dropped / blink detached).
Keeping output/<slug>.svg as final. Check svgo.config.mjs is being applied.
Step 4 — Copy to destination (if requested)
If --out=<path> was passed:
- If the path ends in
.svg, copy output/<slug>.min.svg there.
- If the path is a directory, copy as
<dir>/<slug>.svg (NOT .min.svg
— users want a clean filename at the destination).
- Create parent directories if missing.
- Refuse to overwrite without explicit acknowledgement (
--force).
Step 5 — Report
EXPORTED: <slug>
Source: output/<slug>.svg (<bytes> bytes)
Minified: output/<slug>.min.svg (<bytes> bytes, <pct>% saved)
Destination: <path or "stayed in output/">
Accessibility: title="..." desc="..."
ViewBox: "<viewBox>"
Keep it under 8 lines. The caller will share this with the user.
Anti-patterns
- ❌ Stripping
viewBox, <title>, or <desc>. They're tiny and critical
for accessibility / responsive scaling. SVGO's default removeViewBox
preset would strip viewBox; we disable it.
- ❌ Overwriting an existing destination file without a
--force flag.
Users have lost work to that.
- ❌ Running SVGO on a file we're not sure about. Always do Step 1's
structural check first.
- ❌ Forgetting to copy to
--out= when the user asked. The whole point
of this skill is shipping the file to where they want it.