CommunityCoding & Developmentgithub.com

luk036/add-rust-svgbob

Add svgbob ASCII diagrams (```svgbob) to doc comments for Rust projects using the svgbobdoc crate

What is add-rust-svgbob?

add-rust-svgbob is a OpenCode agent skill that add svgbob ASCII diagrams (```svgbob) to doc comments for Rust projects using the svgbobdoc crate.

Works with~Claude Code~Codex CLI~Cursor✓OpenCode
npx skills add https://github.com/luk036/agent-skills/tree/HEAD/skills/add-rust-svgbob

Installed? Explore more Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Skill: add-rust-svgbob

File references (@path) in this skill are relative to this directory.

What I do

I add ASCII art diagrams to Rust /// doc comments using the svgbobdoc crate's transform!() macro. The ASCII art inside ```svgbob code fences is converted to inline SVG at compile time and embedded as data:image/svg+xml data URIs — no external files needed, works on both local cargo doc and docs.rs.

The diagram lives in the source code itself — anyone reading the Rust file sees the ASCII art directly.

When to use me

Use this when:

  • You have a Rust library with structural/architectural concepts best explained with a diagram
  • You want quick flowcharts, process diagrams, or data flow visuals without external image files
  • The diagram is simple enough to represent with ASCII box-drawing characters
  • You want diagrams that are visible in the source code (not hidden in external PNGs)
  • You maintain a crate where svgbobdoc's dependency weight is acceptable

Not suitable for:

  • Real data visualizations (scatter plots, line charts) — use embed-doc-image instead
  • Complex diagrams with curved paths or fine detail — ASCII art has limitations
  • Projects on very old Rust compilers (< 1.54)

Prerequisites

RequirementPurpose
Rust ≥ 1.54 or nightlyFor inner attribute + proc macro support
svgbobdoc in dependenciesThe proc macro crate
enable feature on svgbobdocActivates the svgbob SVG renderer
doc-images feature flag (or custom)Feature-gating for compatibility
docs.rs metadata configuredEnsures SVGs render on docs.rs

How I work

Step 1: Check current state

Read Cargo.toml to check if svgbobdoc is already configured:

  • Is svgbobdoc in [dependencies] with features = ["enable"]?
  • Is it optional (recommended)?
  • Is there a doc-images or similar feature to enable it?
  • Does [package.metadata.docs.rs] include features = ["doc-images"]?

Check source files for existing ```svgbob usage or svgbobdoc::transform!() calls.

Step 2: Set up infrastructure (if missing)

If svgbobdoc is not configured, add it:

Cargo.toml additions:

[dependencies]
svgbobdoc = { version = "0.3", optional = true, features = ["enable"] }

[features]
doc-images = ["dep:svgbobdoc"]

[package.metadata.docs.rs]
features = ["doc-images"]

If embed-doc-image is also used, combine under the same feature:

[features]
doc-images = ["dep:embed-doc-image", "dep:svgbobdoc"]

Step 3: Scan the project

Look in <project>/src/ recursively for *.rs files. Identify diagram candidates — types and functions where an ASCII diagram would clarify the concept.

Step 4: Identify diagram candidates

A function/type/module is a "diagram candidate" when:

SignalExample
Data flowInput → Processing → Output
Process stepsAlgorithm with clear stages
Coordinate mapping(x, y) → transformed coordinates
Geometric transformationRotation, projection, scaling
Tree/graph structureBinary tree, netlist, dependency graph
ArchitectureModule hierarchy, pipeline stages
State machineStates and transitions
ComparisonBefore vs After, two alternatives
LayoutFloorplan, memory layout, packing

Step 5: Design the ASCII diagram

svgbob rendering capabilities:

ASCII elementsvgbob rendering
.─. / '─'Rounded rectangle borders
│ / ─Lines
/ / \Diagonal lines
► / ▼ / ▲ / ◄Arrow heads (Unicode)
-> / <-Arrow connectors
=== / ~~~Double/wavy lines
( ) / [ ]Curved/angled brackets
○ / ●Circle markers
...Dashed connectors

Design tips for clear diagrams:

  1. Keep it compact — 15-25 rows max per diagram
  2. Use box borders — .───. for top, '───' for bottom
  3. Label arrows — Add text next to ──► connectors
  4. Align with Unicode box-drawing — ─ │ ┌ ┐ └ ┘ ├ ┤ ┬ ┴ ┼
  5. Test the diagram — Use the svgbob editor to preview

Example — a simple data flow:

.───────────.     .───────────.     .───────────.
│  Input    │────►│  Process  │────►│  Output   │
'───────────'     '───────────'     '───────────'

Step 6: Add the diagram

For struct-level docs:

/// Existing description.
///
/// The transformation flow:
#[cfg_attr(feature = "doc-images", doc = svgbobdoc::transform!(
/// ```svgbob
///  .───────────.     .───────────.
///  │  Step 1   │────►│  Step 2   │
///  '───────────'     '───────────'
/// ```
))]
pub struct MyType { ... }

