with one click
visual-companion
// 基于浏览器的伙伴,用于在头脑风暴期间展示模型、图表和视觉选项。意味着它可用于从视觉处理中受益的问题;这并不意味着每个问题都通过浏览器进行。该技能的前置条件必须加载[brainstorming]
// 基于浏览器的伙伴,用于在头脑风暴期间展示模型、图表和视觉选项。意味着它可用于从视觉处理中受益的问题;这并不意味着每个问题都通过浏览器进行。该技能的前置条件必须加载[brainstorming]
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | visual-companion |
| description | 基于浏览器的伙伴,用于在头脑风暴期间展示模型、图表和视觉选项。意味着它可用于从视觉处理中受益的问题;这并不意味着每个问题都通过浏览器进行。该技能的前置条件必须加载[brainstorming] |
重要提示: 该技能的前置条件必须加载[brainstorming]
基于浏览器的视觉头脑风暴伴侣,用于展示模型、图表和选项。
按问题决定,而不是按会话决定。测试标准:用户通过看到它比阅读它更易于理解问题吗?
使用浏览器 当内容本身是视觉的:
使用终端 当内容是文本或表格:
关于 UI 主题的问题不自动是视觉问题。"你想要什么样的向导?" 是概念问题 — 使用终端。"这些向导布局哪个感觉对?" 是视觉问题 — 使用浏览器。
视觉伴侣集成了 awesome-design-md 品牌设计系统库 — 71+ 个知名品牌(Stripe、Linear、Apple、Claude 等)的设计规范,可直接应用到 UI mockup 生成中。
DESIGN.md 是一个纯文本设计系统文档,包含 YAML front matter(颜色 tokens、排版层级、间距尺度、组件样式)+ Markdown 正文(设计哲学、使用规则、反模式)。AI agent 读取后即可按该品牌风格生成 UI。
每个 DESIGN.md 包含:
设计风格库已内置在技能目录中,无需额外下载:
{技能目录}/design-md/
├── stripe/DESIGN.md # 靛蓝 + 渐变网格
├── linear.app/DESIGN.md # 纯黑画布 + 薰衣草蓝
├── apple/DESIGN.md # 极简留白 + SF Pro
├── claude/DESIGN.md # 奶油底色 + 珊瑚橙
├── tesla/DESIGN.md # 彻底减法 + 全屏影像
├── notion/DESIGN.md # 温暖极简 + 衬线标题
├── nvidia/DESIGN.md # 绿黑能量 + 技术力量
├── spotify/DESIGN.md # 鲜绿暗底 + 粗体排版
├── ... (共 71 个品牌)
读取时的相对路径:{技能目录}/design-md/{品牌名}/DESIGN.md
第 1 步:展示风格选项 — 在生成任何 UI mockup 之前,先在终端按分类列出可用风格:
可用设计风格(按领域):
AI & 开发者工具:
Claude | Cursor | Vercel | Warp | Raycast | Ollama
生产力 & SaaS:
Linear | Notion | Intercom | Zapier | Resend
金融科技:
Stripe | Coinbase | Revolut | Wise | Binance
电商 & 零售:
Shopify | Airbnb | Nike | Starbucks
消费科技 & 媒体:
Apple | Spotify | NVIDIA | IBM | PlayStation | Pinterest
汽车:
Tesla | BMW | Ferrari | Bugatti
... (完整列表见 design-md/ 目录)
询问用户:「你想用哪个品牌的设计风格?」
第 2 步:加载 DESIGN.md — 用户选定后,读取对应 design-md/{品牌}/DESIGN.md:
read_file design-md/{品牌}/DESIGN.md
第 3 步:提取设计 tokens — 从 YAML front matter 中提取关键值:
{colors.primary} → 主色 / CTA 按钮色{colors.canvas} → 页面背景色{colors.ink} → 正文文字色{typography.display-xxl} → 最大标题样式{typography.body-md} → 正文样式{rounded.lg} / {rounded.pill} → 卡片 / 按钮圆角{spacing.*} → 间距系统第 4 步:生成风格匹配的 mockup HTML — 将 tokens 转换为 CSS 变量,注入到 HTML 内容片段中:
<style>
:root {
--color-primary: #533afd; /* {colors.primary} */
--color-canvas: #ffffff; /* {colors.canvas} */
--color-ink: #0d253d; /* {colors.ink} */
--color-hairline: #e3e8ee; /* {colors.hairline} */
--font-display: sohne-var, 'SF Pro Display', sans-serif;
--font-body: sohne-var, 'SF Pro Display', sans-serif;
--rounded-card: 12px; /* {rounded.lg} */
--rounded-button: 9999px; /* {rounded.pill} */
--spacing-lg: 24px;
--spacing-xl: 32px;
}
</style>
<div class="mockup" style="background: var(--color-canvas); color: var(--color-ink); font-family: var(--font-body);">
<!-- mockup content using design tokens -->
<h2 style="font-family: var(--font-display); font-size: 48px; font-weight: 300; letter-spacing: -0.96px;">
{标题}
</h2>
<button style="background: var(--color-primary); border-radius: var(--rounded-button); padding: 8px 16px; color: white;">
{CTA 文字}
</button>
</div>
第 5 步:后续迭代 — 用户反馈后,继续使用同一套设计 tokens 生成修改版本。风格在会话期间保持一致。
| DESIGN.md Token | CSS 属性 |
|---|---|
{colors.primary} | background (按钮), color (链接), border-color (焦点环) |
{colors.canvas} | background (页面) |
{colors.ink} | color (正文) |
{colors.hairline} | border (卡片, 分割线) |
{colors.surface-1} | background (卡片, 面板) |
{typography.display-xxl.fontSize} | font-size (最大标题) |
{typography.display-xxl.fontWeight} | font-weight |
{typography.display-xxl.lineHeight} | line-height |
{typography.display-xxl.letterSpacing} | letter-spacing |
{typography.display-xxl.fontFamily} | font-family (带 fallback) |
{typography.body-md.*} | font-size/weight/lineHeight (正文) |
{rounded.pill} = 9999px | border-radius (药丸按钮) |
{rounded.lg} | border-radius (卡片) |
{spacing.xl} | padding, margin, gap |
<style> 块 + 内容片段,由框架模板包装,不写完整 HTML 文档git clone https://github.com/VoltAgent/awesome-design-md.git
服务器监视目录中的 HTML 文件,并将最新的文件提供给浏览器。你将 HTML 内容写入 screen_dir,用户在浏览器中看到它并可以点击选择选项。选择记录到 state_dir/events,你在下一轮读取它。
内容片段 vs 完整文档: 如果你的 HTML 文件以 <!DOCTYPE 或 <html 开头,服务器按原样提供(只注入辅助脚本)。否则,服务器自动将你的内容包装在框架模板中 — 添加头部、CSS 主题、选择指示器和所有交互基础设施。默认编写内容片段。 只有在需要完全控制页面时才编写完整文档。
# Start server with persistence (mockups saved to project)
scripts/start-server.sh --project-dir /path/to/project
# Returns: {"type":"server-started","port":52341,"url":"http://localhost:52341",
# "screen_dir":"/path/to/project/.zjkycode/brainstorm/12345-1706000000/content",
# "state_dir":"/path/to/project/.zjkycode/brainstorm/12345-1706000000/state"}
保存响应中的 screen_dir 和 state_dir。告诉用户打开 URL。
查找连接信息: 服务器将其启动 JSON 写入 $STATE_DIR/server-info。如果你在后台启动服务器但没有捕获 stdout,读取该文件获取 URL 和端口。使用 --project-dir 时,检查 <project>/.zjkycode/brainstorm/ 获取会话目录。
注意: 将项目根目录作为 --project-dir 传递,这样模型会持久保存在 .zjkycode/brainstorm/ 中,并在服务器重启后保留。没有它,文件会进入 /tmp 并被清理。提醒用户将 .zjkycode/ 添加到 .gitignore(如果还没有)。
按平台启动服务器:
Claude Code (macOS / Linux):
# Default mode works — the script backgrounds the server itself
scripts/start-server.sh --project-dir /path/to/project
Claude Code (Windows):
# Windows auto-detects and uses foreground mode, which blocks the tool call.
# Use run_in_background: true on the Bash tool call so the server survives
# across conversation turns.
scripts/start-server.sh --project-dir /path/to/project
通过 Bash 工具调用时,设置 run_in_background: true。然后在下一轮读取 $STATE_DIR/server-info 获取 URL 和端口。
Codex:
# Codex reaps background processes. The script auto-detects CODEX_CI and
# switches to foreground mode. Run it normally — no extra flags needed.
scripts/start-server.sh --project-dir /path/to/project
Gemini CLI:
# Use --foreground and set is_background: true on your shell tool call
# so the process survives across turns
scripts/start-server.sh --project-dir /path/to/project --foreground
其他环境: 服务器必须在后台跨会话轮运行。如果你的环境会回收分离的进程,使用 --foreground 并用平台的后台执行机制启动命令。
如果 URL 从浏览器无法访问(在远程/容器化设置中常见),绑定非回环主机:
scripts/start-server.sh \
--project-dir /path/to/project \
--host 0.0.0.0 \
--url-host localhost
使用 --url-host 控制返回的 URL JSON 中打印的主机名。
检查服务器是否存活,然后写入 HTML 到 screen_dir 的新文件:
$STATE_DIR/server-info 是否存在。如果不存在(或 $STATE_DIR/server-stopped 存在),服务器已关闭 — 在继续之前用 start-server.sh 重启它。服务器在 30 分钟不活动后自动退出。platform.html、visual-style.html、layout.html告诉用户期望什么并结束你的轮次:
在你的下一轮 — 用户在终端回应后:
$STATE_DIR/events(如果存在)— 这包含用户的浏览器交互(点击、选择)作为 JSON 行state_dir/events 提供结构化交互数据迭代或推进 — 如果反馈改变了当前屏幕,写入新文件(例如 layout-v2.html)。只有当前步骤验证后才移动到下一个问题。
返回终端时卸载 — 当下一步不需要浏览器时(例如,澄清问题、权衡讨论),推送等待屏幕以清除过时内容:
<!-- filename: waiting.html (or waiting-2.html, etc.) -->
<div style="display:flex;align-items:center;justify-content:center;min-height:60vh">
<p class="subtitle">Continuing in terminal...</p>
</div>
这防止用户盯着已解决的选择,而对话已经继续。当下一个视觉问题出现时,像往常一样推送新内容文件。
重复直到完成。
只编写放入页面的内容。服务器自动将其包装在框架模板中(头部、主题 CSS、选择指示器和所有交互基础设施)。
最小示例:
<h2>Which layout works better?</h2>
<p class="subtitle">Consider readability and visual hierarchy</p>
<div class="options">
<div class="option" data-choice="a" onclick="toggleSelect(this)">
<div class="letter">A</div>
<div class="content">
<h3>Single Column</h3>
<p>Clean, focused reading experience</p>
</div>
</div>
<div class="option" data-choice="b" onclick="toggleSelect(this)">
<div class="letter">B</div>
<div class="content">
<h3>Two Column</h3>
<p>Sidebar navigation with main content</p>
</div>
</div>
</div>
就是这样。不需要 <html>、CSS 或 <script> 标签。服务器提供所有这些。
框架模板为你的内容提供这些 CSS 类:
<div class="options">
<div class="option" data-choice="a" onclick="toggleSelect(this)">
<div class="letter">A</div>
<div class="content">
<h3>Title</h3>
<p>Description</p>
</div>
</div>
</div>
多选: 在容器上添加 data-multiselect 让用户选择多个选项。每次点击切换项目。指示条显示计数。
<div class="options" data-multiselect>
<!-- same option markup — users can select/deselect multiple -->
</div>
<div class="cards">
<div class="card" data-choice="design1" onclick="toggleSelect(this)">
<div class="card-image"><!-- mockup content --></div>
<div class="card-body">
<h3>Name</h3>
<p>Description</p>
</div>
</div>
</div>
<div class="mockup">
<div class="mockup-header">Preview: Dashboard Layout</div>
<div class="mockup-body"><!-- your mockup HTML --></div>
</div>
<div class="split">
<div class="mockup"><!-- left --></div>
<div class="mockup"><!-- right --></div>
</div>
<div class="pros-cons">
<div class="pros"><h4>Pros</h4><ul><li>Benefit</li></ul></div>
<div class="cons"><h4>Cons</h4><ul><li>Drawback</li></ul></div>
</div>
<div class="mock-nav">Logo | Home | About | Contact</div>
<div style="display: flex;">
<div class="mock-sidebar">Navigation</div>
<div class="mock-content">Main content area</div>
</div>
<button class="mock-button">Action Button</button>
<input class="mock-input" placeholder="Input field">
<div class="placeholder">Placeholder area</div>
h2 — 页面标题h3 — 部分标题.subtitle — 标题下的次要文字.section — 带下边距的内容块.label — 小型大写标签文字当用户在浏览器中点击选项时,他们的交互被记录到 $STATE_DIR/events(每行一个 JSON 对象)。当你推送新屏幕时,文件会自动清除。
{"type":"click","choice":"a","text":"Option A - Simple Layout","timestamp":1706000101}
{"type":"click","choice":"c","text":"Option C - Complex Grid","timestamp":1706000108}
{"type":"click","choice":"b","text":"Option B - Hybrid","timestamp":1706000115}
完整事件流显示用户的探索路径 — 他们可能在确定之前点击多个选项。最后一个 choice 事件通常是最终选择,但点击模式可能揭示值得询问的犹豫或偏好。
如果 $STATE_DIR/events 不存在,用户没有与浏览器交互 — 只使用他们的终端文本。
platform.html、visual-style.html、layout.htmllayout-v2.html、layout-v3.htmlscripts/stop-server.sh $SESSION_DIR
如果会话使用了 --project-dir,模型文件会持久保存在 .zjkycode/brainstorm/ 中供以后参考。只有 /tmp 会话会在停止时被删除。
scripts/frame-template.htmlscripts/helper.js