Surface
Chrome extension
The Chrome extension, prototyped: the toolbar button (or the page's right-click menu) opens Visualli in Chrome's side panel beside the page you're reading — the same visual browsing as the MCP card, no vault or chat — with Open in Visualli to continue the journey.
How it works
- Two ways in: the toolbar button (tooltip "Visualize this page", shortcut Alt+Shift+V; clicking it again closes the panel) and the page's right-click menu (Visualize this page). No selection mapping — the whole page is always the source.
- Why the side panel:
chrome.sidePanelworks on every supported Chrome (114+, opening on click from 116) and stays put as you scroll. Chrome draws the panel's header (icon, Visualli, pin, ✕) and lets people resize it; our content starts below that header, soExtensionPanelis rendered without its own brand mark or close button. - The panel (
ExtensionPanel): the map's title, the source (favicon, domain, reading time) and Open in Visualli (primary — saves the map to the vault and opens the app). Body: Reading thedailyreader.example… with the growing tree while ideas bloom in, then theVisualMap; Couldn't read this page with Try again. - Inside the map everything browsing does works: peek, terms, Go deeper (sheet layout at this width), Step inside, Map it. Content is read-only here (no edit, no moving) — arranging and editing continue in the app.
- Try the narrow width (320px, Chrome's minimum) — the header and map still fit. The browser chrome and the news site in this prototype are deliberately generic and fictitious.
Features
6 of 6 features that apply here are UX ready · 9 N/A · Feature matrix for Chrome extension
UX ready 6
VI-001Visualize this page (toolbar, right-click) · Open in Visualli PRODUCTVI-002Map: bloom, step inside, depth trail SPECVI-004SemanticPeek (an idea's summary) SPECVI-005SemanticAnchor (term definitions) SPECVI-006Go deeper (facets for an idea or term) PRODUCTVI-007Map it (inside this map / new Visualli) PRODUCT
N/A 9
VI-003Touch: tap to peek, tap again to step inside SPECChrome on desktop uses the mouse; the map switches to touch by itself on touchscreensVI-008Movable ideas and Reset layout PRODUCTPage maps are previews; arrange them after Open in VisualliVI-009Edit mode (ideas, connectors, groups) PRODUCTRead-only beside the page; edit after Open in VisualliVI-010Sources panel PRODUCTThe page beside the map is the sourceVI-011Export: single-page PDF, multi-page PDF, .visualli file (no share link) PRODUCTOpen in Visualli, then export from the appVI-012Chat: Composer and receipts PRODUCTContinue the conversation after Open in VisualliVI-013Vault (library of Visuallis) PRODUCTOpen in Visualli saves the map to the vaultVI-014Comfort & appearance SPECUses the comfort settings saved in the person's Visualli account (synced)VI-015Tips in the chat stack (e.g. "Layout saved. Want to edit the content too?") PRODUCTNothing is moved or edited here, so no tips are triggered
Build it
The Visualli extension does one thing: visualize the page you're reading in Chrome's side panel, with Open in Visualli to continue there. Component: ExtensionPanel.
The experience
- Toolbar button — the tree mark. Tooltip "Visualize this page", keyboard shortcut Alt+Shift+V (
commands). Clicking opens the side panel for the current tab; clicking again closes it. Right-click — one item in the page's context menu (contexts: ['page']): Visualize this page, with the tree icon. Same result as the button. There is no "visualize selection" — the whole page is always the source. - Reading —
ExtensionPanel status="reading": the growing tree and Reading ‹domain›…; ideas bloom in as they're found. - The map —
status="ready": a read-onlyVisualMapwith everything browsing does (peek, terms, Step inside, Go deeper, Map it). No edit, no moving, no vault, no composer — like the MCP card. - Open in Visualli — the one primary action: saves the map to the user's vault and opens it in the app (new tab), where chat, editing and sources continue.
- Can't read —
status="error": Couldn't read this page (login, paywall, too little text) and Try again.
Why the side panel (and not split view)
chrome.sidePanelis the stable, documented surface: available from Chrome 114,sidePanel.open()andsetPanelBehavior({ openPanelOnActionClick: true })from 116. That covers effectively every Chrome install still receiving updates; newer versions add a resizable panel and keep it per tab.- Chrome's split view is a user feature with no extension API to open it, so it can't be the primary path. If a user drags the panel into a split, the same
ExtensionPanelsimply gets more room. - Chrome draws the panel's header (icon, Visualli, pin, ✕). Render
ExtensionPanelwithoutlogoSrcandonClosethere, so the brand and close aren't doubled. Minimum width is 320px; the header and map are designed to fit. - Older Chrome (< 114) or browsers without
sidePanel: feature-detectchrome.sidePanel; if it's missing, the button opens the same panel page in a popup window (chrome.windows.create({ type: 'popup', width: 440 })) placed beside the current window. Same component, same flow.
// background.js (MV3 service worker)
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({ id: 'visualize-page', title: 'Visualize this page', contexts: ['page'] });
});
async function openPopup(tab) {
const win = await chrome.windows.getCurrent();
chrome.windows.create({ url: `panel.html?tab=${tab.id}`, type: 'popup', width: 440, height: win.height, left: win.left + win.width - 440, top: win.top });
}
if (chrome.sidePanel?.setPanelBehavior) {
chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true });
} else {
chrome.action.onClicked.addListener(openPopup);
}
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId !== 'visualize-page') return;
// sidePanel.open() must run synchronously inside the click (user gesture) — Chrome 116+.
if (chrome.sidePanel?.open) chrome.sidePanel.open({ tabId: tab.id });
else openPopup(tab);
});
Permissions: sidePanel, contextMenus, activeTab, scripting (read the page's text on click — no broad host permissions), storage.
Rules
- No remote code. MV3 forbids loading scripts from a CDN. Bundle React and the components into the extension.
- Ship fonts and CSS locally. Copy
assets/fonts/andtokens/dist/tokens.cssinto the extension and reference them withchrome.runtime.getURL(). Google Fonts may be blocked by the extension's CSP; the fallbacks in the tokens must still work. - The side panel is your own document: load the tokens normally and set
data-themeon<html>. Nothing is injected into the pages people read; the content script only extracts text when the button is clicked. - Respect comfort settings from the user's Visualli account when available; otherwise follow
prefers-color-schemeandprefers-reduced-motion. - Copy: "Visualize this page" (tooltip and menu item), "Reading ‹domain›…", "Open in Visualli", "Couldn't read this page", "Try again". No emoji, no "AI".
Prototype source: components/catalog/ExtensionView/preview.html · Build notes: docs/platforms/chrome-extension.md