For function-level docs:

/// Description.
#[cfg_attr(feature = "doc-images", doc = svgbobdoc::transform!(
/// ```svgbob
///  .───────────.     .───────────.
///  │  Input x  │────►│ Output f(x)│
///  '───────────'     '───────────'
/// ```
))]
pub fn my_function(x: f64) -> f64 { ... }

IMPORTANT: The /// lines inside transform!() must be preserved exactly. The macro parses /// as doc comment lines and processes ```svgbob blocks within them.

Step 7: Build and verify

# Build with diagrams
cargo doc --features doc-images --no-deps --open

Verification checklist:

  • cargo build (without features) passes — no svgbobdoc dependency leak
  • cargo build --features doc-images passes — transform!() macro runs
  • cargo doc --features doc-images --no-deps completes with zero warnings
  • Generated HTML contains data:image/svg+xml;base64,... URIs
  • SVGs render correctly in browser (proper arrows, boxes, text)
# Verify SVG data URIs on each struct page
grep -c "data:image/svg" target/doc/my_crate/struct.MyType.html

Step 8: Check both feature states

cargo build                          # Must pass (svgbobdoc not linked)
cargo build --features doc-images    # Must pass (transform! runs)
cargo test --all-features            # All tests must pass

Configuration Reference

Basic Cargo.toml (svgbobdoc only)

Minimal setup for a project using only svgbobdoc:

[package]
name = "my-crate"
version = "0.1.0"
edition = "2024"

[dependencies]
svgbobdoc = { version = "0.3", optional = true, features = ["enable"] }

[features]
doc-images = ["dep:svgbobdoc"]

[package.metadata.docs.rs]
features = ["doc-images"]

Combined with embed-doc-image

When using both svgbobdoc (ASCII diagrams) and embed-doc-image (PNG/SVG figures):

[dependencies]
embed-doc-image = { version = "0.1", optional = true }
svgbobdoc = { version = "0.3", optional = true, features = ["enable"] }

[features]
doc-images = ["dep:embed-doc-image", "dep:svgbobdoc"]

[package.metadata.docs.rs]
features = ["doc-images"]

Both share the same doc-images feature — one cargo doc --features doc-images enables both.

Custom feature names

If your project already has a doc-images feature for other purposes, use a different name:

[features]
default = []
svg-docs = ["dep:svgbobdoc"]       # Custom name
doc-images = ["dep:embed-doc-image"] # Existing name

Then in source code:

#[cfg_attr(feature = "svg-docs", doc = svgbobdoc::transform!(
/// ```svgbob
/// diagram
/// ```
))]
pub struct MyType;

Feature resolution with dep: syntax

The dep: prefix in feature definitions was stabilised in Rust 1.60. It explicitly references an optional dependency:

# Modern syntax (Rust ≥ 1.60) — recommended:
doc-images = ["dep:svgbobdoc"]

# Legacy syntax — works but less explicit:
doc-images = ["svgbobdoc"]

The dep: form is preferred — it prevents ambiguity between dependency and feature names.

docs.rs metadata options

SettingPurpose
features = ["doc-images"]Enables svgbobdoc during doc build
rustdoc-args = ["--html-in-header", "src/doc-header.html"]Injects KaTeX/JS headers
all-features = trueBuilds docs with ALL features (use with care)
[package.metadata.docs.rs]
features = ["doc-images"]
rustdoc-args = ["--html-in-header", "src/doc-header.html"]

Conditional compilation with cfg_attr

The core pattern:

#[cfg_attr(
    feature = "doc-images",                    // condition
    doc = svgbobdoc::transform!(               // attribute to emit
        /// ```svgbob
        /// diagram
        /// ```
    )
)]

How it works at each build:

