SaaS 标志
此技能使用的所有文件均位于本 SKILL.md 所在文件夹内,路径均为相对于该文件夹的相对路径。它不需要来自其他技能或其他文件夹的任何内容,所以不要去寻找它们。除非用户指定其他位置,否则将所有生成的文件保存在当前项目的 out/saas-logo/ 目录下。
一个符号,扁平风格。返回的结果是:透明背景上、紧贴边缘裁切好的标志本身,以及该标志在其应用图标瓦片上的版本——这些文件可以直接放入网站中。此技能所借鉴的标志已在 references/analysis.md 中进行了研究:包括这十一个标志各自的几何结构、它们共同遵循的八条规则,以及它们所属的五个家族。在创建第一个标志前请阅读一次该文件;它定义了此处“看起来像真正的 SaaS 标志”的含义。
发送给图像模型的提示词位于 prompt.md 中,包含了模型所需的一切:共享规则(画布、瓦片、扁平填充、线条粗细、颜色)以及参考标志所属的五个家族,每个家族都有自己的规则。你的工作是提示词之前的思考(选择家族和符号)以及之后的判断。
步骤
1. 了解产品
阅读产品简介、README、登陆页面文案等任何现有资料。写一行话:"产品名称 — 用户用它做什么,用一个动词作用于一个宾语。" "将任务交给编码代理" → 移交,一张任务卡。"将文件夹发布为网站" → 发布,一个页面。标志应展示这个动词或宾语,而永远不要展示品类(不要齿轮、云、火箭、图表)。如果产品有品牌色(其 CSS 变量、其 favicon),请记录下来,并记录其首字母。
2. 选择家族
prompt.md 第 3 节中的五个家族,以及各自的适用场景:
- 实心几何体(Vercel, Miro):基础设施、开发者工具,任何希望感觉“必然如此”的产品,用一个形状承载想法。
- 重复几何体(Slack, Claude, Linear, Intercom, PostHog):协作、通信、AI,任何关于多个部分协同工作的产品。
- 字母形状(Webflow, Miro, Notion):产品名称即品牌,且首字母具有强烈形状时(A, M, N, W, K, Z, S, V)。
- 多面体(Airtable, Notion's page):数据、存储、文档,任何需要填充或堆叠的物品。
- 柔和线条(Mintlify, Intercom):面向消费者的友好型产品、文档、支持,任何温暖而非技术性的产品。
当用户提到参考品牌时,家族随之确定:“像 Slack 那样”或“像 Claude 那样” → 重复几何体;“像 Vercel 那样” → 实心几何体;“像 Webflow 那样”或“像 Notion 那样” → 字母形状;“像 Airtable 那样” → 多面体;“像 Mintlify 那样”或“像 Intercom 那样” → 柔和线条。当用户提到家族时,直接使用。如果没有明确指向,则将概念分散在两到三个家族中;最终的呈现结果决定。
3. 编写 3–4 个概念
每个概念包含 2–3 句图像模型无需猜测即可绘制的描述:
- 将符号描述为几何结构,而不是名词。不要写“一张任务卡”,而要写“一个圆角矩形,宽大于高,另一个相同的矩形在其后面,向上和向右偏移其高度的四分之一”。不要写“一个井号”,而要写“四个药丸形状,每个都是一端有圆形凸起的条形,围绕中心旋转 90°”。
- 对于重复几何体,明确数量和节奏:“五条竖条,从左到右高度按 3-5-4-2-3 步进”。
- 家族名称,对于字母形状,明确是哪个字母以及哪两到三笔。
- 颜色:如果有品牌色,使用十六进制值;否则使用“黑色瓦片,白色标志”或“金盏花色瓦片,黑色标志”。
- 排除项,当概念可能引入额外元素时:“无圆点”、“条形周围无边框”、“留白区域保持空白”。
确保不同概念的轮廓有所区别(高 vs 宽,一个整体 vs 分散布局)。放弃任何需要超出其家族允许的图元数量或使用家族禁止的颜色的概念。
4. 组合并生成
对于每个概念,使用 prompt.md 并将 {{input}} 替换为:
<Product> — <产品及其功能>。动词是 <动词>;宾语是 <宾语>。
品牌色:<十六进制值或"无">。首字母:<字母>。
家族:<五个家族之一>
概念:<步骤 3 中的概念描述>
通过 OpenRouter 并行生成所有概念(见下文),每个概念生成一张方形图片。保存为 <concept>.png 或 .jpg,取决于返回的格式(下面的代码片段可以区分它们)。
默认模型:google/gemini-3.1-flash-lite-image(Nano Banana 2 Lite),最便宜且最快;它处理扁平几何结构足够好,可用于整个运行阶段,在它上面失败的概念通常在其他模型上也会失败。仅在以下情况下升级:用户要求,或者一个中意的概念经过两轮渲染仍不够清晰时:切换到 google/gemini-3.1-flash-image(Nano Banana 2),然后是 google/gemini-3-pro-image(Nano Banana Pro),它能绘制最清晰的几何结构:平直的端点、均匀的线条、真正的扁平填充。
5. 检查
使用 bash <本技能文件夹>/scripts/sheet.sh sheet.png a.png b.png … 将所有瓦片排列成行,然后打开生成的 sheet 图。要同时查看参考标志,使用 bash <本技能文件夹>/scripts/fetch-references.sh out/saas-logo/references 通过 Brandfetch 获取这十一个标志到它们自己的 sheet 图中(需要 Brandfetch 客户端 ID;参见脚本头部的说明)。像分析文件评判参考标志那样评判每个瓦片:
- 扁平 — 每个形状使用单一填充,无渐变、无阴影、无斜面。任何不符合此要求的都需要重新生成,不能保留。
- 一致的角部 — 根据家族要求,所有角要么全尖,要么全圆。
- 数量 — 概念中指定的图元数量,不多不少。多了一个点、一个边框、一个缺口,都是重新生成时命名不准确导致的失败(“条形周围无边框”)。
- 轮廓 — 眯起眼睛看。在 16px 大小下应为一个清晰的形状,不应意外形成第二个图案:三条杠和一个曲线可能变成一张脸,一个 V 形和一个点可能变成光标,四个药丸可能变成风车。
- 意义 — 在不看名字的情况下,你能看出动词或宾语吗?如果它看起来像一个品类图标,那么是概念本身错误,而非渲染问题。
- 画布 — 瓦片居中在均匀的灰色背景上,上面没有其他东西,没有文字。瓦片尺寸和确切颜色在不同渲染之间略有不同;这是正常的。当需要一组瓦片完全匹配时,请在同一轮次中使用同一个模型生成所有瓦片,或者进行裁切。
只重新生成那些未通过的瓦片,并在概念中明确指出失败原因。两轮是正常的;一个概念连续失败两次,通常是概念本身的问题,而非模型问题。替换它。
6. 裁切
渲染结果是工作文件:一个带有瓦片的灰色画布。将每个通过的瓦片裁切为可用的文件:
bash <本技能文件夹>/scripts/cut.sh <concept>.png out/saas-logo/<product> --name <product>
这会生成 <product>-mark.png,即透明背景上紧贴边缘裁切、无填充间距的标志本身;以及 <product>-tile.png,即带有透明圆角的圆形应用图标瓦片。画布颜色从渲染图像的角落读取,瓦片颜色从瓦片边缘内部的一个带状区域读取,边缘像素会从这些颜色中分离出来,从而使边缘保持柔和且无光晕。当交付多个概念时,请使用不同的名称(例如 --name relay-bars,--name relay-block)。首次运行会在本技能目录的 scripts/.venv 中创建一个包含 Pillow 和 NumPy 的小型 Python 虚拟环境;此后运行会立即完成。
在深色和浅色背景上打开这两个文件并检查:标志边缘无瓦片颜色镶边、瓦片角落无画布缝隙、标志无被裁剪缺失。出现镶边意味着渲染的瓦片不是平直的(有渐变或暗角);应重新渲染而非修补裁切结果。仅在放大查看时才能看到的边缘微弱颜色印记,是来自 Lite 和 Flash 模型的 JPEG 噪点;如果对质量有要求,请使用 google/gemini-3-pro-image 再次渲染中意的结果,该模型会以 PNG 格式输出。
7. 交付
将标志和应用图标 PNG 文件放入 out/saas-logo/<product>/ 目录。仅在用户要求时,才将它们复制到产品存放品牌资产的目录(如 public/、brand/、assets/)。将渲染结果和 sheet.png 放在旁边的 renders/ 文件夹中,以免混淆。在总结中,按路径命名推荐的 -mark.png 和 -tile.png 文件,用一句话说明你推荐哪个概念及其原因,并列出其他备选概念及其文件。
通过 OpenRouter 生成
API 密钥来自 OPENROUTER_API_KEY。如果未设置,请停止并让用户设置,而不是猜测其他提供商。
KEY="$OPENROUTER_API_KEY"
# request.json: {"model": "google/gemini-3.1-flash-lite-image", "prompt": "<组合后的提示>", "aspect_ratio": "1:1"}
curl -sS https://openrouter.ai/api/v1/images \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d @request.json > response.json
python3 - <<'PY'
import base64, json, pathlib
data = json.loads(pathlib.Path("response.json").read_text())["data"][0]
image = base64.b64decode(data["b64_json"])
# Lite 和 Flash 模型以 JPEG 字节返回,Pro 以 PNG 返回;根据实际格式命名文件
ext = "png" if image.startswith(b"\x89PNG") else "jpg"
pathlib.Path(f"concept.{ext}").write_bytes(image)
PY
scripts/sheet.sh 和 scripts/cut.sh 可以接受这两种格式。
文件
prompt.md— 提示词模板;{{input}}被替换为产品描述、家族和概念。其第 3 节包含五个家族。references/analysis.md— 对十一个标志的研究:每个标志的几何结构、它们共享的规则、五个家族。scripts/fetch-references.sh— 通过 Brandfetch 的 Logo API(需要BRANDFETCH_CLIENT_ID环境变量中的客户端 ID)将参考标志拉取到文件夹和 sheet 图中;任何域名列表都可以,用于不同的参考集。scripts/sheet.sh— 在灰色画布上将瓦片排列成行(需要rsvg-convert;可通过brew install librsvg安装)。scripts/cut.sh、scripts/cut.py— 将渲染结果裁切成可交付的透明标志和应用图标 PNG 文件。