Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge)](LICENSE)

Ask your agent to explain a system architecture, review a diff, or compare requirements against a plan. Instead of ASCII art and box-drawing tables, it generates a self-contained HTML page and opens it in your browser.
Ask your agent to explain a system architecture, review a diff, or compare requirements against a plan. Instead of ASCII art and box-drawing tables, it generates a self-contained HTML page and opens it with Pi's Glimpse native UI when available, falling back to your browser.

```
> draw a diagram of our authentication flow
Expand Down Expand Up @@ -168,13 +168,13 @@ plugins/
└── share.sh ← deploy HTML to Vercel for sharing
```

**Output:** `~/.agent/diagrams/filename.html` → opens in browser
**Output:** `~/.agent/diagrams/filename.html` → opens with Glimpse when available, browser fallback

The skill routes to the right approach automatically: Mermaid for flowcharts and diagrams, CSS Grid for architecture overviews, HTML tables for data, Chart.js for dashboards.

## Limitations

- Generated HTML is portable and self-contained, but auto-opening depends on the harness, browser access, and sandbox rules.
- Generated HTML is portable and self-contained. In Pi, `scripts/open.sh` uses Glimpse when available and falls back to the system browser; other harnesses still depend on browser access and sandbox rules.
- All harnesses write visual output to `~/.agent/diagrams/` unless the user asks for a different path.
- Switching OS theme requires a page refresh for Mermaid SVGs.
- `/share-page` uses `plugins/visual-explainer/scripts/share.sh`, which expects a Pi-compatible `vercel-deploy` skill in a standard Pi skill location. Other harnesses can still generate and open pages, but sharing may need that dependency installed separately.
Expand Down
2 changes: 1 addition & 1 deletion configs/pi/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ For Pi, prefer `pi install git:github.com/nicobailon/visual-explainer` or instal

Do not keep the old manual installer copies alongside a package install. If you previously used `install-pi.sh`, remove `~/.pi/agent/skills/visual-explainer` and the copied `~/.pi/agent/prompts/{diff-review,fact-check,generate-slides,generate-visual-plan,generate-web-diagram,plan-review,project-recap,share-page}.md` files before relying on the package.

Activate with `$visual-explainer` or slash commands such as `/diff-review`, `/plan-review`, `/generate-web-diagram`, `/generate-slides`, and `/share-page` after restarting Pi. Generated pages go to `~/.agent/diagrams/` and should be opened in a browser when possible.
Activate with `$visual-explainer` or slash commands such as `/diff-review`, `/plan-review`, `/generate-web-diagram`, `/generate-slides`, and `/share-page` after restarting Pi. Generated pages go to `~/.agent/diagrams/` and should be opened with `scripts/open.sh`, which uses Pi's Glimpse native UI when available and falls back to the system browser.

Command templates are convenience prompts; the skill itself is the source of behavior. `/share-page` requires a Pi-compatible `vercel-deploy` skill, normally installed with `pi install npm:vercel-deploy`.
13 changes: 8 additions & 5 deletions plugins/visual-explainer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
name: visual-explainer
description: Generate beautiful, self-contained HTML pages that visually explain systems, code changes, plans, and data. Use when the user asks for a diagram, architecture overview, diff review, plan review, project recap, comparison table, or any visual explanation of technical concepts. Also use proactively when you are about to render a complex ASCII table (4+ rows or 3+ columns) — present it as a styled HTML page instead.
license: MIT
compatibility: Requires a browser to view generated HTML files. Optional surf-cli for AI image generation.
compatibility: Uses Pi's Glimpse native UI when available; falls back to opening generated HTML files in the browser. Optional surf-cli for AI image generation.
metadata:
author: nicobailon
version: "0.6.3"
---

# Visual Explainer

Generate self-contained HTML files for technical diagrams, visualizations, and data tables. Always open the result in the browser. Never fall back to ASCII art when this skill is loaded.
Generate self-contained HTML files for technical diagrams, visualizations, and data tables. Always open the result with the provided opener: it uses Pi's Glimpse native UI when available and falls back to the system browser. Never fall back to ASCII art when this skill is loaded.

**Proactive table rendering.** When you're about to present tabular data as an ASCII box-drawing table in the terminal (comparisons, audits, feature matrices, status reports, any structured rows/columns), generate an HTML page instead. The threshold: if the table has 4+ rows or 3+ columns, it belongs in the browser. Don't wait for the user to ask — render it as HTML automatically and tell them the file path. You can still include a brief text summary in the chat, but the table itself should be the HTML page.

Expand Down Expand Up @@ -193,9 +193,12 @@ Keep animations purposeful: entrance reveals, hover feedback, and user-initiated

**Output location:** Write to `~/.agent/diagrams/`. Use a descriptive filename based on content: `modem-architecture.html`, `pipeline-flow.html`, `schema-overview.html`. The directory persists across sessions.

**Open in browser:**
- macOS: `open ~/.agent/diagrams/filename.html`
- Linux: `xdg-open ~/.agent/diagrams/filename.html`
**Open with Glimpse when available, browser otherwise:**
```bash
./plugins/visual-explainer/scripts/open.sh ~/.agent/diagrams/filename.html
```

