| name | map |
| description | Builds an interactive codebase map: beautiful-mermaid architecture diagrams (flowchart/sequence/class/ER/state), a navigable snake flowchart, interleaved prose+code sidebars, and a file tree. Delivers via Cursor Canvas or a Bun React page. Invoke with /map when the user wants a codebase map, architecture explanation, onboarding brief, interactive flow chart, navigable walkthrough, "show me how X works" as a diagram/map, or a visual mental model of a feature/subsystem with clickable jumps into files. |
| license | MIT |
| compatibility | Requires Bun on PATH. Cursor Canvas host also needs Cursor canvases. |
| disable-model-invocation | true |
| metadata | {"surfaces":["ide"]} |
Map
Produce a navigable spatial map: one full-bleed pan/zoom world (Mermaid
architecture + snake flowchart), concise node teasers, clickable edges
(dependencies), a floating left sidebar with interleaved prose + code
excerpts + file backlinks, and a floating right file tree built from every
path referenced in the map.
Host selection
| Environment | Host | Deliverable |
|---|
| Cursor with canvases | Canvas (default on Cursor; IDE-only) | .canvas.tsx in project canvases dir |
| Claude / Codex / Pi / no canvases | Bun React | copy of app/ under $TMPDIR/<repo-slug>/maps/<name>/ |
Same data contracts, scripts, and quality bars for both. Do not invent chrome from scratch.
Agent runbook (read order)
Do this in order — skip steps and you will ship a broken map:
- Prereqs: Bun on
PATH. Resolve SKILL_DIR as the directory
that contains this SKILL.md.
- Canvas host: load the Cursor canvas skill before writing any
.canvas.tsx.
Do not skip.
- Contracts (mandatory reads):
- Explore via cartographer: Launch the cartographer Task subagent
(
subagent_type: cartographer) with the target subsystem/question. Do not
use ad-hoc Grep/Read as the primary exploration path when cartographer is
available. Use its returned map (symbols, files, edges, open questions, and
any candidate NODES / EDGES / paths) to distill 5–12 nodes + edges and
pick Mermaid kind(s).
- Fallback (skills-CLI-only / Pi / no plugin agents): explore with oxcode
- Parallel Search MCP if present, otherwise manual explore — then continue.
- Clone the host template (pick one):
Canvas host (Cursor)
cp "$SKILL_DIR/scaffold.canvas.tsx" \
~/.cursor/projects/<workspace>/canvases/<descriptive-name>.canvas.tsx
MAP_FILE=~/.cursor/projects/<workspace>/canvases/<descriptive-name>.canvas.tsx
scaffold.canvas.tsx is generated from app/src/Map.tsx.
Skill authors regenerate with bun "$SKILL_DIR/scripts/build-canvas-scaffold.ts".
Agents only copy the scaffold — do not edit the generator path unless changing shared UI.
Bun React host (other agents)
Cursor / Canvas does not use this path — canvases already live under
~/.cursor/projects/<workspace>/canvases/ (per workspace). Use the block
below only for Claude / Codex / Pi / no-canvases Bun hosts.
Clone the Vite app into a per-project system temp directory — never under
the target repo (maps/, node_modules, or Vite dist/ must not land in the
project). Resolve the path via map-dir.ts (git toplevel basename → slug):
MAP_DIR=$(bun "$SKILL_DIR/scripts/map-dir.ts" <descriptive-name> --init)
MAP_FILE="$MAP_DIR/src/Map.tsx"
map-dir.ts without --init only prints the path (reproducible; same repo +
name → same dir). With --init it wipes that dir and copies $SKILL_DIR/app.
ROOT in the map data still points at the real repo (for FILE_MAP); only the
host app lives in $MAP_DIR.
Then from $MAP_DIR: bun install && bun run dev → Vite on http://localhost:5173.
Before shipping a Bun map, also run host verify (from skill scripts or $MAP_DIR
— see Quality bar).
-
Replace all placeholders in MAP_FILE before delivery:
ROOT → absolute repo root
FILE_MAP → every real path/range (delete the demo src/example.ts entry)
NODES / EDGES → real walkthrough (fileRef / { type:"code", ref })
ARCH_DIAGRAMS → beautiful-mermaid SVGs + hotspots
- Title / intro copy
-
Scripts (from this skill’s scripts/):
cd "$SKILL_DIR/scripts"
bun install
bun render-mermaid.mjs --json --file diagrams.json > rendered.json
bun update.ts --file "$MAP_FILE"
bun update.ts --file "$MAP_FILE" --check
Authors regenerating chrome / before shipping a Bun map:
cd "$SKILL_DIR/scripts"
bun run verify
verify checks MapView naming (no Map shadow), SSR render, Vite worker
chunk emission, pierre DiffView wiring, and scaffold sync.
7. Optional depth (after the map shell only). The map ends the durable UI
with a comment Add more context below. Agents may insert extra sections
after that comment when they help the reader. Nothing there is required —
do not add a ritual “Gotchas” block. The full-bleed unified map (Mermaid
- snake in one camera) is the only always-on top-level section.
- Ship only if the Quality bar below passes.
Never deliver the scaffold’s placeholder nodes/paths as a finished map.
Single source of truth: all code links live in FILE_MAP. bun update.ts
rewrites FILE_CONTENTS + MAP_PATHS from that block only — never hand-edit
generated blocks, never scrape NODES for paths or the tree.
Chrome source of truth: app/src/Map.tsx
(Bun) / generated scaffold.canvas.tsx (Canvas). Grow the
map by filling data + optional ad-hoc sections; do not re-derive pan/zoom,
sidebars, tree, or preview from prose alone.
Canvas constraint: import only from cursor/canvas (+ React hooks/types)
in .canvas.tsx. Bun app: use app/src/host polyfills (already wired). Do
not npm-import @pierre/trees, @pierre/diffs, or beautiful-mermaid into
Map.tsx / .canvas.tsx — Bun highlighting + tree live in app/src/host via
@pierre/diffs / @pierre/trees (Vite).
Use SDK chrome (Card / CardHeader / CardBody, Callout, Grid /
Divider / Spacer, Link, mergeStyle) for overlays. See
canvas-pattern.md (Native cursor/canvas chrome). Keep
snake camera, Mermaid world, and resize handles custom. Do not use
computeDAGLayout for the serpentine path.
Default export in Map.tsx must be named MapView (never Map — that
shadows globalThis.Map and stack-overflows on load).
Host DiffView / tree / Mermaid package mapping:
canvas-pattern.md § External UX mapping.
Architecture diagrams (beautiful-mermaid)
Every map should open with 1–3 architecture diagrams that explain shape,
not the step-by-step walkthrough (that’s the snake map). Choose the Mermaid
kind that matches the question:
| Question | Mermaid kind | Example |
|---|
| How do stages connect? | flowchart / graph TD | provision pipeline |
| What are the containers / externals? | c4 (author as flowchart with Person / System / External subgraphs; set kind: "c4") | plugin + MCP + canvas |
| Who calls whom, in order? | sequenceDiagram | substrate → registry → ops |
| What types / traits? | classDiagram | Hostable / CatalogResource / ProviderOps |
| What persists where? | erDiagram | tables / resources |
| What states can it be in? | stateDiagram-v2 | lifecycle / checkpoint |
beautiful-mermaid does not parse native C4Container syntax — for C4-style
architecture, render a flowchart with labeled subgraphs and store
kind: "c4" on the ArchDiagram for the toolbar pill.
Authoring workflow
- Write Mermaid source (keep labels short; match node labels to map hotspots).
- Declare
hotspots: { label, nodeId? | edgeKey? }[] — label must match SVG
data-label / text from beautiful-mermaid.
- Render offline (from this skill’s
scripts/; Bun preferred):
cd "$SKILL_DIR/scripts"
bun install
bun render-mermaid.mjs --json --file diagrams.json > rendered.json
- Embed
svg strings into ARCH_DIAGRAMS (no runtime import).
- Keep the arch SVG in the unified camera per
architecture-viewport.md (already in
MapView).
Do not invent a second viewport or static SVG box.
- Wire code preview per code-preview.md: author
FILE_MAP
(every path/range), use fileRef / snippet / { type: "code", ref }, then
one update for previews + file tree:
cd "$SKILL_DIR/scripts"
bun update.ts --file "$MAP_FILE"
bun update.ts --file "$MAP_FILE" --check
- Wire the rest:
- Tab / pills to switch diagram kinds (Fit on switch)
- SVG hotspots →
selectNode / selectEdge (click shapes in the arch region)
Architecture pan/zoom/hotspot quality:
architecture-viewport.md § Required UX checklist.
Distill limits
| Element | Limit |
|---|
| Nodes | 5–12 · 2–3 per row |
| Node (on card) | Label + teaser ≤ ~10 words |
| Edge label (on connector) | ≤ 3 words |
| Sidebar body | 1–3 prose + 1–3 code blocks per node/edge |
| Code excerpt | 4–14 lines, verbatim from disk |
| Files per node/edge | 1–3 in Source index (+ refs from code blocks) |
| Edge gaps | Generous (GAP_X ≥ 90, GAP_Y ≥ 100); labels sit in a chip clear of nodes |
Surfaces: node/edge chips stay short; detail lives in the sidebar
(body: DocBlock[] + Source). File tree (right)
lists nested paths from all FileRefs — compact by default; hover expands
ancestors.
Prose-only sidebars are an anti-pattern. Every node and edge sidebar must
interleave 1–3 short prose blocks with 1–3 verbatim code excerpts so the reader
never has to reconstruct meaning by jumping around the codebase.
Edges are first-class: explain the relationship (trait, API, step variant,
registry lookup), not just the hop name — with real code snippets.
Quality bar
Ship only if all of these pass: