Files
g4borg 61af13521c 🤖 Restructure SVG skill: extract references, add legibility rules
Extract inline SVG rules to references/inline-svg.md for progressive
disclosure. Add references/layout-legibility.md with 7 rules for
readable SVG output (text sizing, contrast, margins, chart patterns,
palettes) based on concrete failure modes from issue #4.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-19 20:46:12 +02:00

78 lines
5.9 KiB
Markdown

---
name: markdown-embedded-svg
description: Use when authoring or editing a Markdown file that contains (or should contain) SVG diagrams, charts, or any graphical representation. Trigger whenever (1) writing a report/document/README in Markdown that needs a diagram, flowchart, chart, or other visual, (2) considering adding `<svg>` markup to a `.md` file, (3) editing existing SVG inside Markdown, (4) a user asks for a "diagram", "visual", "chart", or "flowchart" inside a Markdown document. Markdown renderers (GitHub, Gitea, Obsidian, VS Code preview) sanitize inline SVG very differently from each other — GitHub strips it entirely, Gitea allows only `<svg>` + `<path>`, Obsidian (via DOMPurify) allows most of it. Apply this skill proactively before producing the SVG, not after.
---
# SVG in Markdown
Markdown renderers diverge dramatically on what SVG they allow. The safe default is **not** to embed SVG inline — it's to **save the SVG as a separate `.svg` file and reference it with image-link syntax**. Inline SVG should be treated as a special case the user explicitly asks for, not as the default.
This skill encodes the reasoning behind that choice, layout and legibility rules for readable output, and the per-renderer rules for when inline SVG is what's wanted.
## Default approach: external `.svg` file + image link
For any new diagram going into a Markdown document:
1. Generate the SVG as a standalone `.svg` file. Common conventions:
- `docs/images/<slug>.svg`, `assets/<slug>.svg`, or alongside the `.md` itself.
- Match the project's existing convention if there is one.
2. Reference it from the Markdown with image-link syntax:
```markdown
![Architecture overview](./images/architecture.svg)
```
3. The `.svg` file itself is a normal SVG document — `<style>`, `<circle>`, `<g>`, classes, gradients, animations, anything you'd write in any SVG. The renderer pipeline for standalone SVG files is much more permissive than the inline-Markdown sanitizer (especially on GitHub, where they're handled by entirely different code paths).
This recipe is the **only** approach that reliably produces a rendered diagram on **GitHub** (which strips inline SVG categorically — see below). It also works on Gitea and Obsidian and any other Markdown renderer that supports image links.
Use this default unless the user explicitly asks for inline SVG.
## Why not inline SVG by default
Inline SVG fails silently and inconsistently across renderers. From source-code analysis (see `research/2026-05-05-15-svg-sanitizer-allowlists/` if available locally):
- **GitHub Markdown** (`html-pipeline` + `rgrove/sanitize`): the allow-list contains **zero** SVG elements. `<svg>`, `<g>`, `<path>`, `<circle>` — all stripped. Inline SVG never renders in a `.md` file on github.com. The element is removed; only its bare text-node children leak through.
- **Gitea** (bluemonday default policy): allows only `<svg>` and `<path>`. No `<rect>`, no `<circle>`, no `<g>`, no `<text>`, no gradients, no fills or strokes (the `fill` and `stroke` attributes are also stripped). Self-hosted admins can extend the allow-list via `app.ini`'s `[markup.sanitizer.N]` rules, but defaults are the rule.
- **Obsidian** (DOMPurify defaults): allows most SVG — `<circle>`, `<rect>`, `<ellipse>`, `<g>`, `<text>`, `<defs>`, gradients, paths, filters. Empirically confirmed *not* working in Obsidian: `<use>`, `<style>` element, `<foreignObject>`, `<title>` element. `<script>`, event handlers, and `javascript:` URLs are stripped on every renderer including Obsidian.
- **VS Code Markdown preview** (uses markdown-it + DOMPurify-like sanitization): permissive, similar to Obsidian for most things.
The **strict cross-renderer intersection for inline SVG is effectively empty** — there is no inline-SVG recipe that produces a rendered diagram on GitHub, Gitea, and Obsidian alike. This is why the default has to be the external file.
## Layout and legibility
Renderer compatibility is only half the problem — the other half is producing SVG that's actually readable. Agent-generated SVGs commonly fail on text overflow, poor contrast, and missing margins. **Read `references/layout-legibility.md` before generating any non-trivial SVG** (charts, matrices, diagrams with labels). It covers:
- Estimating text width before sizing containers (SVG doesn't clip text)
- Contrast contracts for text over colored backgrounds (aim for 4.5:1)
- Background rects or halos for text on data-dependent surfaces
- Margin reservation for rotated labels
- The sparse-cells-plus-legend pattern for dense categorical charts
- Palette selection with declared text-color roles
## When the user asks for inline SVG
If the user explicitly says "embed it inline", "put the SVG directly in the markdown", or similar — **read `references/inline-svg.md` before proceeding**. It contains the full per-renderer compatibility table, sanitizer survival rules, and inline-specific checklists. Pick the rule set that matches the target renderer; if the target is unknown, ask.
## Default size
Generated SVG diagrams should not exceed **750 pixels in width** by default — set `width` (and a matching `viewBox`) accordingly. Height is unconstrained — pick whatever the content needs. Wider SVGs blow out the column on most Markdown renderers. Override only when the user explicitly asks for wider.
## Minimal example (external file recipe — the default)
```markdown
The architecture is straightforward:
![Architecture overview](./images/architecture.svg)
Each component handles its own state.
```
Where `./images/architecture.svg` is a normal SVG file — use any elements you want; standalone SVG is not subject to the inline-Markdown sanitizer.
## Pre-commit checklist
- [ ] SVG saved as a `.svg` file in a sensible location.
- [ ] Markdown references it with `![alt](path.svg)`.
- [ ] `width` (the rendered width) ≤ 750px unless asked otherwise.
For inline SVG checklists, see `references/inline-svg.md`.