If the skill is installed elsewhere, run `scripts/open.sh` from that installed skill directory. The opener detects Pi's Glimpse native UI from common Pi/package locations and uses it when present. If Glimpse is not available or fails to start, it falls back to the system browser (`open`, `xdg-open`, or `start`).

**Tell the user** the file path so they can re-open or share it.

Expand Down
2 changes: 1 addition & 1 deletion plugins/visual-explainer/commands/diff-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Verify each claim against the code. If something cannot be verified, mark it as

**Optional illustrations** — if `surf` CLI is available (`which surf`), consider generating a hero banner or conceptual illustration via `surf gemini --generate-image` when it would enhance the page. Embed as base64 data URI. See css-patterns.md "Generated Images" for container styles. Skip if surf isn't available or the diff is purely structural.

Include responsive section navigation. Use diff-style visual language throughout: red for removed/before, green for added/after, yellow for modified, blue for neutral context. Write to `~/.agent/diagrams/` and open in browser.
Include responsive section navigation. Use diff-style visual language throughout: red for removed/before, green for added/after, yellow for modified, blue for neutral context. Write to `~/.agent/diagrams/` and open with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise.

Ultrathink.

Expand Down
2 changes: 1 addition & 1 deletion plugins/visual-explainer/commands/fact-check.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Include in the summary:
- Corrections made (with brief list of what was fixed: "Changed `processCleanup` to `runCleanup` to match actual function name in `worker.ts:45`")
- Unverifiable claims flagged (if any)

**Phase 5: Report.** Tell the user what was checked, what was corrected, and open the file (HTML in browser, markdown path in chat). If nothing needed correction, say so — the verification still has value as confirmation.
**Phase 5: Report.** Tell the user what was checked, what was corrected, and open the file (HTML via `scripts/open.sh` with Glimpse/browser fallback, markdown path in chat). If nothing needed correction, say so — the verification still has value as confirmation.

This is not a re-review. It does not second-guess analysis, opinions, or design judgments. It does not change the document's structure or organization. It is a fact-checker — it verifies that the data presented matches reality, corrects what doesn't, and leaves everything else alone.

