visual-companion

brainstorming · 附屬文件

Visual Companion Guide

視覺夥伴指南

Browser-based visual brainstorming companion for showing mockups, diagrams, and options.

以瀏覽器為基礎的視覺腦力激盪夥伴,用於展示 mockups、圖表與選項。

When to Use

使用時機

Decide per-question, not per-session. The test: would the user understand this better by seeing it than reading it?

逐問題決定,而非逐 session。判斷標準:使用者「看」會比「讀」更容易理解嗎?

Use the browser when the content itself is visual:

內容本身是視覺的,使用瀏覽器:

  • UI mockups — wireframes, layouts, navigation structures, component designs
  • Architecture diagrams — system components, data flow, relationship maps
  • Side-by-side visual comparisons — comparing two layouts, two color schemes, two design directions
  • Design polish — when the question is about look and feel, spacing, visual hierarchy
  • Spatial relationships — state machines, flowcharts, entity relationships rendered as diagrams
  • UI mockups ——線框圖、佈局、導覽結構、元件設計
  • 架構圖 ——系統元件、資料流、關係圖
  • 並排的視覺比較 ——比較兩種佈局、兩種配色、兩個設計方向
  • 設計潤飾 ——當問題關於外觀與感受、間距、視覺層級
  • 空間關係 ——以圖表呈現的狀態機、流程圖、實體關係

Use the terminal when the content is text or tabular:

內容是文字或表格的,使用終端機:

  • Requirements and scope questions — "what does X mean?", "which features are in scope?"
  • Conceptual A/B/C choices — picking between approaches described in words
  • Tradeoff lists — pros/cons, comparison tables
  • Technical decisions — API design, data modeling, architectural approach selection
  • Clarifying questions — anything where the answer is words, not a visual preference
  • 需求與範圍問題 ——「X 是什麼意思?」、「哪些功能在範圍內?」
  • 概念性的 A/B/C 選擇 ——在以文字描述的做法之間做選擇
  • 取捨清單 ——優點/缺點、比較表
  • 技術決策 ——API 設計、資料建模、架構做法選擇
  • 釐清問題 ——任何答案是一段文字、而非視覺偏好的事物

A question about a UI topic is not automatically a visual question. "What kind of wizard do you want?" is conceptual — use the terminal. "Which of these wizard layouts feels right?" is visual — use the browser.

一個關於 UI 主題的問題不自動是視覺問題。「你想要哪種精靈?」是概念問題——使用終端機。「這些精靈佈局哪個感覺對?」是視覺問題——使用瀏覽器。

How It Works

運作方式

The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content to screen_dir, the user sees it in their browser and can click to select options. Selections are recorded to state_dir/events that you read on your next turn.

伺服器監看一個目錄中的 HTML 檔案,並把最新的那份提供給瀏覽器。你把 HTML 內容寫到 screen_dir,使用者在其瀏覽器中看到它,並能點擊以選取選項。選取會被記錄到 state_dir/events,你可以在下一個回合讀取。

Content fragments vs full documents: If your HTML file starts with <!DOCTYPE or <html, the server serves it as-is (just injects the helper script). Otherwise, the server automatically wraps your content in the frame template — adding the header, CSS theme, connection status, and all interactive infrastructure. Write content fragments by default. Only write full documents when you need complete control over the page.

內容片段 vs 完整文件: 若你的 HTML 檔案以 <!DOCTYPE<html 開頭,伺服器會原樣提供它(只注入 helper 腳本)。否則,伺服器會自動把你的內容包進 frame 範本——加上頁首、CSS 主題、連線狀態與所有互動基礎設施。預設撰寫內容片段。 只有在你需要完全掌控頁面時才撰寫完整文件。

Starting a Session

啟動一個 session

# Start AFTER the user approves the companion. --open auto-opens their browser on
# the first screen; --project-dir persists mockups and enables same-port restart.
scripts/start-server.sh --project-dir /path/to/project --open

# Returns: {"type":"server-started","port":52341,
#           "url":"http://localhost:52341/?key=ab12…",
#           "screen_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000/content",
#           "state_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000/state"}
# Start AFTER the user approves the companion. --open auto-opens their browser on
# the first screen; --project-dir persists mockups and enables same-port restart.
scripts/start-server.sh --project-dir /path/to/project --open

# Returns: {"type":"server-started","port":52341,
#           "url":"http://localhost:52341/?key=ab12…",
#           "screen_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000/content",
#           "state_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000/state"}

Save screen_dir and state_dir from the response. With --open, the browser opens itself when you push the first screen — you don't need to ask the user to open it, but still share the URL as a fallback (headless/remote setups won't auto-open).

