visual-explainer
The 9.5K-star skill that stops your agent from dumping ASCII tables in the terminal, tested down to its MCP handshake and md5 determinism.
This is one of the best engineered single-purpose skills GearScope has tested: a zero-dependency renderer, a hardened local MCP server, a 360-line changelog, and design guidance that bans its own genre's cliches. Two real defects surfaced (a silent no-op when the renderer runs from a /tmp path on macOS, and a stale 0.9.0 version inside the plugin manifest), and there is no test suite or CI to catch either. Install it if your agent ever hands you a 15-row table in the terminal.
$/plugin marketplace add nicobailon/visual-explainer && /plugin install visual-explainer@visual-explainer-marketplace
$npm install -g visual-explainer
$pi install git:github.com/nicobailon/visual-explainer
install if
- Developers whose agents dump wide tables, diffs, or architecture sketches into the terminal. The 4-row/3-column auto-trigger plus seven review commands targets exactly this daily annoyance, and the output is a portable HTML file you can attach to a ticket.
- Pi users. The 413-line extension registers a native tool with prepare/render/render_quick actions; this is the most first-class integration in the repo.
- MCP-host users who want render tools without a daemon. The stdio server is local-only, needs no API key, writes nowhere but
~/.agent/diagrams/, and exposes the skill content itself as read-only resources.
skip if
- Terminal-only or headless-SSH users. The deliverable is a browser page; with no browser in the loop you gain nothing over native agent output.
- Anyone who needs pixel-perfect PowerPoint files. The PPTX exporter is honest about being a lossy static handoff (no animations, no live Mermaid, no custom fonts); if PPTX is the goal rather than a bonus, use a deck-native tool.
- Teams wanting CI-validated diagram artifacts. archify's schema-validated JSON IR with SHA-256 receipts is the better fit when diagrams must be checked by a pipeline rather than read by humans.
What It Does
visual-explainer is an agent skill by nicobailon (9,525 stars, MIT, created 2026-02-16, pushed the morning of this review) that makes coding agents stop drawing box-art in your terminal. When you ask for a diagram, a diff review, a plan audit, a data table, or a project recap, the agent writes a complete self-contained HTML page to ~/.agent/diagrams/ and opens it in your browser. The repo ships that skill in five forms: a Claude Code marketplace plugin (7 slash commands), a Pi package with a native visual_explainer tool, a local stdio MCP server with 3 tools, a zero-dependency quick-mode JSON renderer, and a best-effort PPTX exporter, plus copy-in guidance configs for Codex, Antigravity, OpenCode, Cursor, OpenClaw, and Copilot. The target user is anyone whose agent answers "compare these 15 requirements against the plan" with a wall of pipes and dashes.
The Good
The quick-mode renderer is zero-dependency, deterministic, and hostile to injection. quick/render.mjs (209 lines, pure Node stdlib) validates a compact JSON spec and renders complete HTML. It ran on a fresh clone with no npm install, produced byte-identical output across two runs (md5 7c173c8a1648f0405fb80aa0015ff676), escaped every injected payload we fed it ( in a title came out as <script>alert(1)</script>, an card title was fully escaped), and rejected all four negative specs we crafted with errors that name the exact field: spec.sections[0].bogusKey is not supported, table rows that must match the column count, invalid tone enums, and flow edges that must reference a flow node.
The MCP server is hardened beyond what most hobby skills ship. mcp/server.mjs (405 lines) rejects filenames containing path separators or .., refuses to write if ~/.agent/diagrams/ or the target file is a symlink, validates that submitted HTML is a complete document (rejecting fragments with a named error), and injects a favicon, lang, and viewport metadata into documents missing them, all verified in our tool calls. The initialize handshake returned serverInfo visual-explainer 0.10.0, tools/list returned exactly the 3 documented tools, prompts/list returned the 7 bundled commands, and resources/list returned 10 read-only resources exposing the SKILL.md and quick schema to the host model.
The documentation discipline is top-tier for a single-maintainer project. The changelog runs 360 lines across 20+ dated releases back to v0.1.0, each crediting the issue or PR that motivated it (@romkazor in #83, @luketych in #33, @mikeyobrien in #12, and a dozen more). Version 0.10.0 is synchronized across package.json, marketplace.json, SKILL.md metadata, the npm registry, and the git tag. The SKILL.md itself is a 146-line design contract with a reference routing table (all 13 routed targets exist on disk) and an anti-slop section that bans specific hexes (#8b5cf6, #7c3aed, #a78bfa, #d946ef) and Inter-as-primary-font; we grepped the shipped templates and found zero violations of its own rules.
The Bad
The quick renderer silently no-ops when invoked through a /tmp path on macOS. render.mjs decides it is the main module by comparing import.meta.url to a non-canonicalized pathToFileURL(process.argv[1]). Because /tmp is a symlink to /private/tmp, running node /tmp/.../render.mjs spec.json out.html exits 0 and writes nothing, with no error on stdout or stderr. We reproduced this directly: an alias-path invocation given a nonexistent spec file still exited 0 (main never ran), while the canonical /private/tmp path rendered correctly. The failure mode is the problem, not the frequency: an agent that hits it gets a success exit code and no page. The README's own install snippets clone into /tmp. Notably, mcp/server.mjs and pptx/export.mjs both use realpathSync in their main-module guards and are immune; the renderer is the odd one out.
Version drift survived the release that claimed to fix version drift. The v0.10.0 changelog's headline fix is "Synchronized Claude Code marketplace and skill metadata versions after the mismatch reported by @romkazor in #83." The marketplace.json (both spots), package.json, SKILL.md, npm, and the git tag all read 0.10.0, but the inner manifest at plugins/visual-explainer/.claude-plugin/plugin.json still reads 0.9.0. It is a cosmetic gap in a repo whose brand is metadata hygiene, and our structural run failed on exactly this check.
No test suite, no CI, and a 142 MB peer-dependency surprise. There is no .github/ directory and no test files anywhere in the tree, which is why the /tmp bug and the manifest drift had nothing catching them. On the dependency side, npm install (npm 11 auto-installs peers) pulled @earendil-works/pi-coding-agent@0.84.2 into node_modules: 142 MB of the 167 MB total, installed for users who only want the MCP server or PPTX exporter and will never run Pi. A --legacy-peer-deps note in the MCP README would fix the surprise. Minor gaps on top: Hermes is not among the seven documented harness targets (the standard frontmatter means a manual copy into .hermes/skills/ works, undocumented), the repo sets no GitHub topics, and skills.sh shows only 439 installs, so demand lives almost entirely in the Claude marketplace and npm.
Smoke Test Results
Hands-on host testing on macOS 26.5.2 aarch64, Node v24.13.1, npm 11.8.0. The sandbox runner (sbx) was not authenticated, so the three scripts run on the host against fresh clones, with full logs at the paths below. Script totals: Run A 38/38, Run B 24/24, Run C 23/24 (the single failure is the version-drift finding in The Bad).
Run A. Fresh clone, no npm deps preinstalled
$ git clone --depth 1 https://github.com/nicobailon/visual-explainer
β
3.0 MB clone, tag v0.10.0, HEAD dated 2026-08-19
$ node plugins/visual-explainer/quick/render.mjs spec-ok.json out-1.html
β
exit 0 with zero npm deps; complete doctype document with embedded CSS, flow nodes, severity-tagged risks, table
$ node plugins/visual-explainer/quick/render.mjs spec-ok.json out-2.html && md5 out-1.html out-2.html
β
byte-identical renders (7c173c8a1648f0405fb80aa0015ff676)
$ node quick/render.mjs spec-xss.json out-xss.html # title: <script>alert(1)</script>
β
escaped as <script>alert(1)</script>; no raw injected tag anywhere in output
$ node quick/render.mjs spec-neg1.json neg1.html # unknown section key
β
rejected: "spec.sections[0].bogusKey is not supported"
$ node quick/render.mjs spec-neg2.json neg2.html # row shorter than columns
β
rejected: "must match the column count"
$ node quick/render.mjs spec-neg3.json neg3.html # tone: "sparkly"
β
rejected: "must be neutral, accent, positive, warning, danger, or info"
$ node quick/render.mjs spec-neg4.json neg4.html # edge points at missing node
β
rejected: "must reference a flow node"
$ node /tmp/.../quick/render.mjs spec-ok.json out.html # macOS /tmp alias path
β
bug reproduced: exit 0, no file written (non-canonical main-module guard)
$ node mcp/server.mjs
β
fails cleanly: Cannot find package '@modelcontextprotocol/server' (README documents npm install first)
Pass rate: 10 of 10. The zero-dependency renderer works from a bare clone and every negative case is rejected with a field-specific error. The /tmp line passes by reproducing the documented bug (see The Bad).
Run B. With deps preinstalled (npm install)
$ npm install --no-package-lock
β
exit 0 in 6s; resolves @modelcontextprotocol/server@2.0.0, zod@4.4.3, node-html-parser@9.0.1, pptxgenjs@4.0.1 (+ peer pi-coding-agent@0.84.2)
$ python3 mcp-stdio-client.py node mcp/server.mjs --env HOME=/tmp/ve-mcp-home
β
initialize: serverInfo {"name": "visual-explainer", "version": "0.10.0"}; tools 3, prompts 7, resources 10
$ --call visual_explainer_prepare --args '{"topic":"auth flow"}'
β
isError false; returns a 5-step recommendedFlow; writes nothing
$ --call visual_explainer_render_quick --args '{"filename":"ve-smoke-auth-flow","spec":{...steps+evidence...}}'
β
isError false; HTML written to isolated ~/.agent/diagrams/ with correct title and step markup
$ render_quick same spec, second filename; md5 both files
β
byte-identical MCP renders (24eedb7d14f967bc07f820e71731981b)
$ --call visual_explainer_render_quick --args '{"filename":"neg-badkey","spec":{"sections":[{"nope":1}]}}'
β
isError true, names the bad key ("is not supported")
$ --call visual_explainer_render_html --args '{"filename":"../escape-attempt","html":"<!doctype html>..."}'
β
isError true ("filename must be a basename"); confirmed no file written outside ~/.agent/diagrams
$ --call visual_explainer_render_html --args '{"filename":"fragment","html":"<p>not a document</p>"}'
β
isError true ("complete HTML document" contract enforced); a valid doc passes and gains favicon + lang
$ node pptx/export.mjs deck.html deck.pptx
β
exit 0; 75,655-byte valid ZIP container (PK magic) from a 3-slide deck
Pass rate: 9 of 9. Every documented tool contract held under both valid and hostile input, and output is deterministic through the MCP path as well as the CLI path.
Run C. Structural validation (self-consistency)
$ head -10 SKILL.md | grep -E '^(name|description|license):'
β
name, 256-char description, MIT license, metadata.version 0.10.0 all declared
$ compare versions: package.json, marketplace.json x2, plugin.json, SKILL.md, npm view, git tag
β plugin.json reads 0.9.0; the other six surfaces read 0.10.0
$ for f in commands/*.md; do check name+description frontmatter; done
β
7 of 7 command templates carry full frontmatter
$ test -f each of the 13 SKILL.md reference-routing targets
β
all 13 exist (5 references, 4 templates, quick/README, quick/schema, base.css, pptx/export.mjs)
$ grep banned hexes and Inter-primary stacks across templates/
β
zero violations of the skill's own anti-slop rules
$ ls configs/ | wc -l
β
7 platform config dirs (pi, opencode, openclaw, cursor, copilot, codex, antigravity)
Pass rate: 5 of 6. The one failure is the real version-drift finding reported in The Bad; the skill's content is otherwise self-consistent to an unusual degree.
What the runs tell you
The executable surfaces do what the README claims, on a bare clone and after install, under valid and hostile input alike, and the deterministic renderer is safe to point at untrusted model output. The two defects that surfaced (the /tmp silent no-op and the stale inner plugin.json) are edge-case and cosmetic respectively, but both are the kind of drift a test suite would have caught on day one.
Setup Walkthrough
- Claude Code: run
/plugin marketplace add nicobailon/visual-explainer, then/plugin install visual-explainer@visual-explainer-marketplace. Commands arrive namespaced as/visual-explainer:diff-reviewand friends. This is the lowest-friction path. - MCP hosts (checkout path):
git clone --depth 1, thennpm install --no-package-lockinside it (6 seconds, 167 MB with the auto-installed Pi peer; add--legacy-peer-depsif you never use Pi), then point your host atnode /abs/path/plugins/visual-explainer/mcp/server.mjs. - Pi:
pi install git:github.com/nicobailon/visual-explainerregisters the nativevisual_explainertool, the skill, and all 7 prompts in one step. If you used the old curl installer, remove the copied files first or Pi reports shadowing conflicts. - Codex, Antigravity, OpenCode: copy
plugins/visual-explainer/into the platform's skills directory per the README snippets. On macOS, avoid keeping the working clone under/tmpif you plan to invokequick/render.mjsdirectly; use a canonical path (the bug above). - Try
> draw a diagram of our authentication flowor/diff-review --quick main..HEAD. Output lands in~/.agent/diagrams/and opens in your browser.
Alternatives
- tt-a1i/archify - validated, self-contained HTML diagrams from a typed JSON IR with CI-checkable receipts. Prefer it when diagrams are build artifacts; prefer visual-explainer when the goal is readable explanations of reviews, plans, and recaps.
- anthropics/skills (frontend-design) - the design-judgment ancestor this skill credits. Lighter (no commands, renderers, or MCP), but also no quick mode, no diff/plan-review workflows, and no output tooling.
- pbakaus/impeccable - solves the adjacent problem: detecting and fixing AI-slop in HTML you already have. The two pair well; impeccable polishes pages visual-explainer generates.
Reviews stay honest because nobody pays us to publish them. If this one saved you time, throw a coin.
Tip the reviewer- reviewed by
- GearScope
- tested
- 2026-08-20 · macOS (Apple Silicon)
- last verified
- 2026-08-20
- depth
- HANDS-ON
- sponsorship
- none, ever
Don't install your next skill blind.
Every week: the shortlist of skills worth installing β and the ones to skip β from 100+ hands-on tests. No spam, no affiliate links.