svg-creator
End-to-end procedure for creating SVG assets that render correctly across every consumer (GitHub README, slide deck, web app, mobile email, social card). Each section explains the why so you can adapt — don't follow them mechanically.
The viewBox rule (everything else hangs off this)
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 W H" width="W" height="H">
The viewBox must start with 0 0 and use the actual content
dimensions. No offsets like viewBox="120 40 660 420". No padding.
Why: padding inside an asset can't be removed downstream. It bakes
empty pixels into every usage, fights object-fit: contain, breaks
alignment in any consumer's layout, and makes the asset unreusable at
different sizes. Layout spacing belongs in the layout (CSS, README, slide
template), not in the asset.
What this means in practice: if you want a "window inside a workspace" look, the workspace is the asset — make the workspace itself the bounding box. Don't simulate "the window inside a frame" by offsetting the window inside a larger viewBox.
Workflow
1. Preflight (do this once per repo)
node scripts/preflight.mjs
Checks Node ≥ 20, that sharp is resolvable from cwd, and whether the
chrome-devtools MCP is configured. Prints fix commands and exits 1 if any
required dep is missing. Add --install (with optional --yes for
non-interactive use) to install missing deps via the repo's package
manager (auto-detects pnpm / yarn / bun / npm).
The chrome-devtools MCP is optional but recommended — it lets the agent take screenshots of the preview to verify the asset before declaring it done. Without it, fall back to opening the preview URL in a real browser.
2. Plan before drawing
Three decisions before you write any SVG:
Dimensions. Pick W and H from the actual content's bounding box, not the consumer's display size. Sensible defaults:
Use case Recommended GitHub repo banner (5:1) 1280×256Square badge / icon 96×96or128×128Window / IDE / CLI mockup 660×420Wide hero strip (16:5) 1920×400Open Graph / social card 1200×630Favicon source (downscaled) 512×512Filename. kebab-case or snake_case, lowercase, descriptive (
banner-active.svg, notBannerActive.svg). Match the consuming repo's convention.Target directory. Use whatever convention the consuming repo already follows. Common:
assets/,public/,art/,docs/img/.
3. Author the SVG
Apply the viewBox rule above. Three craft notes:
Colors — SVGs cannot read CSS variables. Hardcode hex values.
references/colors.md is a starter palette;
override per project.
Typography — pick fonts upfront. system-ui, sans-serif is safest for
cross-machine consistency. For pixel-perfect text across machines, embed a
webfont via <style>@font-face{...}</style> with a base64-encoded payload
inside the SVG.
Recipes — references/patterns.md has copy-
pasteable patterns for repo banners, badges, window chrome, terminals,
diagram nodes, arrows, and icons — including viewBox math and common
anti-patterns.
4. Lint the viewBox
node scripts/lint-viewbox.mjs path/to/asset.svg
# or recursively over a directory:
node scripts/lint-viewbox.mjs assets/
Checks: viewBox exists, is well-formed, starts with 0 0, has positive
width/height. Exits 1 with a fix hint on failure. Edit and re-run until
clean.
5. Preview in a browser (and screenshot via chrome-devtools MCP)
node scripts/preview-server.mjs path/to/asset.svg
Picks a free port from a small pool of uncommon defaults (5879, 6321,
7843, 8765, 9876, 31415, 42420, 47821, 51234, 61234),
falls back to OS-assigned if all bound. Serves an HTML page that renders
the SVG via <img src="/svg"> — the same path real consumers use, so
what you see is what you'll ship. Endpoints: /, /svg, /health. Run
in background so the agent can keep working.
If you have the chrome-devtools MCP, don't write-and-stop: navigate to the printed URL, take a screenshot, and inspect. Catching an off-by-one viewBox via screenshot is cheap; fixing it after the user notices is not.
1. node scripts/preview-server.mjs path/to/asset.svg (background)
2. chrome-devtools MCP: navigate_page → http://localhost:<port>/
3. chrome-devtools MCP: take_screenshot
4. inspect — does it look right? clipping? wrong colors? phantom whitespace?
If you don't have chrome-devtools MCP, open the URL in a real browser instead. Either way, verify visually before declaring the asset done.
6. Convert to a raster format (optional — ask the user)
Most consumers eventually need a PNG fallback (READMEs, slide decks, social cards). Don't auto-convert — ask the user whether they want a raster sibling, in which format, and at what dimensions.
node scripts/convert.mjs path/to/asset.svg
node scripts/convert.mjs path/to/asset.svg --format webp --width 800
node scripts/convert.mjs path/to/asset.svg --format jpeg --quality 85 --out preview.jpg
Defaults: PNG, sibling path, density 144 DPI for font crispness, native
SVG dimensions. Supports png, jpeg, webp, avif.
7. Confirm
Tell the user:
- Where the asset lives (
<path>/<name>.svg) - The preview URL (if the server is still running)
- Dimensions and a one-line description
- Whether a raster sibling was generated, and where
If anything in steps 4–6 failed, surface it explicitly — don't claim success when only the SVG was written.
Modifying an existing SVG
- Read the file before editing.
- Make the smallest possible edit.
- Re-run the lint.
- Re-preview (the server reads fresh on each request — no cache).
- Re-screenshot via chrome-devtools MCP if available.
Examples
The <bad> example fails the lint and renders with phantom whitespace
when consumed via <img> or object-fit: contain. Fix: shift every
child's coordinate by the offset and reset the viewBox to 0 0 660 420.
References
references/colors.md— starter palette and typography rulesreferences/patterns.md— copy-pasteable SVG recipes (banners, badges, windows, terminals, icons, arrows)
Files in this skill
SKILL.md— this filescripts/preflight.mjs— runtime dependency checkscripts/preview-server.mjs— local Node HTTP preview serverscripts/convert.mjs— sharp-based SVG → PNG / JPEG / WebP / AVIF converterscripts/lint-viewbox.mjs— viewBox lint (enforces0 0 W H)references/colors.md— color and typography starter palettereferences/patterns.md— copy-pasteable SVG recipes