從回應中保存 screen_dirstate_dir。使用 --open 時,當你推送第一個畫面,瀏覽器會自動開啟——你不需要請使用者開啟它,但仍要分享 URL 作為備援(headless/遠端設定不會自動開啟)。

The URL contains a session key (?key=…). The server rejects any request without it, so always give the user the complete URL from the url field — never strip the query string, and never hand out a bare http://host:port. The key gates HTTP and WebSocket access so a stray browser tab or another machine on the network can't read the screens or inject events. After the first load the browser remembers the key via a cookie, so reloads and /files/* assets work without repeating it.

URL 含有 session 金鑰(?key=…)。 伺服器會拒絕任何沒有它的請求,所以務必給使用者 url 欄位中的完整 URL——絕不要剝掉查詢字串,也絕不要交出一個裸的 http://host:port。金鑰把關 HTTP 與 WebSocket 的存取,因此閒置的瀏覽器分頁或網路上的另一台機器無法讀取畫面或注入事件。首次載入後,瀏覽器會透過 cookie 記住金鑰,因此重新載入與 /files/* 資源不需重複它。

Finding connection info: The server writes its startup JSON to $STATE_DIR/server-info. If you launched the server in the background and didn't capture stdout, read that file to get the URL and port. When using --project-dir, check <project>/.superpowers/brainstorm/ for the session directory.

尋找連線資訊: 伺服器把它的啟動 JSON 寫到 $STATE_DIR/server-info。若你在背景啟動伺服器且未擷取 stdout,讀取該檔案以取得 URL 與 port。使用 --project-dir 時,在 <project>/.superpowers/brainstorm/ 檢查 session 目錄。

Note: Pass the project root as --project-dir so mockups persist in .superpowers/brainstorm/ and survive server restarts. Without it, files go to /tmp and get cleaned up. Remind the user to add .superpowers/ to .gitignore if it's not already there.

注意: 把專案根目錄以 --project-dir 傳入,讓 mockups 保存在 .superpowers/brainstorm/ 中並在伺服器重啟後存活。沒有它的話,檔案會進到 /tmp 並被清理。提醒使用者把 .superpowers/ 加入 .gitignore(若還沒有的話)。

Launching the server by platform:

依平台啟動伺服器:

Claude Code:

# Default mode works — the script backgrounds the server itself.
scripts/start-server.sh --project-dir /path/to/project --open

Claude Code:

# Default mode works — the script backgrounds the server itself.
scripts/start-server.sh --project-dir /path/to/project --open

On Windows, the script auto-detects and switches to foreground mode (which blocks the tool call). Use run_in_background: true on the Bash tool call so the server survives across conversation turns, then read $STATE_DIR/server-info on the next turn to get the URL and port.

在 Windows 上,腳本會自動偵測並切換到前景模式(這會阻擋工具呼叫)。在 Bash 工具呼叫上使用 run_in_background: true,讓伺服器跨對話回合存活,然後在下一個回合讀取 $STATE_DIR/server-info 以取得 URL 與 port。

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 --open

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 --open

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 --open --foreground

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 --open --foreground

Copilot CLI:

# Use --foreground and start the server via the bash tool with mode: "async"
# so the process survives across turns. Capture the returned shellId for
# read_bash / stop_bash if you need to interact with it later.
scripts/start-server.sh --project-dir /path/to/project --open --foreground

Copilot CLI:

# Use --foreground and start the server via the bash tool with mode: "async"
# so the process survives across turns. Capture the returned shellId for
# read_bash / stop_bash if you need to interact with it later.
scripts/start-server.sh --project-dir /path/to/project --open --foreground

Other environments: The server must keep running in the background across conversation turns. If your environment reaps detached processes, use --foreground and launch the command with your platform's background execution mechanism.

其他環境: 伺服器必須在背景中跨對話回合持續執行。若你的環境會收割分離的 process,使用 --foreground,並以你平台的背景執行機制啟動指令。

If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host:

若你的瀏覽器無法連到該 URL(在遠端/容器化設定中很常見),綁定一個非 loopback 的主機:

scripts/start-server.sh \
  --project-dir /path/to/project \
  --host 0.0.0.0 \
  --url-host localhost
scripts/start-server.sh \
  --project-dir /path/to/project \
  --host 0.0.0.0 \
  --url-host localhost

Use --url-host to control what hostname is printed in the returned URL JSON.

使用 --url-host 控制回傳的 URL JSON 中印出哪個主機名稱。

The Loop

