Svg creator
Personal monorepo of agent skills (SKILL.md format) — agent-agnostic, works with Claude Code, Cursor, Codex, and others.
npx -y skills add zrosenbauer/skills --skill svg-creatorAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
This skill should be used when the user wants to create, fix, or convert SVG assets in any project — banners, badges, icons, logos, window/IDE mockups, terminal screenshots, or diagram nodes. Common triggers include "create an SVG", "make a banner", "design an icon", "draw a logo", "fix the viewBox", "convert SVG to PNG", and "preview this SVG". Bakes in edge-to-edge viewBox discipline (`viewBox="0 0 W H"` — no padding, no offsets), hardcoded hex colors (SVG cannot read CSS variables), a Node- based local preview server for browser + chrome-devtools MCP screenshot verification, and sharp-based conversion to PNG / JPEG / WebP / AVIF. Skip when the asset is purely raster (no SVG source) or when only an existing PNG needs editing.
SKILL.md
9.2 KB, as published. Nobody here has run it
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×512 -
Filename. 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
<example> <input> "make me a github readme banner for my project 'TaskForge' — 1280x256, dark theme with purple gradient" </input> <output> 1. Plan: 1280×256, file `banner-taskforge.svg`, target `assets/`. 2. Author with `viewBox="0 0 1280 256"`, full-bleed gradient `<rect width="1280" height="256" fill="url(#bg)">`, hardcoded hex stops `#7268F0` → `#B667EF`, hardcoded font `Geist, system-ui, sans-serif`. (See `references/patterns.md` → "GitHub repo banner".) 3. `node scripts/lint-viewbox.mjs assets/banner-taskforge.svg` → ✓ pass. 4. `node scripts/preview-server.mjs assets/banner-taskforge.svg &` → http://localhost:5879/ 5. chrome-devtools MCP: `navigate_page` then `take_screenshot` — confirm gradient covers full bounds, text doesn't clip. 6. Ask user: "Want a PNG sibling for non-SVG-aware consumers?" If yes: `node scripts/convert.mjs assets/banner-taskforge.svg`. 7. Confirm: "asset at `assets/banner-taskforge.svg`, preview at http://localhost:5879/, 1280×256." </output> </example> <example> <good> ```svg <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 660 420" width="660" height="420"> <rect width="660" height="420" rx="10" fill="#1A1A1A"/> <!-- content positioned from origin --> </svg> ``` </good> <bad> ```svg <svg xmlns="http://www.w3.org/2000/svg" viewBox="120 40 660 420" width="660" height="420"> <rect x="120" y="40" width="660" height="420" rx="10" fill="#1A1A1A"/> <!-- content offset by 120/40 — bakes phantom padding into the asset --> </svg> ``` </bad>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.
</example>
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