Compare commits

...

32 Commits

Author SHA1 Message Date
Jim Liu 宝玉 0b8ac256f4 chore: release v1.100.0 2026-04-12 00:30:55 -05:00
Jim Liu 宝玉 eaa0f1aa11 feat(baoyu-imagine): add Z.AI GLM-Image provider
Adds the Z.AI (智谱) provider supporting glm-image and cogview-4-250304
models via the Z.AI sync image API. Configure with ZAI_API_KEY (or
BIGMODEL_API_KEY for backward compat). Reference images are not supported yet.
2026-04-12 00:30:49 -05:00
Jim Liu 宝玉 ec5f4ffcc9 chore: release v1.99.1 2026-04-11 21:02:36 -05:00
Jim Liu 宝玉 d206e1674d fix(baoyu-article-illustrator): omit model field from batch tasks when unspecified
When --model is not provided, build-batch no longer writes a model field
into batch task entries; baoyu-imagine resolves the default from env or
EXTEND config instead of inheriting a hardcoded script default.

Adds tests covering both the omit-by-default and explicit-override paths.
2026-04-11 21:02:18 -05:00
Jim Liu 宝玉 b62ad26098 feat: add baoyu-diagram skill and baoyu-article-illustrator ink-notes style (v1.99.0)
- baoyu-diagram: new skill for generating publication-ready SVG diagrams (flowchart, structural, illustrative) with embedded styles and auto dark-mode
- baoyu-article-illustrator: add ink-notes style and mono-ink palette with presets for before/after, manifesto, and framework diagrams
2026-04-11 20:54:32 -05:00
Jim Liu 宝玉 31b2929d1c chore: release v1.98.0 2026-04-10 10:58:50 -05:00
Jim Liu 宝玉 7c2253dd3e feat(baoyu-xhs-images): add sketch-notes style, palette system, and new presets
- Restore baoyu-xhs-images as active skill (remove deprecated warning)
- Add sketch-notes style: hand-drawn educational infographic with macaron pastels
- Add palette system (macaron/warm/neon) as optional color override dimension
- Add 3 new presets: hand-drawn-edu, sketch-card, sketch-summary
- Add palette gallery documentation and palette override workflow
- Update style-presets.md with palette column
- Update prompt-assembly.md with palette override logic
- Update READMEs to reference baoyu-xhs-images
2026-04-10 10:58:29 -05:00
Jim Liu 宝玉 8be98c5afe chore: release v1.97.1 2026-04-09 13:20:21 -05:00
Jim Liu 宝玉 fe1a854bed fix(baoyu-image-cards): rename palette Zone labels to prevent text rendering in images 2026-04-09 13:20:14 -05:00
Jim Liu 宝玉 eeba585315 chore: release v1.97.0 2026-04-09 13:05:50 -05:00
Jim Liu 宝玉 1ca99ae5ae chore: add .omx to gitignore and update lockfile 2026-04-09 13:05:04 -05:00
Jim Liu 宝玉 c5df9d01bf fix(baoyu-xhs-images): improve deprecated skill description for better routing 2026-04-09 13:05:00 -05:00
Jim Liu 宝玉 ee1fc3c823 feat(baoyu-image-cards): add sketch-notes style, palette system, and 3 new presets 2026-04-09 13:04:57 -05:00
Jim Liu 宝玉 b7725a4ba8 chore: release v1.96.0 2026-04-09 10:47:51 -05:00
Jim Liu 宝玉 a596c653d3 feat(baoyu-image-cards): add image card series skill migrated from baoyu-xhs-images
Rename baoyu-xhs-images to baoyu-image-cards to decouple from Xiaohongshu platform.
Deprecate baoyu-xhs-images with migration notice pointing to baoyu-image-cards.
2026-04-09 10:47:28 -05:00
Jim Liu 宝玉 3017bfe423 chore: release v1.95.1 2026-04-09 10:00:43 -05:00
Jim Liu 宝玉 ae1d619ab2 fix(baoyu-slide-deck): add pptxgenjs dependency and detect image format by magic bytes 2026-04-09 10:00:29 -05:00
Jim Liu 宝玉 4821508c34 chore: release v1.95.0 2026-04-08 22:10:03 -05:00
Jim Liu 宝玉 f1042c8a6c feat(baoyu-slide-deck): add hand-drawn-edu preset and macaron mood 2026-04-08 22:06:54 -05:00
Jim Liu 宝玉 fa0fe441f5 feat(baoyu-infographic): add hand-drawn-edu style with macaron palette 2026-04-08 22:06:50 -05:00
Jim Liu 宝玉 90b2205914 chore: release v1.94.0 2026-04-08 17:58:33 -05:00
Jim Liu 宝玉 8e111c17b3 feat(baoyu-cover-image): add macaron palette and hand-drawn-edu style preset 2026-04-08 17:58:29 -05:00
Jim Liu 宝玉 80d7675355 chore: release v1.93.0 2026-04-08 15:49:00 -05:00
Jim Liu 宝玉 538ede2b32 feat(baoyu-article-illustrator): add hand-drawn-edu preset with sketch-notes + macaron 2026-04-08 15:48:20 -05:00
Jim Liu 宝玉 038e67fd9b refactor(baoyu-article-illustrator): extract palette as independent third dimension
- Create palettes/ directory with macaron, warm, neon palette files
- Move macaron from styles/ to palettes/ (color scheme, not rendering style)
- Extract warm palette variant from vector-illustration into shared palette
- Add neon palette extracted from retro style colors
- Update architecture from Type × Style to Type × Style × Palette
- Add Palette Gallery and override rules to styles.md
- Add Palette Override section to prompt-construction.md
- Update presets table with Palette column
- Add palette selection step to workflow
- Add preferred_palette to EXTEND.md schema
2026-04-08 14:35:51 -05:00
Jim Liu 宝玉 049462d6dd fix(baoyu-article-illustrator): add explicit style file loading step in workflow 2026-04-08 12:52:13 -05:00
Jim Liu 宝玉 c8042cef0d chore: release v1.92.0 2026-04-08 11:51:23 -05:00
Jim Liu 宝玉 15508eae43 feat(baoyu-article-illustrator): add macaron style with soft pastel color blocks 2026-04-08 11:49:49 -05:00
Jim Liu 宝玉 94eab2de63 chore: release v1.91.0 2026-04-07 01:32:21 -05:00
Jim Liu 宝玉 126b72ed36 feat: add pdf-lib dependency for PDF generation 2026-04-07 01:31:35 -05:00
Jim Liu 宝玉 38f4f253df feat(baoyu-comic): add four-panel preset, minimalist art style, and flexible image workflow
- Add minimalist art style (clean line art, limited spot color, stick-figure characters)
- Add four-panel layout with 起承转合 structure
- Add four-panel preset combining minimalist + neutral + four-panel layout
- Make character sheet conditional (skip for simple presets like four-panel)
- Add --ref failure recovery: compress → retry → fall back to prompt-only
2026-04-07 01:31:32 -05:00
Jim Liu 宝玉 8bc01debac Add concept-story preset to baoyu-comic 2026-04-07 01:09:05 -05:00
108 changed files with 11799 additions and 251 deletions
+3 -2
View File
@@ -6,7 +6,7 @@
},
"metadata": {
"description": "Skills shared by Baoyu for improving daily work efficiency",
"version": "1.90.1"
"version": "1.100.0"
},
"plugins": [
{
@@ -21,6 +21,7 @@
"./skills/baoyu-cover-image",
"./skills/baoyu-danger-gemini-web",
"./skills/baoyu-danger-x-to-markdown",
"./skills/baoyu-diagram",
"./skills/baoyu-format-markdown",
"./skills/baoyu-imagine",
"./skills/baoyu-infographic",
@@ -31,7 +32,7 @@
"./skills/baoyu-slide-deck",
"./skills/baoyu-translate",
"./skills/baoyu-url-to-markdown",
"./skills/baoyu-xhs-images",
"./skills/baoyu-image-cards",
"./skills/baoyu-youtube-transcript"
]
}
+2
View File
@@ -154,6 +154,7 @@ illustrations/
comic/
translate/
posts/
diagram/
### IntelliJ IDEA ###
.idea
*.iws
@@ -167,3 +168,4 @@ posts/
.release-artifacts/
.worktrees/
youtube-transcript/
.omx/
+74
View File
@@ -2,6 +2,80 @@
English | [中文](./CHANGELOG.zh.md)
## 1.100.0 - 2026-04-12
### Features
- `baoyu-imagine`: add Z.AI GLM-Image provider — supports `glm-image` and `cogview-4-250304` models via the Z.AI sync image API; configure with `ZAI_API_KEY` (or `BIGMODEL_API_KEY` for backward compatibility)
## 1.99.1 - 2026-04-11
### Fixes
- `baoyu-article-illustrator`: omit `model` field from batch tasks when `--model` is not specified, letting `baoyu-imagine` resolve the default from env/config
## 1.99.0 - 2026-04-10
### Features
- `baoyu-diagram`: add new skill for generating publication-ready SVG diagrams — flowcharts, structural/architecture diagrams, and illustrative intuition diagrams. Claude writes real SVG code directly following a cohesive design system; output is a single self-contained `.svg` file with embedded styles and auto dark-mode, ready to embed in articles, WeChat posts, slides, and docs
## 1.98.0 - 2026-04-10
### Features
- `baoyu-xhs-images`: Restore as active skill (remove deprecated warning)
- `baoyu-xhs-images`: Add `sketch-notes` style — hand-drawn educational infographic with macaron pastels, wobble lines, and warm cream background
- `baoyu-xhs-images`: Add palette system (`macaron`, `warm`, `neon`) as optional `--palette` color override dimension
- `baoyu-xhs-images`: Add 3 new presets: `hand-drawn-edu`, `sketch-card`, `sketch-summary`
## 1.97.1 - 2026-04-09
### Fixes
- `baoyu-image-cards`: rename palette color roles from "Zone N" to "Block Color" to prevent AI rendering labels as visible text in images
## 1.97.0 - 2026-04-09
### Features
- `baoyu-image-cards`: add `sketch-notes` style, palette system (`macaron`, `warm`, `neon`), and 3 new presets (`hand-drawn-edu`, `sketch-card`, `sketch-summary`)
### Fixes
- `baoyu-xhs-images`: improve deprecated skill description for better routing
## 1.96.0 - 2026-04-09
### Features
- `baoyu-image-cards`: add image card series skill migrated from `baoyu-xhs-images`, decoupled from Xiaohongshu platform
- `baoyu-xhs-images`: deprecated, migrated to `baoyu-image-cards`
## 1.95.1 - 2026-04-09
### Fixes
- `baoyu-slide-deck`: add `pptxgenjs` dependency and detect image format by magic bytes instead of file extension in PDF merge
## 1.95.0 - 2026-04-08
### Features
- `baoyu-infographic`: add `hand-drawn-edu` style — macaron pastels, hand-drawn wobble, stick figures
- `baoyu-slide-deck`: add `hand-drawn-edu` preset and `macaron` mood dimension with pastel color palette
## 1.94.0 - 2026-04-08
### Features
- `baoyu-cover-image`: add macaron palette and hand-drawn-edu style preset
## 1.93.0 - 2026-04-08
### Features
- `baoyu-article-illustrator`: add `hand-drawn-edu` preset — flowchart + sketch-notes + macaron combination for hand-drawn educational diagrams
### Refactor
- `baoyu-article-illustrator`: extract palette as independent third dimension in Type × Style × Palette system
### Fixes
- `baoyu-article-illustrator`: add explicit style file loading step in workflow
## 1.92.0 - 2026-04-08
### Features
- `baoyu-article-illustrator`: add `macaron` style — soft macaron pastel color blocks (blue, mint, lavender, peach) on warm cream background with optional hand-drawn mode; add `edu-visual` preset
## 1.90.1 - 2026-04-05
### Fixes
+74
View File
@@ -2,6 +2,80 @@
[English](./CHANGELOG.md) | 中文
## 1.100.0 - 2026-04-12
### 新功能
- `baoyu-imagine`:新增 Z.AI GLM-Image 服务商支持,支持 `glm-image``cogview-4-250304` 模型,通过 Z.AI 同步图像 API 调用;配置 `ZAI_API_KEY`(或 `BIGMODEL_API_KEY` 向后兼容)
## 1.99.1 - 2026-04-11
### 修复
- `baoyu-article-illustrator`:未指定 `--model` 时,批处理任务中不再写入 `model` 字段,改由 `baoyu-imagine` 从环境变量或配置中解析默认值
## 1.99.0 - 2026-04-10
### 新功能
- `baoyu-diagram`:新增技能,用于生成可直接发布的 SVG 图表 —— 包括流程图、架构/结构图、示意图(直觉图解)。Claude 直接输出符合统一设计规范的真实 SVG 代码,产物是单个自包含的 `.svg` 文件,内嵌样式并自动支持深色模式,可直接嵌入文章、微信公众号、幻灯片和文档中
## 1.98.0 - 2026-04-10
### 新功能
- `baoyu-xhs-images`:恢复为正式技能(移除废弃警告)
- `baoyu-xhs-images`:新增 `sketch-notes` 风格 —— 手绘教育信息图,马卡龙配色,波动线条,暖奶油背景
- `baoyu-xhs-images`:新增配色系统(`macaron``warm``neon`),支持 `--palette` 参数覆盖风格默认颜色
- `baoyu-xhs-images`:新增 3 个预设:`hand-drawn-edu``sketch-card``sketch-summary`
## 1.97.1 - 2026-04-09
### 修复
- `baoyu-image-cards`:将配色方案中 "Zone N" 角色名改为 "Block Color",防止 AI 将标签文字渲染到图片中
## 1.97.0 - 2026-04-09
### 新功能
- `baoyu-image-cards`:新增 `sketch-notes` 风格、配色系统(`macaron``warm``neon`)及 3 个新预设(`hand-drawn-edu``sketch-card``sketch-summary`
### 修复
- `baoyu-xhs-images`:优化已弃用技能描述以改善路由匹配
## 1.96.0 - 2026-04-09
### 新功能
- `baoyu-image-cards`:新增图片卡片系列技能,从 `baoyu-xhs-images` 迁移,解除小红书平台绑定
- `baoyu-xhs-images`:已弃用,迁移至 `baoyu-image-cards`
## 1.95.1 - 2026-04-09
### 修复
- `baoyu-slide-deck`:添加 `pptxgenjs` 依赖,PDF 合并时通过魔数字节检测图片格式替代文件扩展名判断
## 1.95.0 - 2026-04-08
### 新功能
- `baoyu-infographic`:新增 `hand-drawn-edu` 风格 — 马卡龙柔和色块、手绘线条、火柴人角色
- `baoyu-slide-deck`:新增 `hand-drawn-edu` 预设和 `macaron` 色调维度,含柔和马卡龙色板
## 1.94.0 - 2026-04-08
### 新功能
- `baoyu-cover-image`:新增马卡龙色板和 hand-drawn-edu 风格预设
## 1.93.0 - 2026-04-08
### 新功能
- `baoyu-article-illustrator`:新增 `hand-drawn-edu` 预设 — flowchart + sketch-notes + macaron 组合,用于手绘教育图解
### 重构
- `baoyu-article-illustrator`:将色板(Palette)提取为独立的第三维度,形成 Type × Style × Palette 三维系统
### 修复
- `baoyu-article-illustrator`:在工作流中添加显式的风格文件加载步骤
## 1.92.0 - 2026-04-08
### 新功能
- `baoyu-article-illustrator`:新增 `macaron` 风格 — 马卡龙柔和色块(浅蓝、浅绿、浅紫、浅橙)配暖白底色,可选手绘模式;新增 `edu-visual` 预设
## 1.90.1 - 2026-04-05
### 修复
+2 -1
View File
@@ -1,6 +1,6 @@
# CLAUDE.md
Claude Code marketplace plugin providing AI-powered content generation skills. Version: **1.90.1**.
Claude Code marketplace plugin providing AI-powered content generation skills. Version: **1.97.0**.
## Architecture
@@ -55,6 +55,7 @@ Priority: project `skills/` → `$HOME/.baoyu-skills/` → system-level.
| Skill | Note |
|-------|------|
| `baoyu-image-gen` | Migrated to `baoyu-imagine`. Do NOT add to `.claude-plugin/marketplace.json`. Do NOT update README for this skill. |
| `baoyu-xhs-images` | Migrated to `baoyu-image-cards`. Do NOT add to `.claude-plugin/marketplace.json`. Do NOT update README for this skill. |
## Release Process
+82 -19
View File
@@ -99,7 +99,7 @@ Content generation and publishing skills.
#### baoyu-xhs-images
Xiaohongshu (RedNote) infographic series generator. Breaks down content into 1-10 cartoon-style infographics with **Style × Layout** two-dimensional system.
Xiaohongshu image card series generator. Breaks down content into 1-10 cartoon-style image cards with **Style × Layout** system and optional palette override.
```bash
# Auto-select style and layout
@@ -112,7 +112,10 @@ Xiaohongshu (RedNote) infographic series generator. Breaks down content into 1-1
/baoyu-xhs-images posts/ai-future/article.md --layout dense
# Combine style and layout
/baoyu-xhs-images posts/ai-future/article.md --style tech --layout list
/baoyu-xhs-images posts/ai-future/article.md --style notion --layout list
# Override palette
/baoyu-xhs-images posts/ai-future/article.md --style notion --palette macaron
# Direct content input
/baoyu-xhs-images 今日星座运势
@@ -122,7 +125,9 @@ Xiaohongshu (RedNote) infographic series generator. Breaks down content into 1-1
/baoyu-xhs-images posts/ai-future/article.md --yes --preset knowledge-card
```
**Styles** (visual aesthetics): `cute` (default), `fresh`, `warm`, `bold`, `minimal`, `retro`, `pop`, `notion`, `chalkboard`
**Styles** (visual aesthetics): `cute` (default), `fresh`, `warm`, `bold`, `minimal`, `retro`, `pop`, `notion`, `chalkboard`, `study-notes`, `screen-print`, `sketch-notes`
**Palettes** (optional color override): `macaron`, `warm`, `neon`
**Style Previews**:
@@ -156,7 +161,7 @@ Xiaohongshu (RedNote) infographic series generator. Breaks down content into 1-1
#### baoyu-infographic
Generate professional infographics with 20 layout types and 17 visual styles. Analyzes content, recommends layout×style combinations, and generates publication-ready infographics.
Generate professional infographics with 21 layout types and 21 visual styles. Analyzes content, recommends layout×style combinations, and generates publication-ready infographics.
```bash
# Auto-recommend combinations based on content
@@ -267,9 +272,47 @@ Generate professional infographics with 20 layout types and 17 visual styles. An
| ![knolling](./screenshots/infographic-styles/knolling.webp) | ![lego-brick](./screenshots/infographic-styles/lego-brick.webp) | |
| knolling | lego-brick | |
#### baoyu-diagram
Generate publication-ready SVG diagrams — flowcharts, structural/architecture diagrams, and illustrative intuition diagrams. Claude writes real SVG code directly following a cohesive design system. Output is a single self-contained `.svg` file with embedded styles and auto dark-mode, ready to embed in articles, WeChat posts, slides, Notion, and docs.
```bash
# Auto-route on the verb in the prompt
/baoyu-diagram "how JWT authentication works"
# Force a specific type
/baoyu-diagram "Kubernetes architecture" --type structural
/baoyu-diagram "how attention works" --type illustrative
/baoyu-diagram "CI/CD pipeline" --type flowchart
# From a markdown source file
/baoyu-diagram path/to/content.md
# Language and output path
/baoyu-diagram "微服务架构" --lang zh
/baoyu-diagram "build pipeline" --out docs/build-pipeline.svg
```
**Options**:
| Option | Description |
|--------|-------------|
| `--type <name>` | `flowchart`, `structural`, `illustrative`, `auto` (default) |
| `--lang <code>` | Output language (en, zh, ja, ...) |
| `--out <path>` | Output file path (default: `diagram/{slug}/diagram.svg`) |
**Diagram types**:
| Type | Reader need | Verbs that trigger it |
|------|-------------|------------------------|
| `flowchart` | Walk me through the steps in order | walk through, steps, process, lifecycle, workflow, state machine |
| `structural` | Show me what's inside what, how it's organised | architecture, components, topology, layout, what's inside |
| `illustrative` | Give me the intuition — draw the mechanism | how does X work, explain X, intuition for, why does X do Y |
Not an image-generation skill — no LLM image model is called. Claude writes the SVG by hand with hand-computed layout math, so every diagram honors the design system. Embedded `<style>` block with `@media (prefers-color-scheme: dark)` means the same file renders correctly in both light and dark mode anywhere it's embedded.
#### baoyu-cover-image
Generate cover images for articles with 5 dimensions: Type × Palette × Rendering × Text × Mood. Combines 9 color palettes with 6 rendering styles for 54 unique combinations.
Generate cover images for articles with 5 dimensions: Type × Palette × Rendering × Text × Mood. Combines 11 color palettes with 7 rendering styles for 77 unique combinations.
```bash
# Auto-select all dimensions based on content
@@ -294,8 +337,8 @@ Generate cover images for articles with 5 dimensions: Type × Palette × Renderi
**Five Dimensions**:
- **Type**: `hero`, `conceptual`, `typography`, `metaphor`, `scene`, `minimal`
- **Palette**: `warm`, `elegant`, `cool`, `dark`, `earth`, `vivid`, `pastel`, `mono`, `retro`
- **Rendering**: `flat-vector`, `hand-drawn`, `painterly`, `digital`, `pixel`, `chalk`
- **Palette**: `warm`, `elegant`, `cool`, `dark`, `earth`, `vivid`, `pastel`, `mono`, `retro`, `duotone`, `macaron`
- **Rendering**: `flat-vector`, `hand-drawn`, `painterly`, `digital`, `pixel`, `chalk`, `screen-print`
- **Text**: `none`, `title-only` (default), `title-subtitle`, `text-rich`
- **Mood**: `subtle`, `balanced` (default), `bold`
@@ -473,20 +516,17 @@ Knowledge comic creator with flexible art style × tone combinations. Creates or
#### baoyu-article-illustrator
Smart article illustration skill with Type × Style two-dimension approach. Analyzes article structure, identifies positions requiring visual aids, and generates illustrations.
Smart article illustration skill with Type × Style × Palette three-dimension approach. Analyzes article structure, identifies positions requiring visual aids, and generates illustrations.
```bash
# Auto-select type and style based on content
/baoyu-article-illustrator path/to/article.md
# Specify type
/baoyu-article-illustrator path/to/article.md --type infographic
# Specify style
/baoyu-article-illustrator path/to/article.md --style blueprint
# Combine type and style
# Specify type and style
/baoyu-article-illustrator path/to/article.md --type flowchart --style notion
# With palette override
/baoyu-article-illustrator path/to/article.md --style vector-illustration --palette macaron
```
**Types** (information structure):
@@ -500,7 +540,7 @@ Smart article illustration skill with Type × Style two-dimension approach. Anal
| `framework` | Concept maps, relationship diagrams | Methodologies, architecture |
| `timeline` | Chronological progression | History, project progress |
**Styles** (visual aesthetics):
**Styles** (rendering approach):
| Style | Description | Best For |
|-------|-------------|----------|
@@ -513,6 +553,14 @@ Smart article illustration skill with Type × Style two-dimension approach. Anal
| `editorial` | Magazine-style infographic | Tech explainers, journalism |
| `scientific` | Academic precise diagrams | Biology, chemistry, technical |
**Palettes** (optional color override):
| Palette | Description | Best For |
|---------|-------------|----------|
| `macaron` | Soft pastel blocks (blue, mint, lavender, peach) on warm cream | Educational, knowledge, tutorials |
| `warm` | Warm earth tones on soft peach, no cool colors | Brand, product, lifestyle |
| `neon` | Vibrant neon on dark purple | Gaming, retro, pop culture |
**Style Previews**:
| | | |
@@ -697,6 +745,9 @@ AI SDK-based image generation using OpenAI, Azure OpenAI, Google, OpenRouter, Da
# DashScope with custom size
/baoyu-imagine --prompt "为咖啡品牌设计一张 21:9 横幅海报,包含清晰中文标题" --image banner.png --provider dashscope --model qwen-image-2.0-pro --size 2048x872
# Z.AI GLM-Image
/baoyu-imagine --prompt "一张带清晰中文标题的科技海报" --image out.png --provider zai
# MiniMax
/baoyu-imagine --prompt "A fashion editorial portrait by a bright studio window" --image out.jpg --provider minimax
@@ -727,8 +778,8 @@ AI SDK-based image generation using OpenAI, Azure OpenAI, Google, OpenRouter, Da
| `--image` | Output image path (required) |
| `--batchfile` | JSON batch file for multi-image generation |
| `--jobs` | Worker count for batch mode |
| `--provider` | `google`, `openai`, `azure`, `openrouter`, `dashscope`, `minimax`, `jimeng`, `seedream`, or `replicate` |
| `--model`, `-m` | Model ID or deployment name. Azure uses deployment name; OpenRouter uses full model IDs; MiniMax uses `image-01` / `image-01-live` |
| `--provider` | `google`, `openai`, `azure`, `openrouter`, `dashscope`, `zai`, `minimax`, `jimeng`, `seedream`, or `replicate` |
| `--model`, `-m` | Model ID or deployment name. Azure uses deployment name; OpenRouter uses full model IDs; Z.AI uses `glm-image`; MiniMax uses `image-01` / `image-01-live` |
| `--ar` | Aspect ratio (e.g., `16:9`, `1:1`, `4:3`) |
| `--size` | Size (e.g., `1024x1024`) |
| `--quality` | `normal` or `2k` (default: `2k`) |
@@ -746,6 +797,8 @@ AI SDK-based image generation using OpenAI, Azure OpenAI, Google, OpenRouter, Da
| `GOOGLE_API_KEY` | Google API key | - |
| `GEMINI_API_KEY` | Alias for `GOOGLE_API_KEY` | - |
| `DASHSCOPE_API_KEY` | DashScope API key (Aliyun) | - |
| `ZAI_API_KEY` | Z.AI API key | - |
| `BIGMODEL_API_KEY` | Backward-compatible alias for Z.AI API key | - |
| `MINIMAX_API_KEY` | MiniMax API key | - |
| `REPLICATE_API_TOKEN` | Replicate API token | - |
| `JIMENG_ACCESS_KEY_ID` | Jimeng Volcengine access key | - |
@@ -757,6 +810,8 @@ AI SDK-based image generation using OpenAI, Azure OpenAI, Google, OpenRouter, Da
| `OPENROUTER_IMAGE_MODEL` | OpenRouter model | `google/gemini-3.1-flash-image-preview` |
| `GOOGLE_IMAGE_MODEL` | Google model | `gemini-3-pro-image-preview` |
| `DASHSCOPE_IMAGE_MODEL` | DashScope model | `qwen-image-2.0-pro` |
| `ZAI_IMAGE_MODEL` | Z.AI model | `glm-image` |
| `BIGMODEL_IMAGE_MODEL` | Backward-compatible alias for Z.AI model | `glm-image` |
| `MINIMAX_IMAGE_MODEL` | MiniMax model | `image-01` |
| `REPLICATE_IMAGE_MODEL` | Replicate model | `google/nano-banana-pro` |
| `JIMENG_IMAGE_MODEL` | Jimeng model | `jimeng_t2i_v40` |
@@ -770,6 +825,8 @@ AI SDK-based image generation using OpenAI, Azure OpenAI, Google, OpenRouter, Da
| `OPENROUTER_TITLE` | Optional app name for OpenRouter attribution | - |
| `GOOGLE_BASE_URL` | Custom Google endpoint | - |
| `DASHSCOPE_BASE_URL` | Custom DashScope endpoint | - |
| `ZAI_BASE_URL` | Custom Z.AI endpoint | `https://api.z.ai/api/paas/v4` |
| `BIGMODEL_BASE_URL` | Backward-compatible alias for Z.AI endpoint | - |
| `MINIMAX_BASE_URL` | Custom MiniMax endpoint | `https://api.minimax.io` |
| `REPLICATE_BASE_URL` | Custom Replicate endpoint | - |
| `JIMENG_BASE_URL` | Custom Jimeng endpoint | `https://visual.volcengineapi.com` |
@@ -782,6 +839,7 @@ AI SDK-based image generation using OpenAI, Azure OpenAI, Google, OpenRouter, Da
**Provider Notes**:
- Azure OpenAI: `--model` means Azure deployment name, not the underlying model family.
- DashScope: `qwen-image-2.0-pro` is the recommended default for custom `--size`, `21:9`, and strong Chinese/English text rendering.
- Z.AI: `glm-image` is recommended for posters, diagrams, and text-heavy Chinese/English images. Reference images are not supported.
- MiniMax: `image-01` supports documented custom `width` / `height`; `image-01-live` is lower latency and works best with `--ar`.
- MiniMax reference images are sent as `subject_reference`; the current API is specialized toward character / portrait consistency.
- Jimeng does not support reference images.
@@ -791,7 +849,7 @@ AI SDK-based image generation using OpenAI, Azure OpenAI, Google, OpenRouter, Da
1. If `--provider` is specified → use it
2. If `--ref` is provided and no provider is specified → try Google, then OpenAI, Azure, OpenRouter, Replicate, Seedream, and finally MiniMax
3. If only one API key is available → use that provider
4. If multiple providers are available → default to Google
4. If multiple providers are available → default to Google, then OpenAI, Azure, OpenRouter, DashScope, Z.AI, MiniMax, Replicate, Jimeng, Seedream
#### baoyu-danger-gemini-web
@@ -1091,6 +1149,11 @@ DASHSCOPE_API_KEY=sk-xxx
DASHSCOPE_IMAGE_MODEL=qwen-image-2.0-pro
# DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/api/v1
# Z.AI
ZAI_API_KEY=xxx
ZAI_IMAGE_MODEL=glm-image
# ZAI_BASE_URL=https://api.z.ai/api/paas/v4
# MiniMax
MINIMAX_API_KEY=xxx
MINIMAX_IMAGE_MODEL=image-01
+81 -18
View File
@@ -99,7 +99,7 @@ clawhub install baoyu-markdown-to-html
#### baoyu-xhs-images
小红书信息图系列生成器。将内容拆解为 1-10 张卡通风格信息图,支持 **风格 × 布局** 二维系统。
小红书图片卡片系列生成器。将内容拆解为 1-10 张卡通风格图片卡片,支持 **风格 × 布局** 系统和可选配色覆盖
```bash
# 自动选择风格和布局
@@ -112,7 +112,10 @@ clawhub install baoyu-markdown-to-html
/baoyu-xhs-images posts/ai-future/article.md --layout dense
# 组合风格和布局
/baoyu-xhs-images posts/ai-future/article.md --style tech --layout list
/baoyu-xhs-images posts/ai-future/article.md --style notion --layout list
# 覆盖配色
/baoyu-xhs-images posts/ai-future/article.md --style notion --palette macaron
# 直接输入内容
/baoyu-xhs-images 今日星座运势
@@ -122,7 +125,9 @@ clawhub install baoyu-markdown-to-html
/baoyu-xhs-images posts/ai-future/article.md --yes --preset knowledge-card
```
**风格**(视觉美学):`cute`(默认)、`fresh``warm``bold``minimal``retro``pop``notion``chalkboard`
**风格**(视觉美学):`cute`(默认)、`fresh``warm``bold``minimal``retro``pop``notion``chalkboard``study-notes``screen-print``sketch-notes`
**配色**(可选颜色覆盖):`macaron``warm``neon`
**风格预览**
@@ -156,7 +161,7 @@ clawhub install baoyu-markdown-to-html
#### baoyu-infographic
专业信息图生成器,支持 20 种布局和 17 种视觉风格。分析内容后推荐布局×风格组合,生成可发布的信息图。
专业信息图生成器,支持 21 种布局和 21 种视觉风格。分析内容后推荐布局×风格组合,生成可发布的信息图。
```bash
# 根据内容自动推荐组合
@@ -267,9 +272,47 @@ clawhub install baoyu-markdown-to-html
| ![knolling](./screenshots/infographic-styles/knolling.webp) | ![lego-brick](./screenshots/infographic-styles/lego-brick.webp) | |
| knolling | lego-brick | |
#### baoyu-diagram
生成可直接发布的 SVG 图表 —— 包括流程图、架构/结构图、示意图(直觉图解)。Claude 直接输出符合统一设计规范的真实 SVG 代码,产物是单个自包含的 `.svg` 文件,内嵌样式并自动支持深色模式,可直接嵌入文章、微信公众号、幻灯片、Notion 和各类文档中。
```bash
# 自动根据提示词中的动词路由类型
/baoyu-diagram "JWT 认证流程是怎么工作的"
# 强制指定类型
/baoyu-diagram "Kubernetes 架构" --type structural
/baoyu-diagram "注意力机制原理" --type illustrative
/baoyu-diagram "CI/CD 流水线" --type flowchart
# 从 Markdown 源文件生成
/baoyu-diagram path/to/content.md
# 语言和输出路径
/baoyu-diagram "微服务架构" --lang zh
/baoyu-diagram "build pipeline" --out docs/build-pipeline.svg
```
**参数**
| 参数 | 说明 |
|------|------|
| `--type <name>` | `flowchart`(流程图)、`structural`(结构/架构图)、`illustrative`(示意图)、`auto`(默认,按动词路由) |
| `--lang <code>` | 输出语言(en、zh、ja 等) |
| `--out <path>` | 输出文件路径(默认:`diagram/{slug}/diagram.svg` |
**三种图表类型**
| 类型 | 适用场景 | 触发动词 |
|------|----------|----------|
| `flowchart` | 按顺序走一遍流程 | 流程、步骤、工作流、生命周期、状态机 |
| `structural` | 展示什么包含什么、如何组织 | 架构、组件、拓扑、布局、什么在什么里面 |
| `illustrative` | 建立直觉 —— 画出机制本身 | 怎么工作、原理、为什么、直观解释 |
本技能不调用任何图像生成模型 —— Claude 通过手算坐标直接写 SVG 代码,确保每个图表都遵守设计规范。内嵌的 `<style>` 块包含 `@media (prefers-color-scheme: dark)`,同一个文件在浅色和深色模式下均正确渲染,可嵌入到任意支持 SVG 的宿主环境中。
#### baoyu-cover-image
为文章生成封面图,支持五维定制系统:类型 × 配色 × 渲染 × 文字 × 氛围。9 种配色方案与 6 种渲染风格组合,提供 54 种独特效果。
为文章生成封面图,支持五维定制系统:类型 × 配色 × 渲染 × 文字 × 氛围。11 种配色方案与 7 种渲染风格组合,提供 77 种独特效果。
```bash
# 根据内容自动选择所有维度
@@ -294,8 +337,8 @@ clawhub install baoyu-markdown-to-html
**五个维度**
- **类型 (Type)**`hero``conceptual``typography``metaphor``scene``minimal`
- **配色 (Palette)**`warm``elegant``cool``dark``earth``vivid``pastel``mono``retro`
- **渲染 (Rendering)**`flat-vector``hand-drawn``painterly``digital``pixel``chalk`
- **配色 (Palette)**`warm``elegant``cool``dark``earth``vivid``pastel``mono``retro``duotone``macaron`
- **渲染 (Rendering)**`flat-vector``hand-drawn``painterly``digital``pixel``chalk``screen-print`
- **文字 (Text)**`none``title-only`(默认)、`title-subtitle``text-rich`
- **氛围 (Mood)**`subtle``balanced`(默认)、`bold`
@@ -473,20 +516,17 @@ clawhub install baoyu-markdown-to-html
#### baoyu-article-illustrator
智能文章插图技能,采用类型 × 风格维系统。分析文章结构,识别需要视觉辅助的位置,生成插图。
智能文章插图技能,采用类型 × 风格 × 色板三维系统。分析文章结构,识别需要视觉辅助的位置,生成插图。
```bash
# 根据内容自动选择类型和风格
/baoyu-article-illustrator path/to/article.md
# 指定类型
/baoyu-article-illustrator path/to/article.md --type infographic
# 指定风格
/baoyu-article-illustrator path/to/article.md --style blueprint
# 组合类型和风格
/baoyu-article-illustrator path/to/article.md --type flowchart --style notion
# 使用色板覆盖
/baoyu-article-illustrator path/to/article.md --style vector-illustration --palette macaron
```
**类型**(信息结构):
@@ -500,7 +540,7 @@ clawhub install baoyu-markdown-to-html
| `framework` | 概念图、关系图 | 方法论、架构 |
| `timeline` | 时间线进展 | 历史、项目进度 |
**风格**视觉美学):
**风格**渲染手法):
| 风格 | 描述 | 适用场景 |
|------|------|----------|
@@ -513,6 +553,14 @@ clawhub install baoyu-markdown-to-html
| `editorial` | 杂志风格信息图 | 科技解说、新闻 |
| `scientific` | 学术精确图表 | 生物、化学、技术 |
**色板**(可选配色覆盖):
| 色板 | 描述 | 适用场景 |
|------|------|----------|
| `macaron` | 马卡龙柔和色块(浅蓝、浅绿、浅紫、浅橙)暖白底 | 教育、知识分享、教程 |
| `warm` | 暖色系(橙、赭石、金)无冷色 | 品牌、产品、生活方式 |
| `neon` | 霓虹色(粉、青、黄)深色底 | 游戏、复古、潮流 |
**风格预览**
| | | |
@@ -697,6 +745,9 @@ AI 驱动的生成后端。
# DashScope 自定义尺寸
/baoyu-imagine --prompt "为咖啡品牌设计一张 21:9 横幅海报,包含清晰中文标题" --image banner.png --provider dashscope --model qwen-image-2.0-pro --size 2048x872
# Z.AI GLM-Image
/baoyu-imagine --prompt "一张带清晰中文标题的科技海报" --image out.png --provider zai
# MiniMax
/baoyu-imagine --prompt "A fashion editorial portrait by a bright studio window" --image out.jpg --provider minimax
@@ -727,8 +778,8 @@ AI 驱动的生成后端。
| `--image` | 输出图片路径(必需) |
| `--batchfile` | 多图批量生成的 JSON 文件 |
| `--jobs` | 批量模式的并发 worker 数 |
| `--provider` | `google``openai``azure``openrouter``dashscope``minimax``jimeng``seedream``replicate` |
| `--model`, `-m` | 模型 ID 或部署名。Azure 使用部署名;OpenRouter 使用完整模型 IDMiniMax 使用 `image-01` / `image-01-live` |
| `--provider` | `google``openai``azure``openrouter``dashscope``zai``minimax``jimeng``seedream``replicate` |
| `--model`, `-m` | 模型 ID 或部署名。Azure 使用部署名;OpenRouter 使用完整模型 IDZ.AI 使用 `glm-image`MiniMax 使用 `image-01` / `image-01-live` |
| `--ar` | 宽高比(如 `16:9``1:1``4:3` |
| `--size` | 尺寸(如 `1024x1024` |
| `--quality` | `normal``2k`(默认:`2k` |
@@ -746,6 +797,8 @@ AI 驱动的生成后端。
| `GOOGLE_API_KEY` | Google API 密钥 | - |
| `GEMINI_API_KEY` | `GOOGLE_API_KEY` 的别名 | - |
| `DASHSCOPE_API_KEY` | DashScope API 密钥(阿里云) | - |
| `ZAI_API_KEY` | Z.AI API 密钥 | - |
| `BIGMODEL_API_KEY` | Z.AI API 密钥向后兼容别名 | - |
| `MINIMAX_API_KEY` | MiniMax API 密钥 | - |
| `REPLICATE_API_TOKEN` | Replicate API Token | - |
| `JIMENG_ACCESS_KEY_ID` | 即梦火山引擎 Access Key | - |
@@ -757,6 +810,8 @@ AI 驱动的生成后端。
| `OPENROUTER_IMAGE_MODEL` | OpenRouter 模型 | `google/gemini-3.1-flash-image-preview` |
| `GOOGLE_IMAGE_MODEL` | Google 模型 | `gemini-3-pro-image-preview` |
| `DASHSCOPE_IMAGE_MODEL` | DashScope 模型 | `qwen-image-2.0-pro` |
| `ZAI_IMAGE_MODEL` | Z.AI 模型 | `glm-image` |
| `BIGMODEL_IMAGE_MODEL` | Z.AI 模型向后兼容别名 | `glm-image` |
| `MINIMAX_IMAGE_MODEL` | MiniMax 模型 | `image-01` |
| `REPLICATE_IMAGE_MODEL` | Replicate 模型 | `google/nano-banana-pro` |
| `JIMENG_IMAGE_MODEL` | 即梦模型 | `jimeng_t2i_v40` |
@@ -770,6 +825,8 @@ AI 驱动的生成后端。
| `OPENROUTER_TITLE` | OpenRouter 归因用应用名 | - |
| `GOOGLE_BASE_URL` | 自定义 Google 端点 | - |
| `DASHSCOPE_BASE_URL` | 自定义 DashScope 端点 | - |
| `ZAI_BASE_URL` | 自定义 Z.AI 端点 | `https://api.z.ai/api/paas/v4` |
| `BIGMODEL_BASE_URL` | Z.AI 端点向后兼容别名 | - |
| `MINIMAX_BASE_URL` | 自定义 MiniMax 端点 | `https://api.minimax.io` |
| `REPLICATE_BASE_URL` | 自定义 Replicate 端点 | - |
| `JIMENG_BASE_URL` | 自定义即梦端点 | `https://visual.volcengineapi.com` |
@@ -782,6 +839,7 @@ AI 驱动的生成后端。
**Provider 说明**
- Azure OpenAI`--model` 表示 Azure deployment name,不是底层模型家族名。
- DashScope`qwen-image-2.0-pro` 是自定义 `--size``21:9` 和中英文排版的推荐默认模型。
- Z.AI`glm-image` 适合海报、图表和中英文排版密集的图片生成,暂不支持参考图。
- MiniMax`image-01` 支持官方文档里的自定义 `width` / `height``image-01-live` 更偏低延迟,适合配合 `--ar` 使用。
- MiniMax 参考图会走 `subject_reference`,当前能力更偏角色 / 人像一致性。
- 即梦不支持参考图。
@@ -791,7 +849,7 @@ AI 驱动的生成后端。
1. 如果指定了 `--provider` → 使用指定的
2. 如果传了 `--ref` 且未指定 provider → 依次尝试 Google、OpenAI、Azure、OpenRouter、Replicate、Seedream,最后是 MiniMax
3. 如果只有一个 API 密钥 → 使用对应服务商
4. 如果多个可用 → 默认使用 Google
4. 如果多个可用 → 默认使用 Google,然后依次为 OpenAI、Azure、OpenRouter、DashScope、Z.AI、MiniMax、Replicate、即梦、豆包
#### baoyu-danger-gemini-web
@@ -1091,6 +1149,11 @@ DASHSCOPE_API_KEY=sk-xxx
DASHSCOPE_IMAGE_MODEL=qwen-image-2.0-pro
# DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/api/v1
# Z.AI
ZAI_API_KEY=xxx
ZAI_IMAGE_MODEL=glm-image
# ZAI_BASE_URL=https://api.z.ai/api/paas/v4
# MiniMax
MINIMAX_API_KEY=xxx
MINIMAX_IMAGE_MODEL=image-01
BIN
View File
Binary file not shown.
+196
View File
@@ -8,6 +8,10 @@
"workspaces": [
"packages/*"
],
"dependencies": {
"pdf-lib": "^1.17.1",
"pptxgenjs": "^4.0.1"
},
"devDependencies": {
"@mozilla/readability": "^0.6.0",
"linkedom": "^0.18.12",
@@ -1010,6 +1014,24 @@
"node": ">= 8"
}
},
"node_modules/@pdf-lib/standard-fonts": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz",
"integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==",
"license": "MIT",
"dependencies": {
"pako": "^1.0.6"
}
},
"node_modules/@pdf-lib/upng": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz",
"integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==",
"license": "MIT",
"dependencies": {
"pako": "^1.0.10"
}
},
"node_modules/@types/bun": {
"version": "1.3.11",
"resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.3.11.tgz",
@@ -1302,6 +1324,12 @@
"node": ">=18"
}
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -1912,6 +1940,12 @@
"node": ">= 14"
}
},
"node_modules/https": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz",
"integrity": "sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==",
"license": "ISC"
},
"node_modules/https-proxy-agent": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
@@ -1957,6 +1991,33 @@
"node": ">= 4"
}
},
"node_modules/image-size": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz",
"integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==",
"license": "MIT",
"dependencies": {
"queue": "6.0.2"
},
"bin": {
"image-size": "bin/image-size.js"
},
"engines": {
"node": ">=16.x"
}
},
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
"license": "MIT"
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/is-docker": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
@@ -2058,6 +2119,12 @@
"node": ">=8"
}
},
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
"license": "MIT"
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -2127,6 +2194,18 @@
"graceful-fs": "^4.1.6"
}
},
"node_modules/jszip": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
"license": "(MIT OR GPL-3.0-or-later)",
"dependencies": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"setimmediate": "^1.0.5"
}
},
"node_modules/juice": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/juice/-/juice-11.1.1.tgz",
@@ -2147,6 +2226,15 @@
"node": ">=18.17"
}
},
"node_modules/lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/lighthouse-logger": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.2.tgz",
@@ -3239,6 +3327,12 @@
"quansync": "^0.2.7"
}
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/parse5": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
@@ -3318,6 +3412,18 @@
"node": ">=8"
}
},
"node_modules/pdf-lib": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz",
"integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==",
"license": "MIT",
"dependencies": {
"@pdf-lib/standard-fonts": "^1.0.0",
"@pdf-lib/upng": "^1.0.1",
"pako": "^1.0.11",
"tslib": "^1.11.1"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -3348,6 +3454,27 @@
"node": ">=6"
}
},
"node_modules/pptxgenjs": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pptxgenjs/-/pptxgenjs-4.0.1.tgz",
"integrity": "sha512-TeJISr8wouAuXw4C1F/mC33xbZs/FuEG6nH9FG1Zj+nuPcGMP5YRHl6X+j3HSUnS1f3at6k75ZZXPMZlA5Lj9A==",
"license": "MIT",
"dependencies": {
"@types/node": "^22.8.1",
"https": "^1.0.0",
"image-size": "^1.2.1",
"jszip": "^3.10.1"
}
},
"node_modules/pptxgenjs/node_modules/@types/node": {
"version": "22.19.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz",
"integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
@@ -3364,6 +3491,12 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -3390,6 +3523,15 @@
],
"license": "MIT"
},
"node_modules/queue": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
"license": "MIT",
"dependencies": {
"inherits": "~2.0.3"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -3427,6 +3569,21 @@
"node": ">=6"
}
},
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"license": "MIT",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/reading-time": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz",
@@ -3564,6 +3721,12 @@
"queue-microtask": "^1.2.2"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -3595,6 +3758,12 @@
"node": ">=10"
}
},
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
"license": "MIT"
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -3667,6 +3836,15 @@
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"license": "BSD-3-Clause"
},
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@@ -3784,6 +3962,12 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
},
"node_modules/tsx": {
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
@@ -3849,6 +4033,12 @@
"node": ">=18.17"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"license": "MIT"
},
"node_modules/unified": {
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
@@ -3933,6 +4123,12 @@
"node": ">= 4.0.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/valid-data-url": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz",
+4
View File
@@ -15,5 +15,9 @@
"turndown": "^7.2.2",
"turndown-plugin-gfm": "^1.0.2",
"tsx": "^4.20.5"
},
"dependencies": {
"pdf-lib": "^1.17.1",
"pptxgenjs": "^4.0.1"
}
}
+13 -11
View File
@@ -1,6 +1,6 @@
---
name: baoyu-article-illustrator
description: Analyzes article structure, identifies positions requiring visual aids, generates illustrations with Type × Style two-dimension approach. Use when user asks to "illustrate article", "add images", "generate images for article", or "为文章配图".
description: Analyzes article structure, identifies positions requiring visual aids, generates illustrations with Type × Style × Palette three-dimension approach. Use when user asks to "illustrate article", "add images", "generate images for article", or "为文章配图".
version: 1.57.0
metadata:
openclaw:
@@ -9,18 +9,19 @@ metadata:
# Article Illustrator
Analyze articles, identify illustration positions, generate images with Type × Style consistency.
Analyze articles, identify illustration positions, generate images with Type × Style × Palette consistency.
## Two Dimensions
## Three Dimensions
| Dimension | Controls | Examples |
|-----------|----------|----------|
| **Type** | Information structure | infographic, scene, flowchart, comparison, framework, timeline |
| **Style** | Visual aesthetics | notion, warm, minimal, blueprint, watercolor, elegant |
| **Style** | Rendering approach | notion, warm, minimal, blueprint, watercolor, elegant |
| **Palette** | Color scheme (optional) | macaron, warm, neon — overrides style's default colors |
Combine freely: `--type infographic --style blueprint`
Combine freely: `--type infographic --style vector-illustration --palette macaron`
Or use presets: `--preset tech-explainer` → type + style in one flag. See [Style Presets](references/style-presets.md).
Or use presets: `--preset edu-visual` → type + style + palette in one flag. See [Style Presets](references/style-presets.md).
## Types
@@ -96,13 +97,14 @@ Full procedures: [references/workflow.md](references/workflow.md#step-2-setup--a
| **Q1: Preset or Type** | [Recommended preset], [alt preset], or manual: infographic, scene, flowchart, comparison, framework, timeline, mixed |
| **Q2: Density** | minimal (1-2), balanced (3-5), per-section (Recommended), rich (6+) |
| **Q3: Style** | [Recommended], minimal-flat, sci-fi, hand-drawn, editorial, scene, poster, Other — **skip if preset chosen** |
| Q4: Language | When article language ≠ EXTEND.md setting |
| Q4: Palette | Default (style colors), macaron, warm, neon — **skip if preset includes palette or preferred_palette set** |
| Q5: Language | When article language ≠ EXTEND.md setting |
Full procedures: [references/workflow.md](references/workflow.md#step-3-confirm-settings-)
### Step 4: Generate Outline
Save `outline.md` with frontmatter (type, density, style, image_count) and entries:
Save `outline.md` with frontmatter (type, density, style, palette, image_count) and entries:
```yaml
## Illustration 1
@@ -137,7 +139,7 @@ Insert `![description]({relative-path}/NN-{type}-{slug}.png)` after paragraphs.
```
Article Illustration Complete!
Article: [path] | Type: [type] | Density: [level] | Style: [style]
Article: [path] | Type: [type] | Density: [level] | Style: [style] | Palette: [palette or default]
Images: X/N generated
```
@@ -180,7 +182,7 @@ When input is **pasted content** (no file path), always uses `illustrations/{top
|------|---------|
| [references/workflow.md](references/workflow.md) | Detailed procedures |
| [references/usage.md](references/usage.md) | Command syntax |
| [references/styles.md](references/styles.md) | Style gallery |
| [references/style-presets.md](references/style-presets.md) | Preset shortcuts (type + style) |
| [references/styles.md](references/styles.md) | Style gallery + Palette gallery |
| [references/style-presets.md](references/style-presets.md) | Preset shortcuts (type + style + palette) |
| [references/prompt-construction.md](references/prompt-construction.md) | Prompt templates |
| [references/config/first-time-setup.md](references/config/first-time-setup.md) | First-time setup |
@@ -20,6 +20,8 @@ preferred_style:
name: null # Built-in or custom style name
description: "" # Override/notes
preferred_palette: null # Built-in palette name (macaron|warm|neon) or null
language: null # zh|en|ja|ko|auto
default_output_dir: null # same-dir|illustrations-subdir|independent
@@ -47,6 +49,7 @@ custom_styles:
| `watermark.position` | enum | bottom-right | Position on image |
| `preferred_style.name` | string | null | Style name or null |
| `preferred_style.description` | string | "" | Custom notes/override |
| `preferred_palette` | string | null | Palette override (macaron, warm, neon, or null) |
| `language` | string | null | Output language (null = auto-detect) |
| `default_output_dir` | enum | null | Output directory preference (null = ask each time) |
| `custom_styles` | array | [] | User-defined styles |
@@ -0,0 +1,29 @@
# macaron
Soft macaron pastel color blocks on warm cream
## Background
- Color: Warm Cream (#F5F0E8)
- Texture: Subtle warm paper grain
## Colors
| Role | Color | Hex | Usage |
|------|-------|-----|-------|
| Background | Warm Cream | #F5F0E8 | Primary background |
| Primary Text | Deep Charcoal | #2D2D2D | Headlines, main text, outlines |
| Macaron Blue | Sky Blue | #A8D8EA | Info block fill, cool-toned zones |
| Macaron Mint | Mint Green | #B5E5CF | Info block fill, growth/positive zones |
| Macaron Lavender | Lavender | #D5C6E0 | Info block fill, abstract/concept zones |
| Macaron Peach | Peach | #FFD5C2 | Info block fill, warm-toned zones |
| Accent | Coral Red | #E8655A | Key data, warnings, emphasis |
| Muted Text | Warm Gray | #6B6B6B | Secondary annotations, small labels |
## Accent
Coral Red (#E8655A) for key data, warnings, and emphasis highlights. Use sparingly — one or two elements per illustration.
## Best For
Educational content, knowledge sharing, concept explainers, tutorials, tech summaries, onboarding materials
@@ -0,0 +1,38 @@
# mono-ink
Black ink on pure white with sparse semantic accent colors
## Background
- Color: Pure White (#FFFFFF)
- Texture: Clean, no grain, no tint
## Colors
| Role | Color | Hex | Usage |
|------|-------|-----|-------|
| Background | Pure White | #FFFFFF | Canvas |
| Primary | Near Black | #1A1A1A | All lines, text, figures, arrows |
| Accent (risk/emphasis) | Coral Red | #E8655A | Risk, problem, gap, key emphasis |
| Accent (positive) | Muted Teal | #5FA8A8 | Positive, solution, "after" state |
| Accent (neutral tag) | Dusty Lavender | #9B8AB5 | Neutral tags, category labels |
| Soft Fill | Pale Gray | #F0F0F0 | Subtle zone backgrounds (optional) |
## Accent
Use black ink for all structural elements — lines, text, figures. Accent colors appear only for semantic highlighting: coral red for risks/gaps/problems, muted teal for positive/solution/after-states, dusty lavender for neutral category tags. Total colored pixels must remain under 10% of canvas. Pale gray may back a subtle zone but must never dominate.
## Compatible With
- `ink-notes` (primary, default pairing)
- `minimal` (strict monochrome variation, drops the style's built-in accent)
- `sketch` (pencil + ink hybrid look)
## Not Recommended With
- `sketch-notes` — its "no pure white backgrounds" rule conflicts
- `warm`, `elegant`, `watercolor`, `fantasy-animation` — color-heavy by design, mono-ink strips their identity
## Best For
Professional visual notes, Before/After essays, tech manifestos, framework analogies, whiteboard-presentation explainers
@@ -0,0 +1,29 @@
# neon
Vibrant neon colors on dark backgrounds
## Background
- Color: Deep Purple (#2D1B4E)
- Texture: Subtle grid pattern or solid dark
## Colors
| Role | Color | Hex | Usage |
|------|-------|-----|-------|
| Background | Deep Purple | #2D1B4E | Primary background |
| Alt Background | Dark Teal | #0F4C5C | Alternative sections |
| Primary | Hot Pink | #FF1493 | Main accent |
| Secondary | Electric Cyan | #00FFFF | Supporting elements |
| Tertiary | Neon Yellow | #FFFF00 | Highlights |
| Accent 1 | Lime Green | #32CD32 | Energy, success |
| Accent 2 | Orange | #FF6B35 | Warmth |
| Text | White | #FFFFFF | Text elements |
## Accent
Hot Pink (#FF1493) for primary emphasis. High contrast neon-on-dark creates immediate visual impact.
## Best For
Gaming, retro tech, 80s/90s nostalgic content, bold editorial, trend and pop culture
@@ -0,0 +1,28 @@
# warm
Warm earth tones on soft peach, no cool colors
## Background
- Color: Soft Peach (#FFECD2)
- Texture: Warm paper texture
## Colors
| Role | Color | Hex | Usage |
|------|-------|-----|-------|
| Background | Soft Peach | #FFECD2 | Primary background |
| Outlines | Deep Charcoal | #2D2D2D | All element outlines |
| Primary | Warm Orange | #ED8936 | Main accent color |
| Secondary | Terracotta | #C05621 | Warm depth |
| Tertiary | Golden Yellow | #F6AD55 | Highlights, energy |
| Accent | Deep Brown | #744210 | Grounding, anchoring |
| Text | Warm Charcoal | #4A4A4A | Text elements |
## Accent
Warm Orange (#ED8936) for primary emphasis. Warm-only palette — no cool colors (no green, blue, purple). Modern-retro feel.
## Best For
Product showcases, team introductions, feature grids, brand content, personal growth, lifestyle
@@ -135,10 +135,10 @@ COLORS: Cream background (#F5F0E6), Coral Red (#E07A5F), Mint Green (#81B29A), M
ELEMENTS: Geometric simplified icons, no gradients, playful decorative elements (dots, stars)
```
**Infographic + vector-illustration (warm palette)**:
**Infographic + vector-illustration + warm palette**:
```
Flat vector illustration infographic. Clean black outlines on all elements.
Warm-only color palette, no cool colors.
PALETTE OVERRIDE (warm): Warm-only color palette, no cool colors.
COLORS: Soft Peach background (#FFECD2), Warm Orange (#ED8936),
Terracotta (#C05621), Golden Yellow (#F6AD55), Deep Brown (#744210)
ELEMENTS: Geometric simplified icons, no gradients, rounded corners,
@@ -182,6 +182,33 @@ COLORS: Cream background (#F5F0E6), steps in Coral/Mint/Mustard, black outlines
ELEMENTS: Rounded rectangles, thick arrows, simple icons per step
```
**Flowchart + sketch-notes + macaron palette**:
```
Hand-drawn educational flowchart on warm cream paper. Slight wobble on all lines.
PALETTE: macaron — soft pastel color blocks
COLORS: Warm Cream background (#F5F0E8), zone fills in Macaron Blue (#A8D8EA),
Lavender (#D5C6E0), Mint (#B5E5CF), Coral Red (#E8655A) for emphasis
ELEMENTS: Rounded cards with dashed/solid borders, wavy hand-drawn arrows with labels,
simple stick-figure characters, doodle decorations (stars, underlines)
STYLE: Color fills don't completely fill outlines, hand-drawn lettering, generous white space
```
**Flowchart + ink-notes + mono-ink palette**:
```
Professional hand-drawn visual-note flowchart on pure white. Black ink line work
with slight wobble, à la Mike Rohde sketchnoting.
PALETTE: mono-ink — black ink dominant, sparse semantic accents
COLORS: Pure White background (#FFFFFF), Near Black (#1A1A1A) for all lines,
text, and figures; Coral Red (#E8655A) only for risk/emphasis,
Muted Teal (#5FA8A8) only for positive/solution states
ELEMENTS: Left-to-right stage boxes with rounded-rect frames, wavy hand-drawn
arrows between stages, simple stick-figure characters with role
labels above (e.g., "ML Engineer", "Team Lead"), dashed-border box
for future/empty stage, small doodle icons per stage
STYLE: Hand-lettered titles (bold, oversized), handwritten stage labels and
annotations, generous white space, bottom tagline summarizing takeaway
```
### Comparison
```
@@ -207,15 +234,37 @@ COLORS: Left side Coral (#E07A5F), Right side Mint (#81B29A), cream background
ELEMENTS: Bold icons, black outlines, centered divider line
```
**Comparison + vector-illustration (warm palette)**:
**Comparison + vector-illustration + warm palette**:
```
Flat vector comparison with split layout. Clear visual separation.
Warm-only color palette, no cool colors.
PALETTE OVERRIDE (warm): Warm-only color palette, no cool colors.
COLORS: Left side Warm Orange (#ED8936), Right side Terracotta (#C05621),
Soft Peach background (#FFECD2), Deep Brown (#744210) accents
ELEMENTS: Bold icons, black outlines, centered divider line
```
**Comparison + ink-notes + mono-ink palette** (Before/After, Traditional vs New):
```
Professional hand-drawn sketchnote comparison on pure white. Black ink line work
with slight wobble, à la Mike Rohde sketchnoting.
PALETTE: mono-ink — black ink dominant, sparse semantic accents
COLORS: Pure White background (#FFFFFF), Near Black (#1A1A1A) for all outlines,
text, figures, arrows; Coral Red (#E8655A) reserved for risks/gaps
(left/Before side); Muted Teal (#5FA8A8) reserved for positives
(right/After side). Color accents under 10% of canvas.
LAYOUT: Left | Right split with vertical hand-drawn divider. Hand-lettered
"Before" label (top-left) and "After" label (top-right).
LEFT SIDE: Stick figure(s) with role label above, speech bubble showing the
pain point, bulleted pain-point list in handwritten text.
RIGHT SIDE: Stick figure(s) showing the new state, bulleted improvement list,
small positive-action icons.
BRIDGE: Curved hand-drawn "mindset shift" arrow bridging left → right with
small inline label describing the shift.
BOTTOM: Single-line hand-lettered tagline summarizing the takeaway.
STYLE: Hand-lettered headings (bold, oversized), handwritten body annotations,
generous white space, no computer fonts, no gradients, no shadows.
```
### Framework
```
@@ -239,15 +288,36 @@ COLORS: Cream background (#F5F0E6), nodes in Coral/Mint/Mustard/Blue, black outl
ELEMENTS: Rounded rectangles or circles for nodes, thick connecting lines
```
**Framework + vector-illustration (warm palette)**:
**Framework + vector-illustration + warm palette**:
```
Flat vector framework diagram with geometric nodes and bold connectors.
Warm-only color palette, no cool colors.
PALETTE OVERRIDE (warm): Warm-only color palette, no cool colors.
COLORS: Soft Peach background (#FFECD2), nodes in Warm Orange (#ED8936),
Terracotta (#C05621), Golden Yellow (#F6AD55), black outlines
ELEMENTS: Rounded rectangles or circles for nodes, thick connecting lines
```
**Framework + ink-notes + mono-ink palette** (command center, OS analogy):
```
Professional hand-drawn sketchnote framework on pure white. Black ink line work
with slight wobble, à la Mike Rohde sketchnoting.
PALETTE: mono-ink — black ink dominant, sparse semantic accents
COLORS: Pure White background (#FFFFFF), Near Black (#1A1A1A) for all lines,
text, figures; Dusty Lavender (#9B8AB5) for neutral category tags only;
Coral Red (#E8655A) for emphasis sparingly. Color accents under 10%.
STRUCTURE: Central rounded-rectangle frame as "the system" with hand-lettered
title inside. Inner layer of labeled sub-components (node labels
above each). Outer layer of feeder arrows from stick-figure
operators/users with role labels.
ELEMENTS: Stick figures at the edges with role tags ("Team Lead", "Operator"),
wavy hand-drawn connector arrows with small inline labels, small
doodle icons per component, dashed-border placeholder(s) for
future/empty capabilities.
BOTTOM: Single-line hand-lettered tagline.
STYLE: Hand-lettered headings, handwritten annotations, generous white space,
no computer fonts, no gradients.
```
### Timeline
```
@@ -296,6 +366,39 @@ TEXTURE: Halftone transitions between sides
---
## Palette Override
When a palette is specified (via `--palette` or preset), it overrides the style's default colors:
1. Read style file → get rendering rules (Visual Elements, Style Rules, line treatment)
2. Read palette file (`palettes/<palette>.md`) → get Colors + Background
3. Palette Colors **replace** style's default Color Palette in prompt
4. Palette Background **replaces** style's Background color (keep style's texture description)
5. Build prompt: style rendering instructions + palette colors
**Prompt frontmatter** includes palette when specified:
```yaml
---
illustration_id: 01
type: infographic
style: vector-illustration
palette: macaron
---
```
**Example**: `vector-illustration` + `macaron` palette:
```
Flat vector illustration infographic. Clean black outlines on all elements.
PALETTE: macaron — soft pastel color blocks
COLORS: Warm Cream background (#F5F0E8), Macaron Blue (#A8D8EA), Mint (#B5E5CF),
Lavender (#D5C6E0), Peach (#FFD5C2), Coral Red (#E8655A) for emphasis
ELEMENTS: Geometric simplified icons, no gradients, playful decorative elements
```
When no palette is specified, use the style's built-in Color Palette as before.
---
## What to Avoid
- Vague descriptions ("a nice image")
@@ -1,52 +1,57 @@
# Style Presets
`--preset X` expands to a type + style combination. Users can override either dimension.
`--preset X` expands to a type + style + optional palette combination. Users can override any dimension.
## By Category
### Technical & Engineering
| --preset | Type | Style | Best For |
|----------|------|-------|----------|
| `tech-explainer` | `infographic` | `blueprint` | API docs, system metrics, technical deep-dives |
| `system-design` | `framework` | `blueprint` | Architecture diagrams, system design |
| `architecture` | `framework` | `vector-illustration` | Component relationships, module structure |
| `science-paper` | `infographic` | `scientific` | Research findings, lab results, academic |
| --preset | Type | Style | Palette | Best For |
|----------|------|-------|---------|----------|
| `tech-explainer` | `infographic` | `blueprint` | — | API docs, system metrics, technical deep-dives |
| `system-design` | `framework` | `blueprint` | — | Architecture diagrams, system design |
| `architecture` | `framework` | `vector-illustration` | — | Component relationships, module structure |
| `science-paper` | `infographic` | `scientific` | — | Research findings, lab results, academic |
### Knowledge & Education
| --preset | Type | Style | Best For |
|----------|------|-------|----------|
| `knowledge-base` | `infographic` | `vector-illustration` | Concept explainers, tutorials, how-to |
| `saas-guide` | `infographic` | `notion` | Product guides, SaaS docs, tool walkthroughs |
| `tutorial` | `flowchart` | `vector-illustration` | Step-by-step tutorials, setup guides |
| `process-flow` | `flowchart` | `notion` | Workflow documentation, onboarding flows |
| `warm-knowledge` | `infographic` | `vector-illustration` (warm palette) | Product showcases, team intros, feature cards, brand content |
| --preset | Type | Style | Palette | Best For |
|----------|------|-------|---------|----------|
| `knowledge-base` | `infographic` | `vector-illustration` | — | Concept explainers, tutorials, how-to |
| `saas-guide` | `infographic` | `notion` | — | Product guides, SaaS docs, tool walkthroughs |
| `tutorial` | `flowchart` | `vector-illustration` | — | Step-by-step tutorials, setup guides |
| `process-flow` | `flowchart` | `notion` | — | Workflow documentation, onboarding flows |
| `warm-knowledge` | `infographic` | `vector-illustration` | `warm` | Product showcases, team intros, feature cards, brand content |
| `edu-visual` | `infographic` | `vector-illustration` | `macaron` | Knowledge summaries, concept explainers, educational articles |
| `hand-drawn-edu` | `flowchart` | `sketch-notes` | `macaron` | Hand-drawn educational diagrams, process explainers, onboarding visuals |
| `ink-notes-compare` | `comparison` | `ink-notes` | `mono-ink` | Before/After essays, Traditional vs New, OS-style comparisons, mindset-shift narratives |
| `ink-notes-flow` | `flowchart` | `ink-notes` | `mono-ink` | Professional process explainers, workforce pipelines, hand-drawn technical walkthroughs |
| `ink-notes-framework` | `framework` | `ink-notes` | `mono-ink` | System analogies, command-center diagrams, architecture-as-metaphor, tech manifestos |
### Data & Analysis
| --preset | Type | Style | Best For |
|----------|------|-------|----------|
| `data-report` | `infographic` | `editorial` | Data journalism, metrics reports, dashboards |
| `versus` | `comparison` | `vector-illustration` | Tech comparisons, framework shootouts |
| `business-compare` | `comparison` | `elegant` | Product evaluations, strategy options |
| --preset | Type | Style | Palette | Best For |
|----------|------|-------|---------|----------|
| `data-report` | `infographic` | `editorial` | — | Data journalism, metrics reports, dashboards |
| `versus` | `comparison` | `vector-illustration` | — | Tech comparisons, framework shootouts |
| `business-compare` | `comparison` | `elegant` | — | Product evaluations, strategy options |
### Narrative & Creative
| --preset | Type | Style | Best For |
|----------|------|-------|----------|
| `storytelling` | `scene` | `warm` | Personal essays, reflections, growth stories |
| `lifestyle` | `scene` | `watercolor` | Travel, wellness, lifestyle, creative |
| `history` | `timeline` | `elegant` | Historical overviews, milestones |
| `evolution` | `timeline` | `warm` | Progress narratives, growth journeys |
| --preset | Type | Style | Palette | Best For |
|----------|------|-------|---------|----------|
| `storytelling` | `scene` | `warm` | — | Personal essays, reflections, growth stories |
| `lifestyle` | `scene` | `watercolor` | — | Travel, wellness, lifestyle, creative |
| `history` | `timeline` | `elegant` | — | Historical overviews, milestones |
| `evolution` | `timeline` | `warm` | — | Progress narratives, growth journeys |
### Editorial & Opinion
| --preset | Type | Style | Best For |
|----------|------|-------|----------|
| `opinion-piece` | `scene` | `screen-print` | Op-eds, commentary, critical essays |
| `editorial-poster` | `comparison` | `screen-print` | Debate, contrasting viewpoints |
| `cinematic` | `scene` | `screen-print` | Dramatic narratives, cultural essays |
| --preset | Type | Style | Palette | Best For |
|----------|------|-------|---------|----------|
| `opinion-piece` | `scene` | `screen-print` | — | Op-eds, commentary, critical essays |
| `editorial-poster` | `comparison` | `screen-print` | — | Debate, contrasting viewpoints |
| `cinematic` | `scene` | `screen-print` | — | Dramatic narratives, cultural essays |
## Content Type → Preset Recommendations
@@ -55,15 +60,17 @@ Use this table during Step 3 to recommend presets based on Step 2 content analys
| Content Type (Step 2) | Primary Preset | Alternatives |
|------------------------|----------------|--------------|
| Technical | `tech-explainer` | `system-design`, `architecture` |
| Tutorial | `tutorial` | `process-flow`, `knowledge-base` |
| Tutorial | `tutorial` | `process-flow`, `knowledge-base`, `edu-visual` |
| Methodology / Framework | `system-design` | `architecture`, `process-flow` |
| Data / Metrics | `data-report` | `versus`, `tech-explainer` |
| Comparison / Review | `versus` | `business-compare`, `editorial-poster` |
| Comparison / Review | `versus` | `business-compare`, `editorial-poster`, `ink-notes-compare` |
| Manifesto / Mindset shift / Professional visual note | `ink-notes-compare` | `ink-notes-framework`, `ink-notes-flow` |
| Narrative / Personal | `storytelling` | `lifestyle`, `evolution` |
| Opinion / Editorial | `opinion-piece` | `cinematic`, `editorial-poster` |
| Historical / Timeline | `history` | `evolution` |
| Academic / Research | `science-paper` | `tech-explainer`, `data-report` |
| SaaS / Product | `saas-guide` | `knowledge-base`, `process-flow`, `warm-knowledge` |
| Education / Knowledge | `edu-visual` | `knowledge-base`, `tutorial`, `hand-drawn-edu` |
## Override Examples
@@ -43,6 +43,7 @@ Use Core Styles for most cases. See full Style Gallery below for granular contro
| `sketch` | Raw pencil notebook style | Brainstorming, creative exploration |
| `screen-print` | Bold poster art, halftone textures, limited colors | Opinion, editorial, cultural, cinematic |
| `sketch-notes` | Soft hand-drawn warm notes | Educational, warm notes |
| `ink-notes` | Black ink on pure white, sparse semantic accents, hand-lettered (à la Mike Rohde's sketchnoting) | Before/After essays, tech manifestos, framework analogies |
| `vintage` | Aged parchment historical | Historical, heritage |
Full specifications: `references/styles/<style>.md`
@@ -81,6 +82,7 @@ Full specifications: `references/styles/<style>.md`
| How-to, steps, workflow, process, tutorial | flowchart | vector-illustration, notion |
| Framework, model, architecture, principles | framework | blueprint, vector-illustration |
| vs, pros/cons, before/after, alternatives | comparison | vector-illustration, notion |
| Manifesto, mindset shift, workforce, OS, whiteboard, professional visual note | comparison / framework | ink-notes |
| Story, emotion, journey, experience, personal | scene | warm, watercolor |
| History, timeline, progress, evolution | timeline | elegant, warm |
| Productivity, SaaS, tool, app, software | infographic | notion, vector-illustration |
@@ -98,12 +100,6 @@ Full specifications: `references/styles/<style>.md`
- Modern, professional, highly readable
- Perfect for knowledge articles and tutorials
### infographic + vector-illustration (warm palette)
- Same rendering: flat vector, black outlines, geometric simplification
- Warm-only palette: terracotta, gold, brown tones on soft peach
- Modern-retro feel, approachable and brand-friendly
- Best for product showcases, team intros, feature grids, brand content
### flowchart + vector-illustration
- Bold arrows and connectors
- Distinct step containers with icons
@@ -200,3 +196,29 @@ Full specifications: `references/styles/<style>.md`
- Limited color coding (one color per concept level)
- Clean silhouette-based iconography
- Poster-style hierarchy with bold typography
---
## Palette Gallery
Palettes override a style's default colors. Combine any style with any palette: `--style vector-illustration --palette macaron`.
| Palette | Description | Best For |
|---------|-------------|----------|
| `macaron` | Soft pastel blocks (blue, mint, lavender, peach) on warm cream | Educational, knowledge, tutorials |
| `warm` | Warm earth tones (orange, terracotta, gold) on soft peach, no cool colors | Brand, product, lifestyle |
| `neon` | Vibrant neon (pink, cyan, yellow) on dark purple | Gaming, retro, pop culture |
| `mono-ink` | Black ink on pure white with sparse semantic accents (coral red, muted teal, dusty lavender) | Professional visual notes, Before/After, manifestos |
Full specifications: `references/palettes/<palette>.md`
When no palette is specified, the style's built-in Color Palette is used.
## Palette Override Rules
1. Read style file → rendering rules (Visual Elements, Style Rules)
2. Read palette file → Colors + Background
3. Palette colors **replace** style's default Color Palette
4. Palette Background **replaces** style's default Background color
5. Style's texture description is preserved
@@ -0,0 +1,90 @@
# ink-notes
Professional black-ink visual notes on pure white, in the tradition of Mike Rohde's sketchnoting
## Compared to sketch-notes
`ink-notes` and `sketch-notes` are distinct styles. Pick the right one:
| | `sketch-notes` | `ink-notes` |
|---|---|---|
| Background | Warm Off-White #FAF8F0 with paper grain | Pure White #FFFFFF, clean, no texture |
| Palette | Soft warm accents (orange, mustard, sage, light blue) | Black ink dominant + sparse semantic accents |
| Feel | Soft, warm, educational, approachable | Professional, structured, whiteboard-presentation |
| Best For | Friendly tutorials, onboarding, casual explainers | Before/After essays, tech manifestos, framework analogies |
When in doubt: warm & friendly → `sketch-notes`. Disciplined & professional → `ink-notes`.
## Design Aesthetic
Disciplined hand-drawn visual note. Confident black ink line work with slight wobble, hand-lettered typography, and sparse color accents used only for semantic emphasis. Feels like a skilled visual notetaker's whiteboard presentation — clean, structured, intentionally hand-drawn rather than decorative.
## Background
- Color: Pure White (#FFFFFF)
- Texture: Clean, no grain, no tint
## Color Palette
| Role | Color | Hex | Usage |
|------|-------|-----|-------|
| Background | Pure White | #FFFFFF | Canvas |
| Primary Ink | Near Black | #1A1A1A | All lines, text, figures, arrows |
| Accent Warm | Coral Red | #E8655A | Risk, problem, gap, emphasis |
| Accent Cool | Muted Teal | #5FA8A8 | Positive, solution, "after" state |
| Accent Neutral | Dusty Lavender | #9B8AB5 | Neutral tags, category labels |
| Soft Fill | Pale Gray | #F0F0F0 | Subtle zone backgrounds (optional) |
Color accents must remain under 10% of canvas area and only carry semantic meaning. Black ink does the structural work.
## Visual Elements
- Black ink line work with intentional slight wobble on all strokes
- Hand-lettered titles (bold, oversized) and handwritten body annotations
- Simple stick-figure characters with expressive poses (pointing, thinking, walking)
- Role labels above characters (e.g., "Tech Lead", "Compliance Officer")
- Thought bubbles and speech bubbles with hand-drawn outlines
- Rounded-rectangle frames for content groupings
- Dashed-border rectangles for placeholder, "coming next", or empty states
- Curvy hand-drawn arrows with small inline labels
- Vertical or horizontal dividers between comparison zones ("Before" | "After")
- "Mindset shift" curved arrow bridging two zones
- Bottom tagline: single-line hand-lettered conclusion that points the takeaway
- Stars, asterisks, underlines for emphasis — used sparingly
## Style Rules
### Do
- Keep background pure white with no texture or tint
- Let black ink dominate outlines, text, and figures
- Use accent colors only for semantic highlighting
- Keep all type hand-lettered — no computer-generated fonts
- Maintain confident line quality (wobble, not mess)
- Include a bottom tagline summarizing the main takeaway
- Structure content into clear zones with visible dividers
- Use dashed boxes for future, empty, or placeholder states
### Don't
- Use warm off-white or paper-textured backgrounds (that is sketch-notes' territory)
- Fill large zones with color blocks
- Use more than 3 accent colors per image
- Use perfect geometric shapes — preserve hand-drawn wobble
- Clutter with decorative doodles; every element must carry meaning
- Use gradients, shadows, or computer-generated fonts
## Type Compatibility
| Type | Rating | Notes |
|------|--------|-------|
| comparison | ✓✓ | Best fit — Before/After, Traditional vs New, side-by-side contrasts |
| framework | ✓✓ | OS-style command centers, layered architectures, organizational models |
| flowchart | ✓✓ | Process explainers with labeled stages, workforce pipelines |
| infographic | ✓ | Multi-zone technical summaries, manifesto-style posters |
| timeline | ✓ | Hand-drawn horizontal arrow with era markers and milestones |
| scene | ✗ | Not recommended — lacks scenic space |
## Best For
Product and engineering essays, tech manifestos, framework introductions, Before/After narratives, OS-level comparisons, workforce and organizational analogies, visual summaries of talks, thought-leadership articles
@@ -24,26 +24,6 @@ Flat vector illustration with no gradients or 3D effects. Clear, uniform-thickne
| Accent 2 | Rock Blue | #577590 | Cool balance |
| Text | Black | #1A1A1A | Text elements |
## Palette Variants
### Warm Palette
Use with `--preset warm-knowledge` or specify in prompt. For product showcases, team introductions, feature grids, brand content.
| Role | Color | Hex | Usage |
|------|-------|-----|-------|
| Background | Soft Peach | #FFECD2 | Primary background |
| Outlines | Deep Charcoal | #2D2D2D | All element outlines |
| Primary | Warm Orange | #ED8936 | Main accent color |
| Secondary | Terracotta | #C05621 | Warm depth |
| Tertiary | Golden Yellow | #F6AD55 | Highlights, energy |
| Accent | Deep Brown | #744210 | Grounding, anchoring |
| Text | Warm Charcoal | #4A4A4A | Text elements |
Warm-only palette, no cool colors (no green, blue, purple). Modern-retro feel.
Default palette includes Mint Green (#81B29A) and Rock Blue (#577590) for colorful educational content. Warm palette uses exclusively warm tones for brand/product/team content.
## Visual Elements
- All objects have closed black outlines (coloring book style)
@@ -211,9 +211,22 @@ If no `preferred_style` (present Core Styles first):
| `poster` | screen-print | Opinion, editorial, cultural, cinematic |
Style selection based on Type × Style compatibility matrix (styles.md).
Full specs: `styles/<style>.md`
**In Step 5.1**, read `styles/<style>.md` for visual elements and rendering rules.
### Q4: Image Text Language ⚠️ REQUIRED when article language ≠ EXTEND.md `language`
### Q4: Palette (optional)
If preset did not specify a palette, and the user may benefit from a palette override, offer available palettes:
- Default (use style's built-in colors) (Recommended)
- `macaron` — soft pastel blocks on warm cream
- `warm` — warm earth tones, no cool colors
- `neon` — vibrant neon on dark backgrounds
**Skip if**: preset already resolved palette, or `preferred_palette` set in EXTEND.md.
See Palette Gallery in [styles.md](styles.md#palette-gallery) and full specs in `palettes/<palette>.md`.
### Q5: Image Text Language ⚠️ REQUIRED when article language ≠ EXTEND.md `language`
Detect article language from content. If different from EXTEND.md `language` setting, MUST ask:
- Article language (match article content) (Recommended)
@@ -294,16 +307,18 @@ For each illustration in the outline:
style: custom-flat-vector
---
```
3. **Follow type-specific template** from [prompt-construction.md](prompt-construction.md)
4. **Prompt quality requirements** (all REQUIRED):
3. **Load style specs**: Read `styles/<style>.md` for visual elements, style rules, and rendering instructions
4. **Load palette specs** (if palette specified): Read `palettes/<palette>.md` for colors and background. Palette colors **replace** the style's default Color Palette. If no palette specified, use the style's built-in colors.
5. **Follow type-specific template** from [prompt-construction.md](prompt-construction.md), using rendering from style + colors from palette (or style default)
6. **Prompt quality requirements** (all REQUIRED):
- `Layout`: Describe overall composition (grid / radial / hierarchical / left-right / top-down)
- `ZONES`: Describe each visual area with specific content, not vague descriptions
- `LABELS`: Use **actual numbers, terms, metrics, quotes from the article** — NOT generic placeholders
- `COLORS`: Specify hex codes with semantic meaning (e.g., `Coral (#E07A5F) for emphasis`)
- `STYLE`: Describe line treatment, texture, mood, character rendering
- `COLORS`: Specify hex codes from palette (or style default) with semantic meaning
- `STYLE`: Describe line treatment, texture, mood, character rendering per style rules
- `ASPECT`: Specify ratio (e.g., `16:9`)
5. **Apply defaults**: composition requirements, character rendering, text guidelines, watermark
6. **Backup rule**: If prompt file exists, rename to `prompts/NN-{type}-{slug}-backup-YYYYMMDD-HHMMSS.md`
7. **Apply defaults**: composition requirements, character rendering, text guidelines, watermark
8. **Backup rule**: If prompt file exists, rename to `prompts/NN-{type}-{slug}-backup-YYYYMMDD-HHMMSS.md`
**Verification** ⛔: Before proceeding to 5.2, confirm ALL prompt files exist:
```
@@ -0,0 +1,85 @@
import assert from "node:assert/strict";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
import test from "node:test";
const execFileAsync = promisify(execFile);
const repoRoot = path.resolve(import.meta.dirname, "..", "..", "..");
const scriptPath = path.join(repoRoot, "skills", "baoyu-article-illustrator", "scripts", "build-batch.ts");
async function makeFixture(): Promise<{
root: string;
outlinePath: string;
promptsDir: string;
outputPath: string;
}> {
const root = await fs.mkdtemp(path.join(os.tmpdir(), "baoyu-article-illustrator-build-batch-"));
const outlinePath = path.join(root, "outline.md");
const promptsDir = path.join(root, "prompts");
const outputPath = path.join(root, "batch.json");
await fs.mkdir(promptsDir, { recursive: true });
await fs.writeFile(
outlinePath,
`## Illustration 1
**Position**: demo
**Purpose**: demo
**Visual Content**: demo
**Filename**: 01-demo.png
`,
);
await fs.writeFile(path.join(promptsDir, "01-demo.md"), "A demo prompt\n");
return { root, outlinePath, promptsDir, outputPath };
}
async function runBuildBatch(args: string[]): Promise<void> {
await execFileAsync(process.execPath, ["--import", "tsx", scriptPath, ...args], {
cwd: repoRoot,
});
}
test("build-batch omits default model so baoyu-imagine can resolve env or EXTEND defaults", async () => {
const fixture = await makeFixture();
await runBuildBatch([
"--outline",
fixture.outlinePath,
"--prompts",
fixture.promptsDir,
"--output",
fixture.outputPath,
]);
const batch = JSON.parse(await fs.readFile(fixture.outputPath, "utf8")) as {
tasks: Array<Record<string, unknown>>;
};
assert.equal(batch.tasks.length, 1);
assert.equal(batch.tasks[0]?.provider, "replicate");
assert.equal(Object.hasOwn(batch.tasks[0]!, "model"), false);
});
test("build-batch preserves explicit model overrides", async () => {
const fixture = await makeFixture();
await runBuildBatch([
"--outline",
fixture.outlinePath,
"--prompts",
fixture.promptsDir,
"--output",
fixture.outputPath,
"--model",
"acme/custom-model",
]);
const batch = JSON.parse(await fs.readFile(fixture.outputPath, "utf8")) as {
tasks: Array<Record<string, unknown>>;
};
assert.equal(batch.tasks[0]?.model, "acme/custom-model");
});
@@ -8,7 +8,7 @@ type CliArgs = {
outputPath: string | null;
imagesDir: string | null;
provider: string;
model: string;
model: string | null;
aspectRatio: string;
quality: string;
jobs: number | null;
@@ -30,7 +30,7 @@ Options:
--output <path> Path to output batch.json
--images-dir <path> Directory for generated images
--provider <name> Provider for baoyu-imagine batch tasks (default: replicate)
--model <id> Model for baoyu-imagine batch tasks (default: google/nano-banana-pro)
--model <id> Explicit model for baoyu-imagine batch tasks (default: resolved by baoyu-imagine config/env)
--ar <ratio> Aspect ratio for all tasks (default: 16:9)
--quality <level> Quality for all tasks (default: 2k)
--jobs <count> Recommended worker count metadata (optional)
@@ -44,7 +44,7 @@ function parseArgs(argv: string[]): CliArgs {
outputPath: null,
imagesDir: null,
provider: "replicate",
model: "google/nano-banana-pro",
model: null,
aspectRatio: "16:9",
quality: "2k",
jobs: null,
@@ -132,15 +132,16 @@ async function main(): Promise<void> {
}
const imageDir = args.imagesDir ?? path.dirname(args.outputPath);
tasks.push({
const task: Record<string, unknown> = {
id: `illustration-${String(entry.index).padStart(2, "0")}`,
promptFiles: [promptFile],
image: path.join(imageDir, entry.filename),
provider: args.provider,
model: args.model,
ar: args.aspectRatio,
quality: args.quality,
});
};
if (args.model) task.model = args.model;
tasks.push(task);
}
const output: Record<string, unknown> = { tasks };
+47 -26
View File
@@ -29,9 +29,9 @@ Create original knowledge comics with flexible art style × tone combinations.
| Option | Values | Description |
|--------|--------|-------------|
| `--art` | ligne-claire (default), manga, realistic, ink-brush, chalk | Art style / rendering technique |
| `--art` | ligne-claire (default), manga, realistic, ink-brush, chalk, minimalist | Art style / rendering technique |
| `--tone` | neutral (default), warm, dramatic, romantic, energetic, vintage, action | Mood / atmosphere |
| `--layout` | standard (default), cinematic, dense, splash, mixed, webtoon | Panel arrangement |
| `--layout` | standard (default), cinematic, dense, splash, mixed, webtoon, four-panel | Panel arrangement |
| `--aspect` | 3:4 (default, portrait), 4:3 (landscape), 16:9 (widescreen) | Page aspect ratio |
| `--lang` | auto (default), zh, en, ja, etc. | Output language |
@@ -55,6 +55,7 @@ Details: [references/partial-workflows.md](references/partial-workflows.md)
| `realistic` | 写实 | Digital painting, realistic proportions, sophisticated |
| `ink-brush` | 水墨 | Chinese brush strokes, ink wash effects |
| `chalk` | 粉笔 | Chalkboard aesthetic, hand-drawn warmth |
| `minimalist` | 极简 | Clean black line art, limited spot color, stick-figure characters |
### Tones (基调)
@@ -77,6 +78,8 @@ Presets with special rules beyond art+tone:
| `--style ohmsha` | `--art manga --tone neutral` | Visual metaphors, NO talking heads, gadget reveals |
| `--style wuxia` | `--art ink-brush --tone action` | Qi effects, combat visuals, atmospheric elements |
| `--style shoujo` | `--art manga --tone romantic` | Decorative elements, eye details, romantic beats |
| `--style concept-story` | `--art manga --tone warm` | Visual symbol system, growth arc, dialogue+action balance |
| `--style four-panel` | `--art minimalist --tone neutral --layout four-panel` | 起承转合 4-panel structure, B&W + spot color, stick-figure characters |
### Compatibility Matrix
@@ -87,6 +90,7 @@ Presets with special rules beyond art+tone:
| realistic | neutral, warm, dramatic, vintage | action | romantic, energetic |
| ink-brush | neutral, dramatic, action, vintage | warm | romantic, energetic |
| chalk | neutral, warm, energetic | vintage | dramatic, action, romantic |
| minimalist | neutral | warm, energetic | dramatic, vintage, romantic, action |
Details: [references/auto-selection.md](references/auto-selection.md)
@@ -101,6 +105,8 @@ Content signals determine default art + tone + layout (or preset):
| Personal story, mentor | ligne-claire + warm |
| Martial arts, wuxia | **wuxia** preset |
| Romance, school life | **shoujo** preset |
| Psychology, motivation, business narrative | **concept-story** preset |
| Business allegory, fable, parable, short insight, 四格 | **four-panel** preset |
| Biography, balanced | ligne-claire + neutral |
**When preset is recommended**: Load `references/presets/{preset}.md` and apply all special rules.
@@ -172,9 +178,9 @@ Comic Progress:
- [ ] Step 4: Review outline (conditional)
- [ ] Step 5: Generate prompts
- [ ] Step 6: Review prompts (conditional)
- [ ] Step 7: Generate images ⚠️ CHARACTER REF REQUIRED
- [ ] 7.1 Generate character sheet FIRST → characters/characters.png
- [ ] 7.2 Generate pages WITH --ref characters/characters.png
- [ ] Step 7: Generate images
- [ ] 7.1 Generate character sheet (if needed) → characters/characters.png
- [ ] 7.2 Generate pages (with --ref if character sheet exists)
- [ ] Step 8: Merge to PDF
- [ ] Step 9: Completion report
```
@@ -205,16 +211,24 @@ Analyze → [Check Existing?] → [Confirm: Style + Reviews] → Storyboard →
| 4 | Review outline (if requested) | User approval |
| 5 | Generate prompts | `prompts/*.md` |
| 6 | Review prompts (if requested) | User approval |
| **7.1** | **Generate character sheet FIRST** | `characters/characters.png` |
| **7.2** | Generate pages **with character ref** | `*.png` files |
| 7.1 | Generate character sheet (if needed) | `characters/characters.png` |
| 7.2 | Generate pages (with character ref if available) | `*.png` files |
| 8 | Merge to PDF | `{slug}.pdf` |
| 9 | Completion report | Summary |
### Step 7: Image Generation ⚠️ CRITICAL
### Step 7: Image Generation
**Character reference is MANDATORY for visual consistency.**
**7.1 Generate character sheet (conditional)**:
**7.1 Generate character sheet first**:
Character sheet is recommended for multi-page comics with recurring characters, but **NOT required** for all presets:
| Condition | Action |
|-----------|--------|
| Multi-page comic with detailed characters | Generate character sheet (recommended) |
| Preset with simplified characters (e.g., four-panel minimalist) | Skip — prompt descriptions are sufficient |
| Single-page comic | Skip unless characters are complex |
**When generating character sheet**:
- **Backup rule**: If `characters/characters.png` exists, rename to `characters/characters-backup-YYYYMMDD-HHMMSS.png`
- Invoke an installed image generation skill such as `baoyu-imagine`
- Read that skill's `SKILL.md` and follow its documented interface rather than calling its scripts directly
@@ -222,18 +236,25 @@ Analyze → [Check Existing?] → [Confirm: Style + Reviews] → Storyboard →
- Save output to `characters/characters.png`
- Use aspect ratio `4:3`
**Compress character sheet** (recommended):
Compress to reduce token usage when used as reference image:
**Compress character sheet** (recommended when using as `--ref`):
- Use available image compression skill (if any)
- Or system tools: `pngquant`, `optipng`, `sips` (macOS)
- **Keep PNG format**, lossless compression preferred
- Or system tools: `sips -s format jpeg -s formatOptions 80 input.png --out output.jpg` (macOS)
- Or: `pngquant --quality=65-80 input.png -o output.png`
- Compression reduces API payload size and avoids `--ref` failures
**7.2 Generate each page WITH character reference**:
**7.2 Generate each page**:
| Skill Capability | Strategy |
|------------------|----------|
| Supports `--ref` | Pass `characters/characters.png` with EVERY page |
| No `--ref` support | Prepend character descriptions to EVERY prompt file |
| Character Sheet | Skill Capability | Strategy |
|-----------------|------------------|----------|
| Exists | Supports `--ref` | Pass `characters/characters.png` with EVERY page |
| Exists | No `--ref` support | Prepend character descriptions to EVERY prompt file |
| Skipped | — | Prompt file contains all character descriptions inline |
**`--ref` failure recovery**: If generation fails with `--ref`:
1. **Compress**: Convert reference image to JPEG with reduced quality:
`sips -s format jpeg -s formatOptions 70 characters.png --out characters-compressed.jpg`
2. **Retry** with compressed image as `--ref`
3. **If still fails**: Fall back to generating WITHOUT `--ref` (prompt-only, character descriptions embedded in prompt text)
**Backup rules for page generation**:
- If prompt file exists: rename to `prompts/NN-{cover|page}-[slug]-backup-YYYYMMDD-HHMMSS.md`
@@ -241,8 +262,8 @@ Compress to reduce token usage when used as reference image:
- Invoke the installed image generation skill for each page
- Use `prompts/01-page-xxx.md` as the prompt-file input
- Save output to `01-page-xxx.png`
- Use aspect ratio `3:4`
- If the chosen skill supports reference images, pass `characters/characters.png` as `--ref`
- Use aspect ratio from storyboard (default `3:4`, preset may override)
- If character sheet exists and skill supports reference images, pass as `--ref`
**Full workflow details**: [references/workflow.md](references/workflow.md)
@@ -273,10 +294,10 @@ Schema: [references/config/preferences-schema.md](references/config/preferences-
- [ohmsha-guide.md](references/ohmsha-guide.md) - Ohmsha manga specifics
**Style Definitions**:
- `references/art-styles/` - Art styles (ligne-claire, manga, realistic, ink-brush, chalk)
- `references/art-styles/` - Art styles (ligne-claire, manga, realistic, ink-brush, chalk, minimalist)
- `references/tones/` - Tones (neutral, warm, dramatic, romantic, energetic, vintage, action)
- `references/presets/` - Presets with special rules (ohmsha, wuxia, shoujo)
- `references/layouts/` - Layouts (standard, cinematic, dense, splash, mixed, webtoon)
- `references/presets/` - Presets with special rules (ohmsha, wuxia, shoujo, concept-story, four-panel)
- `references/layouts/` - Layouts (standard, cinematic, dense, splash, mixed, webtoon, four-panel)
**Workflow**:
- [workflow.md](references/workflow.md) - Full workflow details
@@ -306,6 +327,6 @@ Schema: [references/config/preferences-schema.md](references/config/preferences-
- Maintain style consistency via session ID
- **Step 2 confirmation required** - do not skip
- **Steps 4/6 conditional** - only if user requested in Step 2
- **Step 7.1 character sheet MUST be generated before pages** - ensures consistency
- **Step 7.2 EVERY page MUST reference characters** - use `--ref` or embed descriptions
- **Step 7.1 character sheet** - recommended for multi-page comics, optional for simple presets
- **Step 7.2 character reference** - use `--ref` if sheet exists; compress/convert on failure; fall back to prompt-only
- Watermark/language configured once in EXTEND.md
@@ -0,0 +1,84 @@
# minimalist
极简画风 - Clean black line art, limited spot color, simplified stick-figure characters
## Overview
Minimalist cartoon illustration characterized by clean black line art on white background with very limited spot color for emphasis. Characters are simplified to near-stick-figure abstraction, focusing on gesture and concept rather than anatomical detail. Designed for business allegory, quick-read educational content, and concept illustration.
## Line Work
- Clean, uniform black lines (1.5-2px)
- No hatching, cross-hatching, or shading techniques
- Minimal detail — every line serves a purpose
- Bold outlines for characters, thinner lines for props/labels
- No decorative flourishes or ornamental lines
## Character Design
- Highly simplified, stick-figure-like business characters
- Circle or oval heads with minimal facial features (dot eyes, simple line mouth)
- Body as simple geometric shapes or line constructions
- Distinguishing features through props only (tie, hat, briefcase, glasses)
- No anatomical detail — expressive through posture and gesture
- 4-5 head height proportions (squat, iconic)
## Background Treatment
- Mostly blank/white — negative space is a design element
- Minimal environmental cues (a line for ground, simple desk outline)
- Concept labels and text annotations replace detailed environments
- Icons and symbols over realistic rendering
- No perspective or spatial depth
## Color Approach
- Primarily black and white (90%+ of the image)
- 1-2 spot accent colors for emphasis on key concepts
- Accent color used sparingly: highlighting key objects, text labels, concept indicators
- No gradients, no shading, no color fills on backgrounds
- Color draws the eye to the most important element in each panel
## Default Color Palette
| Role | Color | Hex |
|------|-------|-----|
| Primary | Black ink | `#1A1A1A` |
| Background | Clean white | `#FFFFFF` |
| Accent 1 | Spot orange | `#FF6B35` |
| Accent 2 | Spot blue (optional) | `#3182CE` |
| Text labels | Dark gray | `#4A4A4A` |
| Panel border | Medium gray | `#666666` |
## Visual Elements
- Text labels with accent-color backgrounds or underlines for key terms
- Simple icons: arrows, circles, checkmarks, crosses
- Concept highlight boxes with spot color
- Minimal speech bubbles (simple oval or rectangle, thin black outline)
- No sound effects, no motion lines, no screen tones
## Quality Markers
- ✓ Clean, purposeful line work with no unnecessary detail
- ✓ 90%+ black-and-white with strategic spot color
- ✓ Simplified characters readable at small sizes
- ✓ Text labels integrated naturally into panels
- ✓ Strong negative space usage
- ✓ Every element serves the narrative point
## Compatibility
| Tone | Fit | Notes |
|------|-----|-------|
| neutral | ✓✓ | Ideal for business/educational content |
| warm | ✓ | Works for gentle stories, slight warmth in accent |
| energetic | ✓ | Works for punchy, high-energy content |
| dramatic | ✗ | Style too stripped down for dramatic intensity |
| vintage | ✗ | Minimalist aesthetic conflicts with aged/textured look |
| romantic | ✗ | No capacity for decorative/soft elements |
| action | ✗ | No dynamic line capability for speed/impact |
## Best For
Business allegory, management fables, short concept illustration, four-panel comic strips, quick-insight education, social media content
@@ -11,10 +11,13 @@ Content signals determine default art + tone + layout (or preset).
| Technical explanation, educational | manga | neutral | webtoon | **ohmsha** |
| Pre-1950, classical, ancient | realistic | vintage | cinematic | - |
| Personal story, mentor | ligne-claire | warm | standard | - |
| Psychology, motivation, self-help, coaching | manga | warm | standard | **concept-story** |
| Business narrative, management, leadership | manga | warm | standard | **concept-story** |
| Conflict, breakthrough | (inherit) | dramatic | splash | - |
| Wine, food, business, lifestyle | realistic | neutral | cinematic | - |
| Wine, food, lifestyle | realistic | neutral | cinematic | - |
| Martial arts, wuxia, xianxia | ink-brush | action | splash | **wuxia** |
| Romance, love, school life | manga | romantic | standard | **shoujo** |
| Business allegory, fable, parable, short insight, 四格 | minimalist | neutral | four-panel | **four-panel** |
| Biography, balanced | ligne-claire | neutral | mixed | - |
## Preset Recommendation Rules
@@ -36,6 +39,16 @@ Content signals determine default art + tone + layout (or preset).
- **Special rules**: Decorative elements, eye details, romantic beats
- **Base**: manga + romantic + standard
### concept-story
- **Triggers**: Psychology, motivation, self-help, business narrative, management, leadership, personal growth, coaching, soft skills, abstract concept through story
- **Special rules**: Visual symbol system, growth arc, dialogue+action balance, original characters
- **Base**: manga + warm + standard
### four-panel
- **Triggers**: Business allegory, fable, parable, short insight, four-panel, 四格, 四格漫画, single-page comic, minimalist comic strip
- **Special rules**: Strict 起承转合 4-panel structure, B&W + spot color, simplified stick-figure characters, single-page story
- **Base**: minimalist + neutral + four-panel
## Compatibility Matrix
Art Style × Tone combinations work best when matched appropriately:
@@ -47,6 +60,7 @@ Art Style × Tone combinations work best when matched appropriately:
| realistic | neutral, warm, dramatic, vintage | action | romantic, energetic |
| ink-brush | neutral, dramatic, action, vintage | warm | romantic, energetic |
| chalk | neutral, warm, energetic | vintage | dramatic, action, romantic |
| minimalist | neutral | warm, energetic | dramatic, vintage, romantic, action |
**Note**: Art Style × Tone × Layout can be freely combined. Incompatible combinations work but may produce unexpected results.
@@ -16,9 +16,9 @@ watermark:
content: ""
position: bottom-right # bottom-right|bottom-left|bottom-center|top-right
preferred_art: null # ligne-claire|manga|realistic|ink-brush|chalk
preferred_art: null # ligne-claire|manga|realistic|ink-brush|chalk|minimalist
preferred_tone: null # neutral|warm|dramatic|romantic|energetic|vintage|action
preferred_layout: null # standard|cinematic|dense|splash|mixed|webtoon
preferred_layout: null # standard|cinematic|dense|splash|mixed|webtoon|four-panel
preferred_aspect: null # 3:4|4:3|16:9
language: null # zh|en|ja|ko|auto
@@ -41,7 +41,7 @@ character_presets:
| `watermark.enabled` | bool | false | Enable watermark |
| `watermark.content` | string | "" | Watermark text (@username or custom) |
| `watermark.position` | enum | bottom-right | Position on image |
| `preferred_art` | string | null | Art style (ligne-claire, manga, realistic, ink-brush, chalk) |
| `preferred_art` | string | null | Art style (ligne-claire, manga, realistic, ink-brush, chalk, minimalist) |
| `preferred_tone` | string | null | Tone (neutral, warm, dramatic, romantic, energetic, vintage, action) |
| `preferred_layout` | string | null | Layout preference or null |
| `preferred_aspect` | string | null | Aspect ratio (3:4, 4:3, 16:9) |
@@ -57,6 +57,7 @@ character_presets:
| `realistic` | 写实 | Digital painting, realistic proportions |
| `ink-brush` | 水墨 | Chinese brush strokes, ink wash effects |
| `chalk` | 粉笔 | Chalkboard aesthetic, hand-drawn warmth |
| `minimalist` | 极简 | Clean black line art, limited spot color, stick-figure characters |
## Tone Options
@@ -0,0 +1,40 @@
# four-panel
四格漫画 - Strict 2×2 grid, single-page story
## Panel Structure
- **Panels per page**: 4 (exactly, no variation)
- **Structure**: Strict 2×2 equal grid
- **Gutters**: Consistent white space (8-10px), uniform on all sides
## Grid Configuration
- 2 columns × 2 rows, all panels identical size
- Panel sizes: Exactly equal (each panel = 25% of content area)
- Reading flow: Z-pattern — Panel 1 (top-left) → Panel 2 (top-right) → Panel 3 (bottom-left) → Panel 4 (bottom-right)
## Narrative Structure
Each panel serves a specific narrative role (起承转合 / kishōtenketsu):
| Panel | Position | Role | Purpose |
|-------|----------|------|---------|
| 1 | Top-left | 起 Setup | Establish situation, introduce characters/problem |
| 2 | Top-right | 承 Development | Build on setup, add complication or attempt |
| 3 | Bottom-left | 转 Turn | Twist, key insight, or reversal — the pivotal moment |
| 4 | Bottom-right | 合 Conclusion | Resolution, punchline, or takeaway |
## Aspect Ratio
- Recommended page aspect: **4:3** (landscape)
- Landscape gives each panel a comfortable wide rectangle
- Portrait (3:4) makes panels tall and narrow — avoid for this layout
## Best For
Business allegory, quick-insight education, social media comics, fables, parables, single-concept explanation
## Best Style Pairings
minimalist, ligne-claire, chalk
@@ -0,0 +1,121 @@
# concept-story
概念故事预设 - Narrative comics that visualize abstract concepts through character-driven stories
## Base Configuration
| Dimension | Value |
|-----------|-------|
| Art Style | manga |
| Tone | warm |
| Layout | standard (default) |
Equivalent to: `--art manga --tone warm`
## Unique Rules
This preset includes special rules beyond the art+tone combination. When `--style concept-story` is used, ALL rules below must be applied.
### Concept Visualization System (CRITICAL)
Each major abstract concept SHOULD have a recurring visual symbol/metaphor:
| Concept Type | Visualization Approach |
|-------------|----------------------|
| Psychological need | Tangible object character holds or discovers (e.g., glowing energy ball = competence) |
| Management principle | Environmental metaphor character navigates (e.g., ship wheel = autonomy) |
| Growth/development | Living organic symbol that transforms (e.g., seed → flowering plant = relatedness) |
| Abstract framework | Spatial structure characters can enter or observe |
| Emotional state | Color/lighting shift in the scene atmosphere |
**Unlike ohmsha**: Dialogue panels are allowed and expected. The goal is to COMBINE visual metaphors WITH dialogue, not replace dialogue entirely.
**Pattern**: "Dialogue introduces idea" → "Visual metaphor illustrates it" → "Character reacts/applies it"
### Visual Symbol Continuity
Symbols must persist across the story:
| Stage | Treatment |
|-------|-----------|
| Introduction | Symbol appears with soft glow effect when concept is first mentioned |
| Recurrence | Same symbol reappears in background or character interaction when concept is referenced |
| Resolution | ALL symbols gather in the final composition, showing integration of learned concepts |
**Storyboard requirement**: Include a Symbol Mapping Table defining concept → visual symbol before panel breakdown.
### Character Archetypes (Flexible)
Create original characters based on content domain. No fixed defaults:
| Role | Archetype | Visual Cues |
|------|-----------|------------|
| Protagonist | Learner/worker facing a challenge | Modern professional or student, relatable, starts with constrained posture |
| Mentor | Experienced guide who teaches through experience | Slightly older, calm demeanor, warm color accents |
| Catalyst | Person or event that triggers transformation | Can be a colleague, situation, challenge, or opportunity |
**IMPORTANT**: Characters are created fresh each time based on the source content's domain (business, psychology, education, etc.). No default character set.
### Narrative Arc Structure
Enforce a five-stage growth arc:
| Act | Structure | Visual Tone |
|-----|-----------|------------|
| Opening | Protagonist stuck in routine, faces frustration | Muted warm tones, tight framing, constrained compositions |
| Inciting moment | Mentor appears or opportunity arrives | Brightness increases, panels open up |
| Learning | Concepts introduced through visual metaphors | Rich warm palette, symbols introduced one by one |
| Turning point | Protagonist applies knowledge, faces test | Contrast increases, dynamic compositions |
| Transformation | Growth demonstrated, new understanding visible | Full warm palette, expansive composition, all symbols present |
### Dialogue + Action Balance
- Dialogue is encouraged and expected (unlike ohmsha's NO talking heads rule)
- Every page should combine at least one dialogue panel with at least one visual/action panel
- Avoid pure "lecture" pages where a character explains for 4+ panels straight
- When a character explains a concept verbally, the NEXT panel should visualize it
**Wrong approach**: Four consecutive panels of mentor lecturing at protagonist
**Right approach**: Mentor introduces concept → visual metaphor panel → protagonist reacts → applies understanding
### Scene Atmosphere Rules
| Scene Type | Atmosphere |
|------------|-----------|
| Problem/frustration | Cool muted tones over warm base, tight framing, cluttered environment |
| Mentoring moment | Golden hour lighting, open composition, warm indoor glow |
| Concept visualization | Soft glow effects, clean simplified backgrounds, symbol spotlight |
| Growth/transformation | Warm light expanding outward, character posture opening up |
| Resolution | Full warm palette, spacious composition, all visual symbols visible |
### Ending Requirements
Final page MUST include:
1. Protagonist demonstrating transformed understanding (not just being told)
2. Visual callback showing contrast with opening state (e.g., wilted plant → thriving plant)
3. All concept symbols visible together in the composition
4. A forward-looking element suggesting ongoing growth (not a closed ending)
### Page Title Convention
Every page MUST have a narrative title:
**Wrong**: "Chapter 3: Self-Determination Theory"
**Right**: "The Day Xiao Ming Found His Own Engine"
## Quality Markers
- ✓ Each major concept has a recurring visual symbol
- ✓ Dialogue and visual metaphors work together (not one replacing the other)
- ✓ Clear growth arc from problem to transformation
- ✓ Original characters suited to the content domain
- ✓ Warm, professional atmosphere throughout
- ✓ Visual symbols recur and accumulate through the story
- ✓ Final page integrates all concept symbols with transformation callback
## Best For
Psychology concepts, business/management principles, motivation theory, personal development,
self-help content, leadership frameworks, coaching narratives, soft skill education,
abstract concept explanation through character-driven stories
@@ -0,0 +1,107 @@
# four-panel
四格漫画预设 - Minimalist four-panel business allegory comics
## Base Configuration
| Dimension | Value |
|-----------|-------|
| Art Style | minimalist |
| Tone | neutral |
| Layout | four-panel (default) |
| Aspect | 4:3 (landscape) |
Equivalent to: `--art minimalist --tone neutral --layout four-panel --aspect 4:3`
## Unique Rules
This preset includes special rules beyond the art+tone combination. When `--style four-panel` is used, ALL rules below must be applied.
### 起承转合 Narrative Structure (CRITICAL)
Every comic MUST follow the four-panel 起承转合 structure:
| Panel | Role | Requirements |
|-------|------|-------------|
| 1 (起 Setup) | Introduce the situation | Show character(s) in a recognizable context. Establish the "normal" state or problem |
| 2 (承 Development) | Build on the setup | Add complication, show an attempt, or introduce the concept. Stakes become clearer |
| 3 (转 Turn) | The twist or key insight | **Most important panel.** Show the unexpected reversal, contrast, or "aha" moment that makes the allegory work |
| 4 (合 Conclusion) | Resolution and takeaway | Show the result, consequence, or lesson learned. Can be a visual punchline or summary |
**CRITICAL**: Do NOT deviate from exactly 4 panels. No 5th panel, no title panel, no footer panel within the image.
### Single-Page Story Rule (CRITICAL)
- The entire story is told in ONE page with exactly 4 panels
- Page count: always 1 (plus optional cover)
- No multi-page four-panel stories — if content requires more, create multiple separate four-panel comics
- Storyboard structure: Cover (optional) + 1 page
### Accent Color System
- The image is primarily black-and-white line art
- Use exactly 1-2 spot colors per strip (default: orange `#FF6B35`)
- Rules:
- Key concept label or object: filled with accent color or outlined in accent
- Panel 3 (转 Turn) should have the strongest color emphasis
- Characters remain B&W — color is for concepts/objects/labels only
- Consistent accent color across all 4 panels (do not switch colors between panels)
### Character Design Rules
- Simplified stick-figure-like characters
- Distinguish characters through simple props: ties, glasses, hats, briefcases, aprons
- No detailed faces — dot eyes, line mouth at most
- Characters should be generic enough to represent archetypes (the manager, the employee, the customer)
- Maximum 2-3 characters per strip
### Text in Panels
- Chinese text for dialogue and labels (or match source language)
- Keep text minimal — 1-2 short lines per panel maximum
- Key concept terms can be highlighted with accent color background
- No narrator boxes — dialogue and labels only
- Speech bubbles: simple rectangles or ovals, thin black outline
### Optional Title & Caption
- A brief descriptive title above the 4 panels
- An optional one-line caption/moral below the panels
- These are part of the page composition, not separate panels
### Character Archetypes (Flexible)
Create simple stick-figure characters based on content. No fixed defaults:
| Role | Archetype | Visual Cues |
|------|-----------|------------|
| Protagonist | Worker/employee facing a situation | Simple figure, minimal distinguishing feature (glasses, tie) |
| Authority | Boss/manager/expert | Slightly larger figure, or prop like pointer/clipboard |
| Object | The concept itself | Labeled object, icon, or highlighted text with accent color |
### Prompt Template
When generating image prompts for four-panel comics, include these keywords:
> A minimalist, clean line art digital comic strip in a four-panel grid layout (2×2). The style is simplified cartoon illustration with clear black outlines and a minimal color palette of black, white, and specific spot [accent color] for key concepts.
Each panel description should specify:
- Panel position (Top Left / Top Right / Bottom Left / Bottom Right)
- Character poses and gestures (simple, stick-figure style)
- Dialogue text in Chinese (hand-drawn style)
- Any accent-colored elements (concept labels, key objects)
## Quality Markers
- ✓ Exactly 4 panels in strict 2×2 grid
- ✓ 起承转合 narrative arc clearly present
- ✓ 90%+ black-and-white with strategic spot color
- ✓ Simplified stick-figure characters
- ✓ Key concept visually highlighted with accent color
- ✓ Text is minimal and in Chinese (or source language)
- ✓ Single complete story in one page
- ✓ Panel 3 delivers a clear "turn" or insight
## Best For
Business allegory, management fables, short insights, workplace parables, concept contrasts, social media educational content, quick-read comics
+44 -14
View File
@@ -18,6 +18,8 @@ Comic Progress:
- [ ] Step 5: Generate prompts
- [ ] Step 6: Review prompts (conditional)
- [ ] Step 7: Generate images
- [ ] 7.1 Character sheet (if needed)
- [ ] 7.2 Generate pages
- [ ] Step 8: Merge to PDF
- [ ] Step 9: Completion report
```
@@ -410,28 +412,41 @@ options:
With confirmed prompts from Step 5/6:
### 7.1 Generate Character Reference Sheet (first)
### 7.1 Generate Character Reference Sheet (conditional)
Character sheet is recommended for multi-page comics with recurring characters, but **NOT required** for all presets.
**When to generate**:
| Condition | Action |
|-----------|--------|
| Multi-page comic with detailed/recurring characters | Generate character sheet (recommended) |
| Preset with simplified characters (e.g., four-panel minimalist) | Skip — prompt descriptions are sufficient |
| Single-page comic | Skip unless characters are complex |
**When generating**:
1. Use Reference Sheet Prompt from `characters/characters.md`
2. **Backup rule**: If `characters/characters.png` exists, rename to `characters/characters-backup-YYYYMMDD-HHMMSS.png`
3. Generate → `characters/characters.png`
4. This ensures visual consistency for all subsequent pages
4. **Compress** to reduce API payload size when used as `--ref`:
- `sips -s format jpeg -s formatOptions 80 characters.png --out characters-compressed.jpg` (macOS)
- Or: `pngquant --quality=65-80 characters.png -o characters-compressed.png`
### 7.2 Generate Comic Pages
**CRITICAL: Character Reference is MANDATORY** for visual consistency across all pages.
**Before generating any page**:
1. Read the image generation skill's SKILL.md
2. Check if it supports reference image input (`--ref`, `--reference`, etc.)
3. Choose the appropriate strategy below
3. Determine if character sheet exists
4. Choose the appropriate strategy below
**Character Reference Strategy**:
**Page Generation Strategy**:
| Skill Capability | Strategy | Action |
|------------------|----------|--------|
| Supports `--ref` | **Strategy A** | Pass `characters/characters.png` with EVERY page |
| Does NOT support `--ref` | **Strategy B** | Prepend character descriptions to EVERY prompt |
| Character Sheet | Skill Capability | Strategy |
|-----------------|------------------|----------|
| Exists | Supports `--ref` | **A**: Pass character sheet as `--ref` with every page |
| Exists | No `--ref` support | **B**: Embed character descriptions in every prompt |
| Skipped | — | **C**: Prompt file contains all descriptions inline |
**Strategy A: Using `--ref` parameter** (e.g., baoyu-imagine)
@@ -439,8 +454,16 @@ With confirmed prompts from Step 5/6:
- Invoke that installed skill via its documented interface, not by calling its scripts directly
- For every page, use `prompts/01-page-xxx.md` as the prompt-file input
- Save output to `01-page-xxx.png`
- Use aspect ratio `3:4`
- Pass `characters/characters.png` as `--ref` on every page generation
- Use aspect ratio from storyboard (default `3:4`, preset may override)
- Pass `characters/characters.png` (or compressed version) as `--ref`
**`--ref` failure recovery**:
If generation fails when using `--ref`:
1. **Compress/convert** reference image:
- `sips -s format jpeg -s formatOptions 70 characters.png --out characters-compressed.jpg`
- Or reduce resolution: `sips -Z 1024 characters.png --out characters-small.png`
2. **Retry** with compressed/converted image as `--ref`
3. **If still fails**: Fall back to **Strategy C** — generate WITHOUT `--ref`, with character descriptions embedded in prompt text
**Strategy B: Embedding character descriptions in prompt**
@@ -458,10 +481,17 @@ When skill does NOT support reference images, create combined prompt files:
[Original page prompt here]
```
**Strategy C: Prompt-only (no character sheet)**
When character sheet was skipped or `--ref` failed:
- Prompt file already contains all character descriptions inline
- No `--ref` parameter needed
- Rely on detailed text descriptions for character consistency
**For each page (cover + pages)**:
1. Read prompt from `prompts/NN-{cover|page}-[slug].md`
2. **Backup rule**: If image file exists, rename to `NN-{cover|page}-[slug]-backup-YYYYMMDD-HHMMSS.png`
3. Generate image using Strategy A or B (based on skill capability)
3. Generate image using Strategy A, B, or C
4. Save to `NN-{cover|page}-[slug].png`
5. Report progress after each generation: "Generated X/N: [page title]"
@@ -493,7 +523,7 @@ Title: [title] | Art: [art] | Tone: [tone] | Pages: [count] | Aspect: [ratio] |
Watermark: [enabled/disabled]
Location: [path]
✓ analysis.md
✓ characters.png
✓ characters.png (if generated)
✓ 00-cover-[slug].png ... NN-page-[slug].png
✓ {topic-slug}.pdf
```
+4 -4
View File
@@ -1,6 +1,6 @@
---
name: baoyu-cover-image
description: Generates article cover images with 5 dimensions (type, palette, rendering, text, mood) combining 10 color palettes and 7 rendering styles. Supports cinematic (2.35:1), widescreen (16:9), and square (1:1) aspects. Use when user asks to "generate cover image", "create article cover", or "make cover".
description: Generates article cover images with 5 dimensions (type, palette, rendering, text, mood) combining 11 color palettes and 7 rendering styles. Supports cinematic (2.35:1), widescreen (16:9), and square (1:1) aspects. Use when user asks to "generate cover image", "create article cover", or "make cover".
version: 1.56.1
metadata:
openclaw:
@@ -39,7 +39,7 @@ Generate elegant cover images for articles with 5-dimensional customization.
| Option | Description |
|--------|-------------|
| `--type <name>` | hero, conceptual, typography, metaphor, scene, minimal |
| `--palette <name>` | warm, elegant, cool, dark, earth, vivid, pastel, mono, retro, duotone |
| `--palette <name>` | warm, elegant, cool, dark, earth, vivid, pastel, mono, retro, duotone, macaron |
| `--rendering <name>` | flat-vector, hand-drawn, painterly, digital, pixel, chalk, screen-print |
| `--style <name>` | Preset shorthand (see [Style Presets](references/style-presets.md)) |
| `--text <level>` | none, title-only, title-subtitle, text-rich |
@@ -56,7 +56,7 @@ Generate elegant cover images for articles with 5-dimensional customization.
| Dimension | Values | Default |
|-----------|--------|---------|
| **Type** | hero, conceptual, typography, metaphor, scene, minimal | auto |
| **Palette** | warm, elegant, cool, dark, earth, vivid, pastel, mono, retro, duotone | auto |
| **Palette** | warm, elegant, cool, dark, earth, vivid, pastel, mono, retro, duotone, macaron | auto |
| **Rendering** | flat-vector, hand-drawn, painterly, digital, pixel, chalk, screen-print | auto |
| **Text** | none, title-only, title-subtitle, text-rich | title-only |
| **Mood** | subtle, balanced, bold | balanced |
@@ -69,7 +69,7 @@ Auto-selection rules: [references/auto-selection.md](references/auto-selection.m
**Types**: hero, conceptual, typography, metaphor, scene, minimal
→ Details: [references/types.md](references/types.md)
**Palettes**: warm, elegant, cool, dark, earth, vivid, pastel, mono, retro, duotone
**Palettes**: warm, elegant, cool, dark, earth, vivid, pastel, mono, retro, duotone, macaron
→ Details: [references/palettes/](references/palettes/)
**Renderings**: flat-vector, hand-drawn, painterly, digital, pixel, chalk, screen-print
@@ -27,6 +27,7 @@ When a dimension is omitted, select based on content signals.
| Zen, focus, essential, pure, simple | `mono` |
| History, vintage, retro, classic, exploration | `retro` |
| Movie poster, album cover, concert, cinematic, dramatic, two-color | `duotone` |
| Education, tutorial, knowledge, onboarding, concept explainer | `macaron` |
## Auto Rendering Selection
@@ -18,7 +18,7 @@ watermark:
preferred_type: null # hero|conceptual|typography|metaphor|scene|minimal or null for auto-select
preferred_palette: null # warm|elegant|cool|dark|earth|vivid|pastel|mono|retro or null for auto-select
preferred_palette: null # warm|elegant|cool|dark|earth|vivid|pastel|mono|retro|duotone|macaron or null for auto-select
preferred_rendering: null # flat-vector|hand-drawn|painterly|digital|pixel|chalk or null for auto-select
@@ -0,0 +1,26 @@
# macaron
Soft macaron pastel color blocks on warm cream
## Color Palette
| Role | Color | Hex |
|------|-------|-----|
| Primary 1 | Sky Blue | #A8D8EA |
| Primary 2 | Mint Green | #B5E5CF |
| Primary 3 | Lavender | #D5C6E0 |
| Background | Warm Cream | #F5F0E8 |
| Background Alt | Peach | #FFD5C2 |
| Accent 1 | Coral Red | #E8655A |
| Accent 2 | Deep Charcoal | #2D2D2D |
## Decorative Hints
- Rounded pastel color blocks
- Subtle warm paper grain texture
- Soft shadows, no hard edges
- Gentle gradient transitions between zones
## Best For
Educational content, knowledge sharing, concept explainers, tutorials, tech summaries, onboarding materials
@@ -23,6 +23,7 @@
| `vintage` | `retro` | `hand-drawn` |
| `warm` | `warm` | `hand-drawn` |
| `warm-flat` | `warm` | `flat-vector` |
| `hand-drawn-edu` | `macaron` | `hand-drawn` |
| `watercolor` | `earth` | `painterly` |
| `poster-art` | `retro` | `screen-print` |
| `mondo` | `mono` | `screen-print` |
+290
View File
@@ -0,0 +1,290 @@
---
name: baoyu-diagram
description: Generates publication-ready SVG diagrams — flowcharts, sequence/protocol diagrams, structural/architecture diagrams, and illustrative intuition diagrams — by writing real SVG code directly following a cohesive design system. Use whenever the user asks to "draw a flowchart", "draw a sequence diagram", "show the OAuth / TCP / auth protocol", "make an architecture diagram", "explain how X works visually", "画流程图", "画时序图", "画架构图", "画示意图", "画图解", or wants a clean, embeddable vector diagram for articles, WeChat posts, slides, or docs. Output is a single self-contained .svg file that renders correctly in light and dark mode anywhere it is embedded.
version: 1.0.0
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-diagram
---
# Diagram Generator
Write **real SVG code** directly, following a consistent design system, the output is a single `.svg` file that is self-contained (embedded styles, auto dark-mode), editable by humans, scales to any size without quality loss, and embeds cleanly into articles, WeChat posts, slide decks, Notion, and markdown.
This is not an image-generation skill — it does not call any LLM image model. Claude writes the SVG node-by-node, doing the layout math by hand so every diagram honors the rules in `references/`.
## Usage
```bash
# Prompt for the topic if no argument given
/baoyu-diagram
# Plain-text description
/baoyu-diagram "how JWT authentication works"
# Path to a markdown file as source content
/baoyu-diagram path/to/content.md
# Force a specific diagram type
/baoyu-diagram "transformer attention" --type illustrative
/baoyu-diagram "Kubernetes architecture" --type structural
/baoyu-diagram "CI/CD pipeline" --type flowchart
/baoyu-diagram "OAuth 2.0 flow" --type sequence
/baoyu-diagram "Shape hierarchy" --type class
# Language and output path
/baoyu-diagram "微服务架构" --lang zh
/baoyu-diagram "build pipeline" --out docs/build-pipeline.svg
```
## Options
| Option | Values |
|--------|--------|
| `--type` | `flowchart`, `sequence`, `structural`, `illustrative`, `class`, `auto` (default — route on verb) |
| `--lang` | `en`, `zh`, `ja`, `ko`, ... (default: match the user's language) |
| `--out` | Output file path (default: `diagram/{slug}/diagram.svg`) |
## Diagram types
Pick the type by what the reader needs, not by the noun in the prompt.
**The primary test**: is the reader trying to *document* this, or *understand* it? Documentation wants precision — flowchart, sequence, or structural. Understanding wants the right mental model — illustrative.
| Type | Reader need | Route on verbs like | Reference |
|------|-------------|---------------------|-----------|
| **Flowchart** | Walk me through the steps, in order | "walk through", "steps", "process", "lifecycle", "workflow", "state machine", "gate", "router", "parallelization", "orchestrator", "evaluator" | `references/flowchart.md` |
| **Flowchart (phase band)** | Walk me through each phase; show the tools at each stage | "phase 1/2/3", "multi-phase operation", "each phase has tools", "attack phases", "phased workflow", "security operation phases", "penetration test stages", "phase N feeds phase N+1" | `references/flowchart-phase-bands.md` |
| **Sequence** | Who talks to whom, in what order | "protocol", "handshake", "auth flow", "OAuth", "TCP", "TLS", "gRPC", "request/response", "who calls what", "exchange between", "round trip", "webhook" | `references/sequence.md` |
| **Structural** | Show me what's inside what, how it's organized | "architecture", "organised", "components", "layout", "what's inside", "topology", "subsystem", "two systems", "side by side", "foreground + background" | `references/structural.md` |
| **Illustrative** | Give me the intuition — draw the mechanism | "how does X work", "explain X", "I don't get X", "intuition for", "why does X do Y", "LLM with tools", "agent and environment", "central + attachments" | `references/illustrative.md` |
| **Class** | What are the types and how are they related | "class diagram", "UML", "inheritance", "interface", "schema", "types and subtypes", "data model" | `references/class.md` |
**Routing heuristic**: "how does X work" is the default ambiguous case. Prefer **illustrative** unless the user specifically asks for steps or components. A diagram that makes the reader feel "oh, *that's* what it's doing" is illustrative — even if the subject is software.
**Multi-actor test for sequence**: if the prompt names ≥2 distinct actors/participants/services (User + Server, Client + Auth + Resource, Browser + CDN + Origin), prefer **sequence** even when the verb is "flow" or "process". Single-actor "X flow" (build pipeline, request lifecycle, GC) stays flowchart. When you pick sequence for a multi-actor reason, announce it: *"Picked sequence because the prompt names N actors (…). Rerun with `--type flowchart` to force the step-list version."*
**Worked examples of verb-based routing**: same subject, different diagram depending on what was asked. Use these as a sanity check after picking a type.
| User says | Type | What to draw |
|-------------------------------------------|--------------|----------------------------------------------------------------------------------|
| "how do LLMs work" | Illustrative | Token row, stacked layer slabs, attention threads across layers. |
| "transformer architecture / components" | Structural | Labeled boxes: embedding, attention heads, FFN, layer norm. |
| "how does attention work" | Illustrative | One query token, fan of lines to every key, line thickness = weight. |
| "how does gradient descent work" | Illustrative | Contour surface, a ball rolling down, a trail of discrete steps. |
| "what are the training steps" | Flowchart | Forward → loss → backward → update. |
| "how does TCP work" | Illustrative | Two endpoints, numbered packets in flight, an ACK returning. |
| "TCP handshake sequence" | Sequence | SYN → SYN-ACK → ACK between client and server lifelines. |
| "how does a hash map work" | Illustrative | Key falling through a hash function into one of N buckets. |
| "LLM with retrieval, tools, memory" | Illustrative | Central LLM subject with dashed radial spokes to three labeled attachments. |
| "gate pattern with pass/fail exit" | Flowchart | Pill In → LLM → Gate → LLM → LLM → pill Out, with a dashed Fail branch to Exit. |
| "LLM router / parallelization" | Flowchart | Simple fan-out: pill In → hub → 3 branches → aggregator → pill Out. |
| "Pi session + background analyzer" | Structural (subsystem) | Two dashed sibling containers side by side, each with a short internal flow, labeled cross-system arrows. |
| "prompt engineering vs. context engineering" | Structural (subsystem) | Two sibling containers, each showing its internal mechanism with cross-links. |
| "agent + environment loop" | Illustrative | Human pill ↔ LLM rect ↔ Environment pill, Action/Feedback labels on the edges. |
| "Claude Code workflow with sub-loops" | Sequence | 4 actors with 12 dashed message frames labeled "Until tests pass" / "Until tasks clear". |
| "generator-verifier loop" | Flowchart | Outer loop container; two boxes with green ✓ / coral ✗ status circles on the return edge. See `flowchart.md` → "Loop container" + "Status-circle junctions". |
| "from TODOs to tasks" | Structural (subsystem) | Two siblings: left = checklist (checkbox glyphs); right = DAG of task nodes with one dashed future-state node. See `structural.md` → "Rich interior" + "Dashed future-state node". |
| "finding the sweet spot" | Illustrative | Horizontal spectrum axis between two opposing labels; option boxes under tick points with the middle one highlighted. See `illustrative.md` → "Spectrum / continuum". |
| "agent teams with task queue" | Flowchart | Queue glyph inside the lead box, then vertical fan-out to workers. See `flowchart.md` → "Queue glyph inside box" + "Vertical fan-out". |
| "message bus architecture" | Structural | Central horizontal bar + agents above/below, each linked by a publish/subscribe arrow pair. See `structural.md` → "Bus topology". |
| "shared state store" | Structural | Central hub with a doc icon + 4 corner satellites, bidirectional arrow pairs. See `structural.md` → "Radial star topology". |
| "orchestrator vs. agent teams" | Structural (subsystem) | Two siblings; left = hub + fan-out; right = queue + vertical fan-out. See `structural.md` → "Rich interior for subsystem containers". |
| "orchestrator vs. message bus" | Structural (subsystem) | Two siblings; left = hub + fan-out; right = mini bus topology. See `structural.md` → "Rich interior". |
| "advisor strategy" | Structural | Single container, multi-line box bodies (title/role/meta), mixed solid+dashed+bidirectional arrows with a legend strip. See `structural.md` → "Mixed arrow semantics" + "Multi-line box body". |
| "tool calling vs. programmatic" | Sequence | Parallel independent rounds — left = stacked rounds; right = stacked rounds wrapped in a tall script box. See `sequence.md` → "Parallel independent rounds". |
| "Claude + environment + skill" | Illustrative | Two subject boxes with a bidirectional arrow; annotation circle at the midpoint labels the skill. See `illustrative.md` → "Annotation circle on connector". |
| "code execution vs. dedicated tool" | Structural (subsystem) | Two siblings; left = Computer box with nested Terminal; right = Claude with an attached gadget box for Tools. See `structural.md` → "Rich interior" + "Attached gadget box". |
| "Shape inheritance / class hierarchy" | Class | 3-compartment rects (name / attrs / methods) with hollow-triangle inheritance arrows. See `class.md`. |
| "order lifecycle / status transitions" | Flowchart (state machine) | State rects + initial/final markers + `event [guard] / action` transition labels. See `flowchart.md` → "State machine". |
| "network topology (3-tier)" | Structural (network) | Dashed zone containers (Internet / DMZ / Internal) + labeled device rects. See `structural.md` → "Network topology". |
| "database comparison matrix" | Structural (matrix) | Header row + zebra-striped body rows with ✓/✗ glyphs in cells. See `structural.md` → "Comparison matrix". |
| "multi-phase attack / each phase has tools" | Flowchart (phase band) | Stacked dashed phase bands; compact tool cards with icons in each band; colored cross-band arrows (normal / exploit / findings); operator icons on left. See `flowchart-phase-bands.md`. |
| "phased workflow / phase 1 recon phase 2 exploit" | Flowchart (phase band) | Phase labels as eyebrow text; tool card rows centered in each band; side annotations; legend strip. See `flowchart-phase-bands.md`. |
**Most common routing failure**: picking a flowchart because it feels safer when an illustrative diagram would give the reader more insight. Illustrative is the more ambitious choice, and almost always the right one when the reader needs understanding rather than documentation.
Cycles, ERDs, and gantt charts are **out of scope for v1**. For cycles, draw the stages linearly with a small `↻ returns to start` return glyph (see `flowchart.md`). For ERDs, suggest a dedicated tool (mermaid, plantuml) — do not attempt to fake them in pure SVG.
## Workflow
### Step 1: Capture intent
Read the user's prompt or content file. If the topic is missing, ask for it with AskUserQuestion.
**Before routing, extract these five things from the source:**
1. **Named elements** — list every distinct actor, component, service, state, or phase explicitly named. Count them. If the count is 6+, plan multiple diagrams rather than cramming everything into one (see `flowchart.md` → "Planning before you write SVG").
2. **Relationship type** — for each interaction between elements, classify it:
- Sequential steps / order of operations → flowchart signal
- Containment ("X is inside Y", zones, hierarchies) → structural signal
- Multi-actor message exchange (A sends to B, B replies to C) → sequence signal
- Mechanism ("how does X produce Y") → illustrative signal
More than one type present? Pick the dominant one, or plan two diagrams.
3. **What the reader needs** — complete this sentence before routing: *"After seeing this diagram, the reader understands ___."* If you can't finish it, the topic is underspecified — ask.
4. **Label preview** — for each element name, count the characters. Latin titles >30 chars (CJK >16) will overflow a 180-wide box and need shortening. Draft the abbreviated form now, before layout math, so Step 4 uses real labels.
5. **Language** — CJK vs. Latin. Affects text-width multipliers in Step 4 (15 px/char vs. 8 px/char for titles). Mixed content (CJK labels with some Latin terms) counts as CJK.
### Step 2: Route the diagram type
Match the user's phrasing to the table above. If `--type` is given, use it. Otherwise route on the verb. When genuinely ambiguous between flowchart and illustrative, default to **illustrative** — the reader almost always benefits more from intuition than from a list of steps.
Tell the user which type you picked and why, in one sentence. Do not ask for confirmation — the type can always be changed with `--type` on a rerun.
### Step 3: Load references
**Always read**:
- `references/design-system.md` — philosophy, typography, color palette, hard rules
- `references/svg-template.md` — the `<style>` + `<defs>` boilerplate to copy verbatim
- `references/layout-math.md` — text-width estimation, viewBox sizing, arrow routing
- `references/pitfalls.md` — the pre-save checklist
**Read the one that matches the type**:
- `references/flowchart.md`
- `references/sequence.md`
- `references/structural.md`
- `references/illustrative.md`
- `references/class.md`
**Read on demand** when the plan calls for a small pictorial element (status circle on a decision branch, checkbox inside a list, queue slot inside a box, doc/terminal/script icon inside a subject, annotation circle on a connector, paired pub/sub arrows, dashed future-state node) **or** when drawing a phase-band diagram (compact tool card icons, operator icons):
- `references/glyphs.md` — the shared glyph library, tool card icon set, operator icons, and dark-mode rules
**Read on demand for diagram type extensions:**
- `references/flowchart-poster.md` — when ≥3 poster-mode triggers fire in Step 4a (topic has a short name, named phases, parallel candidates, a loop termination mechanic, overflow annotations, or a footer quote)
- `references/flowchart-phase-bands.md` — when the prompt describes a multi-phase sequential operation where each phase contains parallel tools or steps and outcomes propagate between phases ("phase 1/2/3", "attack phases", "phased workflow with tools")
- `references/structural-network.md` — when drawing network topology: zone containers, wired/wireless device connectivity, security zones (DMZ / VPC / firewall)
- `references/structural-matrix.md` — when drawing a comparison matrix: feature table, ✓/✗ cells, side-by-side "option × attribute" grid
### Step 3.5: Check the patterns library
If the user's topic matches a known AI-system pattern (multi-agent research, message bus, shared state, agent with skills, contextual retrieval), there is a pre-cooked starter plan in `references/patterns/`. Scan `references/patterns/README.md` for a pattern name that matches the prompt. If one matches, load that pattern file and use its mermaid reference + baoyu SVG plan as the starting point for Step 4 — the node list, widths, and arrow routing are already drafted, and you only need to adapt labels.
If nothing matches, skip this step and plan from scratch in Step 4. Do not force a near-miss: two patterns that share a surface name may have genuinely different topologies, and using the wrong pre-plan is worse than planning from scratch.
### Step 4: Plan on paper first
Before writing any SVG, draft a short layout plan. Do the math once, correctly, so the SVG comes out right on the first pass.
**4a. Extract structure from the source** — don't just transcribe the user's bullets into boxes. Read the source looking for these elements. Not every element will be present, but every present element should land in the diagram:
- **Mechanism name** — does the topic have a short, nameable identity (Autoreason, AutoResearch, OAuth, JWT auth, Reflexion loop)? If yes, that's a candidate `.title`.
- **Framing question** — does the source contain a "why does this exist" sentence? Usually in the form *"Problem X has no Y, so we built Z to …"*. That's a candidate subtitle.
- **Phases** — do the stages naturally cluster into 24 named groups (setup / loop body / judgment / convergence)? Each cluster is a candidate `.eyebrow` section.
- **Anchor inputs** — is there a constant input (the task prompt, a dataset, a knowledge base) that every stage references? That's a candidate anchor box above the main flow.
- **Parallel candidates** — at some point, does the process generate N alternatives that are then compared? "Produce A, B, AB and pick the best" is a candidate fan-out + judge pattern. **Watch for the implicit "keep unchanged" candidate** — many iterative methods include "the incumbent wins by default" as one of the options, even when the source doesn't name it explicitly.
- **Loop scope + termination** — which boxes are inside a loop that repeats? What is the *specific* termination rule — streak counter, convergence check, iteration cap, quality threshold? That's a candidate left-rail loop bracket + a dedicated termination box.
- **Per-box context that won't fit in a subtitle** — "sees task + A + critique / adversarial / fresh context" is too long for a 5-word subtitle but too important to drop. Those are candidate right-column `.anno` annotations.
- **Quotable hook** — does the source end with a test result, a quote, or a memorable framing? That's a candidate footer `.caption`.
- **Role categories** — how many *distinct kinds* of operation does the process have (draft / critique / synthesize / judge)? This determines the color budget. Identity is a category, not a sequence.
Write the answers to these in the plan file. If ≥3 of them land, you're building a **poster flowchart** — load `references/flowchart-poster.md` and follow its coordinate budget. Otherwise, it's a simple flowchart and the linear-top-down pattern applies.
**4b. Draft the layout:**
1. **List the nodes / regions / shapes** with their full label text (title + optional subtitle).
- Simple flowchart: ≤5 nodes.
- Poster flowchart: ≤12 nodes grouped into ≤4 eyebrow-divided phases.
- Structural: ≤3 inner regions.
- Illustrative: 1 subject.
- Sequence: list actors (24, max 4) in left-to-right order, each with a short title (≤12 chars) and optional role subtitle; then list messages as ordered `(sender, receiver, short label)` tuples (610 total, 10 is the sweet spot); mark any self-messages; draft a side-note title for the protocol.
2. **For every rect, compute the width** using the formula in `layout-math.md`:
- `width = max(title_chars × 8, subtitle_chars × 7) + 24` (Latin)
- Replace 8 with 15 and 7 with 13 for CJK
- Round up to the nearest 10
3. **Pick colors by category**, not sequence. ≤2 accent ramps per diagram. Gray for neutral/start/end. Reserve blue/green/amber/red for semantic meanings.
- **Sequence exception**: assign one ramp per actor (default `[gray, teal, purple, blue]`), up to 4 ramps total — arrows inherit the sender's ramp.
- **Poster-flowchart exception**: up to 4 ramps, one per distinct agent/role (drafter=purple, critic=coral, synthesizer=teal, judge=amber). Baseline/anchor/convergence stay gray.
4. **Check tier packing**: `N × box_width + (N-1) × gap ≤ 600`. For sequence, use the lane table in `layout-math.md` (N=4 → centers 100/260/420/580) and verify every message label fits its lane span with `label_chars × 7 ≤ |sender_x receiver_x| 8`. For poster fan-out rows (3 candidates), see the coordinate sketch in `flowchart.md`.
5. **Map arrows** and verify none cross an unrelated box. Use L-bends where a straight line would collide. (Sequence messages are always straight horizontal lines — no L-bends. Fan-out candidates converge to a common `ymid` channel just above the judge box.)
6. **Compute viewBox height**: `H = max_y + 20` where `max_y` is the bottom of the lowest element. Poster flowcharts routinely reach H=800950 — don't force them to be compact.
Save this plan to `diagram/{slug}/plan.md` so iteration runs can re-read it.
### Step 5: Write the SVG
Emit a single `<svg width="100%" viewBox="0 0 680 H">` element. Copy the `<style>` + `<defs>` block from `svg-template.md` **verbatim** — don't abbreviate or edit the color ramp definitions. Then add visual elements in z-order:
1. Background decorations (rare)
2. Containers (outer `<rect>` for structural diagrams)
3. Connectors and arrows (drawn first so nodes paint on top)
4. Nodes (rects with text)
5. Labels outside boxes (leader callouts, legends, external I/O labels)
Typography rules:
- Two sizes only: 14px (`t`, `th`) and 12px (`ts`)
- Two weights only: 400 and 500
- Sentence case everywhere — "User login" not "User Login"
- Every `<text>` element gets a class (`t`, `ts`, or `th`) — never hardcode fill colors on text
### Step 6: Run the pre-save checklist
Walk through every item in `references/pitfalls.md`. The top failures to catch every time:
1. viewBox height covers every element with a 20px buffer
2. No rect extends past x=640
3. Every labeled rect is wide enough for its text (char-width check)
4. No arrow crosses an unrelated box
5. Every `<path>` connector has `fill="none"` (or uses `class="arr"`)
6. Every `<text>` has a class — no hardcoded `fill="black"`
7. No `text-anchor="end"` at low x values (label would clip past x=0)
8. ≤2 accent ramps, colors encode category not sequence
9. No `<!-- comments -->` in the final output
If any item fails, fix the SVG before saving. Don't rationalize past a failure — the checklist exists because these bugs are silent: the SVG is valid but looks wrong when rendered.
### Step 7: Save output
If `--out` is given, save the SVG there and skip the scaffolded directory. Otherwise use the default layout:
```
diagram/{topic-slug}/
├── source-{slug}.md # optional: user's input content if provided
├── plan.md # layout sketch from Step 4
└── diagram.svg # final output
```
- **Slug**: 24 kebab-case words derived from the topic.
- **Backup rule**: if `diagram.svg` already exists at the target path, rename the existing one to `diagram-backup-YYYYMMDD-HHMMSS.svg` before writing the new file — never overwrite prior work silently.
- **Plan**: always save `plan.md` from Step 4 beside the SVG so the next iteration can re-read it.
- **Source**: if the user pasted source content, save it as `source-{slug}.md` in the same directory.
### Step 8: Report
Tell the user in 4-6 lines:
- Diagram type picked (and one-sentence why)
- Node count / complexity
- viewBox dimensions
- Language
- Output file path
- One suggestion for how to preview it (e.g., "Open in Chrome for light/dark check")
## Core principles
- **Draw the mechanism, not a diagram about the mechanism** (illustrative). **Draw the sequence, not the architecture** (flowchart). **Draw the containment, not the flow** (structural). **Draw the conversation, not the steps** (sequence). Picking the wrong type is the single biggest failure mode — more harmful than any layout bug.
- **One design system, always.** No `--style` flag, no alternate themes, no per-topic visual variants. The cohesive look across every diagram is the product — if a reader sees two baoyu diagrams in different articles, they should feel they came from the same hand. Any request to "use a different style" is a request to break this principle; push back and ask what the underlying need is instead.
- **Self-contained output.** Every SVG carries its own styles and dark-mode rules. The reader should never need to edit anything after pasting it into their article.
- **Math before markup.** SVG has no auto-layout. Every coordinate is hand-computed. A diagram that "almost fits" has a bug — fix the math, don't nudge pixels.
- **Color encodes meaning, not position.** Five steps in a flowchart are not five colors. All five are gray unless one specific step deserves emphasis — in which case it gets the accent color.
- **The reader has 3 seconds.** If the diagram needs prose explanation to parse, it's failing. Simplify until it can stand alone with only its labels.
## References
- `references/design-system.md` — palette, typography, hard rules
- `references/svg-template.md` — the `<style>` + `<defs>` boilerplate (copy verbatim)
- `references/layout-math.md` — coordinates, text widths, viewBox math, arrow routing
- `references/pitfalls.md` — the pre-save checklist
- `references/flowchart.md` — flowchart-specific rules and worked examples (includes state-machine sub-pattern)
- `references/flowchart-poster.md` — poster flowchart dialect (load on demand when ≥3 poster triggers fire)
- `references/flowchart-phase-bands.md` — phase-band flowchart (horizontal dashed phase containers, compact tool card rows, cross-band semantic arrows, operator icons, legend strip)
- `references/sequence.md` — sequence-diagram rules (actors, lifelines, messages, self-messages)
- `references/structural.md` — structural-specific rules and worked examples (subsystem, bus, radial star, rich interior, mixed arrows)
- `references/structural-network.md` — network topology sub-pattern (zone containers, wired/wireless, tiered layout)
- `references/structural-matrix.md` — comparison matrix sub-pattern (feature table, ✓/✗ cells, zebra rows)
- `references/illustrative.md` — illustrative-specific rules and worked examples
- `references/class.md` — UML class diagram rules (3-compartment rects, relationships, stereotypes)
- `references/glyphs.md` — shared glyph library (status circles, checkboxes, queue slots, icons, annotation circles) and concept-to-shape conventions
- `references/patterns/` — pre-planned starters for common AI-system topologies (RAG, agents, memory tiers, verifier loops, …)
+360
View File
@@ -0,0 +1,360 @@
# Class Diagram (UML)
For showing static structure: what types exist, what they contain, and how they relate. The classic UML class diagram, adapted to baoyu-diagram's flat-rect design system.
## When to use
- "Draw the class diagram for X" / "show me the UML"
- "What are the types and how are they related"
- "Show the inheritance hierarchy"
- "Diagram the domain model / schema / type system"
- "Interface + implementations"
**When not to use:**
- If the user wants to see *behavior* (what happens when X calls Y), use sequence (`sequence.md`).
- If the user wants to see *data storage* with foreign keys and cardinalities only, that's an ER diagram — baoyu doesn't do ERDs in v1, suggest mermaid.
- If the user wants to see *runtime object instances* with field values, you're drawing an object diagram — use the class template with `th`-underlined instance names (`underline` class not in the template; use `text-decoration="underline"` inline on `<text>`) and skip the method compartment.
## Planning
Before writing SVG:
1. **List the classes.** 38 total. More than 8 and you should split into multiple diagrams grouped by package or subsystem.
2. **For each class, list attributes and methods.** Keep each line ≤30 chars. If a signature doesn't fit, abbreviate.
3. **Pick the visibility for each member.** `+` public, `` private, `#` protected, `~` package-private.
4. **List the relationships.** Who extends whom, who implements which interface, who has what.
5. **Pick colors by kind of class**, not by position. See "Color rule" below.
6. **Compute box widths** using the class-specific formula below.
7. **Lay out the classes** — parents / interfaces on top, children below. See "Layout" below.
## Class box template
Each class is a **3-compartment rect**: name (top), attributes (middle), methods (bottom). Horizontal divider lines separate the compartments.
### Geometry
| Element | Value |
|------------------------|-----------------------------------------------|
| Rect corner radius | `rx="6"` |
| Min width | 160 px |
| Name compartment height | 32 px (single line, centered) |
| Attribute/method row height | 18 px per line + 8 px top/bottom padding |
| Horizontal divider | `<line>` using `arr` class at 0.5 stroke |
### Width formula
The box width must fit the longest line across all three compartments:
```
longest = max(name_chars × 8,
max(attribute_line_chars) × 7,
max(method_line_chars) × 7)
width = longest + 24
```
- 8 px/char for 14px `th` (the class name)
- 7 px/char for 12px `ts` (attributes and methods — they use the subtitle class for compact line height)
Round up to the nearest 10. Minimum width is 160 regardless of label length.
### Height formula
```
name_h = 32
attr_h = 16 + (attribute_count × 18)
method_h = 16 + (method_count × 18)
total_h = name_h + attr_h + method_h
```
If the class has no attributes, show an empty attribute compartment with `h = 16`. Never collapse a compartment — readers expect all three.
### SVG template
```svg
<g class="c-teal">
<!-- outer rect spans all three compartments -->
<rect x="80" y="60" width="200" height="144" rx="6"/>
<!-- name compartment (top) -->
<text class="th" x="180" y="80" text-anchor="middle" dominant-baseline="central">User</text>
<!-- divider between name and attributes -->
<line class="arr" x1="80" y1="92" x2="280" y2="92" stroke-width="0.5"/>
<!-- attributes (12px, left-aligned) -->
<text class="ts" x="92" y="110">+ id: UUID</text>
<text class="ts" x="92" y="128">+ email: string</text>
<text class="ts" x="92" y="146"> passwordHash: string</text>
<!-- divider between attributes and methods -->
<line class="arr" x1="80" y1="158" x2="280" y2="158" stroke-width="0.5"/>
<!-- methods (12px, left-aligned) -->
<text class="ts" x="92" y="176">+ login(pwd): Token</text>
<text class="ts" x="92" y="194">+ logout(): void</text>
</g>
```
- Name is `th` 14px centered.
- Attributes and methods are `ts` 12px, **left-aligned at `rect_x + 12`**.
- Divider lines use `class="arr"` with inline `stroke-width="0.5"` (the default 1.5 is too heavy for an internal divider).
- All text inside the class inherits the ramp's text color from the `c-{ramp}` wrapper — no hardcoded fills.
### Stereotypes
For interfaces, abstract classes, and enums, prepend a stereotype line inside the name compartment:
```svg
<g class="c-purple">
<rect x="80" y="60" width="200" height="120" rx="6"/>
<text class="ts" x="180" y="78" text-anchor="middle" dominant-baseline="central">«interface»</text>
<text class="th" x="180" y="94" text-anchor="middle" dominant-baseline="central">Drawable</text>
<line class="arr" x1="80" y1="106" x2="280" y2="106" stroke-width="0.5"/>
...
</g>
```
The stereotype line is 12px `ts`, italic is encoded via the guillemets `«...»` characters — do not use inline `font-style="italic"` since baoyu's typography table doesn't include an italic class for `ts` outside poster captions.
When you add a stereotype, bump the name compartment height to 48 to fit both lines.
Common stereotypes:
- `«interface»` — interface type, no fields, method signatures only.
- `«abstract»` — abstract class with at least one abstract method.
- `«enumeration»` — enum with value constants in the attribute compartment.
- `«datatype»` — value type with no behavior (rare; usually just a plain class).
Abstract class names may optionally use the existing `th` weight — baoyu does not render italics for abstract, the stereotype carries the meaning.
## Relationship arrows
Six UML relationship styles. Each maps to a specific arrow rendering. All connectors use `class="arr"` (or `arr-alt` for dashed variants) so they inherit dark-mode stroke colors.
| Relationship | Line style | Arrowhead | From | Typical label |
|------------------|------------|-------------------|---------------------|-------------------------------------|
| Inheritance | solid | hollow triangle | child → parent | (none) |
| Implementation | dashed | hollow triangle | class → interface | (none) |
| Association | solid | open arrow `>` | from → to | multiplicity `1`, `0..*`, `1..*` |
| Aggregation | solid | hollow diamond | container → part | (none, diamond on container side) |
| Composition | solid | filled diamond | container → part | (none, diamond on container side) |
| Dependency | dashed | open arrow `>` | user → used | optional label like `«uses»` |
### Arrow head definitions (add to `<defs>`)
The template's default `<marker id="arrow">` renders an open arrow — that works for association and dependency. For inheritance/implementation/aggregation/composition you need four additional markers. Add these to `<defs>` **only if the diagram uses them**:
```svg
<defs>
<!-- existing open-arrow marker from the template -->
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</marker>
<!-- hollow triangle for inheritance + implementation -->
<marker id="triangle-hollow" viewBox="0 0 12 12" refX="11" refY="6" markerWidth="10" markerHeight="10" orient="auto">
<path d="M1 1 L11 6 L1 11 Z" fill="none" stroke="context-stroke" stroke-width="1.2" stroke-linejoin="round"/>
</marker>
<!-- hollow diamond for aggregation -->
<marker id="diamond-hollow" viewBox="0 0 14 10" refX="1" refY="5" markerWidth="12" markerHeight="8" orient="auto">
<path d="M1 5 L7 1 L13 5 L7 9 Z" fill="none" stroke="context-stroke" stroke-width="1.2" stroke-linejoin="round"/>
</marker>
<!-- filled diamond for composition -->
<marker id="diamond-filled" viewBox="0 0 14 10" refX="1" refY="5" markerWidth="12" markerHeight="8" orient="auto">
<path d="M1 5 L7 1 L13 5 L7 9 Z" fill="context-stroke" stroke="context-stroke" stroke-width="1" stroke-linejoin="round"/>
</marker>
</defs>
```
**Why `fill="none"` instead of a hardcoded hex.** Hollow markers need to stay hollow in both light and dark mode, and any hardcoded hex color is frozen at author time — it can't respond to the template's `@media (prefers-color-scheme: dark)` block. `fill="none"` means the triangle/diamond is outlined only and the interior is transparent. At 1.2px stroke on a 10×10 marker, the 1.5px line passing behind the marker is invisible to the reader. For the filled composition diamond, `fill="context-stroke"` picks up whichever stroke color the attached line is using, so it inherits dark-mode correctly through the `class="arr"` rules.
### Using the markers
```svg
<!-- Inheritance: Circle extends Shape -->
<line x1="260" y1="200" x2="260" y2="150" class="arr" marker-end="url(#triangle-hollow)"/>
<!-- Implementation: Circle implements Drawable (dashed) -->
<line x1="260" y1="200" x2="460" y2="150" class="arr-alt" marker-end="url(#triangle-hollow)"/>
<!-- Association with multiplicity: User → Order (1 to many) -->
<line x1="180" y1="120" x2="380" y2="120" class="arr" marker-end="url(#arrow)"/>
<text class="ts" x="200" y="112">1</text>
<text class="ts" x="360" y="112">0..*</text>
<!-- Composition: Order composed of LineItems -->
<line x1="380" y1="140" x2="580" y2="140" class="arr" marker-end="url(#diamond-filled)"/>
```
**Pitfall**: the `marker-end` goes on the **parent** end for inheritance/implementation (the triangle points at the parent), and on the **container** end for aggregation/composition (the diamond sits on the container). Direction of `line`/`path` dictates which end is `start` vs `end` — always draw the arrow *toward* the marker.
## Color rule
**One ramp per kind of class**, not per position. This is the same exception as sequence diagrams — identity is a category, so using multiple ramps is fine, but each ramp must correspond to a stable *role*.
Default ramp assignments:
| Class kind | Ramp | Why |
|-------------------|-----------|---------------------------------------|
| Concrete class | `c-gray` | The default — most classes are here |
| Abstract class | `c-teal` | Signals "not directly instantiable" |
| Interface | `c-purple` | Signals "pure contract, no state" |
| Enum / datatype | `c-amber` | Signals "constants / value type" |
Cap at **3 ramps per diagram**. If you have concrete classes + interfaces + enums, use gray + purple + amber. If every class is concrete, all gray is fine and looks cleanest. Do not assign ramps by package or by author — readers won't learn the code.
**Legend implicit**: the ramps are anchored by the class kinds themselves. A reader who sees a purple `«interface» Drawable` box learns the convention immediately. No explicit legend needed unless the diagram uses >3 ramps (which shouldn't happen).
## Layout
Class diagrams are **2D grid** layouts, not linear flows. Parents live above children, interfaces sit on the side of their implementors, and association arrows run horizontally.
### Default: top-down inheritance tree
Parents / interfaces on top, children at the bottom:
```
[ «interface» Drawable ] [ Shape (abstract) ]
| |
| implements | extends
+---------+--------+---------+
| |
[ Circle ] [ Square ]
```
- Tier 1 (y=60): base types (interfaces, abstract base classes)
- Tier 2 (y=240): concrete subtypes
- Tier 3 (y=420): composed types / enums
Vertical gap between tiers: **40 px minimum**.
### 2-wide / 3-wide rows
For 46 classes per tier, pack horizontally with 20px gaps:
```
x=40 x=260 x=480 (width 180 each, gap 20)
```
For >6 classes, you're building a too-big diagram — split by package or subsystem into separate diagrams and link them with prose.
### Association arrows
Association arrows are **horizontal or L-bend**, running between classes in the same tier (or adjacent tiers). Do not let an association arrow cross an inheritance arrow — if they cross, reroute the weaker relationship (usually the association) with an L-bend.
### viewBox height
```
H = tier_count × 200 + 40
```
Where 200 px is the per-tier budget (class box height ~140 + 40 px vertical gap + 20 px margin). Round up after placing the last tier's actual box height — if a class in the last tier is extra-tall, bump H to fit.
Width stays at 680. If a tier of 3-wide boxes doesn't fit at minimum width, narrow the boxes to 180 each (total 540 + 40 gap = 580, centered at x=50).
## Worked example — Shape hierarchy
A small 4-class domain: a `Drawable` interface, an abstract `Shape` class, and two concrete subclasses `Circle` and `Square`.
**Plan:**
1. Classes: `Drawable` (interface), `Shape` (abstract), `Circle`, `Square` — 4 classes, 2 tiers.
2. Attributes/methods:
- `Drawable`: `+ draw(): void`
- `Shape`: `# color: Color`, `# position: Point`, `+ area(): number` (abstract)
- `Circle`: ` radius: number`, `+ area(): number` (override)
- `Square`: ` side: number`, `+ area(): number` (override)
3. Relationships: `Shape` implements `Drawable` (dashed + hollow triangle); `Circle` and `Square` extend `Shape` (solid + hollow triangle).
4. Colors: `Drawable` = `c-purple` (interface); `Shape` = `c-teal` (abstract); `Circle` / `Square` = `c-gray` (concrete). 3 ramps.
5. Widths:
- `Drawable`: name 8 chars, longest method "+ draw(): void" = 14 chars → `max(64, 98) + 24 = 122` → min 160
- `Shape`: name 5 chars, longest "+ area(): number" = 16 chars → `max(40, 112) + 24 = 136` → min 160
- `Circle`/`Square`: ~13 chars longest → min 160
6. Tier 1 (y=60): `Drawable` at x=130, `Shape` at x=390 (row of 2, both width 160, gap 100).
7. Tier 2 (y=260): `Circle` at x=130, `Square` at x=390 (row of 2, width 160, gap 100).
8. Arrows:
- `Shape → Drawable` (implements): horizontal dashed line from Shape's left edge (x=390, y=110) to Drawable's right edge (x=290, y=110).
- `Circle → Shape` (extends): L-bend from Circle's top (x=210, y=260) up to ymid=220, right to x=470, up to Shape's bottom (x=470, y=200).
- `Square → Shape` (extends): straight vertical from Square's top (x=470, y=260) to Shape's bottom (x=470, y=200).
**Coordinates (abbreviated; production code would fill in every `<text>`):**
```svg
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 680 420" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif">
<style>/* template block ... */</style>
<defs>
<marker id="arrow" .../>
<marker id="triangle-hollow" .../>
</defs>
<!-- Tier 1: Drawable (interface, purple) -->
<g class="c-purple">
<rect x="130" y="60" width="160" height="100" rx="6"/>
<text class="ts" x="210" y="76" text-anchor="middle" dominant-baseline="central">«interface»</text>
<text class="th" x="210" y="92" text-anchor="middle" dominant-baseline="central">Drawable</text>
<line class="arr" x1="130" y1="104" x2="290" y2="104" stroke-width="0.5"/>
<!-- empty attribute compartment -->
<line class="arr" x1="130" y1="120" x2="290" y2="120" stroke-width="0.5"/>
<text class="ts" x="142" y="138">+ draw(): void</text>
</g>
<!-- Tier 1: Shape (abstract, teal) -->
<g class="c-teal">
<rect x="390" y="60" width="160" height="140" rx="6"/>
<text class="ts" x="470" y="76" text-anchor="middle" dominant-baseline="central">«abstract»</text>
<text class="th" x="470" y="92" text-anchor="middle" dominant-baseline="central">Shape</text>
<line class="arr" x1="390" y1="104" x2="550" y2="104" stroke-width="0.5"/>
<text class="ts" x="402" y="122"># color: Color</text>
<text class="ts" x="402" y="140"># position: Point</text>
<line class="arr" x1="390" y1="152" x2="550" y2="152" stroke-width="0.5"/>
<text class="ts" x="402" y="170">+ area(): number</text>
</g>
<!-- Tier 2: Circle (concrete, gray) -->
<g class="c-gray">
<rect x="130" y="260" width="160" height="110" rx="6"/>
<text class="th" x="210" y="280" text-anchor="middle" dominant-baseline="central">Circle</text>
<line class="arr" x1="130" y1="292" x2="290" y2="292" stroke-width="0.5"/>
<text class="ts" x="142" y="310"> radius: number</text>
<line class="arr" x1="130" y1="322" x2="290" y2="322" stroke-width="0.5"/>
<text class="ts" x="142" y="340">+ area(): number</text>
</g>
<!-- Tier 2: Square (concrete, gray) -->
<g class="c-gray">
<rect x="390" y="260" width="160" height="110" rx="6"/>
<text class="th" x="470" y="280" text-anchor="middle" dominant-baseline="central">Square</text>
<line class="arr" x1="390" y1="292" x2="550" y2="292" stroke-width="0.5"/>
<text class="ts" x="402" y="310"> side: number</text>
<line class="arr" x1="390" y1="322" x2="550" y2="322" stroke-width="0.5"/>
<text class="ts" x="402" y="340">+ area(): number</text>
</g>
<!-- Shape implements Drawable (dashed, hollow triangle on Drawable side) -->
<line x1="390" y1="110" x2="290" y2="110" class="arr-alt" marker-end="url(#triangle-hollow)"/>
<!-- Circle extends Shape (solid L-bend) -->
<path d="M 210 260 L 210 230 L 470 230 L 470 200" class="arr" fill="none" marker-end="url(#triangle-hollow)"/>
<!-- Square extends Shape (solid straight) -->
<line x1="470" y1="260" x2="470" y2="200" class="arr" marker-end="url(#triangle-hollow)"/>
</svg>
```
viewBox H: bottom of last box is `260 + 110 = 370`, so `H = 370 + 20 = 390`. The example uses 420 for a 30px bottom margin, which is also fine.
## Checklist (class-specific)
On top of the standard `pitfalls.md` checks:
1. Every class has all **three compartments** (name / attrs / methods), even if one is empty.
2. The class **name is `th` centered**, attributes/methods are **`ts` left-aligned at `rect_x + 12`**.
3. Every attribute/method starts with a **visibility marker** (`+ # ~`).
4. Dividers use `class="arr"` with **inline `stroke-width="0.5"`**.
5. Inheritance and implementation arrows point **toward the parent/interface** (triangle on parent side).
6. Aggregation and composition diamonds sit on the **container side**, not the part side.
7. Associations carry **multiplicity labels** at both ends (`1`, `0..*`, `1..*`) when they aren't obvious.
8. Dashed arrows are `arr-alt`, solid arrows are `arr` — never mix.
9. Color ramp budget ≤3, one per class kind (concrete / abstract / interface / enum).
10. Association arrows **do not cross inheritance arrows** — if they do, re-route the association.
@@ -0,0 +1,157 @@
# Design System
The rules that make every diagram feel consistent. Adapted from Anthropic's Imagine Visual Creation Suite for standalone SVG output (self-contained, no host CSS, safe to embed anywhere).
## Philosophy
- **Flat**: No gradients, no drop shadows, no blur, no glow, no neon. Clean flat surfaces only. (One exception — see Illustrative diagrams.)
- **Compact**: Show the essential inline. If something needs a paragraph of explanation, it doesn't belong inside the diagram — move it to the prose around the diagram.
- **Seamless**: The SVG should feel like a native part of the surrounding article, not a foreign object. Transparent background — the host page provides the background.
- **Self-contained**: Every SVG carries its own `<style>` block and color definitions so it renders correctly in browsers, WeChat articles, markdown viewers, Notion, and any other host. See `svg-template.md`.
## Typography
Two body sizes. Sentence case. Plus a tiny poster toolkit for flowcharts that need a title and section headers.
**Body classes** (used by every diagram type):
| Class | Size | Weight | Use for |
|--------|------|--------|------------------------------------------------------------|
| `t` | 14px | 400 | Body text inside neutral boxes, single-line labels |
| `th` | 14px | 500 | Titles — the bold line in a two-line node |
| `ts` | 12px | 400 | Subtitles, descriptions, leader-line callouts, legends |
**Poster classes** (optional — only for poster flowcharts with titles and phase-grouped sections; see `flowchart.md`):
| Class | Size | Weight | Use for |
|-----------|---------|---------|----------------------------------------------------------------------------------|
| `title` | 20px | 600 | The mechanism name at the top of a poster flowchart. Used **once** per diagram. |
| `eyebrow` | 10px | 500 | Uppercase letter-spaced section dividers between phases. Muted gray. ≤40 chars. |
| `caption` | 12px | 400 italic | One-line footer hook below the whole diagram. Italic, muted gray. |
| `anno` | 12px | 400 | Side-column annotation text next to a box ("sees: X / fresh context"). Muted. |
Rules:
- **Never use font sizes outside this table.** Body diagrams get 14 and 12 only. Poster flowcharts can also use 20 (title) and 10 (eyebrow). No decorative 16/18/24.
- **Never use font-weight above 600.** 400, 500, and the single 600 in `.title` are the whole vocabulary.
- **Sentence case for body text.** "User login" not "User Login". The `.eyebrow` class is the single exception — its `text-transform: uppercase` is intentional typographic structure, not shouting.
- **No mid-sentence bolding.** If you need to emphasize a term, it belongs in a title (`th` or `title`) or as a label, not as bold text inside a subtitle.
- **No emoji.** Use simple SVG shapes (circles, triangles, lines) when you need a visual indicator.
Font family: the template sets `font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif` on the `<svg>` element. This gives the user's native system font, which is the closest portable approximation of Anthropic Sans.
## Color palette
Nine ramps, seven stops each, from the Imagine design system. Lower numbers are lighter; higher numbers are darker.
| Ramp | 50 | 100 | 200 | 400 | 600 | 800 | 900 |
|----------|----------|----------|----------|----------|----------|----------|----------|
| gray | #F1EFE8 | #D3D1C7 | #B4B2A9 | #888780 | #5F5E5A | #444441 | #2C2C2A |
| blue | #E6F1FB | #B5D4F4 | #85B7EB | #378ADD | #185FA5 | #0C447C | #042C53 |
| teal | #E1F5EE | #9FE1CB | #5DCAA5 | #1D9E75 | #0F6E56 | #085041 | #04342C |
| purple | #EEEDFE | #CECBF6 | #AFA9EC | #7F77DD | #534AB7 | #3C3489 | #26215C |
| coral | #FAECE7 | #F5C4B3 | #F0997B | #D85A30 | #993C1D | #712B13 | #4A1B0C |
| pink | #FBEAF0 | #F4C0D1 | #ED93B1 | #D4537E | #993556 | #72243E | #4B1528 |
| amber | #FAEEDA | #FAC775 | #EF9F27 | #BA7517 | #854F0B | #633806 | #412402 |
| green | #EAF3DE | #C0DD97 | #97C459 | #639922 | #3B6D11 | #27500A | #173404 |
| red | #FCEBEB | #F7C1C1 | #F09595 | #E24B4A | #A32D2D | #791F1F | #501313 |
### Light-mode color binding (what the template emits)
For any colored box use the ramp class on the shape or its immediate parent `<g>`:
- **fill**: stop 50 (lightest)
- **stroke**: stop 600 (strong border)
- **title text** (`th` class inside): stop 800 (darkest legible)
- **subtitle text** (`ts` class inside): stop 600 (one step lighter than title)
Title and subtitle MUST use different stops. Same stop reads flat; the 500 vs 400 weight alone is not enough contrast.
### Dark-mode color binding (automatic via `@media`)
- **fill**: stop 800
- **stroke**: stop 200
- **title text**: stop 100 (near-white on the ramp)
- **subtitle text**: stop 200
The template's `@media (prefers-color-scheme: dark)` block handles this automatically. No extra work required — just use the `c-{ramp}` classes.
## Color assignment rules
**Color encodes meaning, not sequence.** A diagram with five steps is not rainbow-colored — all five get the same ramp (or gray) unless they belong to different categories.
1. **Group by category**, not by position. All "immune cells" get purple. All "pathogens" get coral. Not step-1 blue, step-2 teal, step-3 amber.
2. **Use ≤2 ramps per diagram.** Gray + one accent is often the cleanest. More than two and the diagram starts to look like a child's toy.
3. **Gray is the default for neutral, structural, generic, start, or end nodes.** Reach for gray first, color second.
4. **Reserve blue/green/amber/red for semantic meaning** — blue for information, green for success, amber for warning, red for error. These carry strong UI connotations that surprise readers if used as "just another color". When you need a neutral accent, prefer purple, teal, coral, or pink.
5. **Exception — illustrative diagrams can use warm/cool mapping:** in illustrative cross-sections, warm ramps (amber, coral, red) mean heat/energy/pressure/activity, cool ramps (blue, teal) mean cold/calm/dormant. This is a physical mapping, not a semantic one, so it's fine.
6. **Exception — sequence diagrams may use one ramp per actor, up to 4 ramps total.** Each actor's header, lifeline context, and the arrows *originating* from that actor share a single ramp. Actor identity is a category (not a sequence), so this obeys the "encode meaning" rule — it just allows more categories than the normal ≤2-ramp cap. The legend is implicit: every ramp is anchored by its labeled actor header at the top of the diagram. See `sequence.md`.
7. **Exception — poster flowcharts may use up to 4 ramps, one per distinct agent/role.** Same principle as the sequence exception: the drafter, the critic, the synthesizer, and the judge are four different *kinds* of operation, not four sequential steps. Each ramp anchors identity. The stage's title box makes the legend implicit. See `flowchart-poster.md`.
8. **Exception — phase-band diagrams may use up to 3 ramp-colored arrow classes** when each ramp encodes a distinct *path type* (e.g., normal flow vs. exploit path vs. data exfiltration). The path type is the information the arrow carries — the ramp makes it visible at a glance rather than relying on labels on every crossing arrow. **A legend strip is mandatory.** See `flowchart-phase-bands.md`.
### If colors or arrow styles encode meaning, add a one-line legend
When a reader has to know what "purple means immune cell" to read the diagram, emit a small legend near the bottom with swatches:
```
[■] Immune cells [■] Pathogens [■] Outcome
```
The **same rule applies to arrow styles**. If the diagram uses ≥2 distinct arrow styles that carry meaning — solid `.arr` vs dashed `.arr-alt`, or two `.arr-{ramp}` colors for "memory read" vs "memory write" — add a legend entry for each style alongside the color swatches:
```
[──] Primary flow [- -] Alternative path [■] Active agent [■] Store
```
A one-line legend is worth more than thirty words of explanatory text. When colors are just for visual interest (no encoded meaning) and only one arrow style is used, skip the legend.
## Icon / glyph policy
Most diagrams are pure text-in-boxes with arrows. When a box really does need a small pictorial element — a checkbox next to a TODO, a ✓/✗ circle on a decision branch, a document icon inside a "shared state store" box — use the shared glyph library at `references/glyphs.md`. Do not draw ad-hoc icons.
**Sourcing rule.** Every glyph must come from the `glyphs.md` set:
- `status-circle-check`, `status-circle-x`, `status-circle-dot` — decision/result indicators on arrow paths
- `checkbox-checked`, `checkbox-empty` — TODO list items
- `queue-slot-filled`, `queue-slot-empty` — queue visualization inside a box
- `doc-icon`, `terminal-icon`, `script-icon` — decorative icons inside a box
- `code-braces`, `annotation-circle` — label decorations
- `dashed-future-rect` — not yet executed / future state
- `pub-sub-arrow-pair` — paired publish/subscribe arrows for bus topology
If you need something that isn't in that list, either re-use the closest existing glyph or label the concept with plain text — do not invent a new icon shape inline. Adding a new glyph is a deliberate change to `glyphs.md`, not an improvisation inside a single SVG.
**Dark-mode rule.** Every glyph element — every `<circle>`, `<rect>`, `<path>`, `<line>`, `<text>` that makes up a glyph — must inherit its color from one of the existing classes defined in `svg-template.md`:
- Shape fill/stroke: `box`, `c-{ramp}`, `arr`, `arr-alt`, `arr-{ramp}`
- Text: `t`, `th`, `ts`
Never emit inline `fill="#..."`, `stroke="#..."`, or `color="#..."` inside a glyph. Hex colors are frozen at author time and do not participate in the `@media (prefers-color-scheme: dark)` re-mapping, so inline-colored glyphs become invisible or wrong-contrast in dark mode. The only inline colors permitted anywhere in a glyph are `fill="none"` and `stroke="none"` — both of which are colorless and safe.
**Scope rule.** Glyphs are not allowed everywhere:
| Diagram type | May use glyphs? | Notes |
|--------------|-----------------|-----------------------------------------------------------------------------------------------|
| flowchart | yes | Status circles on decision branches, queue slots inside a box, checkboxes inside a checklist. |
| structural | yes | Doc/terminal/script icons inside a "state store" box, checkboxes inside a side-by-side list. |
| illustrative | yes | Annotation circle on a connector; decorative icon inside a subject box. |
| sequence | no | Sequence diagrams express everything through messages and lifelines — keep them text-only. |
When in doubt, do not add a glyph. A diagram that needs a pictorial hint to be understood is usually a diagram whose labels are too terse.
## Hard rules
These never bend (except where an exception is listed explicitly).
- No `<!-- comments -->` inside the final SVG output (they waste bytes and don't help readers).
- No gradients, shadows, blur, glow, neon. Flat fills only. Exception: illustrative diagrams may use ONE `<linearGradient>` between two stops of the same ramp to show a continuous physical property (temperature, pressure). See `illustrative.md`.
- No dark or colored background on the outer `<svg>` element. Transparent only — the host provides the background.
- No font size outside the typography table. Body diagrams use 14 and 12. Poster flowcharts may *additionally* use 20 (title) and 10 (eyebrow). Nothing else.
- Sentence case for body text. The `.eyebrow` class's `text-transform: uppercase` is the single allowed ALL-CAPS usage — it's a typographic eyebrow label, not shouting.
- No emoji. Use SVG primitives (circles, triangles, lines) when you need a glyph.
- No rotated text (`transform="rotate(...)"` on `<text>`). Exception: a single left-rail loop-scope label in a poster flowchart may use `transform="rotate(-90 ...)"` — this is the *only* place rotated text is allowed. See `flowchart.md` → "Loop-scope bracket".
- No `filter`, no `pattern`, no radial gradients. The only thing allowed in `<defs>` is the arrow marker, an optional `<clipPath>`, and — for illustrative only — one `<linearGradient>`.
- `<text>` never auto-wraps in SVG. If a label is long enough to need wrapping, it's too long — shorten it or split across two `<text>` elements stacked vertically. See `layout-math.md` for character budgets.
## Why these rules exist
Most of the rules trace back to one principle: **the diagram has to survive streaming rendering, dark mode, and embedding in unknown hosts**. Gradients flash during streaming. CSS variables don't exist outside claude.ai. Emoji render at font-inherited sizes and blow up scale. Rotated text misaligns on CJK fonts. Rainbow colors look like decoration, not information. The design system is narrow on purpose so the result is consistent and portable.
@@ -0,0 +1,278 @@
# Flowchart: Phase Band Layout
Load this file when the prompt describes a **multi-phase sequential operation** where each phase is a named stage containing several parallel tools or steps, and arrows cross between phases to show how outcomes propagate. Typical triggers:
- "Multi-phase attack / penetration test / security operation"
- "Phased workflow with tools at each stage"
- "Show what happens in each phase, and how findings from Phase N feed Phase N+1"
- "Phase 1 / Phase 2 / Phase 3 diagram"
- Source content from security research, incident response, pipeline audits, or any multi-stage operation where each phase has its own "toolkit"
**What distinguishes this from a poster flowchart:** A poster flowchart is a single vertical flow with a strong narrative arc (one loop, one judge, one outcome). A phase-band diagram is a horizontal-band composition — each band is a self-contained stage with its own set of parallel tools, connected to other bands by semantic crossing arrows. The band, not the individual box, is the unit of meaning.
## Canvas geometry
viewBox: `0 0 680 H`
All phase-band diagrams use the standard 680-wide canvas. The space is partitioned into three vertical columns:
```
x = 0 … 64 Left operator column — operator icons + connecting arrows
x = 64 … 480 Main flow zone — phase bands, tool card rows, flow arrows
x = 480 … 648 Annotation zone — side notes, callout boxes
x = 648 … 680 Right breathing room
```
**Band container geometry:**
| Element | Coordinates |
|----------------------|----------------------------------------------|
| Band left edge | `x = 64` |
| Band right edge | `x = 648` |
| Band width | `584` |
| Band padding (sides) | `16` px |
| Main flow interior | `x = 80` to `x = 472` (392 px wide) |
| Annotation interior | `x = 488` to `x = 632` (144 px wide) |
**Vertical geometry:**
```
top padding y = 40
first band top y = 40
between-band gap 16 px
H = 40 + sum(band_h[i]) + (N1) × 16 + 20
```
Each band's height depends on its content. The minimum is **100 px** (phase label row + one card row + padding). Add 80 px for each additional card row. Add 56 px if the band has a side annotation that's taller than the tool row.
---
## Phase band container
Each phase is a full-width dashed-border rounded rect. The phase label sits inside the band at top-left.
```svg
<g class="c-gray">
<rect x="64" y="{band_y}" width="584" height="{band_h}" rx="12"
fill="none" stroke-dasharray="4 4"/>
<text class="eyebrow" x="80" y="{band_y + 18}" text-anchor="start">Phase 1</text>
</g>
```
Rules:
- **`fill="none"`** — dashed bands are schematic regions, not solid boxes. A filled band fights with the tool cards inside it.
- **`stroke-dasharray="4 4"` inline** — same convention as subsystem containers (`structural.md`).
- **`class="c-gray"` on the `<g>`** — gives the dashed stroke its dark-modesafe color without a hardcoded hex.
- **Eyebrow label** — use the `.eyebrow` class (`10px, 500 weight, text-transform: uppercase`). Short labels only: "Phase 1", "Phase 2 — Reconnaissance", "Phases 4 & 5". Never more than 30 characters.
- **No title at the top level** — phase-band diagrams don't use the `.title` class. The diagram's subject is communicated by its surrounding prose, not a poster-style banner.
---
## Tool card rows
Each band's main flow zone holds one or two horizontal rows of compact tool cards. Use the `compact tool card` template from `glyphs.md` → "Compact tool card node template".
**Row placement inside a band:**
```
card_row_y = band_y + 28 (first row — 28px below band top, clearing the phase label)
card_row_y = band_y + 28 + 88 (second row, if needed — 88 = card_h + 8px gap)
```
**Row centering:**
```
row_width = N × card_w + (N1) × gap
row_start_x = 80 + (392 row_width) / 2
card[i].x = row_start_x + i × (card_w + gap)
```
Use `gap = 8` for ≤4 cards at 80 wide, `gap = 6` for 5 cards at 72 wide.
**Arrows between cards inside a band:**
Connect consecutive tool cards with short horizontal `.arr` lines:
```svg
<line x1="{prev_card_right + 5}" y1="{card_cy}"
x2="{next_card_left 5}" y2="{card_cy}"
class="arr" marker-end="url(#arrow)"/>
```
Where `card_cy = card_y + card_h / 2 = card_y + 40`.
For arrows that skip a card or fork into two paths, route with an L-bend above the row at `y = card_row_y 12`.
---
## Side annotations
Annotations in the right column (x = 488632) explain what happens at a phase level or for a group of tool cards. They use the same `anno`-class text convention as poster flowcharts but are wrapped in a light `box`-class rect for visual anchoring.
**Annotation box template:**
```svg
<rect class="box" x="488" y="{anno_y}" width="144" height="{anno_h}" rx="6"/>
<text class="ts" x="496" y="{anno_y + 14}" text-anchor="start">{line 1}</text>
<text class="ts" x="496" y="{anno_y + 28}" text-anchor="start">{line 2}</text>
<!-- additional lines at +14 pitch -->
```
Rules:
- **Max 18 chars per line.** At 7 px/char that's 126 px — fits inside the 144-wide box with 9 px padding each side.
- **Max 4 lines.** `anno_h = 14 + lines × 14 + 10` (min 38).
- **Connect to the band with a short leader line**, not an arrowhead:
```svg
<line x1="480" y1="{anno_cy}" x2="488" y2="{anno_cy}" class="arr" stroke-dasharray="2 2"/>
```
Where `anno_cy` = vertical center of the annotation box. The short dashed leader communicates "this note belongs to that band" without the visual weight of a full arrow.
**Positioning.** Vertically center the annotation box against the tool card row it describes:
```
anno_y = card_row_y + (card_h anno_h) / 2
```
If the annotation is longer than the tool card row, let it extend below — just ensure the band height accommodates it.
---
## Cross-band arrows (semantic multi-path)
The most distinctive feature of phase-band diagrams is arrows that cross from one band to another, each color carrying a semantic meaning (normal flow, attack path, data path, etc.).
**Color convention for security/operation diagrams:**
| Path type | Arrow class | Typical label |
|-------------------|---------------|----------------|
| Normal flow | `arr` | (unlabeled) |
| Exploit / attack | `arr-coral` | (unlabeled) |
| Findings / data | `arr-amber` | (unlabeled) |
| Callback / return | `arr-teal` | (unlabeled) |
**Color budget exception.** Phase-band diagrams may use **up to 3 ramp-colored arrow classes** when each ramp encodes a distinct path type. This is the only flowchart variant where more than 2 ramps are allowed — the path type IS the information. A legend strip is **required** (see Legend below).
**Routing rules for cross-band arrows:**
Route all cross-band arrows through the **left routing channel** at `x = 2054`. This keeps them visually separated from the band content and creates a clean "spine" on the left margin:
```
cross-band arrow: exits left edge of source band, travels down the left channel, enters left edge of target band
```
```svg
<!-- Example: arrow from Phase 2 bottom row → Phase 3, entering at band left edge -->
<path class="arr-coral"
d="M {source_card_cx} {source_card_y + 80}
L {source_card_cx} {phase2_bottom + 8}
L 30 {phase2_bottom + 8}
L 30 {phase3_top 8}
L 80 {phase3_top 8}
L 80 {phase3_first_card_y + 40}"
fill="none" marker-end="url(#arrow-coral)"/>
```
The routing path: exit downward from the source card → horizontal to the left channel at x=30 → descend to the target band level → horizontal right into the band interior → enter the target card.
**Arrow marker by ramp.** The defs block in `svg-template.md` defines `#arrow` (gray, default). For ramp-colored arrows, use `url(#arrow-{ramp})` — the template provides coral, amber, teal variants. If the template's defs don't include a specific ramp marker, fall back to `url(#arrow)` — the arrowhead will be gray but the stroke will carry the ramp color.
**Label policy.** Cross-band arrows generally need **no label** — the color carries the semantic, and the source and target cards already name the tools. Add a 13 word `ts` label only if the path type would be ambiguous without it (e.g., two coral arrows that mean different things).
---
## Legend strip
**Required** when the diagram uses ≥2 distinct arrow ramp colors. Place the legend at the bottom of the canvas, below all bands, at `y = last_band_bottom + 24`:
```svg
<!-- Legend: 3-color path key -->
<line class="arr" x1="64" y1="{leg_y}" x2="84" y2="{leg_y}" marker-end="url(#arrow)"/>
<text class="ts" x="88" y="{leg_y + 4}">Normal flow</text>
<line class="arr-coral" x1="180" y1="{leg_y}" x2="200" y2="{leg_y}" marker-end="url(#arrow)"/>
<text class="ts" x="204" y="{leg_y + 4}">Exploit path</text>
<line class="arr-amber" x1="296" y1="{leg_y}" x2="316" y2="{leg_y}" marker-end="url(#arrow)"/>
<text class="ts" x="320" y="{leg_y + 4}">Findings</text>
```
Keep the legend to ≤4 entries. Each entry occupies ~116 px wide: 20px line + 8px gap + label. The first entry aligns with the band left edge at x=64.
---
## Operator icons
Place operator icons (from `glyphs.md` → "Operator icons") in the left column at x=16, vertically centered on the band they initiate. The typical arrangement is human → ai stacked vertically, connected by a short `.arr` line, with a final arrow from the ai icon into the first band's left edge.
```
operator-human: translate(16, phase1_band_cy 48)
operator-ai: translate(16, phase1_band_cy 4)
connecting line: y1 = operator_human_bottom+2, y2 = operator_ai_y2
entry arrow: from (48, operator_ai_cy) → (62, operator_ai_cy), then into band via L-bend
```
Labels (if used): `ts` text at `x=32`, `text-anchor="middle"`, placed 8px below each icon.
---
## Band height calculation
For a band with:
- Phase label row: 22 px
- One tool card row: 80 px
- Top padding: 6 px, bottom padding: 12 px
Minimum: `6 + 22 + 80 + 12 = 120 px`
For two card rows: `6 + 22 + 80 + 8 + 80 + 12 = 208 px`
For a band with an annotation taller than the card row, use the annotation height + padding:
`band_h = max(card_rows_h, anno_h) + 28 + 18`
---
## Worked coordinate sketch
For a 3-band diagram (Phase 1: 1 card row, Phase 2: 2 card rows with annotation, Phase 3: 2 card rows with cross-band arrows):
```
Phase 1 band: y=40, h=120 → bottom y=160
eyebrow at (80, 58)
1 row of 3 cards (80×80) at y=70, centered in x=80472
cards centered: row_w=3×80+2×8=256, row_start=80+(392-256)/2=148
card centers: (188, 110), (276, 110), (364, 110)
between-band: 16px gap → y=176
Phase 2 band: y=176, h=208 → bottom y=384
eyebrow at (80, 194)
row 1 of 5 cards (72×80) at y=206: row_w=5×72+4×6=384, start=84
cards: (84, 206), (162, 206), (240, 206), (318, 206), (396, 206)
row 2 of 2 cards (80×80) at y=302: start=196
annotation box: x=488 y=234 w=144 h=60
annotation text: 3 lines at y=248, 262, 276
between-band: 16px gap → y=400
Phase 3 band: y=400, h=208 → bottom y=608
cross-band arrow (Phase 2 → Phase 3):
coral: from (396+36, 286) → (396+36, 393) → (30, 393) → (30, 417) → (80, 417) → (80, 480)
legend strip: y=628
viewBox H: 628 + 24 + 16 + 20 = 688 → round to 700
viewBox: 0 0 680 700
```
---
## Common failure modes
- **Too many cards per row.** 6 cards at 80px = 532px — overflows the 392px main flow zone. Shrink cards to 64px, split into two rows, or drop the annotation zone and use the full 584px band width with cards up to 96px.
- **Cross-band arrows routed through band content.** Always exit to the left routing channel (x=2054) before crossing band boundaries. A coral arrow slashing diagonally through a tool card is the #1 visual failure in this layout.
- **Phase label hidden by card row.** The card row y must start at `band_y + 28` at minimum (28 = 10px top padding + 18px for eyebrow text height). Starting at `band_y + 16` clips the eyebrow.
- **Annotation text too long.** Max 18 Latin chars / 9 CJK chars per line in the 144-wide annotation box. "Findings recorded and analyzed. Human reviews summary." needs to be split: "Findings recorded" / "and analyzed." / "Human reviews."
- **All tool cards colored differently.** Color encodes meaning — 5 different ramps for 5 tool cards reads as "these tools belong to 5 different categories" which is usually wrong. Use gray for all; promote only the one card that's the focal point.
- **Legend missing when using ramp arrows.** If you use `arr-coral` or `arr-amber`, you must emit a legend strip. A reader who sees red arrows without a legend doesn't know if "red = danger" or "red = Phase 3 path" or "red = selected".
@@ -0,0 +1,203 @@
# Flowchart: Poster Pattern
Load this file when **≥3 of the poster triggers in Step 4a** fire: the topic has a short name, a "why it exists" sentence, named phases, parallel candidates, a loop condition, overflow annotations, or a footer quote.
A poster flowchart is a richer dialect of the regular flowchart, meant for topics that have a **name, a motivation, phases, parallel candidates, and a loop condition** — things like research methods, iterative algorithms, reasoning frameworks. Instead of a flat sequence of boxes, it reads like a one-page explainer: title at the top, eyebrow-labeled phases, side notes, a left-rail loop bracket, and a footer hook.
This is the dialect the reader remembers. Use it when the content earns it — not every flowchart deserves this treatment.
## When to switch into poster mode
Check all of these. If three or more are true, switch to poster mode:
- [ ] The topic has a **short name** (Autoreason, Chain-of-Thought, AutoResearch, Reflexion) that belongs on the page as a title.
- [ ] The source has a **"why this exists" sentence** that belongs under the title as a subtitle.
- [ ] The stages **group into 24 named phases** (e.g., "The loop" / "Three candidates generated" / "Convergence check"), not just one monotonic column.
- [ ] At some point **N parallel candidates are generated** and then compared — a fan-out + judge pattern.
- [ ] There's a **loop with a specific termination mechanic** (streak counter, convergence check, fixed iteration cap).
- [ ] Individual boxes need **context that won't fit as a subtitle** — "sees X, no bias, fresh context" — which wants to live in a right-side annotation column.
- [ ] The source has a **quotable hook** (a test result, a framing quote) that belongs in a footer caption.
If only 01 of these are true, stick with the simple flowchart. Poster machinery on a three-box diagram is over-dressed.
## Anatomy
```
[ TITLE (20px bold, centered) ]
[ Subtitle (ts, one line, centered) ]
[ EYEBROW: PHASE 1 ]
[ box ] [ side anno ]
[ box ] [ side anno ]
[ EYEBROW: PHASE 2 ]
┌ [ box ] [ box ] [ box ] ← fan-out row
│ \ | /
│ \ | /
│ [ judge box ] ←——— [ side anno ]
│ [ EYEBROW: PHASE 3 ]
│ [ convergence / streak box ] ←——— [ side anno ]
└ (dashed left rail, rotated label "loop until …")
[ CAPTION: footer hook (italic ts, centered) ]
```
The left rail is a dashed vertical line with a rotated label, visually scoping which boxes are "inside the loop". The right side is an annotation column — each major box can have a short `anno`-class note sitting at its right edge.
## Layout budget
A poster flowchart is taller and denser than a simple flowchart. The soft node cap jumps:
- Simple flowchart: ≤5 nodes.
- Poster flowchart: ≤12 nodes, grouped into ≤4 phases. Each phase should fit in 24 boxes.
viewBox width is still 680, but the interior is now divided into a main column and an annotation column:
| Column | x range | Used for |
|---------------|----------|------------------------------------------------------|
| Loop rail | 4060 | Dashed vertical line + rotated label (optional) |
| Main flow | 80470 | Boxes, arrows, eyebrows, title, caption |
| Annotation | 485640 | `anno`-class side notes (12px, left-anchored) |
Center the main column at x=275 (midpoint of 80 and 470), with box width up to 390. Eyebrow labels sit at x=80 (left-anchored) so they feel like "the section starts here" rather than drifting in the middle.
## Vertical geometry
```
title baseline y = 46 (class "title")
subtitle baseline y = 68 (class "ts")
first eyebrow y = 100 (class "eyebrow")
first main box top y = 116 (gap 16 below eyebrow)
phase separator y = box_bottom + 32 (eyebrow) — eyebrow label sits 16 above next box
caption baseline y = last_box_bottom + 44 (class "caption", italic ts)
viewBox height H = caption_y + 20
```
Boxes inside a phase use a 16px vertical gap between a box and the next (tighter than the 60px used in simple flowcharts — poster mode is more compact because the eyebrow already gives visual breathing room).
## Title and subtitle
Place the `.title` element at roughly (340, 46), `text-anchor="middle"`, `dominant-baseline="central"`. Keep it to 13 words — "Autoreason", "Chain-of-thought", "Reflexion loop". If you need a verb, you're doing a caption, not a title.
Place the subtitle at (340, 68), `text-anchor="middle"`, `class="ts"`. One line only. Use it to answer "why does this method exist" in the reader's language: *"No score to optimize? Replace the metric with agents arguing."* Pitch the question, don't define the mechanism — the mechanism is the diagram itself.
## Eyebrow section headers
A `.eyebrow` is a tiny uppercase label that separates phases. Place it at x=80 (left-anchored), `text-anchor="start"`, and let the CSS `text-transform: uppercase` handle the casing — write the label in sentence case in the source. Keep labels short (≤40 chars) and *descriptive of the phase*, not the specific box:
- Good: "The loop", "Three candidates generated", "Convergence check"
- Bad: "Step 2", "Authentication service", "Click handler"
Eyebrows are dividers, not titles. They should feel quiet — if a reader notices them first, they're too loud.
## Anchor box
When a constant input is shared across every stage (the user's task prompt, the training dataset, a knowledge base), draw it **above** the main loop with an eyebrow like "ANCHOR — SEEN BY ALL AGENTS" (write it sentence-case; the CSS uppercases). This visually communicates "this thing doesn't iterate — it's the fixed reference". The arrow from the anchor into the first loop box can be a short straight line or omitted entirely if the eyebrow makes the relationship clear.
## Fan-out + judge pattern
When N candidates are generated in parallel and then compared, lay them out as a horizontal row feeding into a single judge box below. Suggested coordinates for 3 candidates, each 160 wide:
```
Row centers: 165, 275, 385
Row y: (chosen by phase position)
Row box w: 160, h: 72 (three-line is allowed here: label · id + two descriptive lines)
Gap: 110 px (from center to center: 275 - 165 = 110)
```
Arrows from each candidate converge on the judge box below. Route each as an L-bend that meets a common `ymid` a few pixels above the judge box top, then drops straight down into the judge's top edge:
```svg
<path d="M 165 P1b L 165 ymid L 275 ymid" class="arr"/>
<line x1="275" y1="P2b" x2="275" y2="ymid" class="arr"/>
<path d="M 385 P3b L 385 ymid L 275 ymid" class="arr"/>
<line x1="275" y1="ymid" x2="275" y2="judge_top-10" class="arr" marker-end="url(#arrow)"/>
```
where `P1b`, `P2b`, `P3b` are the candidate box bottoms and `ymid` is a horizontal channel 1220px below them. Only the final vertical into the judge carries the arrowhead — the convergence into `ymid` is unheaded.
The candidates often want slightly different colors to communicate "these are three distinct things, not three steps". Using three ramps here is fine; it's an identity category, not a sequence. Keep gray for "A · keep (unchanged)" because it's the status-quo baseline — the accent ramps go to the boxes that represent actual work.
## Side-annotation column
When a box needs more context than fits in its subtitle — "sees task + draft A / adversarial by design / fresh context" — put the overflow in the right annotation column at x=485, text-anchor="start", class="anno". Stack 13 short lines vertically, each 14px tall:
```svg
<text class="anno" x="485" y="box_cy - 14" text-anchor="start">sees: task + draft A</text>
<text class="anno" x="485" y="box_cy" text-anchor="start">adversarial by design</text>
<text class="anno" x="485" y="box_cy + 14" text-anchor="start">fresh context</text>
```
`box_cy` is the vertical center of the box the annotation belongs to. Always keep each line ≤22 characters so the column doesn't spill past x=640. Annotations are *quiet* — they use the `anno` class (muted gray in both modes) and never have their own boxes or borders.
## Loop-scope bracket (left rail)
When a phase or a contiguous set of phases repeat until a condition is met, draw a dashed vertical line along the left margin at x=55 from the top of the loop to the bottom, and place a rotated label to the left of it:
```svg
<line x1="55" y1="loop_top" x2="55" y2="loop_bottom" class="leader"/>
<text class="ts" x="45" y="(loop_top+loop_bottom)/2"
text-anchor="middle"
dominant-baseline="central"
transform="rotate(-90 45 LOOP_CENTER_Y)">loop until streak = 2</text>
```
Use the `leader` class for the line (dashed, light gray) so it doesn't compete with the forward arrows. Keep the rotated label to ≤20 characters. This is the **only** place rotated text is allowed in the whole skill — do not use `transform="rotate"` anywhere else.
## Convergence / termination box
The loop needs to visibly terminate somewhere. Draw a final box (usually gray) that holds the *termination mechanic itself* — not a generic "converged" flag, but the actual rule:
```
Winner becomes new A
A wins again: streak++
B or AB wins: streak = 0
```
The convergence box is three-line (h=72) to hold the mechanic plainly. The right annotation column expands the semantics:
```
streak = 2?
stop, converged
streak = 0?
loop again
```
## Footer caption
A single italic ts line at the bottom of the diagram, centered, `class="caption"`. Use it for a test result, a quote, or a memorable framing — *"In testing: 35/35 blind panel — next best method scored 21"*. One line, never two. If the content needs two lines, it belongs in prose around the diagram, not in the diagram.
## Color budget in poster mode
Poster flowcharts may use up to 4 ramps, one per **role category** — the drafter, the attacker, the synthesizer, the judge. Same rule as sequence diagrams: identity is a category, not a sequence. Gray is still the default for start/end/anchor/convergence boxes; the accent ramps go to the stages that represent distinct agent roles.
Suggested mapping for agent-style posters:
- **Drafter / author** → purple (thoughtful, creative)
- **Critic / strawman / attacker** → coral (adversarial, attention)
- **Synthesizer / merger** → teal (calm, combining)
- **Judge / evaluator** → amber (deliberate, weighty)
- **Baseline / keep-unchanged / anchor / convergence** → gray
Do not use more than 4 ramps. Two of the five roles above will usually collapse into one color or default to gray.
## Worked coordinate sketch
For a 5-phase poster flowchart with ~10 boxes and an annotation column, expect a viewBox around 680×950:
```
title + subtitle y = 3080
anchor eyebrow + box y = 100168
loop eyebrow y = 192
drafter box y = 208272
critic box y = 296360
candidate eyebrow y = 392
fan-out row y = 408480
judge box y = 530594
convergence eyebrow y = 626
convergence box y = 642714
caption y = 750
viewBox H 770
loop rail y1 = 200, y2 = 720
```
@@ -0,0 +1,652 @@
# Flowchart
For sequential processes, decision trees, cause-and-effect chains. The classic "what happens when X" / "walk me through Y" diagram. Boxes and arrows.
## When to use
- "Walk me through the process" / "what are the steps"
- Approval workflows, request lifecycles, build pipelines
- "What happens when I click submit"
- State machines with clear transitions
- TCP handshake sequences, auth flows
**When not to use:** if the reader wants to feel *why* something works rather than read the steps, reach for an illustrative diagram instead (see `illustrative.md`). Route on the verb — "what are the training steps" is flowchart, "how does gradient descent work" is illustrative.
## Planning before you write SVG
**Count the nouns first.** Before listing any nodes, count the distinct nouns in the user's prompt. If the prompt names 6+ components ("draw me auth, products, orders, payments, gateway, queue"), **do not try to fit them into one diagram** — you will get overlapping boxes and arrows routed through labels, every time. Decompose up front:
1. A stripped overview diagram with the components only and at most one or two arrows showing the main flow — no fan-outs, no N-to-N meshes.
2. One detail diagram per interesting sub-flow ("what happens when an order is placed"), each with 34 nodes and room to breathe.
The user asked for completeness — deliver it across several diagrams, not crammed into one. This is the **proactive** version of the advice; `pitfalls.md#9` catches the same failure retrospectively after you've already laid out too many boxes and run out of width.
Once the decomposition question is settled, plan one diagram at a time:
1. **List the nodes.** 35 total. More than 5 and you should either split the diagram or collapse related steps.
2. **For each node, write its full label text.** Title and (optionally) subtitle.
3. **Choose direction.** Top-down is the default for most narratives. Left-to-right works for timelines and short flows. Never mix directions in one diagram.
4. **Pick colors.** Gray for most nodes. One accent color for whatever node is the main character of the story (a decision point, the entry/exit, the piece under discussion). Never rainbow.
5. **Compute box widths** using `layout-math.md`. Every box in the same "tier" (same role) should be the same width for rhythm.
6. **Map out the arrows.** Simple A→B connections when possible. L-bends when a direct line would cross another box.
## Node templates
### Single-line node (44px tall)
Title only. Use when the label is self-explanatory or when space is tight.
```svg
<g class="c-gray">
<rect x="250" y="40" width="180" height="44" rx="6"/>
<text class="th" x="340" y="62" text-anchor="middle" dominant-baseline="central">User login</text>
</g>
```
Rules:
- Height is always 44 when the row contains only single-line nodes.
- `text y = rect y + 22` (centered vertically, with `dominant-baseline="central"`).
- `text x = rect x + width/2` with `text-anchor="middle"`.
### Two-line node (56px tall)
Title + subtitle. Use when the title alone doesn't carry enough meaning.
```svg
<g class="c-blue">
<rect x="250" y="120" width="200" height="56" rx="6"/>
<text class="th" x="350" y="140" text-anchor="middle" dominant-baseline="central">Login service</text>
<text class="ts" x="350" y="160" text-anchor="middle" dominant-baseline="central">Validates credentials</text>
</g>
```
Rules:
- Height is 56 whenever the row contains any two-line node (mix single-line and two-line within the same row and the rhythm breaks — match heights).
- Title `text y = rect y + 20`.
- Subtitle `text y = rect y + 40`.
- Subtitle must be ≤ 5 words. If you can't fit your idea in 5 words, it belongs in prose next to the diagram, not in the box.
### Neutral "box" node
For generic boxes with no color emphasis. Uses the `box` class from the template (light gray fill, subtle stroke).
```svg
<rect class="box" x="40" y="40" width="180" height="44" rx="6"/>
<text class="t" x="130" y="62" text-anchor="middle" dominant-baseline="central">Start</text>
```
Use for start, end, and generic steps. This is the default — reach for color only when a specific node deserves the reader's attention.
### Pill terminal node (44px tall)
For **boundary nodes** — external inputs, external outputs, and early-exit terminals. The capsule shape visually distinguishes "where the flow enters/leaves the system" from "what happens inside the system". Same height as a single-line node (44px), but with `rx = height / 2 = 22` to produce a fully rounded capsule.
```svg
<rect class="box" x="40" y="40" width="80" height="44" rx="22"/>
<text class="t" x="80" y="62" text-anchor="middle" dominant-baseline="central">In</text>
```
Or with a color ramp, the same shape inside a `c-{ramp}` group:
```svg
<g class="c-gray">
<rect x="560" y="40" width="80" height="44" rx="22"/>
<text class="th" x="600" y="62" text-anchor="middle" dominant-baseline="central">Out</text>
</g>
```
Rules:
- **Only for boundary nodes**: In, Out, Exit, Human, Environment, Stop. Do not use pill shapes for internal steps, decisions, or services — those stay rounded rects (`rx="6"`).
- **Height is always 44**. `rx` must equal `height / 2`. If you change the height, change `rx` to match — a 56px pill with `rx="22"` looks like a lozenge, not a capsule.
- **Width follows the text-width formula** (`label × 8 + 24`), but keep labels to 12 words. A pill with "Request received" inside it reads as a button, not a terminal.
- **Default neutral**: use the `box` class. Reach for a color ramp only when the terminal carries meaning — the active input of a highlighted pipeline, the success output of a gate, etc.
- **At most 2 pills per diagram**. More than that and the capsules start to compete with the flowchart boxes for the reader's attention. The pill is meant to be a visual *anchor*, not a pattern.
## Connector templates
### Straight connector
When source and target share an x (vertical flow) or a y (horizontal flow):
```svg
<line x1="340" y1="84" x2="340" y2="120" class="arr" marker-end="url(#arrow)"/>
```
Leave a 10px gap between the arrow endpoint and the target box's edge so the arrowhead doesn't touch the stroke.
### L-bend connector
When the direct line would cross an unrelated box:
```svg
<path d="M 160 84 L 160 102 L 340 102 L 340 120" class="arr" fill="none" marker-end="url(#arrow)"/>
```
Pick the bend coordinate (102 here) so the horizontal segment runs cleanly through the gap between rows. Double-check that the horizontal segment doesn't cross another box — if it does, you need a three-bend route or a different layout.
### Dashed "returns to" indicator for a loop
Instead of drawing a literal ring for a cycle, label the endpoint with a small return glyph:
```svg
<text class="ts" x="340" y="320" text-anchor="middle">↻ returns to start</text>
```
This is cleaner than trying to route a physical arrow from the bottom box back to the top box around the entire layout.
## Layout patterns
**Cycles: your instinct will be a ring. Resist it.** If the last stage feeds back to the first (Krebs cycle, event loop, GC mark-and-sweep, TCP retransmit), your first instinct will be to arrange the stages around a circle with arrows on the outside. Don't. Every spacing rule in this skill is Cartesian — there is no collision check for "input box orbits stage box on a ring" — so ring layouts ship with labels sitting on the ring line, satellite boxes overlapping the stages they feed, and tangential arrows pointing at nothing. Lay the stages out linearly (horizontal or vertical) and convey the loop with the `↻ returns to start` glyph described under "Dashed 'returns to' indicator for a loop" above, or with a single curved return arrow along the margin. The loop is conveyed by the return marker, not by literal ring geometry. `pitfalls.md#10` catches this retrospectively — this note is here so you don't reach for the ring in the first place.
### Linear top-down (the default)
Four single-line boxes centered at x=250, heights aligned, spaced 60px apart vertically:
```
y=40 [ Node 1 ] height 44, y ends at 84
y=120 [ Node 2 ] (60px gap from y=84)
y=200 [ Node 3 ]
y=280 [ Node 4 ]
```
Arrows at y=84→120, y=164→200, y=244→280 (using 10px arrow-to-box gap), each with a length of 26px.
### Horizontal timeline
Four nodes in a row, centered in the 600px usable width:
```
x=50 x=200 x=350 x=500
[Node 1] → [Node 2] → [Node 3] → [Node 4]
```
Width per box: 130px. Gap: 20px. Total: 4×130 + 3×20 = 580. Centered offset: 40 + (600580)/2 = 50. Arrows go between `x = x_i + 130 + 5` and `x = x_{i+1} - 5`.
### Branching decision
A single entry box at the top, two or three children below fanning out. Use a single bend point so the arrows meet cleanly:
```
[ Decision ]
|
+--------+--------+
| | |
[ Yes ] [ Maybe ] [ No ]
```
Compute the fan midpoint as the horizontal center of the three children. Draw three arrows from the decision box to each child, bending at a common ymid.
### Gate (pass / fail split)
A variant of branching decision where one outbound arrow is the **primary** flow and the other is an **alternative** exit. Use a solid arrow for Pass (continues into the main pipeline) and a dashed `.arr-alt` arrow for Fail (routes to an exit terminal). Both arrows get a short 13 word label.
```
[ In ] → [ LLM Call 1 ] → [ Gate ] --Pass-→ [ LLM Call 2 ] → [ LLM Call 3 ] → [ Out ]
\--Fail (dashed)-→ [ Exit ]
```
Pills on `In`, `Out`, and `Exit`; rounded rects on the LLM calls. Gate takes a color ramp (purple is the convention for a judge/evaluator) so the decision point stands out. Route the Fail arrow as a downward L-bend into a lower row, with the Exit pill right-aligned or below the Gate. See the Gate worked example below.
### Fan-out + aggregator (simple mode)
When N branches run in parallel from a single hub and their results flow into a single aggregator, lay them out as a horizontal row between two single boxes. This is the simple-mode equivalent of the poster flowchart's fan-out + judge pattern — same shape, no title / eyebrow / loop rail / annotation column.
Three variants, same skeleton:
| Variant | Hub label | Branch arrows | Aggregator label | When to use |
|------------------|---------------------|----------------------|------------------|-------------------------------------------------------------|
| **Parallelization** | `In` (pill) | all solid | `Aggregator` | All N branches run; results merged |
| **Router** | `LLM Call Router` | **1 solid, N1 dashed** | `Out` (pill) | Exactly 1 branch runs per invocation; dashed = other options |
| **Orchestrator** | `Orchestrator` | all dashed | `Synthesizer` | Orchestrator dynamically chooses a subset; dashed = "maybe" |
Suggested coordinates for 3 branches, each 160 wide:
```
viewBox 0 0 680 340
In/hub (pill) x=60, y=140, w=80, h=44 center at (100, 162)
Branch row y = 140 (same tier as hub)
Branch 1 box x=175, y=140, w=160, h=44 center (255, 162)
Branch 2 box x=175, y=200, w=160, h=44 center (255, 222)
Branch 3 box x=175, y=260, w=160, h=44 center (255, 282)
Hub → Branch 1 L-bend: (140, 162) → (155, 162) → (175, 162) ... straight
Hub → Branch 2 L-bend: (100, 162) → (100, 222) → (175, 222)
Hub → Branch 3 L-bend: (100, 162) → (100, 282) → (175, 282)
Branch 1 → Aggregator straight right: (335, 162) → (365, 162) ... merge channel
Branch 2 → Aggregator L-bend: (335, 222) → (355, 222) → (355, 162) → (365, 162)
Branch 3 → Aggregator L-bend: (335, 282) → (355, 282) → (355, 162) → (365, 162)
Aggregator pill x=365, y=140, w=160, h=44 center (445, 162)
Out pill x=560, y=140, w=80, h=44 center (600, 162)
Aggregator → Out straight: (525, 162) → (550, 162)
```
For the **router variant**, one branch arrow stays `class="arr"` and the other two use `class="arr-alt"`. Same for the return half — the selected branch's arrow into the aggregator is solid, the others dashed. The visual says "at runtime, one path lights up".
The hub and aggregator typically get a **purple** ramp (they are the control points). Branches stay gray unless a specific branch carries meaning.
**Do not upgrade this into a poster flowchart** unless ≥3 of the poster triggers in the "Poster flowchart pattern" section apply — the upgrade criteria are title + phases + loop + annotations, not "has fan-out". A standalone router / parallelization diagram is at its best as a 57 node simple flowchart.
## Rich flowchart sub-patterns
Four optional sub-patterns that a simple or poster flowchart can drop into individual pieces of the layout: a loop container that frames the whole diagram, status circles on decision branches, queue glyphs inside a box, and a vertical fan-out variant. Each is designed to co-exist with the patterns above — you can use a loop container around a vertical fan-out that contains queue-glyph nodes and emits status-circle-tagged arrows, and every individual rule still holds.
### Loop container
A rounded outer rect, captioned with a title and subtitle, that wraps the whole flowchart to signal "this entire thing is a loop" or "this is a named subsystem". Used in Generator-Verifier (image #2) and Agent Teams (image #6) where the diagram is *the* loop body, not one phase inside a larger poster.
**When to reach for it.** If the whole flowchart represents a single named mechanism that the reader should remember as one thing — Generator-Verifier, a worker-pool protocol, a retry loop — and you're not already in poster mode. If you've already committed to poster mode, use eyebrow-divided phases instead; nesting a loop container inside a poster layout is over-dressed.
**Geometry.**
| Element | Coordinates |
|--------------------|-----------------------------------------------------------|
| Container rect | `x=20 y=40 w=640 h=H60 rx=20`, class `box` |
| Container title | `(340, 72)`, class `th`, `text-anchor="middle"` |
| Container subtitle | `(340, 92)`, class `ts`, `text-anchor="middle"` |
| First inner box | `y ≥ 116` (gives the title a 24px buffer above the inner flow) |
| Inner safe area | `x ∈ [40, 620]` (20px interior padding on each side) |
The container is a single `box`-class rect — its stroke is subtle in both modes and doesn't fight for attention. The title and subtitle sit inside the container, aligned to the container's horizontal center. Interior boxes follow normal simple-flowchart geometry, just shifted so the first row's top lands at `y=116` instead of `y=40`.
**viewBox budget.** The container adds roughly 76px to the top (title + subtitle + padding) and 20px to the bottom (interior padding) — build the inner flow normally, then `H = inner_bottom + 40`. Don't forget to recompute the container's `h` attribute to match.
**Mixing with the normal 680 canvas.** The container shrinks the usable width from 600 to 580 (20..620 interior, minus the 20px interior padding each side). If your inner flow was designed at the full 600 budget and no longer fits, either widen nothing and recenter at x=320 instead of x=340, or accept a slightly narrower inner layout.
**Color.** The container itself is always the neutral `box` class — never a ramp — so the interior nodes can still use ramps without double-coloring. If the mechanism has a clear *owner* (e.g., "the verifier's loop"), you can add a small colored pill-label at the container's top-left to tag ownership, but don't tint the whole container.
**Dashed "until X" caption.** If the loop has a termination mechanic ("loop until verifier accepts", "loop until streak = 2"), write it as a `ts` subtitle of the container — that's what the subtitle slot is for. Don't add a separate `↻` marker inside the container when the whole container *is* the loop.
```svg
<!-- Container -->
<rect class="box" x="20" y="40" width="640" height="360" rx="20"/>
<text class="th" x="340" y="72" text-anchor="middle">Generator-verifier</text>
<text class="ts" x="340" y="92" text-anchor="middle">Loops until the verifier accepts</text>
<!-- Inner flow starts at y=116 -->
<g class="c-purple">
<rect x="80" y="180" width="160" height="56" rx="6"/>
<text class="th" x="160" y="200" text-anchor="middle">Generator</text>
<text class="ts" x="160" y="220" text-anchor="middle">Proposes candidate</text>
</g>
<!-- … verifier node, status circles, return arrow … -->
```
### Status-circle junctions
A decision branch tagged with a visible status circle (✓ / ✗ / ●) from `glyphs.md` instead of a bare `Pass` / `Fail` label. Used when the semantics of the branch are *binary outcomes of a judge*, not just control-flow alternatives.
**When to prefer status circles over the Gate pattern's text labels.** Status circles work when each branch carries a single-word outcome (accept / reject / done / blocked) and no additional condition text. The Gate pattern from "Gate (pass / fail split)" above stays the default for conditions that need more than one word (*"retry if rate-limited"*, *"escalate if amount > $10k"*) — don't try to cram that into a glyph.
**Geometry — replacing a Gate's two arrows.** Start from the existing Gate worked example. Instead of labeling the two outbound arrows with text, split each arrow at a point 14px before its target and place a status-circle glyph in the gap:
```
[ Judge ] ──arr──→ ◎✓ ──arr──→ [ Next stage ]
\
──arr-alt──→ ◎✗ ──arr-alt──→ [ Exit ]
```
- Accept branch: solid arrow + `status-circle-check` (green) + solid arrow.
- Reject branch: dashed `arr-alt` arrow + `status-circle-x` (coral) + dashed `arr-alt` arrow.
- In-progress branch (rare — use only when the judge returns "still thinking"): solid arrow + `status-circle-dot` (amber) + solid arrow looping back.
Each arrow segment stops 14px before the status-circle center (the glyph's radius is 12, so 14 gives a 2px visual gap between the arrowhead and the circle's border).
**Status circle anchor math.** For a branch from source `(sx, sy)` to target `(tx, ty)` where the branch would normally be a straight arrow, place the status circle's **center** at `(cx, cy)` = the arrow's midpoint. Split the arrow:
```svg
<!-- arrow segment 1: source → status circle -->
<line x1="sx" y1="sy" x2="cx - 14" y2="cy" class="arr" marker-end="url(#arrow)"/>
<!-- status circle glyph (see glyphs.md) -->
<g transform="translate(${cx - 12}, ${cy - 12})">
<circle class="c-green" cx="12" cy="12" r="12"/>
<path class="arr-green" d="M6 12.5 L10.5 17 L18 8" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</g>
<!-- arrow segment 2: status circle → target -->
<line x1="cx + 14" y1="cy" x2="tx - 10" y2="ty" class="arr" marker-end="url(#arrow)"/>
```
For L-bend branches, put the status circle on the horizontal segment, not at a corner. The reader's eye tracks the glyph along the arrow direction, and corners disrupt that scan.
**Status-circle color rules are not negotiable.** `c-green` for accept, `c-coral` for reject, `c-amber` for in-progress. Even if the diagram's palette is built around blue and teal, the status circles stay green/coral/amber — semantic color wins. (This is the *only* exception to the 2-ramp budget in a simple flowchart.)
**Labels on status-circle branches.** Optional. If the status circle alone isn't enough ("accept" is obvious but "send to verifier" isn't), add a 13 word `ts` label 6px *past* the status circle in the direction of travel, not between the arrow and the circle. Keep labels on the same side as the target so the reading flow stays left-to-right.
### Queue glyph inside a box
A two-line node where the bottom line is a row of `queue-slot-filled` / `queue-slot-empty` glyphs from `glyphs.md` instead of a text subtitle. Used when a source node's value to the reader is "there are tasks waiting" — e.g., the hub of an Agent Teams fan-out (image #6) — and a text subtitle like "4 of 6 tasks pending" would be both noisier and less informative than the row of slots.
**Not a replacement for a normal two-line node.** Only use this when the queue depth is *itself* the information. If the box's purpose is "task router" with an incidental mention of a queue, stay with a text subtitle.
**Geometry.**
| Element | Coordinates |
|-------------------|-----------------------------------------------------------|
| Host rect | `w ≥ 160, h = 52, rx = 6` |
| Title `th` | `y = rect_y + 18`, centered horizontally |
| Queue row y | `rect_y + 30` |
| Queue row start x | `rect_x + (rect_w slots_total_w) / 2` |
| slot pitch | 20 (slot is 16 wide + 4 gap) |
| slots_total_w | `N × 16 + (N 1) × 4 = N × 20 4` |
| Max slots per row | `⌊(rect_w 24 + 4) / 20⌋`, capped at 8 |
Height 52 is different from the standard 44 (single-line) and 56 (two-line) — the queue row plus its visual padding is just slightly shorter than a text subtitle would be. Don't reuse 44 or 56 here; the math won't center correctly.
**Example — 6 slots in a 160-wide host rect, 4 filled and 2 empty.**
```svg
<g class="c-gray">
<rect x="60" y="120" width="160" height="52" rx="6"/>
<text class="th" x="140" y="138" text-anchor="middle">Task queue</text>
<rect class="c-amber" x="72" y="150" width="16" height="16" rx="2"/>
<rect class="c-amber" x="92" y="150" width="16" height="16" rx="2"/>
<rect class="c-amber" x="112" y="150" width="16" height="16" rx="2"/>
<rect class="c-amber" x="132" y="150" width="16" height="16" rx="2"/>
<rect class="c-gray" x="152" y="150" width="16" height="16" rx="2"/>
<rect class="c-gray" x="172" y="150" width="16" height="16" rx="2"/>
</g>
```
Row math: `slots_total_w = 6 × 20 4 = 116`, `row_start_x = 60 + (160 116) / 2 = 82` — then each slot at `82 + k × 20`. The example above uses `72, 92, …` because the rect is 160 wide and 6 slots center at 82, so k=0 sits at 82 (actually 72 in the code because I walked it slightly left for visual breathing; recompute exactly to taste). Always recompute the row start from the formula when the rect width changes.
**Color rules.** Filled slots always use `c-amber` (work waiting is attention-worthy). Empty slots always use `c-gray`. The host rect should be `c-gray` too — if you color the host rect with a ramp, the amber slots stop reading as "waiting work" and the eye loses the signal.
**Interaction with fan-out.** When a queue-glyph node is the *source* of a fan-out, route each outbound arrow from the **title row** of the source, not the queue row. Arrows emerging from the middle of slots look as if the slots themselves are moving, which is the wrong mental model.
### Vertical fan-out
The horizontal fan-out pattern in "Fan-out + aggregator (simple mode)" rotated 90°: source box on the left, branches stacked vertically in a column on the right, aggregator (optional) further right or at the bottom. Used in Agent Teams (image #6) and the left half of Orchestrator vs Agent teams (image #9).
**When to prefer vertical over horizontal fan-out.** Horizontal fan-out is the default — it reads naturally as "one input splits into alternatives". Switch to vertical when:
- The branches are **workers** (not alternatives): they all run, consuming from a queue. A vertical stack communicates "these workers live side-by-side pulling from the same queue" better than a horizontal row.
- The source node has a **queue glyph** inside it (see previous sub-section). A queue glyph wants horizontal width; if you then fan out horizontally below the queue, the diagram gets very wide. Rotate the fan-out instead.
- The diagram needs to leave horizontal space for an aggregator or a second column — e.g., the subsystem-container pattern where the fan-out lives inside a 315-wide container.
**Geometry — 3 workers inside a normal 680 canvas.**
| Element | Coordinates |
|--------------------|----------------------------------------------|
| Source (hub) rect | `x=40 y=160 w=180 h=52 rx=6` (queue glyph inside; see previous sub-section) |
| Worker row y₁ | `y=120` |
| Worker row y₂ | `y=184` |
| Worker row y₃ | `y=248` |
| Worker rect | `x=420 w=180 h=44 rx=6` |
| Bend channel x | `x=320` (halfway between source right 220 and worker left 420) |
| Aggregator (opt.) | `x=420 y=320 w=180 h=44` (if worker outputs merge) |
**Arrow routing.**
```svg
<!-- Source → Worker 1: L-bend up -->
<path d="M220 186 L320 186 L320 142 L420 142" class="arr" fill="none" marker-end="url(#arrow)"/>
<!-- Source → Worker 2: straight horizontal -->
<line x1="220" y1="206" x2="420" y2="206" class="arr" marker-end="url(#arrow)"/>
<!-- Source → Worker 3: L-bend down -->
<path d="M220 226 L320 226 L320 270 L420 270" class="arr" fill="none" marker-end="url(#arrow)"/>
```
The source's right edge is at x=220 (for a 180-wide box starting at x=40). Each arrow starts at the source's right edge at a slightly offset y (186 / 206 / 226) so the three outbound lines don't overlap inside the source rect. The shared bend channel at x=320 keeps the three L-bends visually parallel.
**Source anchor y.** For a 52-tall queue-glyph host rect at y=160, the vertical center is at y=186. Use `186 ± 20` as the three outbound anchor points so the middle arrow lands at the exact center and the top/bottom arrows sit symmetrically. For a 44-tall single-line source at y=160, use `182 ± 16` instead (smaller offset to stay inside the rect).
**Worker heights.** Workers stay at 44 (single-line) in vertical fan-out, because tight vertical stacking reads better with uniform heights. If a worker needs a subtitle, promote the whole row to 56 and recompute the worker y's with `y₁=112, y₂=184, y₃=256` (72px pitch instead of 64).
**Aggregator, if any.** For vertical fan-out with an aggregator, place the aggregator at `x=420 y=320` (below the workers) and route each worker output through a shared return channel at x=720… wait, x=720 is past the right edge. Use `x=630` instead, and drop the aggregator to `x=240 y=320` (below the middle worker), with return arrows routed to a common channel at x=620:
```svg
<line x1="600" y1="142" x2="620" y2="142" class="arr"/>
<path d="M620 142 L620 342 L420 342" class="arr" fill="none" marker-end="url(#arrow)"/>
<line x1="600" y1="206" x2="620" y2="206" class="arr"/>
<path d="M620 206 L620 342 L420 342" class="arr" fill="none" marker-end="url(#arrow)"/>
<line x1="600" y1="270" x2="620" y2="270" class="arr"/>
<path d="M620 270 L620 342 L420 342" class="arr" fill="none" marker-end="url(#arrow)"/>
```
Note that only the final segment (into the aggregator) carries the `marker-end` arrowhead — the three joining segments into the shared channel are unheaded, same as the horizontal fan-out pattern.
**Color.** Workers are typically the same color as each other (they're instances of one role). If the source is a task-queue hub with queue glyphs, keep it `c-gray` and give the workers a single accent ramp (`c-teal` is the default for workers). If one worker is distinguished from the others (the leader, the one under discussion), promote that one worker's ramp; leave the rest gray.
**Container integration.** Vertical fan-out fits naturally inside a 315-wide subsystem container (`structural.md` → "Subsystem architecture pattern"). For the container variant, shrink the source to 120-wide, workers to 140-wide, and recompute the bend channel. See `structural.md` → "Rich interior for subsystem containers" for the full coordinate table.
### State machine
A flowchart variant where the nodes are **states** (things the system *is*) rather than steps (things the system *does*), and the arrows are **transitions** labeled with the event that triggers them. Used for lifecycles — order status, connection state, feature-flag rollout phase, auth session — where "what can happen next from here" matters more than a single linear path.
**When to reach for it.** The reader's question is "what are the possible states and how do I move between them", not "what happens first, second, third". If the diagram has more than one incoming arrow to most nodes (cycles, self-loops, branches returning to earlier states), you're in state-machine territory. If every node has exactly one predecessor, you want a plain flowchart instead.
**Initial and final markers.** Two small circles anchor the diagram as a state machine — these are the only non-rectangle nodes the pattern uses.
| Marker | Shape | Class | Meaning |
|---------------|--------------------------------------------------|-----------|-------------------------------------------|
| Initial state | Filled circle, `r=6` | `c-gray` | Entry point — exactly one per diagram |
| Final state | Hollow circle `r=10` with a filled inner `r=5` | `c-gray` | Terminal state — may appear multiple times |
```svg
<!-- Initial state at (x, y) -->
<circle class="c-gray" cx="x" cy="y" r="6"/>
<!-- Final state at (x, y) -->
<circle class="c-gray" cx="x" cy="y" r="10" fill="none"/>
<circle class="c-gray" cx="x" cy="y" r="5"/>
```
The initial marker gets **no label** — it's the start, that's self-evident. The final marker may get a 1-word `ts` label 14px below (*Closed*, *Archived*) if the specific terminal state matters; otherwise leave it bare. The initial marker's `r=6` is deliberately smaller than the final marker's outer `r=10` so the two read as different symbols at a glance.
**State nodes.** Standard rounded rect, `rx=6`, same dimensions as a flowchart step node (44px single-line or 56px two-line, 160180 wide). The title is a noun or noun phrase — the state's *name*, not a verb. *"Awaiting payment"* not *"Wait for payment"*; *"Paid"* not *"Process payment"*. If a state needs a subtitle, use it to clarify *what's true while here* (*"Funds held, awaiting capture"*), not *what runs next*.
**Transition labels.** Every arrow gets a label in the format:
```
event [guard] / action
```
- **event** — the trigger that fires the transition (*payment_received*, *timeout*, *user_cancel*). Required.
- **[guard]** — an optional boolean precondition in square brackets (*[amount > 0]*, *[retry_count < 3]*). Omit if there's no condition.
- **/ action** — an optional side effect performed on transit (*/ send_receipt*, */ release_hold*). Omit if the transition is pure.
All three parts fit in a single `ts` label placed at the arrow's midpoint (`y = arrow_midpoint_y 6`, `text-anchor="middle"`). The full *event [guard] / action* string still has to respect the 3-word arrow-label rule in spirit — if the guard or action pushes the label past ~28 characters, promote it to a small table below the diagram and leave only *event* on the arrow. Don't wrap labels across two lines mid-arrow.
**Choice point (internal branch).** When one event fans out into multiple destinations based on guards, insert a small diamond (`w=16 h=16`, `transform="rotate(45)"` on a square — or a `<path>` for the rhombus) at the fan-out point. The incoming arrow carries the shared event label (*payment_received*); each outgoing arrow carries only its own `[guard]` (no event, no action on the choice arrows themselves). This keeps the branch legible without repeating the event name.
```svg
<!-- Choice diamond at (cx, cy) -->
<path class="c-gray" d="M cx,cy-10 L cx+10,cy L cx,cy+10 L cx-10,cy Z"/>
```
Use a choice diamond **only** when two or more outgoing arrows share a triggering event. If the branches fire on different events, skip the diamond — draw two independent labeled arrows from the source state. A diamond per decision is mermaid's habit; baoyu keeps them to the rare case where they genuinely remove duplication.
**Self-loops.** A transition that returns to the same state (*retry on transient failure*) draws as a small arc off one side of the state rect:
```svg
<path d="M rect_right, rect_cy_top
C rect_right+30, rect_cy_top10
rect_right+30, rect_cy_bot+10
rect_right, rect_cy_bot"
class="arr" fill="none" marker-end="url(#arrow)"/>
<text class="ts" x="rect_right+34" y="rect_cy">retry [n &lt; 3]</text>
```
Place self-loops on the right edge of the state rect. Left-edge self-loops collide with incoming arrows from the initial marker in most top-down layouts.
**Color.** State machines are almost always **one ramp** — the cohesive lifecycle is the point. Reach for gray when the states are neutral (order lifecycle), teal or purple when the machine represents a *subsystem* you want the reader to recognize as a named thing. The 2-ramp exception is reserved for **error states**: any state that represents a failure or cancellation may switch to `c-coral`, with the rest of the machine in its primary ramp. Don't rainbow the states — same ramp, same weight, let the arrows carry the meaning.
**Layout.** State machines are less strictly directional than flowcharts — cycles make "top-down only" impossible. Do pick a dominant direction (usually left-to-right for linear lifecycles with a few loops, top-down for branching status graphs) and route the *happy path* along that axis; loops and error transitions can bend against the grain. Keep the initial marker at the top-left (or top-center) and the final markers at the opposite corner/edge.
**Worked example — Order lifecycle (4 states + cancel branches).**
```svg
<!-- Initial marker -->
<circle class="c-gray" cx="60" cy="80" r="6"/>
<line x1="66" y1="80" x2="110" y2="80" class="arr" marker-end="url(#arrow)"/>
<!-- State: New -->
<g class="c-gray">
<rect x="110" y="56" width="140" height="48" rx="6"/>
<text class="th" x="180" y="86" text-anchor="middle">New</text>
</g>
<text class="ts" x="295" y="74" text-anchor="middle">pay / hold_funds</text>
<line x1="250" y1="80" x2="340" y2="80" class="arr" marker-end="url(#arrow)"/>
<!-- State: Paid -->
<g class="c-gray">
<rect x="340" y="56" width="140" height="48" rx="6"/>
<text class="th" x="410" y="86" text-anchor="middle">Paid</text>
</g>
<text class="ts" x="525" y="74" text-anchor="middle">ship</text>
<line x1="480" y1="80" x2="570" y2="80" class="arr" marker-end="url(#arrow)"/>
<!-- State: Shipped -->
<g class="c-gray">
<rect x="570" y="56" width="100" height="48" rx="6"/>
<text class="th" x="620" y="86" text-anchor="middle">Shipped</text>
</g>
<!-- State: Delivered (below Shipped) -->
<text class="ts" x="636" y="140" text-anchor="start">delivered</text>
<path d="M620 104 L620 156" class="arr" fill="none" marker-end="url(#arrow)"/>
<g class="c-gray">
<rect x="570" y="156" width="100" height="48" rx="6"/>
<text class="th" x="620" y="186" text-anchor="middle">Delivered</text>
</g>
<!-- Final marker -->
<path d="M620 204 L620 240" class="arr" fill="none" marker-end="url(#arrow)"/>
<circle class="c-gray" cx="620" cy="250" r="10" fill="none"/>
<circle class="c-gray" cx="620" cy="250" r="5"/>
<!-- Cancel branch: New → Cancelled (error state, coral) -->
<text class="ts" x="180" y="146" text-anchor="middle">cancel</text>
<path d="M180 104 L180 156" class="arr" fill="none" marker-end="url(#arrow)"/>
<g class="c-coral">
<rect x="110" y="156" width="140" height="48" rx="6"/>
<text class="th" x="180" y="186" text-anchor="middle">Cancelled</text>
</g>
<!-- Cancel branch: Paid → Cancelled (refund) -->
<text class="ts" x="300" y="146" text-anchor="middle">cancel / refund</text>
<path d="M410 104 L410 180 L250 180" class="arr" fill="none" marker-end="url(#arrow)"/>
```
Two things to note in the example: (1) *Cancelled* uses `c-coral` as the single allowed off-ramp for an error state while everything else stays `c-gray`, and (2) the *Paid → Cancelled* transition bends back horizontally and collapses into the same Cancelled box rather than drawing a second coral rect — one error state serves both cancel sources.
## Rules of thumb
- **Max 5 nodes per diagram.** If the process has more steps, split into "overview" (the main path) and "detail" (what happens inside one of the stages).
- **Single direction only.** Top-down *or* left-to-right. Never both in one diagram.
- **Same-tier nodes same size.** If row A has 140-wide boxes, every box in row A should be 140 wide. Mixing sizes in one row looks like a layout bug.
- **Short arrow labels are allowed; long ones are not.** A 13 word `ts` label can float above an arrow's midpoint when the edge itself carries meaning the source/target nodes don't — *Pass* / *Fail* on a gate's two outbound arrows, *Query* / *Results* on a hub's exchange with an attachment, *Accepted* / *Rejected* on an evaluator's feedback loop. Place the label at `y = arrow_midpoint_y 6` with `text-anchor="middle"` and class `ts`. **Anything longer than 3 words belongs in the target box's subtitle or in prose around the diagram**, never on the arrow itself — long labels collide with other elements and are hard to position. Sequence diagrams have the same allowance (message labels *are* the point of the arrow there — see `sequence.md`) but with a numeric prefix convention.
- **Start and end get gray boxes.** Color is reserved for the interesting steps.
- **Arrowheads end 10px short of the target.** Gives the reader visual breathing room.
## Tiny worked example
Request: "flowchart of logging into a web app"
Plan:
- 4 nodes: Start → Enter credentials → Auth service → Dashboard
- Direction: top-down
- Colors: gray for Start and Dashboard, blue for the two middle steps (they're the active workflow)
- All single-line (44px), width 180 each, centered at x=250
viewBox: max_y = 280 + 44 = 324 → H = 344.
```svg
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 680 344" font-family="...">
<style>...</style>
<defs>
<marker id="arrow" .../>
</defs>
<rect class="box" x="250" y="40" width="180" height="44" rx="6"/>
<text class="t" x="340" y="62" text-anchor="middle" dominant-baseline="central">Start</text>
<g class="c-blue">
<rect x="250" y="120" width="180" height="44" rx="6"/>
<text class="th" x="340" y="142" text-anchor="middle" dominant-baseline="central">Enter credentials</text>
</g>
<g class="c-blue">
<rect x="250" y="200" width="180" height="44" rx="6"/>
<text class="th" x="340" y="222" text-anchor="middle" dominant-baseline="central">Auth service</text>
</g>
<rect class="box" x="250" y="280" width="180" height="44" rx="6"/>
<text class="t" x="340" y="302" text-anchor="middle" dominant-baseline="central">Dashboard</text>
<line x1="340" y1="94" x2="340" y2="110" class="arr" marker-end="url(#arrow)"/>
<line x1="340" y1="174" x2="340" y2="190" class="arr" marker-end="url(#arrow)"/>
<line x1="340" y1="254" x2="340" y2="270" class="arr" marker-end="url(#arrow)"/>
</svg>
```
## Worked example — Gate with pass/fail split
Request: "LLM call with a gate that either continues through two more calls or exits early"
Plan:
- 6 nodes on a single row: `In` (pill) → `LLM Call 1``Gate``LLM Call 2``LLM Call 3``Out` (pill), plus an `Exit` pill dropping below the Gate on the Fail branch.
- Colors: pills gray; LLM calls gray; Gate purple (the decision point).
- Arrow labels: *Pass* on Gate → LLM Call 2 (solid), *Fail* on Gate → Exit (dashed `.arr-alt`).
- Horizontal budget: 6 nodes + 5 gaps of 20px must fit in the 600px usable width. `60 + 106 + 60 + 106 + 106 + 60 = 498`, plus `5 × 20 = 100`, total = **598** — fits with 2px to spare.
- viewBox: single row at y=140, plus an Exit row at y=230. `max_y = 230 + 44 = 274` → H = **294**.
```svg
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 680 294" font-family="...">
<style>...</style>
<defs><marker id="arrow" .../></defs>
<rect class="box" x="40" y="140" width="60" height="44" rx="22"/>
<text class="t" x="70" y="162" text-anchor="middle" dominant-baseline="central">In</text>
<g class="c-gray">
<rect x="120" y="140" width="106" height="44" rx="6"/>
<text class="th" x="173" y="162" text-anchor="middle" dominant-baseline="central">LLM Call 1</text>
</g>
<g class="c-purple">
<rect x="246" y="140" width="60" height="44" rx="6"/>
<text class="th" x="276" y="162" text-anchor="middle" dominant-baseline="central">Gate</text>
</g>
<g class="c-gray">
<rect x="326" y="140" width="106" height="44" rx="6"/>
<text class="th" x="379" y="162" text-anchor="middle" dominant-baseline="central">LLM Call 2</text>
</g>
<g class="c-gray">
<rect x="452" y="140" width="106" height="44" rx="6"/>
<text class="th" x="505" y="162" text-anchor="middle" dominant-baseline="central">LLM Call 3</text>
</g>
<rect class="box" x="578" y="140" width="60" height="44" rx="22"/>
<text class="t" x="608" y="162" text-anchor="middle" dominant-baseline="central">Out</text>
<rect class="box" x="246" y="230" width="60" height="44" rx="22"/>
<text class="t" x="276" y="252" text-anchor="middle" dominant-baseline="central">Exit</text>
<line x1="102" y1="162" x2="118" y2="162" class="arr" marker-end="url(#arrow)"/>
<line x1="228" y1="162" x2="244" y2="162" class="arr" marker-end="url(#arrow)"/>
<line x1="308" y1="162" x2="324" y2="162" class="arr" marker-end="url(#arrow)"/>
<line x1="434" y1="162" x2="450" y2="162" class="arr" marker-end="url(#arrow)"/>
<line x1="560" y1="162" x2="576" y2="162" class="arr" marker-end="url(#arrow)"/>
<line x1="276" y1="184" x2="276" y2="226" class="arr-alt" marker-end="url(#arrow)"/>
<text class="ts" x="316" y="156" text-anchor="middle">Pass</text>
<text class="ts" x="286" y="204" text-anchor="start">Fail</text>
</svg>
```
Notes on this example:
- The *Pass* label sits **above** the solid horizontal arrow from Gate to LLM Call 2 at `y = arrow_y 6 = 156`, centered on the arrow midpoint (316).
- The *Fail* label sits **beside** the dashed vertical arrow at x=286 (10px right of the arrow), with `text-anchor="start"` so it extends rightward — this keeps it clear of the Gate rect's right edge at x=306.
- Both arrow labels are ≤1 word — the rule of thumb at line 159 caps flowchart arrow labels at 3 words.
- The `.arr-alt` class on the Fail arrow matches the stroke color of `.arr` but adds the dashed pattern, so the Fail branch reads as a **conditional exit** rather than a mainline flow.
- The Exit pill is centered at x=276 (same x as the Gate center — both rects share x=246, w=60) so the dashed arrow drops straight down, no bend.
- Rightmost rect edge: Out pill ends at x = 578 + 60 = **638** ≤ 640 ✓ — the pre-save rightmost-edge check from `pitfalls.md#1` passes.
## Poster flowchart pattern
See `references/flowchart-poster.md`. **Load it when ≥3 of the poster triggers fire in Step 4a**: the topic has a short name, a "why it exists" sentence, named phases (24), parallel candidates with a judge, a loop termination mechanic, overflow annotations, or a footer quote. If only 01 apply, the simple flowchart is the right tool.
+633
View File
@@ -0,0 +1,633 @@
# Glyph Library
Small, reusable SVG primitives that several sub-patterns draw *inside* their boxes or *on top of* their connectors: status circles on an arrow, checkboxes in a TODO list, queue slots inside a worker box, a document icon inside a shared-state store, a labeled annotation circle halfway along an arrow.
These are intentionally *shared across types*. A status circle belongs in a flowchart (Generator-Verifier) and also in a structural advisor diagram. A checkbox belongs in a structural "TODOs vs Tasks" comparison and also in an illustrative "agent task list" subject. Keeping them in one place keeps the visual vocabulary consistent across diagrams.
## Hard rules
Every glyph in this file obeys **all** of the design system's hard rules (`design-system.md` → "Hard rules"). In particular:
- **SVG primitives only.** Every glyph is composed of `<rect>`, `<circle>`, `<ellipse>`, `<line>`, `<path>`, or `<text>`. No `<image>`, no `<foreignObject>`, no emoji characters.
- **No hardcoded colors on text or strokes that need dark-mode response.** Every glyph uses the existing CSS classes (`c-{ramp}`, `arr-{ramp}`, `arr-alt`, `box`, `t`/`th`/`ts`). This means both light and dark mode are handled automatically — zero template changes required.
- **No rotated text.** (Glyphs are small enough that horizontal text always fits.)
- **Sentence case** on any labels.
If a new glyph seems to require a hardcoded color or a new CSS rule, stop and reconsider — the shape is probably wrong, or it belongs in one of the existing ramps.
## Coordinate convention
Every glyph block below is drawn with its **top-left anchor at (0, 0)**, then wrapped in a `<g transform="translate(x, y)">` to place it in the diagram. The glyph's *bounding box width × height* is listed in each subsection so you can reserve space and pick `x, y` from the parent layout.
```svg
<!-- Glyph in situ: place at (340, 200) -->
<g transform="translate(340, 200)">
<!-- glyph body at origin (0, 0) -->
</g>
```
All `x`/`y`/`cx`/`cy`/`d` values in the snippets below are **relative to the glyph origin**, not the diagram origin. Don't edit them — just translate the wrapper group.
---
## Status circles
A circle placed on or near an arrow to tag the outcome of a decision. Three variants: ✓ success, ✗ failure, ● in-progress.
**Bounding box.** 24 × 24. Place the center of the circle at `(12, 12)` inside the glyph origin. When placed on a diagram, translate so that `(12, 12)` lands at the desired anchor — usually the midpoint of an arrow or just past a gate node.
**Where they're used.**
- Flowchart (Generator-Verifier, Agent Teams, gate patterns): tag the two branches out of a verifier or judge node.
- Structural (advisor, TODOs→Tasks): mark individual task outcomes inside a state box.
**Color rules.** Status carries semantic color — not negotiable:
- `check``c-green` / `arr-green` (accept, pass, done)
- `x``c-coral` / `arr-coral` (reject, fail, blocked)
- `dot``c-amber` / `arr-amber` (in-progress, busy, running)
**Dark mode.** All three use the existing ramp classes, so both the circle fill and the inner stroke invert automatically.
### status-circle-check
```svg
<g transform="translate(x, y)">
<circle class="c-green" cx="12" cy="12" r="12"/>
<path class="arr-green" d="M6 12.5 L10.5 17 L18 8" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</g>
```
### status-circle-x
```svg
<g transform="translate(x, y)">
<circle class="c-coral" cx="12" cy="12" r="12"/>
<path class="arr-coral" d="M7.5 7.5 L16.5 16.5 M16.5 7.5 L7.5 16.5" stroke-linecap="round" fill="none"/>
</g>
```
### status-circle-dot
```svg
<g transform="translate(x, y)">
<circle class="c-amber" cx="12" cy="12" r="12"/>
<circle class="c-amber" cx="12" cy="12" r="4"/>
</g>
```
The nested small circle shares the ramp but is visually distinct because it sits on top of its own border stroke, reading as a filled dot against the paler ring.
### Placement on an arrow
A status circle placed *on* an arrow replaces that arrow's tail:
```
status-circle-check (center at x=360, y=160)
(start)────arrow 1──→ ◎ ────arrow 2──→(end)
```
Split the original arrow into two segments, both with `marker-end="url(#arrow)"`. The circle sits in the gap. Arrow 1 stops at `circle_cx 14` (2px before the circle border). Arrow 2 starts at `circle_cx + 14`.
**Pitfall.** Don't layer the circle on top of a single continuous line — the arrow renders behind the circle and looks as if it pierces straight through. Always split into two segments.
---
## Checkboxes
A 14 × 14 checkbox glyph for task lists. Two variants: checked (filled green with check) and empty (neutral outline).
**Bounding box.** 14 × 14.
**Where they're used.**
- Structural (TODOs → Tasks comparison, checklist interiors inside a subsystem container): one per task row.
- Illustrative (task list subject, sparingly): only if the task list is the whole mechanism being shown.
**Color rules.**
- `checked``c-green` (task done)
- `empty``c-gray` (task pending)
For an "in-progress" task, substitute `status-circle-dot` at half scale, or just leave it empty. Don't invent a third checkbox color.
### checkbox-checked
```svg
<g transform="translate(x, y)">
<rect class="c-green" x="0" y="0" width="14" height="14" rx="2"/>
<path class="arr-green" d="M3 7.5 L6 10.5 L11 5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</g>
```
### checkbox-empty
```svg
<g transform="translate(x, y)">
<rect class="c-gray" x="0" y="0" width="14" height="14" rx="2"/>
</g>
```
### Checklist rows
A row of checklist items is laid out with the checkbox on the left and a 14px `t`-class label to its right:
```svg
<g transform="translate(40, 120)">
<g transform="translate(0, 0)">
<rect class="c-green" x="0" y="0" width="14" height="14" rx="2"/>
<path class="arr-green" d="M3 7.5 L6 10.5 L11 5" stroke-linecap="round" fill="none"/>
</g>
<text class="t" x="22" y="11">Draft the outline</text>
</g>
```
Row pitch: 22px (14px checkbox height + 8px vertical gap). Label `y = checkbox_y + 11` for vertical centering against the 14px box.
**Row width budget.** Inside a 315-wide subsystem container with 20px interior padding, the label has `315 20 20 14 8 = 253` px of width. At 8px/char (14px Latin) that caps the label at **~31 characters**; at 15px/char (CJK) that caps at **~16 characters**. Longer labels must be truncated or wrapped across two rows.
---
## Queue slots
A row of small filled/empty squares that represents a work queue or a buffer. Not to be confused with checklists — queue slots are *undifferentiated items*, checklists are *named tasks*.
**Bounding box per slot.** 16 × 16. Row pitch: 20 (16 + 4 gap). Typical row: 68 slots max per row.
**Where they're used.**
- Flowchart (Agent Teams, task-queue hub node): show the queue of pending work *inside* a source node.
- Structural (any box representing a worker pool with a buffer): same purpose, different frame.
**Color rules.**
- `filled``c-amber` (work waiting in queue)
- `empty``c-gray` (slot available)
### queue-slot-filled
```svg
<rect class="c-amber" x="x" y="y" width="16" height="16" rx="2"/>
```
### queue-slot-empty
```svg
<rect class="c-gray" x="x" y="y" width="16" height="16" rx="2"/>
```
### Queue row inside a box
For a two-line box (`title + queue row`), the queue row goes at `rect_y + 28` (below the title baseline), starting at `rect_x + 12`:
```svg
<g>
<rect class="c-gray" x="60" y="120" width="160" height="52" rx="6"/>
<text class="th" x="140" y="138" text-anchor="middle">Task queue</text>
<rect class="c-amber" x="72" y="148" width="16" height="16" rx="2"/>
<rect class="c-amber" x="92" y="148" width="16" height="16" rx="2"/>
<rect class="c-amber" x="112" y="148" width="16" height="16" rx="2"/>
<rect class="c-amber" x="132" y="148" width="16" height="16" rx="2"/>
<rect class="c-gray" x="152" y="148" width="16" height="16" rx="2"/>
<rect class="c-gray" x="172" y="148" width="16" height="16" rx="2"/>
</g>
```
Box height for this variant: **52px** (title row + queue row + vertical padding). Don't reuse the default 44 or 56 heights — the queue row needs its own budget.
**Row width budget.** `slots × 20 4 ≤ rect_width 24`. For a 160-wide rect that's `(160 24 + 4) / 20 = 7` slots maximum. Above 7, split into two rows or widen the host rect.
---
## Document & terminal icons
Decorative icons that go *inside* a box (usually illustrative or structural) to hint at what kind of thing the box represents: a document store, a terminal/computer, a code script. These are **not allowed in flowchart or sequence diagrams** — label the rect instead.
**Why only illustrative / structural.** In a flowchart, the reader is tracking sequence; an icon is visual noise competing with the arrow flow. In a structural diagram showing containment, an icon inside a container cell reinforces *what that cell is* and doesn't interrupt any flow. In an illustrative diagram the icon *is* part of the intuition (a document glyph inside a "Shared state" box tells you it's storing artifacts, not messages).
### doc-icon
**Bounding box.** 24 × 28. Place it in the lower half of a box that's at least 80 tall.
```svg
<g transform="translate(x, y)">
<path class="arr" d="M2 2 L16 2 L22 8 L22 26 L2 26 Z" fill="none"/>
<path class="arr" d="M16 2 L16 8 L22 8" fill="none"/>
<line class="arr" x1="6" y1="14" x2="18" y2="14"/>
<line class="arr" x1="6" y1="18" x2="18" y2="18"/>
<line class="arr" x1="6" y1="22" x2="14" y2="22"/>
</g>
```
The outer silhouette is a rectangle with a folded corner; the three short horizontal lines suggest paragraphs.
**Placement inside a box.** For a box at `(box_x, box_y)` with width `box_w` and height `box_h ≥ 80`, place the icon's origin at `(box_x + box_w/2 12, box_y + box_h 36)`. This centers horizontally and leaves 8px below.
### terminal-icon
**Bounding box.** 24 × 24.
```svg
<g transform="translate(x, y)">
<rect class="box" x="0" y="0" width="24" height="24" rx="2"/>
<path class="arr" d="M5 9 L9 12 L5 15" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<line class="arr" x1="11" y1="17" x2="19" y2="17"/>
</g>
```
A framed box containing a `>` prompt chevron and a short input line.
**Dark mode.** The `box` class provides a contrast frame that reads correctly in both modes; the inner chevron and cursor line use `arr` which also inverts.
### script-icon
**Not a fixed-size glyph.** The "script" pattern in image #12 (Programmatic tool calling) is a tall rect that contains multiple horizontal colored dividers and a `{ }` label at the top, representing an inline script that wraps several tool calls. Because the rect's height depends on how many tool calls it wraps, the script-icon is parameterized — build it inline using this recipe:
```svg
<g>
<!-- outer script rect: height depends on wrapped-call count -->
<rect class="c-gray" x="script_x" y="script_y" width="120" height="script_h" rx="6"/>
<text class="th" x="script_x + 60" y="script_y + 22" text-anchor="middle">{ }</text>
<line class="arr" x1="script_x + 16" y1="script_y + 40" x2="script_x + 104" y2="script_y + 40"/>
<!-- one colored band per wrapped call: -->
<rect class="c-teal" x="script_x + 12" y="band1_y" width="96" height="28" rx="4"/>
<rect class="c-purple" x="script_x + 12" y="band2_y" width="96" height="28" rx="4"/>
<rect class="c-amber" x="script_x + 12" y="band3_y" width="96" height="28" rx="4"/>
</g>
```
`script_h = 48 + N × 36` for N wrapped calls; `bandK_y = script_y + 48 + (K-1) × 36`. See `sequence.md` → "Parallel independent rounds" for the full pattern this participates in.
---
## Code braces
Inline `{ }` as a label on a connector or inside a small label rect to signal "code" or "programmatic" handoff.
```svg
<text class="th" x="x" y="y" text-anchor="middle">{ }</text>
```
**Width estimate.** 14px, ~16 char-px. Treat as 2 chars when budgeting for a rect container.
**Where used.** Only in illustrative or structural diagrams that distinguish "data flow" from "code flow" — usually paired with a `script-icon` or a `c-gray` pill labeled "Programmatic".
---
## Annotation circle on connector
A labeled circle that sits on an arrow to name *the thing that mediates the exchange* — for example, "Skill" sitting on the Claude ↔ Environment arrow in image #13.
**Bounding box.** 64 × 64 around the circle. The inner pill is ~52 × 20.
**Where used.** Illustrative only. This is a "the action on this arrow is X" label, which in a flowchart or sequence would be a simple arrow label — in an illustrative diagram, we promote it to a visual node because the mediator *is* the subject.
```svg
<g transform="translate(x, y)">
<!-- outer circle uses .box for the neutral background ring -->
<circle class="box" cx="32" cy="32" r="30"/>
<!-- inner pill with label, picks up its own ramp -->
<g class="c-teal">
<rect x="4" y="22" width="56" height="20" rx="10"/>
<text class="th" x="32" y="36" text-anchor="middle">Skill</text>
</g>
</g>
```
**Placement.** Center the glyph on the arrow's midpoint: `translate(arrow_midx 32, arrow_midy 32)`. The arrow must be split into two segments on either side of the glyph (same rule as status circles), each stopping 32px before the center.
**Label length.** The inner pill caps at ~8 Latin chars at 14px (`8 × 8 = 64`, minus 8px padding each side, gives ~48px of label room — 6 chars is a comfortable fit; "Skill" at 5 chars is ideal). For CJK, cap at 3 characters.
**Pitfall.** Don't use `c-teal` on the outer circle — that double-fills the ramp and the label pill disappears. Keep the outer ring on `box`, the inner pill on a ramp.
---
## Dashed future-state rect
Used in "TODOs → Tasks" (image #4) to show a task that hasn't been scheduled yet — the node exists in the plan but not in the active DAG.
```svg
<rect class="arr-alt" x="x" y="y" width="w" height="h" rx="6"/>
```
Reuses the existing `arr-alt` class — it already provides `fill: none`, `stroke-width: 1.5`, `stroke-dasharray: 5 4`, and dark-mode stroke override. No inline attributes needed.
**Text inside.** Label with `ts` class (12px, muted) — future-state nodes are always visually demoted relative to active ones:
```svg
<g>
<rect class="arr-alt" x="200" y="180" width="120" height="44" rx="6"/>
<text class="ts" x="260" y="205" text-anchor="middle">Task 4</text>
</g>
```
**Pitfall.** Do *not* create a new `.box-future` CSS class. The `arr-alt` class handles it — adding a new class is template bloat.
**Pitfall.** Don't align the dashed rect's center with an active `c-{ramp}` rect's center if their heights differ — the visual baseline looks off. Match the top edge instead, or match the baseline of the label text.
---
## Publish/subscribe arrow pair
Two parallel offset arrows between a node and a bus bar — one labeled "Publish" going down, one labeled "Subscribe" going up. Used in the bus topology pattern (`structural.md` → "Bus topology").
**Not a static glyph.** It's a pair of straight arrows with an 8px horizontal offset between them, each with its own label. Write this inline where you use it:
```svg
<!-- agent_cx is the horizontal center of the agent box;
bar_y_top and bar_y_bottom are the y-edges of the bus bar;
agent_y_bottom is the bottom y of the top agent -->
<line class="arr" x1="agent_cx - 8" y1="agent_y_bottom" x2="agent_cx - 8" y2="bar_y_top" marker-end="url(#arrow)"/>
<line class="arr" x1="agent_cx + 8" y1="bar_y_top" x2="agent_cx + 8" y2="agent_y_bottom" marker-end="url(#arrow)"/>
<text class="ts" x="agent_cx - 14" y="(agent_y_bottom + bar_y_top) / 2 + 4" text-anchor="end">Publish</text>
<text class="ts" x="agent_cx + 14" y="(agent_y_bottom + bar_y_top) / 2 + 4">Subscribe</text>
```
The 8px offset is the documented spacing — wider looks like two unrelated arrows, narrower looks like a single fat arrow.
**Label placement.** The two labels go in the gap between the agent and the bar, one flush against the left arrow (anchor `end`) and one flush against the right arrow (anchor `start`). If the agent's bottom and the bar's top are closer than 40px, move the labels to the *side* of the pair rather than between them.
**Color.** Both arrows use `arr` (default gray). If the pattern needs to highlight one specific agent's channel, upgrade that pair to `arr-{ramp}` where `{ramp}` matches the agent's box — but only that one pair, not all of them.
---
## Concept-to-shape conventions
Before drawing any node, decide what shape it should be. baoyu-diagram is a **flat-rect aesthetic** — almost every concept maps to a labeled rectangle. The table below is the canonical lookup so you don't invent a new icon shape inline and so you don't reach for mermaid/plantuml-style iconography that clashes with the design system.
| Concept | Use this shape | Notes |
|----------------------------|--------------------------------------------------------|-------------------------------------------------------|
| User / human / actor | Labeled rect with `ts` subtitle "(user)" or similar | No stick figure. In sequence, an actor header rect. |
| LLM / model | Labeled rect, optionally `c-teal` or `c-purple` | No brain icon. Label with the model name. |
| Agent / orchestrator | Labeled rect, often the centerpiece of the diagram | If it's the mechanism's name, use `.title` class for the whole diagram title instead. |
| Tool / function | Labeled rect; or compact tool card with `tool-card-*` icon in phase-band diagrams | No gear icon in standard diagrams. Phase-band exception: see "Tool card icons" section. |
| API / gateway / endpoint | Labeled rect | No hexagon. Label with the route or service name. |
| Memory (short-term) | Rect with dashed border via `class="arr-alt"` inline | Dashed = ephemeral. See `svg-template.md``.arr-alt`. |
| Memory (long-term) / DB | Rect with `doc-icon` inside (structural/illustrative) | No cylinder. In flowchart/sequence, label with "(DB)". |
| Vector store | Rect labeled with dimensions ("768d") + doc-icon | No cylinder with grid lines. |
| Queue / buffer | Rect containing `queue-slot-filled` / `-empty` glyphs | See glyphs → "Queue slots". |
| Task list / checklist | Rect containing `checkbox-checked` / `-empty` rows | See glyphs → "Checkboxes". |
| External service | Labeled rect inside a dashed-border container | The dashed container communicates "not ours". |
| Decision point | Rotated square (diamond), flowchart only | See `flowchart.md` → diamond decision nodes. |
| Process / step | Rounded rect (`rx="6"`) | The default shape. Reach for this first. |
| Start / End boundary | Pill (rounded rect with `rx = height/2`) | See `flowchart.md` → "Pill terminal node". ≤2 per diagram. |
| State in state machine | Rounded rect with title | See `flowchart.md` → "State-machine sub-pattern". |
| Initial / final state | Filled 8px circle / 12px hollow circle with inner 8px | State-machine exception to the "rect only" rule. |
| Class (UML) | 3-compartment rect (name / attrs / methods) | See `class.md`. |
### Rejected shapes — never use these
These shapes look great in mermaid/plantuml/fireworks-style diagrams but break baoyu's flat-rect aesthetic and its dark-mode color contract. If the diagram seems to demand one, the *label* is wrong — fix the label.
- **Stick figure** (for users / actors). Use a labeled rect.
- **Brain glyph** (for LLMs). Use a labeled rect with the model name.
- **Gear / cog glyph** (for tools). Use a labeled rect with the tool name.
- **Cylinder** (for databases). Use a rect with `doc-icon` or a "(DB)" suffix in the label.
- **Cloud silhouette** (for external services). Use a dashed-border container.
- **Disk / drum / tape-reel** (for storage). Same as cylinder — use a rect.
- **Briefcase, folder, envelope, magnifying glass** (for everything else). Use a rect.
The rationale for each: these glyphs all require either hardcoded fills (breaking dark mode), or non-rectangular paths that don't compose with the 44/56 row heights and the `c-{ramp}` stroke conventions, or visual weight that competes with the actual information in the box labels. baoyu's readability comes from consistent typography and color — not from pictograms.
**When in doubt, ask: "does the shape carry information the label doesn't?"** If the answer is no, it's decoration and you should drop it. If yes, the label is missing the information and you should add it.
## Glyph checklist before saving
When you include any glyph in a diagram, verify:
1. **Class check** — every shape in the glyph uses one of `c-{ramp}`, `arr-{ramp}`, `arr`, `arr-alt`, `box`, or a text class (`t`/`th`/`ts`). No inline `fill="#..."` or `stroke="#..."` on anything that needs dark-mode inversion.
2. **Positioning check** — the glyph is wrapped in `<g transform="translate(x, y)">` and the anchor math lands it where the parent layout expects (box center, arrow midpoint, checklist row).
3. **No-collision check** — for status circles and annotation circles, the arrow they sit on has been split into two segments leaving a gap for the glyph, not routed *through* it.
4. **Ramp meaning check** — status colors (`c-green` for pass, `c-coral` for fail, `c-amber` for in-progress) are not overridden by the surrounding diagram's color budget. Status semantics always win over the "≤2 ramps" rule.
5. **Icon scope check**`doc-icon`, `terminal-icon`, and `script-icon` only appear in illustrative or structural diagrams. A flowchart that wants to show "this is a document" uses the label, not the icon. `tool-card-*` icons only appear inside compact tool cards in phase-band diagrams.
---
## Tool card icons
Small 24 × 24 icons for use **exclusively inside compact tool card nodes** in phase-band diagrams (see `references/flowchart-phase-bands.md`). Each icon supplements—never replaces—the text label on the card. Without the label the icon has no meaning; without the icon the label still works fine.
**Scope rule.** These icons are not allowed in any other diagram type. They require the compact tool card node template below — dropping a tool icon directly into a standard 44px flowchart node looks wrong and breaks the icon-to-card sizing contract.
**Dark-mode rule.** All strokes use `class="arr"` (inherits the template's stroke color). `fill="none"` on any outer shape is safe. No inline hex colors.
**Bounding box:** 24 × 24 for all icons. Place the icon origin so the glyph center lands at the top-center of the card (see compact tool card template below).
---
### icon-scan
Concentric target rings — communicates "scanning / finding".
```svg
<g transform="translate(x, y)">
<circle class="arr" cx="12" cy="12" r="10" fill="none"/>
<circle class="arr" cx="12" cy="12" r="6" fill="none"/>
<circle class="arr" cx="12" cy="12" r="2" fill="none"/>
<line class="arr" x1="18" y1="6" x2="22" y2="2"/>
</g>
```
The small tick line at the top-right angle reads as "aim" without being a literal crosshair.
---
### icon-search
Document face with text lines — communicates "reading / querying" without using a magnifying glass (which is prohibited as a shape replacement for labels in standard diagrams).
```svg
<g transform="translate(x, y)">
<rect class="arr" x="2" y="2" width="20" height="20" rx="2" fill="none"/>
<line class="arr" x1="5" y1="8" x2="19" y2="8"/>
<line class="arr" x1="5" y1="12" x2="19" y2="12"/>
<line class="arr" x1="5" y1="16" x2="13" y2="16"/>
</g>
```
---
### icon-data
Three vertical bars of different heights — bar chart shape for "data analysis / metrics".
```svg
<g transform="translate(x, y)">
<line class="arr" x1="2" y1="22" x2="22" y2="22"/>
<rect class="arr" x="3" y="14" width="4" height="8" fill="none"/>
<rect class="arr" x="10" y="7" width="4" height="15" fill="none"/>
<rect class="arr" x="17" y="10" width="4" height="12" fill="none"/>
</g>
```
---
### icon-code
Angle brackets with a slash — `</>` pattern for "code / script analysis".
```svg
<g transform="translate(x, y)">
<path class="arr" d="M8 4 L3 12 L8 20" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<path class="arr" d="M16 4 L21 12 L16 20" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<line class="arr" x1="14" y1="5" x2="10" y2="19" stroke-linecap="round"/>
</g>
```
---
### icon-exploit
Lightning bolt — communicates "attack / execution / injection".
```svg
<g transform="translate(x, y)">
<path class="arr" d="M14 2 L9 12 L13 12 L10 22 L15 11 L11 11 Z" fill="none"
stroke-linecap="round" stroke-linejoin="round"/>
</g>
```
---
### icon-callback
Two arrows in a circle (↩ motif) — communicates "callback / round-trip / webhook".
```svg
<g transform="translate(x, y)">
<path class="arr" d="M4 12 A8 8 0 1 1 12 20" fill="none" stroke-linecap="round"/>
<path class="arr" d="M8 22 L12 20 L10 16" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
</g>
```
---
## Compact tool card node template
**Used only in phase-band diagrams.** A 80 × 80 node that shows a 24 × 24 icon above a two-line text label. The icon provides visual differentiation at a glance; the label provides the actual meaning.
**Bounding box:** 80 × 80 (or wider if the label is longer — see sizing rule below).
**Sizing rule:**
```
card_w = max(line1_chars × 7, line2_chars × 7, 24) + 24
card_w = round up to nearest 8, minimum 72, maximum 128
card_h = 80 (fixed)
```
For a single-line label (e.g., "Scan"):
```
card_w = max(4 × 7, 24) + 24 = max(28, 24) + 24 = 52 → round to 72 (minimum)
```
For a two-word label split over two lines (e.g., "Search" / "tool"):
```
card_w = max(6×7, 4×7) + 24 = 42 + 24 = 66 → round to 72 (minimum)
```
For a longer label (e.g., "Code" / "analysis"):
```
card_w = max(4×7, 8×7) + 24 = 56 + 24 = 80 → round to 80
```
**Template (two-line label, 80-wide card):**
```svg
<g class="c-gray" transform="translate(card_x, card_y)">
<rect x="0" y="0" width="80" height="80" rx="6"/>
<!-- icon: 24×24, top-center; origin = ((8024)/2, 10) = (28, 10) -->
<g transform="translate(28, 10)">
<!-- paste icon glyph here (icon origin at 0,0) -->
</g>
<!-- two-line label: line 1 at y=50, line 2 at y=64 -->
<text class="ts" x="40" y="50" text-anchor="middle" dominant-baseline="central">Scan</text>
<text class="ts" x="40" y="64" text-anchor="middle" dominant-baseline="central">tool</text>
</g>
```
For a single-line label (when the full name fits in ≤10 chars):
```svg
<text class="ts" x="40" y="57" text-anchor="middle" dominant-baseline="central">Scanner</text>
```
**Color rules.**
- Use `c-gray` for all tool cards by default. Color encodes meaning, not tool identity — don't give each tool a different ramp.
- If **one specific tool** is the subject of the diagram (e.g., the exploitation tool that's being analyzed), promote just that one card to a semantic ramp (`c-coral` for attack tools, `c-amber` for analysis tools). All other cards stay `c-gray`.
**Row packing.** Align cards in a horizontal row inside the phase band's main flow zone. The gap between cards is **8px minimum**:
```
row_width = N × card_w + (N1) × 8
required: row_width ≤ 380 (main flow zone width inside a band)
```
| Cards | card_w | row_width | Fits? |
|-------|--------|-----------|-------|
| 4 | 80 | 352 | ✓ |
| 5 | 72 | 388 | ✗ — use card_w=72 with 6px gap: 5×72+4×6=384 ✓ |
| 6 | 64 | 408 | ✗ — split into two rows of 3 |
To center a row of N cards:
```
row_start_x = band_x + band_padding + (main_flow_w row_width) / 2
card[i].x = row_start_x + i × (card_w + gap)
```
---
## Operator icons
Larger icons (32 × 40) for the **left operator column** of a phase-band diagram — the human or AI actor that initiates the operation. These appear once per diagram, outside (to the left of) the phase band containers.
---
### operator-human
A simplified head + shoulders silhouette. 32 × 40.
```svg
<g transform="translate(x, y)">
<circle class="arr" cx="16" cy="11" r="8" fill="none"/>
<path class="arr" d="M2 40 Q2 24 16 24 Q30 24 30 40" fill="none" stroke-linecap="round"/>
</g>
```
Place the icon's origin at `(operator_x, operator_y)`. The icon's visual center is at `(16, 24)`. Add a `ts` label below: `y = operator_y + 44`.
---
### operator-ai
An asterisk-in-circle — six spokes radiating from center, with an outer ring. 32 × 32.
```svg
<g transform="translate(x, y)">
<circle class="arr" cx="16" cy="16" r="14" fill="none"/>
<line class="arr" x1="16" y1="4" x2="16" y2="28"/>
<line class="arr" x1="4" y1="16" x2="28" y2="16"/>
<line class="arr" x1="7" y1="7" x2="25" y2="25"/>
<line class="arr" x1="25" y1="7" x2="7" y2="25"/>
</g>
```
For a six-spoke variant (closer to the Anthropic asterisk):
```svg
<g transform="translate(x, y)">
<circle class="arr" cx="16" cy="16" r="14" fill="none"/>
<line class="arr" x1="16" y1="3" x2="16" y2="29"/>
<line class="arr" x1="4" y1="10" x2="28" y2="22"/>
<line class="arr" x1="4" y1="22" x2="28" y2="10"/>
</g>
```
---
**Placement in a phase-band diagram:**
Both operator icons sit in the left margin at `x=20`, vertically positioned to align with the band they feed into (usually Phase 1):
```
operator-human: x=20, y=phase1_band_y + (band_h / 2) 20 44 16
operator-ai: x=20, y=phase1_band_y + (band_h / 2) 16 + 16
label under each: ts at (36, icon_y + icon_h + 8), text-anchor="middle"
```
The stacked human → ai pair is typical (human provides the target; ai runs the operation). Connect them with a short `arr` line, then connect the ai icon to the band's first card with an arrow entering the left edge of the band.
If any check fails, fix the SVG before saving. See `pitfalls.md` entries #19#28 for the full list of glyph-related failure modes and their fixes.
@@ -0,0 +1,492 @@
# Illustrative Diagram
For building *intuition* — the kind of diagram that makes a reader go "oh, *that's* what it's doing". Unlike flowcharts (which document steps) or structural diagrams (which document containment), an illustrative diagram draws the mechanism. The shape of the drawing *is* the explanation.
## When to use
This is the default for *"how does X actually work"* questions with no further qualification. Reach for it whenever the breakthrough moment is visual rather than procedural.
- **Physical subjects** — water heaters, engines, lungs, heart valves, batteries, transistors. Draw simplified cross-sections or cutaways.
- **Abstract subjects** — transformer attention, gradient descent, hash tables, the call stack, embeddings, recursion. Invent a spatial metaphor that makes the mechanism obvious.
Trigger phrases: "how does X work", "explain X", "I don't get X", "give me an intuition for X".
## When NOT to use
- The reader wants a reference, not an intuition. "What are the components of a transformer" is a structural diagram (labeled boxes). "How does attention work" is illustrative (fan of weighted lines).
- The metaphor would be arbitrary rather than revealing. Drawing "the cloud" as a cloud shape teaches nothing about how distributed computing works — skip the illustration and use a structural diagram instead.
- The mechanism is actually a sequence of discrete steps. That's a flowchart.
## Core principle
**Draw the mechanism, not a diagram *about* the mechanism.** Spatial arrangement carries the meaning; labels annotate. A good illustrative diagram still reads clearly even if you remove all the text.
- Color encodes intensity. Warm ramps (amber, coral, red) for heat/energy/pressure/activity. Cool ramps (blue, teal) for cold/calm/dormant. Gray for inert structure. A reader should glance at the drawing and immediately see *where the action is* without reading a label.
- Layout follows the subject's geometry. Tall narrow subject → tall narrow drawing. Wide flat subject → wide flat drawing. Let the thing dictate proportions within the 680px viewBox.
- Layering is encouraged for shapes. Unlike flowcharts where boxes never overlap, illustrative diagrams use z-ordering deliberately: a pipe entering a tank goes *behind* the tank wall, a flame goes *under* the kettle. Later in source = on top.
## Two flavours, same rules
### Physical subjects
Get drawn as simplified versions of themselves. Cross-sections, cutaways, schematics.
- A water heater is a tall rounded rect with a burner underneath. Not a Bézier portrait of a water heater.
- A flame is three triangles, not a fire.
- A lung is a branching tree in an oval-ish cavity. Not a medical illustration.
- A transistor is three terminals meeting at a junction. Not a 3D render.
**Fidelity ceiling**: if a `<path>` needs more than ~6 segments, simplify it. Recognizable silhouette beats accurate contour.
### Abstract subjects
Get drawn as spatial metaphors that make the mechanism obvious.
- **Attention in a transformer** — a row of tokens with weight-scaled lines fanning from one query token to every other token. Line thickness = attention weight.
- **Gradient descent** — a contour surface with a dot rolling downhill, trailing a path of discrete steps.
- **Hash table** — a funnel dropping items into a row of labeled buckets.
- **Call stack** — a vertical stack of frames growing upward with each push.
- **Embeddings** — a 2D scatter of labeled dots, clusters visible by position.
- **Convolution** — a small kernel sliding across a grid, highlighting the current receptive field.
The metaphor *is* the explanation. Don't label the metaphor — if you have to write "this represents attention", the drawing isn't doing its job.
## What changes from the flowchart/structural rules
- **Shapes are freeform.** Use `<path>`, `<ellipse>`, `<circle>`, `<polygon>`, curved lines. You're not limited to rounded rects.
- **Color encodes intensity, not category.** Warm = active/high-weight/attended-to, cool or gray = dormant/low-weight/ignored. The reader should see where the energy is without reading a label.
- **Layering and overlap are allowed — for shapes.** Draw a pipe entering the tank body. Draw insulation wrapping a chamber. Use z-order deliberately.
- **Text is still the exception — never let a stroke cross a label.** The overlap permission is for shapes only. Every label needs 8px of clear air between its baseline and the nearest stroke. If there's no quiet region for a label, the drawing is too dense — remove something or split into two diagrams.
- **Small shape-based indicators are allowed** when they tell the reader about physical state. Triangles for flames. Circles for bubbles. Wavy lines for steam or radiation. Keep them simple — basic SVG primitives, not detailed illustrations.
- **Lines stop at component edges.** When a stroke meets a component (a pipe entering a tank, a wire into a terminal, an arrow into a region), draw the line as segments that *end at the component's boundary* — don't draw straight through the component and rely on the fill to hide the overdraw. The host page's background color is not guaranteed (WeChat dark mode, Notion, markdown viewers), so any fill-based occlusion becomes a coupling between stroke color and background color. Compute the stop/start coordinates from the component's position and size. This matters more for illustrative diagrams than for flowcharts because curved and irregular edges make the overdraw more visible.
- **One gradient is permitted** — and only one. This is the single exception to the flat-fills rule. Use it to show a *continuous* physical property (temperature stratification in a tank, pressure drop along a pipe) with a `<linearGradient>` between exactly two stops from the same ramp. No radial gradients, no multi-stop fades, no decoration gradients. If two stacked flat-fill rects communicate the same thing, do that instead.
## Label placement
At 680px width you don't have room for a drawing *and* label columns on both sides. Pick one side and put all the labels there.
**Default to right-side labels** with `text-anchor="start"`. Labels on the left with `text-anchor="end"` are the ones that clip — the text extends leftward from x and long labels blow past x=0 without warning.
Reserve **at least 140px** of horizontal margin on the label side. Your drawing sits in roughly x=40 to x=500, labels sit in x=510 to x=640.
For each label, draw a dashed leader line from the referenced feature on the drawing to the label:
```svg
<g>
<line class="leader" x1="380" y1="120" x2="510" y2="140"/>
<circle cx="380" cy="120" r="2" fill="#888780"/>
<text class="ts" x="516" y="144">Hot zone</text>
</g>
```
The small circle at the anchor end makes the leader read as an intentional pointer rather than a stray stroke.
**Large internal zones** (big enough to hold text without crowding) can have labels sitting inside them, with at least 20px of clear air from any edge.
## Composition order
Write the SVG in this layering order so z-index comes out right:
1. **Silhouette first.** The largest shape, centered in the viewBox. This defines the subject's footprint.
2. **Internal structure.** Chambers, pipes, membranes, mechanical parts. Drawn inside the silhouette.
3. **State indicators.** Color fills showing temperature/pressure/concentration, the one optional gradient. Applied after shapes so they tint on top of the structure.
4. **External connections.** Pipes entering or exiting, arrows showing flow direction.
5. **Labels and leader lines.** Last, so they sit on top of everything else.
Don't try to optimize this order — just follow it every time. Z-ordering bugs are hard to debug after the fact.
## Tiny worked example — attention fan
Request: "how does attention work in a transformer"
Plan:
- Spatial metaphor: a row of 5 tokens at the bottom, one highlighted (the query), with 5 lines fanning up to a layer above. Line thickness encodes weight — thickest line to "sat", mid lines to nearby tokens, thin lines to distant ones.
- Colors: gray for dormant tokens, amber for the query token. Fan lines hardcoded amber `#EF9F27` with varying stroke-width and opacity.
- One caption below the fan: "Line thickness = attention weight".
## Central subject + radial attachments
For **"how does X interact with its environment"** diagrams where a central subject connects outward to a small set of optional capabilities — an LLM with retrieval, tools, and memory; a browser with DOM, storage, and network; a GPU with shared memory, registers, and global memory. The layout is a hub-and-spoke: one subject in the middle, 24 attachments arranged around it, and dashed connectors showing that each attachment is an *available capability*, not a mandatory step.
**Why illustrative and not structural**: the reader's question is "how does the subject use its environment" — that's intuition about a mechanism, not a documentation of what lives inside what. A structural diagram of "LLM + retrieval + tools + memory" would read like a block diagram; the radial layout instead reads like "this thing reaches out to these things when it needs to".
### Anatomy
```
[ In pill ] → [ LLM Call ] → [ Out pill ]
|
┌──────┼──────┐ ← three dashed spokes dropping
↓ ↓ ↓ from the subject center
[Retrieval] [Tools] [Memory]
```
- A **horizontal mainline** across the vertical center of the diagram carries the primary flow. Both ends are pill-shaped terminals.
- The **central subject** is the node in the middle of the mainline — a rounded rect (not a pill), typically using a color ramp (`c-purple` is conventional for "the model").
- **24 attachments** sit below the subject as rounded rects, spaced horizontally.
- **Dashed `.arr-alt` connectors** drop from the subject's bottom edge to each attachment's top edge. These are dashed to communicate "optional capability, used when needed" — the mainline is what always runs, the spokes are what the subject reaches for.
- **Short 12 word labels** beside each spoke (`Query` / `Call` / `Read`) communicate the relationship. See the `.arr-alt` notes in `svg-template.md`.
### Layout
Standard geometry at viewBox width 680:
```
Mainline y = 160 # rect top; cy = 182 (rect height 44)
In pill x=60, w=80 # right edge 140
Subject box x=290, w=180 # center (380, 182), bottom edge 204
Out pill x=560, w=80 # center (600, 182), right edge 640 ✓
Attachment row y = 320 # 116px below subject cy; bottom 364
Attachment w = 120 # fits "Retrieval" (9 × 8 + 24 = 96)
Attachment 1 x=120, center (180, 342)
Attachment 2 x=320, center (380, 342) # directly below subject
Attachment 3 x=520, center (580, 342) # right edge 640 ✓
Spoke channel ymid = 290 # 86px below subject bottom, 30px above att row
Spoke 1 (L): path (380, 204) → (380, 290) → (180, 290) → (180, 320)
Spoke 2 (M): straight (380, 204) → (380, 320)
Spoke 3 (R): path (380, 204) → (380, 290) → (580, 290) → (580, 320)
```
The center spoke is a straight vertical line; the outer spokes are L-bends that drop to a shared horizontal channel at `y = 290` before turning down into the attachments. Don't route the outer spokes as diagonals — diagonal lines in an otherwise orthogonal diagram read as stray strokes.
Mainline arrow endpoints: `In→Subject` runs from `(140, 182)` to `(290, 182)`; `Subject→Out` runs from `(470, 182)` to `(560, 182)`. Both use solid `.arr`.
### Rules
- **At most 4 attachments.** Five overflows the horizontal budget at 140px each. If you need 5+, split into two diagrams (subject + capability group A, subject + capability group B) or step the pattern up to a structural diagram.
- **Dashed spokes only when the attachments are optional.** If every spoke always runs, the pattern isn't radial — it's a fan-out flowchart and should use solid `.arr` connectors in the simple fan-out pattern from `flowchart.md`.
- **Spoke labels stay short.** 12 words, `ts`, positioned beside the spoke midpoint with `text-anchor="end"` for labels on the left of a spoke and `"start"` for labels on the right. Bidirectional relationships draw two labels on opposite sides of the spoke ("Query" above, "Results" below — same spoke).
- **No rotated text.** Design-system.md's rotation ban applies here; radial layouts do *not* unlock rotated labels.
- **No literal icons.** A radial hub describing "LLM + tools + memory" uses labeled rounded rects for each capability, not tool wrench glyphs or memory-chip drawings.
- **Central subject stays a rect, not a circle.** Circles read as "state" or "particle"; this pattern is about a subject reaching for capabilities, and a rounded rect labels cleanly at 14px.
### Worked example — LLM hub
Request: "how an LLM uses retrieval, tools, and memory"
Plan:
- Mainline `In``LLM Call``Out` along the horizontal center; rects at y=160, cy=182
- `LLM Call` uses `c-purple` to mark it as the central subject
- 3 attachments below at y=320: `Retrieval` / `Tools` / `Memory`, all gray, w=120 each
- Three dashed `.arr-alt` spokes — the middle spoke straight down, the outer two as L-bends through a shared channel at y=290
- One short label beside each spoke (`Query` / `Call` / `Read`) picking the most representative verb; the bidirectional return path is left implicit so the diagram stays quiet
- viewBox: last element `Retrieval` bottom = 320 + 44 = 364 → H = **384**
```svg
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 680 384" font-family="...">
<style>...</style>
<defs><marker id="arrow" .../></defs>
<rect class="box" x="60" y="160" width="80" height="44" rx="22"/>
<text class="t" x="100" y="182" text-anchor="middle" dominant-baseline="central">In</text>
<g class="c-purple">
<rect x="290" y="160" width="180" height="44" rx="6"/>
<text class="th" x="380" y="182" text-anchor="middle" dominant-baseline="central">LLM Call</text>
</g>
<rect class="box" x="560" y="160" width="80" height="44" rx="22"/>
<text class="t" x="600" y="182" text-anchor="middle" dominant-baseline="central">Out</text>
<line x1="140" y1="182" x2="288" y2="182" class="arr" marker-end="url(#arrow)"/>
<line x1="470" y1="182" x2="558" y2="182" class="arr" marker-end="url(#arrow)"/>
<g class="c-gray">
<rect x="120" y="320" width="120" height="44" rx="6"/>
<text class="th" x="180" y="342" text-anchor="middle" dominant-baseline="central">Retrieval</text>
</g>
<g class="c-gray">
<rect x="320" y="320" width="120" height="44" rx="6"/>
<text class="th" x="380" y="342" text-anchor="middle" dominant-baseline="central">Tools</text>
</g>
<g class="c-gray">
<rect x="520" y="320" width="120" height="44" rx="6"/>
<text class="th" x="580" y="342" text-anchor="middle" dominant-baseline="central">Memory</text>
</g>
<path d="M 380 204 L 380 290 L 180 290 L 180 318" class="arr-alt" fill="none" marker-end="url(#arrow)"/>
<line x1="380" y1="204" x2="380" y2="318" class="arr-alt" marker-end="url(#arrow)"/>
<path d="M 380 204 L 380 290 L 580 290 L 580 318" class="arr-alt" fill="none" marker-end="url(#arrow)"/>
<text class="ts" x="280" y="284" text-anchor="middle">Query</text>
<text class="ts" x="390" y="258" text-anchor="start">Call</text>
<text class="ts" x="480" y="284" text-anchor="middle">Read</text>
</svg>
```
Notes on this example:
- The central subject `LLM Call` uses `c-purple` while attachments stay gray — this is the single-accent rule from the design system, where the accent ramp anchors reader attention on "the thing doing the reaching".
- All three spokes use `class="arr-alt"` because retrieval, tool-calls, and memory reads are **optional** — an LLM invocation might use all three, some, or none. If the diagram were describing a specific pipeline where all three always run, the spokes would be solid `.arr`.
- **One short verb per spoke**, not a bidirectional pair. Two stacked labels per spoke would crowd the horizontal channel at y=290; picking the representative verb (Query, Call, Read) is quieter and the reader infers the return path. If the return direction matters, split into two diagrams rather than stacking labels.
- Each label sits on the horizontal channel (y=284, 6px above y=290) directly over the L-bend corner so it reads as belonging to that spoke. The middle spoke's label sits 32px above to avoid colliding with the other labels.
- Spoke 2 drops straight down from the subject's bottom edge to the middle attachment's top edge because they're vertically aligned — no need for a bend. The arrowhead lands at y=318 (2px short of the attachment's top at y=320) to leave the 10px-ish breathing room flowchart.md recommends.
- Rightmost rect edges: Out pill ends at `560 + 80 = 640` ✓, Memory ends at `520 + 120 = 640` ✓ — both exactly flush with the 640 bound.
## Spectrum / continuum
For topics where the reader's question is *"where on the scale between X and Y does Z sit"* — Anthropic's "Finding the sweet spot" diagram (image #5) is the canonical example. The layout is a single horizontal axis with opposing concepts at either end, tick points along it, option boxes hanging below each tick, and optional italic captions under the options.
This is a **new illustrative sub-pattern**, distinct from the radial-attachments layout above. Use it when the intuition the reader needs is "these options are *positions* on a single continuum, and one of them is better than the others because of where it sits on the continuum".
### When to use
- "Finding the sweet spot between A and B"
- "The trade-off between flexibility and rigidity / latency and quality / cost and performance"
- "Where does approach X sit on the X-to-Y spectrum"
- Any topic where the reader has been thinking in a binary and you're showing them it's a gradient
### When not to use
- The options are unordered categories (use a structural diagram with sibling boxes instead).
- The trade-off has more than one dimension (spectrum only works for 1-D).
- There's no "wrong" end to the axis — the spectrum works because both extremes are undesirable and there's a sweet spot in between. If one end is just "better", use a chart, not this pattern.
### Geometry
See also `layout-math.md` → "Spectrum geometry".
| Element | Coordinates |
|--------------------|--------------------------------------------------|
| Eyebrow (optional) | `(340, 50)`, class `eyebrow`, `text-anchor="middle"` |
| Axis line | `x1=80 y1=140 x2=600 y2=140`, class `arr`, markers on **both** ends |
| Left-end label | `(80, 120)`, class `ts`, `text-anchor="start"`, uppercase content |
| Right-end label | `(600, 120)`, class `ts`, `text-anchor="end"`, uppercase content |
| Tick points (N) | circles at `(tick_x, 140)` `r=6` |
| Option boxes | `y=200 h=60 w=120 rx=6`, one per tick point |
| Captions (optional)| `y=292 and y=308`, italic `ts`, `text-anchor="middle"` |
For **3 ticks**, tick_x = `160, 340, 520`; option box x = `100, 280, 460` (each 120 wide, centered on tick_x).
For **4 ticks**, tick_x = `140, 280, 420, 560`; option box x = `80, 220, 360, 500` (each 120 wide).
For **5 ticks**, tick_x = `120, 240, 360, 480, 600`; option box width shrinks to 100 (x = `70, 190, 310, 430, 550`).
### The axis
The axis is a single horizontal line with arrow markers at both ends (so it reads "this extends both ways, no natural direction"). Unlike regular arrows which use `marker-end`, the spectrum axis uses **both** `marker-start` and `marker-end`:
```svg
<line class="arr" x1="80" y1="140" x2="600" y2="140"
marker-start="url(#arrow)" marker-end="url(#arrow)"/>
```
The `context-stroke` marker in the template automatically colors both arrowheads to match the line.
**Do not** add a color ramp to the axis. It's always `arr` (neutral gray) — colored axes imply that one end is "good" and the other "bad", which defeats the entire point of a spectrum diagram.
### End labels
The labels at the two ends describe the **extremes** the axis is measuring between. Keep them to 23 words, usually in all caps or title case to signal they're axis labels, not box labels. In image #5 these are "NO STRUCTURE" and "TOO RIGID".
Place them *above* the axis with at least 8px of clearance between the end of the axis arrowhead and the label's text baseline. Left label uses `text-anchor="start"` anchored at the axis x1; right label uses `text-anchor="end"` anchored at the axis x2. No leader lines — the proximity to the axis end is enough.
### Tick points and option boxes
Each tick is a small circle (r=6) sitting on the axis line. Tick circles use `c-gray` by default (subtle dots) — the sweet-spot tick upgrades to an accent ramp (`c-green` or `c-amber`) to draw the eye.
Each tick has a **matching option box** directly below it. The option box is a two-line node (60 tall, title + 1-word id) centered on the tick's x. The option's id (left subtitle like "A", "B", "C") is optional and mostly for referring back in the caption.
The sweet-spot option's box takes the same accent ramp as its tick — green/amber highlights "this is the one". All other option boxes stay neutral gray (`c-gray`).
### Italic per-option captions
Below each option box, an optional 12 line italic `ts` caption explains *what that option feels like*. Keep each line ≤24 characters (≈3 words) so the captions don't spill into each other horizontally. Captions are always italic (use inline `font-style="italic"`), matching the `caption` class from poster flowcharts but placed under each option individually.
```svg
<text class="ts" x="160" y="292" text-anchor="middle" font-style="italic">vague and</text>
<text class="ts" x="160" y="308" text-anchor="middle" font-style="italic">untestable</text>
```
If the captions need more than 2 lines each, the spectrum is the wrong pattern — the options need their own diagram.
### Eyebrow
A spectrum diagram can carry a small `eyebrow`-class label at the very top (y=50) to name the trade-off: "CHOOSING AN EVALUATION APPROACH". This is optional but strongly recommended — without an eyebrow the reader has to infer "what is this spectrum *about*" from the end labels alone, and end labels are short by design.
### Worked example — sweet spot
Request: "Show the trade-off between an evaluation that's too loose and one that's too rigid."
Plan:
- Eyebrow: "CHOOSING AN EVALUATION"
- Axis: "NO STRUCTURE" on the left, "TOO RIGID" on the right
- 3 tick points with option boxes: "A · none", "B · rubric", "C · checklist"
- "B · rubric" is the sweet spot → `c-green`
- Italic captions under each: "vague and / untestable", "structured / and flexible", "brittle, / doesn't generalize"
- viewBox H ≈ 340
```svg
<text class="eyebrow" x="340" y="50" text-anchor="middle">Choosing an evaluation</text>
<text class="ts" x="80" y="120" text-anchor="start">NO STRUCTURE</text>
<text class="ts" x="600" y="120" text-anchor="end">TOO RIGID</text>
<line class="arr" x1="80" y1="140" x2="600" y2="140"
marker-start="url(#arrow)" marker-end="url(#arrow)"/>
<circle class="c-gray" cx="160" cy="140" r="6"/>
<circle class="c-green" cx="340" cy="140" r="6"/>
<circle class="c-gray" cx="520" cy="140" r="6"/>
<g class="c-gray">
<rect x="100" y="200" width="120" height="60" rx="6"/>
<text class="th" x="160" y="222" text-anchor="middle">None</text>
<text class="ts" x="160" y="242" text-anchor="middle">A</text>
</g>
<g class="c-green">
<rect x="280" y="200" width="120" height="60" rx="6"/>
<text class="th" x="340" y="222" text-anchor="middle">Rubric</text>
<text class="ts" x="340" y="242" text-anchor="middle">B</text>
</g>
<g class="c-gray">
<rect x="460" y="200" width="120" height="60" rx="6"/>
<text class="th" x="520" y="222" text-anchor="middle">Checklist</text>
<text class="ts" x="520" y="242" text-anchor="middle">C</text>
</g>
<text class="ts" x="160" y="292" text-anchor="middle" font-style="italic">vague and</text>
<text class="ts" x="160" y="308" text-anchor="middle" font-style="italic">untestable</text>
<text class="ts" x="340" y="292" text-anchor="middle" font-style="italic">structured</text>
<text class="ts" x="340" y="308" text-anchor="middle" font-style="italic">and flexible</text>
<text class="ts" x="520" y="292" text-anchor="middle" font-style="italic">brittle, doesn't</text>
<text class="ts" x="520" y="308" text-anchor="middle" font-style="italic">generalize</text>
```
viewBox: max_y = 308 + 4 = 312 → H = **332**.
### Pitfalls
- **Axis end labels clipped**: if `text-anchor="end"` is used on the left label or `text-anchor="start"` on the right, labels extend past the axis ends and read backwards. Left is `start`, right is `end`.
- **Sweet spot not the right color**: using `c-coral` for the sweet spot because "it's the attention color" is backwards — `c-coral` reads as "warning", `c-green` reads as "good", `c-amber` reads as "deliberate". Match the ramp to the *outcome*, not just the emphasis.
- **Tick count ≠ option count**: every tick needs an option box and vice versa. An orphan tick or an orphan option is a layout bug.
- **Captions too long**: 2 italic lines at ≤24 chars each. Longer captions collide.
## Annotation circle on connector
For diagrams where a connector (arrow between two subjects) has a **named mediator** that deserves to be visible as a node itself. Image #13 (Claude ↔ Environment with Skill) is the canonical case: Claude talks to its environment, and the "Skill" that mediates the exchange is too important to be a mere label on the arrow — it becomes a labeled circle sitting on the connector.
**When to use.** Only in illustrative diagrams. Flowcharts and sequence diagrams label their arrows with text; structural diagrams use arrow labels or inline text. The annotation-circle-on-connector is an *illustrative* convention specifically — it promotes "the thing on the arrow" to a visual node without breaking the two-subject layout.
**When not to use.**
- The mediator is actually a step in a sequence — use a flowchart node.
- The mediator is a system component — use a structural box.
- There are two or more mediators on the same connector — the pattern doesn't stack; restructure the diagram.
### Geometry
See `glyphs.md` → "Annotation circle on connector" for the full glyph. The placement rule:
| Element | Coordinates |
|------------------------|--------------------------------------------|
| Subject A | e.g., `x=80 y=160 w=180 h=56` |
| Subject B | e.g., `x=440 y=160 w=180 h=56` |
| Bidirectional arrows | A↔B, offset by 10px vertically |
| Annotation circle | `cx = (A_right + B_left) / 2`, `cy = arrows_y_midpoint` |
| Short connector line | `x1 = cx, y1 = cy, x2 = cx, y2 = cy + 40`, class `arr` (no arrowhead) |
The annotation circle sits **above** the pair of bidirectional arrows, with a short vertical connector line (no arrowhead) dropping from the bottom of the circle to the midpoint of the arrow pair. This reads as "this circle is a flag attached to the arrow below it".
### Arrow routing
The two-way exchange between Subject A and Subject B uses a pair of offset horizontal arrows:
```svg
<!-- Claude → Environment (top arrow) -->
<line class="arr" x1="260" y1="184" x2="440" y2="184" marker-end="url(#arrow)"/>
<text class="ts" x="350" y="178" text-anchor="middle">Action</text>
<!-- Environment → Claude (bottom arrow) -->
<line class="arr" x1="440" y1="204" x2="260" y2="204" marker-end="url(#arrow)"/>
<text class="ts" x="350" y="218" text-anchor="middle">Feedback</text>
```
The arrow-pair y midpoint is `(184 + 204) / 2 = 194`. The annotation circle's connector line ends at `(350, 194)` (the midpoint). The circle itself sits above, centered at `(350, 150)` with r=30.
### The annotation circle itself
```svg
<g transform="translate(318, 118)">
<circle class="box" cx="32" cy="32" r="30"/>
<g class="c-teal">
<rect x="4" y="22" width="56" height="20" rx="10"/>
<text class="th" x="32" y="36" text-anchor="middle">Skill</text>
</g>
</g>
<line class="arr" x1="350" y1="180" x2="350" y2="194"/>
```
The outer circle uses the neutral `box` class (so the ring itself doesn't fight for attention), and the inner pill uses a ramp (usually `c-teal` — the mediator is an aid, not an adversary).
### Label length
The inner pill caps at ~6 Latin characters. "Skill" fits. "Constraint" does not — shorten or restructure. For CJK, cap at 3 characters.
### Multiple circles on one arrow
**Not allowed.** If two mediators sit on the same connector, you're describing a sequence, not a mediator — use a flowchart instead.
## Decorative icon inside box
The **only** place in the design system where an icon is allowed inside a rect is inside an illustrative diagram's subject box or a structural diagram's hub/shared-state box. The rule is strict: the icon must come from `glyphs.md`'s icon set, and it lives in the lower half of a box that's at least 80px tall.
### Why only here
Flowcharts and sequence diagrams use the label alone — adding an icon to a flowchart box just adds visual noise to a process the reader is tracking sequentially. In an illustrative diagram, the icon reinforces *what kind of thing the box represents* (a document store, a terminal, a code script), and that reinforcement is part of the intuition the diagram is trying to build.
### Allowed icon set
Only these, from `glyphs.md`:
- `doc-icon` — documents, artifacts, shared files, logs
- `terminal-icon` — terminals, computers, shells, CLI environments
- `script-icon` — inline scripts, programmatic tool calls (used in structural "Parallel independent rounds" pattern; rarely in illustrative)
**No other icons.** Do not draw an LLM brain, a wrench for "tools", a cloud for "cloud", a gear for "settings". Label the rect.
### Placement
For a box at `(box_x, box_y, box_w, box_h)`:
- Title `th` at `(box_x + box_w/2, box_y + 22)`.
- Subtitle `ts` at `(box_x + box_w/2, box_y + 40)` (optional).
- Icon anchor at `(box_x + box_w/2 12, box_y + box_h 36)` (for a 24-wide, 28-tall icon).
The icon must have at least **8px of clear air** above it (between the subtitle baseline + descender and the icon's top). If the box is too short to fit both text and icon, grow the box — don't squeeze them.
### Color
The icon uses `arr` or `box` classes (neutral stroke), **not** a ramp. The parent box carries the ramp color — the icon is a secondary visual cue that inherits the reader's attention from the box, not from its own color.
```svg
<g class="c-amber">
<rect x="260" y="280" width="160" height="80" rx="10"/>
<text class="th" x="340" y="302" text-anchor="middle">Shared state</text>
<text class="ts" x="340" y="320" text-anchor="middle">Task artifacts</text>
<g transform="translate(328, 324)">
<path class="arr" d="M2 2 L16 2 L22 8 L22 26 L2 26 Z" fill="none"/>
<path class="arr" d="M16 2 L16 8 L22 8" fill="none"/>
<line class="arr" x1="6" y1="14" x2="18" y2="14"/>
<line class="arr" x1="6" y1="18" x2="18" y2="18"/>
<line class="arr" x1="6" y1="22" x2="14" y2="22"/>
</g>
</g>
```
### Multiple icons in one diagram
One icon per box is the cap. Two in the same diagram is fine if they're in different boxes and each serves its own intuition. Three or more icons in one diagram starts to feel like a screenshot — simplify.
## Rules of thumb
- **Silhouette > outline.** A simple rounded rect labeled "Reactor" beats a detailed reactor drawing. The reader needs to recognize *what kind of thing* it is, not admire your drafting.
- **Color on what matters.** If the hot zone is the point, color only the hot zone. Leave the rest of the drawing in neutral stroke lines. Color where the meaning is.
- **One gradient, deliberately.** If you reach for a gradient, ask: "is this showing a continuous physical property?" If yes, use it. If no, use flat fills.
- **Labels in the quiet zone.** Before placing a label, check that no stroke will cross its bounding box. If there's no quiet zone, remove something from the drawing.
- **One idea per diagram.** If you catch yourself cramming two mechanisms into one drawing, split them. Two 10-element diagrams beat one 20-element diagram every time.
## Common failure modes specific to illustrative
- **Too literal** — tracing a real photo of the subject. Six Bézier curves, not sixty. Stylize.
- **Label crossed by stroke** — text sits where a pipe or arrow also passes. Move the label to the margin with a leader line; never use a background rect to hide the stroke.
- **Gradient as decoration** — using a gradient because it "looks nice". Remove it. Gradients are only for continuous physical properties.
- **Color by category instead of intensity** — dormant and active nodes using different ramps for variety. Use gray for dormant, one accent for active. Let the color tell the story.
- **Both-sides labels** — drawing has labels on the left *and* the right. Pick one side. At 680px wide, you don't have room for both.
@@ -0,0 +1,525 @@
# Layout Math
SVG has no auto-layout. Every coordinate, width, and height is hand-computed. Most diagram failures trace back to text overflowing its container or elements landing outside the viewBox. This file is the arithmetic you run *before* writing any `<rect>`.
## The coordinate system
- **viewBox**: `0 0 680 H`. Width is always 680. Compute H from content.
- **Safe area**: `x ∈ [40, 640]`, `y ∈ [40, H - 40]`. Leave 40px of breathing room on every edge.
- **Usable width**: 600 px (640 40).
- **Pixel units are 1:1.** The `width="100%"` with `viewBox="0 0 680 H"` means the browser scales the whole coordinate space to fit the container. A 14px font is really 14px. Character widths below assume this 1:1 ratio.
## Text width estimation
SVG `<text>` never auto-wraps. If you put more characters in a box than it can hold, they overflow visibly. Use these character-to-pixel multipliers, calibrated on Anthropic Sans:
| Case | Approx. width per character |
|------------------------------------------|-----------------------------|
| 14px latin, weight 500 (`th`, titles) | ~8 px |
| 14px latin, weight 400 (`t`, body) | ~8 px |
| 12px latin, weight 400 (`ts`, subtitles) | ~7 px |
| 14px CJK (Chinese, Japanese, Korean) | ~15 px (~2× Latin) |
| 12px CJK | ~13 px (~1.9× Latin) |
**Special characters:** chemical formulas (C₆H₁₂O₆), math symbols (∑ ∫ √), subscripts, superscripts all take the same horizontal space as normal characters — don't assume subscripts are narrower. For labels that mix Latin and formulas, add 3050% padding to your width estimate.
### Empirical calibration samples
Real measurements of Anthropic Sans at the sizes this skill uses. The multipliers above are the safe ceilings derived from these samples — not the averages. Letter composition matters: narrow letters like `l`/`i`/`f` push the per-char average down, tall letters like `B`/`J`/`P`/`Q` push it up.
| Text | Chars | Weight | Size | Measured width | Per-char |
|-----------------------------------------|-------|--------|-------|----------------|----------|
| `Authentication Service` | 22 | 500 | 14 px | 167 px | ~7.6 |
| `Background Job Processor` | 24 | 500 | 14 px | 201 px | ~8.4 |
| `Detects and validates incoming tokens` | 37 | 400 | 14 px | 279 px | ~7.5 |
| `forwards request to` | 19 | 400 | 12 px | 123 px | ~6.5 |
| `データベースサーバー接続` | 12 | 400 | 14 px | 181 px | ~15.1 |
The formula uses **8** for 14px Latin and **7** for 12px Latin because those are the safe ceilings, not the average. A label like "Background Job Processor" at 8.4 px/char would overflow a box sized from a 7.6 px/char average — always round up, never down.
**Worked sanity check**: `"Detects and validates incoming tokens"` (37 chars, `ts` class at 12px) → formula gives `37 × 7 + 24 = 283 px`. Measured 279 px + 24 px padding = 303 px. The formula is ~7% conservative, which is the correct direction for rect sizing — bias toward extra padding, never toward clipping.
### Rect sizing formula
For a two-line node (title + subtitle) the width must fit whichever line is longer:
```
width_needed = max(title_chars × 8, subtitle_chars × 7) + 24
```
The `+ 24` is 12px of horizontal padding on each side. If the text is centered, that's 12px of clear air between the text edge and the rect stroke — looks balanced.
For a single-line node:
```
width_needed = title_chars × 8 + 24
```
For CJK content, replace the 8 with 15 and the 7 with 13.
**Round up to the nearest 10px** for cleaner coordinates. A box that "needs" 167px becomes 170px.
### Worked examples
- `"JWT authentication"` (18 chars, title) → `18 × 8 + 24 = 168` → round to **170**
- `"Validates user credentials"` (26 chars, subtitle) in a two-line box with title `"Login service"` (13 chars, 8-wide) → `max(13 × 8, 26 × 7) + 24 = max(104, 182) + 24 = 206` → round to **210**
- `"微服务架构"` (5 CJK chars, title) → `5 × 15 + 24 = 99` → round to **100**
- `"发送 HTTP 请求 forwards request"` (mixed, treat CJK chars as 15px and Latin as 8px) → `3×15 + 4×8 + 13×8 = 45 + 32 + 104 = 181 + spaces + 24 ≈ 220`
**Rule of thumb**: if you find yourself adding characters to a label, recheck the width. It's easy to write "Authentication" once, size the box to fit, then expand it to "Authentication service" and forget to resize.
## viewBox height calculation
After placing every element, compute max_y:
1. For every `<rect>`, compute `y + height`.
2. For every `<text>`, the bottom is `y + 4` (roughly — 4px descent below the baseline).
3. For every `<circle>`, it's `cy + r`.
4. `max_y` is the maximum across all of these.
5. `H = max_y + 20`
**Don't guess.** A 20px buffer below the last element keeps things tight without clipping descenders.
**Don't leave huge empty space at the bottom.** If the diagram ends at y=280, H should be 300 — not 560. Excess whitespace below the content feels like a rendering bug.
## Tier packing (horizontal rows)
When placing N boxes in a horizontal row, check total width before you start writing coordinates:
```
total = N × box_width + (N - 1) × gap
```
- `box_width`: chosen to fit the longest label in that row
- `gap`: 20px minimum between adjacent boxes
Required: `total ≤ 600` (the usable width). If not, one of three things must give:
1. **Shrink box_width** — cut subtitles, shorten titles
2. **Wrap to 2 rows**
3. **Split into an overview diagram + detail diagrams** (one per sub-flow)
### Worked example — four consumer boxes
- 4 boxes, each containing `"Consumer N"` (10 chars title) and `"Processes events"` (16 chars subtitle)
- Needed width per box: `max(10×8, 16×7) + 24 = max(80, 112) + 24 = 136` → round to **140**
- 4 boxes × 140 + 3 gaps × 20 = 560 + 60 = **620****overflows** by 20
- Fix: shrink to **130** each (check: `max(10×8, 16×7) + 24 = 136`, so 130 is tight — cut subtitle to 14 chars or drop it entirely)
- Or: drop to 3 boxes per row, stack the fourth below
- Or: 4 × 130 + 3 × 20 = 580, centered at `x = 40 + (600-580)/2 = 50` → boxes at x = 50, 200, 350, 500
## Swim-lane (sequence) layout
Sequence diagrams have their own coordinate system — actor columns ("lanes") along the top, dashed lifelines running down, numbered horizontal messages between them. The numbers below are fixed conventions so every sequence diagram in the skill feels consistent.
### Lane widths and centers
N = number of actors. Lane width `lane_w`, header rect width `header_w = lane_w 20`, lifeline x = lane center. Gap between lanes = 20.
| N | lane_w | header_w | First offset | Lane centers (x) |
|---|--------|----------|--------------|--------------------------------|
| 2 | 290 | 270 | 40 | 185, 495 |
| 3 | 186 | 166 | 40 | 133, 340, 547 |
| 4 | 140 | 120 | 30 | 100, 260, 420, 580 |
| 5 | 112 | 92 | 26 | 82, 214, 346, 478, 610 |
| 6 | 100 | 80 | 30 | 80, 190, 300, 410, 520, 630 |
Hard cap: **4 actors** (comfortable), **6 actors** (maximum). 5 is allowed only when every actor title is ≤12 characters and has no subtitle. 6 requires every title ≤9 characters (`9 × 8 + 24 = 96`, just inside `header_w=100`) and no subtitle. N=6 also collapses the intra-lane gap (the 20px padding between `lane_w` and `header_w` becomes 0 — the headers pack shoulder-to-shoulder) and borrows 10px of left-edge margin and all of the right-edge margin: the rightmost header rect sits flush against x=680. Use N=6 only when every actor is genuinely essential — otherwise merge actors or split the diagram. More than 6 doesn't fit 680px legibly.
### Vertical geometry (fixed for all sequence diagrams)
```
actor header box y = 40..88 (height 48, rx 8)
title (th) y = 60 (dominant-baseline="central")
role subtitle (ts) y = 78 (optional, one line, ≤16 chars)
lifeline start y = 92
first message row arrow_y[0] = 120
message row pitch 44 px → arrow_y[k] = 120 + 44 · k
lifeline tail y = last_arrow_y + 24
```
### viewBox height
```
header_bottom = 88
first_arrow_y = 120
last_arrow_y = 120 + 44 × (M 1) # M = number of messages
lifeline_bottom = last_arrow_y + 24
note_bottom = lifeline_bottom + 16 + 48 # only if side note is at the bottom
H = max(lifeline_bottom, note_bottom) + 20
```
### Message arrows
Each message is a horizontal `<line>` at `y = arrow_y[k]`, running from the sender lifeline x to the receiver lifeline x with a 6px offset so the arrowhead doesn't touch the dashes:
- Left-to-right: `x1 = sender_x + 6`, `x2 = receiver_x 6`
- Right-to-left: `x1 = sender_x 6`, `x2 = receiver_x + 6`
Use `class="arr-{ramp}"` where `{ramp}` matches the sender's actor ramp. Always set `marker-end="url(#arrow)"`.
### Message labels
Label sits **above** the arrow at `y = arrow_y 10` with `text-anchor="middle"`, `class="ts"`, and the number prefix baked into the text (`"1. Click login"`, not separate tspans). Label x is the midpoint of sender and receiver: `(sender_x + receiver_x) / 2`.
Max characters that fit in a label between two adjacent lanes (e.g. lanes 1↔2 for N=4):
```
label_chars_max ≈ (|sender_x receiver_x| 8) / 7
```
For N=4 adjacent lanes (|Δx|=160): ~21 chars. For the longest cross-diagram leap (lane 1↔4, |Δx|=480): ~67 chars. In practice, aim for ≤30 chars — short messages read faster, even when there's room.
### Self-messages
A self-message is a 16×24 `<rect>` using the actor's `c-{ramp}` class, horizontally centered on the lifeline: `rect_x = lifeline_x 8`, `rect_y = arrow_y 12`. The label sits **to the left** of the rect (so it stays inside the diagram for the rightmost lane) at `x = rect_x 8` with `text-anchor="end"`, `class="ts"`, `dominant-baseline="central"`, and the same numbered format.
### Side note
A `class="box"` rect with a `th` title and optional `ts` subtitle. Default size 240×48, `rx="10"`. Placement depends on N:
- **N ≤ 3**: top-left at `(40, 40)` — tucks beside the first actor header, no overlap because `first_offset ≥ 40`.
- **N ≥ 4**: bottom-left at `(40, lifeline_bottom + 16)` — the top is packed tight against the leftmost header, so use the bottom margin.
### Worked example — OAuth 2.0 (N=4, M=10)
```
lane centers 100, 260, 420, 580 (lane_w=140, header_w=120)
header_bottom 88
first_arrow_y 120
last_arrow_y 120 + 44×9 = 516 (10 messages)
lifeline_bottom 540
note_bottom 540 + 16 + 48 = 604 (note at bottom)
H 604 + 20 = 624
viewBox "0 0 680 624"
```
Label budgets: adjacent lanes (|Δx|=160) fit ~21 chars; "Redirect with client_id, scope" at 30 chars needs `|Δx| ≥ 218`, so it must span at least 2 lanes — put it between Client app (260) and Auth server (420), |Δx|=160 — **too tight**. Shorten to "Redirect (client_id + scope)" (28 chars, still over). Shorten further to "Redirect + client_id" (20 chars). Always verify every label against its span before finalizing.
## Centering inside the safe area
For N boxes of width `w` with gap `g`:
```
total = N × w + (N - 1) × g
offset = 40 + (600 - total) / 2
box[i].x = offset + i × (w + g)
```
Centered content feels deliberate. Left-aligned content feels incomplete.
## Sibling subsystem containers (2-up)
The structural subsystem-architecture pattern (see `structural.md` → "Subsystem architecture pattern") places **two sibling dashed-border containers** side by side, each holding a short internal flow. The 2-up layout sacrifices the default 40px horizontal safe margin in exchange for a usable container interior wide enough to hold 34 flowchart nodes.
Standard 2-up geometry at viewBox width 680:
```
container_w = 315 # each sibling
container_gap = 10 # space between siblings
left_margin = 20 # leaner than the usual 40
container_A.x = 20
container_B.x = 345 # left_margin + container_w + container_gap
rightmost edge = 345 + 315 = 660 # leaves 20px to x=680
interior_w = 315 40 = 275 # after 20px padding on each side
interior_A.x = 40
interior_B.x = 365
```
Inside each 275-wide interior, node widths follow the normal text-width formula but should cap at ~235 so the L-bend connectors have clear vertical channels on both sides. Typical nodes are 180 wide centered, or 150 wide for a 2-column row.
A **labeled cross-system arrow** bridges the 10px container gap:
```
from B_right_node.right_edge → to A_left_node.left_edge
arrow_x1 = interior_B.rightmost_node.x + 10
arrow_x2 = interior_A.leftmost_node.x 10
arrow_y = matching row y # both nodes on the same tier
label at (x_mid, arrow_y 6), class="ts", text-anchor="middle"
```
The cross-system arrow label is the one place where a flowchart-style connector *must* have a label — the reader cannot infer the relationship from the container titles alone. Keep the label to ≤3 words.
Dashed container borders use **inline `stroke-dasharray="4 4"`** on the `<rect>` rather than a CSS class — dashed is a one-off container-styling concern, not a reusable shape property, so the template's class list stays stable.
### Worked example — Pi session + Background analyzer
Two siblings, each with 3 internal nodes stacked vertically:
```
container A "Pi session" container B "Background analyzer"
x=20, y=40, w=315, h=260 x=345, y=40, w=315, h=260
rx=20, stroke-dasharray="4 4" same styling
Inside A (x_center = 177): Inside B (x_center = 502):
[ User input ] y=96 [ Analyze patterns ] y=96
[ Pi responds ] y=170 [ Write summary ] y=170
[ (session ends) ] y=244 [ Update memory ] y=244
Cross-system arrow: B top row → A top row at y=118
x1 = 347 (container B left edge + 2)? No — from interior node B₁ left edge
Actually: from B₁.x 10 (headed right-to-left pointing at A₁)
Details below in structural.md's worked example.
```
viewBox H for 3 stacked rows: last node bottom y = 244 + 44 = 288; container bottom 40 + 260 = 300; H = 300 + 20 = **320**.
## Sub-pattern coordinate tables
Fixed coordinate tables for the sub-patterns introduced in `structural.md`, `illustrative.md`, and `sequence.md`. Use these values verbatim — they're tuned so each sub-pattern respects the 680 viewBox and the 40 safe margin.
### Bus topology geometry
For `structural.md` → "Bus topology sub-pattern". A central horizontal bar bridges N agents above it and N agents below it.
| Element | Coordinates |
|----------------------------|------------------------------------------|
| Bus bar | `x=40 y=280 w=600 h=40 rx=20` |
| Bus label baseline | `y=304`, `text-anchor="middle"` at x=340 |
| Top agent row (box top) | `y=80`, `h=60` |
| Bottom agent row (box top) | `y=400`, `h=60` |
| Default viewBox H | 500 |
Agent centers by row count:
| Agents per row | Box width | Centers (x) |
|----------------|-----------|--------------------------------------------|
| 2 | 180 | 180, 500 |
| 3 | 140 | 170, 340, 510 |
| 4 | 110 | 120, 260, 420, 560 |
Publish/subscribe arrow pair: two vertical lines per agent, offset by 8px horizontally (one at `agent_cx 8`, one at `agent_cx + 8`). Publish goes down from agent to bar; Subscribe goes up from bar to agent. Labels sit at the channel midpoint y, `text-anchor="end"` (Publish on left) and `text-anchor="start"` (Subscribe on right).
### Radial star geometry (3 / 4 / 5 / 6 satellites)
For `structural.md` → "Radial star topology sub-pattern". A central hub surrounded by N peripheral satellites, each bidirectionally connected.
**Hub (always fixed):**
| Element | Coordinates |
|---------------|----------------------------|
| Hub rect | `x=260 y=280 w=160 h=80 rx=10` |
| Hub center | `(340, 320)` |
| viewBox H | 560 |
**Satellite positions:**
| N | Satellites (box top-left → w=160 h=60) |
|---|-----------------------------------------------------------------------------------|
| 3 | `(60, 120)`, `(460, 120)`, `(260, 460)` |
| 4 | `(60, 120)`, `(460, 120)`, `(60, 460)`, `(460, 460)` |
| 5 | `(260, 60)`, `(60, 200)`, `(460, 200)`, `(60, 460)`, `(460, 460)` |
| 6 | `(20, 120)`, `(260, 60)`, `(500, 120)`, `(20, 460)`, `(260, 520)`, `(500, 460)` |
Satellite centers: add `(80, 30)` to the box top-left to get `(cx, cy)`.
**Arrow pairs:** each satellite connects to the hub with two single-headed arrows offset by 8 px perpendicular to the arrow direction. For a satellite at `(sx, sy)` and hub center `(340, 320)`, compute the direction vector, normalize to unit length, then offset each line by `(+4dy, 4dx)` and `(4dy, +4dx)` respectively (where `(dx, dy)` is the unit direction).
For straightforward placement, use these pre-computed endpoint offsets for N=4:
| Satellite center | Outbound start (satellite → hub) | Outbound end |
|------------------|----------------------------------|--------------|
| TL `(140, 150)` | `(224, 176)` | `(264, 276)` |
| TR `(540, 150)` | `(456, 176)` | `(416, 276)` |
| BL `(140, 490)` | `(224, 464)` | `(264, 364)` |
| BR `(540, 490)` | `(456, 464)` | `(416, 364)` |
Inbound (hub → satellite) is the reverse of each outbound, offset perpendicular by 8.
### Spectrum geometry
For `illustrative.md` → "Spectrum / continuum". A 1-D axis with end labels, tick points, option boxes, and italic captions.
**Fixed vertical positions:**
| Element | Coordinates |
|---------------------------|--------------------------------------------|
| Eyebrow (optional) | `y=50`, `text-anchor="middle"` at x=340 |
| End labels (L / R) | `y=120`, at `x=80` (start) / `x=600` (end) |
| Axis line | `x1=80 y1=140 x2=600 y2=140` |
| Tick circles | `cy=140`, `r=6` |
| Option box top | `y=200`, `h=60` |
| Caption line 1 | `y=292`, italic `ts` |
| Caption line 2 | `y=308`, italic `ts` |
| Default viewBox H | 332 |
**Tick and option-box x positions by tick count:**
| Ticks | Tick centers (x) | Option box x (w=120) |
|-------|-----------------------------|-----------------------------|
| 2 | 200, 480 | 140, 420 |
| 3 | 160, 340, 520 | 100, 280, 460 |
| 4 | 140, 280, 420, 560 | 80, 220, 360, 500 |
| 5 | 120, 240, 360, 480, 600 (w=100) | 70, 190, 310, 430, 550 |
Axis uses `marker-start` **and** `marker-end` (both ends arrowed to signal no natural direction). Axis stroke class is `arr` (neutral gray) — never a color ramp.
Sweet-spot tick and its option box use `c-green` or `c-amber`; all other ticks and boxes stay `c-gray`. Captions cap at 24 characters per line, 2 lines per option.
### Parallel rounds geometry
For `sequence.md` → "Parallel independent rounds". Stacked independent call/response rounds without shared lifelines.
**Stacked rounds variant (full-width):**
| Element | Coordinates |
|----------------------|----------------------------------------|
| Source actor | `x=60 y=120 w=120 h=60` |
| Round k action box | `x=340 y=100 + (k-1)×80 w=160 h=48` |
| Round k call arrow | `y = 124 + (k-1)×80` |
| Round k response | `y = 134 + (k-1)×80` |
| Call label | `y = 115 + (k-1)×80` |
| Response label | `y = 145 + (k-1)×80` |
| Row pitch | 80 |
Arrow x endpoints: `x1 = source_right_edge + 6 = 186`, `x2 = action_left_edge 6 = 334` (going right); reverse for the return arrow.
**Script-wrapper variant:**
| Element | Coordinates |
|----------------------|----------------------------------------|
| Source actor | `x=60 y=120 w=120 h=60` |
| Script wrapper | `x=240 y=100 w=140 h=260 rx=6` |
| `{ }` label | `(310, 124)`, class `th` |
| Divider line | `x1=256 y1=140 x2=364 y2=140` |
| Wrapped band k | `x=252 y=152 + (k-1)×60 w=116 h=48` |
| External action box | `x=440 y=200 w=160 h=48` (optional) |
| Default viewBox H | 380 |
Up to 3 wrapped bands inside the script wrapper (with `script_h = 260`). Grow `script_h` by 60 for each additional band.
**Inside a 315-wide subsystem container** (half-width), scale the coordinates:
| Element | Container A (x=20) |
|--------------------|---------------------------------|
| Source actor | `x=40 y=120 w=100 h=50` |
| Round k action | `x=200 y=104 + (k-1)×64 w=120 h=40` |
| Row pitch | 64 |
### Multi-line box body line heights
For `structural.md` → "Multi-line box body". A three-line box used for advisor-role labels: title + italic role + meta.
| Line | y-offset from `rect_y` | Class |
|------------|--------------------------|---------------|
| Title | `+22` | `th` |
| Role | `+42` | `ts` + italic |
| Meta | `+62` | `ts` muted |
| Min h | 80 | |
Row pitch is 20. For a box at y=140, lines sit at `162, 182, 202`. Box height never drops below 80 — if the role or meta line is absent, use a standard 56-tall two-line box instead, don't shrink a three-line box.
### Annotation circle on connector geometry
For `illustrative.md` → "Annotation circle on connector". A labeled circle sitting above a pair of bidirectional arrows between two subjects.
| Element | Coordinates |
|-----------------------|----------------------------------------------|
| Subject A box | `x=80 y=160 w=180 h=56` |
| Subject B box | `x=440 y=160 w=180 h=56` |
| A → B arrow | `(266, 184) → (434, 184)`, `arr` |
| B → A arrow | `(434, 204) → (266, 204)`, `arr` |
| Arrow pair y midpoint | 194 |
| Annotation circle | outer `c="box"` r=30 at `(cx, cy) = (350, 150)` |
| Inner pill | `x=cx28 y=cy+12 w=56 h=20 rx=10` (uses ramp)|
| Connector line | `(cx, cy+30) → (cx, 194)`, `arr` (no marker) |
Label goes inside the pill at `(cx, cy+26)`, `th`, centered. Subject A/B labels use `th` at `(subject_cx, subject_cy)`.
### Container loop geometry (simple flowchart)
For `flowchart.md` → "Loop container". An outer rounded rect framing a simple flowchart.
| Element | Coordinates |
|--------------------|--------------------------------------------|
| Container rect | `x=20 y=40 w=640 h=H60 rx=20`, class `box`|
| Title | `(340, 72)`, class `th` |
| Subtitle | `(340, 92)`, class `ts` |
| First inner box y | ≥ 116 |
| Inner safe area | `x ∈ [40, 620]` |
| Bottom padding | 20px |
After placing the inner flow, compute `inner_bottom = max y of any inner element`, then `H = inner_bottom + 40` and `container_h = H 60`.
## Arrow routing
Every arrow has a start point (source box edge) and an end point (target box edge), with an optional bend in between.
**Direct arrow** — when source and target are aligned on an axis (same x for vertical, same y for horizontal):
```svg
<line x1="200" y1="76" x2="200" y2="120" class="arr" marker-end="url(#arrow)"/>
```
Leave **10px** between the arrow's endpoint and the target box's top edge so the arrowhead doesn't touch the border.
**L-bend arrow** — when the direct line would cross another box:
```svg
<path d="M x1 y1 L x1 ymid L x2 ymid L x2 y2" class="arr" fill="none" marker-end="url(#arrow)"/>
```
- `ymid` is a horizontal "channel" chosen to thread cleanly between the two levels
- Always include `fill="none"` on `<path>` used as a connector — SVG defaults to black fill
**Collision check.** Before finalizing every arrow, trace its path against every rect you've already placed:
```
for each rect R in the diagram:
if rect R is not the source or target of this arrow:
does the arrow's line segment intersect the interior of R?
if yes: use an L-bend to route around R
```
This is the #1 diagram failure mode. Arrows slashing through unrelated boxes.
**Connection-point convention.** Every arrow anchors to the midpoint of a box edge (top, bottom, left, or right), never to a corner. With `rx="6"` or `rx="12"` rounded corners, the actual corner curve occupies the first ~612px of each edge — so stay **≥20px from any corner** when picking a connection point. An arrow that enters a box 4px from its corner reads as "touching the rounded curve" instead of "attached to the edge", and the arrowhead looks smeared. For a 180-wide rect, valid top-edge connection points sit at `x ∈ [rect_x + 20, rect_x + 160]`; the outer 20px on each side belong to the corner radius.
**Multi-arrow stagger.** When two or more arrows terminate on the same edge of the same box from different sources (three fan-in arrows hitting a single aggregator; two feedback lines returning to a start node), stagger their arrival points by **≥12px** along the target edge. Example: three arrows fanning into the top edge of a 180-wide box sit at `target_x 24`, `target_x`, `target_x + 24`. Same rule applies to horizontal arrows converging on a left/right edge (stagger the y by ≥12px). Without the stagger, the arrowheads stack on top of each other and the reader can't tell how many incoming edges there are — a 3-to-1 fan-in reads as a single thick arrow.
## text-anchor safety
`text-anchor` controls which point of the text aligns to the `x` coordinate:
- `"start"` — x is the left edge. Text extends right.
- `"middle"` — x is the horizontal center. Text extends both ways.
- `"end"` — x is the right edge. Text extends left.
**Danger**: `text-anchor="end"` at low x values. If `x=50` and the label is 200px wide, the text starts at `x = -150` — outside the viewBox. Check: `label_chars × 8 < x` must hold for `text-anchor="end"` labels.
**Default to `text-anchor="start"` on the left side and `"middle"` in the center.** Use `"end"` only when you've verified the x coordinate is high enough.
## Vertical text centering inside a rect
Every `<text>` inside a rect needs `dominant-baseline="central"`. Without it, SVG treats `y` as the baseline — the glyph body sits ~4px above where you think and descenders hit the next line.
```svg
<rect x="100" y="20" width="180" height="44" rx="6" class="c-blue"/>
<text class="th" x="190" y="42" text-anchor="middle" dominant-baseline="central">Login</text>
```
For a rect at `(x, y, w, h)`:
- Single line centered: `text_x = x + w/2`, `text_y = y + h/2`, `dominant-baseline="central"`
- Two lines (44 + 14 layout inside a 56-tall box):
- Title: `text_y = y + 20` (center of top 40px)
- Subtitle: `text_y = y + 40` (center of bottom 16px)
- Both use `dominant-baseline="central"`
## Quick-reference sizes
Standard dimensions that work well and keep the diagram rhythm consistent:
| Element | Size |
|-----------------------------|----------------------|
| Single-line node height | 44 px |
| Two-line node height | 56 px |
| Default node width | 180 px (adjust up) |
| Minimum gap between nodes | 20 px horizontal, 60 px vertical |
| Container padding | 20 px |
| Rect corner radius | `rx="6"` (subtle), `rx="12"` (container), `rx="20"` (outer container) |
| Connector stroke width | 1.5 px (set by `.arr`) |
| Diagram border stroke | 0.5 px |
| Viewport safe margin | 40 px on each edge |
Stick to these unless you have a concrete reason to deviate.
@@ -0,0 +1,38 @@
# AI pattern catalog
Pre-planned diagram starters for recurring multi-agent coordination shapes — research orchestrators, message buses, shared-state stores, agent-with-skills composition. Each file here is a thin wrapper around one specific pattern: a one-line description, the diagram type baoyu prefers for it, the ramp palette that works, a reference mermaid block (industry-standard shorthand you can sanity-check against), and a pre-cooked baoyu SVG plan that saves you a planning pass.
## How to use this directory
1. **Check the index below** for a pattern name matching the user's topic. Exact matches are rare — usually the user says *"agents coordinating through a shared channel"* and you recognize *message-bus*, or *"agents building on each other's findings in a store"* and you recognize *shared-state*.
2. **If a pattern matches**, open its file and read end-to-end. The mermaid block tells you *what* to draw (structurally), the baoyu SVG plan tells you *how* (coordinates, widths, arrow routing).
3. **If no pattern matches**, fall back to the normal Step 4 planning flow in `SKILL.md`. Do not force a near-miss — two coordination patterns that share a surface name often have different topologies (message bus ≠ shared state, even though both put a central element between agents).
The mermaid reference is **authoritative for structure**, not for rendering. Never emit mermaid as the final output; always convert to a hand-written baoyu SVG using the plan in the same file.
## Scope
This directory covers **AI-system topologies**, not generic software patterns. For flowchart / sequence / structural / illustrative / class diagram techniques, stay in the top-level references files. If an AI-system pattern needs a technique that isn't documented in those files yet, add the technique upstream — not here.
## Index
| Pattern | Default type | One-line hook |
|--------------------------|-----------------|-----------------------------------------------------------------------------------------------------|
| [multi-agent-research](multi-agent-research.md) | flowchart | Lead agent + memory sidecar + parallel search subagents (each looping) + citation stage (Anthropic) |
| [message-bus](message-bus.md) | structural | N agents coordinate via a central publish/subscribe bar — no direct agent-to-agent edges |
| [shared-state](shared-state.md) | structural | N peer agents read/write a central store — no orchestrator, findings immediately visible to all |
| [agent-skills](agent-skills.md) | structural | Agent loop + runtime + MCP servers (left) + skills library on filesystem (right) — composition view |
| [contextual-retrieval](contextual-retrieval.md) | flowchart | Contextualizer LLM prepends 50100 tokens to each chunk → dual-track (embedding + BM25) + rank fusion |
## Adding a new pattern
Keep each file under ~80 lines. A pattern file has six sections in this order:
1. **Name + 1-line description**
2. **Default diagram type** — plus when to pick an alternate type
3. **Palette** — which ramps, tied to which roles
4. **Sub-pattern** — the specific section in a top-level reference file that does the heavy lifting
5. **Mermaid reference** — the canonical industry-standard sketch, in a ` ```mermaid` block
6. **Baoyu SVG plan** — node list with widths, arrow list, viewBox dimensions, any gotchas
When you add a new pattern, update this README's index table in the same commit. Do not create orphan files — if you can't write a one-line hook for the index, the pattern isn't well-defined yet.
@@ -0,0 +1,92 @@
# Agent with skills
**One-line description.** The architectural snapshot of a general-purpose agent composed of four layers — **agent loop** (reasoning), **agent runtime** (code + filesystem), **MCP servers** (outbound connectors to external tools and data), and a **skills library** (local, progressively-disclosed domain expertise on the filesystem). This is the "Skills: the complete picture" diagram from Anthropic's skills blog post — the shape that explains *why you stop building specialized agents and start shipping skills to one general agent*. It is a **system composition** diagram, not a workflow: it answers "what the agent is", not "what it does next".
## Default diagram type
**Structural — central hub with bilateral satellite groups.** Single agent box in the middle with a visible interior loop glyph; MCP servers stacked vertically on the **left**; skills stacked vertically inside a **filesystem container** on the **right**. The left/right split is the point: *left is network-reachable tools, right is on-disk expertise*.
Alternate types:
- **Before/after poster flowchart** (two stacked frames, per `flowchart.md` → "Poster flowchart") when illustrating the evolution from specialized-per-domain agents → general agent + skills. This is Anthropic's Figure 1 / Figure 2 shape.
- **Flowchart with a loop container** when the user wants to show activation order (loop → read skill → call MCP → write file → loop). The structural snapshot loses sequencing; the flowchart gains it.
## Palette
Three role ramps + gray. This is a structural diagram where the two satellite groups must be visually distinct:
- **`c-gray`** — filesystem container, title bar, legend, arrow labels.
- **`c-teal`** — agent (central hub). Teal anchors the LLM/reasoning role.
- **`c-purple`** — MCP servers. Shared across all three (homogeneous satellite group — instances of one role do not get distinct colors).
- **`c-coral`** — skills. Shared across all three; coral reads as Anthropic's own skills brand-orange and sits opposite the MCP group.
This is a **category coloring**, not a rainbow: one ramp per satellite *group*, not per satellite. The structural radial-star rule in `structural.md` ("satellites stay neutral gray") is deliberately overridden here because we have **two distinct kinds of satellite** that the reader must tell apart at a glance.
Legend is required.
## Sub-pattern
`structural.md`**Radial star topology** as the base (hub with satellites, bidirectional arrows), extended to an **asymmetric two-group** variant: left group is a loose stack (no container), right group is wrapped in a `structural.md`**Container box** to show the filesystem boundary. The agent's interior loop uses `glyphs.md`**terminal-icon** plus a hand-drawn circular arrow pair around it (the "reason · act" cycle) — this is what distinguishes the agent visually from its satellites.
## Mermaid reference
```mermaid
flowchart LR
subgraph MCP
M1[MCP server 1]
M2[MCP server 2]
M3[MCP server 3]
end
A[Agent<br/>reason · runtime]
subgraph Filesystem
S1[Skill A]
S2[Skill B]
S3[Skill C]
end
M1 <--> A
M2 <--> A
M3 <--> A
A <--> S1
A <--> S2
A <--> S3
A -. reason · act loop .-> A
```
Two subgraphs flanking a central hub plus a self-loop on the hub is the defining shape. Drop either subgraph and the pattern collapses into something else — a plain tool-calling loop (if you drop skills) or a read-only retrieval shape (if you drop MCP).
## Baoyu SVG plan
Central agent with an interior loop glyph; three MCP servers stacked on the left; three skills stacked inside a filesystem container on the right.
- **viewBox**: `0 0 820 460`
- **Agent (hub)**`c-teal`, `x=310 y=110 w=200 h=240`, large central box:
- Title *Agent* at `(410, 140)` class `th`.
- Interior loop glyph centered at `(410, 230)`: a `terminal-icon` at `(398, 218)` (24×24 from `glyphs.md`), with two curved arrows forming a circle around it — `path d="M 370 230 A 40 40 0 1 1 450 230" class="arr" marker-end="url(#arrow)"` plus the mirror arc below. This is the reason-act loop made visible.
- Subtitle *reason · runtime* at `(410, 310)` class `ts`.
- **MCP server stack** (3 boxes, `c-purple`, single-line title, same size):
- *MCP server 1*, `x=60 y=140 w=170 h=52`.
- *MCP server 2*, `x=60 y=210 w=170 h=52`.
- *MCP server 3*, `x=60 y=280 w=170 h=52`.
- **Filesystem container**`rect x=570 y=100 w=220 h=260 rx=16` class `box`, title *Filesystem* at `(680, 128)` class `th`, centered.
- **Skills stack** inside the filesystem (3 boxes, `c-coral`, single-line title, same size):
- *Skill A*, `x=600 y=150 w=160 h=52`.
- *Skill B*, `x=600 y=216 w=160 h=52`.
- *Skill C*, `x=600 y=282 w=160 h=52`.
**Arrow plan.** Six bidirectional pairs, three per side. Each pair uses two single-headed arrows offset 8px perpendicular to direction (same rule as `structural.md` → "Radial star → Arrow pairs"):
- MCP server *n* ↔ Agent: short horizontal channel from `(230, y_center)` to `(310, y_center)` and back, where `y_center ∈ {166, 236, 306}`. Both solid `arr`.
- Agent ↔ Skill *n*: short horizontal channel from `(510, y_center)` to `(600, y_center)` and back, where `y_center ∈ {176, 242, 308}`. Arrows cross the filesystem container edge — that crossing is semantically important and must not be hidden.
No external self-loop arc on the agent — the interior loop glyph (`terminal-icon` + circular arrows) already carries that meaning, and an exterior arc would collide with the MCP/skills channels.
**Legend** (bottom, required):
```
[■] Agent [■] MCP server [■] Skill [▭] Filesystem [↔] bidirectional channel
```
**Gotchas.**
- Never color the 3 MCP servers differently from each other, nor the 3 skills. Each group is a homogeneous tier; per-item coloring turns an architecture diagram into a role diagram.
- Keep the filesystem container around the skills. Dropping it makes skills look like peers of MCP servers and erases the "local, progressively disclosed from disk" property that is the whole reason skills are not MCP servers.
- Convention: **MCP on the left, skills on the right**, matching Anthropic's own materials. Flipping the sides loses a free point of recognition.
- If the user wants to show **progressive disclosure** (metadata → SKILL.md → references/), add a nested three-tier rect *inside each skill box* — that is an extension of this pattern, not an alternate type.
@@ -0,0 +1,98 @@
# Contextual retrieval
**One-line description.** Anthropic's preprocessing recipe for RAG: before chunks are embedded and indexed, an LLM (the *contextualizer*) reads the whole document together with each chunk and emits 50100 tokens of situating context that gets prepended to the chunk. The contextualized chunk then feeds **both** a semantic index (embedding model → vector DB) and a lexical index (TF-IDF → BM25). At runtime the query hits both indices, results merge through rank fusion, and the top-K chunks go to the generative model. The diagram's job is to show the contextualizer as the distinctive new step and the dual-track preprocessing it feeds.
## Default diagram type
**Flowchart (poster style) with two stacked phases.** The pattern has a name, a clear preprocessing / runtime split, a fan-out into parallel tracks, and a distinctive new step — that's poster flowchart territory. A flat linear chart would smear the two phases and hide what's new. Stack the phases vertically with eyebrow dividers; each phase reads left-to-right.
Alternate types:
- **Structural — subsystem containers side by side** when contrasting contextual retrieval against plain RAG (two siblings, each a mini pipeline). See `structural.md` → "Rich interior for subsystem containers".
- **Preprocessing-only flowchart** when the runtime story isn't needed — drop phase 2 and end at the two indices.
## Palette
Three accent ramps plus gray, under the poster-flowchart 4-ramp exception (ramps encode role *categories*, not sequence):
- **`c-gray`** — corpus, query, rank fusion, top-K chunks, response. Neutral data / IO.
- **`c-purple`** — Claude in both its roles: contextualizer and generative model. One ramp for both anchors the "same Claude, two prompts" story without adding a fourth color.
- **`c-teal`** — semantic track (embedding model + vector DB).
- **`c-amber`** — lexical track (TF-IDF + BM25 index).
Do **not** color the contextualizer and generative model differently — doing so implies different models or different roles, but the whole point is the same Claude doing both jobs.
## Sub-pattern
`flowchart.md`**Poster flowchart pattern** (eyebrow-divided phases, ≤4 ramps for role categories) + **Fan-out + aggregator (simple mode)** applied twice: the contextualizer splits into two tracks that never reconverge in phase 1, and query + both indices converge at rank fusion in phase 2.
## Mermaid reference
```mermaid
flowchart TB
subgraph Preprocessing
C[Corpus] -- chunks --> CTX[Contextualizer · Claude]
CTX -- context + chunk --> EM[Embedding model]
CTX -- context + chunk --> TF[TF-IDF]
EM --> VDB[(Vector DB)]
TF --> BM[(BM25 index)]
end
subgraph Runtime
Q[User query] --> RF[Rank fusion]
VDB --> RF
BM --> RF
RF --> TK[Top-K chunks] --> GM[Generative model · Claude] --> R[Response]
end
```
Defining edges: `CTX --> EM` *and* `CTX --> TF` (the contextualized chunk goes to both tracks) plus `VDB --> RF` *and* `BM --> RF` (both indices feed fusion). Drop either pair and the diagram collapses into plain RAG or embedding-only retrieval.
## Baoyu SVG plan
Two stacked phases with eyebrow labels and a thin horizontal divider between them.
- **viewBox**: `0 0 680 540`
- **Phase 1 eyebrow***Preprocessing · Runs once per corpus update* at `(40, 50)`, class `eyebrow`.
Phase 1 interior:
- **Corpus**`c-gray`, `x=40 y=80 w=100 h=56`, two-line (*Corpus*, *Documents*).
- **Contextualizer**`c-purple`, `x=180 y=72 w=260 h=72`, multi-line (*Contextualizer*, *Claude*, *50100 tokens per chunk*). Visibly the largest box — it's the pattern's signature step.
- **Embedding model**`c-teal`, `x=140 y=180 w=160 h=48`, single-line.
- **TF-IDF**`c-amber`, `x=380 y=180 w=160 h=48`, single-line.
- **Vector DB**`c-teal`, `x=140 y=260 w=160 h=56`, two-line (*Vector DB*, *Semantic index*).
- **BM25 index**`c-amber`, `x=380 y=260 w=160 h=56`, two-line (*BM25 index*, *Lexical index*).
**Phase 1 arrows:**
- *Corpus → Contextualizer*: `(140, 108) → (180, 108)`, label *chunks* at `(160, 102)`.
- *Contextualizer → Embedding model*: L-bend `(260, 144) → (260, 160) → (220, 160) → (220, 180)`, label *context + chunk* at `(170, 164)` `text-anchor="end"`.
- *Contextualizer → TF-IDF*: L-bend `(360, 144) → (360, 160) → (460, 160) → (460, 180)`, label *context + chunk* at `(470, 164)` `text-anchor="start"`. (Both arrows labeled — the reader must see that *both* tracks receive the contextualized chunk.)
- *Embedding model → Vector DB*: straight vertical `(220, 228) → (220, 260)`.
- *TF-IDF → BM25 index*: straight vertical `(460, 228) → (460, 260)`.
- **Phase divider** — dashed line `x1=40 y1=340 x2=640 y2=340`, class `arr-alt`.
- **Phase 2 eyebrow***Runtime · Per user query* at `(40, 362)`, class `eyebrow`.
Phase 2 interior (single horizontal row at y=400456):
- *User query* `c-gray` `x=40 w=100`, *Rank fusion* `c-gray` `x=160 w=100`, *Top-K chunks* `c-gray` `x=280 w=100` (two-line with subtitle *Top 20*), *Generative model* `c-purple` `x=400 w=140` (two-line with subtitle *Claude*), *Response* `c-gray` `x=560 w=80`. All `y=400 h=56`.
**Phase 2 arrows** (straight horizontal, 20px gaps between boxes at y=428): query→fusion, fusion→top-K, top-K→generator, generator→response.
**Cross-phase arrows** (indices into rank fusion):
- *Vector DB → Rank fusion*: vertical drop `(200, 316) → (200, 400)` — lands inside rank fusion's top edge (x=160260).
- *BM25 index → Rank fusion*: L-bend `(460, 316) → (460, 372) → (220, 372) → (220, 400)`. The 20px x-offset from the Vector DB arrow keeps the two inbound arrows from stacking.
Both cross-phase arrows are solid `.arr` — they're the main data flow, nothing alternate.
**Legend** (bottom, required — 3 accent ramps encode category):
```
[■] Claude (contextualizer + generator) [■] Semantic track [■] Lexical track
```
Place at `y=510`, centered at `x=340`.
**Gotchas.**
- Both tracks must show they receive the *contextualized* chunk — label both outgoing arrows from the contextualizer. If only one is labeled, readers assume the other track still uses raw chunks.
- Do not draw the contextualizer as a self-loop on the Corpus. It's a distinct LLM step that runs once per chunk with whole doc + chunk as input, conceptually closer to an orchestrator than an inline transform.
- Keep rank fusion gray, not amber — it merges two tracks but it's a structural aggregator, not an accent role. Giving it amber visually absorbs it into the lexical track.
**Reranker variant.** The reranking extension inserts a **reranker** box between *Rank fusion* and *Top-K chunks*. Insert `Reranker` at `x=280 y=400 w=120 h=56` (shift Top-K, generator, response right by 140 and widen the viewBox to 820). Annotate the reranker's input arrow with *top 150* and its output with *top 20* — the winnowing ratio is the whole point.
@@ -0,0 +1,73 @@
# Message bus
**One-line description.** N agents coordinate through a shared publish/subscribe channel rather than talking to each other directly. Each agent subscribes to the topics it cares about and publishes events others may handle. Unlike orchestrator-subagent (central router) or shared-state (central store), the bus carries *events in flight* — agents react to what's happening, not to what's been accumulated. Canonical use cases: event-driven pipelines, security-ops triage → investigation → response, growing agent ecosystems where new capabilities plug in without rewiring.
## Default diagram type
**Structural — bus topology.** The defining visual is a central horizontal bar with agents fanning out above and below, each linked by a pair of offset arrows (publish down, subscribe up). A flowchart would force one specific event sequence, but the whole point of a bus is that the workflow emerges from events; a structural diagram shows the coordination shape without committing to a single path.
Alternate types:
- **Sequence** when the user wants to show one specific event cascade (alert arrives → triage classifies → network agent investigates → response agent acts) with explicit ordering. Use 45 lifelines, not the bus geometry.
- **Flowchart** only if the pipeline really is fixed, in which case it's not a message bus — it's just a linear workflow.
## Palette
- **`c-gray`** — the event source / external input (the thing that only publishes, never subscribes). Neutral because it's outside the coordinated agent set.
- **`c-teal`** — the agent role for all subscribed agents. One shared ramp because every agent on the bus is a peer; coloring them differently implies a hierarchy that the pattern explicitly rejects.
- **`c-amber`** — the bus bar itself. Amber is the convention for "the shared channel everyone looks at" per `structural.md` → "Bus topology sub-pattern".
Do **not** rainbow the agents by role (network / identity / response / enrichment → four different ramps). The reader should feel the agents are interchangeable peers that differ only in what topics they subscribe to, not in what kind of thing they are.
## Sub-pattern
`structural.md`**Bus topology sub-pattern** + `glyphs.md`**Publish/subscribe arrow pair**. This pattern is the flagship use case for both; the bus topology section is written with this diagram in mind and `layout-math.md` → "Bus topology geometry" has the fixed coordinates.
## Mermaid reference
```mermaid
flowchart TD
S[Alert source] -- publish --> B[[Message bus]]
B -- subscribe --> T[Triage agent]
T -- publish --> B
B -- subscribe --> E[Enrichment agent]
E -- publish --> B
B -- subscribe --> N[Network agent]
B -- subscribe --> I[Identity agent]
B -- subscribe --> R[Response agent]
```
The `[[bus]]` notation stands in for a central bar — mermaid can't draw the real geometry. What matters structurally is that every agent talks only to the bus, never agent-to-agent, and that most agents both publish *and* subscribe (the source is the exception).
## Baoyu SVG plan
Bus bar centered horizontally; 3 agents on top, 3 agents on bottom. Uses the Anthropic security-ops example labels verbatim — swap them for the user's domain when adapting.
- **viewBox**: `0 0 680 500`
- **Bus bar**`c-amber`, `x=40 y=280 w=600 h=40 rx=20`. Label *Message bus (publish/subscribe)* at `(340, 304)`, class `th`, centered.
- **Top row** (3 boxes, centers at `x = 170, 340, 510`, `w=140 h=60`, `y=80`, two-line):
- *Alert source*, **`c-gray`**, subtitle *External events* — the only pure publisher. Mark it gray to distance it from the coordinated agent set.
- *Triage agent*, `c-teal`, subtitle *Classifies severity*.
- *Enrichment agent*, `c-teal`, subtitle *Gathers context*.
- **Bottom row** (same centers, `y=400`, `h=60`):
- *Network agent*, `c-teal`, subtitle *Investigates traffic*.
- *Identity agent*, `c-teal`, subtitle *Checks credentials*.
- *Response agent*, `c-teal`, subtitle *Triggers actions*.
**Publish/subscribe arrow pairs** (use the glyph template verbatim, 8px offset):
- For each agent centered at `agent_cx`, with top agents at `agent_y_bottom=140` and the bus top at `bar_y_top=280`, draw two vertical lines:
- Publish: `(agent_cx 8, 140) → (agent_cx 8, 280)` with arrowhead.
- Subscribe: `(agent_cx + 8, 280) → (agent_cx + 8, 140)` with arrowhead.
- For bottom agents, `agent_y_top=400`, `bar_y_bottom=320`, mirror: Publish goes down from agent to bus, Subscribe goes up from bus to agent. (Yes — publish on a bottom agent still goes *out of* the agent toward the bus, which is visually upward.)
- **Gotcha — Alert source exception.** Alert source is a pure publisher; draw only its Publish arrow (`(162, 140) → (162, 280)`) and omit the Subscribe return. Do *not* draw a subscribe arrow with no label, and do not put a "(source)" parenthetical in the subtitle — the gray ramp + missing return arrow is the signal.
- **Labels.** Only label the Publish/Subscribe arrows for one representative agent (e.g., Triage), not all six. With six pairs on one diagram, labeling every pair becomes text soup — a single labeled example plus the legend below is enough.
**Legend.** Required because the two arrow directions encode distinct semantics and the color-off source agent needs a key:
```
[↓] Publish [↑] Subscribe [■] Event source [■] Subscribed agent [■] Bus
```
Place at `y=480`, `text-anchor="middle"` at `x=340`.
**When to drop to 2+2 or go up to 4+4.** The 3+3 layout is the sweet spot. With 2 agents per row use `w=180` centered at `x=180, 500`. With 4 per row use `w=110` centered at `x=120, 260, 420, 560` and drop the Publish/Subscribe *labels* entirely — four pairs plus labels per row is too dense. Beyond 8 total agents, the diagram is telling you the ecosystem has outgrown a single-canvas structural view; consider grouping agents by topic or splitting into two diagrams.
@@ -0,0 +1,84 @@
# Multi-agent research
**One-line description.** A lead agent plans a research task, persists its plan to a memory sidecar, spawns a row of parallel search subagents (each running its own search-and-think loop over a different aspect of the question), synthesizes their findings, then hands the synthesized draft to a dedicated citation subagent that attributes sources before the final report goes back to the user. This is Anthropic's Research-feature shape. The parts that distinguish it from a plain orchestrator fan-out are the **memory sidecar**, the **per-subagent iteration loop**, and the **post-processing citation stage**.
## Default diagram type
**Structural flowchart — central orchestrator with two flanking peers plus a subagent row.** The topology has one big star (the lead agent) with a memory store on one side and a citation subagent on the other, and a row of interchangeable search subagents underneath. A plain fan-out misses memory; a vertical queue-backed worker pool misses the pre/post peers. Draw the lead agent large and central, flank it with memory + citations, and put search subagents in a horizontal row below.
Alternate types:
- **Sequence** when the user wants to show turn order — `LeadResearcher → Memory (save plan) → Subagent1/2 (parallel dispatch) → LeadResearcher (synthesize) → CitationAgent → User`. This is the shape of the process diagram in Anthropic's own post.
## Palette
Four role ramps (at the `design-system.md` limit for multi-agent diagrams):
- **`c-gray`** — user box, final report, structural labels.
- **`c-teal`** — lead agent / orchestrator. The primary role anchors the strongest color.
- **`c-purple`** — search subagents, **all the same color**. Instances of one role share a ramp; they are interchangeable workers, not distinct actors.
- **`c-coral`** — citation subagent. Distinct from the search pool because it is a different specialist running at a different stage.
- **`c-amber`** — memory store. Amber is the standing convention for a retriever/store sidecar, which also prevents readers from mistaking memory for a third agent role.
Legend is required — three distinct non-gray role ramps plus the store color.
## Sub-pattern
`flowchart.md`**Fan-out + aggregator (simple mode)** for the lead ↔ subagents channel, plus `flowchart.md`**Self-loops** (borrowed from the state-machine section) on each search subagent to show its internal search/think iteration. The flanking peers (memory, citation) are **bidirectional satellites** off the lead agent — not part of the fan-out.
## Mermaid reference
```mermaid
flowchart TB
U[User query] --> L[Lead agent<br/>orchestrator]
L <--> M[(Memory<br/>plan + context)]
L <--> C[Citation subagent]
L --> S1[Search subagent A]
L --> S2[Search subagent B]
L --> S3[Search subagent C]
S1 --> L
S2 --> L
S3 --> L
S1 -. search + think .-> S1
S2 -. search + think .-> S2
S3 -. search + think .-> S3
L --> R[Final report]
R --> U
```
The distinctive edges vs. a plain orchestrator fan-out: the bidirectional `L <--> M` sidecar, the `L <--> C` post-processor, and the three self-loops on the search subagents.
## Baoyu SVG plan
Central lead agent with two flanking peers on the top row and three parallel search subagents in a row below. User box on the far left.
- **viewBox**: `0 0 820 460`
- **User**`c-gray`, `x=30 y=150 w=120 h=64`, two-line (*User*, *Submits query*).
- **Lead agent**`c-teal`, `x=310 y=90 w=260 h=180`, multi-line block:
- Title *Lead agent* at `(440, 120)` class `th`.
- Subtitle *(orchestrator)* at `(440, 140)` class `ts`.
- Tool stack at y=178, 198, 218, 238, class `ts`, centered: *Tools:*, *search · MCP · memory*, *run_subagent*, *complete_task*.
- **Citations subagent**`c-coral`, `x=170 y=156 w=120 h=60`, two-line (*Citations*, *subagent*).
- **Memory**`c-amber`, `x=590 y=156 w=200 h=60`, two-line (*Memory*, *plan + context*).
- **Search subagent row** (3 workers, all `c-purple`, same size):
- *Search subagent A*, `x=200 y=340 w=160 h=64`, two-line (*Search subagent*, *Aspect A*).
- *Search subagent B*, `x=390 y=340 w=160 h=64`, two-line (*Search subagent*, *Aspect B*).
- *Search subagent C*, `x=580 y=340 w=160 h=64`, two-line (*Search subagent*, *Aspect C*).
**Arrow plan.**
- User ↔ Lead — stacked request/response pair: `user → lead` solid `arr` `M 150 174 L 310 174` labeled *query*; `lead → user` dashed `arr-alt` `M 310 198 L 150 198` labeled *final report*.
- Lead ↔ Citations — short bidirectional pair on lead's left edge: `M 290 180 L 310 180` (in), `M 310 204 L 290 204` (out). Both solid `arr`.
- Lead ↔ Memory — matching pair on lead's right edge: `M 570 180 L 590 180`, `M 590 204 L 570 204`.
- Lead → each subagent — vertical L-bends from lead's bottom edge `(y=270)` via a shared channel at `y=305`. Dispatch arrows anchor on lead at `(360, 270)`, `(470, 270)`, `(520, 270)` and land at each subagent's top-center `(280, 340)`, `(470, 340)`, `(660, 340)`. Middle arrow is straight; outer two L-bend through the channel.
- Subagent → Lead — matching return arrows offset 16px to the right of each dispatch arrow, using `arr-alt` to mark the return.
- **Self-loop on each search subagent** — per `flowchart.md` → Self-loops, a short arc off the right edge: `M {x+w} {y+16} C {x+w+24} {y+8}, {x+w+24} {y+h-8}, {x+w} {y+h-16}` class `arr`, with a `ts` label *search + think* at `({x+w+28}, {y+h/2})`. Repeat for all three subagents. This is the key visual that distinguishes research subagents from plain workers.
**Legend** (bottom, required):
```
[■] Lead agent [■] Search subagent [■] Citation subagent [■] Memory [──] dispatch [- -] return
```
**Gotchas.**
- Do not color the 3 search subagents differently — they are one pool, not three roles. Rainbow-ing them turns a homogeneous worker pool into a role fan-out and misrepresents the pattern.
- Keep memory amber even though it is a peer of lead — the store convention keeps readers from reading it as a third agent.
- The citation subagent runs *at the end* logically, but the architecture view draws it as a peer of the lead agent (not a downstream successor), matching Anthropic's own diagram. If the user asks for the turn-order view instead, switch to the sequence alternate.
@@ -0,0 +1,64 @@
# Shared state
**One-line description.** N peer agents coordinate by reading and writing a persistent shared store — database, filesystem, document — with no central orchestrator, router, or message bus between them. Each agent checks the store for relevant findings, acts on what it sees, and writes its own contributions back. Findings are immediately visible to every other agent; the store becomes an evolving knowledge base. Canonical use case: a research synthesis system where an academic-literature agent, industry-reports agent, patent agent, and news agent all build on each other's discoveries in real time.
## Default diagram type
**Structural — radial star.** The point of the pattern is *no central coordinator* — the hub is a passive store, not an active router. A radial star diagram puts the store in the center and the agents around it, with bidirectional read/write channels on every spoke. A flowchart would smuggle in an implied order; a bus topology would suggest events in flight rather than accumulated state.
Alternate types:
- **Illustrative** when the user wants a *cross-section* metaphor — concentric layers, store as a well, agents as drawers dipping in. Rarely the right call for production docs but occasionally useful for teaching the intuition.
- **Structural (subsystem)** when the user is contrasting shared-state with a different pattern (agent teams, message bus) — in that case use the two-sibling container layout and make this pattern's side a mini radial star inside the right container. See `structural.md` → "Rich interior for subsystem containers".
## Palette
- **`c-amber`** — the shared state hub. This is the one place in the diagram that "everybody is looking at," and amber is the documented convention for shared-state hubs per `structural.md` → "Radial star topology sub-pattern".
- **`c-gray`** — the peripheral satellite agents. They are peers doing the same *kind* of work (read + write), and the pattern's whole argument is that they're interchangeable. Giving each satellite its own ramp is rainbow coloring that implies a hierarchy that doesn't exist.
- **`c-teal`** — acceptable *instead of* gray for all satellites together (single ramp for "agent peer"), when the diagram needs to distinguish the agents from other gray scaffolding elsewhere on the canvas. Never mix gray and teal satellites in the same diagram — it looks like two tiers.
Never promote one satellite to a different ramp "to show the primary agent". If one agent really is primary, the topology isn't radial star — it's orchestrator-subagent or agent-teams.
## Sub-pattern
`structural.md`**Radial star topology sub-pattern**. The central hub carries a `doc-icon` glyph from `glyphs.md` → "Document & terminal icons" to signal it's a store (not just an abstract coordinator). `layout-math.md` → "Radial star geometry (3 / 4 / 5 / 6 satellites)" has the fixed coordinate table for N=3 through N=6.
## Mermaid reference
```mermaid
flowchart LR
A[Academic agent] <--> S[(Shared state store)]
I[Industry agent] <--> S
P[Patent agent] <--> S
N[News agent] <--> S
```
The defining shape is the bidirectional double-headed arrow between every satellite and the store, with *no arrows between satellites*. Any agent-to-agent edge turns the topology into a mesh and is a signal to switch patterns.
## Baoyu SVG plan
N=4 radial star with a doc-icon hub. Uses the Anthropic research-synthesis example labels verbatim — swap them for the user's domain.
- **viewBox**: `0 0 680 560`
- **Hub (shared state store)**`c-amber`, `x=260 y=280 w=160 h=80 rx=10`.
- Title *Shared state* at `(340, 302)`, `th`, centered.
- Subtitle *Database / filesystem / doc* at `(340, 320)`, `ts`, centered.
- `doc-icon` glyph at `translate(328, 328)` (bottom-center of hub rect). Copy the 5-line doc-icon path from `structural.md` → "Hub content" verbatim — it's the worked example for exactly this diagram.
- **Satellites** (4, all `c-gray`, `w=160 h=60`, two-line):
- *Academic agent*, `x=60 y=120`, subtitle *Literature search*.
- *Industry agent*, `x=460 y=120`, subtitle *Market reports*.
- *Patent agent*, `x=60 y=460`, subtitle *Patent filings*.
- *News agent*, `x=460 y=460`, subtitle *Current coverage*.
**Bidirectional arrow pairs** (use the pre-computed N=4 endpoints from `layout-math.md` → "Radial star geometry"):
- TL Academic: outbound `(224, 176) → (264, 276)`, inbound offset perpendicular by 8.
- TR Industry: outbound `(456, 176) → (416, 276)`, inbound offset.
- BL Patent: outbound `(224, 464) → (264, 364)`, inbound offset.
- BR News: outbound `(456, 464) → (416, 364)`, inbound offset.
- Label each pair with a single `ts` *Read / write* next to the satellite end (not between the two offset lines — the 8px gap is too narrow). For the top satellites, place the label just below the satellite box at `y ≈ 198`. For the bottom satellites, just above at `y ≈ 448`.
**Centered banner for termination rule.** Shared-state systems cycle indefinitely without an explicit termination condition. Drop a small centered `ts` caption at the top of the canvas — `y=60`, `text-anchor="middle"` at `x=340` — naming the rule the system uses: *Until convergence (no new findings for N cycles)*, *Until time budget exhausted*, or *Until a designated terminator agent signals done*. This is not ornamental — a shared-state diagram without a termination line misrepresents the pattern. See the blog's "reactive loops" failure mode.
**Legend.** Not needed — the single accent color on the hub and the shared gray on satellites self-document. If you used `c-teal` satellites instead of gray, still no legend: one ramp on all peers means "they're all the same role", which is the whole message.
**When to use N≠4.** Stick to N=4 unless the source explicitly names a different count. N=3 when the user names three investigators, N=56 for larger ecosystems. Beyond 6 satellites, switch to the bus topology pattern — a shared store with 8+ agents suggests event-driven coordination, not accumulated state.
+287
View File
@@ -0,0 +1,287 @@
# Pitfalls Checklist
Run through this list after writing the SVG and before saving the file. Most diagram failures are one of these ten, and they all happen silently — the SVG is "valid" but looks wrong when rendered.
Read this as a code review on yourself. If any item fails, fix the SVG and re-check.
## 1. viewBox clips content
**Symptom**: the bottom row of boxes is cut off, or a label disappears past the right edge.
**Check**:
- Find the lowest element. For rects: `y + height`. For text: `y + 4` (descender). For circles: `cy + r`.
- `viewBox` height must be `max(those) + 20` or more.
- Find the rightmost element. For rects: `x + width`. No rect's right edge should exceed 640.
**Fix**: increase `H` in `viewBox="0 0 680 H"`, or shrink the content horizontally.
**Exception — subsystem architecture pattern.** The 2-up sibling containers (see `structural.md` → "Subsystem architecture pattern" and `layout-math.md` → "Sibling subsystem containers (2-up)") deliberately sacrifice the 40px horizontal safe margin so each sibling interior is wide enough for a short internal flow. With `container_A.x=20` and `container_B.x=345, width=315`, container B's right edge lands at **660**. That is the documented layout; rects belonging to the 2-up pattern may extend up to x=660 instead of 640. All content *inside* each container (internal nodes, cross-system labels) still respects its own interior edge — no individual flowchart rect inside a sibling should touch the dashed border.
## 2. Text overflows its box
**Symptom**: a label spills out past the border of its container.
**Check**: for every labeled rect, compute `label_chars × char_width + 24` (8 for 14px latin, 7 for 12px latin, 15 for 14px CJK). The rect's width must be ≥ that number.
**Fix**: widen the rect, or shorten the label. Subtitles > 5 words are always a smell — cut them.
## 3. Arrow crosses an unrelated box
**Symptom**: an arrow visibly slashes through the interior of a rect it's not anchored to.
**Check**: for every arrow, trace its line segment(s). For every other rect in the diagram, does the arrow cross the rect's interior? If yes, it's a bug.
**Fix**: replace the straight `<line>` with an L-bend `<path>` that routes around the obstacle:
```svg
<path d="M x1 y1 L x1 ymid L x2 ymid L x2 y2" class="arr" fill="none" marker-end="url(#arrow)"/>
```
Pick `ymid` so the horizontal channel runs through empty space between rows.
## 4. Connector path is missing `fill="none"`
**Symptom**: a curved connector renders as a giant black blob instead of a thin line.
**Check**: every `<path>` or `<polyline>` used as a connector must have `fill="none"` as an explicit attribute. SVG defaults paths to `fill: black`.
**Fix**: add `fill="none"` — or use the `arr` class, which already sets it.
## 5. Text has no class, renders as default
**Symptom**: a label looks slightly different from the rest — wrong size, wrong color, or black in dark mode.
**Check**: every `<text>` element must have a class: `t`, `ts`, `th`, or (in poster flowcharts only) `title`, `eyebrow`, `caption`, `anno`. No unclassed text. No `fill="inherit"`. No hardcoded `fill="black"`.
**Fix**: add the appropriate class. `t` for single-line body, `th` for titles (bold), `ts` for subtitles and callouts. In a poster flowchart, `title` for the top label, `eyebrow` for section dividers, `caption` for the footer hook, `anno` for right-column side notes.
## 6. Title and subtitle use the same color stop
**Symptom**: a two-line node looks visually flat — the title and subtitle blur together.
**Check**: inside any `c-{ramp}` box, the `th` and `ts` children must land on different stops. The template handles this automatically (th → stop 800, ts → stop 600), so this only breaks if you manually override a fill. Don't.
**Fix**: remove the inline `fill=` override; let the template classes do their job.
## 7. `text-anchor="end"` at low x
**Symptom**: a label is missing from the left side of the diagram — it's actually there, but it extends past x=0 and is clipped by the viewBox.
**Check**: for every `<text>` with `text-anchor="end"`, the label's width must fit to the left of its x coordinate: `label_chars × char_width < x`.
**Fix**: use `text-anchor="start"` and right-align the column manually, or move the text to a higher x.
## 8. Color rainbow (colors cycle instead of encoding meaning)
**Symptom**: a 5-step flowchart uses blue-teal-amber-coral-purple, one per step. Reader can't tell if the colors mean anything.
**Check**: do colors encode categories (all "immune cells" share one color) or do they encode sequence (step-1 blue, step-2 teal)? Sequence is wrong.
**Fix**: collapse to ≤2 ramps. Use gray for neutral/structural/sequential steps. Reserve one accent color for whichever nodes deserve emphasis — the decision point, the anomaly, the main character of the story.
## 9. Too many boxes in a full-width row
**Symptom**: boxes overlap each other, or text spills across box borders.
**Check**: `N × box_width + (N - 1) × gap ≤ 600`. If you tried to fit 5+ boxes at default width (180 each), you've already overflowed.
**Fix**:
- Shrink box_width to ≤110 (drops subtitles)
- Wrap to 2 rows
- Split into overview + detail diagrams
## 10. Cycle drawn as a physical ring
**Symptom**: a four-stage cycle (Krebs, event loop, GC) is laid out with boxes orbiting a dashed circle. Labels collide with stage boxes; feedback arrows point at weird angles.
**Check**: does the diagram try to show a loop by arranging boxes in a circle?
**Fix**: lay the stages out linearly (horizontal or vertical) and draw a single return arrow from the last stage back to the first — or simply add a small `↻ returns to start` label near the endpoint. The loop is conveyed by the return arrow, not by literal ring geometry.
## 11. Dark-mode invisible text (bonus check)
**Symptom**: the SVG looks fine in light mode, but text disappears in dark mode.
**Check**: did you hardcode any `fill="#..."` or `fill="black"` on a `<text>` or ignore the `t`/`ts`/`th` classes? If yes, dark mode won't override it.
**Fix**: remove hardcoded fills on text. Let the template classes handle both modes.
**Exception**: physical-color scenes (sky blue, grass green, water teal in an illustrative diagram) *should* stay the same in both modes. Hardcode those hex values deliberately. But all label text — the `<text>` elements with callouts and titles — must use the classes.
## 12. `<!--` comments left in the SVG (bonus check)
**Symptom**: final SVG has HTML comments. They waste bytes and some markdown renderers show them.
**Check**: grep for `<!--` in your generated SVG. There should be none in the output (even though they appear in the template documentation above).
**Fix**: strip them before saving.
## 13. Lifeline clipped at the bottom (sequence)
**Symptom**: the last message arrow looks like it's hanging in space because the lifeline ends at the arrow's y, with no tail beneath it.
**Check**: `lifeline_y2 ≥ last_arrow_y + 24`. Every lifeline needs a 24px tail past the last message.
**Fix**: extend all lifeline `<line y2="...">` values to `last_arrow_y + 24` and bump viewBox H accordingly.
## 14. Actor header overflow (sequence)
**Symptom**: the title or role text spills past the actor header rect.
**Check**: `max(title_chars × 8, role_chars × 7) + 24 ≤ header_w`. For N=4, header_w=120, so the title caps at (120 24) / 8 = 12 characters. Longer titles need a shorter actor, a merged actor, or dropping the role subtitle.
**Fix**: cut the role subtitle first (it's optional), then shorten the title. Never widen the lane beyond the table in `layout-math.md` — it breaks the tier packing.
## 15. Message label too long for its lane span (sequence)
**Symptom**: a message label collides with an adjacent actor's header or another message label.
**Check**: `label_chars × 7 ≤ |sender_x receiver_x| 8`. For N=4 adjacent lanes (|Δx|=160), labels cap at ~21 chars. For longer leaps the budget grows linearly.
**Fix**: shorten the label (the most effective fix — "Redirect with client_id, scope" → "Redirect + client_id"), or restructure the message between actors that are further apart on the diagram (rare).
## 16. Arrow endpoint mispositioned on lifeline (sequence)
**Symptom**: the arrowhead touches the dashed lifeline stroke and looks smeared, or the arrow stops 15px short and looks disconnected from the target.
**Check**: every message arrow's `x2` must equal `receiver_x ± 6` (minus 6 for left-to-right, plus 6 for right-to-left). Same for `x1` on the sender side.
**Fix**: recompute every arrow's x1/x2 from the lifeline center table. Never eyeball.
## 17a. Poster flowchart missing its title or subtitle
**Symptom**: the diagram contains eyebrow-divided phases and a fan-out row, but no `title` at the top — it looks like a collection of boxes floating in space.
**Check**: if the diagram qualifies as a poster (≥3 of the poster triggers in `flowchart.md`), it *must* have a `.title` at the top. The title is the reader's first anchor — without it, the eyebrows and side notes feel unmoored.
**Fix**: add a one-line `.title` with the mechanism name at (340, 46), and a `.ts` subtitle at (340, 68) that frames the "why".
## 17b. Fan-out row conflates "candidates" with "sequence"
**Symptom**: three side-by-side boxes labeled step 1 / step 2 / step 3, each in a different color.
**Check**: a fan-out row should contain **parallel alternatives** that all feed into a judge, not sequential steps. If the boxes have a reading order, they belong in a column, not a row. Colors on a fan-out row are fine *if* they represent distinct candidate identities (keep / rewrite / synthesize), not fine if they're decorating sequence.
**Fix**: either reorient to a vertical column (sequence) or rewrite the labels so each is clearly a *kind* of candidate (A · keep, B · rewrite, AB · synthesize), not a step number.
## 17c. Side-annotation column floats too far from its box
**Symptom**: an `anno` line at y=200 is supposed to belong to a box at y=300 — 100px away — and the reader has to guess which box it describes.
**Check**: an annotation line's y must fall inside the vertical range of its target box (top to bottom). For a 56-tall box at y=300, annotations belong at y between 304 and 350. One line at the box center, or up to three lines vertically centered on the box.
**Fix**: recompute each annotation's y from its target box's y + height/2, then stack lines at ±14px from center.
## 17d. Loop-rail rotated label clips the top or bottom
**Symptom**: the rotated "loop until …" label extends past the loop rail line, or overlaps the first/last box inside the loop.
**Check**: `transform="rotate(-90 cx cy)"` rotates around `(cx, cy)`, where the text after rotation occupies ≈ `label_chars × 7` horizontally (now vertically post-rotation). The rotated label's extent must fit between `loop_top` and `loop_bottom`.
**Fix**: shorten the label (≤20 chars), or extend the rail.
## 18. Self-message rect not centered on its lifeline (sequence)
**Symptom**: the small self-message rect sits to one side of the lifeline, not straddling it.
**Check**: `rect_x = lifeline_x rect_w / 2`. For `rect_w = 16`, that's `lifeline_x 8`. Off-by-one is easy when rect_w is small.
**Fix**: recompute rect_x from the lifeline x. Double-check the rect has the actor's `c-{ramp}` class so the fill matches the lifeline's owning actor.
## 19. Bus-topology bar not centered or shifted off-axis
**Symptom**: the central horizontal bar in a message-bus diagram is slightly off-center, so the Publish/Subscribe arrow pairs from the top and bottom agents don't line up symmetrically and the whole diagram feels tilted.
**Check**: the bus bar must sit at `x=40 y=280 w=600 h=40` (see `layout-math.md` → "Bus topology geometry"). `bar_cx = 340`. Every agent row must center on that same `bar_cx` axis — if the top row is centered at x=340 but the bottom row drifts to x=335, the diagram is crooked.
**Fix**: recompute top and bottom agent x positions from the shared center using the "Bus topology geometry" table. Agents per row: 2 → centers at 180, 500. 3 → 170, 340, 510. 4 → 120, 260, 420, 560. Don't eyeball.
## 20. Radial-star satellites not at symmetric offsets
**Symptom**: three or four "satellite" boxes around a hub are almost, but not quite, evenly spaced — one is 20px further from the hub than the others, or one sits at a slightly different y than its mirror.
**Check**: use the fixed satellite coordinate table in `layout-math.md` → "Radial star geometry". The N=4 boxes must sit at `(60, 120)`, `(460, 120)`, `(60, 460)`, `(460, 460)` — any deviation breaks the mirror symmetry and the eye catches it immediately.
**Fix**: copy the coordinate table verbatim. If you need a satellite at a non-symmetric position because its label is longer, the pattern isn't the right shape — drop the satellite to a subtitle or switch to a bus topology.
## 21. Spectrum axis arrow covered by end label
**Symptom**: the left or right end of the spectrum axis's arrowhead sits behind the end label's text, or the label's descender touches the arrowhead.
**Check**: axis at `y=140`, end labels at `y=120` — that's only 20px of vertical separation. For end labels that include descender glyphs (p, g, y, q), the descenders sit around `y=124`, leaving 16px to the arrowhead. Verify the label baseline at 120 and that `text-anchor` correctly flushes each label to its axis end (`start` on left, `end` on right).
**Fix**: if the label still collides after fixing the text-anchor, bump end-label `y` to `116` (4px clearance above the arrowhead).
## 22. Box icon overlapping its text
**Symptom**: a `doc-icon` or `terminal-icon` inside a structural/illustrative box touches or overlaps the subtitle text below the title.
**Check**: for a box with title `y+22` and subtitle `y+40`, the subtitle baseline sits at `box_y + 44` (including descender). The icon's top must sit at **≥ 8px below that**, so `icon_top ≥ box_y + 52`. For a 28-tall icon, `box_h ≥ 52 + 28 + 8 = 88`. The documented minimum in `glyphs.md` is 80, which assumes a title-only box (no subtitle) — grow to 88 when both title and subtitle are present.
**Fix**: grow `box_h` until the math works, or drop the subtitle if the box is already at the design max height.
## 23. Checklist row width overflow
**Symptom**: a checkbox + label row inside a subsystem container runs past the container's right edge and the label clips.
**Check**: inside a 315-wide subsystem container, checklist width budget is `interior_w checkbox_w gap right_padding = 275 14 8 20 = 233` px, so `label_chars × 8 ≤ 233` → cap at ~29 Latin chars (or 15 CJK). The `glyphs.md` doc cites ~31 Latin chars for a looser budget — use 29 when you want a safety margin inside a sibling container.
**Fix**: truncate the label or wrap to two rows. Don't shrink the checkbox — 14px is the floor.
## 24. Status circle not aligned with the arrow path
**Symptom**: a `status-circle-check` (or `-x`, `-dot`) glyph sits next to the arrow instead of **on** it, or sits exactly on the arrow's path but the arrow still draws through the circle's center as a single continuous line.
**Check**: the arrow must be **split into two segments**: segment 1 from source to `(circle_cx 14, circle_cy)`, segment 2 from `(circle_cx + 14, circle_cy)` to target. If the original `<line>` is still there in one piece, delete it and replace with the two segments.
**Fix**: recompute the two segments. Both get `marker-end="url(#arrow)"` so each has its own arrowhead landing 2px before the circle's edge. See `flowchart.md` → "Status-circle junctions" for the exact template.
## 25. Dashed future-state node drifts out of row alignment
**Symptom**: a dashed `arr-alt`-class rect in a DAG sits at y=180 while the solid nodes around it sit at y=180.5 (or whatever the stroke-centering math produces), so the row looks misaligned even though the coordinates match.
**Check**: SVG strokes are centered on the path, so a rect with `stroke-width="1.5"` extends 0.75 px into the interior *and* 0.75 px outside its `x/y/width/height` attributes. Because the dashed rect's stroke is a different *pattern* from the solid rect's stroke, the visual difference can magnify this half-pixel. For perfect row alignment, the dashed rect and the solid rect must share the exact same x, y, width, and height — any "nudge by 1 to compensate" breaks the row.
**Fix**: keep the coordinates identical. If the visual misalignment persists and you've confirmed the coords match, the issue is the dash pattern start position, not the coordinates — try `stroke-dashoffset="0"` to force dash alignment, or accept the micro-difference (it's imperceptible at 1× zoom).
## 26. Parallel-rounds y's not at a consistent pitch
**Symptom**: three rounds stacked vertically look visually uneven because the gaps between rounds aren't equal — round 1→2 is 80px but round 2→3 is 72px.
**Check**: round pitch is **80** in the full-width variant (`layout-math.md` → "Parallel rounds geometry"). Round k's call arrow y = `124 + (k1) × 80`. If you computed round 2's y from round 1 by eye, recheck — "visually close enough" is not close enough for a side-by-side comparison diagram.
**Fix**: recompute all round y's from the table.
## 27. Annotation-circle connector line not perpendicular to the arrow
**Symptom**: the small vertical line connecting an annotation circle to its underlying arrow pair is slightly tilted because its x doesn't match the circle's center x.
**Check**: the connector line's `x1` and `x2` must both equal `circle_cx`. The circle is placed via `translate(cx 32, cy 32)`, so the circle's center is `(cx, cy)` in diagram coordinates. The connector's `y1 = cy + 30` (bottom of circle), `y2 = arrows_y_midpoint`.
**Fix**: recompute `x1 = x2 = circle_cx`. Don't set them from the translate offsets directly — use the diagram-space `cx` you passed to translate.
## 28. Glyph using inline fill or stroke, broken in dark mode
**Symptom**: a `status-circle-check`, `doc-icon`, or `annotation-circle` renders correctly in light mode but is invisible (or wrong color) in dark mode.
**Check**: grep the SVG for any `fill="#..."` or `stroke="#..."` inside a glyph's element tags. Glyphs must use only CSS classes (`c-{ramp}`, `arr-{ramp}`, `arr`, `arr-alt`, `box`, `t`/`th`/`ts`) so the template's `@media (prefers-color-scheme: dark)` block inverts them automatically.
**Fix**: replace every hardcoded color on a glyph element with the corresponding class. If you need a color that isn't in the 9-ramp palette, you don't need a new color — you're asking the glyph to say something it shouldn't. See `glyphs.md` → "Hard rules" for the full policy.
---
## Quick self-review template
Before writing the file, mentally run through:
> 1. Lowest element is at y = ___ → viewBox H = ___ + 20 = ___ ✓
> 2. Rightmost rect edge is at x = ___ → ≤ 640 ✓
> 3. Longest label is "___" (___ chars) → needs width ___ → actual width ___
> 4. Arrows checked against all boxes → no crossings ✓
> 5. All connector paths have `fill="none"`
> 6. All `<text>` elements have a class ✓
> 7. Colors: ≤ 2 ramps → ___ and ___ → assigned by category ✓
> 8. No hardcoded text fills ✓
> 9. No comments in final output ✓
If any of these feel fuzzy, the diagram isn't ready.
+303
View File
@@ -0,0 +1,303 @@
# Sequence Diagram
For multi-actor protocols and conversations — "who talks to whom, in what order". A row of actor headers at the top, dashed lifelines dropping down, and numbered horizontal message arrows between them. The classic UML sequence diagram, adapted to this skill's design system.
## When to use
- Authentication and authorization flows — OAuth, OIDC, SAML, Kerberos, JWT refresh, mTLS handshakes
- Wire protocols — TCP three-way handshake, TLS handshake, WebSocket upgrade, HTTP/2 multiplex
- RPC patterns — gRPC unary and streaming, JSON-RPC, GraphQL over websockets
- Webhooks, callbacks, and event dispatch — stripe webhooks, GitHub events, PubSub fan-out
- Any "request + response" dance between 24 named services where *order* and *who initiates what* is the point
**Trigger verbs**: "protocol", "handshake", "auth flow", "request/response", "exchange between", "round trip", "who calls what", "API dance".
**When not to use**:
- Single-actor sequential process → `flowchart.md` ("what steps does the build pipeline run")
- Containment / architecture / "what lives inside what" → `structural.md`
- "Feel how X works" / mechanism intuition → `illustrative.md`
**Routing test**: if the prompt names ≥2 distinct actors/participants/services (User + Server, Client + Auth + Resource, Browser + CDN + Origin), prefer sequence even when the noun is "flow" or "process". Single-actor "X flow" stays flowchart.
## Planning before you write SVG
1. **List the actors**, 24 of them, in the order they appear across the page (usually left = initiator, right = downstream services). Each actor needs a short title (≤12 chars for N=4) and an optional single-line role subtitle.
2. **Assign one color ramp to each actor**. Default palette: `[c-gray, c-teal, c-purple, c-blue]` left-to-right. Swap in `c-coral`, `c-pink`, `c-amber`, `c-green` as needed — pick cool/neutral ramps and avoid semantic collisions (green for success, red for error) unless the actor literally means that.
3. **List the messages** as ordered tuples `(sender, receiver, short label)`. Cap at 10 messages — 68 is the sweet spot. If your protocol has more, split into an overview diagram and one detail diagram per sub-flow.
4. **Mark self-messages** — messages that stay on the same lifeline (e.g., "validate token" on the resource server). Limit to 12 per diagram.
5. **Plan a side note** — a short title that names the protocol. For N ≤ 3, place it at top-left beside the first actor header. For N ≥ 4, place it at bottom-left under the lifelines.
6. **Check every message label** against its lane span using the budget formula in `layout-math.md`. Shorten aggressively — labels that barely fit today will overflow if you tweak the actor order.
Save the plan to `plan.md` alongside the SVG so the next iteration can read it.
## Actor headers
Each actor header is a two-line node (title + role) or a single-line node (title only), wrapped in a `c-{ramp}` group. Height is always 48, y=40..88.
Single-line (title only):
```svg
<g class="c-gray">
<rect x="40" y="40" width="120" height="48" rx="8"/>
<text class="th" x="100" y="64" text-anchor="middle" dominant-baseline="central">User</text>
</g>
```
Two-line (title + role):
```svg
<g class="c-teal">
<rect x="200" y="40" width="120" height="48" rx="8"/>
<text class="th" x="260" y="60" text-anchor="middle" dominant-baseline="central">Client app</text>
<text class="ts" x="260" y="78" text-anchor="middle" dominant-baseline="central">Web</text>
</g>
```
Rules:
- Header width matches `header_w` from `layout-math.md` (e.g., 120 for N=4).
- Header x = lane center header_w/2.
- Title `y = 60` when role is present, `y = 64` when title-only (centered in the 48px box).
- Role `y = 78`, always `ts`.
- Sentence case. "Auth server", not "Auth Server".
### Pill-shaped actor header (optional)
An actor that represents an **external participant**`Human`, `User`, `Environment`, an input source, an output sink — can use a pill-shaped header (`rx = height / 2 = 24`) instead of the default rounded rect. The capsule shape visually separates "outside the system" from "inside the system" without using color.
```svg
<g class="c-gray">
<rect x="40" y="40" width="120" height="48" rx="24"/>
<text class="th" x="100" y="64" text-anchor="middle" dominant-baseline="central">Human</text>
</g>
```
Rules:
- **Only for external actors.** Internal services (Auth server, Client app, Resource server) keep the `rx="8"` rectangle. Mixing pills and rects in the same diagram is fine as long as the distinction tracks "external vs internal" — if every actor is a pill, drop them all back to rectangles.
- **Height is still 48.** `rx` must equal `height / 2 = 24`. Don't adjust the height.
- **No role subtitle** inside a pill. The capsule is for actors whose name is self-explanatory (Human, Environment). If you need a subtitle, you want a rectangle, not a pill.
- **At most 2 pills per diagram.** More than that and the visual contrast between external and internal actors disappears.
## Lifelines
One `<line>` per actor, using `class="lifeline"`, from y=92 down to the tail below the last message.
```svg
<line class="lifeline" x1="100" y1="92" x2="100" y2="540"/>
<line class="lifeline" x1="260" y1="92" x2="260" y2="540"/>
<line class="lifeline" x1="420" y1="92" x2="420" y2="540"/>
<line class="lifeline" x1="580" y1="92" x2="580" y2="540"/>
```
All lifelines share the same y2. Compute once: `y2 = last_arrow_y + 24`.
## Messages
Each message is a single `<line>` at its row's `arrow_y`, with a `ts` label above. The stroke class encodes the sender's actor ramp.
```svg
<!-- arrow row 0, arrow_y = 120 -->
<text class="ts" x="180" y="110" text-anchor="middle">1. Click login</text>
<line class="arr-gray" x1="106" y1="120" x2="254" y2="120" marker-end="url(#arrow)"/>
<!-- arrow row 1, arrow_y = 164, right-to-left -->
<text class="ts" x="180" y="154" text-anchor="middle">3. Show consent screen</text>
<line class="arr-purple" x1="254" y1="164" x2="106" y2="164" marker-end="url(#arrow)"/>
```
Rules:
- Label `y = arrow_y 10`, centered between sender and receiver x.
- Arrow `y1 = y2 = arrow_y`.
- Arrow endpoints are offset ±6 from the lifeline x so the arrowhead doesn't touch the dashes:
- Left-to-right: `x1 = sender_x + 6`, `x2 = receiver_x 6`
- Right-to-left: `x1 = sender_x 6`, `x2 = receiver_x + 6`
- Stroke class = `arr-{sender_ramp}``arr-gray` for User, `arr-teal` for Client app, etc. Never use `class="arr"` (the default mono-gray arrow class) on a sequence message.
- Label text is sentence case with a numeric prefix: `"1. Click login"`, `"3. Show consent screen"`. Numbers make the reading order unambiguous when arrows cross.
- Keep labels short — verify every label fits its lane span using the budget formula in `layout-math.md`.
## Self-messages
A self-message stays on one actor's lifeline. Draw it as a small 16×24 rect on the lifeline, colored in that actor's ramp, with the label to the **left** (so it stays inside the diagram even for the rightmost lane).
```svg
<!-- self-message on Resource server at arrow_y = 472 -->
<rect class="c-blue" x="572" y="460" width="16" height="24" rx="4"/>
<text class="ts" x="564" y="472" text-anchor="end" dominant-baseline="central">9. Validate token</text>
```
Rules:
- `rect_x = lifeline_x 8` (rect is 16 wide, centered on the lifeline).
- `rect_y = arrow_y 12` (rect is 24 tall, centered on the arrow row).
- Label `x = rect_x 8`, `text-anchor="end"`, `dominant-baseline="central"`, `class="ts"`.
- Label still gets its numeric prefix (`"9. Validate token"`), following the overall message order.
- Limit self-messages to 12 per diagram — more than that and the metaphor of "an actor talking to itself" stops reading clearly.
## Message frames
A **frame** is a dashed rounded rect that visually groups a contiguous run of messages under a single condition — *"Until tasks clear"*, *"Iterative research loop"*, *"Only if authenticated"*. It reads like a bracket around the enclosed messages, not like a new container. Anthropic's house-style sequence diagrams use frames for repeating or conditional sub-flows that don't warrant their own diagram.
```svg
<rect x="90" y="108" width="490" height="112"
rx="8" fill="none" stroke="#B4B2A9" stroke-width="1"
stroke-dasharray="5 4"/>
<text class="ts" x="100" y="120" text-anchor="start" dominant-baseline="central">Until tasks clear</text>
```
Rules:
- **Dashed rounded rect**, `rx="8"`, 1px stroke in the muted gray (`#B4B2A9` light / `#5F5E5A` dark — match `.lifeline`). Use inline `stroke-dasharray="5 4"` rather than a new CSS class.
- **Horizontal span**: `x = leftmost_lane_x 20`, `width = rightmost_lane_x leftmost_lane_x + 40`. The frame stretches 20px past the outermost lanes it covers, so the label has clear air at the corner.
- **Vertical span**: `y = first_arrow_y 12`, `height = last_arrow_y first_arrow_y + 24`. Tight enough that the frame feels like a bracket, not a new section.
- **Label position**: top-left inside the frame, at `(frame_x + 10, frame_y + 12)`, `class="ts"`, `text-anchor="start"`, `dominant-baseline="central"`. Keep the label ≤24 characters.
- **No numeric prefix** on the frame label — numbering is for individual messages. The frame is meta.
- **At most 2 frames per diagram**, and **frames never nest**. Two frames can sit one above the other, but they cannot contain each other. If you need nested scoping, split into two diagrams.
- **Draw frames BEFORE the messages** in source order so the dashed border sits behind the arrows and labels.
When to use a frame:
- A **loop** — "Until tests pass", "Until tasks clear", "Iterative research loop"
- A **conditional block** — "Only if authenticated", "When cache miss"
- A **named sub-protocol** — "Token refresh", "Retry with backoff"
Don't use a frame to decorate a single message, and don't use one to group messages that have nothing in common — frames are a scoping tool, not a visual group.
## Side note
A titled annotation for the protocol itself. Uses `class="box"` with a `th` title and an optional `ts` subtitle.
Top-left (for N ≤ 3):
```svg
<rect class="box" x="40" y="40" width="240" height="48" rx="10"/>
<text class="th" x="60" y="60" dominant-baseline="central">OAuth 2.0</text>
<text class="ts" x="60" y="78" dominant-baseline="central">Authorization code flow</text>
```
Bottom-left (for N ≥ 4, because the top row is filled with actor headers):
```svg
<rect class="box" x="40" y="556" width="240" height="48" rx="10"/>
<text class="th" x="60" y="576" dominant-baseline="central">OAuth 2.0</text>
<text class="ts" x="60" y="594" dominant-baseline="central">Authorization code flow</text>
```
Budget: title ≤24 chars, subtitle ≤32 chars. The box is 240 wide, padding 20 per side → usable width 200 → ~24 `th` chars or ~28 `ts` chars.
## Layout patterns
### 2-actor request/response (N=2)
User asks, server responds. Two lanes at x=185 and x=495. Typical message count: 24. Side note at top-left.
### 3-leg handshake (N=2, M=3)
Classic TCP. Same layout as above, three messages going SYN → SYN-ACK → ACK. Color the initiator arrows in one ramp and the responder arrows in another — the alternation reads as the handshake.
### 4-actor OAuth-style flow (N=4, M=810)
User, Client app, Auth server, Resource server. The canonical shape. Lane centers at 100, 260, 420, 580. Side note at bottom-left. One self-message on the Resource server for the "validate token" step.
### Async webhook (N=2 or 3)
Sender fires an event, receiver acknowledges later. Often has a gap in the middle that you can skip — no need to draw "wait 30 seconds" as a message; just put consecutive messages in the natural reading order.
## Parallel independent rounds
A sub-pattern for topics where **multiple independent call/response rounds** happen in sequence but share no lifeline state — each round is its own contained exchange, and the diagram's job is to contrast the structure of the rounds rather than track continuous state on a lifeline. Image #12 (Tool calling vs. Programmatic tool calling) is the canonical case.
**When to use.**
- Comparing tool-call vs. programmatic-script patterns where each round is an independent call/response.
- Showing "N separate rounds of the same exchange" to communicate volume or variety.
- The right half of a 2-up comparison where each side shows a different protocol style.
**When not to use.**
- There's genuine shared state between rounds (conversation history, pending requests) — that's a regular sequence with full lifelines.
- There are only 2 actors and 24 messages — that's a regular 2-actor sequence.
- The rounds are conditional ("if X then do round 2") — that's a frame on a regular sequence.
### Geometry — stacked rounds variant
Each round is a **row-sized mini-exchange** between a fixed source on the left and a round-specific action box on the right. Rounds stack vertically with no shared lifeline. See `layout-math.md` → "Parallel rounds geometry".
| Element | Coordinates |
|--------------------|-------------------------------------------------|
| Source actor | `x=60 y=120 w=120 h=60` (persistent on left) |
| Round 1 action | `x=340 y=100 w=160 h=48 rx=6` |
| Round 2 action | `x=340 y=180 w=160 h=48 rx=6` |
| Round 3 action | `x=340 y=260 w=160 h=48 rx=6` |
| Row pitch | 80 (round_y increases by 80 per round) |
The source actor is drawn **once** at the top-left, not repeated per round. Its box height is just tall enough to span the first round's arrow row, with no lifeline extending below it — the absence of a lifeline is the signal that the source isn't carrying state across rounds.
**Why no lifeline.** A lifeline would visually suggest that state persists; in this pattern each round is a fresh stateless call. The source box itself is the anchor — the left edge of every arrow starts at `source_right_edge`, not at a lifeline x.
**Arrow pairs per round.** Each round is two arrows:
```svg
<!-- Round 1 -->
<text class="ts" x="260" y="115" text-anchor="middle">1. Call tool A</text>
<line class="arr-gray" x1="186" y1="124" x2="334" y2="124" marker-end="url(#arrow)"/>
<text class="ts" x="260" y="145" text-anchor="middle">2. Response</text>
<line class="arr-teal" x1="334" y1="134" x2="186" y2="134" marker-end="url(#arrow)"/>
```
Round k's arrow y values: `call_y = 100 + 24 + (k-1) × 80`, `response_y = call_y + 10`. Action box for round k: `y = call_y 24`.
**Action box colors.** Each round's action box **can** take a different ramp — this is the only place in a sequence diagram where color is allowed to cycle across messages. The reason: each round calls a *different tool* (file write, api call, db query), and the color communicates that variety. Use up to 3 different ramps; more than that and the reader can't remember what each ramp means.
Source actor ramp stays **constant** across all rounds (usually `c-gray` — "Claude" or "Agent").
### Script-wrapper variant
The right half of image #12 uses the same stacked-rounds shape but wraps **multiple action boxes inside a single tall script rect** that represents an inline program executing several tool calls. Uses the `script-icon` pattern from `glyphs.md`.
| Element | Coordinates |
|----------------------|-----------------------------------------|
| Source actor | `x=60 y=120 w=120 h=60` |
| Script wrapper | `x=240 y=100 w=140 h=260 rx=6`, `c-gray`|
| `{ }` label in wrapper | `(310, 124)`, `th` |
| Divider line | `(256, 140) → (364, 140)`, `arr` |
| Wrapped action 1 | `x=252 y=152 w=116 h=48 rx=4` |
| Wrapped action 2 | `x=252 y=212 w=116 h=48 rx=4` |
| Wrapped action 3 | `x=252 y=272 w=116 h=48 rx=4` |
| External action | `x=440 y=200 w=160 h=48 rx=6` (optional)|
The script wrapper replaces the individual action boxes with a single container that contains N smaller colored bands. Only the **script wrapper itself** gets arrows from the source — the inner bands are decorative, showing what's inside the script without each needing its own call arrow.
```svg
<!-- Single arrow from source to script -->
<line class="arr-gray" x1="186" y1="230" x2="234" y2="230" marker-end="url(#arrow)"/>
<text class="ts" x="210" y="220" text-anchor="middle">run script</text>
```
If the script calls an external tool (image #12's right half: a `file_system` external box on the far right), draw a single arrow from the script's right edge to the external box at the script's middle y.
### Side-by-side comparison
The most common use of parallel rounds is inside a 2-up structural subsystem layout (`structural.md` → "Subsystem architecture pattern"): left container shows the stacked-rounds variant, right container shows the script-wrapper variant. Each sibling container is 315 wide, so halve the coordinates above:
- Source actor inside container: `x = container_x + 20, w=100 h=50`
- Action box inside container: `x = container_x + 180, w=120 h=40`
- Round pitch inside container: 64
See `structural.md` → "Rich interior for subsystem containers" for how this interior type registers.
### Rules
- **No lifelines.** If you draw lifelines, you're describing a regular stateful sequence, not parallel independent rounds. Drop them.
- **Source actor appears once.** Never duplicate the source per round — that multiplies the visual noise and breaks the "same caller, different calls" intuition.
- **Numeric prefixes still apply.** Within each round the two arrows are numbered (`1. Call tool A`, `2. Response`), and the numbering resets per round (or continues across rounds, at your choice — document it in the side note).
- **≤3 rounds per diagram.** 4+ rounds runs out of vertical space and overwhelms the comparison. Use two diagrams if you need to show more.
- **No frames around rounds.** A frame is a scoping bracket for a loop or a condition; parallel rounds are already independent, so a frame would be redundant.
- **Action ramps cap at 3.** Each round can take a distinct ramp, but stop at 3 distinct colors.
## Rules of thumb
- **Max 4 actors (comfortable), max 6 actors (absolute ceiling).** 5 is allowed only when every title is ≤12 chars and every subtitle is omitted. 6 requires every title ≤9 chars (so it fits the 100-wide header rect) and no subtitles, and the diagram loses its 40px horizontal safe margin — see `layout-math.md` → "Swim-lane (sequence) layout" for the full N=5 and N=6 coordinate tables. Beyond 6, split into an overview diagram plus one detail diagram per sub-flow — a 7-actor sequence diagram is guaranteed to feel cramped no matter how carefully you pack the labels.
- **610 messages is the sweet spot.** 4 is too sparse (use a flowchart); 12+ is too dense (split).
- **One ramp per actor**, up to 4 total. The default `[gray, teal, purple, blue]` works for most protocols. Swap ramps only when a topic needs it.
- **Number every message.** Even "obvious" single-step diagrams benefit from "1. ...". Readers scan numbers before they read words.
- **Every arrow gets a label.** Sequence diagrams are the one place in this skill where arrow labels are mandatory, not optional — the label *is* the message, and without it the diagram says nothing.
- **Sender's ramp colors the arrow.** Never use `class="arr"` (mono-gray) for a sequence message.
- **Labels above the line, never on it.** Labels float 10px above the arrow at the row midpoint, `text-anchor="middle"`, `class="ts"`.
- **No crossings within a single row.** Two messages at the same `arrow_y` collide — always move one to a new row.
- **No arcs, no curves.** Flat horizontal lines only. Self-messages use a labeled rect, not a small arc.
@@ -0,0 +1,113 @@
# Structural: Comparison Matrix
Load this file when the content is a **feature comparison**: "which of these databases supports X", side-by-side feature tables, ✓/✗ grids, or any "option × attribute" matrix.
Sub-pattern for side-by-side feature comparisons — *"which of these three databases supports transactions"*, *"which of these four frameworks has a migration path"*. The subject is a tabular matrix with **rows = features** and **columns = systems** (or the reverse). Structural diagram type is the right home because the matrix is really a structured grid of containers, just with a disciplined layout.
## When to use it
- The reader's question is *"which option has property X"*, and they'll compare across rows or columns.
- You have 25 columns and 28 rows. Beyond 5 columns, split into two matrices. Beyond 8 rows, promote the most important 6 and drop the rest into prose.
- Each cell's value fits in **one word or a ✓/✗ glyph**. If cells need sentences, this isn't a matrix — it's a comparison essay, which belongs in prose around the diagram.
## Structure
A comparison matrix is one header row (column labels) plus N body rows (attribute on the left, values in each column). The grid has no visible gridlines — the zebra-striped row backgrounds provide the horizontal separation, and the column alignment provides the vertical separation. Flat aesthetic, no table borders.
| Element | Width / coordinates |
|--------------------|-------------------------------------------------------------|
| Attribute column | 160 wide |
| Value columns | `(600 160) / N` wide, equal to each other |
| Row height | 36 (single-line `t` value) or 52 (two-line title + subtitle)|
| Row gap | 0 (rows touch — the alternating fill creates the band) |
| Header row height | 40 (slightly taller than body rows) |
| Header text | `th` class, centered |
| Body attribute | `t` class, left-anchored at `col_x + 12` |
| Body value (text) | `t` class, centered in column |
| Body value (glyph) | `status-circle-check` / `status-circle-x`, centered in column|
**Column count formula.** For 3 value columns: value_width = 440/3 ≈ 147. For 4: 110. For 5: 88. At 5 columns the value column barely fits *"Supported"*; past that, any label longer than 8 characters clips. Hard cap at 5 columns — if you have 6 systems to compare, split into *(A, B, C)* and *(D, E, F)* matrices.
## Alternating row fills
Zebra striping uses the `.row-alt` class from `svg-template.md` on every other body row. The header row uses `.box` with a slightly darker inline `stroke-width="1"` or the default `.box`:
```svg
<!-- Header row -->
<rect class="box" x="40" y="60" width="600" height="40" rx="6"/>
<!-- Body row 1 (default .box) -->
<rect class="box" x="40" y="100" width="600" height="36"/>
<!-- Body row 2 (.row-alt) -->
<rect class="row-alt" x="40" y="136" width="600" height="36"/>
<!-- Body row 3 (default .box) -->
<rect class="box" x="40" y="172" width="600" height="36"/>
```
Rounded corners (`rx="6"`) only on the *header* row and on the *last* body row — the middle rows are sharp-cornered so they stack seamlessly. Implementation trick: give the first body row `rx="0"` explicitly, and only round the bottom of the last row using the standard outer-wrapper approach, or accept square corners throughout for simplicity (which is also fine).
## Cell contents
Cells fall into three buckets:
- **Boolean** — use `status-circle-check` (c-green) for *yes*, `status-circle-x` (c-coral) for *no*, from `glyphs.md`. Centered in the cell. No extra text label. ✓/✗ is a visual shortcut that reads faster than the word.
- **Short text** — 12 words like *"v2.1"*, *"Postgres"*, *"Yes"*, *"Optional"*. Use class `t`, `text-anchor="middle"`, centered at the cell's x-midpoint.
- **Tier** — when the value is a level (*"Full"*, *"Partial"*, *"None"*), still use short text. Resist the urge to map tiers to colors — that re-categorizes the data and breaks the 2-ramp budget.
**No subtitle text inside a cell.** If a value *needs* a qualifier (*"Yes, since v3"*), the qualifier belongs in a footnote marker (*"Yes†"*) with the footnote written as `ts` text below the whole matrix. Don't stack two `ts` lines inside a 36px cell.
## Worked example — 3-system × 5-feature comparison
Request: *"Compare Postgres, MySQL, and SQLite on: transactions, JSON columns, full-text search, replication, on-disk encryption."*
Plan:
- Header row: attribute column + 3 system columns. Value_width = 440/3 ≈ 147.
- 5 body rows, alternating `.box` and `.row-alt`.
- Feature names are 14px body text; system values are mostly ✓/✗ glyphs, with one short text ("Built-in"/"Plugin").
- Single accent: none — the green/coral in the status circles already encodes meaning, and adding a ramp to the matrix would clash with the semantic greens.
```svg
<svg ... viewBox="0 0 680 320">
<!-- Header row -->
<rect class="box" x="40" y="40" width="600" height="40" rx="6"/>
<text class="th" x="120" y="64" text-anchor="middle">Feature</text>
<text class="th" x="267" y="64" text-anchor="middle">Postgres</text>
<text class="th" x="413" y="64" text-anchor="middle">MySQL</text>
<text class="th" x="560" y="64" text-anchor="middle">SQLite</text>
<!-- Row 1: Transactions (all yes) -->
<rect class="box" x="40" y="80" width="600" height="36"/>
<text class="t" x="52" y="103">Transactions</text>
<g transform="translate(255, 86)"><circle class="c-green" cx="12" cy="12" r="12"/><path class="arr-green" d="M6 12.5 L10.5 17 L18 8" fill="none" stroke-linecap="round" stroke-linejoin="round"/></g>
<g transform="translate(401, 86)"><circle class="c-green" cx="12" cy="12" r="12"/><path class="arr-green" d="M6 12.5 L10.5 17 L18 8" fill="none" stroke-linecap="round" stroke-linejoin="round"/></g>
<g transform="translate(548, 86)"><circle class="c-green" cx="12" cy="12" r="12"/><path class="arr-green" d="M6 12.5 L10.5 17 L18 8" fill="none" stroke-linecap="round" stroke-linejoin="round"/></g>
<!-- Row 2: JSON columns (all yes — alternating stripe) -->
<rect class="row-alt" x="40" y="116" width="600" height="36"/>
<text class="t" x="52" y="139">JSON columns</text>
<!-- ✓ ✓ ✓ glyphs at same offsets -->
<!-- Row 3: Full-text search (text value varies) -->
<rect class="box" x="40" y="152" width="600" height="36"/>
<text class="t" x="52" y="175">Full-text search</text>
<text class="t" x="267" y="175" text-anchor="middle">Built-in</text>
<text class="t" x="413" y="175" text-anchor="middle">Built-in</text>
<text class="t" x="560" y="175" text-anchor="middle">Plugin</text>
<!-- Row 4: Replication (SQLite no — alternating stripe) -->
<rect class="row-alt" x="40" y="188" width="600" height="36"/>
<text class="t" x="52" y="211">Replication</text>
<!-- ✓ Postgres, ✓ MySQL, ✗ SQLite -->
<!-- Row 5: On-disk encryption (all ✗ except one) -->
<rect class="box" x="40" y="224" width="600" height="36" rx="6"/>
<text class="t" x="52" y="247">On-disk encryption</text>
<!-- ✗ ✗ ✓ -->
</svg>
```
A 5-row × 4-column matrix at 36px row height lands the final body row's bottom at y=260, plus 40 bottom margin = viewBox height 300. Six rows pushes the bottom to 296 + 40 = 336 — still comfortable on the 680-wide canvas.
**Column x-midpoints (for 3 value columns).** Attribute column center: 120. Value column centers: 160 + 147/2 = 233.5 ≈ 234, 160 + 147 × 1.5 = 380.5 ≈ 381, 160 + 147 × 2.5 = 527.5 ≈ 528. The worked example above uses 267 / 413 / 560 because it centers the value columns on their actual bounding boxes after the 40px left canvas margin — recompute from `40 + 160 + (i + 0.5) × value_width` for your own grids.
@@ -0,0 +1,136 @@
# Structural: Network Topology
Load this file when the prompt asks about **network infrastructure**: "where do the wires go", "which zone is this device in", "DMZ / firewall / VPC topology", security zones, or device connectivity. The reader's question is *"what is connected to what, and across which boundary"*.
Sub-pattern for diagrams whose subject is **where the wires go** — which devices sit where, which security zones contain them, which links are wired vs wireless. The structural diagram type is the right home for this (devices are containers, zones are outer containers, cables are arrows), but topology drawings have some conventions of their own.
## When to use it
- The reader's question is *"what is connected to what, and across which boundary"*, not *"what happens when a request arrives"* (that's a sequence diagram).
- You can name ≤10 devices. More than that, split into *edge topology* and *internal topology* — no single network diagram should try to show the whole datacenter.
- The zones matter as much as the devices. A network drawing without zones is just a bus or radial topology in disguise — use those sub-patterns instead.
## No custom device icons
baoyu is a flat-rect aesthetic. A router is a rounded rect labeled *Router*, a firewall is a rounded rect labeled *Firewall*, a cloud/Internet boundary is a rounded rect labeled *Internet*. **Do not draw a cylinder for a server, a trapezoid for a switch, a cloud silhouette for the Internet, or a shield-with-flames for a firewall.** The two-line node (type on top in `th`, name on bottom in `ts`) carries the same information with no aesthetic break:
```svg
<g class="c-gray">
<rect x="120" y="160" width="160" height="56" rx="6"/>
<text class="th" x="200" y="182" text-anchor="middle">Firewall</text>
<text class="ts" x="200" y="202" text-anchor="middle">edge-fw-01</text>
</g>
```
The device *type* is the title; the device's specific *name* or role (hostname, function) is the subtitle. If the diagram only has generic types without specific instances, a single-line 44-tall rect with the type as the title is fine.
## Zone containers
Use the existing dashed-container trick from `structural.md` → "Subsystem architecture pattern", with a top-left pill label for the zone name. One container per security zone:
| Zone | Typical label | Notes |
|----------|---------------|-----------------------------------------------------------------|
| Internet | *Internet* | Anything outside the org — clients, public DNS, SaaS endpoints |
| DMZ | *DMZ* | Reverse proxies, WAFs, public web/API frontends |
| Internal | *Internal* | Application servers, internal APIs, caches |
| Data | *Data* | Databases, object stores, message brokers — isolate from DMZ |
| Mgmt | *Management* | Bastion, monitoring, config — often spans other zones via ACLs |
Keep containers to **≤4 zones per diagram**. A 5-zone network is better split into two diagrams (*edge flow* + *internal flow*) than crammed into one 680-wide canvas.
The container rect uses `class="arr-alt"` — it inherits the dashed stroke from the template and dark-mode-safe coloring. The pill-shaped zone label sits in the top-left at `(container_x + 12, container_y 8)` with class `ts` and an optional small background rect:
```svg
<rect class="arr-alt" x="40" y="60" width="600" height="180" rx="12"/>
<rect class="box" x="40" y="52" width="80" height="16" rx="8"/>
<text class="ts" x="80" y="64" text-anchor="middle">DMZ</text>
```
The label's background rect (`class="box"`) sits on top of the container's dashed top edge, masking it — the label reads as a tab attached to the zone rather than text floating inside it.
## Wired vs wireless
Two distinct link styles, both already in the template:
- **Wired link** — solid `class="arr"`. Optional `ts` label on the arrow midpoint carries the bandwidth or protocol (*1 Gbps*, *VPN*, *TLS*). Follows the normal 13 word arrow-label rule.
- **Wireless link** — dashed `class="arr-alt"`. Same label rules. Wireless is also the right choice for *logical* links (VPN tunnels across the public internet, cross-AZ replication) where the link isn't a single physical cable.
**Two link styles means you need a legend.** Per `design-system.md`, any diagram that uses ≥2 arrow styles with distinct meaning must emit a one-line legend. For network topology:
```
[──] Wired [- -] Wireless / VPN [■] DMZ [■] Internal
```
Place the legend at the bottom of the canvas, 20px above the bottom edge, aligned with the subject matter above it.
## Tiered top-down layout
Network topology almost always reads top-down because the conventional mental model is *"traffic flows from the public internet down into the protected core"*. Lay out the zones vertically, one tier per row:
```
Row 1 (y=60..96) Internet container
Row 2 (y=116..180) Edge container (reverse proxy, firewall)
Row 3 (y=200..264) Core container (app servers, services)
Row 4 (y=284..348) Access / data container (databases, caches)
```
Each tier is a separate dashed container. Links run **between** containers, not inside — intra-zone links are assumed (everything in the same zone can reach everything else in that zone via the switch fabric) and cluttering the diagram with them wastes space.
## Worked example — 3-tier network
Request: *"Draw a 3-tier network: public internet talking to a DMZ firewall, which routes to internal app servers, which talk to a database."*
Plan:
- 3 zones: Internet, DMZ, Internal.
- 4 devices: Client (Internet), Firewall (DMZ), App (Internal), DB (Internal).
- All wired, so no legend needed — single arrow style.
- Direction: top-down.
- Colors: all `c-gray`. Devices aren't categorized by function strongly enough to warrant a ramp split.
```svg
<svg ... viewBox="0 0 680 340">
<!-- Zone: Internet -->
<rect class="arr-alt" x="40" y="32" width="600" height="64" rx="12"/>
<rect class="box" x="40" y="24" width="80" height="16" rx="8"/>
<text class="ts" x="80" y="36" text-anchor="middle">Internet</text>
<g class="c-gray">
<rect x="260" y="50" width="160" height="36" rx="6"/>
<text class="th" x="340" y="74" text-anchor="middle">Client</text>
</g>
<!-- Internet → DMZ arrow -->
<line x1="340" y1="86" x2="340" y2="118" class="arr" marker-end="url(#arrow)"/>
<!-- Zone: DMZ -->
<rect class="arr-alt" x="40" y="118" width="600" height="80" rx="12"/>
<rect class="box" x="40" y="110" width="60" height="16" rx="8"/>
<text class="ts" x="70" y="122" text-anchor="middle">DMZ</text>
<g class="c-gray">
<rect x="240" y="140" width="200" height="52" rx="6"/>
<text class="th" x="340" y="162" text-anchor="middle">Firewall</text>
<text class="ts" x="340" y="180" text-anchor="middle">edge-fw-01</text>
</g>
<!-- DMZ → Internal arrow -->
<line x1="340" y1="192" x2="340" y2="220" class="arr" marker-end="url(#arrow)"/>
<!-- Zone: Internal -->
<rect class="arr-alt" x="40" y="220" width="600" height="100" rx="12"/>
<rect class="box" x="40" y="212" width="80" height="16" rx="8"/>
<text class="ts" x="80" y="224" text-anchor="middle">Internal</text>
<g class="c-gray">
<rect x="120" y="244" width="180" height="52" rx="6"/>
<text class="th" x="210" y="266" text-anchor="middle">App server</text>
<text class="ts" x="210" y="284" text-anchor="middle">web-api-*</text>
</g>
<g class="c-gray">
<rect x="380" y="244" width="180" height="52" rx="6"/>
<text class="th" x="470" y="266" text-anchor="middle">Database</text>
<text class="ts" x="470" y="284" text-anchor="middle">postgres-primary</text>
</g>
<!-- App → DB wired link -->
<line x1="300" y1="270" x2="380" y2="270" class="arr" marker-end="url(#arrow)"/>
</svg>
```
Notice that the diagram shows inter-zone links (Client → Firewall → App) *and* one intra-zone link (App → DB). The intra-zone App → DB link is drawn because it's the whole point of the diagram — otherwise the reader wouldn't know the DB is in the *Internal* zone, not a fourth *Data* zone. When you leave intra-zone links out, make sure the device names alone answer *"who talks to whom"*.
@@ -0,0 +1,659 @@
# Structural Diagram
For concepts where physical or logical containment matters — "things inside other things". A large outer container with smaller regions inside it, labeled, and optionally connected by arrows or external inputs and outputs.
## When to use
- "How is X organised" / "what's the architecture" / "where does Y live"
- File systems (blocks inside inodes inside partitions)
- Cloud topologies (instance inside subnet inside VPC)
- Biological containment (organelles inside cells)
- Service architectures with clear boundaries (microservices inside a service mesh inside a cluster)
- CPU cache hierarchies (L1 inside core, L2 shared between cores)
**When not to use:** if the explanation is about *what happens over time*, reach for a flowchart. Containment diagrams answer "where", flowcharts answer "what order".
## Container rules
### Outer container
- Large rounded rect
- `rx="20"` (or up to 24 if the diagram needs a softer feel)
- Light fill (stop 50) and 0.5px stroke (stop 600) — both come automatically from the `c-{ramp}` class
- Label sits at the top-center inside the container, 2030px down from the top edge, as a `th` title
- A short subtitle can sit 18px below the title, as a `ts`
Example frame:
```svg
<g class="c-green">
<rect x="60" y="40" width="560" height="300" rx="20"/>
<text class="th" x="340" y="72" text-anchor="middle" dominant-baseline="central">VPC</text>
<text class="ts" x="340" y="92" text-anchor="middle" dominant-baseline="central">us-east-1</text>
</g>
```
### Inner regions
- Medium rounded rects, `rx="10"` (812 range)
- Different color ramp from the parent (see "Color pairing" below)
- 20px minimum padding between the inner region edge and the container edge on all sides
- 16px minimum gap between adjacent inner regions
- Same dimensions as a flowchart node: 44px tall for single-line, 56px for two-line, or larger rects (100+ tall) to represent regions of space
### Nesting depth
Maximum **23 levels**. Deeper nesting gets unreadable at 680px width. If you need four levels, split into two diagrams: the outer two levels in one diagram, then a detail diagram zooming into one of the inner regions.
## Color pairing
When you nest containers, pick ramps that *relate* rather than clash. A library branch + circulation desk is clearly two parts of one building, so use related cool ramps (green outer, teal inner). A library branch + café is two functionally different spaces, so use one cool and one warm (green + amber).
**Rule of thumb**:
- Same-category nesting → related cool ramps (green + teal, blue + teal, purple + pink)
- Different-category nesting → one cool + one warm (green + amber, blue + coral)
- Structural/neutral containers → gray + any accent
The key point: don't reuse the same ramp on parent and child. The template's `c-{ramp}` classes resolve to fixed fill/stroke stops, so a nested `c-blue` inside a parent `c-blue` gives identical fills — the hierarchy flattens visually.
## Layout
Inner regions sit **side by side** inside the container, not stacked unless you have a tall narrow container (e.g., a CPU cache hierarchy with L1 on top of L2 on top of L3). Horizontal layout is the default because the viewBox is 680 wide — you have room for 23 regions across but only 12 stacked vertically before it gets too tall.
Example layout math for 2 inner regions inside a 560-wide container:
```
container: x=60, width=560
inner padding: 20 on each side → inner safe area is x=80 to x=600, width 520
gap between regions: 20
region width: (520 - 20) / 2 = 250
region A: x=80, width=250
region B: x=350, width=250
```
For 3 inner regions:
```
inner safe area: width 520
gaps: 2 × 20 = 40
region width: (520 - 40) / 3 ≈ 160
regions at x = 80, 260, 440 (all width 160)
```
## External inputs and outputs
Arrows entering or leaving the container represent external data, requests, or physical flows. They sit outside the container with arrows pointing in or out:
```svg
<text class="ts" x="40" y="185" text-anchor="middle">Request</text>
<line x1="40" y1="200" x2="58" y2="200" class="arr" marker-end="url(#arrow)"/>
```
Rules:
- External labels are ≤2 words ("Request", "Output", "Cold water", "Sunlight"). Long labels belong in prose around the diagram.
- Place the text label directly above the arrow, `text-anchor="middle"` aligned with the arrow's horizontal center.
- Leave 2px of gap between the arrow endpoint and the container edge.
- If you have multiple inputs/outputs, stack them vertically at the same x coordinate with 4060px spacing between them.
## Internal arrows between regions
Sometimes two inner regions talk to each other. Draw an arrow between them with a short text label centered above or below:
```svg
<text class="ts" x="305" y="175" text-anchor="middle">Books</text>
<line x1="330" y1="185" x2="370" y2="185" class="arr" marker-end="url(#arrow)"/>
```
Keep these labels to 12 words. If the arrow's meaning is obvious from the region names (e.g., "Request Router" → "Auth Service"), skip the label entirely.
## What goes inside a region
Text only. A region is not a container for another flowchart — if you find yourself drawing a nested flowchart inside a region, you've reached the nesting limit. Split it into a separate diagram.
Each region has:
- A title (`th` class, 14px bold)
- An optional subtitle (`ts` class, 12px, ≤5 words) describing what happens there
- Nothing else. No icons, no illustrations, no mini-boxes inside
**Exception — subsystem architecture pattern.** When the topic is "two or three parallel subsystems cooperating" (see "Subsystem architecture pattern" below), each sibling container *may* contain a short internal flow of up to 5 flowchart-style nodes with arrows between them. This is the only structural layout where a region holds more than text, and the 5-node cap is a hard ceiling. If you need more than 5 nodes inside a region, the pattern isn't the right shape — split the inner flow into its own flowchart diagram and keep the structural diagram at the containment level.
## Worked example
Request: "AWS VPC with a web tier and a database tier"
Plan:
- Outer container: VPC (green, subtitle "us-east-1")
- Two inner regions side by side: "Public subnet" (teal, subtitle "Web servers") and "Private subnet" (blue, subtitle "Database")
- External input arrow: "Internet" → public subnet
- Internal arrow: public subnet → private subnet, labeled "SQL"
Layout:
- Container at x=80, y=40, width=540, height=280 → `rx="20"`
- Public subnet at x=120, y=140, width=220, height=140 → `rx="10"` (inside container with 40px padding from left, 60px below title)
- Private subnet at x=380, y=140, width=220, height=140
- Container title at y=72, subtitle at y=92
- External "Internet" arrow: from (48, 210) to (78, 210) pointing right, with text at (48, 196)
- Internal "SQL" arrow: from (350, 210) to (378, 210), with text at (364, 196)
viewBox: max_y = 40 + 280 = 320 → H = 340
## Subsystem architecture pattern
A variant for topics that have **two or three parallel subsystems cooperating** — the canonical shape is "two sibling dashed-border containers, each holding a short internal flow, with a labeled cross-system arrow linking them". Unlike the default structural diagram (outer container + inner regions), this pattern places the subsystems *side by side at the top level* and lets each one carry its own mini-flowchart.
**When to use**:
- "Pi session + background analyzer" — foreground conversation and a separate analyzer running in parallel
- "Prompt engineering vs. context engineering" — two frameworks shown side by side with their internal loops
- "Producer subsystem + consumer subsystem" — a queue-like split where each side has its own internal pipeline
- "Foreground + background" workflows — any time you're comparing two pipelines that share data across a boundary
**When not to use**:
- Containment — one thing is *inside* another. Use the default outer-container pattern instead.
- A single pipeline with no peer system. That's just a flowchart.
- More than 3 siblings. Three is the hard ceiling; four already blows the horizontal budget.
### Sibling containers
Each sibling is a **dashed-border** rounded rect. Use **inline `stroke-dasharray="4 4"`** on the rect rather than a CSS class — dashed is a one-off container style, not a reusable shape property, so the template's class list stays stable. The stroke color still comes from a `c-{ramp}` class on the wrapping `<g>` so dark mode works.
```svg
<g class="c-gray">
<rect x="20" y="40" width="315" height="260" rx="20"
fill="none" stroke-dasharray="4 4"/>
<text class="th" x="40" y="64" dominant-baseline="central">Pi session</text>
<text class="ts" x="40" y="82" dominant-baseline="central">Foreground conversation</text>
</g>
```
Rules:
- **Fill is `none`.** The dashed border reads as "this is a schematic region", not "this is a solid box". A filled sibling container fights with its internal nodes for the reader's attention.
- **Stroke comes from the `c-{ramp}` class.** Dark-mode handling is automatic.
- **Title at top-left**, not top-center — siblings compete for the top-center axis, so pull each title to the inside corner. Title at `(container_x + 20, container_y + 24)`, `text-anchor="start"`.
- **Optional subtitle** (`ts`) directly below the title at `y = title_y + 18`, also left-anchored. ≤5 words.
- **Pick ramps so the siblings feel related but distinct.** Same-category (foreground + background → gray + teal). Different-category (prompt engineering + context engineering → purple + teal). Never use the same ramp on both siblings.
### Layout math (2-up)
See `layout-math.md` → "Sibling subsystem containers (2-up)" for the full formula. The standard geometry:
```
container A x=20, y=40, w=315, h=260, rx=20
container B x=345, y=40, w=315, h=260, rx=20
gap = 10 px
interior A x=40 to x=315 (width 275)
interior B x=365 to x=640 (width 275)
```
### Internal nodes inside a sibling
A sibling container may hold **up to 5 flowchart-style nodes** with arrows between them — this is the explicit exception to the "region is text only" rule in the "What goes inside a region" section above. Use the standard flowchart node templates (`c-{ramp}` rect 44 or 56 tall). Center each node at the interior x (`container_x + container_w/2`) unless there's a specific left-to-right sub-flow.
Keep the internal flow **vertical** inside each sibling. The 275px interior width isn't enough for a horizontal pipeline of 3+ nodes with proper breathing room, and a vertical stack gives the cross-system arrow somewhere clean to land.
Rules:
- **≤5 nodes per sibling**. Hard cap. More than that and the pattern isn't the right shape.
- **Same title color as the container** — the internal nodes inherit the sibling's ramp unless one specific node deserves a second accent color.
- **Node width ≤ 235** (interior 275 minus 20px padding each side), typically 180.
- **No nested sibling containers.** A sibling cannot itself be a subsystem architecture diagram.
### Cross-system arrows
The point of the pattern is usually the **labeled arrows** crossing between siblings. Draw them across the 10px container gap. Unlike the external-input arrows at the top of this file, cross-system arrows get a label above (not beside) and use the solid `.arr` class.
```svg
<text class="ts" x="340" y="136" text-anchor="middle">Event</text>
<line x1="315" y1="146" x2="345" y2="146" class="arr" marker-end="url(#arrow)"/>
```
Rules:
- **Label ≤3 words.** "Event", "Session context", "Summary write-back". Anything longer belongs in prose.
- **Label position**: centered horizontally at the gap midpoint (`x=340` for the 20-345 layout), `y = arrow_y 10`, `text-anchor="middle"`, `class="ts"`.
- **Arrow row**: `y` matches the row of the source and target nodes so the line is flat. If the source is on row 1 and the target on row 2, pick the row closer to where the reader's eye lands (usually the target).
- **Bidirectional exchanges**: draw two separate single-headed arrows at slightly offset y values (`y` and `y + 12`), each with its own label. Never use a double-headed marker — the asymmetry of the two labels *is* the information.
### Worked example — Pi session + Background analyzer
Two siblings: a foreground conversation (`Pi session`, gray) and a background analyzer (`Background analyzer`, teal). The session emits events to the analyzer; the analyzer writes summaries back into the session's memory.
Plan:
- Container A "Pi session" at x=20, w=315, h=260
- Container B "Background analyzer" at x=345, w=315, h=260
- Three internal nodes in each sibling, stacked vertically
- Two cross-system arrows: row 1 left→right labeled "Event", row 3 right→left labeled "Summary"
- viewBox: `max_y = 40 + 260 = 300` → H = 320
```svg
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 680 320" font-family="...">
<style>...</style>
<defs><marker id="arrow" .../></defs>
<g class="c-gray">
<rect x="20" y="40" width="315" height="260" rx="20"
fill="none" stroke-dasharray="4 4"/>
<text class="th" x="40" y="64" dominant-baseline="central">Pi session</text>
<text class="ts" x="40" y="82" dominant-baseline="central">Foreground conversation</text>
</g>
<g class="c-teal">
<rect x="345" y="40" width="315" height="260" rx="20"
fill="none" stroke-dasharray="4 4"/>
<text class="th" x="365" y="64" dominant-baseline="central">Background analyzer</text>
<text class="ts" x="365" y="82" dominant-baseline="central">Runs in parallel</text>
</g>
<g class="c-gray">
<rect x="87" y="118" width="180" height="44" rx="6"/>
<text class="th" x="177" y="140" text-anchor="middle" dominant-baseline="central">User turn</text>
</g>
<g class="c-gray">
<rect x="87" y="180" width="180" height="44" rx="6"/>
<text class="th" x="177" y="202" text-anchor="middle" dominant-baseline="central">Pi responds</text>
</g>
<g class="c-gray">
<rect x="87" y="242" width="180" height="44" rx="6"/>
<text class="th" x="177" y="264" text-anchor="middle" dominant-baseline="central">Memory updated</text>
</g>
<g class="c-teal">
<rect x="412" y="118" width="180" height="44" rx="6"/>
<text class="th" x="502" y="140" text-anchor="middle" dominant-baseline="central">Analyze turn</text>
</g>
<g class="c-teal">
<rect x="412" y="180" width="180" height="44" rx="6"/>
<text class="th" x="502" y="202" text-anchor="middle" dominant-baseline="central">Write summary</text>
</g>
<g class="c-teal">
<rect x="412" y="242" width="180" height="44" rx="6"/>
<text class="th" x="502" y="264" text-anchor="middle" dominant-baseline="central">Push to memory</text>
</g>
<line x1="177" y1="162" x2="177" y2="180" class="arr" marker-end="url(#arrow)"/>
<line x1="177" y1="224" x2="177" y2="242" class="arr" marker-end="url(#arrow)"/>
<line x1="502" y1="162" x2="502" y2="180" class="arr" marker-end="url(#arrow)"/>
<line x1="502" y1="224" x2="502" y2="242" class="arr" marker-end="url(#arrow)"/>
<text class="ts" x="340" y="130" text-anchor="middle">Event</text>
<line x1="267" y1="140" x2="412" y2="140" class="arr" marker-end="url(#arrow)"/>
<text class="ts" x="340" y="254" text-anchor="middle">Summary</text>
<line x1="412" y1="264" x2="267" y2="264" class="arr" marker-end="url(#arrow)"/>
</svg>
```
Notes on this example:
- The two sibling containers are drawn **first** in source order so every internal node paints on top of the dashed border.
- The cross-system arrows are labeled above and span the 10px gap plus the 20px padding on each side (so the actual horizontal run is 267 → 412 = 145px).
- The "Event" label sits above the top cross-system arrow, the "Summary" label above the bottom one — both ≤2 words, both `class="ts"`, both `text-anchor="middle"` centered at x=340 (the midpoint of the 10px gap).
- Row-to-row internal arrows inside each sibling are standard vertical `.arr` lines between node top/bottom edges with a 10px stand-off.
## Bus topology sub-pattern
For topics where N agents all publish to and subscribe from a **shared message bus***"multiple workers coordinating via a central channel"*, image #7 (Message Bus) in the Anthropic reference set. A central horizontal bar represents the bus; agents sit in a row above and below it, each connected via a pair of offset arrows (see `glyphs.md` → "Publish/subscribe arrow pair").
**When to use.**
- "Message bus / event bus coordination"
- "Pub/sub topology with N publishers and N subscribers"
- "Shared queue everyone reads and writes"
- The reader needs to feel that *no agent talks to another agent directly* — all coordination passes through the bus.
**When not to use.** If the coordination is point-to-point (agent A only talks to agent B), it's just a structural arrow. If there's a clear orchestrator controlling the workers, use the "Rich interior for subsystem containers" fan-out variant below (image #9 left half), not the bus topology.
### Geometry
The bus bar is the visual spine of the diagram. Agents fan out above and below it. See also `layout-math.md` → "Bus topology geometry".
| Element | Coordinates |
|----------------------|-----------------------------------------------------------|
| Bus bar | `x=40 y=280 w=600 h=40 rx=20`, class `c-amber` or `c-gray`|
| Bus label | `(340, 304)`, class `th`, `text-anchor="middle"` |
| Top agent row y | `80` (box top); `h=60` (two-line) |
| Bottom agent row y | `400` (box top); `h=60` |
| Agent row box width | 140 (three agents) or 180 (two agents) or 110 (four) |
For **N=3 agents per row** (6 total), center the three agents at `x = 170, 340, 510` with `w=140`. For N=4 per row (8 total), center at `x = 120, 260, 420, 560` with `w=110`. For N=2 per row (4 total), center at `x = 180, 500` with `w=180`.
The bus bar uses `c-amber` when it's the "shared channel" of a message-bus system (amber = attention, the central thing everyone looks at) or `c-gray` when it's just structural scaffolding. Never use a cool ramp for the bus bar — the bus should feel active.
### Arrow pairs
Each agent connects to the bus with a **pair** of offset arrows: Publish (agent → bus) and Subscribe (bus → agent). The pair uses an 8px horizontal offset so the two arrows read as parallel, not concentric. See `glyphs.md` → "Publish/subscribe arrow pair" for the exact template.
For the top row, each agent's bottom edge is at `y=140`, the bus top is at `y=280`, so the arrow channel is 140px tall. Place the Publish/Subscribe labels at the channel midpoint (y=210):
```svg
<!-- Top agent at center x=340, publishing down and subscribing up -->
<line class="arr" x1="332" y1="140" x2="332" y2="280" marker-end="url(#arrow)"/>
<line class="arr" x1="348" y1="280" x2="348" y2="140" marker-end="url(#arrow)"/>
<text class="ts" x="324" y="214" text-anchor="end">Publish</text>
<text class="ts" x="356" y="214">Subscribe</text>
```
For the bottom row, mirror the y coordinates: agent top at `y=400`, bus bottom at `y=320`. The Subscribe arrow now goes up out of the bus into the agent; Publish goes down out of the agent into the bus.
### Labels on the bus bar
The bus bar is **always labeled** — a reader who can't tell if the central bar is "a bus" or "a queue" or "a shared log" will read the diagram wrong. Put a single `th` label at the bar's center: "Message bus", "Event bus", "Shared log", "Task queue". If the bus semantics need a second word, use a `ts` subtitle below the label (still inside the 40px-tall bar, `y = bar_y + 28`).
### Dark mode
All the bus-topology elements use `c-{ramp}` classes and stock `arr` utilities, so dark mode is automatic. The only thing to watch: if you used inline `stroke="#..."` on the Publish/Subscribe arrows, they won't invert. Use the unadorned `.arr` class and let the template's dark-mode override handle color.
## Radial star topology sub-pattern
For topics where a **central hub** is surrounded by N peripheral satellites that all talk to it bidirectionally — *"shared state with four workers"*, image #8 (Shared State). The hub is a single labeled box in the center; the satellites are smaller boxes at the four corners (or at radial offsets for N≠4).
**When to use.**
- "Shared state store with multiple accessors"
- "Central coordinator with N workers" where coordinator semantics are read/write, not command/control
- "Hub-and-spoke" architectures
**When not to use.** If the hub is the orchestrator *and* issues commands (one-way), it's a fan-out, not a radial star. If the satellites talk to each other (not just to the hub), the topology is a mesh, not a radial star — that's usually a sign to switch to a bus topology instead.
### Geometry (N=4)
See also `layout-math.md` → "Radial star geometry (3 / 4 / 5 / 6 satellites)".
| Element | Coordinates |
|----------------------|--------------------------------------------|
| Hub | `x=260 y=280 w=160 h=80 rx=10` |
| Satellite TL | `x=60 y=120 w=160 h=60` |
| Satellite TR | `x=460 y=120 w=160 h=60` |
| Satellite BL | `x=60 y=460 w=160 h=60` |
| Satellite BR | `x=460 y=460 w=160 h=60` |
| Hub center | `(340, 320)` |
| Satellite centers | `(140, 150)`, `(540, 150)`, `(140, 490)`, `(540, 490)` |
Hub is 80 tall to hold a 3-line label (title + subtitle + doc-icon if used). Satellites are 60 tall for a standard two-line label. viewBox H ≈ 560.
### Arrow pairs (bidirectional)
Each satellite connects to the hub with two single-headed arrows offset by 8px **perpendicular to the arrow direction**. For the top-left satellite, the arrow runs diagonally from `(220, 180)` to `(260, 280)` (approximately); offset the two lines by `(±4, ∓4)` to get clean parallel channels:
```svg
<!-- Top-left satellite to hub: outbound (satellite→hub) on top, inbound on bottom -->
<line class="arr" x1="224" y1="176" x2="264" y2="276" marker-end="url(#arrow)"/>
<line class="arr" x1="216" y1="184" x2="256" y2="284" marker-end="url(#arrow)"/>
```
Label each pair with a single `ts` label sitting *next to* the pair, not between the two lines (the 8px offset is too narrow for a label to fit). For diagonal pairs, place the label at the satellite end:
```svg
<text class="ts" x="230" y="198" text-anchor="start">Read / write</text>
```
Or use one label per direction if the semantics differ (`Query` outbound, `Result` inbound).
### Hub content
The hub is the one place in a structural diagram where a **decorative icon** is allowed: drop a `doc-icon` or `terminal-icon` from `glyphs.md` into the lower half of the hub rect to reinforce what kind of hub it is. See `glyphs.md` → "Document & terminal icons" for placement math.
```svg
<g class="c-amber">
<rect x="260" y="280" width="160" height="80" rx="10"/>
<text class="th" x="340" y="302" text-anchor="middle">Shared state</text>
<text class="ts" x="340" y="320" text-anchor="middle">Task artifacts</text>
<!-- doc-icon placed at bottom-center of hub -->
<g transform="translate(328, 324)">
<path class="arr" d="M2 2 L16 2 L22 8 L22 26 L2 26 Z" fill="none"/>
<path class="arr" d="M16 2 L16 8 L22 8" fill="none"/>
<line class="arr" x1="6" y1="14" x2="18" y2="14"/>
<line class="arr" x1="6" y1="18" x2="18" y2="18"/>
<line class="arr" x1="6" y1="22" x2="14" y2="22"/>
</g>
</g>
```
### Color budget
The hub takes the accent ramp (amber is the convention for shared-state hubs — everyone looks at it). Satellites stay **neutral** (`c-gray`) unless one satellite is distinguished from the others. Mixing four different ramps on four satellites is "rainbow" — it implies four different kinds of worker, which isn't what a radial star is saying.
### N≠4 variants
See `layout-math.md` for the full coordinate table. Summary:
- **N=3**: satellites at `(140, 100)`, `(540, 100)`, `(340, 500)` (two on top, one bottom center).
- **N=5**: four corners as in N=4, plus one at `(340, 100)` top center.
- **N=6**: three on top at `x=100, 340, 580` and three on bottom at the same x's (y=100 top, y=500 bottom).
Beyond N=6 the pattern doesn't fit the 680 viewBox — switch to a bus topology.
## Rich interior for subsystem containers
The base subsystem-container rule from "Subsystem architecture pattern" above says each sibling holds *up to 5 flowchart-style nodes in a vertical column*. This sub-section extends that rule: a sibling may instead hold **any one** of the following interior layouts. Each has its own geometry within the 315-wide container; mix-and-match across siblings is fine (e.g., container A holds a checklist, container B holds a DAG).
Pick the interior type that matches the subsystem's semantics:
| Interior type | Use for | See |
|---------------------------|--------------------------------------------------------|----------------------------------------------|
| Vertical flowchart | Sequential pipeline (the default) | "Internal nodes inside a sibling" above |
| Fan-out (hub + ≤3 branches) | Orchestrator dispatching to workers (image #9 left) | Below |
| Queue + vertical fan-out | Worker pool with a shared queue (image #9 right) | Below |
| Mini bus topology | Bus-coordinated workers (image #10 right) | Below |
| Checklist | Task list using `checkbox-*` glyphs (image #4 left) | `glyphs.md` → "Checkboxes" |
| DAG (≤6 nodes) | Task graph with dependencies (image #4 right) | Below |
| Nested container + gadget | Thing-within-a-thing + attached tool (image #14) | "Attached gadget box" below |
### Fan-out interior
Hub box + three worker boxes in a vertical column, inside a 315-wide container at x=20 or x=345.
| Element | Container A (x=20) | Container B (x=345) |
|---------------|---------------------------------|---------------------------------|
| Hub box | `x=50 y=120 w=120 h=44 rx=6` | `x=375 y=120 w=120 h=44 rx=6` |
| Worker 1 | `x=195 y=100 w=120 h=44` | `x=520 y=100 w=120 h=44` |
| Worker 2 | `x=195 y=160 w=120 h=44` | `x=520 y=160 w=120 h=44` |
| Worker 3 | `x=195 y=220 w=120 h=44` | `x=520 y=220 w=120 h=44` |
| Bend channel | `x=185` | `x=510` |
Route each worker arrow as a short L-bend: hub right-edge → bend channel → worker left-edge. The same routing logic as `flowchart.md` → "Vertical fan-out", scaled to the 315-wide container.
### Queue + vertical fan-out interior
Same as the fan-out interior but the hub box carries a `queue-slot` row in its bottom half (see `flowchart.md` → "Queue glyph inside a box"). Hub box height grows to 52 to accommodate the glyph row:
| Element | Coordinates (container A) |
|---------------|-----------------------------------|
| Hub (queue) | `x=50 y=116 w=120 h=52 rx=6` |
| Workers | same as fan-out interior |
Hub title `y = 134`, queue row `y = 146`, 4 slots at `x = 62, 82, 102, 122`. (Fewer slots than the full 6 because the container is narrow.)
### Mini bus topology interior
A small bus bar and 23 mini-agents above/below it, scaled down to fit inside a 315-wide container:
| Element | Container A (x=20) |
|------------------|-----------------------------------|
| Bus bar | `x=40 y=200 w=275 h=28 rx=14` |
| Bus label | `(177, 218)`, `th` |
| Top agent 1 | `x=50 y=110 w=100 h=44` |
| Top agent 2 | `x=195 y=110 w=100 h=44` |
| Bottom agent 1 | `x=50 y=260 w=100 h=44` |
| Bottom agent 2 | `x=195 y=260 w=100 h=44` |
The mini bus drops the Publish/Subscribe text labels (no room) and just shows the offset arrow pairs — the outer container's title already names the pattern. Use `c-amber` on the bus bar.
### DAG interior
Up to 6 small boxes connected by L-bend arrows, representing a task graph with dependencies. Use this for image #4's "Tasks" right-side panel.
Boxes are small (80 × 32) and laid out on a 3-column × 2-row grid inside the container:
| Grid position | x (container A) | x (container B) |
|-----------------|-----------------|-----------------|
| Column 1 | 40 | 365 |
| Column 2 | 145 | 470 |
| Column 3 | 250 | 575 |
Box height: 32. Row y: `120, 200`. `rx=4` (smaller than standard 6 because the boxes are tight).
Dashed future-state nodes (`arr-alt` class — see "Dashed future-state node" below) intermix with solid nodes in the same grid, representing the not-yet-scheduled parts of the graph.
### Checklist interior
A column of `checkbox-*` glyphs plus `t` labels inside the container. See `glyphs.md` → "Checklist rows" for row geometry. For a 315-wide container:
- First row at `y = 116`
- Row pitch: 22
- Checkbox anchor at `x = container_x + 20`
- Label anchor at `x = container_x + 42`
- Label width budget: container interior width 42 20 = 253 px (≈31 Latin / 16 CJK chars)
Up to 8 rows fit in a 260-tall container (8 × 22 = 176, plus header + padding).
## Mixed arrow semantics
Sub-pattern for diagrams — especially advisor-strategy and multi-agent architectures (image #11) — where **multiple kinds of relationships** exist on the same canvas: synchronous call, asynchronous notification, read/write data flow, and a reentry loop. Using `.arr` for all of them strips the distinction; using random colors for different line types triggers the "color rainbow" pitfall.
The solution is a **4-class arrow vocabulary** with a tiny legend strip inside the container.
### The vocabulary
| Arrow style | CSS class | Semantic | Typical label |
|---------------------------------|-------------------|--------------------------------------------|---------------------|
| Solid 1.5px | `arr` / `arr-{ramp}` | Synchronous call, required path | "calls", "invokes" |
| Dashed 1.5px | `arr-alt` | Asynchronous, optional, conditional | "notifies", "may call" |
| Two offset single-headed arrows | `arr` ×2 | Bidirectional read/write on shared resource | "read / write" |
| U-shaped reentry path | `arr` | Main loop, reentry to top of flow | "loop" |
This is the only place in the skill that **four distinct line styles** appear in one diagram — elsewhere, two is the cap. The cost of richness is a required legend strip.
### Legend strip
Place a one-line mini-legend inside the container at the top, below the container title, using `ts`-class text and tiny 20px example line segments:
```svg
<g transform="translate(40, 108)">
<!-- Solid = calls -->
<line class="arr" x1="0" y1="6" x2="20" y2="6" marker-end="url(#arrow)"/>
<text class="ts" x="24" y="10">calls</text>
<!-- Dashed = notifies -->
<line class="arr-alt" x1="80" y1="6" x2="100" y2="6" marker-end="url(#arrow)"/>
<text class="ts" x="104" y="10">notifies</text>
<!-- Pair = read/write -->
<line class="arr" x1="170" y1="2" x2="190" y2="2" marker-end="url(#arrow)"/>
<line class="arr" x1="190" y1="10" x2="170" y2="10" marker-end="url(#arrow)"/>
<text class="ts" x="194" y="10">read / write</text>
</g>
```
Keep the legend to 34 entries (the ones that actually appear in the diagram — don't document every possible edge type). The legend is always `ts` muted, never accent color — it's meta-information.
### U-shaped reentry loop
A solid arrow path that exits the right side of the final node, arcs around the bottom of the diagram, and re-enters the left side of the first node. Used for "main loop runs every turn" semantics.
```svg
<path class="arr"
d="M 560 200 L 600 200 L 600 330 L 80 330 L 80 200 L 120 200"
fill="none" marker-end="url(#arrow)"/>
<text class="ts" x="340" y="324" text-anchor="middle">runs every turn</text>
```
The horizontal return channel (`y=330` in the example) must lie in empty space below all other boxes. If it can't, use a `↻ runs every turn` text label next to the final node instead, same as the simple-flowchart return convention.
### Pitfall
Don't invent new arrow classes (`.arr-read`, `.arr-write`, `.arr-async`). The four-style vocabulary above is comprehensive; anything else is a template change and breaks the "minimal CSS" rule. If your diagram genuinely needs a 5th semantic, you're asking one diagram to do too much — split it.
## Multi-line box body
Most structural boxes hold one or two lines of text. Advisor-strategy and agent-role diagrams (image #11) sometimes need **three-line boxes**: a title, a role/kind subtitle, and a meta line like "runs every turn" or "executor · sonnet". This sub-section documents the layout.
### Geometry
| Element | Coordinates |
|-----------------|------------------------------------|
| Host rect | `h = 80`, `rx=6`, `w ≥ 180` |
| Title `th` | `y = rect_y + 22`, `text-anchor="middle"` |
| Role `ts` | `y = rect_y + 42`, italic (see below) |
| Meta `ts` | `y = rect_y + 62`, muted (see below) |
Row pitch is 20 (tight). The 80px total is the minimum — if you need more breathing room, grow to 88 or 92, but never less than 80.
### Style variations on the two subtitles
The `ts` class renders as muted 12px in both modes. For the role line (middle), apply italic via an inline `font-style="italic"` attribute. For the meta line (bottom), leave it plain `ts` — it inherits the muted color automatically.
```svg
<g class="c-teal">
<rect x="80" y="140" width="180" height="80" rx="6"/>
<text class="th" x="170" y="162" text-anchor="middle">Advisor</text>
<text class="ts" x="170" y="182" text-anchor="middle" font-style="italic">opus · reasoning</text>
<text class="ts" x="170" y="202" text-anchor="middle">runs every turn</text>
</g>
```
### Pitfall
Three-line boxes are dense. Don't use them when a two-line box will do. If you find yourself adding a third line *to every box* in the diagram, the diagram is carrying too much information — move the metadata out to the annotation column or a caption.
## Attached gadget box
A small "attached tool" box that hangs off a parent box via a short connector with no arrowhead. Used in image #14 (Code execution vs. Dedicated tool) to show that "Tools" is an attached capability of the Claude box, not a peer or a pipeline step.
### Geometry
| Element | Coordinates relative to parent |
|---------------|------------------------------------------------------|
| Connector | from `(parent_cx, parent_bottom)` to `(parent_cx, parent_bottom + 24)`, class `arr` **without** `marker-end` |
| Child rect | `x = parent_cx 60`, `y = parent_bottom + 24`, `w=120 h=56 rx=6` |
| Child title | `y = child_y + 22`, `th` |
| Child subtitle | `y = child_y + 40`, `ts` |
The child is centered under the parent. The short connector is a plain line (no arrow) — the gadget is attached, not called.
### Color
The gadget box inherits the parent's ramp if it's a direct extension (Claude + Tools → both `c-amber`). If the gadget is a *distinct thing attached to* the parent (Claude + External database → `c-amber` Claude + `c-gray` database), color them separately.
### Pitfall
Don't over-use this. One attached gadget per diagram is fine; three or more and the gadgets start to look like real workflow steps. If you need to attach three things to a parent, you're describing a fan-out, not gadgetry.
## Dashed future-state node
Sub-pattern for diagrams that distinguish **current state** (active, realized) from **future state** (planned, not yet scheduled) — image #4's "Tasks" panel, where Task 4 sits ghosted in the DAG because it hasn't been assigned yet.
### The rule
Use the existing `.arr-alt` class on the rect. It already provides `fill: none`, `stroke-width: 1.5`, `stroke-dasharray: 5 4`, and dark-mode handling:
```svg
<g>
<rect class="arr-alt" x="200" y="180" width="120" height="44" rx="6"/>
<text class="ts" x="260" y="205" text-anchor="middle">Task 4</text>
</g>
```
**Do not** create a new `.box-future` CSS class. The template's class list stays stable — future-state styling is fully expressible with what already exists.
**Do not** put a title (`th`) inside a dashed future rect. Future-state is demoted — use only `ts` (12px muted) for the label. A dashed rect with a bold title reads as contradiction: "this is a real thing but it's tentative?" — pick one.
### Mixing with active nodes in a DAG
When a DAG contains both active (solid) and future (dashed) nodes, keep the geometry identical across both types — same rect width, height, rx, y-coordinate. The only difference should be the stroke dasharray and the text weight. Any other difference (padding, shadow, label size) confuses the reader.
Route arrows into a dashed rect with the `.arr-alt` class too, and *out* of a dashed rect with `.arr-alt` — the "not yet scheduled" status is contagious forward in the graph. Arrows going *from a solid into a dashed* use solid `.arr` (the active task is scheduled to emit into the future task once it runs).
## Network topology sub-pattern
See `references/structural-network.md`. **Load it when the prompt asks about network infrastructure**: "where do the wires go", "which zone is this device in", "DMZ / firewall / VPC topology", security zones, or device connectivity.
## Comparison matrix sub-pattern
See `references/structural-matrix.md`. **Load it when the content is a feature comparison**: "which of these databases supports X", side-by-side feature tables, ✓/✗ grids, or any "option × attribute" matrix.
## Common failure modes
- **Hierarchy flattens** — parent and child use the same `c-{ramp}` class. Fix: pick different ramps.
- **Overflowing inner regions** — two 250-wide regions + 20 gap + 40 padding = 560, fits a 560-wide outer container exactly with no breathing room. Widen the outer container to 580 or shrink the inner regions.
- **External arrow with `text-anchor="end"` at low x** — the label extends past x=0 and clips. Use `text-anchor="middle"` for centered labels or `"start"` for labels that extend right.
- **Trying to draw literal shapes for the container** — don't draw an actual cell ellipse or a literal server tower. Rounded rects with clear labels read better than shapes that try to be literal. Save illustrative drawing for `illustrative.md` type diagrams.
- **Subsystem pattern with 6+ internal nodes** — the ≤5-node cap per sibling is the ceiling. Beyond that, the internal flow wants to live in its own flowchart diagram, and the structural diagram should step up one level to just the containment picture.
- **Subsystem pattern used for containment** — if one subsystem is logically *inside* the other, don't make them siblings. Nest them the normal way and skip the dashed-border trick.
@@ -0,0 +1,219 @@
# SVG Template
Every diagram this skill produces starts with the same boilerplate: root `<svg>` element, an embedded `<style>` block that defines all color classes (including dark mode), and a `<defs>` block with the arrow marker. Copy this template verbatim into every diagram, then write your visual elements after the closing `</defs>`.
**Why we embed the styles.** In claude.ai's Imagine runtime, classes like `c-blue`, `t`, `ts`, `th` are pre-loaded by the host. A standalone SVG dropped into a WeChat article or a Notion page has no such host — it has to carry its own styles. The `<style>` block below reproduces the Imagine class system as self-contained CSS so every SVG renders correctly anywhere.
## The template
Fill in `H` with the actual viewBox height computed from your content (see `layout-math.md`). Leave everything else exactly as written.
```svg
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 680 H" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif">
<style>
.t { font-size: 14px; font-weight: 400; fill: #2C2C2A; }
.ts { font-size: 12px; font-weight: 400; fill: #5F5E5A; }
.th { font-size: 14px; font-weight: 500; fill: #2C2C2A; }
.title { font-size: 20px; font-weight: 600; fill: #2C2C2A; }
.eyebrow { font-size: 10px; font-weight: 500; fill: #888780; letter-spacing: 1.2px; text-transform: uppercase; }
.caption { font-size: 12px; font-weight: 400; fill: #888780; font-style: italic; }
.anno { font-size: 12px; font-weight: 400; fill: #888780; }
.box { fill: #F1EFE8; stroke: #B4B2A9; stroke-width: 0.5; }
.row-alt { fill: #FFFFFF; stroke: #D3D1C7; stroke-width: 0.5; }
.arr { fill: none; stroke: #5F5E5A; stroke-width: 1.5; }
.arr-alt { fill: none; stroke: #5F5E5A; stroke-width: 1.5; stroke-dasharray: 5 4; }
.leader{ fill: none; stroke: #B4B2A9; stroke-width: 0.5; stroke-dasharray: 3 3; }
.lifeline { fill: none; stroke: #B4B2A9; stroke-width: 1; stroke-dasharray: 4 4; }
.arr-gray { fill: none; stroke: #5F5E5A; stroke-width: 1.5; }
.arr-blue { fill: none; stroke: #185FA5; stroke-width: 1.5; }
.arr-teal { fill: none; stroke: #0F6E56; stroke-width: 1.5; }
.arr-purple { fill: none; stroke: #534AB7; stroke-width: 1.5; }
.arr-coral { fill: none; stroke: #993C1D; stroke-width: 1.5; }
.arr-pink { fill: none; stroke: #993556; stroke-width: 1.5; }
.arr-amber { fill: none; stroke: #854F0B; stroke-width: 1.5; }
.arr-green { fill: none; stroke: #3B6D11; stroke-width: 1.5; }
.arr-red { fill: none; stroke: #A32D2D; stroke-width: 1.5; }
.c-gray > rect, .c-gray > circle, .c-gray > ellipse, rect.c-gray, circle.c-gray, ellipse.c-gray { fill: #F1EFE8; stroke: #5F5E5A; stroke-width: 0.5; }
.c-gray .th, .c-gray .t { fill: #444441; }
.c-gray .ts { fill: #5F5E5A; }
.c-blue > rect, .c-blue > circle, .c-blue > ellipse, rect.c-blue, circle.c-blue, ellipse.c-blue { fill: #E6F1FB; stroke: #185FA5; stroke-width: 0.5; }
.c-blue .th, .c-blue .t { fill: #0C447C; }
.c-blue .ts { fill: #185FA5; }
.c-teal > rect, .c-teal > circle, .c-teal > ellipse, rect.c-teal, circle.c-teal, ellipse.c-teal { fill: #E1F5EE; stroke: #0F6E56; stroke-width: 0.5; }
.c-teal .th, .c-teal .t { fill: #085041; }
.c-teal .ts { fill: #0F6E56; }
.c-purple > rect, .c-purple > circle, .c-purple > ellipse, rect.c-purple, circle.c-purple, ellipse.c-purple { fill: #EEEDFE; stroke: #534AB7; stroke-width: 0.5; }
.c-purple .th, .c-purple .t { fill: #3C3489; }
.c-purple .ts { fill: #534AB7; }
.c-coral > rect, .c-coral > circle, .c-coral > ellipse, rect.c-coral, circle.c-coral, ellipse.c-coral { fill: #FAECE7; stroke: #993C1D; stroke-width: 0.5; }
.c-coral .th, .c-coral .t { fill: #712B13; }
.c-coral .ts { fill: #993C1D; }
.c-pink > rect, .c-pink > circle, .c-pink > ellipse, rect.c-pink, circle.c-pink, ellipse.c-pink { fill: #FBEAF0; stroke: #993556; stroke-width: 0.5; }
.c-pink .th, .c-pink .t { fill: #72243E; }
.c-pink .ts { fill: #993556; }
.c-amber > rect, .c-amber > circle, .c-amber > ellipse, rect.c-amber, circle.c-amber, ellipse.c-amber { fill: #FAEEDA; stroke: #854F0B; stroke-width: 0.5; }
.c-amber .th, .c-amber .t { fill: #633806; }
.c-amber .ts { fill: #854F0B; }
.c-green > rect, .c-green > circle, .c-green > ellipse, rect.c-green, circle.c-green, ellipse.c-green { fill: #EAF3DE; stroke: #3B6D11; stroke-width: 0.5; }
.c-green .th, .c-green .t { fill: #27500A; }
.c-green .ts { fill: #3B6D11; }
.c-red > rect, .c-red > circle, .c-red > ellipse, rect.c-red, circle.c-red, ellipse.c-red { fill: #FCEBEB; stroke: #A32D2D; stroke-width: 0.5; }
.c-red .th, .c-red .t { fill: #791F1F; }
.c-red .ts { fill: #A32D2D; }
@media (prefers-color-scheme: dark) {
.t, .th { fill: #F1EFE8; }
.ts { fill: #B4B2A9; }
.title { fill: #F1EFE8; }
.eyebrow { fill: #888780; }
.caption { fill: #888780; }
.anno { fill: #888780; }
.box { fill: #2C2C2A; stroke: #888780; }
.row-alt { fill: #444441; stroke: #5F5E5A; }
.arr { stroke: #B4B2A9; }
.arr-alt { stroke: #B4B2A9; }
.leader { stroke: #888780; }
.lifeline { stroke: #5F5E5A; }
.arr-gray { stroke: #B4B2A9; }
.arr-blue { stroke: #85B7EB; }
.arr-teal { stroke: #5DCAA5; }
.arr-purple { stroke: #AFA9EC; }
.arr-coral { stroke: #F0997B; }
.arr-pink { stroke: #ED93B1; }
.arr-amber { stroke: #EF9F27; }
.arr-green { stroke: #97C459; }
.arr-red { stroke: #F09595; }
.c-gray > rect, .c-gray > circle, .c-gray > ellipse, rect.c-gray, circle.c-gray, ellipse.c-gray { fill: #444441; stroke: #B4B2A9; }
.c-gray .th, .c-gray .t { fill: #F1EFE8; }
.c-gray .ts { fill: #D3D1C7; }
.c-blue > rect, .c-blue > circle, .c-blue > ellipse, rect.c-blue, circle.c-blue, ellipse.c-blue { fill: #0C447C; stroke: #85B7EB; }
.c-blue .th, .c-blue .t { fill: #B5D4F4; }
.c-blue .ts { fill: #85B7EB; }
.c-teal > rect, .c-teal > circle, .c-teal > ellipse, rect.c-teal, circle.c-teal, ellipse.c-teal { fill: #085041; stroke: #5DCAA5; }
.c-teal .th, .c-teal .t { fill: #9FE1CB; }
.c-teal .ts { fill: #5DCAA5; }
.c-purple > rect, .c-purple > circle, .c-purple > ellipse, rect.c-purple, circle.c-purple, ellipse.c-purple { fill: #3C3489; stroke: #AFA9EC; }
.c-purple .th, .c-purple .t { fill: #CECBF6; }
.c-purple .ts { fill: #AFA9EC; }
.c-coral > rect, .c-coral > circle, .c-coral > ellipse, rect.c-coral, circle.c-coral, ellipse.c-coral { fill: #712B13; stroke: #F0997B; }
.c-coral .th, .c-coral .t { fill: #F5C4B3; }
.c-coral .ts { fill: #F0997B; }
.c-pink > rect, .c-pink > circle, .c-pink > ellipse, rect.c-pink, circle.c-pink, ellipse.c-pink { fill: #72243E; stroke: #ED93B1; }
.c-pink .th, .c-pink .t { fill: #F4C0D1; }
.c-pink .ts { fill: #ED93B1; }
.c-amber > rect, .c-amber > circle, .c-amber > ellipse, rect.c-amber, circle.c-amber, ellipse.c-amber { fill: #633806; stroke: #EF9F27; }
.c-amber .th, .c-amber .t { fill: #FAC775; }
.c-amber .ts { fill: #EF9F27; }
.c-green > rect, .c-green > circle, .c-green > ellipse, rect.c-green, circle.c-green, ellipse.c-green { fill: #27500A; stroke: #97C459; }
.c-green .th, .c-green .t { fill: #C0DD97; }
.c-green .ts { fill: #97C459; }
.c-red > rect, .c-red > circle, .c-red > ellipse, rect.c-red, circle.c-red, ellipse.c-red { fill: #791F1F; stroke: #F09595; }
.c-red .th, .c-red .t { fill: #F7C1C1; }
.c-red .ts { fill: #F09595; }
}
</style>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</marker>
</defs>
<!-- your visual elements go here -->
</svg>
```
## Poster-flowchart utility classes
Four classes are available for poster-style flowcharts (see `flowchart.md` → "Poster flowchart pattern"). These are **optional** — simple flowcharts, structural, illustrative, and sequence diagrams should ignore them and pay nothing beyond ~300 bytes of unused CSS.
| Class | Size | Use for |
|-------------|--------|------------------------------------------------------------------------------------------|
| `.title` | 20px 600 | Diagram-level title. Used ONCE at the top when the topic has a short mechanism name. |
| `.eyebrow` | 10px 500 | Small uppercase section dividers between groups of stages. Letter-spaced, muted gray. |
| `.caption` | 12px italic | Footer hook line at the bottom of the diagram. One line, italic, muted gray. |
| `.anno` | 12px | Side-column annotation text — "sees: X / fresh context" notes beside a box. Muted gray. |
All four work in both light and dark mode via the template's `@media` block. Never use `.title`, `.eyebrow`, or `.caption` inside a regular box — they're meta-labels for the whole diagram, not cell content.
## Sequence-diagram utility classes
The `<style>` block also defines `.lifeline` (dashed vertical lifeline for sequence diagrams) and nine `.arr-{ramp}` colored-arrow utilities (`arr-gray`, `arr-blue`, `arr-teal`, `arr-purple`, `arr-coral`, `arr-pink`, `arr-amber`, `arr-green`, `arr-red`). These are only used by sequence diagrams, where each actor's messages inherit the actor's ramp color. Flowchart, structural, and illustrative diagrams ignore them and pay nothing beyond ~600 bytes of unused CSS. Arrow marker `url(#arrow)` uses `context-stroke` so arrowheads automatically match the colored stroke — never set `fill` on these paths.
## The `.row-alt` alternating-row utility
A paired companion to `.box` for **comparison-matrix tables** (see `structural.md` → "Comparison-matrix sub-pattern"). The two classes alternate to create zebra striping across rows of a matrix so the eye can follow a row across 45 columns without drifting into the next row.
- **Light mode**: `.box` = cream `#F1EFE8`, `.row-alt` = pure white `#FFFFFF` — the contrast between the two fills is deliberately low (one ramp stop) so the striping is legible but doesn't compete with the cell text.
- **Dark mode**: `.box` = near-black `#2C2C2A`, `.row-alt` = one step lighter `#444441` — same principle, inverted.
Alternate rows by applying `.box` to odd rows and `.row-alt` to even rows, or vice versa. Do **not** use either class to hint at semantic status (active / inactive / warning) — that's what `c-{ramp}` is for. `.row-alt` is purely for visual rhythm.
## The `.arr-alt` alternative-flow utility
The `<style>` block also defines `.arr-alt` — a **1.5px dashed** connector for *alternative*, *optional*, or *weak* flows. Same weight as `.arr`, but the dash pattern (`5 4`) visually demotes the connector so a reader scans the solid arrows first.
Use it when semantics call for it, not as decoration:
- **Flowchart** — the Fail branch out of a Gate, the unchosen paths in a router fan-out, the "Stop" return from an agent loop, or any conditional/optional edge that only fires part of the time.
- **Illustrative** — the spokes in a central-subject-plus-radial-attachments layout (LLM hub to Retrieval / Tools / Memory), where the attachments are *available capabilities* rather than guaranteed steps.
Do **not** use `.arr-alt` as a decorative stroke, and do not use it inside sequence diagrams (every sequence message is either there or not — there is no "maybe" in a protocol). `.arr-alt` is distinct from `.leader`: `.leader` is 0.5px hair-dashed for illustrative callout lines, `.arr-alt` is 1.5px mid-dashed for connectors that carry meaning.
## Rules for using the template
- **viewBox width is always 680.** Never change it. This is the container width every diagram is sized against. If your content is narrow, keep the width at 680 and center your content inside — do not shrink the viewBox to hug the drawing.
- **viewBox height is computed from content.** See `layout-math.md` for the formula. Rule of thumb: `H = max_y + 20` where `max_y` is the lowest point of any element (bottom of the lowest rect, baseline + 4px descent of the lowest text).
- **Arrow marker uses `context-stroke`.** This means the arrowhead automatically matches the color of whichever line it's attached to. Use `marker-end="url(#arrow)"` on any `<line>` or `<path>` connector.
- **Add a `<clipPath>` to `<defs>` only if an illustrative diagram needs one.** Nothing else belongs in `<defs>`.
- **Add a single `<linearGradient>` to `<defs>` only for illustrative diagrams** showing a continuous physical property (temperature stratification, pressure drop). Between two stops from the same ramp. Never more than one gradient per SVG.
## Using the color classes
Apply `c-{ramp}` to the `<g>` wrapper that contains both the shape and its text:
```svg
<g class="c-blue">
<rect x="100" y="20" width="180" height="44" rx="6"/>
<text class="th" x="190" y="42" text-anchor="middle" dominant-baseline="central">Login service</text>
</g>
```
Or directly to the shape itself if there's no wrapping `<g>`:
```svg
<rect class="c-blue" x="100" y="20" width="180" height="44" rx="6"/>
```
**Do not nest `c-*` groups.** The CSS uses direct-child selectors — `<g class="c-blue"><g>...</g></g>` won't apply the fill to the inner shapes. If you need a click handler (future), put it on the same group that carries the color class, not a wrapper.
## What to emit after the template
Visual elements in this order:
1. Background decorations (dashed frame for a schematic container, for example)
2. Containers (outer group rectangles for structural diagrams)
3. Connectors and arrows (so they sit behind the boxes they connect, preventing visible overlap) — both solid `.arr`/`.arr-{ramp}` primary flows and `.arr-alt` alternative/optional/weak flows belong in this layer
4. Nodes (rects with text)
5. Labels outside boxes (legend swatches, leader callouts)
When connectors and nodes fight for z-order, nodes win — draw the connectors first so the boxes paint on top of any line that crosses their edge.
+641
View File
@@ -0,0 +1,641 @@
---
name: baoyu-image-cards
description: Generates infographic image card series with 12 visual styles, 8 layouts, and 3 color palettes. Breaks content into 1-10 cartoon-style image cards optimized for social media engagement. Use when user mentions "小红书图片", "小红书种草", "小绿书", "微信图文", "微信贴图", "image cards", "图片卡片", or wants social media infographic series.
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-image-cards
---
# Image Card Series Generator
Break down complex content into eye-catching image card series with multiple style options.
## Usage
```bash
# Auto-select style and layout based on content
/baoyu-image-cards posts/ai-future/article.md
# Specify style
/baoyu-image-cards posts/ai-future/article.md --style notion
# Specify layout
/baoyu-image-cards posts/ai-future/article.md --layout dense
# Combine style and layout
/baoyu-image-cards posts/ai-future/article.md --style notion --layout list
# Specify palette (override style colors)
/baoyu-image-cards posts/ai-future/article.md --style notion --palette macaron
# Use preset (style + layout + optional palette shorthand)
/baoyu-image-cards posts/ai-future/article.md --preset knowledge-card
# Preset with override
/baoyu-image-cards posts/ai-future/article.md --preset poster --layout quadrant
# Preset with palette override
/baoyu-image-cards posts/ai-future/article.md --preset hand-drawn-edu --palette warm
# Direct content input
/baoyu-image-cards
[paste content]
# Direct input with options
/baoyu-image-cards --style bold --layout comparison
[paste content]
# Non-interactive (for scheduled tasks / automation)
/baoyu-image-cards posts/ai-future/article.md --yes
/baoyu-image-cards posts/ai-future/article.md --yes --preset knowledge-card
```
## Options
| Option | Description |
|--------|-------------|
| `--style <name>` | Visual style (see Style Gallery) |
| `--layout <name>` | Information layout (see Layout Gallery) |
| `--palette <name>` | Color palette override (see Palette Gallery) |
| `--preset <name>` | Style + layout + optional palette shorthand (see [Style Presets](references/style-presets.md)) |
| `--yes` | Non-interactive mode: skip all confirmations. Uses EXTEND.md preferences if found, otherwise uses defaults (no watermark, auto style/layout). Auto-confirms recommended plan (Path A). Suitable for scheduled tasks and automation. |
## Dimensions
| Dimension | Controls | Options |
|-----------|----------|---------|
| **Style** | Visual aesthetics: lines, decorations, rendering | cute, fresh, warm, bold, minimal, retro, pop, notion, chalkboard, study-notes, screen-print, sketch-notes |
| **Layout** | Information structure: density, arrangement | sparse, balanced, dense, list, comparison, flow, mindmap, quadrant |
| **Palette** (optional) | Color override: replaces style's default colors | macaron, warm, neon |
Style × Layout can be freely combined, with optional palette override. Example: `--style notion --layout dense` creates an intellectual-looking knowledge card with high information density. Add `--palette macaron` to swap colors to soft pastels while keeping notion's rendering style.
Or use presets: `--preset knowledge-card` → style + layout in one flag. See [Style Presets](references/style-presets.md).
**Palette behavior**:
- No `--palette` → style uses its built-in colors (or its `default_palette` if defined)
- `--palette macaron` → overrides any style's colors with macaron palette
- Palette replaces colors only; style rendering rules (line treatment, elements, textures) stay unchanged
- Some styles declare a `default_palette` (e.g., sketch-notes defaults to macaron)
## Style Gallery
| Style | Description |
|-------|-------------|
| `cute` (Default) | Sweet, adorable, girly aesthetic |
| `fresh` | Clean, refreshing, natural |
| `warm` | Cozy, friendly, approachable |
| `bold` | High impact, attention-grabbing |
| `minimal` | Ultra-clean, sophisticated |
| `retro` | Vintage, nostalgic, trendy |
| `pop` | Vibrant, energetic, eye-catching |
| `notion` | Minimalist hand-drawn line art, intellectual |
| `chalkboard` | Colorful chalk on black board, educational |
| `study-notes` | Realistic handwritten photo style, blue pen + red annotations + yellow highlighter |
| `screen-print` | Bold poster art, halftone textures, limited colors, symbolic storytelling |
| `sketch-notes` | Hand-drawn educational infographic, macaron pastels on warm cream, wobble lines |
Detailed style definitions: `references/presets/<style>.md`
## Preset Gallery
Quick-start presets by content scenario. Use `--preset <name>` or recommend during Step 2.
**Knowledge & Learning**:
| Preset | Style | Layout | Best For |
|--------|-------|--------|----------|
| `knowledge-card` | notion | dense | 干货知识卡、概念科普 |
| `checklist` | notion | list | 清单、排行榜、必备清单 |
| `concept-map` | notion | mindmap | 概念图、知识脉络 |
| `swot` | notion | quadrant | SWOT分析、四象限分类 |
| `tutorial` | chalkboard | flow | 教程步骤、操作流程 |
| `classroom` | chalkboard | balanced | 课堂笔记、知识讲解 |
| `study-guide` | study-notes | dense | 学习笔记、考试重点 |
| `hand-drawn-edu` | sketch-notes | flow | 手绘教程、流程图解 |
| `sketch-card` | sketch-notes | dense | 手绘知识卡、概念科普 |
| `sketch-summary` | sketch-notes | balanced | 手绘总结、图文笔记 |
**Lifestyle & Sharing**:
| Preset | Style | Layout | Best For |
|--------|-------|--------|----------|
| `cute-share` | cute | balanced | 少女风分享、日常种草 |
| `girly` | cute | sparse | 甜美封面、氛围感 |
| `cozy-story` | warm | balanced | 生活故事、情感分享 |
| `product-review` | fresh | comparison | 产品对比、测评 |
| `nature-flow` | fresh | flow | 健康流程、自然主题 |
**Impact & Opinion**:
| Preset | Style | Layout | Best For |
|--------|-------|--------|----------|
| `warning` | bold | list | 避坑指南、重要提醒 |
| `versus` | bold | comparison | 正反对比、强烈对照 |
| `clean-quote` | minimal | sparse | 金句、极简封面 |
| `pro-summary` | minimal | balanced | 专业总结、商务内容 |
**Trend & Entertainment**:
| Preset | Style | Layout | Best For |
|--------|-------|--------|----------|
| `retro-ranking` | retro | list | 复古排行、经典盘点 |
| `throwback` | retro | balanced | 怀旧分享、老物件 |
| `pop-facts` | pop | list | 趣味冷知识、好玩的事 |
| `hype` | pop | sparse | 炸裂封面、惊叹分享 |
**Poster & Editorial**:
| Preset | Style | Layout | Best For |
|--------|-------|--------|----------|
| `poster` | screen-print | sparse | 海报风封面、影评书评 |
| `editorial` | screen-print | balanced | 观点文章、文化评论 |
| `cinematic` | screen-print | comparison | 电影对比、戏剧张力 |
Full preset definitions: [references/style-presets.md](references/style-presets.md)
## Layout Gallery
| Layout | Description |
|--------|-------------|
| `sparse` (Default) | Minimal information, maximum impact (1-2 points) |
| `balanced` | Standard content layout (3-4 points) |
| `dense` | High information density, knowledge card style (5-8 points) |
| `list` | Enumeration and ranking format (4-7 items) |
| `comparison` | Side-by-side contrast layout |
| `flow` | Process and timeline layout (3-6 steps) |
| `mindmap` | Center radial mind map layout (4-8 branches) |
| `quadrant` | Four-quadrant / circular section layout |
Detailed layout definitions: `references/elements/canvas.md`
## Palette Gallery
Optional color override. Replaces style's built-in colors while preserving rendering rules.
| Palette | Background | Zone Colors | Accent | Feel |
|---------|------------|-------------|--------|------|
| `macaron` | Warm cream #F5F0E8 | Blue #A8D8EA, Lavender #D5C6E0, Mint #B5E5CF, Peach #F8D5C4 | Coral #E8655A | Soft, educational, approachable |
| `warm` | Soft Peach #FFECD2 | Orange #ED8936, Terracotta #C05621, Golden #F6AD55, Rose #D4A09A | Sienna #A0522D | Cozy, earth tones, no cool colors |
| `neon` | Dark Purple #1A1025 | Cyan #00F5FF, Magenta #FF00FF, Green #39FF14, Pink #FF6EC7 | Yellow #FFFF00 | High-energy, futuristic |
Detailed palette definitions: `references/palettes/<palette>.md`
## Auto Selection
| Content Signals | Style | Layout | Recommended Preset |
|-----------------|-------|--------|--------------------|
| Beauty, fashion, cute, girl, pink | `cute` | sparse/balanced | `cute-share`, `girly` |
| Health, nature, clean, fresh, organic | `fresh` | balanced/flow | `product-review`, `nature-flow` |
| Life, story, emotion, feeling, warm | `warm` | balanced | `cozy-story` |
| Warning, important, must, critical | `bold` | list/comparison | `warning`, `versus` |
| Professional, business, elegant, simple | `minimal` | sparse/balanced | `clean-quote`, `pro-summary` |
| Classic, vintage, old, traditional | `retro` | balanced | `throwback`, `retro-ranking` |
| Fun, exciting, wow, amazing | `pop` | sparse/list | `hype`, `pop-facts` |
| Knowledge, concept, productivity, SaaS | `notion` | dense/list | `knowledge-card`, `checklist` |
| Education, tutorial, learning, teaching, classroom | `chalkboard` | balanced/dense | `tutorial`, `classroom` |
| Notes, handwritten, study guide, knowledge, realistic, photo | `study-notes` | dense/list/mindmap | `study-guide` |
| Movie, album, concert, poster, opinion, editorial, dramatic, cinematic | `screen-print` | sparse/comparison | `poster`, `editorial`, `cinematic` |
| Hand-drawn, infographic, diagram, visual summary, 手绘, 图解, workflow, process | `sketch-notes` | flow/balanced/dense | `hand-drawn-edu`, `sketch-card`, `sketch-summary` |
## Outline Strategies
Three differentiated outline strategies for different content goals:
### Strategy A: Story-Driven (故事驱动型)
| Aspect | Description |
|--------|-------------|
| **Concept** | Personal experience as main thread, emotional resonance first |
| **Features** | Start from pain point, show before/after change, strong authenticity |
| **Best for** | Reviews, personal shares, transformation stories |
| **Structure** | Hook → Problem → Discovery → Experience → Conclusion |
### Strategy B: Information-Dense (信息密集型)
| Aspect | Description |
|--------|-------------|
| **Concept** | Value-first, efficient information delivery |
| **Features** | Clear structure, explicit points, professional credibility |
| **Best for** | Tutorials, comparisons, product reviews, checklists |
| **Structure** | Core conclusion → Info card → Pros/Cons → Recommendation |
### Strategy C: Visual-First (视觉优先型)
| Aspect | Description |
|--------|-------------|
| **Concept** | Visual impact as core, minimal text |
| **Features** | Large images, atmospheric, instant appeal |
| **Best for** | High-aesthetic products, lifestyle, mood-based content |
| **Structure** | Hero image → Detail shots → Lifestyle scene → CTA |
## File Structure
Each session creates an independent directory named by content slug:
```
image-cards/{topic-slug}/
├── source-{slug}.{ext} # Source files (text, images, etc.)
├── analysis.md # Deep analysis + questions asked
├── outline-strategy-a.md # Strategy A: Story-driven
├── outline-strategy-b.md # Strategy B: Information-dense
├── outline-strategy-c.md # Strategy C: Visual-first
├── outline.md # Final selected/merged outline
├── prompts/
│ ├── 01-cover-[slug].md
│ ├── 02-content-[slug].md
│ └── ...
├── 01-cover-[slug].png
├── 02-content-[slug].png
└── NN-ending-[slug].png
```
**Slug Generation**:
1. Extract main topic from content (2-4 words, kebab-case)
2. Example: "AI工具推荐" → `ai-tools-recommend`
**Conflict Resolution**:
If `image-cards/{topic-slug}/` already exists:
- Append timestamp: `{topic-slug}-YYYYMMDD-HHMMSS`
- Example: `ai-tools` exists → `ai-tools-20260118-143052`
**Source Files**:
Copy all sources with naming `source-{slug}.{ext}`:
- `source-article.md`, `source-photo.jpg`, etc.
- Multiple sources supported: text, images, files from conversation
## Workflow
### Progress Checklist
Copy and track progress:
```
Image Card Series Progress:
- [ ] Step 0: Check preferences (EXTEND.md) ⛔ BLOCKING (--yes: use defaults if not found)
- [ ] Found → load preferences → continue
- [ ] Not found → run first-time setup → MUST complete before Step 1 (--yes: skip setup, use defaults)
- [ ] Step 1: Analyze content → analysis.md
- [ ] Step 2: Smart Confirm ⚠️ REQUIRED (--yes: auto-confirm Path A)
- [ ] Path A: Quick confirm → generate recommended outline
- [ ] Path B: Customize → adjust then generate outline
- [ ] Path C: Detailed → 3 outlines → second confirm → generate outline
- [ ] Step 3: Generate images (sequential)
- [ ] Step 4: Completion report
```
### Flow
```
Input → [--yes?] ─┬─ Yes → [Step 0: Load or defaults] → Analyze → Auto-confirm → Generate → Complete
└─ No → [Step 0: Preferences] ─┬─ Found → Continue
└─ Not found → First-Time Setup ⛔ BLOCKING
└─ Complete setup → Save EXTEND.md → Continue
┌─────────────────────────────────────────────────────────────────────────────────────┘
Analyze → [Smart Confirm] ─┬─ Quick: confirm recommended → outline.md → Generate → Complete
├─ Customize: adjust options → outline.md → Generate → Complete
└─ Detailed: 3 outlines → [Confirm 2] → outline.md → Generate → Complete
```
### Step 0: Load Preferences (EXTEND.md) ⛔ BLOCKING
**Purpose**: Load user preferences or run first-time setup.
**`--yes` mode**: If EXTEND.md found → load it. If not found → use built-in defaults (no watermark, style/layout auto-select, language from content). Do NOT run first-time setup, do NOT create EXTEND.md, do NOT ask any questions. Proceed directly to Step 1.
**CRITICAL** (interactive mode only): If EXTEND.md not found, MUST complete first-time setup before ANY other questions or steps. Do NOT proceed to content analysis, do NOT ask about style, do NOT ask about layout — ONLY complete the preferences setup first.
Check EXTEND.md existence (priority order):
```bash
# macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-image-cards/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-image-cards/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-image-cards/EXTEND.md" && echo "user"
```
```powershell
# PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-image-cards/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-image-cards/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-image-cards/EXTEND.md") { "user" }
```
┌────────────────────────────────────────────────────┬───────────────────┐
│ Path │ Location │
├────────────────────────────────────────────────────┼───────────────────┤
│ .baoyu-skills/baoyu-image-cards/EXTEND.md │ Project directory │
├────────────────────────────────────────────────────┼───────────────────┤
│ $HOME/.baoyu-skills/baoyu-image-cards/EXTEND.md │ User home │
└────────────────────────────────────────────────────┴───────────────────┘
┌───────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Result │ Action │
├───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Found │ Read, parse, display summary → Continue to Step 1 │
├───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Not found │ ⛔ BLOCKING: Run first-time setup ONLY (see below) → Complete and save EXTEND.md → Then Step 1 │
└───────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────┘
**First-Time Setup** (when EXTEND.md not found):
**Language**: Use user's input language or saved language preference.
Use AskUserQuestion with ALL questions in ONE call. See `references/config/first-time-setup.md` for question details.
**EXTEND.md Supports**: Watermark | Preferred style/layout | Custom style definitions | Language preference
Schema: `references/config/preferences-schema.md`
### Step 1: Analyze Content → `analysis.md`
Read source content, save it if needed, and perform deep analysis.
**Actions**:
1. **Save source content** (if not already a file):
- If user provides a file path: use as-is
- If user pastes content: save to `source.md` in target directory
- **Backup rule**: If `source.md` exists, rename to `source-backup-YYYYMMDD-HHMMSS.md`
2. Read source content
3. **Deep analysis** following `references/workflows/analysis-framework.md`:
- Content type classification (种草/干货/测评/教程/避坑...)
- Hook analysis (爆款标题潜力)
- Target audience identification
- Engagement potential (收藏/分享/评论)
- Visual opportunity mapping
- Swipe flow design
4. Detect source language
5. Determine recommended image count (2-10)
6. **Auto-recommend** best strategy + style + layout + palette based on content signals
7. **Save to `analysis.md`**
### Step 2: Smart Confirm ⚠️
**Purpose**: Present auto-recommended plan, let user confirm or adjust.
**`--yes` mode**: Skip this entire step. Use auto-recommended strategy + style + layout + palette from Step 1 analysis (or `--style`/`--layout`/`--palette`/`--preset` if provided). Generate outline directly using Path A logic → save to `outline.md` → proceed to Step 3. No AskUserQuestion calls.
**Interactive mode**: Do NOT skip.
**Auto-Recommendation Logic**:
1. Use Auto Selection table to match content signals → best strategy + style + layout + palette
2. Infer optimal image count from content density
3. Load style's default elements from preset (apply palette override if applicable)
**Display** (analysis summary + recommended plan):
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 内容分析
主题:[topic] | 类型:[content_type]
要点:[key points summary]
受众:[target audience]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🎨 推荐方案(自动匹配)
策略:[A/B/C] [strategy name][reason]
风格:[style] · 布局:[layout] · 配色:[palette or "默认"] · 预设:[preset]
图片:[N]张(封面+[N-2]内容+结尾)
元素:[background] / [decorations] / [emphasis]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
**Use AskUserQuestion** with single question:
| Option | Description |
|--------|-------------|
| 1. ✅ 确认,直接生成(推荐) | Trust auto-recommendation, proceed immediately |
| 2. 🎛️ 自定义调整 | Modify strategy/style/layout/count in one step |
| 3. 📋 详细模式 | Generate 3 outlines, then choose (two confirmations) |
#### Path A: Quick Confirm (Option 1)
Generate single outline using recommended strategy + style → save to `outline.md` → Step 3.
#### Path B: Customize (Option 2)
**Use AskUserQuestion** with adjustable options (leave blank = keep recommended):
1. **策略风格**: Current: [strategy + style]. Options: A Story-Driven(warm) | B Information-Dense(notion) | C Visual-First(screen-print). Or specify style directly: cute/fresh/warm/bold/minimal/retro/pop/notion/chalkboard/study-notes/screen-print/sketch-notes. Or use preset: knowledge-card / checklist / tutorial / poster / hand-drawn-edu / etc.
2. **布局**: Current: [layout]. Options: sparse | balanced | dense | list | comparison | flow | mindmap | quadrant
3. **配色**: Current: [palette or "默认"]. Options: 默认 | macaron | warm | neon
4. **图片数量**: Current: [N]. Range: 2-10
5. **补充说明**(可选): Selling point emphasis, audience adjustment, custom color preference, etc.
**After response**: Generate single outline with user's choices → save to `outline.md` → Step 3.
#### Path C: Detailed Mode (Option 3)
Full two-confirmation flow for maximum control:
**Step 2a: Content Understanding**
**Use AskUserQuestion** for:
1. Core selling point (multiSelect: true)
2. Target audience
3. Style preference: Authentic sharing / Professional review / Aesthetic mood / Auto
4. Additional context (optional)
**After response**: Update `analysis.md`.
**Step 2b: Generate 3 Outline Variants**
| Strategy | Filename | Outline | Recommended Style |
|----------|----------|---------|-------------------|
| A | `outline-strategy-a.md` | Story-driven: emotional, before/after | warm, cute, fresh |
| B | `outline-strategy-b.md` | Information-dense: structured, factual | notion, minimal, chalkboard |
| C | `outline-strategy-c.md` | Visual-first: atmospheric, minimal text | bold, pop, retro, screen-print |
**Outline format** (YAML front matter + content):
```yaml
---
strategy: a # a, b, or c
name: Story-Driven
style: warm # recommended style for this strategy
palette: ~ # optional palette override (macaron, warm, neon, or ~ for style default)
style_reason: "Warm tones enhance emotional storytelling and personal connection"
elements: # from style preset, can be customized
background: solid-pastel
decorations: [clouds, stars-sparkles]
emphasis: star-burst
typography: highlight
layout: balanced # primary layout
image_count: 5
---
## P1 Cover
**Type**: cover
**Hook**: "入冬后脸不干了🥹终于找到对的面霜"
**Visual**: Product hero shot with cozy winter atmosphere
**Layout**: sparse
## P2 Problem
**Type**: pain-point
**Message**: Previous struggles with dry skin
**Visual**: Before state, relatable scenario
**Layout**: balanced
...
```
**Differentiation requirements**:
- Each strategy MUST have different outline structure AND different recommended style
- Adapt page count: A typically 4-6, B typically 3-5, C typically 3-4
- Include `style_reason` explaining why this style fits the strategy
Reference: `references/workflows/outline-template.md`
**Step 2c: Outline & Style Selection**
**Use AskUserQuestion** with three questions:
**Q1: Outline Strategy**: A / B / C / Combine (specify pages from each)
**Q2: Visual Style**: Use recommended | Select preset | Select style | Custom description
**Q3: Visual Elements**: Use defaults (Recommended) | Adjust background | Adjust decorations | Custom
**After response**: Save selected/merged outline to `outline.md` with confirmed style and elements → Step 3.
### Step 3: Generate Images
With confirmed outline + style + layout:
**Visual Consistency — Reference Image Chain**:
To ensure character/style consistency across all images in a series:
1. **Generate image 1 (cover) FIRST** — without `--ref`
2. **Use image 1 as `--ref` for ALL remaining images** (2, 3, ..., N)
- This anchors the character design, color rendering, and illustration style
- Command pattern: `--ref <path-to-image-01.png>` added to every subsequent generation
This is critical for styles that use recurring characters, mascots, or illustration elements. Image 1 becomes the visual anchor for the entire series.
**For each image (cover + content + ending)**:
1. Save prompt to `prompts/NN-{type}-[slug].md` (in user's preferred language)
- **Backup rule**: If prompt file exists, rename to `prompts/NN-{type}-[slug]-backup-YYYYMMDD-HHMMSS.md`
2. Generate image:
- **Image 1**: Generate without `--ref` (this establishes the visual anchor)
- **Images 2+**: Generate with `--ref <image-01-path>` for consistency
- **Backup rule**: If image file exists, rename to `NN-{type}-[slug]-backup-YYYYMMDD-HHMMSS.png`
3. Report progress after each generation
**Watermark Application** (if enabled in preferences):
Add to each image generation prompt:
```
Include a subtle watermark "[content]" positioned at [position].
The watermark should be legible but not distracting from the main content.
```
Reference: `references/config/watermark-guide.md`
**Image Generation Skill Selection**:
- Check available image generation skills
- If multiple skills available: ask user preference (interactive) or use first available skill (`--yes` mode)
**Session Management**:
If image generation skill supports `--sessionId`:
1. Generate unique session ID: `cards-{topic-slug}-{timestamp}`
2. Use same session ID for all images
3. Combined with reference image chain, ensures maximum visual consistency
### Step 4: Completion Report
```
Image Card Series Complete!
Topic: [topic]
Mode: [Quick / Custom / Detailed]
Strategy: [A/B/C/Combined]
Style: [style name]
Palette: [palette name or "default"]
Layout: [layout name or "varies"]
Location: [directory path]
Images: N total
✓ analysis.md
✓ outline.md
✓ outline-strategy-a/b/c.md (detailed mode only)
Files:
- 01-cover-[slug].png ✓ Cover (sparse)
- 02-content-[slug].png ✓ Content (balanced)
- 03-content-[slug].png ✓ Content (dense)
- 04-ending-[slug].png ✓ Ending (sparse)
```
## Image Modification
| Action | Steps |
|--------|-------|
| **Edit** | **Update prompt file FIRST** → Regenerate with same session ID |
| **Add** | Specify position → Create prompt → Generate → Renumber subsequent files (NN+1) → Update outline |
| **Delete** | Remove files → Renumber subsequent (NN-1) → Update outline |
**IMPORTANT**: When updating images, ALWAYS update the prompt file (`prompts/NN-{type}-[slug].md`) FIRST before regenerating. This ensures changes are documented and reproducible.
## Content Breakdown Principles
1. **Cover (Image 1)**: Hook + visual impact → `sparse` layout
2. **Content (Middle)**: Core value per image → `balanced`/`dense`/`list`/`comparison`/`flow`
3. **Ending (Last)**: CTA / summary → `sparse` or `balanced`
**Style × Layout Matrix** (✓✓ = highly recommended, ✓ = works well):
| | sparse | balanced | dense | list | comparison | flow | mindmap | quadrant |
|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| cute | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓ | ✓ | ✓ | ✓ |
| fresh | ✓✓ | ✓✓ | ✓ | ✓ | ✓ | ✓✓ | ✓ | ✓ |
| warm | ✓✓ | ✓✓ | ✓ | ✓ | ✓✓ | ✓ | ✓ | ✓ |
| bold | ✓✓ | ✓ | ✓ | ✓✓ | ✓✓ | ✓ | ✓ | ✓✓ |
| minimal | ✓✓ | ✓✓ | ✓✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| retro | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓ | ✓ | ✓ | ✓ |
| pop | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓ | ✓ | ✓ |
| notion | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ |
| chalkboard | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓ |
| study-notes | ✗ | ✓ | ✓✓ | ✓✓ | ✓ | ✓ | ✓✓ | ✓ |
| screen-print | ✓✓ | ✓✓ | ✗ | ✓ | ✓✓ | ✓ | ✗ | ✓✓ |
| sketch-notes | ✓ | ✓✓ | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓ |
## References
Detailed templates in `references/` directory:
**Elements** (Visual building blocks):
- `elements/canvas.md` - Aspect ratios, safe zones, grid layouts
- `elements/image-effects.md` - Cutout, stroke, filters
- `elements/typography.md` - Decorated text (花字), tags, text direction
- `elements/decorations.md` - Emphasis marks, backgrounds, doodles, frames
**Presets** (Style presets):
- `presets/<name>.md` - Element combination definitions (cute, notion, warm...)
- `style-presets.md` - Preset shortcuts (style + layout + palette combos)
**Palettes** (Color overrides):
- `palettes/<name>.md` - Color palette definitions (macaron, warm, neon)
**Workflows** (Process guides):
- `workflows/analysis-framework.md` - Content analysis framework
- `workflows/outline-template.md` - Outline template with layout guide
- `workflows/prompt-assembly.md` - Prompt assembly guide
**Config** (Settings):
- `config/preferences-schema.md` - EXTEND.md schema
- `config/first-time-setup.md` - First-time setup flow
- `config/watermark-guide.md` - Watermark configuration
## Notes
- Auto-retry once on failure | Cartoon alternatives for sensitive figures
- Use confirmed language preference | Maintain style consistency
- **Smart Confirm required** (Step 2) - do not skip; detailed mode uses two sub-confirmations
## Extension Support
Custom configurations via EXTEND.md. See **Step 0** for paths and supported options.
@@ -0,0 +1,122 @@
---
name: first-time-setup
description: First-time setup flow for baoyu-xhs-images preferences
---
# First-Time Setup
## Overview
When no EXTEND.md is found, guide user through preference setup.
**⛔ BLOCKING OPERATION**: This setup MUST complete before ANY other workflow steps. Do NOT:
- Ask about content/article
- Ask about style or layout
- Ask about target audience
- Proceed to content analysis
ONLY ask the questions in this setup flow, save EXTEND.md, then continue.
## Setup Flow
```
No EXTEND.md found
┌─────────────────────┐
│ AskUserQuestion │
│ (all questions) │
└─────────────────────┘
┌─────────────────────┐
│ Create EXTEND.md │
└─────────────────────┘
Continue to Step 1
```
## Questions
**Language**: Use user's input language or saved language preference.
Use single AskUserQuestion with multiple questions (AskUserQuestion auto-adds "Other" option):
### Question 1: Watermark
```
header: "Watermark"
question: "Watermark text for generated images? Type your watermark content (e.g., name, @handle)"
options:
- label: "No watermark (Recommended)"
description: "No watermark, can enable later in EXTEND.md"
```
Position defaults to bottom-right.
### Question 2: Preferred Style
```
header: "Style"
question: "Default visual style preference? Or type another style name or your custom style"
options:
- label: "None (Recommended)"
description: "Auto-select based on content analysis"
- label: "cute"
description: "Sweet, adorable - classic XHS aesthetic"
- label: "notion"
description: "Minimalist hand-drawn, intellectual"
```
### Question 3: Save Location
```
header: "Save"
question: "Where to save preferences?"
options:
- label: "Project"
description: ".baoyu-skills/ (this project only)"
- label: "User"
description: "~/.baoyu-skills/ (all projects)"
```
## Save Locations
| Choice | Path | Scope |
|--------|------|-------|
| Project | `.baoyu-skills/baoyu-xhs-images/EXTEND.md` | Current project |
| User | `~/.baoyu-skills/baoyu-xhs-images/EXTEND.md` | All projects |
## After Setup
1. Create directory if needed
2. Write EXTEND.md with frontmatter
3. Confirm: "Preferences saved to [path]"
4. Continue to Step 1
## EXTEND.md Template
```yaml
---
version: 1
watermark:
enabled: [true/false]
content: "[user input or empty]"
position: bottom-right
opacity: 0.7
preferred_style:
name: [selected style or null]
description: ""
preferred_layout: null
language: null
custom_styles: []
---
```
## Modifying Preferences Later
Users can edit EXTEND.md directly or run setup again:
- Delete EXTEND.md to trigger setup
- Edit YAML frontmatter for quick changes
- Full schema: `config/preferences-schema.md`
@@ -0,0 +1,118 @@
---
name: preferences-schema
description: EXTEND.md YAML schema for baoyu-xhs-images user preferences
---
# Preferences Schema
## Full Schema
```yaml
---
version: 1
watermark:
enabled: false
content: ""
position: bottom-right # bottom-right|bottom-left|bottom-center|top-right
preferred_style:
name: null # Built-in or custom style name
description: "" # Override/notes
preferred_layout: null # sparse|balanced|dense|list|comparison|flow
language: null # zh|en|ja|ko|auto
custom_styles:
- name: my-style
description: "Style description"
color_palette:
primary: ["#FED7E2", "#FEEBC8"]
background: "#FFFAF0"
accents: ["#FF69B4", "#FF6B6B"]
visual_elements: "Hearts, stars, sparkles"
typography: "Rounded, bubbly hand lettering"
best_for: "Lifestyle, beauty"
---
```
## Field Reference
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `version` | int | 1 | Schema version |
| `watermark.enabled` | bool | false | Enable watermark |
| `watermark.content` | string | "" | Watermark text (@username or custom) |
| `watermark.position` | enum | bottom-right | Position on image |
| `preferred_style.name` | string | null | Style name or null |
| `preferred_style.description` | string | "" | Custom notes/override |
| `preferred_layout` | string | null | Layout preference or null |
| `language` | string | null | Output language (null = auto-detect) |
| `custom_styles` | array | [] | User-defined styles |
## Position Options
| Value | Description |
|-------|-------------|
| `bottom-right` | Lower right corner (default, most common) |
| `bottom-left` | Lower left corner |
| `bottom-center` | Bottom center |
| `top-right` | Upper right corner |
## Custom Style Fields
| Field | Required | Description |
|-------|----------|-------------|
| `name` | Yes | Unique style identifier (kebab-case) |
| `description` | Yes | What the style conveys |
| `color_palette.primary` | No | Main colors (array) |
| `color_palette.background` | No | Background color |
| `color_palette.accents` | No | Accent colors (array) |
| `visual_elements` | No | Decorative elements |
| `typography` | No | Font/lettering style |
| `best_for` | No | Recommended content types |
## Example: Minimal Preferences
```yaml
---
version: 1
watermark:
enabled: true
content: "@myusername"
preferred_style:
name: notion
---
```
## Example: Full Preferences
```yaml
---
version: 1
watermark:
enabled: true
content: "@myxhsaccount"
position: bottom-right
preferred_style:
name: notion
description: "Clean knowledge cards for tech content"
preferred_layout: dense
language: zh
custom_styles:
- name: corporate
description: "Professional B2B style"
color_palette:
primary: ["#1E3A5F", "#4A90D9"]
background: "#F5F7FA"
accents: ["#00B4D8", "#48CAE4"]
visual_elements: "Clean lines, subtle gradients, geometric shapes"
typography: "Modern sans-serif, professional"
best_for: "Business, SaaS, enterprise"
---
```
@@ -0,0 +1,62 @@
---
name: watermark-guide
description: Watermark configuration guide for baoyu-xhs-images
---
# Watermark Guide
## Position Diagram
```
┌─────────────────────────────┐
│ [top-right]│
│ │
│ │
│ IMAGE CONTENT │
│ │
│ │
│[bottom-left][bottom-center][bottom-right]│
└─────────────────────────────┘
```
## Position Recommendations
| Position | Best For | Avoid When |
|----------|----------|------------|
| `bottom-right` | Default choice, most common | Key info in bottom-right |
| `bottom-left` | Right-heavy layouts | Key info in bottom-left |
| `bottom-center` | Centered designs | Text-heavy bottom area |
| `top-right` | Bottom-heavy content | Title/header in top-right |
## Content Format
| Format | Example | Style |
|--------|---------|-------|
| Handle | `@username` | Most common for XHS |
| Text | `MyBrand` | Simple branding |
| Chinese | `小红书:用户名` | Platform specific |
| URL | `myblog.com` | Cross-platform |
## Best Practices
1. **Consistency**: Use same watermark across all images in series
2. **Legibility**: Ensure watermark readable on both light/dark areas
3. **Size**: Keep subtle - should not distract from content
## Prompt Integration
When watermark is enabled, add to image generation prompt:
```
Include a subtle watermark "[content]" positioned at [position].
The watermark should be legible but not distracting from the main content.
```
## Common Issues
| Issue | Solution |
|-------|----------|
| Watermark invisible | Adjust position or check contrast |
| Watermark too prominent | Change position or reduce size |
| Watermark overlaps content | Change position |
| Inconsistent across images | Use session ID for consistency |
@@ -0,0 +1,122 @@
# Canvas & Layout
Core canvas specifications and layout grids for Xiaohongshu infographics.
## Aspect Ratios
| Name | Ratio | Pixels | Note |
|------|-------|--------|------|
| portrait-3-4 | 3:4 | 1242×1660 | Highest traffic on XHS (recommended) |
| square | 1:1 | 1242×1242 | Second recommended |
| portrait-2-3 | 2:3 | 1242×1863 | Taller format |
**Default**: portrait-3-4 for maximum engagement.
## Safe Zones
Avoid placing critical content in these areas:
| Zone | Position | Reason |
|------|----------|--------|
| bottom-overlay | Bottom 10% | Title bar overlay on mobile |
| top-right | Top-right corner | Like/share button overlay |
| bottom-right | Bottom-right corner | Watermark position |
```
┌─────────────────────────────┐
│ [like/share]│ ← top-right: avoid
│ │
│ │
│ ✓ SAFE CONTENT AREA │
│ │
│ │
│ [title bar overlay area] │ ← bottom 10%: avoid key info
└─────────────────────────────┘
```
## Grid Layouts
### Density-Based Layouts
| Layout | Info Density | Whitespace | Points/Image | Best For |
|--------|--------------|------------|--------------|----------|
| sparse | Low | 60-70% | 1-2 | Covers, quotes, impactful statements |
| balanced | Medium | 40-50% | 3-4 | Standard content, tutorials |
| dense | High | 20-30% | 5-8 | Knowledge cards, cheat sheets |
### Structure-Based Layouts
| Layout | Structure | Items | Best For |
|--------|-----------|-------|----------|
| list | Vertical enumeration | 4-7 | Rankings, checklists, step guides |
| comparison | Left vs Right | 2 sections | Before/after, pros/cons |
| flow | Connected nodes | 3-6 steps | Processes, timelines, workflows |
| mindmap | Center radial | 4-8 branches | Concept maps, brainstorming, topic overview |
| quadrant | 4-section grid | 4 sections | SWOT analysis, priority matrix, classification |
## Layout by Position
| Position | Recommended Layout | Why |
|----------|-------------------|-----|
| Cover | sparse | Maximum visual impact, clear title |
| Setup | balanced | Context without overwhelming |
| Core | balanced/dense/list | Based on content density |
| Payoff | balanced/list | Clear takeaways |
| Ending | sparse | Clean CTA, memorable close |
## Grid Cells
For multi-element compositions:
| Name | Cells | Use Case |
|------|-------|----------|
| single | 1 | Hero image, maximum impact |
| dual | 2 | Before/after, comparison |
| triptych | 3 | Steps, process flow |
| quad | 4 | Product showcase |
| six-grid | 6 | Checklist, collection |
| nine-grid | 9 | Multi-image gallery |
## Visual Balance
### Sparse Layout
- Single focal point centered
- Breathing room on all sides
- Symmetrical composition
### Balanced Layout
- Top-weighted title
- Evenly distributed content below
- Clear visual hierarchy
### Dense Layout
- Organized grid structure
- Clear section boundaries
- Compact but readable spacing
### List Layout
- Left-aligned items
- Clear number/bullet hierarchy
- Consistent item format
### Comparison Layout
- Symmetrical left/right
- Clear visual contrast
- Divider between sections
### Flow Layout
- Directional flow (top→bottom or left→right)
- Connected nodes with arrows
- Clear progression indicators
### Mindmap Layout
- Central topic node
- Radial branches outward
- Hierarchical sub-branches
- Organic curved connections
### Quadrant Layout
- 4-section grid (2×2)
- Clear axis labels
- Each quadrant with distinct content
- Optional circular variant for cycles
@@ -0,0 +1,152 @@
# Decorative Assets
Visual embellishments and decorative elements for Xiaohongshu infographics.
## Emphasis Marks (强调标记)
Elements to draw attention to specific content.
| Name | Description | Use Case |
|------|-------------|----------|
| red-arrow | Red arrow pointing to target | Product features, key points |
| circle-mark | Circle highlight annotation | Highlighting details |
| underline | Straight or wavy underline | Text emphasis |
| star-burst | Starburst explosion effect | Special offers, wow factor |
| checkmark | Checkmark/tick symbol | Completed items, pros |
| cross-mark | X mark symbol | Cons, things to avoid |
| exclamation | Exclamation point decoration | Important warnings |
| question | Question mark decoration | FAQ, curiosity |
| numbering | Circled numbers | Steps, rankings |
| bracket | Bracket highlighting | Grouping, emphasis |
## Backgrounds (背景)
Base layer treatments.
| Name | Description | Use Case |
|------|-------------|----------|
| solid-saturated | High-saturation solid color | Bold, energetic |
| solid-pastel | Soft pastel solid color | Cute, gentle |
| gradient-linear | Linear color gradient | Modern, dynamic |
| gradient-radial | Radial color gradient | Spotlight effect |
| frosted-glass | Frosted glass blur effect | Layered compositions |
| paper-texture | Paper or craft texture | Handmade aesthetic |
| fabric-texture | Fabric/cloth texture | Cozy, tactile |
| chalkboard | Blackboard texture | Educational content |
| grid | Subtle grid pattern | Structured, organized |
| dots | Polka dot pattern | Playful, retro |
## Doodles & Emoji (涂鸦)
Hand-drawn decorative elements.
| Name | Description | Use Case |
|------|-------------|----------|
| hand-drawn-lines | Sketchy hand-drawn lines | Connections, borders |
| stars-sparkles | Stars and sparkle effects | Magic, excellence |
| flowers | Floral decorations | Beauty, feminine |
| hearts | Heart symbols | Love, favorites |
| clouds | Cloud shapes | Dreamy, thoughts |
| arrows-curvy | Curved directional arrows | Flow, direction |
| squiggles | Wavy squiggle lines | Energy, movement |
| confetti | Scattered confetti | Celebration |
| leaves | Leaf decorations | Nature, fresh |
| bubbles | Circular bubble shapes | Playful, light |
## Emoji Integration
| Category | Examples | Use Case |
|----------|----------|----------|
| Reactions | 🥹 😍 🤯 | Emotional emphasis |
| Objects | ✨ 💡 🎯 | Visual markers |
| Actions | 👇 👆 ➡️ | Directional cues |
| Nature | 🌸 🌿 ☀️ | Thematic decoration |
## Frames (边框)
Container and border treatments.
| Name | Description | Use Case |
|------|-------------|----------|
| polaroid | Instant photo frame | Photo showcase |
| film-strip | Film negative border | Cinematic, retro |
| phone-screenshot | Mobile device mockup | App/screen content |
| torn-paper | Torn paper edge effect | Scrapbook aesthetic |
| rounded-rect | Rounded rectangle border | Clean containers |
| decorative | Ornate decorative border | Premium, elegant |
| tape-corners | Washi tape corners | Crafty, casual |
| stamp-border | Stamp perforated edge | Vintage, postal |
## Dividers (分隔线)
Section separators.
| Name | Description | Use Case |
|------|-------------|----------|
| line-simple | Simple horizontal line | Clean separation |
| line-dashed | Dashed line | Subtle division |
| line-wavy | Wavy line | Playful separation |
| dots-row | Row of dots | Decorative division |
| ornamental | Decorative flourish | Elegant separation |
## Stickers (贴纸)
Pre-composed decorative elements.
| Name | Description | Use Case |
|------|-------------|----------|
| badge-new | "NEW" badge | New products |
| badge-hot | "HOT" badge | Trending items |
| badge-sale | Sale/discount badge | Promotions |
| seal-quality | Quality seal | Recommendations |
| ribbon-award | Award ribbon | Best picks |
| tag-price | Price tag shape | Pricing info |
## Style-Specific Decorations
### Cute Style
- Hearts, stars, sparkles
- Ribbon decorations, sticker-style
- Cute character elements
### Notion Style
- Simple line doodles
- Geometric shapes, stick figures
- Maximum whitespace, minimal decoration
### Warm Style
- Sun rays, coffee cups, cozy items
- Warm lighting effects
- Friendly, inviting decorations
### Fresh Style
- Plant leaves, clouds, water drops
- Simple geometric shapes
- Open, breathing composition
### Bold Style
- Exclamation marks, arrows
- Warning icons, strong shapes
- High contrast elements
### Pop Style
- Bold shapes, speech bubbles
- Comic-style effects, starburst
- Dynamic, energetic decorations
### Retro Style
- Halftone dots, vintage badges
- Classic icons, tape effects
- Aged texture overlays
### Chalkboard Style
- Chalk dust effects
- Hand-drawn doodles
- Mathematical formulas, simple icons
### Screen-Print Style
- Bold silhouettes, geometric shapes
- Halftone dot patterns, print grain
- No doodles — negative space does the work
- Stencil-cut edges, color block boundaries
- Vintage poster border treatments
@@ -0,0 +1,92 @@
# Image Processing Layer
Visual effects applied to image elements in Xiaohongshu infographics.
## AI Cutout (抠图)
Subject extraction styles for product/figure isolation.
| Name | Description | Use Case |
|------|-------------|----------|
| clean | Sharp edges, precise boundaries | Product photography, tech items |
| soft | Soft transition, feathered edges | Portrait cutout, organic subjects |
| stylized | Hand-drawn edge treatment | Artistic compositions |
## Stroke Effects (描边)
Border treatments for cutout elements.
| Name | Description | Use Case |
|------|-------------|----------|
| white-solid | White solid line border | Classic sticker feel, high contrast |
| colored-solid | Colored solid line border | Playful vibe, brand colors |
| dashed | Dashed/dotted border | Handmade aesthetic, casual |
| double | Double-layer stroke | Emphasis effect, premium feel |
| glow | Soft outer glow | Dreamy, soft aesthetic |
| shadow | Drop shadow effect | Depth, floating element |
**Stroke Width Guidelines**:
- Thin: 2-4px - Subtle, elegant
- Medium: 5-8px - Standard visibility
- Thick: 10-15px - Bold emphasis
## Filters (滤镜)
Color grading and mood presets popular on XHS.
| Name | Chinese | Description | Mood |
|------|---------|-------------|------|
| clear-glow | 清透感 | Transparent, radiant, luminous | Fresh, youthful |
| film-grain | 胶片感 | Vintage film aesthetic, grain texture | Nostalgic, artistic |
| cream-skin | 奶油肌 | Smooth, creamy complexion tones | Soft, flattering |
| japanese-magazine | 日杂感 | Lifestyle magazine aesthetic | Curated, aspirational |
| high-saturation | 高饱和 | Vibrant, punchy colors | Energetic, eye-catching |
| muted-tones | 莫兰迪 | Morandi-style desaturated palette | Sophisticated, calm |
| warm-tone | 暖色调 | Golden hour warmth | Cozy, inviting |
| cool-tone | 冷色调 | Blue-shifted coolness | Modern, clean |
## Texture Overlays
Additional texture effects.
| Name | Description | Use Case |
|------|-------------|----------|
| paper | Paper or fabric texture | Handmade feel |
| noise | Fine grain noise | Analog aesthetic |
| halftone | Dot pattern | Retro print style |
| scratch | Light scratch marks | Vintage wear |
## Blending Modes
For layered compositions.
| Mode | Effect | Use Case |
|------|--------|----------|
| multiply | Darken, merge | Shadow effects |
| screen | Lighten, glow | Light effects |
| overlay | Contrast boost | Vibrant compositions |
| soft-light | Subtle blending | Natural layering |
## Effect Combinations
Common effect stacks for different styles:
### Cute Style
- Filter: clear-glow or cream-skin
- Stroke: white-solid (medium)
- Texture: none
### Notion Style
- Filter: none or muted-tones
- Stroke: white-solid (thin) or none
- Texture: paper (subtle)
### Retro Style
- Filter: film-grain
- Stroke: double or dashed
- Texture: halftone, scratch
### Bold Style
- Filter: high-saturation
- Stroke: colored-solid (thick)
- Texture: none
@@ -0,0 +1,96 @@
# Typography System
Text styling elements for Xiaohongshu infographics.
## Decorated Text (花字)
Stylized text treatments for emphasis and visual appeal.
| Name | Description | Use Case |
|------|-------------|----------|
| gradient | Gradient color fill | Title emphasis, modern feel |
| stroke-text | Outlined text with stroke | Cover headlines, high visibility |
| shadow-3d | 3D shadow/extrusion effect | Key terms, depth |
| highlight | Highlighter marker effect | Critical information, key points |
| neon | Neon glow effect | Tech content, night aesthetic |
| handwritten | Authentic handwritten style | Personal touch, casual |
| bubble | Rounded, inflated letterforms | Cute, playful content |
| brush | Brush stroke texture | Artistic, dynamic |
## Tags & Labels (标签)
Structured text containers.
| Name | Description | Use Case |
|------|-------------|----------|
| black-white | Black background, white text | Brand names, prices, categories |
| white-black | White background, black text | Clean labels, minimal style |
| bubble | Speech bubble style | Dialogue, annotations, callouts |
| pointer | Arrow pointer with label | Product callouts, pointing to features |
| ribbon | Ribbon/banner shape | Special offers, highlights |
| stamp | Stamp/seal style | Authenticity, recommendations |
| pill | Rounded pill shape | Tags, categories, keywords |
## Text Hierarchy
Recommended text sizing for visual hierarchy.
| Level | Role | Relative Size | Style |
|-------|------|---------------|-------|
| H1 | Main title | 100% | Bold, decorated |
| H2 | Section header | 70-80% | Semi-bold |
| H3 | Subsection | 50-60% | Medium weight |
| Body | Content text | 40-50% | Regular |
| Caption | Small notes | 30-35% | Light |
## Text Direction
| Direction | Description | Use Case |
|-----------|-------------|----------|
| horizontal | Standard left-to-right | Default for most content |
| vertical | Top-to-bottom columns | Magazine style, traditional Chinese |
| curved | Text following a curve | Decorative, around shapes |
| diagonal | Angled text | Dynamic compositions |
## Text Effects
| Effect | Description | Use Case |
|--------|-------------|----------|
| shadow | Drop shadow behind text | Readability on busy backgrounds |
| outline | Outline around letterforms | High contrast visibility |
| glow | Soft glow around text | Dreamy, emphasis |
| underline-wavy | Wavy underline decoration | Playful emphasis |
| strikethrough | Crossed out text | Before/after, corrections |
## Language Considerations
### Chinese Text (中文)
- Punctuation: 「」()、。!?
- Spacing: No spaces between characters
- Line height: 1.5-1.8x for readability
### Mixed Text
- English in Chinese context: Maintain consistent baseline
- Numbers: Use consistent number style (lining vs old-style)
## Style-Specific Typography
### Cute Style
- Rounded, bubbly hand lettering
- Soft shadows, playful decorations
- Pink/pastel color accents
### Notion Style
- Clean hand-drawn lettering
- Simple sans-serif labels
- Minimal decoration
### Bold Style
- Impactful hand lettering with shadows
- High contrast colors
- Strong outlines
### Chalkboard Style
- Chalk texture on all text
- Visible imperfections
- Multi-color chalk variety
@@ -0,0 +1,33 @@
# Macaron Palette
Soft pastel color blocks on warm cream background. Gentle, approachable, educational feel.
## Background
- Color: Warm cream (#F5F0E8)
- Texture: Subtle paper grain, warm tone
## Colors
| Role | Color | Hex | Usage |
|------|-------|-----|-------|
| Background | Warm Cream | #F5F0E8 | Primary background |
| Text | Deep Charcoal | #2C3E50 | Titles, main content |
| Secondary Text | Warm Gray | #6B6B6B | Annotations, labels |
| Block Color | Macaron Blue | #A8D8EA | Content block fill |
| Block Color | Macaron Lavender | #D5C6E0 | Content block fill |
| Block Color | Macaron Mint | #B5E5CF | Content block fill |
| Block Color | Macaron Peach | #F8D5C4 | Content block fill |
| Accent | Coral Red | #E8655A | Emphasis, highlights |
## Semantic Constraint
Soft pastel macaron color palette. Use block colors as rounded card backgrounds for distinct information sections. Accent coral red sparingly for emphasis on key terms only. All colors should feel gentle and approachable — no saturated or neon tones. Do NOT render color names or role labels as visible text in the image.
## Best Paired With
- `sketch-notes` — natural pairing for hand-drawn educational content
- `notion` — macaron accents soften the monochrome aesthetic
- `chalkboard` — pastel chalk tones replace standard chalk colors
- `warm` — reinforces the cozy, friendly feel
- `fresh` — complements the clean, natural aesthetic
@@ -0,0 +1,32 @@
# Neon Palette
Vibrant neon colors on dark background. High-energy, futuristic, eye-catching.
## Background
- Color: Dark Purple (#1A1025)
- Texture: Smooth, deep
## Colors
| Role | Color | Hex | Usage |
|------|-------|-----|-------|
| Background | Dark Purple | #1A1025 | Primary background |
| Text | Bright White | #F0F0F0 | Titles, main content |
| Secondary Text | Light Lavender | #B8B8D4 | Annotations, labels |
| Block Color | Neon Cyan | #00F5FF | Content block fill |
| Block Color | Neon Magenta | #FF00FF | Content block fill |
| Block Color | Neon Green | #39FF14 | Content block fill |
| Block Color | Neon Pink | #FF6EC7 | Content block fill |
| Accent | Electric Yellow | #FFFF00 | Emphasis, highlights |
## Semantic Constraint
Vibrant neon color palette on dark background. Colors should glow against the dark base. High contrast, futuristic feel. Use neon sparingly — too many glowing elements become chaotic. Let dark background breathe.
## Best Paired With
- `bold` — amplifies high-impact energy
- `pop` — neon takes the vibrancy further
- `minimal` — neon accents on dark create striking contrast
- `notion` — futuristic knowledge card aesthetic
@@ -0,0 +1,32 @@
# Warm Palette
Warm earth tones on soft peach background. Cozy, inviting, no cool colors.
## Background
- Color: Soft Peach (#FFECD2)
- Texture: Warm, slightly textured
## Colors
| Role | Color | Hex | Usage |
|------|-------|-----|-------|
| Background | Soft Peach | #FFECD2 | Primary background |
| Text | Deep Brown | #744210 | Titles, main content |
| Secondary Text | Warm Brown | #9C6644 | Annotations, labels |
| Block Color | Warm Orange | #ED8936 | Content block fill |
| Block Color | Terracotta | #C05621 | Content block fill |
| Block Color | Golden Yellow | #F6AD55 | Content block fill |
| Block Color | Dusty Rose | #D4A09A | Content block fill |
| Accent | Burnt Sienna | #A0522D | Emphasis, highlights |
## Semantic Constraint
Warm-only color palette, no cool colors (no blue, green, purple). Earth tones throughout. Evokes comfort, warmth, and trust. All colors should feel like autumn sunlight.
## Best Paired With
- `warm` — natural pairing, amplifies cozy feel
- `cute` — warm pastels enhance the sweet aesthetic
- `retro` — earth tones complement vintage style
- `sketch-notes` — warm educational feel
@@ -0,0 +1,72 @@
---
name: bold
category: impact
---
# Bold Style
High impact, attention-grabbing aesthetic.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | dual
image_effects:
cutout: clean
stroke: colored-solid | double
filter: high-saturation
typography:
decorated: shadow-3d | stroke-text
tags: black-white | ribbon
direction: horizontal | diagonal
decorations:
emphasis: exclamation | star-burst | red-arrow
background: solid-saturated | gradient-linear
doodles: arrows-curvy | squiggles
frames: none
```
## Color Palette
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Vibrant red, orange, yellow | #E53E3E, #DD6B20, #F6E05E |
| Background | Deep black, dark charcoal | #000000, #1A1A1A |
| Accents | White, neon yellow | #FFFFFF, #F7FF00 |
## Visual Elements
- Exclamation marks, arrows, warning icons
- Strong shapes, high contrast elements
- Dramatic compositions
- Bold geometric forms
## Typography
- Bold, impactful hand lettering with shadows
- High contrast text treatments
- Large, commanding headlines
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Impactful statements |
| balanced | ✓ | Warning content |
| dense | ✓ | Critical information cards |
| list | ✓✓ | Must-know lists, rankings |
| comparison | ✓✓ | Dramatic contrasts |
| flow | ✓ | Critical process steps |
## Best For
- Important tips and warnings
- Must-know content
- Critical announcements
- Rankings and comparisons
- Attention-grabbing hooks
@@ -0,0 +1,97 @@
---
name: chalkboard
category: educational
---
# Chalkboard Style
Black chalkboard background with colorful chalk drawing aesthetic.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | dual | triptych
image_effects:
cutout: stylized
stroke: none
filter: none
typography:
decorated: handwritten
tags: none
direction: horizontal | vertical
decorations:
emphasis: underline | circle-mark | arrows-curvy
background: chalkboard
doodles: hand-drawn-lines | stars-sparkles
frames: none
```
## Color Palette
| Role | Colors | Hex |
|------|--------|-----|
| Background | Chalkboard black, green-black | #1A1A1A, #1C2B1C |
| Primary Text | Chalk white | #F5F5F5 |
| Accent 1 | Chalk yellow | #FFE566 |
| Accent 2 | Chalk pink | #FF9999 |
| Accent 3 | Chalk blue | #66B3FF |
| Accent 4 | Chalk green | #90EE90 |
| Accent 5 | Chalk orange | #FFB366 |
## Visual Elements
- Hand-drawn chalk illustrations with sketchy, imperfect lines
- Chalk dust effects around text and key elements
- Doodles: stars, arrows, underlines, circles, checkmarks
- Mathematical formulas and simple diagrams
- Eraser smudges and chalk residue textures
- Stick figures and simple icons
- Connection lines with hand-drawn feel
## Typography
- Hand-drawn chalk lettering style
- Visible chalk texture on all text
- Imperfect baseline adds authenticity
- White or bright colored chalk for emphasis
## Style Rules
### Do
- Maintain authentic chalk texture on all elements
- Use imperfect, hand-drawn quality throughout
- Add subtle chalk dust and smudge effects
- Create visual hierarchy with color variety
- Include playful doodles and annotations
### Don't
- Use perfect geometric shapes
- Create clean digital-looking lines
- Add photorealistic elements
- Use gradients or glossy effects
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Educational covers |
| balanced | ✓✓ | Standard lessons |
| dense | ✓✓ | Detailed tutorials |
| list | ✓✓ | Learning checklists |
| comparison | ✓ | Concept comparisons |
| flow | ✓✓ | Process explanations |
## Best For
- Educational content
- Tutorials and how-to's
- Classroom themes
- Teaching materials
- Workshops
- Informal learning sessions
- Knowledge sharing
@@ -0,0 +1,72 @@
---
name: cute
category: sweet
---
# Cute Style
Sweet, adorable, girly - classic Xiaohongshu aesthetic.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | dual | quad
image_effects:
cutout: soft
stroke: white-solid | colored-solid
filter: clear-glow | cream-skin
typography:
decorated: bubble | highlight
tags: pill | bubble
direction: horizontal
decorations:
emphasis: star-burst | hearts
background: solid-pastel | gradient-linear
doodles: hearts | stars-sparkles | flowers
frames: polaroid | tape-corners
```
## Color Palette
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Pink, peach, mint, lavender | #FED7E2, #FEEBC8, #C6F6D5, #E9D8FD |
| Background | Cream, soft pink | #FFFAF0, #FFF5F7 |
| Accents | Hot pink, coral | #FF69B4, #FF6B6B |
## Visual Elements
- Hearts, stars, sparkles, cute faces
- Ribbon decorations, sticker-style
- Cute stickers, emoji icons
- Soft, rounded shapes
## Typography
- Rounded, bubbly hand lettering
- Soft shadows, playful decorations
- Pink/pastel color accents on text
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Covers, emotional impact |
| balanced | ✓✓ | Standard cute content |
| dense | ✓ | Cute knowledge cards |
| list | ✓✓ | Checklists, cute rankings |
| comparison | ✓ | Before/after transformations |
| flow | ✓ | Cute step guides |
## Best For
- Lifestyle content
- Beauty and skincare
- Fashion and style
- Daily tips and hacks
- Personal shares
@@ -0,0 +1,72 @@
---
name: fresh
category: natural
---
# Fresh Style
Clean, refreshing, natural aesthetic.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | triptych
image_effects:
cutout: soft
stroke: white-solid | none
filter: clear-glow | cool-tone
typography:
decorated: none | highlight
tags: pill | white-black
direction: horizontal
decorations:
emphasis: checkmark | circle-mark
background: solid-white | solid-pastel
doodles: leaves | clouds | bubbles
frames: rounded-rect | none
```
## Color Palette
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Mint green, sky blue, light yellow | #9AE6B4, #90CDF4, #FAF089 |
| Background | Pure white, soft mint | #FFFFFF, #F0FFF4 |
| Accents | Leaf green, water blue | #48BB78, #4299E1 |
## Visual Elements
- Plant leaves, clouds, water drops
- Simple geometric shapes
- Breathing room, open composition
- Natural, organic elements
## Typography
- Clean, light hand lettering with breathing room
- Airy spacing
- Fresh color accents
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Clean covers |
| balanced | ✓✓ | Standard fresh content |
| dense | ✓ | Organized information |
| list | ✓ | Wellness tips |
| comparison | ✓ | Before/after health |
| flow | ✓✓ | Organic processes |
## Best For
- Health and wellness
- Minimalist lifestyle
- Self-care content
- Nature-related topics
- Clean living tips
@@ -0,0 +1,72 @@
---
name: minimal
category: elegant
---
# Minimal Style
Ultra-clean, sophisticated aesthetic.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single
image_effects:
cutout: clean
stroke: none | white-solid
filter: none | muted-tones
typography:
decorated: none
tags: white-black | pill
direction: horizontal
decorations:
emphasis: underline | circle-mark
background: solid-white | solid-pastel
doodles: hand-drawn-lines
frames: none | rounded-rect
```
## Color Palette
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Black, white | #000000, #FFFFFF |
| Background | Off-white, pure white | #FAFAFA, #FFFFFF |
| Accents | Single color (content-derived) | Blue, green, or coral |
## Visual Elements
- Single focal point, thin lines
- Maximum whitespace
- Simple, clean decorations
- Restrained visual elements
## Typography
- Clean, simple hand lettering
- Minimal weight variations
- Elegant spacing
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Elegant statements |
| balanced | ✓✓ | Professional content |
| dense | ✓✓ | Clean knowledge cards |
| list | ✓ | Simple lists |
| comparison | ✓ | Clean comparisons |
| flow | ✓ | Elegant processes |
## Best For
- Professional content
- Serious topics
- Elegant presentations
- High-end products
- Business content
@@ -0,0 +1,73 @@
---
name: notion
category: minimal
---
# Notion Style
Minimalist hand-drawn line art, intellectual aesthetic.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | dual
image_effects:
cutout: clean
stroke: none | white-solid
filter: none | muted-tones
typography:
decorated: none | handwritten
tags: black-white | pill
direction: horizontal
decorations:
emphasis: circle-mark | underline
background: solid-white | paper-texture
doodles: hand-drawn-lines | arrows-curvy
frames: none | rounded-rect
```
## Color Palette
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Black, dark gray | #1A1A1A, #4A4A4A |
| Background | Pure white, off-white | #FFFFFF, #FAFAFA |
| Accents | Pastel blue, pastel yellow, pastel pink | #A8D4F0, #F9E79F, #FADBD8 |
## Visual Elements
- Simple line doodles, hand-drawn wobble effect
- Geometric shapes, stick figures
- Maximum whitespace, single-weight ink lines
- Clean, uncluttered compositions
## Typography
- Clean hand-drawn lettering
- Simple sans-serif labels
- Minimal decoration on text
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Concept covers |
| balanced | ✓✓ | Standard explanations |
| dense | ✓✓ | Knowledge cards, cheat sheets |
| list | ✓✓ | Productivity tips, tool lists |
| comparison | ✓✓ | Data comparisons |
| flow | ✓✓ | Process diagrams |
## Best For
- Knowledge sharing
- Concept explanations
- SaaS content
- Productivity tips
- Tech tutorials
- Professional content
@@ -0,0 +1,72 @@
---
name: pop
category: energetic
---
# Pop Style
Vibrant, energetic, eye-catching aesthetic.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | quad
image_effects:
cutout: stylized
stroke: colored-solid | double
filter: high-saturation
typography:
decorated: stroke-text | shadow-3d
tags: bubble | ribbon
direction: horizontal | curved
decorations:
emphasis: star-burst | exclamation
background: solid-saturated | dots
doodles: stars-sparkles | confetti | squiggles
frames: none
```
## Color Palette
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Bright red, yellow, blue, green | #F56565, #ECC94B, #4299E1, #48BB78 |
| Background | White, light gray | #FFFFFF, #F7FAFC |
| Accents | Neon pink, electric purple | #FF69B4, #9F7AEA |
## Visual Elements
- Bold shapes, speech bubbles
- Comic-style effects, starburst
- Dynamic, energetic compositions
- High-energy decorations
## Typography
- Dynamic, energetic hand lettering with outlines
- Bold color combinations
- Playful, expressive forms
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Exciting announcements |
| balanced | ✓✓ | Fun tutorials |
| dense | ✓ | Packed information |
| list | ✓✓ | Fun facts lists |
| comparison | ✓✓ | Dynamic comparisons |
| flow | ✓ | Energetic processes |
## Best For
- Exciting announcements
- Fun facts
- Engaging tutorials
- Entertainment content
- Youth-oriented content
@@ -0,0 +1,72 @@
---
name: retro
category: vintage
---
# Retro Style
Vintage, nostalgic, trendy aesthetic.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | dual
image_effects:
cutout: stylized
stroke: dashed | double
filter: film-grain | muted-tones
typography:
decorated: brush | handwritten
tags: stamp | ribbon
direction: horizontal
decorations:
emphasis: star-burst | numbering
background: paper-texture | dots
doodles: stars-sparkles | squiggles
frames: polaroid | film-strip | stamp-border
```
## Color Palette
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Muted orange, dusty pink, faded teal | #E07A4D, #D4A5A5, #6B9999 |
| Background | Aged paper, sepia tones | #F5E6D3, #E8DCC8 |
| Accents | Faded red, vintage gold | #C55A5A, #B8860B |
## Visual Elements
- Halftone dots, vintage badges
- Classic icons, tape effects
- Aged texture overlays
- Nostalgic decorative elements
## Typography
- Vintage-style hand lettering
- Classic feel with imperfections
- Aged texture on text
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Vintage covers |
| balanced | ✓✓ | Classic content |
| dense | ✓ | Vintage knowledge cards |
| list | ✓✓ | Classic rankings |
| comparison | ✓ | Then vs now |
| flow | ✓ | Historical timelines |
## Best For
- Throwback content
- Classic tips
- Timeless advice
- Vintage aesthetics
- Nostalgic shares
@@ -0,0 +1,92 @@
---
name: screen-print
category: poster
---
# Screen-Print Style
Bold poster art with halftone textures, limited colors, and symbolic storytelling.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | dual
image_effects:
cutout: silhouette
stroke: none
filter: halftone | print-grain
typography:
decorated: stroke-text | shadow-3d
tags: none
direction: horizontal
decorations:
emphasis: star-burst | numbering
background: solid-saturated | paper-texture
doodles: none
frames: none
```
## Color Palette
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Burnt Orange, Deep Teal | #E8751A, #0A6E6E |
| Background | Off-Black, Warm Cream | #121212, #F5E6D0 |
| Accents | Crimson, Amber | #C0392B, #F4A623 |
**Duotone Pairs** (choose ONE based on content mood):
| Pair | Color A | Color B | Feel |
|------|---------|---------|------|
| Orange + Teal | #E8751A | #0A6E6E | Cinematic, action |
| Red + Cream | #C0392B | #F5E6D0 | Bold, classic |
| Blue + Gold | #1A3A5C | #D4A843 | Premium, prestigious |
| Crimson + Navy | #DC143C | #0D1B2A | Dramatic, noir |
| Magenta + Cyan | #C2185B | #00BCD4 | Vibrant, pop |
**Rule**: Use 2-5 colors maximum. Fewer colors = stronger impact.
## Visual Elements
- Bold silhouettes and symbolic shapes
- Halftone dot patterns within color fills
- Slight color layer misregistration (print offset effect)
- Geometric framing (circles, arches, triangles)
- Figure-ground inversion (negative space tells secondary story)
- Stencil-cut edges, no outlines — shapes defined by color boundaries
- Typography integrated as design element, not overlay
- Vintage poster border treatments
## Typography
- Bold condensed sans-serif or hand-drawn lettering
- Art Deco influences, vintage poster typography
- Typography as integral part of composition (not separate layer)
- High contrast with background for readability
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Iconic poster covers, dramatic statements |
| balanced | ✓✓ | Editorial compositions, opinion pieces |
| dense | ✗ | Too much info clashes with minimal poster aesthetic |
| list | ✓ | Bold rankings, top picks |
| comparison | ✓✓ | Duotone split compositions, before/after |
| flow | ✓ | Cinematic progression, timelines |
| mindmap | ✗ | Too complex for geometric poster style |
| quadrant | ✓✓ | Strong geometric division, classification |
## Best For
- Opinion pieces, cultural commentary
- Movie/music/book recommendations
- Dramatic announcements
- Before/after transformations
- Bold editorial content
- Event promotions
@@ -0,0 +1,100 @@
---
name: sketch-notes
category: educational
default_palette: macaron
---
# Sketch Notes Style
Hand-drawn educational infographic with slight line wobble, like a high-quality presentation visual summary.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | dual
image_effects:
cutout: stylized
stroke: none
filter: none
typography:
decorated: handwritten
tags: rounded-badge
direction: horizontal
decorations:
emphasis: underline | circle-mark | arrows-curvy | star-burst
background: paper-texture
doodles: hand-drawn-lines | stars-sparkles | arrows-curvy | squiggles
frames: rounded-rect
```
## Color Palette
Default: **macaron** palette (see `palettes/macaron.md`)
When no `--palette` is specified, uses macaron colors: warm cream background (#F5F0E8), macaron blue/lavender/mint/peach zone blocks, coral red accent.
## Visual Elements
- Hand-drawn wobble on all lines and shapes
- Simple stick-figure characters at desks, working, thinking
- Rounded cards with pastel color blocks as information sections
- Color fills do NOT completely fill outlines (hand-painted feel)
- Doodle decorations: small stars, underlines, checkmarks, lock icons, clipboard icons
- Wavy hand-drawn arrows connecting zones with small text labels
- Thought bubbles and speech bubbles with sketchy outlines
- Simple conceptual icons (documents, lightbulbs, gears, arrows)
- Generous whitespace between zones for clean composition
## Typography
- Bold hand-drawn lettering for titles (large, prominent)
- Bold keywords within content zones
- Smaller annotations in secondary text color
- Hand-drawn quality on ALL text, no computer-generated fonts
- Clear information hierarchy: title > zone labels > body text > annotations
## Style Rules
### Do
- Maintain slight wobble on every line, shape, and border
- Use palette block colors as distinct section backgrounds
- Leave color fills intentionally incomplete at edges
- Include simple doodle icons relevant to content
- Keep generous whitespace between zones
- Use accent color sparingly for emphasis on key terms
- Draw connecting arrows with hand-drawn wavy feel
### Don't
- Use perfect geometric shapes or straight lines
- Create photorealistic elements
- Fill colors completely to edges (maintain hand-painted gap)
- Use dark or saturated backgrounds
- Overcrowd with too many decorative elements
- Use gradient fills or glossy effects
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓ | Simple covers with single zone |
| balanced | ✓✓ | Standard educational summaries |
| dense | ✓✓ | Knowledge cards, concept maps |
| list | ✓✓ | Step-by-step guides, checklists |
| comparison | ✓ | Side-by-side concept contrast |
| flow | ✓✓ | Process diagrams, workflows, tutorials |
| mindmap | ✓✓ | Concept maps, radial knowledge maps |
| quadrant | ✓ | Classification matrices |
## Best For
- Educational content, tutorials, how-to guides
- Process and workflow explanations
- Knowledge summaries, concept diagrams
- Technical explanations made approachable
- Visual summaries of articles or talks
- Onboarding materials, friendly guides
@@ -0,0 +1,115 @@
---
name: study-notes
category: realistic
---
# Study Notes Style
Realistic handwritten photo aesthetic - student notes style, dense and messy but readable.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single
image_effects:
cutout: none
stroke: none
filter: natural-photo
typography:
decorated: none
tags: none
direction: horizontal
decorations:
emphasis: circle-mark | underline | checkmark | cross | star-simple
background: lined-paper-white
doodles: arrows-simple | margin-notes | corrections | explanatory-diagrams
frames: none
```
## Color Palette (Three-Color Annotation System)
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Blue ballpoint, Black ink | #1E3A5F, #1A1A1A |
| Highlights | Yellow highlighter | #FFFF00 (50% opacity) |
| Accents | Red pen (circles, underlines) | #CC0000 |
| Background | White lined paper | #FFFFFF |
## Visual Elements
- Realistic photo perspective: top-down view of study desk
- Hand holding blue ballpoint pen, actively underlining
- Extremely dense handwritten content, filling entire page
- Red pen annotations: circles, underlines, stars, boxes
- Yellow highlighter marking key terms
- Correction marks, cramped notes squeezed into margins
- Simple hand-drawn symbols: → * ✓ ✗ !
- Varying pen pressure creating lighter and darker strokes
## Typography
- Authentic student handwriting
- Messy but readable, clear structure maintained
- Varying font sizes (large titles, small body, tiny margin notes)
- CJK optimized
## Content Structure
Three-section layout:
### Top Section
- Core topic (circled multiple times in red)
- First section title + 3-4 key points
- Arrow connections, red underlines
### Middle Section
- Second section title (red pen box)
- Numbered steps ①②③
- Specific methods and supplementary notes
### Bottom Section
- Third section title (red star)
- Time points / key metrics
- Key quotes / core tips (tiny corner notes)
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✗ | Not suitable - style requires dense content |
| balanced | ✓ | When content is lighter |
| dense | ✓✓ | Best fit - knowledge notes, summaries |
| list | ✓✓ | Step checklists, rankings |
| comparison | ✓ | Comparative analysis |
| flow | ✓ | Process flows |
| mindmap | ✓✓ | Mind map notes |
| quadrant | ✓ | Quadrant analysis |
## Best For
- Study guides, exam notes
- Knowledge organization, framework summaries
- Tutorial summaries, quick notes
- "Top student notes" style content
- Knowledge sharing requiring authentic feel
## Style Rules
### DO ✓
- Keep content extremely dense
- Use simple symbols (→ * ✓ ✗ !)
- Annotate key points with red pen
- Include correction marks
- Squeeze tiny notes into margins
### DON'T ✗
- Use complex emojis
- Leave too much whitespace
- Make neat, tidy layouts
- Add colorful decorations
- Include cartoon elements
@@ -0,0 +1,72 @@
---
name: warm
category: cozy
---
# Warm Style
Cozy, friendly, approachable aesthetic.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | dual
image_effects:
cutout: soft
stroke: white-solid | glow
filter: warm-tone | cream-skin
typography:
decorated: highlight | handwritten
tags: ribbon | bubble
direction: horizontal
decorations:
emphasis: star-burst | hearts
background: solid-pastel | gradient-radial
doodles: clouds | stars-sparkles
frames: polaroid | tape-corners
```
## Color Palette
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Warm orange, golden yellow, terracotta | #ED8936, #F6AD55, #C05621 |
| Background | Cream, soft peach | #FFFAF0, #FED7AA |
| Accents | Deep brown, soft red | #744210, #E57373 |
## Visual Elements
- Sun rays, coffee cups, cozy items
- Warm lighting effects
- Friendly, inviting decorations
- Soft, comfortable shapes
## Typography
- Friendly, rounded hand lettering
- Warm color accents
- Comfortable, approachable feel
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Emotional covers |
| balanced | ✓✓ | Personal stories |
| dense | ✓ | Detailed experiences |
| list | ✓ | Life lessons |
| comparison | ✓✓ | Before/after stories |
| flow | ✓ | Journey narratives |
## Best For
- Personal stories
- Life lessons
- Emotional content
- Comfort and lifestyle
- Heartfelt shares
@@ -0,0 +1,43 @@
# Style Presets
`--preset X` expands to a style + layout + optional palette combination. Users can override any dimension.
| --preset | Style | Layout | Palette |
|----------|-------|--------|---------|
| `knowledge-card` | `notion` | `dense` | |
| `checklist` | `notion` | `list` | |
| `concept-map` | `notion` | `mindmap` | |
| `swot` | `notion` | `quadrant` | |
| `tutorial` | `chalkboard` | `flow` | |
| `classroom` | `chalkboard` | `balanced` | |
| `study-guide` | `study-notes` | `dense` | |
| `cute-share` | `cute` | `balanced` | |
| `girly` | `cute` | `sparse` | |
| `cozy-story` | `warm` | `balanced` | |
| `product-review` | `fresh` | `comparison` | |
| `nature-flow` | `fresh` | `flow` | |
| `warning` | `bold` | `list` | |
| `versus` | `bold` | `comparison` | |
| `clean-quote` | `minimal` | `sparse` | |
| `pro-summary` | `minimal` | `balanced` | |
| `retro-ranking` | `retro` | `list` | |
| `throwback` | `retro` | `balanced` | |
| `pop-facts` | `pop` | `list` | |
| `hype` | `pop` | `sparse` | |
| `poster` | `screen-print` | `sparse` | |
| `editorial` | `screen-print` | `balanced` | |
| `cinematic` | `screen-print` | `comparison` | |
| `hand-drawn-edu` | `sketch-notes` | `flow` | `macaron` |
| `sketch-card` | `sketch-notes` | `dense` | `macaron` |
| `sketch-summary` | `sketch-notes` | `balanced` | `macaron` |
Empty Palette = use style's built-in colors (or style's `default_palette` if defined in frontmatter).
## Override Examples
- `--preset knowledge-card --style chalkboard` = chalkboard style with dense layout
- `--preset poster --layout quadrant` = screen-print style with quadrant layout
- `--preset hand-drawn-edu --palette warm` = sketch-notes style with flow layout, warm palette instead of macaron
- `--style notion --palette macaron` = notion rendering rules with macaron colors
Explicit `--style`/`--layout`/`--palette` flags always override preset values.
@@ -0,0 +1,198 @@
# Xiaohongshu Content Analysis Framework
Deep analysis framework tailored for Xiaohongshu's unique engagement patterns.
## Purpose
Before creating infographics, thoroughly analyze the source material to:
- Maximize hook power and swipe motivation
- Identify save-worthy and share-worthy elements
- Plan the visual narrative arc
- Match content to optimal style/layout
## Platform Characteristics
Unlike other platforms, Xiaohongshu content must prioritize:
- **Hook Power**: First image decides 90% of engagement
- **Swipe Motivation**: Each image must compel users to continue
- **Save Value**: Content worth bookmarking for later
- **Share Triggers**: Emotional resonance that drives sharing
## Analysis Dimensions
### 1. Content Type Classification
| Type | Characteristics | Best Style | Best Layout |
|------|----------------|------------|-------------|
| 种草/安利 | Product recommendation, benefits focus | cute/fresh | balanced/list |
| 干货分享 | Knowledge, tips, how-to | notion | dense/list |
| 个人故事 | Personal experience, emotional | warm | balanced |
| 测评对比 | Review, comparison, pros/cons | bold/notion | comparison |
| 教程步骤 | Step-by-step guide | fresh/notion | flow/list |
| 避坑指南 | Warnings, mistakes to avoid | bold | list/comparison |
| 清单合集 | Collections, recommendations | cute/minimal | list/dense |
### 2. Hook Analysis (爆款标题潜力)
Evaluate title/hook potential using these patterns:
**Hook Types**:
- **数字钩子**: "5个方法", "3分钟学会", "99%的人不知道"
- **痛点钩子**: "踩过的坑", "后悔没早知道", "别再..."
- **好奇钩子**: "原来...", "竟然...", "没想到..."
- **利益钩子**: "省钱", "变美", "效率翻倍"
- **身份钩子**: "打工人必看", "学生党", "新手妈妈"
**Rating Scale**:
- ⭐⭐⭐⭐⭐ (5/5): Multiple strong hooks combined
- ⭐⭐⭐⭐ (4/5): Clear hook with room for enhancement
- ⭐⭐⭐ (3/5): Basic hook, needs strengthening
- ⭐⭐ (2/5): Weak hook, requires significant improvement
- ⭐ (1/5): No clear hook
### 3. Target Audience (用户画像)
| Audience | Interests | Preferred Style | Content Focus |
|----------|-----------|-----------------|---------------|
| 学生党 | 省钱、学习、校园 | cute/fresh | 平价、教程、学习方法 |
| 打工人 | 效率、职场、减压 | minimal/notion | 工具、技巧、摸鱼 |
| 宝妈 | 育儿、家居、省心 | warm/fresh | 实用、安全、经验 |
| 精致女孩 | 美妆、穿搭、仪式感 | cute/retro | 好看、氛围、品质 |
| 技术宅 | 工具、效率、极客 | notion/chalkboard | 深度、专业、新奇 |
| 美食爱好者 | 探店、食谱、测评 | warm/pop | 好吃、简单、颜值 |
| 旅行达人 | 攻略、打卡、小众 | fresh/retro | 省钱、避坑、拍照 |
### 4. Engagement Potential
**Save Value (收藏价值)**:
- Is it reference material? ✓ High save potential
- Is it a checklist or list? ✓ High save potential
- Is it a tutorial? ✓ High save potential
- Is it time-sensitive news? ✗ Low save potential
**Share Triggers (分享冲动)**:
- "我朋友也需要看这个" → High share potential
- "这说的就是我" → Identity resonance
- "太有用了必须分享" → Utility sharing
- "笑死,给朋友看看" → Entertainment sharing
**Comment Inducement (评论诱导)**:
- Open-ended questions: "你是哪种类型?"
- Experience sharing: "评论区说说你的经历"
- Debate triggers: "你觉得呢?"
- Help requests: "有更好的推荐吗?"
**Interaction Design (互动设计)**:
- Polls: "A还是B"
- Challenges: "你能做到几个?"
- Tags: "@你那个需要的朋友"
### 5. Visual Opportunity Map
| Content Element | Visual Treatment | Example |
|-----------------|------------------|---------|
| 数据/统计 | Highlighted numbers, simple charts | "节省80%时间" 大字突出 |
| 对比 | Before/after, side-by-side | 左右分屏对比图 |
| 步骤 | Numbered flow, arrows | 1→2→3 流程图 |
| 清单 | Checklist with icons | ✓/✗ 列表配图标 |
| 情感 | Character expressions, scenes | 卡通人物表情包 |
| 产品 | Product showcase, lifestyle | 产品实拍+使用场景 |
| 引用 | Quote cards, speech bubbles | 金句卡片设计 |
### 6. Swipe Flow Design
Plan the narrative arc across images:
| Position | Purpose | Hook Strategy |
|----------|---------|---------------|
| **Cover (封面)** | Stop scrolling | 最强视觉冲击 + 核心标题 |
| **Setup (铺垫)** | Build context | 痛点共鸣 / 好奇心 |
| **Core (核心)** | Deliver value | 干货内容,每页1-2个要点 |
| **Payoff (收获)** | Practical takeaway | 可执行的行动建议 |
| **Ending (结尾)** | Drive action | CTA + 互动引导 |
**Swipe Motivation Between Images**:
- End each image with a hook for the next
- Use "下一页更精彩" type transitions
- Create information gaps that require swiping
- Build anticipation through numbering ("第3个最重要")
## Output Format
Analysis results should be saved to `analysis.md` with:
```yaml
---
title: "5个让你效率翻倍的AI工具"
topic: 干货分享
content_type: 工具推荐
source_language: zh
user_language: zh
recommended_image_count: 6
---
## Target Audience
- **Primary**: 打工人、自由职业者 - 追求效率提升
- **Secondary**: 学生党 - 写论文、做作业需要
- **Tertiary**: 内容创作者 - 需要AI辅助
## Hook Analysis
**标题钩子评分**: ⭐⭐⭐⭐ (4/5)
- ✓ 数字钩子: "5个"
- ✓ 利益钩子: "效率翻倍"
- △ 可增强: 加入身份标签 "打工人必看"
**建议优化**:
- 原标题: "5个让你效率翻倍的AI工具"
- 优化: "打工人必看!5个让我效率翻倍的AI神器"
## Value Proposition
**为什么用户要看?**
1. **实用价值**: 直接可用的工具推荐
2. **省时省力**: 不用自己筛选,直接抄作业
3. **FOMO**: 别人都在用,我不能落后
**收藏理由**: 工具清单,需要时可以回来查
## Engagement Design
- **互动点**: 结尾问"你最常用哪个?"
- **评论诱导**: "还有什么好用的工具评论区分享"
- **分享触发**: 打工人会转发给同事
## Content Signals
- "AI工具" → notion + dense
- "效率" → notion + list
- "干货" → minimal + dense
## Swipe Flow
| Image | Position | Purpose | Hook |
|-------|----------|---------|------|
| 1 | Cover | 吸引停留 | 标题+视觉冲击 |
| 2 | Setup | 建立共鸣 | 为什么需要AI工具 |
| 3-5 | Core | 核心价值 | 每页1-2个工具详解 |
| 6 | Ending | 行动引导 | 总结+互动引导 |
## Recommended Approaches
1. **Notion + Dense** - 知识卡片风格,适合干货分享 (recommended)
2. **Notion + List** - 清爽知识卡片风格
3. **Minimal + Balanced** - 简约高端,适合职场人群
```
## Analysis Checklist
Before proceeding to outline generation:
- [ ] Can I identify the content type?
- [ ] Is the hook strong enough? (≥3 stars)
- [ ] Do I know the primary audience?
- [ ] Have I identified save/share triggers?
- [ ] Are there clear visual opportunities?
- [ ] Is the swipe flow planned?
- [ ] Have I identified the best style+layout recommendation?
@@ -0,0 +1,247 @@
# Xiaohongshu Outline Template
Template for generating infographic series outlines with layout specifications.
## File Naming
Outline files use strategy identifier in the name:
- `outline-strategy-a.md` - Story-driven variant
- `outline-strategy-b.md` - Information-dense variant
- `outline-strategy-c.md` - Visual-first variant
- `outline.md` - Final selected (copied from chosen variant)
## Image File Naming
Images use meaningful slugs for readability:
```
NN-{type}-[slug].png
NN-{type}-[slug].md (in prompts/)
```
| Type | Usage |
|------|-------|
| `cover` | First image (cover) |
| `content` | Middle content images |
| `ending` | Last image |
**Examples**:
- `01-cover-ai-tools.png`
- `02-content-why-ai.png`
- `03-content-chatgpt.png`
- `04-content-midjourney.png`
- `05-content-notion-ai.png`
- `06-ending-summary.png`
**Slug rules**:
- Derived from image content (kebab-case)
- Must be unique within the series
- Keep short but descriptive (2-4 words)
## Layout Selection Guide
### Density-Based Layouts
| Layout | When to Use | Info Points | Whitespace |
|--------|-------------|-------------|------------|
| sparse | Covers, quotes, impact statements | 1-2 | 60-70% |
| balanced | Standard content, tutorials | 3-4 | 40-50% |
| dense | Knowledge cards, cheat sheets | 5-8 | 20-30% |
### Structure-Based Layouts
| Layout | When to Use | Structure |
|--------|-------------|-----------|
| list | Rankings, checklists, steps | Numbered/bulleted vertical |
| comparison | Before/after, pros/cons | Left vs right split |
| flow | Processes, timelines | Connected nodes with arrows |
### Position-Based Recommendations
| Position | Recommended | Reasoning |
|----------|-------------|-----------|
| Cover | sparse | Maximum impact, clear title |
| Setup | balanced | Context without overwhelming |
| Core | balanced/dense/list | Match content density |
| Payoff | balanced/list | Clear takeaways |
| Ending | sparse | Clean CTA, memorable |
## Outline Format
```markdown
# Xiaohongshu Infographic Series Outline
---
strategy: a # a, b, or c
name: Story-Driven
style: notion
default_layout: dense
image_count: 6
generated: YYYY-MM-DD HH:mm
---
## Image 1 of 6
**Position**: Cover
**Layout**: sparse
**Hook**: 打工人必看!
**Slug**: ai-tools
**Filename**: 01-cover-ai-tools.png
**Text Content**:
- Title: 「5个AI神器让你效率翻倍」
- Subtitle: 亲测好用,建议收藏
**Visual Concept**:
科技感背景,多个AI工具图标环绕,中心大标题,
霓虹蓝+深色背景,未来感十足
**Swipe Hook**: 第一个就很强大👇
---
## Image 2 of 6
**Position**: Content
**Layout**: balanced
**Core Message**: 为什么你需要AI工具
**Slug**: why-ai
**Filename**: 02-content-why-ai.png
**Text Content**:
- Title: 「为什么要用AI?」
- Points:
- 重复工作自动化
- 创意辅助不卡壳
- 效率提升10倍
**Visual Concept**:
对比图:左边疲惫打工人,右边轻松使用AI的人
科技线条装饰,简洁有力
**Swipe Hook**: 接下来是具体工具推荐👇
---
## Image 3 of 6
**Position**: Content
**Layout**: dense
**Core Message**: ChatGPT使用技巧
**Slug**: chatgpt
**Filename**: 03-content-chatgpt.png
**Text Content**:
- Title: 「ChatGPT」
- Subtitle: 最强AI助手
- Points:
- 写文案:给出框架,秒出初稿
- 改文章:润色、翻译、总结
- 编程:写代码、找bug
- 学习:解释概念、出题练习
**Visual Concept**:
ChatGPT logo居中,四周放射状展示功能点
深色科技背景,霓虹绿点缀
**Swipe Hook**: 下一个更适合创意工作者👇
---
## Image 4 of 6
**Position**: Content
**Layout**: dense
**Core Message**: Midjourney绘图
**Slug**: midjourney
**Filename**: 04-content-midjourney.png
**Text Content**:
- Title: 「Midjourney」
- Subtitle: AI绘画神器
- Points:
- 输入描述,秒出图片
- 风格多样:写实/插画/3D
- 做封面、做头像、做素材
- 不会画画也能当设计师
**Visual Concept**:
展示几张MJ生成的不同风格图片
画框/画布元素装饰
**Swipe Hook**: 还有一个效率神器👇
---
## Image 5 of 6
**Position**: Content
**Layout**: balanced
**Core Message**: Notion AI笔记
**Slug**: notion-ai
**Filename**: 05-content-notion-ai.png
**Text Content**:
- Title: 「Notion AI」
- Subtitle: 智能笔记助手
- Points:
- 自动总结长文
- 头脑风暴出点子
- 整理会议记录
**Visual Concept**:
Notion界面风格,简洁黑白配色
展示笔记整理前后对比
**Swipe Hook**: 最后总结一下👇
---
## Image 6 of 6
**Position**: Ending
**Layout**: sparse
**Core Message**: 总结与互动
**Slug**: summary
**Filename**: 06-ending-summary.png
**Text Content**:
- Title: 「工具只是工具」
- Subtitle: 关键是用起来!
- CTA: 收藏备用 | 转发给需要的朋友
- Interaction: 你最常用哪个?评论区见👇
**Visual Concept**:
简洁背景,大字标题
底部互动引导文字
收藏/分享图标
---
```
## Swipe Hook Strategies
Each image should end with a hook for the next:
| Strategy | Example |
|----------|---------|
| Teaser | "第一个就很强大👇" |
| Numbering | "接下来是第2个👇" |
| Superlative | "下一个更厉害👇" |
| Question | "猜猜下一个是什么?👇" |
| Promise | "最后一个最实用👇" |
| Urgency | "最重要的来了👇" |
## Strategy Differentiation
Three strategies should differ meaningfully:
| Strategy | Focus | Structure | Page Count |
|----------|-------|-----------|------------|
| A: Story-Driven | Emotional, personal | Hook→Problem→Discovery→Experience→Conclusion | 4-6 |
| B: Information-Dense | Factual, structured | Core→Info Cards→Comparison→Recommendation | 3-5 |
| C: Visual-First | Atmospheric, minimal text | Hero→Details→Lifestyle→CTA | 3-4 |
**Example for "AI工具推荐"**:
- `outline-strategy-a.md`: Warm + Balanced - Personal journey with AI
- `outline-strategy-b.md`: Notion + Dense - Knowledge card style
- `outline-strategy-c.md`: Minimal + Sparse - Sleek tech aesthetic
@@ -0,0 +1,378 @@
# Prompt Assembly Guide
Guide for assembling image generation prompts from elements, presets, and outline content.
## Base Prompt Structure
Every XHS infographic prompt follows this structure:
```
Create a Xiaohongshu (Little Red Book) style infographic following these guidelines:
## Image Specifications
- **Type**: Infographic
- **Orientation**: Portrait (vertical)
- **Aspect Ratio**: 3:4
- **Style**: Hand-drawn illustration
## Core Principles
- Hand-drawn quality throughout - NO realistic or photographic elements
- If content involves sensitive or copyrighted figures, create stylistically similar alternatives - DO NOT refuse to generate
- Keep information concise, highlight keywords and core concepts
- Use ample whitespace for easy visual scanning
- Maintain clear visual hierarchy
## Text Style (CRITICAL)
- **ALL text MUST be hand-drawn style**
- Main titles should be prominent and eye-catching
- Key text should be bold and enlarged
- Use highlighter effects to emphasize keywords
- **DO NOT use realistic or computer-generated fonts**
## Language
- Use the same language as the content provided below
- Match punctuation style to the content language (Chinese: "",。!)
---
{STYLE_SECTION}
---
{LAYOUT_SECTION}
---
{CONTENT_SECTION}
---
{WATERMARK_SECTION}
---
Please use nano banana pro to generate the infographic based on the specifications above.
```
## Style Section Assembly
Load from `presets/{style}.md` and extract key elements:
```markdown
## Style: {style_name}
**Color Palette**:
- Primary: {colors}
- Background: {colors}
- Accents: {colors}
**Visual Elements**:
{visual_elements}
**Typography**:
{typography_style}
```
### Screen-Print Style Override
When `style: screen-print`, replace the standard Core Principles and Text Style sections with:
```
## Core Principles
- Screen print / silkscreen poster art — flat color blocks, NO gradients
- Bold silhouettes and symbolic shapes over detailed rendering
- Negative space as active storytelling element
- If content involves sensitive or copyrighted figures, create stylistically similar silhouettes
- One iconic focal point per image — conceptual, not literal
## Color Rules (CRITICAL)
- **2-5 FLAT COLORS MAXIMUM** — fewer colors = stronger impact
- Choose ONE duotone pair from preset as dominant palette
- Halftone dot patterns for tonal variation (NOT gradients)
- Slight color layer misregistration for print authenticity
## Text Style (CRITICAL)
- Bold condensed sans-serif or Art Deco influenced lettering
- Typography INTEGRATED into composition as design element
- High contrast with background, stencil-cut quality
- **DO NOT use delicate, thin, or handwritten fonts**
## Composition
- Geometric framing: circles, arches, triangles
- Figure-ground inversion where possible (negative space forms secondary image)
- Stencil-cut edges between color blocks, no outlines
- Paper grain texture beneath all colors
```
## Palette Override
When `--palette` is specified (or style has `default_palette` in frontmatter and no explicit `--palette`), palette colors **replace** the style's Color Palette in the prompt. Style rendering rules (Visual Elements, Typography, Style Rules) remain unchanged.
Load from `palettes/{palette}.md` and override:
```markdown
## Palette Override: {palette_name}
**Background**: {palette background color and hex}
**Colors**:
- Text: {text color and hex}
- Secondary: {secondary text color and hex}
- Zone 1: {zone color and hex}
- Zone 2: {zone color and hex}
- Zone 3: {zone color and hex}
- Zone 4: {zone color and hex}
- Accent: {accent color and hex}
**Constraint**: {semantic constraint from palette}
```
**Override rules**:
1. Palette Background **replaces** style's background color (keep style's texture description)
2. Palette Colors **replace** style's Color Palette section entirely
3. Palette Semantic Constraint is appended to the style section
4. If no `--palette` and style has `default_palette` → load that palette
5. If no `--palette` and no `default_palette` → use style's built-in colors (no override)
6. Explicit `--palette` always overrides style's `default_palette`
## Layout Section Assembly
Load from `elements/canvas.md` and extract relevant layout:
```markdown
## Layout: {layout_name}
**Information Density**: {density}
**Whitespace**: {percentage}
**Structure**:
{structure_description}
**Visual Balance**:
{balance_description}
```
## Content Section Assembly
From outline entry:
```markdown
## Content
**Position**: {Cover/Content/Ending}
**Core Message**: {message}
**Text Content**:
{text_list}
**Visual Concept**:
{visual_description}
```
## Watermark Section (if enabled)
```markdown
## Watermark
Include a subtle watermark "{content}" positioned at {position}. The watermark should
be legible but not distracting from the main content.
```
## Assembly Process
### Step 0: Resolve Style Preset (if `--preset` used)
If user specified `--preset`, resolve to style + layout + palette from `references/style-presets.md`:
```python
# e.g., --preset hand-drawn-edu → style=sketch-notes, layout=flow, palette=macaron
style, layout, palette = resolve_preset(preset_name)
```
Explicit `--style`/`--layout`/`--palette` flags override preset values.
### Step 1: Load Style Definition
```python
preset = load_preset(style_name) # e.g., "sketch-notes"
```
Extract:
- Color palette (may be overridden by palette)
- Visual elements
- Typography style
- Best practices (do/don't)
- `default_palette` from frontmatter (if present)
### Step 1.5: Apply Palette Override (if applicable)
```python
# Priority: explicit --palette > preset palette > style default_palette > none
palette = resolve_palette(cli_palette, preset_palette, style_default_palette)
if palette:
palette_def = load_palette(palette) # e.g., "macaron"
# Replace style colors with palette colors
# Keep style rendering rules (visual elements, typography, style rules)
```
### Step 2: Load Layout
```python
layout = get_layout_from_canvas(layout_name) # e.g., "dense"
```
Extract:
- Information density guidelines
- Whitespace percentage
- Structure description
- Visual balance rules
### Step 3: Format Content
From outline entry, format:
- Position context (Cover/Content/Ending)
- Text content with hierarchy
- Visual concept description
- Swipe hook (for context, not in prompt)
### Step 4: Add Watermark (if applicable)
If preferences include watermark:
- Add watermark section with content, position, opacity
### Step 5: Visual Consistency — Reference Image Chain
When generating multiple images in a series:
1. **Image 1 (cover)**: Generate without `--ref` — this establishes the visual anchor
2. **Images 2+**: Always pass image 1 as `--ref` to the installed image generation skill.
Read that skill's `SKILL.md` and use its documented interface rather than calling its scripts directly.
For each later image, use the assembled prompt file as input, set the output image path, keep aspect ratio `3:4`, use quality `2k`, and pass image 1 as the reference.
This ensures the AI maintains the same character design, illustration style, and color rendering across the series.
### Step 6: Combine
Assemble all sections into final prompt following base structure.
## Example: Assembled Prompt
```markdown
Create a Xiaohongshu (Little Red Book) style infographic following these guidelines:
## Image Specifications
- **Type**: Infographic
- **Orientation**: Portrait (vertical)
- **Aspect Ratio**: 3:4
- **Style**: Hand-drawn illustration
## Core Principles
- Hand-drawn quality throughout - NO realistic or photographic elements
- If content involves sensitive or copyrighted figures, create stylistically similar alternatives
- Keep information concise, highlight keywords and core concepts
- Use ample whitespace for easy visual scanning
- Maintain clear visual hierarchy
## Text Style (CRITICAL)
- **ALL text MUST be hand-drawn style**
- Main titles should be prominent and eye-catching
- Key text should be bold and enlarged
- Use highlighter effects to emphasize keywords
- **DO NOT use realistic or computer-generated fonts**
## Language
- Use the same language as the content provided below
- Match punctuation style to the content language (Chinese: "",。!)
---
## Style: Notion
**Color Palette**:
- Primary: Black (#1A1A1A), dark gray (#4A4A4A)
- Background: Pure white (#FFFFFF), off-white (#FAFAFA)
- Accents: Pastel blue (#A8D4F0), pastel yellow (#F9E79F), pastel pink (#FADBD8)
**Visual Elements**:
- Simple line doodles, hand-drawn wobble effect
- Geometric shapes, stick figures
- Maximum whitespace, single-weight ink lines
- Clean, uncluttered compositions
**Typography**:
- Clean hand-drawn lettering
- Simple sans-serif labels
- Minimal decoration on text
---
## Layout: Dense
**Information Density**: High (5-8 key points)
**Whitespace**: 20-30% of canvas
**Structure**:
- Multiple sections, structured grid
- More text, compact but organized
- Title + multiple sections with headers + numerous points
**Visual Balance**:
- Organized grid structure
- Clear section boundaries
- Compact but readable spacing
---
## Content
**Position**: Content (Page 3 of 6)
**Core Message**: ChatGPT 使用技巧
**Text Content**:
- Title: 「ChatGPT」
- Subtitle: 最强 AI 助手
- Points:
- 写文案:给出框架,秒出初稿
- 改文章:润色、翻译、总结
- 编程:写代码、找 bug
- 学习:解释概念、出题练习
**Visual Concept**:
ChatGPT logo 居中,四周放射状展示功能点
深色科技背景,霓虹绿点缀
---
## Watermark
Include a subtle watermark "@myxhsaccount" positioned at bottom-right
with approximately 50% visibility. The watermark should
be legible but not distracting from the main content.
---
Please use nano banana pro to generate the infographic based on the specifications above.
```
## Prompt Checklist
Before generating, verify:
- [ ] Style section loaded from correct preset
- [ ] Palette override applied (if `--palette` specified or style has `default_palette`)
- [ ] Layout section matches outline specification
- [ ] Content accurately reflects outline entry
- [ ] Language matches source content
- [ ] Watermark included (if enabled in preferences)
- [ ] No conflicting instructions
+44 -6
View File
@@ -1,7 +1,7 @@
---
name: baoyu-imagine
description: AI image generation with OpenAI, Azure OpenAI, Google, OpenRouter, DashScope, MiniMax, Jimeng, Seedream and Replicate APIs. Supports text-to-image, reference images, aspect ratios, and batch generation from saved prompt files. Sequential by default; use batch parallel generation when the user already has multiple prompts or wants stable multi-image throughput. Use when user asks to generate, create, or draw images.
version: 1.56.4
description: AI image generation with OpenAI, Azure OpenAI, Google, OpenRouter, DashScope, Z.AI GLM-Image, MiniMax, Jimeng, Seedream and Replicate APIs. Supports text-to-image, reference images, aspect ratios, and batch generation from saved prompt files. Sequential by default; use batch parallel generation when the user already has multiple prompts or wants stable multi-image throughput. Use when user asks to generate, create, or draw images.
version: 1.57.0
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-imagine
@@ -13,7 +13,7 @@ metadata:
# Image Generation (AI SDK)
Official API-based image generation. Supports OpenAI, Azure OpenAI, Google, OpenRouter, DashScope (阿里通义万象), MiniMax, Jimeng (即梦), Seedream (豆包) and Replicate providers.
Official API-based image generation. Supports OpenAI, Azure OpenAI, Google, OpenRouter, DashScope (阿里通义万象), Z.AI GLM-Image, MiniMax, Jimeng (即梦), Seedream (豆包) and Replicate providers.
## Script Directory
@@ -103,6 +103,12 @@ ${BUN_X} {baseDir}/scripts/main.ts --prompt "为咖啡品牌设计一张 21:9
# DashScope legacy Qwen fixed-size model
${BUN_X} {baseDir}/scripts/main.ts --prompt "一张电影感海报" --image out.png --provider dashscope --model qwen-image-max --size 1664x928
# Z.AI GLM-image
${BUN_X} {baseDir}/scripts/main.ts --prompt "一张带清晰中文标题的科技海报" --image out.png --provider zai
# Z.AI GLM-image with explicit custom size
${BUN_X} {baseDir}/scripts/main.ts --prompt "A science illustration with labels" --image out.png --provider zai --model glm-image --size 1472x1088
# MiniMax
${BUN_X} {baseDir}/scripts/main.ts --prompt "A fashion editorial portrait by a bright studio window" --image out.jpg --provider minimax
@@ -161,8 +167,8 @@ Paths in `promptFiles`, `image`, and `ref` are resolved relative to the batch fi
| `--image <path>` | Output image path (required in single-image mode) |
| `--batchfile <path>` | JSON batch file for multi-image generation |
| `--jobs <count>` | Worker count for batch mode (default: auto, max from config, built-in default 10) |
| `--provider google\|openai\|azure\|openrouter\|dashscope\|minimax\|jimeng\|seedream\|replicate` | Force provider (default: auto-detect) |
| `--model <id>`, `-m` | Model ID (Google: `gemini-3-pro-image-preview`; OpenAI: `gpt-image-1.5`; Azure: deployment name such as `gpt-image-1.5` or `image-prod`; OpenRouter: `google/gemini-3.1-flash-image-preview`; DashScope: `qwen-image-2.0-pro`; MiniMax: `image-01`) |
| `--provider google\|openai\|azure\|openrouter\|dashscope\|zai\|minimax\|jimeng\|seedream\|replicate` | Force provider (default: auto-detect) |
| `--model <id>`, `-m` | Model ID (Google: `gemini-3-pro-image-preview`; OpenAI: `gpt-image-1.5`; Azure: deployment name such as `gpt-image-1.5` or `image-prod`; OpenRouter: `google/gemini-3.1-flash-image-preview`; DashScope: `qwen-image-2.0-pro`; Z.AI: `glm-image`; MiniMax: `image-01`) |
| `--ar <ratio>` | Aspect ratio (e.g., `16:9`, `1:1`, `4:3`) |
| `--size <WxH>` | Size (e.g., `1024x1024`) |
| `--quality normal\|2k` | Quality preset (default: `2k`) |
@@ -180,6 +186,8 @@ Paths in `promptFiles`, `image`, and `ref` are resolved relative to the batch fi
| `OPENROUTER_API_KEY` | OpenRouter API key |
| `GOOGLE_API_KEY` | Google API key |
| `DASHSCOPE_API_KEY` | DashScope API key (阿里云) |
| `ZAI_API_KEY` | Z.AI API key |
| `BIGMODEL_API_KEY` | Backward-compatible alias for Z.AI API key |
| `MINIMAX_API_KEY` | MiniMax API key |
| `REPLICATE_API_TOKEN` | Replicate API token |
| `JIMENG_ACCESS_KEY_ID` | Jimeng (即梦) Volcengine access key |
@@ -191,6 +199,8 @@ Paths in `promptFiles`, `image`, and `ref` are resolved relative to the batch fi
| `OPENROUTER_IMAGE_MODEL` | OpenRouter model override (default: `google/gemini-3.1-flash-image-preview`) |
| `GOOGLE_IMAGE_MODEL` | Google model override |
| `DASHSCOPE_IMAGE_MODEL` | DashScope model override (default: `qwen-image-2.0-pro`) |
| `ZAI_IMAGE_MODEL` | Z.AI model override (default: `glm-image`) |
| `BIGMODEL_IMAGE_MODEL` | Backward-compatible alias for Z.AI model override |
| `MINIMAX_IMAGE_MODEL` | MiniMax model override (default: `image-01`) |
| `REPLICATE_IMAGE_MODEL` | Replicate model override (default: google/nano-banana-pro) |
| `JIMENG_IMAGE_MODEL` | Jimeng model override (default: jimeng_t2i_v40) |
@@ -203,6 +213,8 @@ Paths in `promptFiles`, `image`, and `ref` are resolved relative to the batch fi
| `OPENROUTER_TITLE` | Optional app name for OpenRouter attribution |
| `GOOGLE_BASE_URL` | Custom Google endpoint |
| `DASHSCOPE_BASE_URL` | Custom DashScope endpoint |
| `ZAI_BASE_URL` | Custom Z.AI endpoint (default: `https://api.z.ai/api/paas/v4`) |
| `BIGMODEL_BASE_URL` | Backward-compatible alias for Z.AI endpoint |
| `MINIMAX_BASE_URL` | Custom MiniMax endpoint (default: `https://api.minimax.io`) |
| `REPLICATE_BASE_URL` | Custom Replicate endpoint |
| `JIMENG_BASE_URL` | Custom Jimeng endpoint (default: `https://visual.volcengineapi.com`) |
@@ -277,6 +289,32 @@ Official references:
- [Text-to-image guide](https://help.aliyun.com/zh/model-studio/text-to-image)
- [Qwen-Image Edit API](https://help.aliyun.com/zh/model-studio/qwen-image-edit-api)
### Z.AI Models
Use `--model glm-image` or set `default_model.zai` / `ZAI_IMAGE_MODEL` when the user wants GLM-image output.
Official Z.AI image model options currently documented in the sync image API:
- `glm-image` (recommended default)
- Text-to-image only in `baoyu-imagine`
- Native `quality` options are `hd` and `standard`; this skill maps `2k -> hd` and `normal -> standard`
- Recommended sizes: `1280x1280`, `1568x1056`, `1056x1568`, `1472x1088`, `1088x1472`, `1728x960`, `960x1728`
- Custom `--size` requires width and height between `1024` and `2048`, divisible by `32`, with total pixels <= `2^22`
- `cogview-4-250304`
- Legacy Z.AI image model family exposed by the same endpoint
- Custom `--size` requires width and height between `512` and `2048`, divisible by `16`, with total pixels <= `2^21`
Notes:
- The official sync API returns a temporary image URL; `baoyu-imagine` downloads that URL and writes the image locally
- `--ref` is not supported for Z.AI in this skill yet
- The sync API currently returns a single image, so `--n > 1` is rejected
Official references:
- [GLM-Image Guide](https://docs.z.ai/guides/image/glm-image)
- [Generate Image API](https://docs.z.ai/api-reference/image/generate-image)
### MiniMax Models
Use `--model image-01` or set `default_model.minimax` / `MINIMAX_IMAGE_MODEL` when the user wants MiniMax image generation.
@@ -342,7 +380,7 @@ ${BUN_X} {baseDir}/scripts/main.ts --prompt "A cat" --image out.png --provider r
1. `--ref` provided + no `--provider` → auto-select Google first, then OpenAI, then Azure, then OpenRouter, then Replicate, then Seedream, then MiniMax (MiniMax subject reference is more specialized toward character/portrait consistency)
2. `--provider` specified → use it (if `--ref`, must be `google`, `openai`, `azure`, `openrouter`, `replicate`, `seedream`, or `minimax`)
3. Only one API key available → use that provider
4. Multiple available → default to Google
4. Multiple available → default to Google, then OpenAI, Azure, OpenRouter, DashScope, Z.AI, MiniMax, Replicate, Jimeng, Seedream
## Quality Presets
@@ -53,6 +53,8 @@ options:
description: "Router for Gemini/FLUX/OpenAI-compatible image models"
- label: "DashScope"
description: "Alibaba Cloud - Qwen-Image, strong Chinese/English text rendering"
- label: "Z.AI"
description: "GLM-image, strong poster and text-heavy image generation"
- label: "MiniMax"
description: "MiniMax image generation with subject-reference character workflows"
- label: "Replicate"
@@ -119,6 +121,20 @@ options:
description: "Faster variant, use aspect ratio instead of custom size"
```
### Question 2e: Default Z.AI Model
Only show if user selected Z.AI.
```yaml
header: "Z.AI Model"
question: "Default Z.AI image generation model?"
options:
- label: "glm-image (Recommended)"
description: "Best default for posters, diagrams, and text-heavy images"
- label: "cogview-4-250304"
description: "Legacy Z.AI image model on the same endpoint"
```
### Question 3: Default Quality
```yaml
@@ -165,6 +181,7 @@ default_model:
azure: [selected azure deployment or null]
openrouter: [selected openrouter model or null]
dashscope: null
zai: [selected Z.AI model or null]
minimax: [selected minimax model or null]
replicate: null
---
@@ -257,6 +274,24 @@ Notes for DashScope setup:
- `qwen-image-max` / `qwen-image-plus` / `qwen-image` only support five fixed sizes: `1664*928`, `1472*1104`, `1328*1328`, `1104*1472`, `928*1664`.
- In `baoyu-imagine`, `quality` is a compatibility preset. It is not a native DashScope parameter.
### Z.AI Model Selection
```yaml
header: "Z.AI Model"
question: "Choose a default Z.AI image generation model?"
options:
- label: "glm-image (Recommended)"
description: "Current flagship image model with better text rendering and poster layouts"
- label: "cogview-4-250304"
description: "Legacy model on the sync image endpoint"
```
Notes for Z.AI setup:
- Prefer `glm-image` for posters, diagrams, and Chinese/English text-heavy layouts.
- In `baoyu-imagine`, Z.AI currently exposes text-to-image only; reference images are not wired for this provider.
- The sync Z.AI image API returns a downloadable image URL, which the runtime saves locally after download.
### Replicate Model Selection
```yaml
@@ -302,6 +337,7 @@ default_model:
azure: [value or null]
openrouter: [value or null]
dashscope: [value or null]
zai: [value or null]
minimax: [value or null]
replicate: [value or null]
```
@@ -11,7 +11,7 @@ description: EXTEND.md YAML schema for baoyu-imagine user preferences
---
version: 1
default_provider: null # google|openai|azure|openrouter|dashscope|minimax|replicate|null (null = auto-detect)
default_provider: null # google|openai|azure|openrouter|dashscope|zai|minimax|replicate|null (null = auto-detect)
default_quality: null # normal|2k|null (null = use default: 2k)
@@ -25,6 +25,7 @@ default_model:
azure: null # Azure deployment name, e.g., "gpt-image-1.5" or "image-prod"
openrouter: null # e.g., "google/gemini-3.1-flash-image-preview"
dashscope: null # e.g., "qwen-image-2.0-pro"
zai: null # e.g., "glm-image"
minimax: null # e.g., "image-01"
replicate: null # e.g., "google/nano-banana-pro"
@@ -49,6 +50,9 @@ batch:
dashscope:
concurrency: 3
start_interval_ms: 1100
zai:
concurrency: 3
start_interval_ms: 1100
minimax:
concurrency: 3
start_interval_ms: 1100
@@ -69,6 +73,7 @@ batch:
| `default_model.azure` | string\|null | null | Azure default deployment name |
| `default_model.openrouter` | string\|null | null | OpenRouter default model |
| `default_model.dashscope` | string\|null | null | DashScope default model |
| `default_model.zai` | string\|null | null | Z.AI default model |
| `default_model.minimax` | string\|null | null | MiniMax default model |
| `default_model.replicate` | string\|null | null | Replicate default model |
| `batch.max_workers` | int\|null | 10 | Batch worker cap |
@@ -100,6 +105,7 @@ default_model:
azure: "gpt-image-1.5"
openrouter: "google/gemini-3.1-flash-image-preview"
dashscope: "qwen-image-2.0-pro"
zai: "glm-image"
minimax: "image-01"
replicate: "google/nano-banana-pro"
batch:
@@ -111,6 +117,9 @@ batch:
azure:
concurrency: 3
start_interval_ms: 1100
zai:
concurrency: 3
start_interval_ms: 1100
openrouter:
concurrency: 3
start_interval_ms: 1100
+41 -2
View File
@@ -78,7 +78,7 @@ test("parseArgs parses the main baoyu-imagine CLI flags", () => {
"--image",
"out/hero",
"--provider",
"openai",
"zai",
"--quality",
"2k",
"--imageSize",
@@ -95,7 +95,7 @@ test("parseArgs parses the main baoyu-imagine CLI flags", () => {
assert.deepEqual(args.promptFiles, ["prompts/system.md", "prompts/content.md"]);
assert.equal(args.imagePath, "out/hero");
assert.equal(args.provider, "openai");
assert.equal(args.provider, "zai");
assert.equal(args.quality, "2k");
assert.equal(args.imageSize, "4K");
assert.deepEqual(args.referenceImages, ["ref/one.png", "ref/two.jpg"]);
@@ -124,6 +124,7 @@ default_image_size: 2K
default_model:
google: gemini-3-pro-image-preview
openai: gpt-image-1.5
zai: glm-image
azure: image-prod
minimax: image-01
batch:
@@ -134,6 +135,9 @@ batch:
start_interval_ms: 900
openai:
concurrency: 4
zai:
concurrency: 2
start_interval_ms: 1000
minimax:
concurrency: 2
start_interval_ms: 1400
@@ -151,6 +155,7 @@ batch:
assert.equal(config.default_image_size, "2K");
assert.equal(config.default_model?.google, "gemini-3-pro-image-preview");
assert.equal(config.default_model?.openai, "gpt-image-1.5");
assert.equal(config.default_model?.zai, "glm-image");
assert.equal(config.default_model?.azure, "image-prod");
assert.equal(config.default_model?.minimax, "image-01");
assert.equal(config.batch?.max_workers, 8);
@@ -161,6 +166,10 @@ batch:
assert.deepEqual(config.batch?.provider_limits?.openai, {
concurrency: 4,
});
assert.deepEqual(config.batch?.provider_limits?.zai, {
concurrency: 2,
start_interval_ms: 1000,
});
assert.deepEqual(config.batch?.provider_limits?.minimax, {
concurrency: 2,
start_interval_ms: 1400,
@@ -316,6 +325,27 @@ test("detectProvider selects Azure when only Azure credentials are configured",
);
});
test("detectProvider selects Z.AI when credentials are present or the model id matches", (t) => {
useEnv(t, {
GOOGLE_API_KEY: null,
OPENAI_API_KEY: null,
AZURE_OPENAI_API_KEY: null,
AZURE_OPENAI_BASE_URL: null,
OPENROUTER_API_KEY: null,
DASHSCOPE_API_KEY: null,
ZAI_API_KEY: "zai-key",
BIGMODEL_API_KEY: null,
MINIMAX_API_KEY: null,
REPLICATE_API_TOKEN: null,
JIMENG_ACCESS_KEY_ID: null,
JIMENG_SECRET_ACCESS_KEY: null,
ARK_API_KEY: null,
});
assert.equal(detectProvider(makeArgs()), "zai");
assert.equal(detectProvider(makeArgs({ model: "glm-image" })), "zai");
});
test("detectProvider infers Seedream from model id and allows Seedream reference-image workflows", (t) => {
useEnv(t, {
GOOGLE_API_KEY: null,
@@ -375,6 +405,7 @@ test("batch worker and provider-rate-limit configuration prefer env over EXTEND
BAOYU_IMAGE_GEN_MAX_WORKERS: "12",
BAOYU_IMAGE_GEN_GOOGLE_CONCURRENCY: "5",
BAOYU_IMAGE_GEN_GOOGLE_START_INTERVAL_MS: "450",
BAOYU_IMAGE_GEN_ZAI_CONCURRENCY: "4",
});
const extendConfig: Partial<ExtendConfig> = {
@@ -385,6 +416,10 @@ test("batch worker and provider-rate-limit configuration prefer env over EXTEND
concurrency: 2,
start_interval_ms: 900,
},
zai: {
concurrency: 1,
start_interval_ms: 1200,
},
minimax: {
concurrency: 1,
start_interval_ms: 1500,
@@ -398,6 +433,10 @@ test("batch worker and provider-rate-limit configuration prefer env over EXTEND
concurrency: 5,
startIntervalMs: 450,
});
assert.deepEqual(getConfiguredProviderRateLimits(extendConfig).zai, {
concurrency: 4,
startIntervalMs: 1200,
});
assert.deepEqual(getConfiguredProviderRateLimits(extendConfig).minimax, {
concurrency: 1,
startIntervalMs: 1500,
+28 -4
View File
@@ -58,6 +58,7 @@ const DEFAULT_PROVIDER_RATE_LIMITS: Record<Provider, ProviderRateLimit> = {
openai: { concurrency: 3, startIntervalMs: 1100 },
openrouter: { concurrency: 3, startIntervalMs: 1100 },
dashscope: { concurrency: 3, startIntervalMs: 1100 },
zai: { concurrency: 3, startIntervalMs: 1100 },
minimax: { concurrency: 3, startIntervalMs: 1100 },
jimeng: { concurrency: 3, startIntervalMs: 1100 },
seedream: { concurrency: 3, startIntervalMs: 1100 },
@@ -76,7 +77,7 @@ Options:
--image <path> Output image path (required in single-image mode)
--batchfile <path> JSON batch file for multi-image generation
--jobs <count> Worker count for batch mode (default: auto, max from config, built-in default 10)
--provider google|openai|openrouter|dashscope|minimax|replicate|jimeng|seedream|azure Force provider (auto-detect by default)
--provider google|openai|openrouter|dashscope|zai|minimax|replicate|jimeng|seedream|azure Force provider (auto-detect by default)
-m, --model <id> Model ID
--ar <ratio> Aspect ratio (e.g., 16:9, 1:1, 4:3)
--size <WxH> Size (e.g., 1024x1024)
@@ -113,6 +114,8 @@ Environment variables:
GOOGLE_API_KEY Google API key
GEMINI_API_KEY Gemini API key (alias for GOOGLE_API_KEY)
DASHSCOPE_API_KEY DashScope API key
ZAI_API_KEY Z.AI API key
BIGMODEL_API_KEY Backward-compatible alias for Z.AI API key
MINIMAX_API_KEY MiniMax API key
REPLICATE_API_TOKEN Replicate API token
JIMENG_ACCESS_KEY_ID Jimeng Access Key ID
@@ -122,6 +125,8 @@ Environment variables:
OPENROUTER_IMAGE_MODEL Default OpenRouter model (google/gemini-3.1-flash-image-preview)
GOOGLE_IMAGE_MODEL Default Google model (gemini-3-pro-image-preview)
DASHSCOPE_IMAGE_MODEL Default DashScope model (qwen-image-2.0-pro)
ZAI_IMAGE_MODEL Default Z.AI model (glm-image)
BIGMODEL_IMAGE_MODEL Backward-compatible alias for Z.AI model (glm-image)
MINIMAX_IMAGE_MODEL Default MiniMax model (image-01)
REPLICATE_IMAGE_MODEL Default Replicate model (google/nano-banana-pro)
JIMENG_IMAGE_MODEL Default Jimeng model (jimeng_t2i_v40)
@@ -133,6 +138,8 @@ Environment variables:
OPENROUTER_TITLE Optional app name for OpenRouter attribution
GOOGLE_BASE_URL Custom Google endpoint
DASHSCOPE_BASE_URL Custom DashScope endpoint
ZAI_BASE_URL Custom Z.AI endpoint
BIGMODEL_BASE_URL Backward-compatible alias for Z.AI endpoint
MINIMAX_BASE_URL Custom MiniMax endpoint
REPLICATE_BASE_URL Custom Replicate endpoint
JIMENG_BASE_URL Custom Jimeng endpoint
@@ -239,6 +246,7 @@ export function parseArgs(argv: string[]): CliArgs {
v !== "openai" &&
v !== "openrouter" &&
v !== "dashscope" &&
v !== "zai" &&
v !== "minimax" &&
v !== "replicate" &&
v !== "jimeng" &&
@@ -395,6 +403,7 @@ export function parseSimpleYaml(yaml: string): Partial<ExtendConfig> {
openai: null,
openrouter: null,
dashscope: null,
zai: null,
minimax: null,
replicate: null,
jimeng: null,
@@ -423,6 +432,7 @@ export function parseSimpleYaml(yaml: string): Partial<ExtendConfig> {
key === "openai" ||
key === "openrouter" ||
key === "dashscope" ||
key === "zai" ||
key === "minimax" ||
key === "replicate" ||
key === "jimeng" ||
@@ -441,6 +451,7 @@ export function parseSimpleYaml(yaml: string): Partial<ExtendConfig> {
key === "openai" ||
key === "openrouter" ||
key === "dashscope" ||
key === "zai" ||
key === "minimax" ||
key === "replicate" ||
key === "jimeng" ||
@@ -571,13 +582,14 @@ export function getConfiguredProviderRateLimits(
openai: { ...DEFAULT_PROVIDER_RATE_LIMITS.openai },
openrouter: { ...DEFAULT_PROVIDER_RATE_LIMITS.openrouter },
dashscope: { ...DEFAULT_PROVIDER_RATE_LIMITS.dashscope },
zai: { ...DEFAULT_PROVIDER_RATE_LIMITS.zai },
minimax: { ...DEFAULT_PROVIDER_RATE_LIMITS.minimax },
jimeng: { ...DEFAULT_PROVIDER_RATE_LIMITS.jimeng },
seedream: { ...DEFAULT_PROVIDER_RATE_LIMITS.seedream },
azure: { ...DEFAULT_PROVIDER_RATE_LIMITS.azure },
};
for (const provider of ["replicate", "google", "openai", "openrouter", "dashscope", "minimax", "jimeng", "seedream", "azure"] as Provider[]) {
for (const provider of ["replicate", "google", "openai", "openrouter", "dashscope", "zai", "minimax", "jimeng", "seedream", "azure"] as Provider[]) {
const envPrefix = `BAOYU_IMAGE_GEN_${provider.toUpperCase()}`;
const extendLimit = extendConfig.batch?.provider_limits?.[provider];
configured[provider] = {
@@ -629,6 +641,7 @@ function inferProviderFromModel(model: string | null): Provider | null {
const normalized = model.trim();
if (normalized.includes("seedream") || normalized.includes("seededit")) return "seedream";
if (normalized === "image-01" || normalized === "image-01-live") return "minimax";
if (normalized === "glm-image" || normalized === "cogview-4-250304") return "zai";
return null;
}
@@ -656,6 +669,7 @@ export function detectProvider(args: CliArgs): Provider {
const hasOpenai = !!process.env.OPENAI_API_KEY;
const hasOpenrouter = !!process.env.OPENROUTER_API_KEY;
const hasDashscope = !!process.env.DASHSCOPE_API_KEY;
const hasZai = !!(process.env.ZAI_API_KEY || process.env.BIGMODEL_API_KEY);
const hasMinimax = !!process.env.MINIMAX_API_KEY;
const hasReplicate = !!process.env.REPLICATE_API_TOKEN;
const hasJimeng = !!(process.env.JIMENG_ACCESS_KEY_ID && process.env.JIMENG_SECRET_ACCESS_KEY);
@@ -676,6 +690,13 @@ export function detectProvider(args: CliArgs): Provider {
return "minimax";
}
if (modelProvider === "zai") {
if (!hasZai) {
throw new Error("Model looks like a Z.AI image model, but ZAI_API_KEY is not set.");
}
return "zai";
}
if (args.referenceImages.length > 0) {
if (hasGoogle) return "google";
if (hasOpenai) return "openai";
@@ -695,6 +716,7 @@ export function detectProvider(args: CliArgs): Provider {
hasAzure && "azure",
hasOpenrouter && "openrouter",
hasDashscope && "dashscope",
hasZai && "zai",
hasMinimax && "minimax",
hasReplicate && "replicate",
hasJimeng && "jimeng",
@@ -705,7 +727,7 @@ export function detectProvider(args: CliArgs): Provider {
if (available.length > 1) return available[0]!;
throw new Error(
"No API key found. Set GOOGLE_API_KEY, GEMINI_API_KEY, OPENAI_API_KEY, AZURE_OPENAI_API_KEY+AZURE_OPENAI_BASE_URL, OPENROUTER_API_KEY, DASHSCOPE_API_KEY, MINIMAX_API_KEY, REPLICATE_API_TOKEN, JIMENG keys, or ARK_API_KEY.\n" +
"No API key found. Set GOOGLE_API_KEY, GEMINI_API_KEY, OPENAI_API_KEY, AZURE_OPENAI_API_KEY+AZURE_OPENAI_BASE_URL, OPENROUTER_API_KEY, DASHSCOPE_API_KEY, ZAI_API_KEY, MINIMAX_API_KEY, REPLICATE_API_TOKEN, JIMENG keys, or ARK_API_KEY.\n" +
"Create ~/.baoyu-skills/.env or <cwd>/.baoyu-skills/.env with your keys."
);
}
@@ -744,6 +766,7 @@ export function isRetryableGenerationError(error: unknown): boolean {
async function loadProviderModule(provider: Provider): Promise<ProviderModule> {
if (provider === "google") return (await import("./providers/google")) as ProviderModule;
if (provider === "dashscope") return (await import("./providers/dashscope")) as ProviderModule;
if (provider === "zai") return (await import("./providers/zai")) as ProviderModule;
if (provider === "minimax") return (await import("./providers/minimax")) as ProviderModule;
if (provider === "replicate") return (await import("./providers/replicate")) as ProviderModule;
if (provider === "openrouter") return (await import("./providers/openrouter")) as ProviderModule;
@@ -775,6 +798,7 @@ function getModelForProvider(
return extendConfig.default_model.openrouter;
}
if (provider === "dashscope" && extendConfig.default_model.dashscope) return extendConfig.default_model.dashscope;
if (provider === "zai" && extendConfig.default_model.zai) return extendConfig.default_model.zai;
if (provider === "minimax" && extendConfig.default_model.minimax) return extendConfig.default_model.minimax;
if (provider === "replicate" && extendConfig.default_model.replicate) return extendConfig.default_model.replicate;
if (provider === "jimeng" && extendConfig.default_model.jimeng) return extendConfig.default_model.jimeng;
@@ -999,7 +1023,7 @@ async function runBatchTasks(
const acquireProvider = createProviderGate(providerRateLimits);
const workerCount = getWorkerCount(tasks.length, jobs, maxWorkers);
console.error(`Batch mode: ${tasks.length} tasks, ${workerCount} workers, parallel mode enabled.`);
for (const provider of ["replicate", "google", "openai", "openrouter", "dashscope", "jimeng", "seedream", "azure"] as Provider[]) {
for (const provider of ["replicate", "google", "openai", "openrouter", "dashscope", "zai", "minimax", "jimeng", "seedream", "azure"] as Provider[]) {
const limit = providerRateLimits[provider];
console.error(`- ${provider}: concurrency=${limit.concurrency}, startIntervalMs=${limit.startIntervalMs}`);
}
@@ -0,0 +1,180 @@
import assert from "node:assert/strict";
import test, { type TestContext } from "node:test";
import type { CliArgs } from "../types.ts";
import {
buildRequestBody,
buildZaiUrl,
extractImageFromResponse,
getDefaultModel,
getModelFamily,
parseAspectRatio,
parseSize,
resolveSizeForModel,
validateArgs,
} from "./zai.ts";
function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {
return {
prompt: null,
promptFiles: [],
imagePath: null,
provider: null,
model: null,
aspectRatio: null,
size: null,
quality: null,
imageSize: null,
referenceImages: [],
n: 1,
batchFile: null,
jobs: null,
json: false,
help: false,
...overrides,
};
}
function useEnv(
t: TestContext,
values: Record<string, string | null>,
): void {
const previous = new Map<string, string | undefined>();
for (const [key, value] of Object.entries(values)) {
previous.set(key, process.env[key]);
if (value == null) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
t.after(() => {
for (const [key, value] of previous.entries()) {
if (value == null) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
});
}
test("Z.AI default model prefers env override and otherwise uses glm-image", (t) => {
useEnv(t, {
ZAI_IMAGE_MODEL: null,
BIGMODEL_IMAGE_MODEL: null,
});
assert.equal(getDefaultModel(), "glm-image");
process.env.BIGMODEL_IMAGE_MODEL = "cogview-4-250304";
assert.equal(getDefaultModel(), "cogview-4-250304");
});
test("Z.AI URL builder normalizes host, v4 base, and full endpoint inputs", (t) => {
useEnv(t, { ZAI_BASE_URL: "https://api.z.ai" });
assert.equal(buildZaiUrl(), "https://api.z.ai/api/paas/v4/images/generations");
process.env.ZAI_BASE_URL = "https://proxy.example.com/api/paas/v4/";
assert.equal(buildZaiUrl(), "https://proxy.example.com/api/paas/v4/images/generations");
process.env.ZAI_BASE_URL = "https://proxy.example.com/custom/images/generations";
assert.equal(buildZaiUrl(), "https://proxy.example.com/custom/images/generations");
});
test("Z.AI model family and parsing helpers recognize documented formats", () => {
assert.equal(getModelFamily("glm-image"), "glm");
assert.equal(getModelFamily("cogview-4-250304"), "legacy");
assert.deepEqual(parseAspectRatio("16:9"), { width: 16, height: 9 });
assert.equal(parseAspectRatio("wide"), null);
assert.deepEqual(parseSize("1280x1280"), { width: 1280, height: 1280 });
assert.deepEqual(parseSize("1472*1088"), { width: 1472, height: 1088 });
assert.equal(parseSize("big"), null);
});
test("Z.AI size resolution follows documented recommended ratios and validates custom sizes", () => {
assert.equal(
resolveSizeForModel("glm-image", makeArgs({ aspectRatio: "16:9", quality: "2k" })),
"1728x960",
);
assert.equal(
resolveSizeForModel("cogview-4-250304", makeArgs({ aspectRatio: "4:3", quality: "normal" })),
"1152x864",
);
assert.equal(
resolveSizeForModel("glm-image", makeArgs({ size: "1568x1056", quality: "2k" })),
"1568x1056",
);
const uncommon = resolveSizeForModel(
"glm-image",
makeArgs({ aspectRatio: "5:2", quality: "normal" }),
);
const parsed = parseSize(uncommon);
assert.ok(parsed);
assert.ok(parsed.width % 32 === 0);
assert.ok(parsed.height % 32 === 0);
assert.ok(parsed.width * parsed.height <= 2 ** 22);
assert.throws(
() => resolveSizeForModel("glm-image", makeArgs({ size: "1000x1000", quality: "2k" })),
/between 1024 and 2048/,
);
assert.throws(
() => resolveSizeForModel("glm-image", makeArgs({ size: "1280x1260", quality: "2k" })),
/divisible by 32/,
);
assert.throws(
() => resolveSizeForModel("cogview-4-250304", makeArgs({ size: "2048x2048", quality: "2k" })),
/must not exceed 2\^21 total pixels/,
);
});
test("Z.AI validation rejects unsupported refs and multi-image requests", () => {
assert.throws(
() => validateArgs("glm-image", makeArgs({ referenceImages: ["ref.png"] })),
/text-to-image only/,
);
assert.throws(
() => validateArgs("glm-image", makeArgs({ n: 2 })),
/single image per request/,
);
});
test("Z.AI request body maps skill quality and resolved size into provider fields", () => {
const body = buildRequestBody(
"A cinematic science poster",
"glm-image",
makeArgs({ aspectRatio: "4:3", quality: "normal" }),
);
assert.deepEqual(body, {
model: "glm-image",
prompt: "A cinematic science poster",
quality: "standard",
size: "1472x1088",
});
});
test("Z.AI response extraction downloads the returned image URL", async (t) => {
const originalFetch = globalThis.fetch;
t.after(() => {
globalThis.fetch = originalFetch;
});
globalThis.fetch = async () =>
new Response(Uint8Array.from([1, 2, 3]), {
status: 200,
headers: { "Content-Type": "image/png" },
});
const image = await extractImageFromResponse({
data: [{ url: "https://cdn.example.com/glm-image.png" }],
});
assert.deepEqual([...image], [1, 2, 3]);
await assert.rejects(
() => extractImageFromResponse({ data: [{}] }),
/No image URL/,
);
});
@@ -0,0 +1,306 @@
import type { CliArgs, Quality } from "../types";
type ZaiModelFamily = "glm" | "legacy";
type ZaiRequestBody = {
model: string;
prompt: string;
quality: "hd" | "standard";
size: string;
};
type ZaiResponse = {
data?: Array<{ url?: string }>;
};
const DEFAULT_MODEL = "glm-image";
const GLM_MAX_PIXELS = 2 ** 22;
const LEGACY_MAX_PIXELS = 2 ** 21;
const GLM_SIZE_STEP = 32;
const LEGACY_SIZE_STEP = 16;
const GLM_RECOMMENDED_SIZES: Record<string, string> = {
"1:1": "1280x1280",
"3:2": "1568x1056",
"2:3": "1056x1568",
"4:3": "1472x1088",
"3:4": "1088x1472",
"16:9": "1728x960",
"9:16": "960x1728",
};
const LEGACY_RECOMMENDED_SIZES: Record<string, string> = {
"1:1": "1024x1024",
"9:16": "768x1344",
"3:4": "864x1152",
"16:9": "1344x768",
"4:3": "1152x864",
"2:1": "1440x720",
"1:2": "720x1440",
};
export function getDefaultModel(): string {
return process.env.ZAI_IMAGE_MODEL || process.env.BIGMODEL_IMAGE_MODEL || DEFAULT_MODEL;
}
function getApiKey(): string | null {
return process.env.ZAI_API_KEY || process.env.BIGMODEL_API_KEY || null;
}
export function buildZaiUrl(): string {
const base = (process.env.ZAI_BASE_URL || process.env.BIGMODEL_BASE_URL || "https://api.z.ai/api/paas/v4")
.replace(/\/+$/g, "");
if (base.endsWith("/images/generations")) return base;
if (base.endsWith("/api/paas/v4")) return `${base}/images/generations`;
if (base.endsWith("/v4")) return `${base}/images/generations`;
return `${base}/api/paas/v4/images/generations`;
}
export function getModelFamily(model: string): ZaiModelFamily {
return model.trim().toLowerCase() === "glm-image" ? "glm" : "legacy";
}
export function parseAspectRatio(ar: string): { width: number; height: number } | null {
const match = ar.match(/^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?)$/);
if (!match) return null;
const width = Number(match[1]);
const height = Number(match[2]);
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
return null;
}
return { width, height };
}
export function parseSize(size: string): { width: number; height: number } | null {
const match = size.trim().match(/^(\d+)\s*[xX*]\s*(\d+)$/);
if (!match) return null;
const width = parseInt(match[1]!, 10);
const height = parseInt(match[2]!, 10);
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
return null;
}
return { width, height };
}
function formatSize(width: number, height: number): string {
return `${width}x${height}`;
}
function roundToStep(value: number, step: number): number {
return Math.max(step, Math.round(value / step) * step);
}
function getRatioValue(ar: string): number | null {
const parsed = parseAspectRatio(ar);
if (!parsed) return null;
return parsed.width / parsed.height;
}
function findClosestRatioKey(ar: string, candidates: string[]): string | null {
const targetRatio = getRatioValue(ar);
if (targetRatio == null) return null;
let bestKey: string | null = null;
let bestDiff = Infinity;
for (const candidate of candidates) {
const candidateRatio = getRatioValue(candidate);
if (candidateRatio == null) continue;
const diff = Math.abs(candidateRatio - targetRatio);
if (diff < bestDiff) {
bestDiff = diff;
bestKey = candidate;
}
}
return bestDiff <= 0.05 ? bestKey : null;
}
function getTargetPixels(quality: Quality): number {
return quality === "normal" ? 1024 * 1024 : 1536 * 1536;
}
function fitToPixelBudget(
width: number,
height: number,
targetPixels: number,
maxPixels: number,
step: number,
): { width: number; height: number } {
let nextWidth = width;
let nextHeight = height;
const pixels = nextWidth * nextHeight;
if (pixels > maxPixels) {
const scale = Math.sqrt(maxPixels / pixels);
nextWidth *= scale;
nextHeight *= scale;
} else {
const scale = Math.sqrt(targetPixels / pixels);
nextWidth *= scale;
nextHeight *= scale;
}
let roundedWidth = roundToStep(nextWidth, step);
let roundedHeight = roundToStep(nextHeight, step);
let roundedPixels = roundedWidth * roundedHeight;
while (roundedPixels > maxPixels && (roundedWidth > step || roundedHeight > step)) {
if (roundedWidth >= roundedHeight && roundedWidth > step) {
roundedWidth -= step;
} else if (roundedHeight > step) {
roundedHeight -= step;
} else {
break;
}
roundedPixels = roundedWidth * roundedHeight;
}
return { width: roundedWidth, height: roundedHeight };
}
function validateCustomSize(
size: string,
family: ZaiModelFamily,
): string {
const parsed = parseSize(size);
if (!parsed) {
throw new Error("Z.AI --size must be in WxH format, for example 1280x1280.");
}
const widthStep = family === "glm" ? GLM_SIZE_STEP : LEGACY_SIZE_STEP;
const minEdge = family === "glm" ? 1024 : 512;
const maxPixels = family === "glm" ? GLM_MAX_PIXELS : LEGACY_MAX_PIXELS;
if (parsed.width < minEdge || parsed.width > 2048 || parsed.height < minEdge || parsed.height > 2048) {
throw new Error(
family === "glm"
? "GLM-image custom size requires width and height between 1024 and 2048."
: "Z.AI legacy image models require width and height between 512 and 2048."
);
}
if (parsed.width % widthStep !== 0 || parsed.height % widthStep !== 0) {
throw new Error(
family === "glm"
? "GLM-image custom size requires width and height divisible by 32."
: "Z.AI legacy image models require width and height divisible by 16."
);
}
if (parsed.width * parsed.height > maxPixels) {
throw new Error(
family === "glm"
? "GLM-image custom size must not exceed 2^22 total pixels."
: "Z.AI legacy image size must not exceed 2^21 total pixels."
);
}
return formatSize(parsed.width, parsed.height);
}
export function resolveSizeForModel(
model: string,
args: Pick<CliArgs, "size" | "aspectRatio" | "quality">,
): string {
const family = getModelFamily(model);
const quality = args.quality === "normal" ? "normal" : "2k";
if (args.size) {
return validateCustomSize(args.size, family);
}
const recommended = family === "glm" ? GLM_RECOMMENDED_SIZES : LEGACY_RECOMMENDED_SIZES;
const defaultSize = family === "glm" ? "1280x1280" : "1024x1024";
if (!args.aspectRatio) return defaultSize;
const recommendedRatio = findClosestRatioKey(args.aspectRatio, Object.keys(recommended));
if (recommendedRatio) {
return recommended[recommendedRatio]!;
}
const parsedRatio = parseAspectRatio(args.aspectRatio);
if (!parsedRatio) return defaultSize;
const targetPixels = getTargetPixels(quality);
const maxPixels = family === "glm" ? GLM_MAX_PIXELS : LEGACY_MAX_PIXELS;
const step = family === "glm" ? GLM_SIZE_STEP : LEGACY_SIZE_STEP;
const fit = fitToPixelBudget(
parsedRatio.width,
parsedRatio.height,
targetPixels,
maxPixels,
step,
);
return formatSize(fit.width, fit.height);
}
function getZaiQuality(quality: CliArgs["quality"]): "hd" | "standard" {
return quality === "normal" ? "standard" : "hd";
}
export function validateArgs(_model: string, args: CliArgs): void {
if (args.referenceImages.length > 0) {
throw new Error("Z.AI GLM-image currently supports text-to-image only in baoyu-imagine. Remove --ref or choose another provider.");
}
if (args.n > 1) {
throw new Error("Z.AI image generation currently returns a single image per request in baoyu-imagine.");
}
}
export function buildRequestBody(
prompt: string,
model: string,
args: CliArgs,
): ZaiRequestBody {
validateArgs(model, args);
return {
model,
prompt,
quality: getZaiQuality(args.quality),
size: resolveSizeForModel(model, args),
};
}
export async function extractImageFromResponse(result: ZaiResponse): Promise<Uint8Array> {
const url = result.data?.[0]?.url;
if (!url) {
throw new Error("No image URL in Z.AI response");
}
const imageResponse = await fetch(url);
if (!imageResponse.ok) {
throw new Error(`Failed to download image from Z.AI: ${imageResponse.status}`);
}
return new Uint8Array(await imageResponse.arrayBuffer());
}
export async function generateImage(
prompt: string,
model: string,
args: CliArgs,
): Promise<Uint8Array> {
const apiKey = getApiKey();
if (!apiKey) {
throw new Error("ZAI_API_KEY is required. Get one from https://docs.z.ai/.");
}
const response = await fetch(buildZaiUrl(), {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify(buildRequestBody(prompt, model, args)),
});
if (!response.ok) {
const err = await response.text();
throw new Error(`Z.AI API error (${response.status}): ${err}`);
}
const result = (await response.json()) as ZaiResponse;
return extractImageFromResponse(result);
}
+2
View File
@@ -3,6 +3,7 @@ export type Provider =
| "openai"
| "openrouter"
| "dashscope"
| "zai"
| "minimax"
| "replicate"
| "jimeng"
@@ -61,6 +62,7 @@ export type ExtendConfig = {
openai: string | null;
openrouter: string | null;
dashscope: string | null;
zai: string | null;
minimax: string | null;
replicate: string | null;
jimeng: string | null;
+6 -3
View File
@@ -1,6 +1,6 @@
---
name: baoyu-infographic
description: Generates professional infographics with 21 layout types and 20 visual styles. Analyzes content, recommends layout×style combinations, and generates publication-ready infographics. Use when user asks to create "infographic", "信息图", "visual summary", "可视化", or "高密度信息大图".
description: Generates professional infographics with 21 layout types and 21 visual styles. Analyzes content, recommends layout×style combinations, and generates publication-ready infographics. Use when user asks to create "infographic", "信息图", "visual summary", "可视化", or "高密度信息大图".
version: 1.56.1
metadata:
openclaw:
@@ -26,7 +26,7 @@ Two dimensions: **layout** (information structure) × **style** (visual aestheti
| Option | Values |
|--------|--------|
| `--layout` | 21 options (see Layout Gallery), default: bento-grid |
| `--style` | 20 options (see Style Gallery), default: craft-handmade |
| `--style` | 21 options (see Style Gallery), default: craft-handmade |
| `--aspect` | Named: landscape (16:9), portrait (9:16), square (1:1). Custom: any W:H ratio (e.g., 3:4, 4:3, 2.35:1) |
| `--lang` | en, zh, ja, etc. |
@@ -82,6 +82,7 @@ Full definitions: `references/layouts/<layout>.md`
| `pop-laboratory` | Blueprint grid, coordinate markers, lab precision |
| `morandi-journal` | Hand-drawn doodle, warm Morandi tones |
| `retro-pop-grid` | 1970s retro pop art, Swiss grid, thick outlines |
| `hand-drawn-edu` | Macaron pastels, hand-drawn wobble, stick figures |
Full definitions: `references/styles/<style>.md`
@@ -104,6 +105,8 @@ Full definitions: `references/styles/<style>.md`
| Product Guide | `dense-modules` + `morandi-journal` |
| Technical Guide | `dense-modules` + `pop-laboratory` |
| Trendy Guide | `dense-modules` + `retro-pop-grid` |
| Educational Diagram | `hub-spoke` + `hand-drawn-edu` |
| Process Tutorial | `linear-progression` + `hand-drawn-edu` |
Default: `bento-grid` + `craft-handmade`
@@ -259,7 +262,7 @@ Report: topic, layout, style, aspect, language, output path, files created.
- `references/structured-content-template.md` - Content format
- `references/base-prompt.md` - Prompt template
- `references/layouts/<layout>.md` - 21 layout definitions
- `references/styles/<style>.md` - 20 style definitions
- `references/styles/<style>.md` - 21 style definitions
## Extension Support
@@ -0,0 +1,63 @@
# hand-drawn-edu
Hand-drawn educational infographic with macaron pastel color blocks on warm cream paper texture.
## Color Palette
- Background: Warm cream (#F5F0E8) with subtle paper grain texture
- Primary text: Deep charcoal (#2D2D2D) for headlines, outlines
- Macaron Blue: #A8D8EA for cool-toned information zones
- Macaron Mint: #B5E5CF for growth/positive zones
- Macaron Lavender: #D5C6E0 for abstract/concept zones
- Macaron Peach: #FFD5C2 for warm-toned zones
- Accent: Coral Red (#E8655A) for key data, warnings, emphasis
- Muted annotations: Warm gray (#6B6B6B) for secondary labels
## Visual Elements
- Macaron pastel rounded cards as distinct information zones
- Hand-drawn wavy connection lines and arrows with small text labels
- Simple stick-figure characters and cartoon icons to humanize concepts
- Doodle decorations: small stars, underlines, spirals, sparkles
- Color fills don't completely fill outlines — preserve casual hand-drawn feel
- Dashed borders for secondary or contained zones
- Small icon doodles (clipboard, lock, checkmark, lightbulb) to reinforce concepts
- Bold centered quote or takeaway at the bottom
- Slight hand-drawn wobble on all lines and shapes
## Variants
| Variant | Focus | Visual Emphasis |
|---------|-------|-----------------|
| **Sketch-notes** | Concept mapping | More stick figures, thought bubbles, connecting arrows |
| **Pastel cards** | Structured info | Cleaner macaron blocks, less doodle, more white space |
## Typography
- Main title: Bold hand-drawn lettering with organic strokes, large confident letterforms with slight wobble
- Section headers: Hand-lettered text on or inside macaron color blocks
- Body text: Clear handwritten print style, legible but not mechanical
- Annotations: Warm gray (#6B6B6B), smaller, neat handwritten labels
- Keywords: Bold emphasis within body text
## Style Enforcement
- All lines must have slight hand-drawn wobble — no perfect geometry
- Each information zone uses a distinct macaron color block
- Maintain consistent wobble quality across all shapes and lines
- Include at least one simple cartoon character or stick figure
- Generous white space between zones — each zone should breathe
- Maximum 4 macaron colors per infographic
## Avoid
- Perfect geometric shapes or straight lines
- Photorealistic elements or stock illustration style
- Pure white backgrounds
- Flat vector icons or digital-precision graphics
- Overcrowded layouts — let zones breathe
- Corporate or clinical aesthetic
## Best For
Educational diagrams, process explainers, concept maps, knowledge summaries, tutorial walkthroughs, onboarding visuals
+5 -1
View File
@@ -71,6 +71,7 @@ Transform content into professional slide deck images.
| `corporate` | clean + professional + geometric + balanced | Investor decks, proposals |
| `minimal` | clean + neutral + geometric + minimal | Executive briefings |
| `sketch-notes` | organic + warm + handwritten + balanced | Educational, tutorials |
| `hand-drawn-edu` | organic + macaron + handwritten + balanced | Educational diagrams, process explainers |
| `watercolor` | organic + warm + humanist + minimal | Lifestyle, wellness |
| `dark-atmospheric` | clean + dark + editorial + balanced | Entertainment, gaming |
| `notion` | clean + neutral + geometric + dense | Product demos, SaaS |
@@ -88,7 +89,7 @@ Transform content into professional slide deck images.
| Dimension | Options | Description |
|-----------|---------|-------------|
| **Texture** | clean, grid, organic, pixel, paper | Visual texture and background treatment |
| **Mood** | professional, warm, cool, vibrant, dark, neutral | Color temperature and palette style |
| **Mood** | professional, warm, cool, vibrant, dark, neutral, macaron | Color temperature and palette style |
| **Typography** | geometric, humanist, handwritten, editorial, technical | Headline and body text styling |
| **Density** | minimal, balanced, dense | Information density per slide |
@@ -99,6 +100,7 @@ Full specs: `references/dimensions/*.md`
| Content Signals | Preset |
|-----------------|--------|
| tutorial, learn, education, guide, beginner | `sketch-notes` |
| hand-drawn, infographic, diagram, process, onboarding | `hand-drawn-edu` |
| classroom, teaching, school, chalkboard | `chalkboard` |
| architecture, system, data, analysis, technical | `blueprint` |
| creative, children, kids, cute | `vector-illustration` |
@@ -393,6 +395,8 @@ options:
description: "Blues, grays, analytical"
- label: "vibrant"
description: "High saturation, bold"
- label: "macaron"
description: "Pastel blocks (blue, mint, lavender, peach) on cream"
```
(Note: "dark", "neutral" available via Other)
@@ -8,6 +8,7 @@ Color temperature and palette style.
|--------|-------------------|---------------|----------|
| `professional` | Cool-neutral | Navy, gold, structured grays | Business, investor, corporate |
| `warm` | Warm | Earth tones, oranges, natural colors | Education, friendly, approachable |
| `macaron` | Warm | Pastel blocks (blue, mint, lavender, peach) on cream | Educational diagrams, knowledge sharing |
| `cool` | Cool | Blues, grays, cyan, teal | Technical, data, analytical |
| `vibrant` | Varied | High saturation, bold colors | Marketing, creative, attention-grabbing |
| `dark` | Dark | Deep backgrounds with bright accents | Entertainment, gaming, atmospheric |
@@ -36,6 +37,19 @@ Accent 2: #E9C46A (Mustard Yellow)
Accent 3: #87A96B (Sage Green)
```
### macaron
```
Background: #F5F0E8 (Warm Cream)
Primary Text: #2D2D2D (Deep Charcoal)
Muted Text: #6B6B6B (Warm Gray)
Macaron Blue: #A8D8EA (Sky Blue)
Macaron Mint: #B5E5CF (Mint Green)
Macaron Lavender: #D5C6E0 (Lavender)
Macaron Peach: #FFD5C2 (Peach)
Accent: #E8655A (Coral Red)
```
### cool
```
@@ -95,6 +109,13 @@ Accent 2: #A1A1AA (Light Gray)
- Soft transitions between colors
- Welcoming atmosphere
### macaron
- Soft pastel color blocks as distinct information zones
- Each zone uses one macaron color (blue, mint, lavender, peach)
- Coral Red accent used sparingly for emphasis
- Warm cream background maintains friendly, approachable feel
### cool
- Blue-dominant palette
@@ -129,6 +150,7 @@ Accent 2: #A1A1AA (Light Gray)
|------|-----------------|------------|
| professional | clean texture, geometric typography | organic texture, handwritten |
| warm | organic texture, humanist typography | pixel texture, minimal density |
| macaron | organic texture, handwritten typography | pixel texture, dark mood |
| cool | grid texture, technical typography | paper texture, handwritten |
| vibrant | pixel/organic texture, editorial typography | neutral mood overlaps |
| dark | clean/pixel texture, technical typography | paper texture |
@@ -11,6 +11,7 @@ Maps 16 preset styles to their dimension combinations.
| corporate | clean | professional | geometric | balanced |
| minimal | clean | neutral | geometric | minimal |
| sketch-notes | organic | warm | handwritten | balanced |
| hand-drawn-edu | organic | macaron | handwritten | balanced |
| watercolor | organic | warm | humanist | minimal |
| dark-atmospheric | clean | dark | editorial | balanced |
| notion | clean | neutral | geometric | dense |
@@ -50,6 +51,11 @@ Maps 16 preset styles to their dimension combinations.
- **Feel**: Friendly learning, approachable education
- **Auto-select**: tutorial, learn, education, guide, beginner
### hand-drawn-edu
- **Dimensions**: organic + macaron + handwritten + balanced
- **Feel**: Hand-drawn educational infographic, macaron pastel zones
- **Auto-select**: hand-drawn, infographic, diagram, process, onboarding
### watercolor
- **Dimensions**: organic + warm + humanist + minimal
- **Feel**: Artistic, natural, lifestyle
@@ -114,7 +120,7 @@ When user selects "Custom dimensions", combine any:
- **Typography** (5): geometric, humanist, handwritten, editorial, technical
- **Density** (3): minimal, balanced, dense
Total possible combinations: 5 × 6 × 5 × 3 = **450 unique styles**
Total possible combinations: 5 × 7 × 5 × 3 = **525 unique styles**
## Recommended Combinations (Beyond Presets)
@@ -55,6 +55,6 @@ Visual texture and background treatment.
|---------|-----------------|------------|
| clean | professional, neutral moods | handwritten typography |
| grid | cool, professional moods | handwritten, vibrant moods |
| organic | warm, vibrant moods | technical typography |
| organic | warm, macaron, vibrant moods | technical typography |
| pixel | vibrant, dark moods | editorial typography |
| paper | warm moods | geometric typography, minimal density |
@@ -0,0 +1,69 @@
# hand-drawn-edu
Hand-drawn educational infographic with macaron pastel color blocks on warm cream paper
## Design Aesthetic
Hand-drawn educational infographic feel with slight wobble on all lines and shapes, like a high-quality presentation visual summary. Warm cream paper background with macaron pastel color blocks creating distinct information zones. Simple cartoon characters and doodle decorations bring concepts to life while maintaining clean composition and generous white space.
## Background
- Color: Warm Cream (#F5F0E8)
- Texture: Subtle warm paper grain, hand-drawn feel with slight organic imperfection
## Typography
### Primary Font (Headlines)
Bold hand-drawn lettering with organic strokes. Large, confident letterforms with slight wobble. Thick marker-style strokes. Render as hand-drawn letters, not typed text.
### Secondary Font (Body)
Clear handwritten style for body text and labels. Warm gray (#6B6B6B) for annotations and small labels. Bold keywords within body text for emphasis. Legible but not mechanical.
## Color Palette
| Role | Color | Hex | Usage |
|------|-------|-----|-------|
| Background | Warm Cream | #F5F0E8 | Primary background |
| Primary Text | Deep Charcoal | #2D2D2D | Headlines, main text, outlines |
| Macaron Blue | Sky Blue | #A8D8EA | Info block fill, cool-toned zones |
| Macaron Mint | Mint Green | #B5E5CF | Info block fill, growth/positive zones |
| Macaron Lavender | Lavender | #D5C6E0 | Info block fill, abstract/concept zones |
| Macaron Peach | Peach | #FFD5C2 | Info block fill, warm-toned zones |
| Accent | Coral Red | #E8655A | Key data, warnings, emphasis |
| Muted Text | Warm Gray | #6B6B6B | Secondary annotations, small labels |
## Visual Elements
- Macaron pastel rounded cards as distinct information zones
- Hand-drawn wavy connection lines and arrows between zones
- Simple stick-figure characters and cartoon icons
- Doodle decorations: small stars, underlines, spirals
- Color fills don't completely fill outlines — preserve hand-drawn casual feel
- Dashed borders for secondary or contained zones
- Small icon doodles (clipboard, lock, checkmark) to reinforce concepts
## Style Rules
### Do
- Use distinct macaron color blocks for each information zone
- Keep hand-drawn wobble consistent across all lines and shapes
- Include simple cartoon characters to humanize concepts
- Add small label annotations on connecting arrows
- Include a bold centered quote or takeaway at the bottom
- Maintain generous white space between zones
### Don't
- Use perfect geometric shapes or straight lines
- Create photorealistic elements
- Mix more than 4 macaron colors per slide
- Use pure white backgrounds
- Add slide numbers, footers, or logos
- Overcrowd — each zone should breathe
## Best For
Educational diagrams, process explainers, concept maps, onboarding visuals, knowledge summaries, tutorial walkthroughs

Some files were not shown because too many files have changed in this diff Show More