迴圈

  1. Check server is alive, then write HTML to a new file in screen_dir: - Required: confirm the server is alive before referring to the URL or pushing a screen. Check that $STATE_DIR/server-info exists and $STATE_DIR/server-stopped does not. If it has shut down, restart it with start-server.sh using the same --project-dir — it reuses the same port, so the user's open tab reconnects on its own (it shows a "paused" overlay while the server is down) and you don't need to send a new URL. The server auto-exits after 4 hours idle (configurable with --idle-timeout-minutes). - Use semantic filenames: platform.html, visual-style.html, layout.html - Never reuse filenames — each screen gets a fresh file - Use your file-creation tool — never use cat/heredoc (dumps noise into terminal) - Server automatically serves the newest file
  1. 檢查伺服器存活,然後把 HTML 寫入 screen_dir 中的一個新檔案: - 必要:在參照 URL 或推送畫面之前,先確認伺服器存活。 檢查 $STATE_DIR/server-info 存在、且 $STATE_DIR/server-stopped 不存在。若它已關閉,用相同的 --project-dirstart-server.sh 重新啟動——它會重用相同的 port,因此使用者已開啟的分頁會自行重新連線(伺服器停機期間它會顯示「paused」覆蓋層),你也不需要寄送新 URL。伺服器在閒置 4 小時後自動結束(可用 --idle-timeout-minutes 設定)。 - 使用語意化檔名:platform.htmlvisual-style.htmllayout.html - 絕不重用檔名 ——每個畫面都使用新的檔案 - 使用你的檔案建立工具——絕不使用 cat/heredoc(會把雜訊倒進終端機) - 伺服器自動提供最新的檔案
  1. Tell user what to expect and end your turn: - Remind them of the URL (every step, not just first) - Give a brief text summary of what's on screen (e.g., "Showing 3 layout options for the homepage") - Ask them to respond in the terminal: "Take a look and let me know what you think. Click to select an option if you'd like."
  1. 告訴使用者會看到什麼並結束你的回合: - 提醒他們 URL(每一步都要,不只是第一次) - 給出畫面上內容的簡短文字摘要(例如「顯示首頁的 3 種佈局選項」) - 請他們在終端機中回應:「看一下並讓我知道你的想法。若你願意,可以點擊選取一個選項。」
  1. On your next turn — after the user responds in the terminal: - Read $STATE_DIR/events if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines - Merge with the user's terminal text to get the full picture - The terminal message is the primary feedback; state_dir/events provides structured interaction data
  1. 在你的下一個回合 ——在使用者於終端機回應之後: - 若存在,讀取 $STATE_DIR/events ——它包含使用者的瀏覽器互動(點擊、選取),以 JSON 行格式呈現 - 與使用者的終端機文字合併,取得完整樣貌 - 終端機訊息是主要回饋;state_dir/events 提供結構化的互動資料
  1. Iterate or advance — if feedback changes current screen, write a new file (e.g., layout-v2.html). Only move to the next question when the current step is validated.
  1. 迭代或前進 ——若回饋改變目前的畫面,寫入一個新檔案(例如 layout-v2.html)。只有目前步驟獲得驗證後才移動到下一個問題。
  1. Unload when returning to terminal — when the next step doesn't need the browser (e.g., a clarifying question, a tradeoff discussion), push a waiting screen to clear the stale content:
  1. 回到終端機時卸載 ——當下一步不需要瀏覽器時(例如釐清問題、取捨討論),推送一個等待畫面以清除過時的內容:

```html

Continuing in terminal...

```

```html

Continuing in terminal...

```

This prevents the user from staring at a resolved choice while the conversation has moved on. When the next visual question comes up, push a new content file as usual.

這能防止使用者在對話已前進時,還盯著一個已解決的選擇。當下一個視覺問題出現時,照常推送新的內容檔案。

  1. Repeat until done.
  1. 重複直到完成。

Writing Content Fragments

撰寫內容片段

Write just the content that goes inside the page. The server wraps it in the frame template automatically (header, theme CSS, connection status, and all interactive infrastructure).

只撰寫會放進頁面內的內容。伺服器會自動把它包進 frame 範本(頁首、主題 CSS、連線狀態與所有互動基礎設施)。

Minimal example:

最小範例:

<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>
<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>

That's it. No <html>, no CSS, no <script> tags needed. The server provides all of that.

就是這樣。不需要 <html>、CSS 或 <script> 標籤。伺服器會提供所有這些。

CSS Classes Available

可用的 CSS 類別

The frame template provides these CSS classes for your content:

frame 範本為你的內容提供這些 CSS 類別:

Options (A/B/C choices)

選項(A/B/C 選擇)

<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>
<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>

Multi-select: Add data-multiselect to the container to let users select multiple options. Each click toggles the item's selected styling.

多重選取: 在容器上加入 data-multiselect,讓使用者可以選取多個選項。每次點擊會切換該項目的選取樣式。

