Single-page reference. Use the minimap to jump between sections.
Code Canvas is an infinite canvas for exploring and reviewing codebases visually.
Files are arranged as a folder-aware dependency graph: each file still sits inside its real folder structure, but the layout also accounts for how files import and depend on each other. That combination turns the canvas into a map of the codebase's actual architecture.
Use it to:
Supported languages and frameworks
You can ask the AI questions about these docs by connecting Code Canvas's MCP.
In the app, press Cmd+K to open the command palette and find any feature.
You can also open these docs inside the app from the help menu in the bottom-left sidebar. UI links highlight the relevant panel directly in the application's interface when clicked.
Code Canvas runs in three forms: a browser app, a VSCode extension, and a desktop app.
The following features require the local Node.js server running on your local machine:
Start the server with:
npx code-canvas-serverThe local server runs on your computer, and it's required only when using the browser version.
code --install-extension alex-c.code-canvas-appcursor --install-extension alex-c.code-canvas-app)The extension mirrors the active editor into the canvas: the cursor position, selection, and word under the caret all drive canvas highlights and navigation in real time, so opening a function in VS Code or Cursor jumps the canvas to it. The reframe behavior (keep zoom, smooth transition, include references, zoom level) is set in Navigation Settings.
Option+Click any file on the canvas to open it in an editor column beside the canvas. Click directly on a line of code and the editor scrolls to that line; click on the filename label to open the file at the top.
codeCanvas.startOnStartup → open Code Canvas automatically when the editor starts with a workspace (off by default)codeCanvas.showStatusBarItem → show or hide the Code Canvas status bar itemConnect a public GitHub repo without signing in for instant read-only browsing with language servers, search, diffs, and MCP. Point Code Canvas at a local folder when you need private code or live file watching.
owner/repogithub.com with v2.codecanvas.app in any GitHub repo URL to open it directly, e.g. v2.codecanvas.app/facebook/reactnpx code-canvas-server to enable the local connectionFiles can open as text regardless of their extension, including files with no extension. Unrecognized formats show up to the first 256 KiB; binary files show whatever text can be decoded, with replacement characters for unreadable bytes. Truncated or converted previews are read-only in the inline editor. Syntax highlighting and code analysis are available where the language is supported, and your ignored-path settings still apply.
In Folders, the Opening section below Folder Actions has Open with collapsed folders by default and Auto, both enabled by default. Auto chooses the collapse depth for each group of newly opened files: 1,000 or fewer stay fully expanded; 1,001 to 2,999 use about 75% of the repository's depth, rounded to the nearest level and capped one below the maximum; 3,000 or more use one below the maximum. For a repository with 11 levels, those depths are 0, 8, and 10. Hover over Auto to see these rules.
Turn off Auto to choose a Collapse depth manually. Move the slider right to collapse more levels, up to the repository root at the maximum. Its range follows the loaded repository's depth, and your manual depth is preserved while Auto is on. Turning off Open with collapsed folders by default disables both modes.
This applies when opening groups of files, including Open All. Folder positions are calculated before files are rendered, so files hidden inside collapsed folders do not need canvas graphics until you expand them. Expand folders individually to explore a large repository gradually. The settings are saved on this device and affect future opens.
Long files show the first 1,000 lines by default, followed by one Long file row with the collapsed line count. Click that row to expand the file. Symbols are clipped to the visible lines, and imports, exports, and dependency edges in the hidden tail connect to its collapsed marker.
Open File nodes on the right, then Long Files, to change Max lines, turn off Collapse long files, or Expand all X collapsed files on the canvas. The limit and toggle are saved on this device. Existing unchanged-line folding still applies; in diff views, the limit counts displayed rows after that folding.
Dependency edges connect files to the declarations, modules, or local resources they depend on.
A resolved symbol reference connects to its declaration. A module or source-file load can connect to a file without an exported declaration.
Files are arranged left to right by dependency and folder structure
Toggle edge visibility from Dependency Edge Visibility in the Dependency Edges panel
Connections for files in view remain available when zoomed out, independently of CST detail. In the CST panel's Settings > Analysis, turn off Edge culling to load connections for every open file. With culling enabled, Advanced settings lets you release connections after they leave the visible area (the default), or retain them in memory for faster return visits.
When the displayed graph contains relationships beyond imports, an info icon beside Style explains the relationships present, including relationships visible only in a diff. Imports retain the blue-grey tint; uses, rendering and framework relationships are teal; augmentation, composition and ownership are amber; inheritance is violet; and conformance is green. Resource and document/configuration references use the neutral family. Augments describes additions to an existing type, such as a Swift extension. Selection, custom styles, and enabled graph highlights can override those colors. A merged bundle containing different relationship kinds uses the neutral import color. SVG exports use the same relationship palette.
A relationship describes meaning; import, re-export, and barrel routing describe how the connection passes through files. Type-only references retain that evidence without adding a separate color. Repeated uses of one declaration and relationship are grouped into one edge. With CST highlights and Selected Edge CST Nodes enabled, selecting a file highlights the primary syntax anchors of its connected edges where CST data is available, including syntax hidden from the ordinary overlay. File-only endpoints have no declaration highlight. The complete occurrence list remains available through MCP.
Code relationships determine dependency depth, cycles, backwards-edge highlights, and dependency layout. Local document links and resource loads stay visible, selectable, exportable, and included in rendering limits, but do not count as code architecture dependencies. For example, an explicit JavaScript import of a stylesheet keeps its import meaning while its resource category excludes it from code metrics. Multiple relationships between the same pair of code files contribute one file-level connection to layout and architecture metrics.
Swift files in a SwiftPM or Xcode target can reference each other's types without file imports. Code Canvas detects explicit type uses such as constructors, static access, type annotations, and generic arguments, and groups repeated uses of the same declaration in a file into one edge. Matching respects target membership, enclosing scope, and visibility. Xcode membership comes from project source lists or synchronized folders and their exclusions; analysis does not invoke Xcode or require a build. Ambiguous names, multiple target memberships, unsupported build settings, and references requiring inferred receiver types remain unresolved; LSP symbol inspection can reveal additional relationships.
The Swift scan respects ignored paths and analysis limits. If a target has omitted source files, its type relationships remain unresolved because those files could contain competing declarations.
When All is off, edges filter by category. Combine them as needed:
Selected → only edges touching a selected file
Changes → only edges touching a file changed in the active diff
Backwards → only cycle / layering edges, useful for spotting architectural violations
Internal → edges that stay inside the same folder
External → edges that cross folders, with a nesting-depth range slider that controls how far up the folder tree the edge has to cross to count
For very large codebases, turn All off and combine these filters to keep rendering responsive. If too many edges are visible at once, Code Canvas can also auto-trim them and notify you.
Dependency extraction, CST display, and language-server navigation are separate capabilities. Coverage below describes static relationships; it does not imply exhaustive call graphs, runtime loader execution, macro expansion, or compiler inference.
Best support: JavaScript, TypeScript, React, Next.js, Vue, Svelte, Python, and Swift. This includes everything in Good support, with more dependency edges shown by default, more detailed analysis, and support for more configuration files and frameworks.
Good support: PHP, Ruby, Java, Go, Rust, C, C++, Objective-C, and C#. This includes syntax highlighting, language-server highlights when you click a symbol (including calls, definitions, and references), and some dependency edges shown by default. Language-server features require a working server for that language.
The table below describes the specific static relationships Code Canvas tracks for each language and additional file type.
| Language | What's tracked |
|---|---|
| JavaScript | ESM/CommonJS imports and re-exports, static loader aliases and shadows, literal dynamic imports, and statically configured Vite aliases, globs and worker resources |
| TypeScript | JavaScript relationships plus explicit type references, inheritance and implementation, declaration merging and augmentation, import types, triple-slash references, and static tsconfig project scope |
| JSX / TSX / React | Imported component rendering through named, default and namespace bindings, including repeated JSX tags and aliases; local shadows do not become component dependencies |
| Vue | Independently parsed normal/setup scripts, literal external script/template/style sources, actual module exports, and component/directive uses through setup imports, options registrations, or a proven application registration |
| Nuxt | Detected Nuxt roots and supported literal configuration select automatic component names and composable exports. Script and parsed template calls respect local bindings; repeated uses aggregate |
| Svelte | Modern and legacy module scripts, separate instance scripts, actual named module exports, synthetic default components, and literal imports in parsed markup expressions. Instance props are separate from module exports |
| SvelteKit | Pages and layouts connect to actual load modules and the nearest applicable layout, respecting route groups, root/named layout resets, and supported route configuration. These framework relationships use file endpoints; $lib and literal aliases resolve local files |
| Python | Ordered import roots and namespace packages, package facades, aliases, explicit type/base/decorator references, and statically bound importlib or built-in loaders |
| PHP | Namespace imports and aliases, literal include paths, namespaces, classes, interfaces, traits, functions, and constants |
| Go | Same-package and imported declaration uses, receiver ownership, embedded types and explicit constraints, respecting module/workspace replacements, package visibility, selected platform/build tags and test scope |
| Rust | Cargo target/module scope, visible path uses and re-exports, implementation ownership and trait conformance, explicit bounds and supertraits, cfg/features, and literal include resources |
| Swift | SwiftPM target imports and local path-package products, declaration-specific imports, augmentation, explicit type uses, inheritance and protocol conformance, with scoped declaration identities |
| Java | Same-package, imported and qualified types, annotations, static owners, inheritance and implementation, constrained by static Maven/Gradle source roots and JPMS modules/services |
| C | Translation-unit declarations and uses, compiler-ordered includes, forced headers and preprocessor branches, with definition ownership only where static build context proves it |
| C++ | C-style includes plus qualified types, bases, aliases, templates/concepts and named modules/partitions within proven compilation and module ownership scope |
| Objective-C / Objective-C++ | Header and public module-map scope, class/protocol types, superclass and protocol adoption, categories/extensions and implementation ownership. Hybrid .mm references retain original Objective-C and C++ source ranges |
| C# | Type uses, aliases, inheritance, interface implementation, partial ownership and extension containers within statically known project sources/references, using directives, selected target frameworks and defines |
| Ruby / Rails | Proven constant references, superclass and mixin relationships, sparse reopened declaration ownership and bounded literal loading. Detected/configured Rails Zeitwerk roots add namespace, inflection, ignored/collapsed-root and engine scope |
| CSS | Static @import and url() references to eligible local stylesheets and text resources, including escaped URLs and import layer/supports clauses |
| HTML | Script sources, stylesheet links and actual inline JavaScript module imports with original HTML ranges and a static base URL; origin-relative paths require a declared document root |
| Bash | Literal source and dot commands under an explicit working-directory and PATH context; unknown or changed execution context remains unresolved |
| JSON configuration | Recognized TypeScript/JavaScript configuration inheritance and project references, and declared JSON Schema references. Arbitrary JSON keys do not create edges |
| Markdown | CommonMark inline/reference links and images to eligible local files, excluding fenced/inline code, unused definitions and remote targets |
| MDX | Actual ESM imports/exports, bound JSX component rendering and CommonMark links. The implicit document component has a file endpoint; MDX does not have a bundled CST display grammar or language server |
Vue application registration must be static and unconditional. Template scopes introduced by v-for or v-slot, dynamic registrations, Nuxt layers/modules that modify automatic maps, and dynamic framework configuration remain unresolved. Nuxt 4 projects relying on legacy directory detection should specify srcDir. SvelteKit supports literal configuration in svelte.config and the Vite sveltekit plugin; custom component extensions and generated layouts are not inferred.
Source files and configuration are analyzed locally. The analyzer does not execute project configuration, fetch missing packages, expand macros, or infer runtime receiver dispatch. Missing, ignored, inaccessible or ambiguous providers stay unresolved. A source-file load does not prove that every declaration in that file is available.
When a project requires an invocation choice, supply it through MCP's analysis:start command. Paths are relative to the connected repository. For example, a shell project can set its working directory and ordered PATH directories:
{"type":"analysis:start","args":{"context":{"languages":{"shell":{"cwd":"scripts","path":["scripts/lib"]}}}}}
Explicit analysis options take precedence over supported project configuration. The same explicit options apply to both sides of a diff; each side uses its own configuration snapshot. The dependency-analysis state store exposes analysisContext and analysisContextDiagnostics, including the selected context and unresolved scope reason. Language-specific examples document supported keys such as Go platform/build tags, Rust cfg/features, Python source roots, Ruby load paths, HTML documentRoot and C# target frameworks. Shell and plain Ruby execution directories are never guessed from the file's directory or the host process environment.
An index file (index.ts, index.tsx, index.js, index.jsx, index.mjs, index.cjs, index.mts, index.cts) often re-exports things from sibling files → a "barrel"
Two display modes live in Barrel and Re-export settings inside the Dependency Edges panel:
Re-export edges → direct shortcut from importer to the original source export, skipping the barrel
Barrel edges → split into two hops: importer to the barrel re-export row, then re-export row to the source
Each can be independently shown or highlighted
TypeScript path aliases → read from tsconfig.json
Vite aliases → read from vite.config.{ts,js,mjs,cjs}
Index file fallback → ./foo resolves to ./foo/index.ts (or other resolvable extensions)
@/ shorthand falls back to src/
External (npm) modules are tagged external and don't draw edges
The goal of the layout is to reveal architecture. The files are arranged left to right based on dependency and folder structure.
The algorithm starts at leaf folders, laying out all the files inside the folder based on dependency, then moves up one level in the folder hierarchy, treating the sorted child folders as single nodes at that level. The process repeats until it reaches the root folder.
By combining the folder structure and dependencies, the layout of the files on the canvas reveals the architecture of the codebase.
Because files are laid out left to right, an edge that runs backwards from a file on the left to a file on the right usually signals a circular dependency or layering problem somewhere in the import chain. It is not always a direct file-to-file cycle; it can be a cycle between modules or folders. You can highlight these from Dependency Edge Visibility, where backwards edges render in red.
Open the Layout panel to apply layout, toggle auto layout, change horizontal and vertical alignment, adjust file and folder spacing, set folder padding, change sort behavior, and tune rank breaking. Hover a control label in the panel for a short description of what that control changes.
The Break slider controls rank breaking, letting you change the aspect ratio of the graph while preserving its edge relationships. Each file on the canvas is much taller than it is wide, just by the nature of how code files are written, so rank breaking is there to produce a more cohesive layout that fits the screen better.
Language servers add semantic information on top of the canvas. Hover a function and Code Canvas highlights its definition, references, callers, callees, and implementations across every open file.
Open the LSP panel
Use the LSP menu to open Language servers, then load or connect the server you need. TypeScript ships bundled.
References in light amber
Definitions in pink
Type definitions in pink with a stroke
Implementations in green
Incoming calls (who calls this) in light purple
Outgoing calls (what this calls) in orange
Click a symbol to pin its graph; Shift+Click to pin multiple.
The File nodes panel gains three actions that act on the currently-selected file node(s):
Open Importers → pulls every file that imports the selection onto the canvas. Resolved by asking the language service for references to each export, so it works for files that aren't on the canvas yet.
Open Imports → pulls every file the selection imports onto the canvas. Derived from the dependency graph, so the imported file must already have been analyzed.
Highlight Top-Level Symbols → in the Symbols section, pins a symbol graph for every top-level symbol in the selection, one after another. Skip imports is on by default so the highlights cover declarations rather than the imports the file brings in; toggle it off to include import statements as well.
All three are also available from the command palette (Cmd+K).
LSP settings include:
Query On Hover → auto-query as you hover; with it off, click a symbol to query
Auto Open Matches → automatically open files that contain matches, up to the Max files limit
Keep Zoom → keep the current zoom when navigating to a result
Smooth Transition → animate the viewport instead of jumping
Out-of-view target labels → when a symbol's target file scrolls off the canvas, a sticky label appears at the canvas edge pointing toward it, so you don't lose the connection. Toggle it from LSP Symbol Edge Settings.
Mirror IDE editor → in the VS Code / Cursor extension, the active editor's cursor and selection mirror into canvas highlights. Reframe behavior lives in Navigation Settings.
Use Clear Symbols (Shift+C) to remove every pinned symbol at once.
CST stands for concrete syntax tree. Code Canvas tints code regions by their syntactic role (functions, classes, conditionals, loops) so you can read structure at a glance, especially when zoomed out where individual characters disappear. Think of it as a smarter minimap baked into the canvas itself.
Code Canvas loads CST detail as you zoom closer and retains it while memory permits. The cache adapts to available memory with headroom for other work, releasing older offscreen detail first. Removing a file from the canvas releases its cached detail. If all requested edges or CST nodes cannot fit, a notification identifies which detail is limited.
Per-type colors are editable from the CST panel
Pick a custom color, fill mode (solid or gradient), opacity, and border width / sides for any node type
Hide types you don't want to see
For large CST regions, such as function bodies or statement blocks, you do not always have to place the cursor directly over the name token. Symbol Mapping chooses a meaningful token inside that region instead, so hovering or clicking anywhere inside the construct can still highlight the related connections on the canvas.
See code changes in the context of the whole codebase. Local working changes update in real time as you edit; pull requests load from GitHub. Reviewing a change on the canvas shows you not just what changed but where it sits in the architecture and what it connects to.
Local changes → your working tree, refreshes when files change
Pull requests → pick from the GitHub PR list (sign-in required for private repos)
Local changes are the default source. Selecting a PR replaces them on the canvas with that PR's changes; closing the PR returns the canvas to your local changes.
Changes → the file as it is now, with added and modified lines marked and a marker where lines were deleted. Like an editor window in an IDE: deleted lines are not rendered, just signposted.
Unified → old and new in a single column
Split → old and new side by side
Cycle modes with D; reverse with Shift+D
The language server highlights work on both versions of a diff (old and new) separately, so you can trace references, definitions, and calls in either side independently.
The File nodes and Folders panels gain extra buttons during a diff session, each with a keyboard shortcut:
Shift+O → Open Changed Files: open every changed file in the active diff onto the canvas
Option+O → Close Files Without Changes: remove canvas files whose own path has no changes
Close Folders Without Changes: remove files whose entire folder has no changes (unchanged files inside a folder that has at least one change are kept)
Open All Folders With Changes: open every file in any folder that contains at least one changed file, so unchanged neighbors come along for context
Diffs above the per-file scan limit are skipped to keep the canvas responsive. When that happens, the File nodes panel shows an amber Large Diffs card with a one-click action to load just the open canvas files that were skipped, without raising the global limit.
Open Diff settings from the settings gear next to the diff mode toggle.
Context → number of unchanged lines kept above and below each change when collapsed
Character diff → Word, Char, or Off for fine-grained highlighting inside modified lines
Show deleted chars → render character-level deletion markers on modified lines
Similarity threshold → minimum similarity required to pair an added line with a removed line for character diffing; higher values pair only near-identical lines
Collapse / expand unchanged → toggle with C
git status for the current local sessionConnect AI agents to Code Canvas through MCP and they can drop annotated cards onto the canvas while they explain code. Each note's links resolve to specific files, folders, or symbols. Clicking one navigates the canvas and highlights the target. Reading an explanation while seeing the actual code is much more useful than reading text in isolation.
A title and a markdown body, both written by the agent
Links use the cc:// scheme and target one of:
a file: cc://file/path/to/file.ts
a folder: cc://folder/path/to/dir
a symbol: cc://symbol/path/to/file.ts:LINE:CHAR
a range: cc://range/path/to/file.ts:SL:SC-EL:EC
Clicking a link navigates the canvas and highlights the target
Hovering a link previews the highlight without navigating
Connect the MCP and ask the AI to explain a feature using agent_notes. The description appears in the Agent Notes panel as a navigable note instead of plain chat text.
Find code, files, or folders across the entire workspace, highlight matches, and jump straight to results on the canvas. Off-canvas matches stay listed alongside on-canvas ones, so a single search shows both what you can already see and what you'd need to open.
Code → full-text search across file contents
Files & folders → search by filename and folder path
Tab toggles modes from the search input
.* → regex
Aa → case sensitive
Word → whole word
Ignored → include gitignored files (local repos only)
Canvas → only files currently open on the canvas
Grouped into On Canvas and Off Canvas sections
Click an on-canvas result to focus it on the canvas
Click an off-canvas result to open the file and focus the match
ArrowUp / ArrowDown to navigate, ArrowLeft / ArrowRight to collapse / expand, Enter to open
Keep Zoom and Smooth Transition toggles control how navigation behaves
The Settings panel covers app-wide preferences. Feature-specific controls live in their own right-sidebar panels: Layout, Dependency Edges, Folders, File nodes, LSP, CST, and Agent notes.
Viewport → Smooth Zoom, Viewport Details, Activity Indicator
UI → Controls Bar and Minimap (with position/size reset)
Repository → dot-prefixed folders in the local folder picker
VS Code / Cursor → start Code Canvas automatically when the editor starts and toggle the status bar item, shown only in the extension
Reset → reset all settings or clear individual stored groups such as repository connection, UI settings, editor tabs, agent notes, server/auth/MCP, shortcut overrides, and dismissed toasts
Each right-sidebar panel has a header menu (the ⋮ button next to the panel title) with a Reset settings action for that panel only. Layout, Dependency Edges, Folders, File nodes, LSP, CST, and Agent notes all have one. Use it to clear a single feature's settings without touching anything else.
Hover a setting label for a description of what it does.
Code Canvas exposes an MCP server so AI agents can read the canvas, search the workspace, query the language server, post agent notes, and read these docs. Connect once and the agent works inside the same view you do.
Copy this into your MCP config, or give it to your AI agent and ask it to set up the connection:
{
"mcpServers": {
"code-canvas": {
"command": "npx",
"args": ["-y", "-p", "code-canvas-server", "code-canvas-mcp"]
}
}
}
In the VSCode extension, MCP connects through the extension backend; no separate npx code-canvas-server process is required.
In the browser app, start the local server first with npx code-canvas-server.
MCP connections are always enabled. Open MCP Connections in the Local Server panel to copy the config and see connected agents.
list_commands → discover canvas and UI commands
use_command → run a command such as canvas:openFiles, layout:apply, viewport:fitNodes, folder:collapseAll, or agentNotes:push
query → read canvas state, nodes, folders, backwards edges, layout config, and registered state stores. General edge queries preserve semantic relationships, graph categories, resolved endpoint identities, type-only status, occurrence ranges, and rule provenance. Backwards-edge results use code relationships only.
search → search code, file paths, file contents, or language-server data
lsp_servers → detect, start, reload, stop, and inspect language servers
read_docs → read this guide, a section, or the section list
Once connected, ask "explain this codebase using agent_notes" and the agent will open files, lay them out, and post navigable agent notes describing what it finds.
The command palette is one searchable list of everything Code Canvas can do, from opening panels and toggling settings to running canvas actions. Instead of hunting through the interface for the right control, you type what you want and run it.
Start typing to filter actions by name; matches rank as you type
ArrowUp / ArrowDown to move through results, Enter to run the highlighted one
Selecting an action runs it immediately and closes the palette
Some actions also live somewhere in the interface, such as a panel, a toggle, or a button. Hover an option in the palette and a Go to UI button appears on its left side. Clicking it doesn't run the action; it highlights where that control sits in the app, so you can find it and learn where it lives instead of just triggering it blind.
Use Enter when you just want the action done, and Go to UI when you want to see where it lives for next time.