2026-03-06 12:55:29 -08:00
# Visual Companion Guide
Browser-based visual brainstorming companion for showing mockups, diagrams, and options.
## When to Use
Decide per-question, not per-session. The test: **would the user understand this better by seeing it than reading it? **
**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
**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
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.
## How It Works
2026-05-08 15:52:38 -07:00
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 tries the mockup in their browser, and they respond in the terminal. Use `[data-choice]` only when you are deliberately asking the user to pick among named A/B/C visual options.
2026-03-06 12:55:29 -08:00
**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, selection indicator, and all interactive infrastructure. **Write content fragments by default. ** Only write full documents when you need complete control over the page.
## Starting a Session
```bash
# Start server with persistence (mockups saved to project)
2026-05-23 17:01:46 -07:00
scripts/start-server.sh --project-dir /path/to/project
2026-03-06 12:55:29 -08:00
# Returns: {"type":"server-started","port":52341,"url":"http://localhost:52341",
2026-03-24 11:07:59 -07:00
# "screen_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000/content",
# "state_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000/state"}
2026-03-06 12:55:29 -08:00
```
2026-03-24 11:07:59 -07:00
Save `screen_dir` and `state_dir` from the response. Tell user to open the URL.
2026-03-06 12:55:29 -08:00
2026-03-24 11:07:59 -07:00
**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.
2026-03-09 20:46:34 -07:00
2026-03-06 12:55:29 -08:00
**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.
2026-03-09 20:29:15 -07:00
**Launching the server by platform:**
2026-03-06 12:55:29 -08:00
Phase D: cross-runtime tweaks (visual-companion, executing-plans, test)
Misc platform/runtime statements and adjacencies that don't fit the
prose, config-ref, README-ordering, or tool-vocabulary buckets:
- visual-companion frame template: rename CSS/HTML id #claude-content
→ #frame-content. The id is purely styling — nothing external
references it. The brainstorm-server test that asserted the old
string is updated in lockstep.
- visual-companion launch instructions: add a Copilot CLI section
alongside Claude Code, Codex, and Gemini CLI; combine the Claude
Code (macOS / Linux) and (Windows) sections so heading style
matches the other (non-OS-qualified) platforms.
- visual-companion: "Use Write tool" → "Use your file-creation tool"
for the cat/heredoc warning. The prohibition is what's load-
bearing, not the tool name.
- executing-plans/SKILL.md: list all subagent-capable runtimes
(Claude Code, Codex CLI, Codex App, Copilot CLI, Gemini CLI) and
point at the per-platform tool refs as the source of truth.
- executing-plans/SKILL.md: relative path "using-superpowers/
references/" → "../using-superpowers/references/" to resolve
correctly from the executing-plans/ directory.
No bundled spec doc here — Phase D was scope-extension work that
took place across rounds, with no standalone spec authored.
2026-05-05 18:26:01 -07:00
**Claude Code:**
2026-03-09 20:29:15 -07:00
```bash
Phase D: cross-runtime tweaks (visual-companion, executing-plans, test)
Misc platform/runtime statements and adjacencies that don't fit the
prose, config-ref, README-ordering, or tool-vocabulary buckets:
- visual-companion frame template: rename CSS/HTML id #claude-content
→ #frame-content. The id is purely styling — nothing external
references it. The brainstorm-server test that asserted the old
string is updated in lockstep.
- visual-companion launch instructions: add a Copilot CLI section
alongside Claude Code, Codex, and Gemini CLI; combine the Claude
Code (macOS / Linux) and (Windows) sections so heading style
matches the other (non-OS-qualified) platforms.
- visual-companion: "Use Write tool" → "Use your file-creation tool"
for the cat/heredoc warning. The prohibition is what's load-
bearing, not the tool name.
- executing-plans/SKILL.md: list all subagent-capable runtimes
(Claude Code, Codex CLI, Codex App, Copilot CLI, Gemini CLI) and
point at the per-platform tool refs as the source of truth.
- executing-plans/SKILL.md: relative path "using-superpowers/
references/" → "../using-superpowers/references/" to resolve
correctly from the executing-plans/ directory.
No bundled spec doc here — Phase D was scope-extension work that
took place across rounds, with no standalone spec authored.
2026-05-05 18:26:01 -07:00
# Default mode works — the script backgrounds the server itself.
2026-05-23 17:01:46 -07:00
scripts/start-server.sh --project-dir /path/to/project
2026-03-09 20:29:15 -07:00
```
Phase D: cross-runtime tweaks (visual-companion, executing-plans, test)
Misc platform/runtime statements and adjacencies that don't fit the
prose, config-ref, README-ordering, or tool-vocabulary buckets:
- visual-companion frame template: rename CSS/HTML id #claude-content
→ #frame-content. The id is purely styling — nothing external
references it. The brainstorm-server test that asserted the old
string is updated in lockstep.
- visual-companion launch instructions: add a Copilot CLI section
alongside Claude Code, Codex, and Gemini CLI; combine the Claude
Code (macOS / Linux) and (Windows) sections so heading style
matches the other (non-OS-qualified) platforms.
- visual-companion: "Use Write tool" → "Use your file-creation tool"
for the cat/heredoc warning. The prohibition is what's load-
bearing, not the tool name.
- executing-plans/SKILL.md: list all subagent-capable runtimes
(Claude Code, Codex CLI, Codex App, Copilot CLI, Gemini CLI) and
point at the per-platform tool refs as the source of truth.
- executing-plans/SKILL.md: relative path "using-superpowers/
references/" → "../using-superpowers/references/" to resolve
correctly from the executing-plans/ directory.
No bundled spec doc here — Phase D was scope-extension work that
took place across rounds, with no standalone spec authored.
2026-05-05 18:26:01 -07:00
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.
2026-03-06 12:55:29 -08:00
2026-03-17 04:09:36 +00:00
**Codex:**
2026-03-15 18:24:23 +00:00
```bash
2026-03-17 04:09:36 +00:00
# Codex reaps background processes. The script auto-detects CODEX_CI and
# switches to foreground mode. Run it normally — no extra flags needed.
2026-05-23 17:01:46 -07:00
scripts/start-server.sh --project-dir /path/to/project
2026-03-15 18:24:23 +00:00
```
2026-03-09 20:29:15 -07:00
**Gemini CLI:**
2026-03-06 12:55:29 -08:00
```bash
2026-03-09 20:29:15 -07:00
# Use --foreground and set is_background: true on your shell tool call
# so the process survives across turns
2026-05-23 17:01:46 -07:00
scripts/start-server.sh --project-dir /path/to/project --foreground
2026-03-06 12:55:29 -08:00
```
Phase D: cross-runtime tweaks (visual-companion, executing-plans, test)
Misc platform/runtime statements and adjacencies that don't fit the
prose, config-ref, README-ordering, or tool-vocabulary buckets:
- visual-companion frame template: rename CSS/HTML id #claude-content
→ #frame-content. The id is purely styling — nothing external
references it. The brainstorm-server test that asserted the old
string is updated in lockstep.
- visual-companion launch instructions: add a Copilot CLI section
alongside Claude Code, Codex, and Gemini CLI; combine the Claude
Code (macOS / Linux) and (Windows) sections so heading style
matches the other (non-OS-qualified) platforms.
- visual-companion: "Use Write tool" → "Use your file-creation tool"
for the cat/heredoc warning. The prohibition is what's load-
bearing, not the tool name.
- executing-plans/SKILL.md: list all subagent-capable runtimes
(Claude Code, Codex CLI, Codex App, Copilot CLI, Gemini CLI) and
point at the per-platform tool refs as the source of truth.
- executing-plans/SKILL.md: relative path "using-superpowers/
references/" → "../using-superpowers/references/" to resolve
correctly from the executing-plans/ directory.
No bundled spec doc here — Phase D was scope-extension work that
took place across rounds, with no standalone spec authored.
2026-05-05 18:26:01 -07:00
**Copilot CLI:**
```bash
# 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.
2026-05-23 17:01:46 -07:00
scripts/start-server.sh --project-dir /path/to/project --foreground
Phase D: cross-runtime tweaks (visual-companion, executing-plans, test)
Misc platform/runtime statements and adjacencies that don't fit the
prose, config-ref, README-ordering, or tool-vocabulary buckets:
- visual-companion frame template: rename CSS/HTML id #claude-content
→ #frame-content. The id is purely styling — nothing external
references it. The brainstorm-server test that asserted the old
string is updated in lockstep.
- visual-companion launch instructions: add a Copilot CLI section
alongside Claude Code, Codex, and Gemini CLI; combine the Claude
Code (macOS / Linux) and (Windows) sections so heading style
matches the other (non-OS-qualified) platforms.
- visual-companion: "Use Write tool" → "Use your file-creation tool"
for the cat/heredoc warning. The prohibition is what's load-
bearing, not the tool name.
- executing-plans/SKILL.md: list all subagent-capable runtimes
(Claude Code, Codex CLI, Codex App, Copilot CLI, Gemini CLI) and
point at the per-platform tool refs as the source of truth.
- executing-plans/SKILL.md: relative path "using-superpowers/
references/" → "../using-superpowers/references/" to resolve
correctly from the executing-plans/ directory.
No bundled spec doc here — Phase D was scope-extension work that
took place across rounds, with no standalone spec authored.
2026-05-05 18:26:01 -07:00
```
2026-03-09 20:29:15 -07:00
**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.
2026-03-06 12:55:29 -08:00
If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host:
```bash
2026-05-23 17:01:46 -07:00
scripts/start-server.sh \
2026-03-06 12:55:29 -08:00
--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.
## The Loop
2026-03-11 18:32:09 -07:00
1. **Check server is alive ** , then **write HTML ** to a new file in `screen_dir` :
2026-03-24 11:07:59 -07:00
- Before each write, check that `$STATE_DIR/server-info` exists. If it doesn't (or `$STATE_DIR/server-stopped` exists), the server has shut down — restart it with `start-server.sh` before continuing. The server auto-exits after 30 minutes of inactivity.
2026-03-06 12:55:29 -08:00
- Use semantic filenames: `platform.html` , `visual-style.html` , `layout.html`
- **Never reuse filenames** — each screen gets a fresh file
Phase D: cross-runtime tweaks (visual-companion, executing-plans, test)
Misc platform/runtime statements and adjacencies that don't fit the
prose, config-ref, README-ordering, or tool-vocabulary buckets:
- visual-companion frame template: rename CSS/HTML id #claude-content
→ #frame-content. The id is purely styling — nothing external
references it. The brainstorm-server test that asserted the old
string is updated in lockstep.
- visual-companion launch instructions: add a Copilot CLI section
alongside Claude Code, Codex, and Gemini CLI; combine the Claude
Code (macOS / Linux) and (Windows) sections so heading style
matches the other (non-OS-qualified) platforms.
- visual-companion: "Use Write tool" → "Use your file-creation tool"
for the cat/heredoc warning. The prohibition is what's load-
bearing, not the tool name.
- executing-plans/SKILL.md: list all subagent-capable runtimes
(Claude Code, Codex CLI, Codex App, Copilot CLI, Gemini CLI) and
point at the per-platform tool refs as the source of truth.
- executing-plans/SKILL.md: relative path "using-superpowers/
references/" → "../using-superpowers/references/" to resolve
correctly from the executing-plans/ directory.
No bundled spec doc here — Phase D was scope-extension work that
took place across rounds, with no standalone spec authored.
2026-05-05 18:26:01 -07:00
- Use your file-creation tool — **never use cat/heredoc ** (dumps noise into terminal)
2026-03-06 12:55:29 -08:00
- Server automatically serves the newest file
2. **Tell user what to expect and end your turn: **
- Remind them of the URL (every step, not just first)
2026-05-08 15:52:38 -07:00
- Give a brief text summary of what's on screen (e.g., "Showing an interactive meal-planning mockup with tabs and an editable grocery list")
- Ask them to respond in the terminal: "Take a look, try the mockup, and tell me what feels right or wrong."
- If the screen is a deliberate A/B/C choice, also say: "Click an option if you'd like; your terminal feedback is still the source of truth."
2026-03-06 12:55:29 -08:00
3. **On your next turn ** — after the user responds in the terminal:
2026-03-24 11:07:59 -07:00
- Read `$STATE_DIR/events` if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines
2026-03-06 12:55:29 -08:00
- Merge with the user's terminal text to get the full picture
2026-03-24 11:07:59 -07:00
- The terminal message is the primary feedback; `state_dir/events` provides structured interaction data
2026-03-06 12:55:29 -08:00
4. **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.
5. **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:
```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>
```
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.
6. Repeat until done.
## Writing Content Fragments
Write just the content that goes inside the page. The server wraps it in the frame template automatically (header, theme CSS, selection indicator, and all interactive infrastructure).
2026-05-08 15:52:38 -07:00
## Interactive Mockups With Alpine
Frame-wrapped fragments automatically load Alpine.js. Use Alpine when visible interaction is central to the design question: tabs, toggles, accordions, modal open/close, wizard next/back, lightweight form validation, or simple add/remove list behavior.
Keep it illustrative. Do not build a fake application just because realistic chrome includes many controls. If an interaction is not part of the question, render that area as passive content.
```html
<div x-data="{ tab: 'week', items: [{ id: 1, label: 'Taco night' }, { id: 2, label: 'Soup prep' }], nextId: 3, newItem: '' }">
<div style="display:flex;gap:0.5rem;margin-bottom:1rem">
<button class="mock-button" @click ="tab = 'week'">Week</button>
<button class="mock-button" @click ="tab = 'list'">Grocery list</button>
</div>
<section x-show="tab === 'week'">
<h3>Week plan</h3>
<p class="subtitle">Three realistic meals are enough for the mockup.</p>
</section>
<section x-show="tab === 'list'">
<h3>Grocery list</h3>
<ul>
<template x-for="item in items" :key="item.id">
<li x-text="item.label"></li>
</template>
</ul>
<input class="mock-input" x-model="newItem" placeholder="Add item">
<button class="mock-button" @click ="if (newItem.trim()) { items.push({ id: nextId++, label: newItem.trim() }); newItem = '' }">Add</button>
</section>
</div>
```
Rules:
- Write content fragments by default; do not add an Alpine `<script>` tag.
- Generate 2-5 compact, realistic records for the user's domain. Put records in `x-data` only when interaction needs state.
- Use stable ids for repeatable records; do not key dynamic lists by user-entered labels.
- Keep terminal feedback primary. Alpine interactions are for understanding, not telemetry.
- Use `data-choice` only for deliberate named options the agent should read next turn.
- Use `@click.stop` or separate controls when an Alpine control is near a `[data-choice]` surface.
- Do not call `fetch` , simulate backend writes, or use `localStorage` / `sessionStorage` .
- Do not load live network images. Use local `/files/<basename>` assets when the project provides them, or use a simple local placeholder.
2026-03-06 12:55:29 -08:00
**Minimal example:**
```html
<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.
## CSS Classes Available
The frame template provides these CSS classes for your content:
2026-05-08 15:52:38 -07:00
### Deliberate Options (A/B/C choices)
Use these only when you want a structured choice event. Do not wrap ordinary Alpine controls in `[data-choice]` .
2026-03-06 12:55:29 -08:00
```html
<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. The indicator bar shows the count.
```html
<div class="options" data-multiselect>
<!-- same option markup — users can select/deselect multiple -->
</div>
```
2026-05-08 15:52:38 -07:00
### Deliberate Cards (visual design choices)
Use `[data-choice]` cards for visual alternatives, not for normal clickable app UI.
2026-03-06 12:55:29 -08:00
```html
<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
```html
<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)
```html
<div class="split">
<div class="mockup"><!-- left --></div>
<div class="mockup"><!-- right --></div>
</div>
```
### Pros/Cons
```html
<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)
```html
<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
## Browser Events Format
2026-05-08 15:52:38 -07:00
When the user clicks deliberate `[data-choice]` options in the browser, those selections are recorded to `$STATE_DIR/events` (one JSON object per line). Ordinary Alpine interactions such as tabs, toggles, forms, and modals are not recorded. The file is cleared automatically when you push a new screen, so each screen starts with a clean event log. The terminal message remains the primary feedback.
2026-03-06 12:55:29 -08:00
```jsonl
{"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.
2026-03-24 11:07:59 -07:00
If `$STATE_DIR/events` doesn't exist, the user didn't interact with the browser — use only their terminal text.
2026-03-06 12:55:29 -08:00
## 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
2026-05-08 15:52:38 -07:00
- **Use local assets when images matter** — if the project has relevant images, reference them through `/files/<basename>` . Do not pull images from remote URLs just to make a mockup feel polished.
2026-03-06 12:55:29 -08:00
- **Keep mockups simple** — focus on layout and structure, not pixel-perfect design
## 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
## Cleaning Up
```bash
2026-05-23 17:01:46 -07:00
scripts/stop-server.sh $SESSION_DIR
2026-03-06 12:55:29 -08:00
```
If the session used `--project-dir` , mockup files persist in `.superpowers/brainstorm/` for later reference. Only `/tmp` sessions get deleted on stop.
## Reference
2026-05-23 17:01:46 -07:00
- Frame template (CSS reference): `scripts/frame-template.html`
- Helper script (client-side): `scripts/helper.js`