技术栈示意图 (stack-diagram) 是做什么的?
生成工程绘图风格的架构图:白色方块上的真实 Logo、带标签的分组框(类似云厂商的 VPC 图)、带等宽字体标签的正交箭头,配合酷炫的方格纸背景。一个自包含的 HTML 文件是源头;PNG / TSX / 即时制品都由此派生。
要求
- Python 3.9+(
fetch_icons.py、build.py和share.py仅使用标准库) - 获取图标时需要网络访问图标源(svgl.app、raw.githubusercontent.com、cdn.jsdelivr.net、AWS 图标需访问 aws.amazon.com 和 d1.awsstatic.com、Google Cloud 图标需访问 services.google.com、Azure 图标需访问 learn.microsoft.com 和 arch-center.azureedge.net,以及使用
name=URL时访问品牌自家网站或仓库) - 用于
render_png.py的 Playwright + Chromium:pip install playwright && python3 -m playwright install --with-deps chromium
工作流程
- 确定内容(节点、分组、边)
- 获取图标 —
scripts/fetch_icons.py - 规划坐标 — 阅读
references/geometry.md - 根据
assets/template.html构建 HTML —scripts/build.py - 交付前渲染 PNG 并查看它
- 按请求的格式交付
- 可选:分享到公共画廊
第1步 — 内容
根据用户提供的技术/服务列表,决定:
- 节点:每个技术 = 一个节点(名称加上简短的小写角色描述,如
http server、sqlite db) - 分组:将共享运行时、供应商或仓库的事物用框起来(例如,一个云供应商框内包含一个运行时框;一个用于工具集的 monorepo 框)。允许一层嵌套;更深则会显得杂乱。分组标签使用品牌自身的写法(
GitHub、npm);模板会按原样显示。 - 边,分为三种:
- 强调色实线 = 主要请求/数据流(一条连续路径效果最佳)
- 中性色实线 = 次要内部连接
- 中性色虚线 = 开发/部署时关系(CI、git hooks、IaC 部署)
如果用户只给出了一个扁平的工具列表,根据这些工具的功能推断出合理的分组和流程——仅在某个工具的意义模棱两可,以至于无论哪种画法都会错误时才进行询问。
第2步 — 图标
python3 scripts/fetch_icons.py <icons-dir> tanstack hono drizzle "betterauth:better-auth" "orpc=https://orpc.unnoq.com/logo.webp"
python3 scripts/fetch_icons.py <icons-dir> "aws:aws/AWS-Cloud-logo" "vpc:aws/vpc" "fargate:aws/fargate" "s3:aws/s3"
python3 scripts/fetch_icons.py <icons-dir> "gcp:google-cloud" "run:gcp/cloud-run" "lb:gcp/load-balancing" "sql:gcp/cloud-sql"
python3 scripts/fetch_icons.py <icons-dir> "azure:azure/Azure-A" "app:azure/app-service" "vnet:azure/vnet" "sql:azure/sql-database"
python3 scripts/fetch_icons.py <icons-dir> "k8s:kubernetes" "ing:k8s/ingress" "svc:k8s/service" "deploy:k8s/deployment" "pod:k8s/pod"
规格形式:name(名称用作 slug)、name:slug(不同的 slug)、name=URL(明确的 URL)、name:aws/<Name>(官方 AWS 图标)、name:gcp/<Product>(官方 Google Cloud 图标)、name:azure/<Name>(官方 Azure 图标)、name:k8s/<Resource>(官方 Kubernetes 图标)。脚本依次尝试:svgl → devicon → gilbarbara/logos,写入文件加上 manifest.json,并标记填充色为白色的图标。svgl (svgl.app) 是首选,因为它包含现代开发品牌(TanStack、Better Auth、Hono...)的当前官方标志。当 Logo 有浅色/深色版本时,浅色版本保存为 <name>(两种主题下瓦片都是白色的),深色版本保存为 <name>_dark 用于分组标签。svgl 仅按精确标题匹配,因此未命中会直接跳过。它的 API 也暴露了 wordmark 变体——偶尔用于宽分组标签,绝不用于瓦片。
比机制更重要的规则:
- 绝对不要重新着色 Logo。 用户会注意到。如果 Logo 是白色的或对于白色瓦片太亮,将其放在深色瓦片上(
tile dark类),而不是修改其填充色。清单中的white_fill标志是一个启发式的——白色填充可能是彩色标志上的内部细节(tRPC、Ubuntu),所以在使用深色瓦片前瞄一眼 SVG。 - 仅使用官方标志。 simple-icons 被故意排除在来源之外:它的图形是单色重新绘制,用户一眼就能看出问题。当所有来源都未命中时(
FAIL),找到官方文件并以name=URL形式传递——在项目的仓库(根目录logo*.svg、docs/、assets/、public/)和其网站上(/logo.svg、/favicon.svg、/images/logo.svg)查找。一些标志仅存在于仓库中(Lefthook 的是evilmartians/lefthook根目录下的logo_sign.svg)。 - 抽象概念使用象形图,而不是文字。 像“开发环境”、“定时任务”、“队列”、“缓存”或“webhook 接收器”这样的节点没有品牌——使用
name:lucide/<icon>选择一个 Lucide 线条图标(例如devenv:lucide/terminal、cron:lucide/clock;浏览 lucide.dev/icons)。不要在瓦片中使用文字,也不要使用 emoji。 - 供应商子产品(Cloudflare D1/R2/KV...)通常没有独立的 Logo:只需在瓦片上复用供应商 Logo,让节点名称携带区分信息(“Cloudflare D1” / “sqlite db”)。
- AWS 使用 AWS 自己的图标。 每个服务都有一个:使用
name:aws/<Name>获取,运行时从 AWS 官方图标包读取(例如lambda:aws/lambda、aws:aws/AWS-Cloud-logo、s3:aws/s3)。AWS-/Amazon-前缀是可选的,常用缩写词有效(s3、sqs、sns、ses、ecs、eks、ecr、elb、alb、nlb、iam、kms、msk、vpc),未命中时会打印出所有名称。slugaws、amazonwebservices和aws-*指向同一个包,包中没有的会输出FAIL而不是回退到第三方副本。务必为服务编写aws/前缀:裸的dynamodb仍然会通过第三方链。将包和松散图标文件排除在仓库之外:AWS 允许在图表中使用图标,但重新分发未得到确认。 - AWS 区域遵循 AWS 自己的绘图规则。 服务图标自带正方形,并且可以在浅色和深色背景上工作,所以使用
tile bare:白色瓦片只会增加边框。区域内的人员和通用节点使用 AWS 的通用图标(user:aws/General-User;还有General-Users、General-Client、General-Internet、General-Server),使用tile bare res和模板的lt/dk对。分组使用模板的group aws表示 AWS Cloud(标签中包含aws:aws/AWS-Cloud-logo),再加上region、az、vpc、private或public表示其他:直角、仅边框、标签用墨水色、无供应商色调,角落处是一个 30px 的图标(而不是 14px 的)。在 VPC 内部,当你了解或可以安全推断出公有和私有子网的分隔时,展示它们(面向互联网的负载均衡器在公有子网;应用服务器和数据库在私有子网):一个扁平的 VPC 是 AWS 人员首先会注意到的问题。内部的边使用一种颜色和一个开放箭头:<path class="aws" ... marker-end="url(#open)"/>,开发/部署使用aws dash,标签使用普通的.el,并且不为它们添加图例。节点命名为Amazon S3/AWS Fargate,而不是裸的S3/Fargate;像ALB这样的简称放在角色行,全名(Elastic Load Balancing)下面。名称可能占用两行,但Amazon/AWS必须保留在第一个单词的行上:如果它会在前缀后换行,则加宽该节点(left:<centerX-76>px; width:152px)。 - Google Cloud 使用 Google 自己的图标。 使用
name:gcp/<Product>获取,运行时从 Google 官方包读取(例如run:gcp/cloud-run、lb:gcp/load-balancing、memorystore:gcp/memorystore)。只有核心产品有自己的图标(Cloud Run、Cloud SQL、Cloud Storage、BigQuery、GKE、Compute Engine、Vertex AI...)。其他所有产品都使用其类别的图标,正如 Google 指南所规定:Cloud Load Balancing 和 Cloud CDN 都获得 Networking 图标;Memorystore 和 Firestore 都获得 Databases 图标。编写产品名称,脚本会自动选择图标。Cloud/Google前缀是可选的,一些简称有效(vpc、iam、kms、iap、gce、gcs),未命中时会打印出所有名称。gcp/storage是 Storage 类别;Cloud Storage 是gcp/cloud-storage。sluggcp-*和google-cloud-*指向同一个包,包中没有的会输出FAIL而不是回退到第三方副本:那些副本是已废弃的六边形图标,Google 表示不应再使用。务必为产品编写gcp/前缀:裸的bigquery仍然会通过第三方链。gcp:google-cloud是用于分组标签的 Google Cloud 标志。Gemini 和 Firebase 不在包中:使用裸的gemini和firebase。将包和松散图标文件排除在仓库之外:Google 提供图标用于图表和文档,重新分发未得到确认。 - Google Cloud 图保持常规样式,使用 Google 的分组。 Google 自己的图表(纯蓝色面板、水平卡片)被故意不复制:图标放在常规的白色瓦片上,边和图例保持原样。分组使用模板的
group gcp表示 Google Cloud(标签中包含gcp:google-cloud),再加上vpc、region、subnet或zone。VPC 是全局的,子网是区域性的,因此将区域放在 VPC 内部,切勿将 VPC 放在区域内部。全局和无服务器服务(外部负载均衡器、Cloud Storage、Cloud Run)保持在 VPC 外部。由于图标是共享的,务必编写产品的完整名称(Cloud Load Balancing,而不是LB),并加宽名称会换行的节点(left:<centerX-76>px; width:152px)。 - Azure 使用微软自己的图标。 每个服务都有一个:使用
name:azure/<Name>获取,运行时从微软官方包读取(例如app:azure/app-service、azure:azure/Azure-A、vault:azure/key-vault)。Azure-/Microsoft-前缀和复数s是可选的,常用简称有效(aks、vm、vnet、nsg、waf、blob、cosmos、redis、postgres、functions、front-door、apim、ai-search),未命中时会打印出所有名称。slugazure、microsoft-azure和azure-*指向同一个包,包中没有的会输出FAIL而不是回退到第三方副本。务必为服务编写azure/前缀:裸的cosmos仍然会通过第三方链。Microsoft Entra ID 有单独的图标集:将其官方文件作为name=URL传递。微软仅允许在架构图、培训材料和文档中使用这些图标。切勿裁剪、翻转、旋转或重塑图标,仅将其用于它所代表的微软服务,并将包和松散图标文件排除在仓库之外。 - Azure 图保持常规样式,使用微软的分组颜色。 微软自己的图表被故意不复制:图标放在常规的白色瓦片上,边和图例保持原样。分组使用模板的
group azure表示 Azure(标签中包含azure:azure/Azure-A),再加上rg、region、vnet、subnet或zone,并且vnet或subnet标签带有其图标(vnet:azure/vnet、subnet:azure/subnet)。VNet 属于一个区域,因此它放在区域内部。像 Front Door 这样的全局服务保持在区域外部。App Service 位于 VNet 外部,除非它在 App Service 环境中运行,通过私有端点访问的 PaaS 服务可以放在 VNet 内部,其角色为private endpoint。微软要求在每个图标旁显示服务的完整名称(Azure SQL Database,而不是SQL),因此加宽名称会换行的节点(left:<centerX-76>px; width:152px)。 - Kubernetes 使用官方的社区图标。 使用
name:k8s/<Resource>获取,从官方的 kubernetes/community 图标集读取(例如pod:k8s/pod、deploy:k8s/deployment、svc:k8s/service、ing:k8s/ingress、cm:k8s/configmap、secret:k8s/secret、node:k8s/node、api:k8s/kube-apiserver)。资源和基础设施图标使用未标记的变体,以保持图形在图表比例下清晰简洁,控制平面组件使用标记变体。常见的短名称和复数形式有效(svc/service/services、deploy/deployment/deployments、po/pod/pods、cm/configmap/configmaps、sts/statefulset、ds/daemonset、node/nodes等)。未命中会打印出可用的名称。slugk8s、kubernetes和k8s/k8s通过链提供官方的 Kubernetes 轮式 Logo。 - Kubernetes 图默认保持常规样式。 图标放在常规的白色瓦片上,这使它们与技术栈中的其他技术(如 NGINX、cert-manager、外部数据库或云负载均衡器)保持统一,并在方格纸背景上提供一致的立体感和对比度。对于最小的独立图形,也支持
tile bare。分组使用标准分组(cluster、namespace、node、pod)。在图表页脚中注明引用了 Kubernetes Icons Set。 - 供应商的规则仅涵盖其自身区域。 AWS、Google Cloud、Azure 和 Kubernetes 的规则仅适用于该供应商的分组内部,即使图表中不显示其他内容。其外部的一切,例如旁边的用户或跨越进入其内部的边,都保持常规的瓦片、分组、边和图例。
- 非品牌节点(用户、浏览器、互联网、设备、裸金属服务器):从
assets/generic/复制一个图形到图标目录,以节点名称命名,或使用name:lucide/<icon>——不要使用 emoji。这些不是品牌 Logo,因此可以将其着色为图表的墨水色(获取脚本会自动为 Lucide 图标执行此操作)。 - 分组标签图标渲染为 14px——它们需要一个方形图形标记。文字标记和宽标识在这个尺寸下会变得模糊;如果主图标是一个文字标记,请单独为标签获取品牌的方形图标(svgl 通常有;否则是项目自己的图标或 favicon 文件)。
- 分组标签位于分组的色调上,而不是白色瓦片上,因此在深色主题中,带有黑色部分的标记会消失在那里。如果
fetch_icons.py保存了<name>_dark,在标签中使用模板的lt/dk对;如果没有深色变体并且标记有黑色部分,则在标签中添加plate类。