Browser-based visual brainstorming companion for showing mockups, diagrams, and options.
以瀏覽器為基礎的視覺腦力激盪夥伴,用於展示 mockups、圖表與選項。
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:
內容本身是視覺的,使用瀏覽器:
Use the terminal when the content is text or tabular:
內容是文字或表格的,使用終端機:
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 主題的問題不自動是視覺問題。「你想要哪種精靈?」是概念問題——使用終端機。「這些精靈佈局哪個感覺對?」是視覺問題——使用瀏覽器。
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 主題、連線狀態與所有互動基礎設施。預設撰寫內容片段。 只有在你需要完全掌控頁面時才撰寫完整文件。
# 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_dir 與 state_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 中印出哪個主機名稱。
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 filescreen_dir 中的一個新檔案:
- 必要:在參照 URL 或推送畫面之前,先確認伺服器存活。 檢查 $STATE_DIR/server-info 存在、且 $STATE_DIR/server-stopped 不存在。若它已關閉,用相同的 --project-dir 以 start-server.sh 重新啟動——它會重用相同的 port,因此使用者已開啟的分頁會自行重新連線(伺服器停機期間它會顯示「paused」覆蓋層),你也不需要寄送新 URL。伺服器在閒置 4 小時後自動結束(可用 --idle-timeout-minutes 設定)。
- 使用語意化檔名:platform.html、visual-style.html、layout.html
- 絕不重用檔名 ——每個畫面都使用新的檔案
- 使用你的檔案建立工具——絕不使用 cat/heredoc(會把雜訊倒進終端機)
- 伺服器自動提供最新的檔案$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$STATE_DIR/events ——它包含使用者的瀏覽器互動(點擊、選取),以 JSON 行格式呈現
- 與使用者的終端機文字合併,取得完整樣貌
- 終端機訊息是主要回饋;state_dir/events 提供結構化的互動資料layout-v2.html). Only move to the next question when the current step is validated.layout-v2.html)。只有目前步驟獲得驗證後才移動到下一個問題。```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.
這能防止使用者在對話已前進時,還盯著一個已解決的選擇。當下一個視覺問題出現時,照常推送新的內容檔案。
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> 標籤。伺服器會提供所有這些。
The frame template provides these CSS classes for your content:
frame 範本為你的內容提供這些 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>
<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>
<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>
<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>
<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>
<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>
<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>
h2 — page titleh3 — section heading.subtitle — secondary text below title.section — content block with bottom margin.label — small uppercase label texth2 ——頁面標題h3 ——區段標題.subtitle ——標題下方的次要文字.section ——含底部邊距的內容區塊.label ——小號大寫標籤文字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 不存在,表示使用者沒有與瀏覽器互動——只使用他們的終端機文字。
platform.html, visual-style.html, layout.htmllayout-v2.html, layout-v3.htmlplatform.html、visual-style.html、layout.htmllayout-v2.html、layout-v3.htmlscripts/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 會在停止時被刪除。
scripts/frame-template.htmlscripts/helper.jsscripts/frame-template.htmlscripts/helper.js