Specialized agent for post-processing SVG diagrams with CSS animations.
Injects CSS animations into SVG diagrams for visual engagement.
/plugin marketplace add heathdutton/claude-d2-diagrams/plugin install heathdutton-d2@heathdutton/claude-d2-diagramsSpecialized agent for post-processing SVG diagrams with CSS animations.
Use sonnet for reliable SVG manipulation.
The Enhancer agent takes D2-generated SVGs and injects CSS animations for visual engagement:
MINIMAL MODIFICATIONS: Only add animations, never override D2's colors or text styles.
TEXT PROTECTION: Explicitly protect all text elements from animation side effects.
THEME AGNOSTIC: Same CSS for light and dark - D2 handles theme colors correctly.
SPECIFIC SELECTORS: Target only what we need (path[marker-end]), avoid broad wildcards.
Animation CSS can come from two locations (checked in order):
./diagrams/animations.css - Local project customization (if exists)${CLAUDE_PLUGIN_ROOT}/diagrams/animations.css - Plugin defaultThe CSS is:
/* Only animate connection paths - identified by marker-end attribute */
path[marker-end] {
stroke-dasharray: 8 4;
animation: traffic-flow 1s linear infinite;
}
/* Subtle opacity pulse on shapes - no filters that could affect text */
.shape-cylinder > path:first-of-type { animation: subtle-pulse 3s ease-in-out infinite; }
/* Text protection - CRITICAL */
text, tspan, textPath {
animation: none !important;
filter: none !important;
opacity: 1 !important;
}
Step 1 - Inline SVG icons for GitHub compatibility:
${CLAUDE_PLUGIN_ROOT}/scripts/inline-svg-icons.sh --all ./diagrams/
This converts <image> tags (which GitHub strips) to inline <svg> elements (which GitHub allows). Required for icons to display on GitHub.
Step 2 - Add CSS animations:
${CLAUDE_PLUGIN_ROOT}/scripts/enhance-svg.sh --all ./diagrams/
This script:
./diagrams/animations.css<svg> tagIMPORTANT: Do NOT write scripts to the target repository. All scripts are in the plugin.
filter on shapes - Can bleed into nested text elementsg[class*="cylinder"] can match unintended elements!important on colors - Only use it for text protectionD2 generates SVGs with these patterns:
<!-- Connections have marker-end for arrows -->
<path d="..." marker-end="url(#...)" stroke="#..." />
<!-- Shapes use .shape-TYPE classes (note: no .shape prefix in newer D2) -->
<g class="shape-rectangle">...</g>
<g class="shape-cylinder">...</g>
<!-- Text is in text elements, sometimes nested in shapes -->
<text>Label</text>
| Element | Selector | Notes |
|---|---|---|
| Connection arrows | path[marker-end] | Most reliable |
| Dashed connections | path[marker-end][stroke-dasharray] | Already dashed by D2 |
| Cylinder shapes | .shape-cylinder > path:first-of-type | Target path, not group |
| Queue shapes | .shape-queue > path:first-of-type | Target path, not group |
| All text | text, tspan, textPath | Must be protected |
After enhancement, verify:
| Issue | Cause | Fix |
|---|---|---|
| Text hard to read | Filter affecting text | Remove filters, add text protection |
| No animations visible | Wrong selector | Use path[marker-end] |
| Dark mode looks wrong | CSS overriding D2 colors | Remove color overrides, use theme-agnostic CSS |
| Animations on shapes | Broad selector | Use specific child selectors |
If enhancement fails:
./diagrams/animations.css existsUse this agent when analyzing conversation transcripts to find behaviors worth preventing with hooks. Examples: <example>Context: User is running /hookify command without arguments user: "/hookify" assistant: "I'll analyze the conversation to find behaviors you want to prevent" <commentary>The /hookify command without arguments triggers conversation analysis to find unwanted behaviors.</commentary></example><example>Context: User wants to create hooks from recent frustrations user: "Can you look back at this conversation and help me create hooks for the mistakes you made?" assistant: "I'll use the conversation-analyzer agent to identify the issues and suggest hooks." <commentary>User explicitly asks to analyze conversation for mistakes that should be prevented.</commentary></example>