svg-graphics
SVG Graphics Skill
Scalable, accessible, theme-aware visuals.
Why SVG
- Scales infinitely (retina, print)
- Text is searchable/accessible
- CSS-styleable (dark mode!)
- Small file size
- Version control friendly
Banner Template
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 300">
<!-- Background -->
<rect width="100%" height="100%" fill="#1a1a2e"/>
<!-- Title -->
<text x="50" y="100" font-size="48" fill="#fff" font-family="system-ui">
Project Name
</text>
<!-- Tagline -->
<text x="50" y="150" font-size="24" fill="#888">
One-line description
</text>
<!-- Feature pills -->
<g transform="translate(50, 200)">
<rect rx="12" width="100" height="24" fill="#4a4a6a"/>
<text x="50" y="17" text-anchor="middle" fill="#fff" font-size="12">Feature 1</text>
</g>
</svg>
Key Techniques
| Technique | Use Case |
|---|---|
viewBox |
Responsive scaling |
<defs> + <use> |
Reusable components |
<linearGradient> |
Modern backgrounds |
<clipPath> |
Shaped containers |
| CSS variables | Theme switching |
Dark/Light Mode
<style>
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a2e; }
.text { fill: #ffffff; }
}
@media (prefers-color-scheme: light) {
.bg { fill: #ffffff; }
.text { fill: #1a1a2e; }
}
</style>
Icon Guidelines
| Size | Use |
|---|---|
| 16x16 | Favicon, small UI |
| 32x32 | Tab icon, lists |
| 128x128 | App icon |
| 512x512 | Store listing |
SMIL Animation
Delayed Fade-In Pattern
Elements that should appear after load (hero text, feature pills, etc.):
<!-- Element starts invisible, fades in after delay -->
<g opacity="0">
<text x="50" y="100" font-size="48" fill="#fff">Title</text>
<animate
attributeName="opacity"
from="0" to="1"
dur="0.8s"
begin="0.5s"
fill="freeze"
/>
</g>
Key attributes:
| Attribute | Purpose | Values |
|---|---|---|
begin |
Delay before start | "0.5s", "1s", "click" |
dur |
Animation duration | "0.3s" to "2s" typical |
fill |
State after animation | "freeze" (keep end state) or "remove" (revert) |
repeatCount |
Repetitions | "1", "3", "indefinite" |
Staggered Entrance
Multiple elements appearing in sequence:
<g opacity="0">
<rect rx="12" width="100" height="24" fill="#4a4a6a"/>
<text x="50" y="17" text-anchor="middle" fill="#fff" font-size="12">Feature 1</text>
<animate attributeName="opacity" from="0" to="1" dur="0.5s" begin="0.3s" fill="freeze"/>
</g>
<g opacity="0">
<rect rx="12" width="100" height="24" fill="#4a4a6a"/>
<text x="50" y="17" text-anchor="middle" fill="#fff" font-size="12">Feature 2</text>
<animate attributeName="opacity" from="0" to="1" dur="0.5s" begin="0.6s" fill="freeze"/>
</g>
<g opacity="0">
<rect rx="12" width="100" height="24" fill="#4a4a6a"/>
<text x="50" y="17" text-anchor="middle" fill="#fff" font-size="12">Feature 3</text>
<animate attributeName="opacity" from="0" to="1" dur="0.5s" begin="0.9s" fill="freeze"/>
</g>
Pattern: Increment begin by 0.3s per element for smooth staggering.
SMIL Compatibility
| Platform | Support |
|---|---|
| Chrome/Edge | Full SMIL |
| Firefox | Full SMIL |
| Safari | Full SMIL |
| GitHub README | No animation (static render) |
| npm/PyPI README | No animation (static render) |
Rule: For README badges/banners, set initial opacity="1" as fallback — animated SVGs render as static first frame in non-animated contexts.
CSS Transform Patterns
The Nested Group Pattern
Problem: Combining position transforms (translate) with animation transforms (rotate, scale) on the same element causes conflicts — the animation resets position.
Solution: Use nested <g> groups to separate concerns:
<!-- Outer group: POSITION (static) -->
<g transform="translate(600, 150)">
<!-- Inner group: ANIMATION (dynamic) -->
<g>
<animateTransform
attributeName="transform"
type="rotate"
from="0" to="360"
dur="10s"
repeatCount="indefinite"
/>
<!-- The actual shape -->
<circle r="20" fill="#4a90d9"/>
</g>
</g>
Rule: Never mix static positioning and animated transforms on the same element. Always wrap in a positioning group.
Scale from Center
<g transform="translate(100, 100)">
<!-- transform-origin doesn't work reliably in SVG;
use translate to center, then scale -->
<g>
<animateTransform
attributeName="transform"
type="scale"
from="0.8" to="1.0"
dur="0.5s"
fill="freeze"
/>
<!-- Shape centered at origin (0,0) -->
<circle cx="0" cy="0" r="30" fill="#d3f5db"/>
</g>
</g>
Pulse Effect
<circle cx="50" cy="50" r="10" fill="#cf222e">
<animateTransform
attributeName="transform"
type="scale"
values="1;1.2;1"
dur="1.5s"
repeatCount="indefinite"
/>
</circle>
ClipPath Container Layering
The 3-Layer Pattern
For shaped containers with content and visible borders:
<defs>
<clipPath id="container-clip">
<rect x="50" y="50" width="400" height="200" rx="16"/>
</clipPath>
</defs>
<!-- Layer 1: BACKGROUND (fill behind clip) -->
<rect x="50" y="50" width="400" height="200" rx="16" fill="#f6f8fa"/>
<!-- Layer 2: CLIPPED CONTENT (stays inside shape) -->
<g clip-path="url(#container-clip)">
<!-- Content that may overflow is safely clipped -->
<image href="photo.jpg" x="50" y="50" width="400" height="200"/>
<text x="70" y="120" font-size="24" fill="#fff">Overlay Text</text>
</g>
<!-- Layer 3: BORDER OUTLINE (drawn last, on top) -->
<rect x="50" y="50" width="400" height="200" rx="16"
fill="none" stroke="#d1d9e0" stroke-width="2"/>
Draw order matters:
- Background fill (behind everything)
- Clipped content group (contained within shape)
- Border outline (on top,
fill="none")
Rounded Card Pattern
<defs>
<clipPath id="card">
<rect width="300" height="180" rx="12"/>
</clipPath>
</defs>
<g transform="translate(20, 20)">
<!-- Card background -->
<rect width="300" height="180" rx="12" fill="#ffffff"/>
<!-- Card content (clipped) -->
<g clip-path="url(#card)">
<!-- Header band -->
<rect width="300" height="48" fill="#0550ae"/>
<text x="16" y="32" fill="#fff" font-size="16" font-weight="bold">Card Title</text>
<!-- Body -->
<text x="16" y="80" fill="#1f2328" font-size="14">Card content here</text>
</g>
<!-- Card border -->
<rect width="300" height="180" rx="12" fill="none" stroke="#d1d9e0"/>
</g>
SVG Optimization
SVGO Configuration
{
"plugins": [
"preset-default",
{ "name": "removeViewBox", "active": false },
{ "name": "removeDimensions", "active": true },
{ "name": "removeTitle", "active": false }
]
}
Critical: Never remove viewBox (breaks scaling) or <title> (breaks accessibility).
Size Budget
| SVG Type | Target Size | Max |
|---|---|---|
| Icon | < 1 KB | 2 KB |
| Badge/shield | < 2 KB | 5 KB |
| Banner | < 10 KB | 25 KB |
| Complex diagram | < 25 KB | 50 KB |
Common Optimization Wins
| Technique | Savings |
|---|---|
| Remove editor metadata (Inkscape, Illustrator) | 20-50% |
| Simplify paths (reduce decimal precision) | 10-20% |
| Remove empty groups/unused defs | 5-15% |
| Convert shapes to paths | 5-10% |
| Gzip on server | 60-80% additional |
Accessibility
role="img"on decorative SVGs<title>for screen readers- Sufficient contrast (4.5:1 min)
aria-hidden="true"if decorative
Tools
| Tool | Purpose |
|---|---|
| SVGO | Optimize/minify |
| Inkscape | Visual editing |
| svg-to-png | Rasterization |
SVG for Documentation Illustrations
SVG isn't just for branding — it's the best format for polished documentation visuals that need more control than Mermaid provides.
When to Choose SVG Over Mermaid
| Scenario | Use SVG | Use Mermaid |
|---|---|---|
| Architecture overview for README | ✅ Branded, polished | ❌ Too generic |
| Internal dev docs flow | ❌ Overkill | ✅ Quick, accurate |
| Marketing / landing page | ✅ Full design control | ❌ Unbranded |
| Infographic with custom layout | ✅ Arbitrary positioning | ❌ Auto-layout only |
| Dark/light theme required | ✅ CSS media queries | ⚠️ Limited theming |
| Print / high-DPI output | ✅ Infinitely scalable | ⚠️ Rasterized at render |
Illustration Template
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 400" role="img">
<title>Architecture Overview</title>
<style>
@media (prefers-color-scheme: dark) {
.bg { fill: #1e1e1e; }
.text { fill: #d4d4d4; }
.box { fill: #2d2d2d; stroke: #444; }
.accent { fill: #0078d4; }
}
@media (prefers-color-scheme: light) {
.bg { fill: #ffffff; }
.text { fill: #1a1a1a; }
.box { fill: #f5f5f5; stroke: #ddd; }
.accent { fill: #0078d4; }
}
.label { font-family: system-ui, sans-serif; font-size: 14px; }
.title-text { font-family: system-ui, sans-serif; font-size: 20px; font-weight: 600; }
.connector { stroke-width: 2; stroke-dasharray: 4 4; }
</style>
<rect class="bg" width="100%" height="100%"/>
<!-- Title -->
<text class="title-text text" x="400" y="30" text-anchor="middle">Architecture Name</text>
<!-- Boxes with rounded corners -->
<g transform="translate(100, 60)">
<rect class="box" rx="8" width="200" height="80" stroke-width="1.5"/>
<text class="label text" x="100" y="45" text-anchor="middle">Component A</text>
</g>
<!-- Connector arrow -->
<line class="connector accent" x1="300" y1="100" x2="400" y2="100"/>
<polygon class="accent" points="400,95 410,100 400,105"/>
<g transform="translate(420, 60)">
<rect class="box" rx="8" width="200" height="80" stroke-width="1.5"/>
<text class="label text" x="100" y="45" text-anchor="middle">Component B</text>
</g>
</svg>
Key Principles for Illustrations
- Always include dark/light mode via
@media (prefers-color-scheme: ...)— GitHub renders both - Use semantic class names (
.box,.accent,.connector) not inline styles - Center with
text-anchor="middle"— more maintainable than manual x positioning - Group with
<g transform="translate()">— move entire components by adjusting one value - Keep
viewBoxratio consistent — 800×400 (2:1) for wide illustrations, 600×600 (1:1) for square
Illustrating Real-World Subjects (Animals, Objects, People)
The Snowman Problem
Problem: When asked to draw a dog, cat, person, or any real-world subject, AI defaults to stacking circles and rectangles — producing geometric snowmen with accessories instead of recognizable illustrations.
Root Cause: The model uses primitive shapes (<circle>, <rect>, <ellipse>) as building blocks. Real-world subjects have organic, asymmetric silhouettes that require <path> elements with Bezier curves.
The Snowman Test: If you remove all color, texture, and small details — does the silhouette alone identify the subject? A circle on a circle is always a snowman, no matter how many ears/tails you add.
Mandatory Rules for Subject Illustrations
| # | Rule | Why |
|---|---|---|
| 1 | Start with the silhouette — sketch the outer <path> outline FIRST |
The outline makes or breaks recognition. If the outline looks wrong, details won't fix it. |
| 2 | Use <path> with Bezier curves for ALL organic shapes |
<circle> and <ellipse> produce geometric/robotic results. Real animals have no perfect circles. |
| 3 | Pass the squint test — outline alone must be identifiable | Remove all fill colors and details. If the outline doesn't read as the subject, redo the outline. |
| 4 | Get proportions right before adding details | Head-to-body ratio, limb length, and placement matter more than eyes/nose/accessories. |
| 5 | Count limbs correctly — quadrupeds have 4 legs, birds have 2 + wings | The most common error. Don't draw 2 legs on a 4-legged animal. In side view, show at least 3 legs (near pair + 1 far). |
| 6 | Differentiate species by key anatomical features | A dog is not a cat is not a bear. See the feature table below. |
Feature Differentiation Table
What makes each animal visually distinct — the features to exaggerate:
| Animal | Key Silhouette Features | Common AI Mistakes |
|---|---|---|
| Dog | Snout/muzzle protruding from head, floppy or pointed ears (SIDE of head, not top), 4 legs, wagging tail, body longer than tall | Flat face (no snout), cat ears on top, 2 legs, perfect circle head |
| Cat | Pointed ears on TOP of head, round face, long curved whiskers, slender body, long curving tail, 4 legs with small paws | No whiskers, dog-like snout added, thick stocky body |
| Bird | Beak (triangular), wings (large relative to body), 2 thin legs, tail feathers, no arms | 4 legs, no beak, arms instead of wings |
| Fish | Streamlined oval body, tail fin, dorsal fin, NO legs | Legs added, round body (balloon), no fins |
| Person | Head on neck on shoulders, 2 arms with hands, 2 legs with feet, torso taller than wide | Snowman stack, no neck, T-pose arms |
| Horse | Long neck, elongated head with flat front, 4 long thin legs, mane, flowing tail | Dog-like proportions, short legs, round head |
| Rabbit | LONG upright ears (longer than head), round body, short front legs, large hind legs, cotton tail | Short ears (looks like a bear), same-length legs |
The Path-First Approach
Never build an animal from primitive shapes. Build from a single continuous <path> outline.
Step-by-Step: Drawing a Dog (Side View)
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300" role="img">
<title>Dog illustration</title>
<!-- Step 1: BODY OUTLINE - single path defining the entire silhouette -->
<!-- Start at chest, go along back, tail, rear leg, belly, front leg, up to chin, head, ear, back to start -->
<path d="
M 120,180
C 120,140 140,110 180,105
C 210,100 250,100 280,110
Q 300,118 310,135
L 330,115
L 320,140
Q 315,160 310,180
L 305,220
L 290,220
L 290,185
Q 260,195 220,195
L 180,220
L 165,220
L 170,185
Q 140,180 120,180
Z
" fill="#c89050" stroke="#6b4226" stroke-width="2"/>
<!-- Step 2: HEAD - overlapping path with snout protruding forward -->
<path d="
M 130,160
C 120,130 100,110 85,100
Q 70,92 60,100
C 50,110 55,130 60,140
L 65,148
Q 80,160 100,165
Q 115,168 130,160
Z
" fill="#c89050" stroke="#6b4226" stroke-width="2"/>
<!-- Step 3: SNOUT/MUZZLE - the feature that makes it a dog, not a snowman -->
<path d="
M 72,130
C 60,125 50,128 48,135
C 46,142 52,148 62,148
Q 70,145 72,138
Z
" fill="#e8c690" stroke="#6b4226" stroke-width="1.5"/>
<!-- Step 4: EAR - floppy, attached to SIDE of head (not on top!) -->
<path d="
M 100,105
C 105,85 115,75 120,80
C 125,88 118,105 110,112
Z
" fill="#a0703c" stroke="#6b4226" stroke-width="1.5"/>
<!-- Step 5: Details LAST - eye, nose, mouth -->
<circle cx="82" cy="115" r="4" fill="#2c1810"/> <!-- Eye -->
<ellipse cx="52" cy="135" rx="5" ry="4" fill="#2c1810"/> <!-- Nose -->
<path d="M 55,142 Q 62,148 68,144" fill="none" stroke="#6b4226" stroke-width="1.5"/> <!-- Mouth -->
<!-- Step 6: TAIL - curved upward, characteristic dog pose -->
<path d="M 325,120 Q 345,90 350,100 Q 348,115 330,125"
fill="#c89050" stroke="#6b4226" stroke-width="2"/>
</svg>
Why this works:
- Silhouette reads as "dog" even without color (elongated body, protruding snout, floppy ear)
- Snout is the dominant facial feature — face is NOT flat
- 4 legs visible (2 front, 2 back in side view)
- Body is longer than tall (dog proportions, not snowman proportions)
- ALL shapes use
<path>with curves — no perfect circles
Proportion Guide
For side-view quadrupeds (dog, cat, horse):
┌──────────────────────────────────────────┐
│ HEAD NECK BODY │
│ ┌───┐ ┌─┐ ┌──────────┐ │
│ ear→ │ │───│ │───│ │ ←tail │
│ │ • │ │ │ │ │ / │
│ snout→│ ▪ │ └─┘ │ │ / │
│ └───┘ │ │/ │
│ └──┬──┬──┬─┘ │
│ │ │ │ │ │
│ legs (4, not 2!) │
│ │
│ HEAD:BODY ratio ≈ 1:2.5 (dog) │
│ HEAD:BODY ratio ≈ 1:2 (cat) │
│ HEAD:BODY ratio ≈ 1:4 (horse) │
│ LEG length ≈ body height (dog, horse) │
│ LEG length ≈ 0.7× body height (cat) │
└──────────────────────────────────────────┘
Color Guidelines for Illustrated Subjects
| Subject | Natural Palette | Avoid |
|---|---|---|
| Dog | Browns (#c89050, #a0703c, #6b4226), Golden (#e8c690), Black, White, Gray | Green, blue, purple (unnatural) |
| Cat | Gray (#8e8e8e), Orange (#d68c45), Black, White, Siamese (#c4a882) | Bright green, neon colors |
| Bird | Species-specific; blue (#4a90d9), red (#cf4040), yellow (#e6b422), green (#5ab05a) | All one color (usually multi-toned) |
| Person | Skin tones, clothing colors | Geometric shapes for body parts |
| Tree | Green canopy (#4a8c3f, #6aad5a), brown trunk (#6b4226, #8b6914) | Blue leaves, gray trunk |
Rule: Use realistic base colors unless the user specifically requests a stylized/cartoon palette.
Common Failure Modes
| Failure | Cause | Fix |
|---|---|---|
| "Snowman with ears" | Using stacked circles for body | Use one continuous <path> for body outline |
| "Cat ears on everything" | Triangles placed on top of circular head | Place ears on SIDE of head (dogs), check species table |
| "Floating face" | Features placed on a perfect circle with no jaw/chin structure | Give head a distinct shape — snout, jawline, not a circle |
| "Stick figure animal" | Rectangles for legs attached to circles | Legs should taper, connect to body organically with curves |
| "2-legged quadruped" | Forgetting rear or front leg pair | Always count: is this animal 2-legged or 4-legged? |
| "Psychedelic colors" | Using brand/branding palette instead of natural colors | Real animals have earthy, natural tones — check color table |
| "Giant head, tiny body" | No proportion reference | Check proportion guide — head is usually smaller than body |
Workflow for Subject Illustrations
- Identify — What species/object? What view? (side/front/3-quarter)
- Reference proportions — Check the proportion guide and feature table
- Draw silhouette — Single
<path>for body outline. Apply squint test. - Add major features — Head shape, ears at correct position, limbs (count them!)
- Add details last — Eyes, nose, mouth, texture, color
- Squint test — Remove all color. Is the silhouette recognizable?
Synapses
See synapses.json for connections.