Install
openclaw skills install @archsueh/archviz-skillsRestrained information visualization skill pack for AI agents. Every visualization starts with a brief read and three dials. Supports Mermaid, ASCII/termaid terminal rendering, self-contained HTML, Python (Plotly), Obsidian Canvas, draw.io guidance, and Three.js 3D archviz. Text-first, preview-compatible, anti-slop. Default mode is 2D infoviz; enter 3D only when the brief mentions building, floorplan, structure, or spatial walkthrough. Use when the user asks for diagram, visualization, chart, gantt, sankey, mindmap, flowchart, xychart, 可视化, 架构图, 流程图, 信息图, 甘特图, funnel, state diagram, decision matrix, 封面, 卡片, 信息卡, 分享图, 排版, or 3D building/archviz.
openclaw skills install @archsueh/archviz-skillsEvery rule is contextual. Read the brief first, then pull only what fits.
Good: "用 archviz 给这份产品全案 §2 画 V1 闭环图" · "Gantt + 任务表 + ASCII fallback" · "内嵌 Warm Paper SVG 到 Obsidian 笔记"
Bad: "帮我生成小红书 PNG 并截图上传" → use claude-design-card (Bun + Playwright). archviz supplies the language + HTML skeleton, not the screenshot CLI.
design-taste-frontend, frontend-design, or huashu-design.claude-design-card.mermaid-arc-skills (lighter, Mermaid-focused).imagegen / fal MCP.| Need | Use |
|---|---|
| Diagram in .md + fallbacks | archviz-skills |
| Editable professional diagram | archviz-skills draw.io mode (references/drawio-output-mode.md) |
| Publishable PNG card (14 formats) | claude-design-card |
| Swiss/guizang Mermaid styling only | mermaid-arc-skills |
| DESIGN.md for a product brand | anydesign + host DESIGN.md |
| Gate | Pass criteria | On fail |
|---|---|---|
| G0 Brief | One-line "Reading this as…" + dials set | STOP — infer from host doc |
| G1 Type | QR table match; ≤2 types per deliverable | STOP — split diagram |
| G2 Tokens | Palette locked; contrast computed; max 1 accent | STOP — fix init/CSS |
| G3 Editorial ask | If card/cover ambiguous: 1 primary + 2 alt OR user said "your call" | STOP — do not guess platform |
| G4 Generate | Template read if path exists | Fallback: flowchart TD + subgraph |
| G5 Validate | references/validation-checklist.md pre+post | STOP — ASCII fallback + document ⚠️ |
| G6 Embed | Caption = finding first | Revise caption before ship |
Iron rule: No ship without G2 contrast check. No Family A cover with >3 text layers.
Dials: COMPLEXITY=4 DENSITY=3 RESTRAINT=8
Palette: surface=#f5f0eb text=#1B365D border=#a8a29e accent=#002FA7 (max 1)
Init: %%{init: {'theme':'base','themeVariables':{'primaryColor':'#f5f0eb','primaryTextColor':'#1B365D','primaryBorderColor':'#a8a29e','lineColor':'#a8a29e','tertiaryColor':'#d6d3d1','fontSize':'13px'}}}%%
Contrast: luminance(0.299R+0.587G+0.114B) < 128 → light text, ≥ 128 → dark text
Labels: ≤6 words / ≤8 Chinese chars / no ALL CAPS
Gantt: codes only inside block + table beside / min 3w / termaid for terminal
Anti-slop: no purple default / no rainbow / no flowchart-for-everything / no pie
Editorial: Parchment=#f5f4ed ink=#141413 terracotta=#c96442 (max 1) serif 500 not 700
Type selection (fast):
| Data | Type | Template |
|---|---|---|
| Hierarchical | mindmap | — |
| Sequential | flowchart LR/TD | — |
| System/layered | flowchart TD + subgraph | — |
| Comparison/ranking | xychart-beta (bar) | — |
| Proportional | treemap or stacked bar | — |
| Timeline | gantt | mermaid/gantt.mmd |
| Distribution | histogram/box | mermaid/distribution.mmd |
| Correlation | scatter/heatmap | python/scatter-plot.py |
| Flow/network | sankey | mermaid/sankey.mmd |
| Funnel/conversion | funnel chart | html/funnel.html |
| Decision/evaluation | decision matrix (table) | mermaid/decision-matrix.mmd |
| State transitions | stateDiagram-v2 | mermaid/state-machine.mmd |
| Dependencies | dependency graph | mermaid/dependency-network.mmd |
| Editable architecture handoff | draw.io XML plan | references/drawio-output-mode.md |
| Multi-criteria scoring | radar or diverging bar | html/radar.html / mermaid/diverging-bar.mmd |
| Simple (≤5 items) | TABLE, not chart | — |
| 3D: Building structure | Three.js structure shell | html/threejs-archviz.html |
| 3D: Floor plan | Three.js extruded floor | html/threejs-floorplan.html |
| 3D: Section cut | Three.js ClippingPlane | html/threejs-archviz.html |
| Cover / hero (click promise) | Editorial Family A HTML | html/editorial-card.html |
| Knowledge card (saveable) | Editorial Family B HTML | html/editorial-card.html |
| Social square (quote/data) | Editorial Family C HTML | html/editorial-card.html |
| Long-form article layout | Editorial Family D HTML | html/editorial-card.html |
Mixed types (when data spans categories):
Degradation strategy (when data is too complex):
50 nodes → split into 2-3 linked diagrams with shared legend
7 categories → aggregate into "Other" + detail diagram
Environment routing:
| Env | Output |
|---|---|
| Obsidian/preview | lightweight Mermaid / self-contained HTML |
| Terminal | termaid-first (termaid diagram.mmd --theme mono --width N) then ASCII fallback |
| Deliverables | Python (Plotly/Matplotlib) |
| Editable handoff | draw.io .drawio source + optional PNG/SVG/PDF export |
| 3D / archviz | Three.js self-contained HTML (CDN import) |
Specialized references:
references/termaid-routing.mdreferences/drawio-output-mode.mdreferences/scene-contract.md3D archviz mode (when brief = building/structure/spatial):
structure=#a8a29e, floor=#e8e4e0, accent-3d=#002FA7CDN importmap pattern (self-contained HTML, zero build):
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/",
"animejs": "https://cdn.jsdelivr.net/npm/animejs@4.4.1/dist/bundles/anime.esm.js"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { animate } from 'animejs'; // v4: named export, NOT default
</script>
Tech stack pitfalls (硬规则,已踩坑验证):
| Pitfall | Symptom | Fix |
|---|---|---|
| animejs CDN 404 | Canvas blank, no errors | v4.4.1 路径是 dist/bundles/anime.esm.js,不是 lib/anime.es.js |
| animejs default import | import anime from 'animejs' → undefined | v4 是 named export: import { animate } from 'animejs' |
| animejs v3→v4 API | anime({targets: x, ...}) 报错 | v4 是 animate(target, params),无 targets key |
animate 命名冲突 | 渲染循环函数也叫 animate → 覆盖 import | 渲染循环用 renderLoop 或 tick,不要用 animate |
| Three.js CatmullRom | CatmullRomCurvePath 不存在 | 用 CatmullRomCurve3(3D 曲线) |
Full rules → DESIGN.md. Templates → templates/.
Before generating, read these signals:
Output one line: "Reading this as: <type> for <audience>, <vibe>, <palette>."
Palette routing: academic/diagram default → Warm Paper + IKB · editorial/card/cover → Editorial Parchment + Terracotta · host doc with existing tokens → match host (Aver cinnabar, etc.).
4-layer analysis (from anydesign): Identity → System → Components → Layout. Mark confidence: ✅/⚠️/❓.
DESIGN.md contract (from awesome-design-md): Atmosphere → Tokens → Components → Layout → Guardrails. If any layer is unknown, state the assumption before generating.
Anti-default: No purple gradients, no rainbow nodes, no centered symmetry, no flowchart-for-everything, no default theme.
| Dial | Default | Range |
|---|---|---|
| COMPLEXITY | 4 | 1(minimal)–10(dense) |
| DENSITY | 3 | 1(airy)–10(packed) |
| RESTRAINT | 8 | 1(expressive)–10(austere) |
Inference: "academic" → 3-5/2-3/9-10 · "playful" → 5-8/3-5/3-5 · "data report" → 6-8/6-8/5-7
Defined in DESIGN.md. Summary:
| Token | Warm Paper | Swiss | IKB |
|---|---|---|---|
| surface | #f5f0eb | #f5f5f4 | #e4e8f0 |
| text | #1B365D | #1B365D | #0a0a0a |
| border | #a8a29e | #d6d3d1 | #94a3b8 |
| accent | — | — | #002FA7 |
| Editorial Parchment | #f5f4ed | #141413 | #e8e6dc |
Rules: Max 1 accent. No AI-purple. Same doc = same palette. Contrast check mandatory. Light surface uses dark text. Editorial mode: serif display 500 max, no #ffffff canvas, no cool #64748b grays. Full rules → references/editorial-parchment-language.md.
越大越细,越小越粗:Large=200(ExtraLight) · Body=300(Light) · Small=500-600(SemiBold)
Labels: ≤6 words · ≤8 Chinese chars · no ALL CAPS · same language per diagram
| Data | Format |
|---|---|
| 2-3 items | Table |
| 4-8 items | Bar chart |
| Proportional | Treemap/stacked |
| Sequential | Flowchart |
| Hierarchical | Mindmap |
| Timeline | Gantt |
Simple comparison (≤5 items) → TABLE, not chart.
Do: Cite hex/px · Infer semantic roles · Mark confidence (✅/⚠️/❓) · Match document style
Don't: Generic descriptions · Colors without hex · Invent tokens · Ignore context
---
diagram: [name]
type: [mindmap|flowchart|xychart-beta|gantt|...]
context: [paper|log|PPT|note]
dials: {complexity: N, density: N, restraint: N}
tokens: {surface: "#f5f0eb", text: "#1B365D", border: "#a8a29e", accent: "#002FA7"}
confidence: {palette: "✅", layout: "✅", nodes: "⚠️"}
---
Pre-gen checklist: Brief done? DESIGN.md contract complete? Dials set? Tokens locked? Labels short? Gantt: codes+table? Card/cover: compressed to judgment+promise+one evidence?
After generating a diagram, run a validation loop:
Generate → Render → Check → Fix → Re-render (max 2 rounds)
Step 1: Render
termaid diagram.mmd --theme mono (terminal) or paste into ObsidianStep 2: Check (read the rendered output)
Step 3: Fix (if issues found)
Step 4: Re-render and verify fix
Stop when: 0 issues found, or 2 rounds exhausted (report remaining issues to user).
Terminal validation (termaid):
# Render and visually inspect
termaid diagram.mmd --theme mono
# If output looks wrong, edit .mmd and re-run
Trigger: 封面、卡片、信息卡、小红书、公众号、分享图、排版、knowledge card, or publishable HTML.
Load: references/editorial-parchment-language.md + templates/html/editorial-card.html.
Gate G3: platform/read-vs-share unclear → 1 primary + 2 alternatives + ≤3 questions. User says「按你判断」→ Family B default.
Families: A cover · B knowledge 1080×1440 · C square · D long-form width-led. Full sizes/safe-zones → reference file.
Primary: termaid (pip install termaid)
# 直接渲染 Mermaid 文件到终端
termaid diagram.mmd --theme mono
termaid diagram.mmd --theme terra
echo 'graph LR; A-->B-->C' | termaid --theme mono
6种主题: default, terra, neon, mono, amber, phosphor
支持18种图: flowchart, sequence, class, ER, state, block, git, gantt, architecture, pie, treemap, mindmap, timeline, kanban, quadrant, xychart, user journey, packet
Python API:
from termaid import render
print(render("graph LR\n A --> B --> C"))
Fallback: 纯文本ASCII(termaid不可用时)
Plain text only. Max 80 columns. No box-drawing characters.
| 元素 | 符号 |
|---|---|
| 节点 | [文本] 或 (文本) |
| 重要节点 | [[文本]] 或 ((文本)) |
| 决策 | {文本} |
| 箭头 | --> ==> |
Save and reuse visual styles across diagrams.
Preset format (YAML):
# .archviz-preset.yaml
name: warm-paper-restrained
tokens:
surface: "#f5f0eb"
text: "#1B365D"
border: "#a8a29e"
accent: "#002FA7"
mermaid_init: "%%{init: {'theme':'base','themeVariables':{'primaryColor':'#f5f0eb','primaryTextColor':'#1B365D','primaryBorderColor':'#a8a29e','lineColor':'#a8a29e','tertiaryColor':'#d6d3d1','fontSize':'13px'}}}%%"
dials: {complexity: 4, density: 3, restraint: 8}
Extract from existing diagram:
%%{init:...}%% block from a .mmd filethemeVariables into token names.archviz-preset.yamlApply preset:
.archviz-preset.yaml from project root (if exists)Built-in presets: warm-paper (default), swiss-neutral, ikb-accent, lemon-accent, stone-mono, editorial-parchment, warm-paper-dark, ikb-dark
Actual files live in templates/. Current inventory (do not hardcode counts in prompts):
templates/
├── mermaid/ 15 files (gantt, sankey, distribution, diverging-bar, network, scoring, intro, architecture, closed-loop variants, funnel, decision-matrix, state-machine, dependency-network)
│ flowchart + mindmap: inline Mermaid (no standalone .mmd)
├── ascii/ 4 files (flowchart, architecture, gantt, icon-system)
├── html/ 15 files (+ editorial-card; bubble, bullet-graph, funnel, gauge, heatmap, line, radar, sunburst, treemap, waffle, waterfall, threejs-archviz, threejs-floorplan)
└── python/ 5 files (scatter-plot, box-plot, candlestick, parallel-coordinates, viz template)
templates/<mode>/ at use time instead of relying on this list.
Flowchart and mindmap have no template files — generate inline using tokens from DESIGN.md.| Issue | Fix |
|---|---|
| Editorial wrong palette | Host doc wins; else Editorial Parchment #f5f4ed + Terracotta #c96442 — never mix with IKB |
| Cover too dense | Family A: drop to judgment + promise + one evidence; move rest to Family B |
| Card needs PNG export | Out of scope — hand off HTML to claude-design-card screenshot.ts or browser export |
| Mindmap fails | Use flowchart/subgraph |
| Architecture-beta lexer error | Use flowchart TD + subgraph (preview-compatible) |
| Gantt text overflow | Codes only + table + ASCII fallback |
| Theme too flashy | Force solarized-light/nord-light |
| Text unreadable | Check contrast rule (QR) |
| Too many nodes | Split into subgraphs |
| Canvas blank (Three.js) | Check console for CDN 404 / import errors |
| animejs not animating | v4 API: animate(target, props) not anime({targets}) |
| Render loop stops | Don't name loop function animate (conflicts with animejs import) |
| Anti-pattern | Symptom | Fix |
|---|---|---|
| Pie for everything | Pie chart with >5 slices or similar values | ≤3 slices → table; >3 → treemap or stacked bar |
| Rainbow nodes | Every node a different color | Same hue, vary lightness. Max 1 accent |
| Flowchart-for-everything | Non-sequential data forced into flowchart | Match data relationship to type table (§QR) |
| Label soup | Labels >10 words, full sentences | ≤6 words / ≤8 Chinese chars. Detail in caption |
| 3D decoration | 3D bar/pie for "visual interest" | Flat only. Depth = data dimension, never decoration |
| Dual Y-axis lie | Two unrelated metrics on shared axis | Split into 2 charts or use indexed/baseline ratio |
| Truncated axis | Bar chart Y-axis starts at non-zero | Always start at 0. Use inset zoom if range matters |
| Legend overload | >7 legend items, hard to match | Aggregate "Other". Use direct labeling |
| Default theme | Mermaid/Chart.js default purple/blue gradient | Always apply custom init + tokens from DESIGN.md |
| Missing caption | Diagram embedded without context | Caption = finding, not title. "Sales dropped 30% in Q3" not "Q3 Sales Chart" |
| Color as only channel | Red/green distinction for colorblind users | Add pattern/shape/label. Never rely on color alone |
| Spaghetti network | >20 edges in network/graph | Cluster nodes, hide weak edges, or split into subgraphs |
| Mixed metaphor | Flowchart arrows + pie segments + bar heights in one view | One visual language per diagram. Split if needed |
| Infinite Gantt | Gantt with 30+ tasks, unreadable | Group into phases. Detail in separate Gantt or table |
| Emoji overload | 🎯📊🔥 in every node | Max 1 icon per group. No emoji in formal deliverables |
| Cover as summary slide | 4–6 bullets on a platform cover | Family A: judgment + promise + one evidence only |
| Editorial serif 700 | Headlines feel bombastic / off-brand | Georgia/Newsreader at 500; enlarge size instead |
| Cool SaaS white | #ffffff + #64748b on cards | Parchment #f5f4ed + Near-Black #141413 |
| Equal card grid | Every module same weight | One hero + hierarchy via type scale |
| 绝不 | Why |
|---|---|
| Ship Mermaid default theme | Reads as AI slop; always custom init |
| Two accents in one set (IKB + Terracotta + cinnabar) | Breaks restraint dial |
font-weight: 700 on editorial serif | Off-brand; enlarge type instead |
#ffffff canvas or #64748b UI gray | Violates warm editorial contract |
| Box-drawing in ASCII | Garbles in chat/non-mono viewers |
| Pie chart >3 slices | Use table or treemap |
| Skip ASCII fallback when target env unknown | Text-first survivability |
| Embed diagram without finding-caption | Violates G6 |
| Duplicate claude-design-card Playwright pipeline inside archviz | Toolkit bloat — boundary in §When NOT |
references/editorial-parchment-language.md)Full design system → DESIGN.md · Editorial cards → references/editorial-parchment-language.md · Research → research/
This skill uses darwin-skill for self-scoring and optimization, and skills-curation for audit.
Darwin Evaluation of 0.1.6 (simulated run):
Recommendations applied for 0.1.7:
Error Handling Table (new for 0.1.7):
| Failure | Symptom | Fix / Gate |
|---|---|---|
| Render fail (Mermaid syntax) | Blank or error in viewer | Fallback to flowchart + subgraph; re-validate with G5 |
| Token overflow in large diagram | Agent context exceeded | Split per degradation strategy; use scene-contract |
| Contrast fail | Unreadable text | Enforce G2 luminance check before ship |
| 3D CDN 404 | Canvas blank | Use verified v4 paths; test with preview.html |
| CJK font mismatch | Garbled labels | Use Noto SC in tokens; termaid for terminal |
| No caption | Diagram without context | Enforce G6 before embed |
Self-Evolution Loop (darwin on self):
Integration Notes:
agy -p "use darwin and curation on /Users/mac/Developer/archviz-skills for 0.1.7; context: hsueh design teaching, absolute paths, restrained viz"Three.js + animejs v4 实战中遇到的坑,按出现顺序记录。
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/",
"animejs": "https://cdn.jsdelivr.net/npm/animejs@4.4.1/dist/bundles/anime.esm.js"
}
}
</script>
⚠️ animejs v4 路径不是 lib/anime.es.js — 那是 v3 的路径。v4.4.1 的正确路径是 dist/bundles/anime.esm.js。验证方法:curl -sI <CDN_URL> 返回 200 才可用。
| v3(旧) | v4.4.1(当前) |
|---|---|
import anime from 'animejs' | import { animate } from 'animejs' |
anime({targets: obj, x: 1, duration: 500}) | animate(obj, {x: 1, duration: 500}) |
包装函数(统一写法,避免每次改 API):
import { animate } from 'animejs';
function tween(target, props) { return animate(target, props); }
// 用法:tween(camera.position, {x: 6, y: 4, z: 8, duration: 800})
// ❌ 错误 — animate 与 animejs 导入冲突
function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); }
animate();
// ✅ 正确 — 用 renderLoop 或其他名称
function renderLoop() { requestAnimationFrame(renderLoop); renderer.render(scene, camera); }
renderLoop();
// ❌ 物体 y=0 会埋进地面
scene.add(dryer); // dryer.position.y 默认 0
// ✅ 物体抬高到地面之上
scene.add(dryer);
dryer.position.y = 2; // 或者降低地面:gMesh.position.y = -0.5
// ❌ 跳跃式,无过渡
camera.position.set(6, 4, 8);
// ✅ 用 tween 平滑过渡
tween(camera.position, {x: 6, y: 4, z: 8, duration: 800, easing: 'easeInOutCubic'});
模板约束 max 3 光源(1 HemisphereLight + 1 DirectionalLight + 1 AmbientLight)。超出会影响性能且难以控制阴影。