Build commandcfg_attr evaluates toResult
cargo buildfeature = "doc-images" is falseAttribute suppressed — no macro, no svgbob dep
cargo build --features doc-imagesfeature = "doc-images" is true#[doc = svgbobdoc::transform!(...)] emits — SVG generated
cargo doc --features doc-imagesSame as aboveSVG data URIs embedded in HTML
docs.rs (metadata sets features)Same as aboveSVG renders on docs.rs

Checking feature resolution

Verify the feature is correctly wired:

# Check that svgbobdoc is NOT linked in default build
cargo build --verbose 2>&1 | grep svgbobdoc
# (should produce no output)

# Check that svgbobdoc IS linked with feature
cargo build --features doc-images --verbose 2>&1 | grep svgbobdoc
# Output: "Compiling svgbobdoc v0.3.0"

svgbob ASCII Art Syntax Guide

Box-drawing characters

The svgbob renderer recognises these Unicode box-drawing characters and converts them to SVG paths:

CharacterCode pointRenders as
─U+2500Horizontal line
│U+2502Vertical line
┌U+250CTop-left corner
┐U+2510Top-right corner
└U+2514Bottom-left corner
┘U+2518Bottom-right corner
├U+251CLeft T-junction
┤U+2524Right T-junction
┬U+252CTop T-junction
┴U+2534Bottom T-junction
┼U+253CCross junction
╱U+2571Diagonal up-right
╲U+2572Diagonal up-left
◄U+25C4Left arrow head
►U+25BARight arrow head
▲U+25B2Up arrow head
▼U+25BCDown arrow head
●U+25CFFilled circle
○U+25CBEmpty circle
═U+2550Double horizontal
║U+2551Double vertical
≈U+2248Wavy line
→U+2192Rightwards arrow

Creating boxes

Rounded rectangle (most common for diagram nodes):

.───────────.
│  content  │
'───────────'
  • Use . for top-left, ' for top-right corners
  • Use ' for bottom-left, . for bottom-right corners
  • Fill the top/bottom borders with ─
  • Fill side borders with │

Sharp rectangle:

┌───────────┐
│  content  │
└───────────┘

Connecting boxes with arrows

Horizontal arrow:

.───.         .───.
│ A │────────►│ B │
'───'         '───'

Vertical arrow:

.───.
│ A │
'───'
  │
  ▼
.───.
│ B │
'───'

Arrow from specific side:

         .───.
         │ B │
         '───'
           ▲
           │
.───.      │
│ A │──────┘
'───'

Adding labels to arrows

Place text next to the arrow line. svgbob automatically positions it:

.───.     condition    .───.
│ A │══════════════════►│ B │
'───'                  '───'
.───.     false     .───.
│ A │──────────────►│ B │
'───'              '───'

Multi-line text in boxes

svgbob wraps text naturally based on box width:

.──────────────────.
│ This text will   │
│ wrap inside the  │
│ box boundaries   │
'──────────────────'

Diagonal lines

.───.     .───.
│ A │╲    │ C │
'───' ╲   '───'
       ╲
        ╲ .───.
         ╲│ B │
          ╲'───'

Trees and hierarchies

Binary tree:

       .───.
       │ R │
       '───'
       ╱   ╲
   .───.     .───.
   │ L │     │ R │
   '───'     '───'
   ╱   ╲       ╲
 .───. .───.   .───.
 │LL │ │LR │   │RR │
 '───' '───'   '───'

Indented hierarchy (no lines):

.───────────────.
│ Root          │
│ ├── Child A   │
│ ├── Child B   │
│ └── Child C   │
'───────────────'

Grids and matrices

.──────┬──────┬──────.
│  a   │  b   │  c   │
├──────┼──────┼──────┤
│  d   │  e   │  f   │
├──────┼──────┼──────┤
│  g   │  h   │  i   │
'──────┴──────┴──────'

Comparison layouts

Side-by-side:

.─────────────.  .─────────────.
│ Before      │  │ After       │
│  .───────.  │  │  .───────.  │
│  │ Old   │  │  │  │ New   │  │
│  '───────'  │  │  '───────'  │
'─────────────'  '─────────────'

Before → After (sequential):

.───────────────.     .───────────────.
│  Slow path    │────►│  Fast path    │
│  O(n²)        │     │  O(n log n)   │
'───────────────'     '───────────────'

Database / Table schemas

.──────────────────────.
│  Table: users        │
├──────────────────────┤
│  id         INTEGER  │──► PK
│  name       TEXT     │
│  email      TEXT     │──► UNIQUE
│  created_at DATETIME │
'──────────────────────'

Flowchart with decision

