# Milestone 7: Graph Visualization ## Overview Export the knowledge graph as interactive HTML visualizations, SVG images, and Mermaid diagrams. See and understand your knowledge structure. ## Motivation - Visual understanding of knowledge structure - Identify orphaned or disconnected nodes - Documentation and sharing - Obsidian-style graph view is beloved ## Features ### 7.1 Interactive HTML Export ```bash # Export full graph as interactive HTML cortex export --format html --output graph.html # Export subgraph from a root node cortex export abc123 --format html --output component-graph.html # Export with filters cortex export --kind component --format html ``` ### 7.2 SVG/PNG Export ```bash # Static SVG export cortex export --format svg --output graph.svg # PNG with custom dimensions cortex export --format png --width 1920 --height 1080 # Export specific depth from root cortex export abc123 --format svg --depth 3 ``` ### 7.3 Mermaid Diagram Export ```bash # Export as Mermaid syntax cortex export --format mermaid # Output: # ```mermaid # graph TD # A[Component: Auth] --> B[Component: UserService] # A --> C[Decision: Use JWT] # ``` ``` ### 7.4 Live Server ```bash # Start live visualization server cortex viz # Opens browser with interactive graph # Auto-refreshes on database changes ``` ### 7.5 Customization ```bash # Custom color scheme cortex export --format html --theme dark # Filter by tags cortex export --format html --tags auth,security # Layout options cortex export --format html --layout force|tree|radial ``` ## Implementation ### HTML Exporter (D3.js) ```typescript // src/core/export/html.ts export async function exportHtml(options: ExportOptions): Promise { const { nodes, edges } = await getGraphData(options); const graphData = { nodes: nodes.map(n => ({ id: n.id, label: n.title, kind: n.kind, tags: n.tags, group: kindToGroup(n.kind), })), links: edges.map(e => ({ source: e.fromId, target: e.toId, type: e.type, })), }; return generateHtmlTemplate(graphData, options.theme); } function generateHtmlTemplate(data: GraphData, theme: string): string { return ` Cortex Knowledge Graph
`; } ``` ### D3 Force Graph ```typescript const D3_SCRIPT = ` const width = window.innerWidth; const height = window.innerHeight; const svg = d3.select("#graph") .append("svg") .attr("width", width) .attr("height", height); const simulation = d3.forceSimulation(data.nodes) .force("link", d3.forceLink(data.links).id(d => d.id).distance(100)) .force("charge", d3.forceManyBody().strength(-300)) .force("center", d3.forceCenter(width / 2, height / 2)); // ... link and node rendering // ... drag behavior // ... zoom behavior // ... click to show details `; ``` ### Mermaid Exporter ```typescript // src/core/export/mermaid.ts export async function exportMermaid(options: ExportOptions): Promise { const { nodes, edges } = await getGraphData(options); const lines = ['graph TD']; // Define nodes for (const node of nodes) { const shape = kindToShape(node.kind); lines.push(` ${shortId(node.id)}${shape.open}"${escape(node.title)}"${shape.close}`); } // Define edges for (const edge of edges) { const arrow = typeToArrow(edge.type); lines.push(` ${shortId(edge.fromId)} ${arrow} ${shortId(edge.toId)}`); } return lines.join('\n'); } function kindToShape(kind: string): { open: string; close: string } { switch (kind) { case 'component': return { open: '[', close: ']' }; case 'decision': return { open: '{', close: '}' }; case 'task': return { open: '([', close: '])' }; default: return { open: '(', close: ')' }; } } ``` ### Live Visualization Server ```typescript // src/server/viz.ts export function startVizServer(port: number): void { const app = express(); app.get('/', async (req, res) => { const html = await exportHtml({ theme: 'dark', layout: 'force' }); res.send(html); }); app.get('/api/graph', async (req, res) => { const data = await getGraphData({}); res.json(data); }); // WebSocket for live updates const wss = new WebSocketServer({ server }); watchDatabase((change) => { wss.clients.forEach(client => { client.send(JSON.stringify({ type: 'update', data: change })); }); }); app.listen(port); open(`http://localhost:${port}`); } ``` ## CLI Commands | Command | Description | |---------|-------------| | `cortex export --format html` | Export interactive HTML | | `cortex export --format svg` | Export static SVG | | `cortex export --format png` | Export PNG image | | `cortex export --format mermaid` | Export Mermaid syntax | | `cortex export --depth ` | Export subgraph | | `cortex viz` | Start live visualization server | | `cortex viz --port ` | Custom port | ## MCP Tools ```typescript memory_export // Export graph in specified format memory_visualize // Get visualization URL ``` ## Testing - [ ] HTML export renders correctly in browsers - [ ] SVG export produces valid SVG - [ ] Mermaid syntax is valid - [ ] Subgraph export respects depth - [ ] Live server updates on changes - [ ] Large graphs (1000+ nodes) perform well ## Acceptance Criteria - [ ] Interactive HTML with zoom, pan, search - [ ] Click node to see details - [ ] Color-coded by node kind - [ ] Edge types visually distinct - [ ] Mermaid compatible with GitHub/docs - [ ] Live server auto-refreshes ## Estimated Effort - HTML + D3 template: 6 hours - SVG export: 3 hours - Mermaid export: 2 hours - Live server: 4 hours - Theming: 2 hours - Testing: 3 hours - **Total: ~20 hours** ## Dependencies - D3.js (bundled in HTML output) - Optional: Puppeteer for PNG export ## References - [D3.js Force Graph](https://observablehq.com/@d3/force-directed-graph) - [Mermaid.js](https://mermaid.js.org/) - [Obsidian Graph View](https://help.obsidian.md/Plugins/Graph+view)