Expand Down
2 changes: 1 addition & 1 deletion plugins/visual-explainer/commands/generate-slides.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ Follow the visual-explainer skill workflow. Read the reference template at `./te

**Compositional variety:** Consecutive slides must vary their spatial approach. Alternate between centered, left-heavy, right-heavy, split, edge-aligned, and full-bleed. Three centered slides in a row means push one off-axis.

Write to `~/.agent/diagrams/` and open the result in the browser.
Write to `~/.agent/diagrams/` and open the result with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise.
2 changes: 1 addition & 1 deletion plugins/visual-explainer/commands/generate-visual-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,6 @@ Verify each against the code. If something cannot be verified, mark it as uncert
- Never use `display: flex` on `<li>` for markers — use absolute positioning
- Test tables with wide content don't overflow their container

Write to `~/.agent/diagrams/` with a descriptive filename (e.g., `feature-name-plan.html`). Open the result in the browser. Tell the user the file path.
Write to `~/.agent/diagrams/` with a descriptive filename (e.g., `feature-name-plan.html`). Open the result with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise. Tell the user the file path.

Ultrathink.
4 changes: 2 additions & 2 deletions plugins/visual-explainer/commands/generate-web-diagram.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
description: Generate a beautiful standalone HTML diagram and open it in the browser
description: Generate a beautiful standalone HTML diagram and open it with Glimpse when available, browser fallback
---
Load the visual-explainer skill, then generate an HTML diagram for: $@

Follow the visual-explainer skill workflow. Read the reference template and CSS patterns before generating. Pick a distinctive aesthetic that fits the content — vary fonts, palette, and layout style from previous diagrams.

If `surf` CLI is available (`which surf`), consider generating an AI illustration via `surf gemini --generate-image` when an image would genuinely enhance the page — a hero banner, conceptual illustration, or educational diagram that Mermaid can't express. Match the image style to the page's palette. Embed as base64 data URI. See css-patterns.md "Generated Images" for container styles. Skip images when the topic is purely structural or data-driven.

Write to `~/.agent/diagrams/` and open the result in the browser.
Write to `~/.agent/diagrams/` and open the result with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise.
2 changes: 1 addition & 1 deletion plugins/visual-explainer/commands/plan-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Verify each claim against the code and the plan. If something cannot be verified

**Optional illustrations** — if `surf` CLI is available (`which surf`), consider generating a conceptual illustration of the planned system via `surf gemini --generate-image` when it would help the reader visualize the change. Embed as base64 data URI. See css-patterns.md "Generated Images" for container styles. Skip if surf isn't available or the plan is purely structural.

Include responsive section navigation. Use a current-vs-planned visual language throughout: blue/neutral for current state, green/purple for planned additions, amber for areas of concern, red for gaps or risks. Write to `~/.agent/diagrams/` and open in browser.
Include responsive section navigation. Use a current-vs-planned visual language throughout: blue/neutral for current state, green/purple for planned additions, amber for areas of concern, red for gaps or risks. Write to `~/.agent/diagrams/` and open with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise.

Ultrathink.

Expand Down
2 changes: 1 addition & 1 deletion plugins/visual-explainer/commands/project-recap.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Verify each claim against the code. If something cannot be verified, mark it as
- Flag each with a severity and a concrete suggestion (e.g., "add a doc comment to `buildCoordinationInstructions` explaining the 4 coordination levels — this function is called from 3 places and the behavior is non-obvious")
8. **Next steps** — inferred from recent activity, open TODOs, project trajectory. Not prescriptive — just "here's where the momentum was pointing when you left." Include any explicit next-step notes from progress docs or plan files.

Include responsive section navigation. Use a warm, approachable visual language: muted blues and greens for architecture, amber callouts for cognitive debt hotspots, green/blue/amber/red for state-of-things status. Overflow prevention on any side-by-side or grid-based sections: apply `min-width: 0` on all grid/flex children and `overflow-wrap: break-word`. Never use `display: flex` on `<li>` for marker characters — use absolute positioning instead (see css-patterns.md Overflow Protection). Write to `~/.agent/diagrams/` and open in browser.
Include responsive section navigation. Use a warm, approachable visual language: muted blues and greens for architecture, amber callouts for cognitive debt hotspots, green/blue/amber/red for state-of-things status. Overflow prevention on any side-by-side or grid-based sections: apply `min-width: 0` on all grid/flex children and `overflow-wrap: break-word`. Never use `display: flex` on `<li>` for marker characters — use absolute positioning instead (see css-patterns.md Overflow Protection). Write to `~/.agent/diagrams/` and open with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise.

Ultrathink.

Expand Down
86 changes: 86 additions & 0 deletions plugins/visual-explainer/scripts/open-with-glimpse.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env node
import { access, readFile } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import { spawn } from 'node:child_process';
import { dirname, resolve } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);
const here = dirname(fileURLToPath(import.meta.url));

function expandHome(path) {
if (!path) return path;
return path.startsWith('~/') ? `${process.env.HOME}${path.slice(1)}` : path;
}

function browserOpen(file) {
const command = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';
const args = process.platform === 'win32' ? ['/c', 'start', '', file] : [file];
const child = spawn(command, args, { detached: true, stdio: 'ignore' });
child.unref();
}

async function firstExisting(paths) {
for (const candidate of paths) {
if (!candidate) continue;
const resolved = expandHome(candidate);
try {
await access(resolved);
return resolved;
} catch {}
}
return null;
}

async function resolveGlimpseModule() {
try {
return require.resolve('glimpseui/src/glimpse.mjs');
} catch {}

const envPath = process.env.GLIMPSE_MODULE || process.env.GLIMPSE_PATH;
const packageRoot = resolve(here, '../../../..');
return firstExisting([
envPath,
resolve(packageRoot, 'node_modules/glimpseui/src/glimpse.mjs'),
'~/.pi/agent/git/github.com/hazat/glimpse/src/glimpse.mjs',
'~/.bun/install/global/node_modules/glimpseui/src/glimpse.mjs',
'~/.bun/install/cache/glimpseui@0.8.0@@@1/src/glimpse.mjs',
]);
}

const args = process.argv.slice(2);
if (args.includes('--check')) {
process.exit((await resolveGlimpseModule()) ? 0 : 1);
}

const fileArg = args.find((arg) => !arg.startsWith('--'));
if (!fileArg) {
console.error('Usage: open-with-glimpse.mjs [--check] <html-file>');
process.exit(2);
}

const htmlFile = resolve(expandHome(fileArg));
const title = args.includes('--title') ? args[args.indexOf('--title') + 1] : `Visual Explainer — ${htmlFile.split('/').pop()}`;
const glimpseModule = await resolveGlimpseModule();

if (!glimpseModule) {
browserOpen(htmlFile);
process.exit(0);
}

try {
const { open } = await import(pathToFileURL(glimpseModule).href);
const html = await readFile(htmlFile, 'utf8');
const win = open(html, {
title,
width: 1200,
height: 850,
openLinks: true,
});
win.on('closed', () => process.exit(0));
} catch (error) {
console.error(`Glimpse failed, opening in browser instead: ${error.message}`);
browserOpen(htmlFile);
process.exit(0);
}
22 changes: 22 additions & 0 deletions plugins/visual-explainer/scripts/open.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail

if [[ $# -lt 1 ]]; then
echo "Usage: $0 <html-file>" >&2
exit 2
fi

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
HTML_FILE="$1"

if node "$SCRIPT_DIR/open-with-glimpse.mjs" --check >/dev/null 2>&1; then
node "$SCRIPT_DIR/open-with-glimpse.mjs" "$HTML_FILE" >/tmp/visual-explainer-glimpse.log 2>&1 &
disown || true
else
case "$(uname -s)" in
Darwin) open "$HTML_FILE" ;;
Linux) xdg-open "$HTML_FILE" ;;
MINGW*|MSYS*|CYGWIN*) start "" "$HTML_FILE" ;;
*) echo "No opener known for this OS. File: $HTML_FILE" >&2 ;;
esac
fi