.───────────.
│  Start    │
'─────┬─────'
      │
      ▼
.───────────.
│  Process  │
'─────┬─────'
      │
      ▼
.───────────.   yes   .───────────.
│  Check?  │─────────►│  Option A │
'─────┬─────'         '───────────'
      │
      │ no
      ▼
.───────────.
│  Option B │
'───────────'

Layered architecture

.───────────────────────────.
│  Application Layer        │
├───────────────────────────┤
│  Business Logic Layer     │
├───────────────────────────┤
│  Data Access Layer        │
├───────────────────────────┤
│  Database                 │
'───────────────────────────'

Timing / sequence diagram (simple)

Client───┬──────────────────┐
         │   Request        │
         │─────────────────►│
         │                  │
         │◄─────────────────│
         │    Response      │
         │                  │

Best practices for readable ASCII art

  1. Use a monospace font in your editor — the diagram must align properly in source code

  2. Tab width = 8 — or use spaces only. Tabs in ASCII art often break alignment

  3. Pad box contents — leave at least one space on each side of text inside boxes:

    ✅   .──────.     ❌   .──────.
        │ ok   │             │bad  │
        '──────'             '──────'
    
  4. Align arrow connectors — arrow lines should point exactly at the middle of the target box side

  5. Test widths — keep within 60-70 characters to avoid horizontal scroll in cargo doc

  6. Escape [ brackets in text — rustdoc interprets [text] as intra-doc links. Inside ```svgbob blocks this is less of an issue because svgbob code fences are inside the transform!() macro which outputs a string, but be aware that bracket content may be parsed depending on context

  7. Preview in the svgbob editor — use https://ivanceras.github.io/svgbob-editor/ before committing

Common mistakes

MistakeProblemFix
Using `instead of│`Thin ASCII pipe rendered instead of solid line
Using - instead of ─Dashed line instead of solidUse Unicode ─ (U+2500)
Forgetting /// prefixMacro doesn't parse the linesEvery line must start with ///
Missing cfg_attrsvgbobdoc becomes required depAlways wrap in cfg_attr(feature = "...", ...)
Arrow not touching boxGap in the diagramExtend the line to touch the box border
Mixing tabs and spacesMisaligned renderingUse spaces only for ASCII art
Trailing spaces trimmedUnexpected gapsPreserve trailing spaces for alignment

Domain-specific diagram templates

Sequence Generators (LDS)

ConceptTemplate
Radical inverseDigit reversal: n → base-b digits → reverse → fraction
VdC → Circleφ(n) → θ = 2π·φ → (cos θ, sin θ)
VdC → Disk(φ₂, φ₃) → (θ, r) → (r·cosθ, r·sinθ)
VdC → Sphere(φ₂, φ₃) → (z, θ) → cyl. proj. → (x, y, z)
Hopf fibration(φ₂, φ₃, φ₅) → (η, ψ, φ) → S³ point

Diagram: Two VdC values mapping to a 2D point

 .───────────.   θ = 2π·φ₂(n)
 │ φ₂(n)     │───► angle θ
 '───────────'
 .───────────.   r = √φ₃(n)         .───────────────.
 │ φ₃(n)     │───► radius r ──────►│ (r·cosθ,      │
 '───────────'                      │  r·sinθ)      │
                                    '───────────────'

Data Flow / Pipeline

ConceptTemplate
Simple pipeInput ──► Process ──► Output
BranchingInput ──► [A ──► OutA, B ──► OutB]
Merge[A, B] ──► Merge ──► Output
FeedbackProcess ──► Output ──► (feedback) ──► Input
.──────────.    .───────────.    .──────────.
│  Source  │───►│  Transform │───►│  Sink   │
'──────────'    '───────────'    '──────────'

Geometric Transformations

ConceptTemplate
Rotation(x, y) ──► θ ──► (x·cosθ - y·sinθ, x·sinθ + y·cosθ)
Scaling(x, y) ──► s ──► (s·x, s·y)
Translation(x, y) ──► (dx, dy) ──► (x+dx, y+dy)
Projection(x, y, z) ──► perspective ──► (x', y')
.───────────.         .───────────────.
│  (x, y)   │────────►│  (x', y')    │
'───────────'  Rotate  '──────────────'

Tree Structures

ConceptTemplate
Binary treeRoot with left/right children
Quad treeSubdivided rectangle
HierarchyParent with children list
       .───.
       │ R │
       '───'
       ╱   ╲
   .───.     .───.
   │ A │     │ B │
   '───'     '───'
   ╱   ╲       ╲
 .───. .───.   .───.
 │C  │ │D  │   │E  │
 '───' '───'   '───'

Comparison / Side-by-Side

.────────────────────.
│  Before            │
│  .───────────.     │
│  │  slow     │     │
│  '───────────'     │
'────────────────────'
         │
         ▼
.────────────────────.
│  After             │
│  .───────────.     │
│  │  fast!    │     │
│  '───────────'     │
'────────────────────'

State Machine

.───────────.   event A   .───────────.
│  State 1  │───────────►│  State 2  │
'───────────'            '───────────'
     ▲                        │
     │      event B           │
     └────────────────────────┘

Crate-Level Diagram Gallery

When adding multiple diagrams to a project, organize them in a table in the crate-level docs:

//! | Type | Diagram |
//! |------|---------|
//! | [`VdCorput`] | Digit reversal flow |
//! | [`Circle`] | Angle mapping to S¹ |
//! | [`Disk`] | Polar mapping to D² |

Each diagram is added with its own #[cfg_attr(feature = "doc-images", doc = svgbobdoc::transform!(...))].

CRITICAL RULES

Rule 1: Never destroy existing documentation

Always append diagrams to existing doc comments. Never delete existing doc text, examples, or section headers. Insert the #[cfg_attr(feature = "doc-images", doc = svgbobdoc::transform!(...))] after the existing /// doc comment block and before the #[derive(...)] or item definition.

Rule 2: Use ```svgbob code fences

The transform!() macro looks for ```svgbob blocks to convert to SVG. Regular ```text or ``` blocks are NOT converted. The language hint must be svgbob:

✅ Correct:
/// ```svgbob
///  .─.
///  │A│
///  '─'
/// ```

❌ Will NOT be processed:
/// ```text
///  .─.
///  │A│
///  '─'
/// ```

Rule 3: Feature-gate ALL transform!() calls

Every svgbobdoc::transform!(...) must be wrapped in:

#[cfg_attr(feature = "doc-images", doc = svgbobdoc::transform!(
/// ```svgbob
/// ...
/// ```
))]