<div class="options" data-multiselect>
  <!-- same option markup — users can select/deselect multiple -->
</div>
<div class="options" data-multiselect>
  <!-- same option markup — users can select/deselect multiple -->
</div>

Cards (visual designs)

卡片(視覺設計)

<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="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>

Mockup container

Mockup 容器

<div class="mockup">
  <div class="mockup-header">Preview: Dashboard Layout</div>
  <div class="mockup-body"><!-- your mockup HTML --></div>
</div>
<div class="mockup">
  <div class="mockup-header">Preview: Dashboard Layout</div>
  <div class="mockup-body"><!-- your mockup HTML --></div>
</div>

Split view (side-by-side)

分割檢視(並排)

<div class="split">
  <div class="mockup"><!-- left --></div>
  <div class="mockup"><!-- right --></div>
</div>
<div class="split">
  <div class="mockup"><!-- left --></div>
  <div class="mockup"><!-- right --></div>
</div>

Pros/Cons

優點/缺點

<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="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>

Mock elements (wireframe building blocks)

Mock 元素(線框圖建構積木)

<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>
<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>

Typography and sections

排版與區段

  • h2 — page title
  • h3 — section heading
  • .subtitle — secondary text below title
  • .section — content block with bottom margin
  • .label — small uppercase label text
  • h2 ——頁面標題
  • h3 ——區段標題
  • .subtitle ——標題下方的次要文字
  • .section ——含底部邊距的內容區塊
  • .label ——小號大寫標籤文字

Browser Events Format

瀏覽器事件格式

When the user clicks options in the browser, their interactions are recorded to $STATE_DIR/events (one JSON object per line). The file is cleared automatically when you push a new screen.

當使用者在瀏覽器中點擊選項時,他們的互動會被記錄到 $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}
{"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}

The full event stream shows the user's exploration path — they may click multiple options before settling. The last choice event is typically the final selection, but the pattern of clicks can reveal hesitation or preferences worth asking about.

完整的事件串流顯示使用者的探索路徑——他們可能先點擊多個選項才定案。最後的 choice 事件通常是最終選取,但點擊模式可以透露出值得追問的猶豫或偏好。

If $STATE_DIR/events doesn't exist, the user didn't interact with the browser — use only their terminal text.

$STATE_DIR/events 不存在,表示使用者沒有與瀏覽器互動——只使用他們的終端機文字。

Design Tips

設計提示

  • Scale fidelity to the question — wireframes for layout, polish for polish questions
  • Explain the question on each page — "Which layout feels more professional?" not just "Pick one"
  • Iterate before advancing — if feedback changes current screen, write a new version
  • 2-4 options max per screen
  • Use real content when it matters — for a photography portfolio, use actual images (Unsplash). Placeholder content obscures design issues.
  • Keep mockups simple — focus on layout and structure, not pixel-perfect design
  • 把擬真度對齊問題 ——佈局用線框圖,潤飾問題用潤飾
  • 在每個頁面上說明問題 ——「哪種佈局感覺更專業?」而不只是「選一個」
  • 前進之前先迭代 ——若回饋改變目前的畫面,寫入一個新版本
  • 每個畫面最多 2-4 個選項
  • 在重要時使用真實內容 ——對攝影作品集,使用真實的圖片(Unsplash)。佔位內容會掩蓋設計問題。
  • 保持 mockups 簡單 ——聚焦於佈局與結構,而非像素完美的設計

File Naming

檔名

  • Use semantic names: platform.html, visual-style.html, layout.html
  • Never reuse filenames — each screen must be a new file
  • For iterations: append version suffix like layout-v2.html, layout-v3.html
  • Server serves newest file by modification time
  • 使用語意化名稱:platform.htmlvisual-style.htmllayout.html
  • 絕不重用檔名——每個畫面都必須是新檔案
  • 迭代時:加上版本後綴,例如 layout-v2.htmllayout-v3.html
  • 伺服器依修改時間提供最新的檔案

Cleaning Up

清理

scripts/stop-server.sh $SESSION_DIR
scripts/stop-server.sh $SESSION_DIR

If the session used --project-dir, mockup files persist in .superpowers/brainstorm/ for later reference. Only /tmp sessions get deleted on stop.

若 session 使用了 --project-dir,mockup 檔案會保存在 .superpowers/brainstorm/ 中供日後參照。只有 /tmp session 會在停止時被刪除。

Reference

參考文件

  • Frame template (CSS reference): scripts/frame-template.html
  • Helper script (client-side): scripts/helper.js
  • Frame 範本(CSS 參考):scripts/frame-template.html
  • Helper 腳本(用戶端):scripts/helper.js