Without the cfg_attr, the proc macro runs on every build, forcing svgbobdoc to be a non-optional dependency.

Rule 4: Preserve /// prefix inside transform!()

The transform!() macro parses /// as doc comment lines. Each line inside the macro must start with ///:

✅ Correct:
#[doc = svgbobdoc::transform!(
/// ```svgbob
/// diagram
/// ```
)]

❌ Wrong — missing /// prefix:
#[doc = svgbobdoc::transform!(
"``svgbob
diagram
``"
)]

Rule 5: Match doc-images feature name to Cargo.toml

The feature name in cfg_attr must match the feature defined in Cargo.toml. If your project uses a different feature name (e.g., svg-docs), use that instead:

[features]
svg-docs = ["dep:svgbobdoc"]
#[cfg_attr(feature = "svg-docs", doc = svgbobdoc::transform!(...))]

Rule 6: Use Unicode box-drawing characters

svgbob renders Unicode box-drawing characters (─ │ ┌ ┐ └ ┘ ├ ┤ ┬ ┴ ┼ ╱ ╲ ◄ ► ▼ ▲ ● ○) into proper SVG lines and shapes. Use these characters rather than ASCII approximations:

Good (Unicode)Bad (ASCII)
───►--->
.───..---.
│ text │`
'───''---'

Rule 7: Test the diagram before embedding

Use the svgbob editor to preview your ASCII art before adding it to source code. This catches rendering issues early.

Rule 8: Keep diagrams simple

A good svgbob diagram should be:

  • ≤ 25 lines tall (fits on one screen)
  • ≤ 60 characters wide (fits in standard doc width)
  • ≤ 15 elements (boxes, arrows, labels)
  • Self-explanatory with minimal labels

If your diagram is more complex, consider splitting it into multiple smaller diagrams or using embed-doc-image with an external SVG.

Rule 9: Verify both feature states

cargo build                              # Must pass
cargo build --features doc-images        # Must pass
cargo doc --features doc-images --no-deps # Zero warnings

Rule 10: Coordinate with embed-doc-image

If the project also uses embed-doc-image:

  • Both crates can share the same doc-images feature
  • svgbobdoc handles structural/flow diagrams
  • embed-doc-image handles real plots and screenshots
  • Both produce data: URIs that render seamlessly together

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

Related Skills