aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/docs/docs.json12
-rw-r--r--apps/docs/memory-graph/api-reference.mdx334
-rw-r--r--apps/docs/memory-graph/examples.mdx407
-rw-r--r--apps/docs/memory-graph/installation.mdx28
-rw-r--r--apps/docs/memory-graph/npm.mdx5
-rw-r--r--apps/docs/memory-graph/overview.mdx38
-rw-r--r--apps/docs/memory-graph/quickstart.mdx207
-rw-r--r--packages/memory-graph/README.md372
8 files changed, 1075 insertions, 328 deletions
diff --git a/apps/docs/docs.json b/apps/docs/docs.json
index dab7caeb..347d6df5 100644
--- a/apps/docs/docs.json
+++ b/apps/docs/docs.json
@@ -213,6 +213,18 @@
"ai-sdk/infinite-chat",
"ai-sdk/npm"
]
+ },
+ {
+ "group": "Memory Graph",
+ "icon": "network",
+ "pages": [
+ "memory-graph/overview",
+ "memory-graph/installation",
+ "memory-graph/quickstart",
+ "memory-graph/api-reference",
+ "memory-graph/examples",
+ "memory-graph/npm"
+ ]
}
]
}
diff --git a/apps/docs/memory-graph/api-reference.mdx b/apps/docs/memory-graph/api-reference.mdx
new file mode 100644
index 00000000..92641a74
--- /dev/null
+++ b/apps/docs/memory-graph/api-reference.mdx
@@ -0,0 +1,334 @@
+---
+title: 'API Reference'
+description: 'Complete reference for Memory Graph props and types'
+---
+
+## Component Props
+
+### MemoryGraph
+
+The main graph component.
+
+#### Core Props
+
+<ParamField path="documents" type="DocumentWithMemories[]" required>
+ Array of documents to display in the graph. Each document must include its memory entries.
+</ParamField>
+
+<ParamField path="isLoading" type="boolean" default="false">
+ Shows a loading indicator when true.
+</ParamField>
+
+<ParamField path="error" type="Error | null" default="null">
+ Error object to display. Shows an error message overlay when set.
+</ParamField>
+
+<ParamField path="variant" type='"console" | "consumer"' default='"console"'>
+ Visual variant:
+ - `console`: Full-featured dashboard view (0.8x zoom, space selector visible)
+ - `consumer`: Embedded widget view (0.5x zoom, space selector hidden)
+</ParamField>
+
+<ParamField path="children" type="ReactNode">
+ Content to render when no documents exist. Useful for empty states.
+</ParamField>
+
+#### Pagination Props
+
+<ParamField path="isLoadingMore" type="boolean" default="false">
+ Shows a subtle indicator when loading additional documents.
+</ParamField>
+
+<ParamField path="hasMore" type="boolean" default="false">
+ Whether more documents are available to load.
+</ParamField>
+
+<ParamField path="totalLoaded" type="number">
+ Total number of documents currently loaded. Shown in loading indicator.
+</ParamField>
+
+<ParamField path="loadMoreDocuments" type="() => Promise<void>">
+ Callback to load more documents. Called automatically when viewport shows most documents.
+</ParamField>
+
+<ParamField path="autoLoadOnViewport" type="boolean" default="true">
+ Automatically load more documents when 80% are visible in viewport.
+</ParamField>
+
+#### Display Props
+
+<ParamField path="showSpacesSelector" type="boolean">
+ Show or hide the space filter dropdown. Defaults to `true` for console variant, `false` for consumer.
+</ParamField>
+
+<ParamField path="highlightDocumentIds" type="string[]" default="[]">
+ Array of document IDs to highlight with a pulsing outline. Accepts both `customId` and internal `id`.
+</ParamField>
+
+<ParamField path="highlightsVisible" type="boolean" default="true">
+ Controls whether highlights are shown. Useful for toggling highlights without changing the array.
+</ParamField>
+
+<ParamField path="occludedRightPx" type="number" default="0">
+ Pixels occluded on the right side (e.g., by a sidebar). Graph auto-fits accounting for this space.
+</ParamField>
+
+<ParamField path="legendId" type="string">
+ Custom ID for the legend component. Useful for testing or styling.
+</ParamField>
+
+#### Controlled State Props
+
+<ParamField path="selectedSpace" type="string">
+ Currently selected space. When provided, makes space selection controlled. Use `"all"` for all spaces.
+</ParamField>
+
+<ParamField path="onSpaceChange" type="(spaceId: string) => void">
+ Callback when space selection changes. Required when using `selectedSpace`.
+</ParamField>
+
+<ParamField path="memoryLimit" type="number">
+ Maximum memories to show per document when a specific space is selected. Only applies when `selectedSpace !== "all"`.
+</ParamField>
+
+<ParamField path="isExperimental" type="boolean" default="false">
+ Enable experimental features. Currently unused but reserved for future features.
+</ParamField>
+
+## Data Types
+
+### DocumentWithMemories
+
+```typescript
+interface DocumentWithMemories {
+ id: string;
+ customId?: string | null;
+ contentHash: string | null;
+ orgId: string;
+ userId: string;
+ connectionId?: string | null;
+ title?: string | null;
+ content?: string | null;
+ summary?: string | null;
+ url?: string | null;
+ source?: string | null;
+ type?: string | null;
+ status: 'pending' | 'processing' | 'done' | 'failed';
+ metadata?: Record<string, string | number | boolean> | null;
+ processingMetadata?: Record<string, unknown> | null;
+ raw?: string | null;
+ tokenCount?: number | null;
+ wordCount?: number | null;
+ chunkCount?: number | null;
+ averageChunkSize?: number | null;
+ summaryEmbedding?: number[] | null;
+ summaryEmbeddingModel?: string | null;
+ createdAt: string | Date;
+ updatedAt: string | Date;
+ memoryEntries: MemoryEntry[];
+}
+```
+
+### MemoryEntry
+
+```typescript
+interface MemoryEntry {
+ id: string;
+ customId?: string | null;
+ documentId: string;
+ content: string | null;
+ summary?: string | null;
+ title?: string | null;
+ url?: string | null;
+ type?: string | null;
+ metadata?: Record<string, string | number | boolean> | null;
+ embedding?: number[] | null;
+ embeddingModel?: string | null;
+ tokenCount?: number | null;
+ createdAt: string | Date;
+ updatedAt: string | Date;
+
+ // Fields from join relationship
+ sourceAddedAt?: Date | null;
+ sourceRelevanceScore?: number | null;
+ sourceMetadata?: Record<string, unknown> | null;
+ spaceContainerTag?: string | null;
+
+ // Version chain fields
+ updatesMemoryId?: string | null;
+ nextVersionId?: string | null;
+ relation?: 'updates' | 'extends' | 'derives' | null;
+
+ // Memory status fields
+ isForgotten?: boolean;
+ forgetAfter?: Date | string | null;
+ isLatest?: boolean;
+
+ // Space/container fields
+ spaceId?: string | null;
+
+ // Legacy fields (for backwards compatibility)
+ memory?: string | null;
+ memoryRelations?: Array<{
+ relationType: 'updates' | 'extends' | 'derives';
+ targetMemoryId: string;
+ }> | null;
+ parentMemoryId?: string | null;
+}
+```
+
+### GraphNode
+
+Internal type for rendered nodes:
+
+```typescript
+interface GraphNode {
+ id: string;
+ type: 'document' | 'memory';
+ x: number;
+ y: number;
+ data: DocumentWithMemories | MemoryEntry;
+ size: number;
+ color: string;
+ isHovered: boolean;
+ isDragging: boolean;
+}
+```
+
+### GraphEdge
+
+Internal type for connections:
+
+```typescript
+interface GraphEdge {
+ id: string;
+ source: string;
+ target: string;
+ similarity: number;
+ edgeType: 'doc-memory' | 'doc-doc' | 'version';
+ relationType?: 'updates' | 'extends' | 'derives';
+ color: string;
+ visualProps: {
+ opacity: number;
+ thickness: number;
+ glow: number;
+ pulseDuration: number;
+ };
+}
+```
+
+## Exported Components
+
+Besides `MemoryGraph`, the package exports individual components for advanced use cases:
+
+### GraphCanvas
+
+Low-level canvas renderer. Not recommended for direct use.
+
+```typescript
+import { GraphCanvas } from '@supermemory/memory-graph';
+```
+
+### Legend
+
+Graph legend showing node types and counts.
+
+```typescript
+import { Legend } from '@supermemory/memory-graph';
+```
+
+### LoadingIndicator
+
+Loading state indicator with progress counter.
+
+```typescript
+import { LoadingIndicator } from '@supermemory/memory-graph';
+```
+
+### NodeDetailPanel
+
+Side panel showing node details when clicked.
+
+```typescript
+import { NodeDetailPanel } from '@supermemory/memory-graph';
+```
+
+### SpacesDropdown
+
+Space filter dropdown.
+
+```typescript
+import { SpacesDropdown } from '@supermemory/memory-graph';
+```
+
+## Exported Hooks
+
+### useGraphData
+
+Processes documents into graph nodes and edges.
+
+```typescript
+import { useGraphData } from '@supermemory/memory-graph';
+
+const { nodes, edges } = useGraphData(
+ data,
+ selectedSpace,
+ nodePositions,
+ draggingNodeId,
+ memoryLimit
+);
+```
+
+### useGraphInteractions
+
+Handles pan, zoom, and node interactions.
+
+```typescript
+import { useGraphInteractions } from '@supermemory/memory-graph';
+
+const {
+ panX,
+ panY,
+ zoom,
+ selectedNode,
+ handlePanStart,
+ handleWheel,
+ // ... more interaction handlers
+} = useGraphInteractions('console');
+```
+
+## Constants
+
+### colors
+
+Color palette used throughout the graph:
+
+```typescript
+import { colors } from '@supermemory/memory-graph';
+
+colors.document.primary; // Document fill color
+colors.memory.primary; // Memory fill color
+colors.connection.strong; // Strong edge color
+```
+
+### GRAPH_SETTINGS
+
+Initial zoom and pan settings for variants:
+
+```typescript
+import { GRAPH_SETTINGS } from '@supermemory/memory-graph';
+
+GRAPH_SETTINGS.console.initialZoom; // 0.8
+GRAPH_SETTINGS.consumer.initialZoom; // 0.5
+```
+
+### LAYOUT_CONSTANTS
+
+Spatial layout configuration:
+
+```typescript
+import { LAYOUT_CONSTANTS } from '@supermemory/memory-graph';
+
+LAYOUT_CONSTANTS.clusterRadius; // Memory orbit radius
+LAYOUT_CONSTANTS.documentSpacing; // Distance between documents
+```
diff --git a/apps/docs/memory-graph/examples.mdx b/apps/docs/memory-graph/examples.mdx
new file mode 100644
index 00000000..14d615d5
--- /dev/null
+++ b/apps/docs/memory-graph/examples.mdx
@@ -0,0 +1,407 @@
+---
+title: 'Examples'
+description: 'Common use cases and implementation patterns'
+---
+
+## With Pagination
+
+Load documents in chunks for better performance with large datasets.
+
+```tsx
+'use client';
+
+import { MemoryGraph } from '@supermemory/memory-graph';
+import type { DocumentWithMemories } from '@supermemory/memory-graph';
+import { useCallback, useEffect, useState } from 'react';
+
+export default function PaginatedGraph() {
+ const [documents, setDocuments] = useState<DocumentWithMemories[]>([]);
+ const [page, setPage] = useState(1);
+ const [hasMore, setHasMore] = useState(true);
+ const [isLoading, setIsLoading] = useState(true);
+ const [isLoadingMore, setIsLoadingMore] = useState(false);
+
+ // Initial load
+ useEffect(() => {
+ fetchPage(1, false);
+ }, []);
+
+ const fetchPage = async (pageNum: number, append: boolean) => {
+ if (pageNum === 1) {
+ setIsLoading(true);
+ } else {
+ setIsLoadingMore(true);
+ }
+
+ const res = await fetch(`/api/graph?page=${pageNum}&limit=100`);
+ const data = await res.json();
+
+ if (append) {
+ setDocuments(prev => [...prev, ...data.documents]);
+ } else {
+ setDocuments(data.documents);
+ }
+
+ setHasMore(data.pagination.currentPage < data.pagination.totalPages);
+ setIsLoading(false);
+ setIsLoadingMore(false);
+ };
+
+ const loadMore = useCallback(async () => {
+ if (!isLoadingMore && hasMore) {
+ const nextPage = page + 1;
+ setPage(nextPage);
+ await fetchPage(nextPage, true);
+ }
+ }, [page, hasMore, isLoadingMore]);
+
+ return (
+ <div style={{ height: '100vh' }}>
+ <MemoryGraph
+ documents={documents}
+ isLoading={isLoading}
+ isLoadingMore={isLoadingMore}
+ hasMore={hasMore}
+ totalLoaded={documents.length}
+ loadMoreDocuments={loadMore}
+ />
+ </div>
+ );
+}
+```
+
+## Highlighting Search Results
+
+```tsx
+'use client';
+
+import { MemoryGraph } from '@supermemory/memory-graph';
+import { useState } from 'react';
+
+export default function SearchableGraph() {
+ const [documents, setDocuments] = useState([]);
+ const [searchResults, setSearchResults] = useState<string[]>([]);
+ const [searchQuery, setSearchQuery] = useState('');
+
+ const handleSearch = async (query: string) => {
+ setSearchQuery(query);
+
+ if (!query) {
+ setSearchResults([]);
+ return;
+ }
+
+ const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
+ const data = await res.json();
+
+ // Extract document IDs from search results
+ const docIds = data.results.map(r => r.documentId);
+ setSearchResults(docIds);
+ };
+
+ return (
+ <div style={{ height: '100vh' }}>
+ <div style={{ position: 'absolute', top: 16, left: 16, zIndex: 10 }}>
+ <input
+ type="text"
+ placeholder="Search memories..."
+ value={searchQuery}
+ onChange={(e) => handleSearch(e.target.value)}
+ style={{
+ padding: '8px 12px',
+ borderRadius: 8,
+ border: '1px solid #333',
+ background: '#1a1a1a',
+ color: 'white',
+ }}
+ />
+ </div>
+
+ <MemoryGraph
+ documents={documents}
+ highlightDocumentIds={searchResults}
+ highlightsVisible={searchResults.length > 0}
+ />
+ </div>
+ );
+}
+```
+
+## Controlled Space Selection
+
+Control space filtering from outside the component.
+
+```tsx
+'use client';
+
+import { MemoryGraph } from '@supermemory/memory-graph';
+import { useState } from 'react';
+
+export default function ControlledSpaceGraph() {
+ const [documents, setDocuments] = useState([]);
+ const [selectedSpace, setSelectedSpace] = useState('all');
+
+ // Extract available spaces from documents
+ const spaces = Array.from(
+ new Set(
+ documents.flatMap(doc =>
+ doc.memoryEntries.map(m => m.spaceId || 'default')
+ )
+ )
+ );
+
+ return (
+ <div style={{ height: '100vh' }}>
+ <div style={{
+ position: 'absolute',
+ top: 16,
+ right: 16,
+ zIndex: 10,
+ background: '#1a1a1a',
+ padding: 16,
+ borderRadius: 8,
+ border: '1px solid #333',
+ }}>
+ <h3 style={{ margin: '0 0 12px 0', color: 'white' }}>Filters</h3>
+
+ <select
+ value={selectedSpace}
+ onChange={(e) => setSelectedSpace(e.target.value)}
+ style={{
+ padding: '8px 12px',
+ borderRadius: 6,
+ background: '#2a2a2a',
+ color: 'white',
+ border: '1px solid #444',
+ width: '100%',
+ }}
+ >
+ <option value="all">All Spaces</option>
+ {spaces.map(space => (
+ <option key={space} value={space}>{space}</option>
+ ))}
+ </select>
+
+ <button
+ onClick={() => setSelectedSpace('all')}
+ style={{
+ marginTop: 12,
+ padding: '6px 12px',
+ borderRadius: 6,
+ background: '#333',
+ color: 'white',
+ border: 'none',
+ width: '100%',
+ cursor: 'pointer',
+ }}
+ >
+ Reset
+ </button>
+ </div>
+
+ <MemoryGraph
+ documents={documents}
+ selectedSpace={selectedSpace}
+ onSpaceChange={setSelectedSpace}
+ showSpacesSelector={false}
+ />
+ </div>
+ );
+}
+```
+
+## Embedded Widget
+
+Use the consumer variant for embedded views with custom styling.
+
+```tsx
+'use client';
+
+import { MemoryGraph } from '@supermemory/memory-graph';
+
+export default function EmbeddedGraph({ documents }) {
+ return (
+ <div
+ style={{
+ height: 400,
+ borderRadius: 12,
+ overflow: 'hidden',
+ border: '1px solid #2a2a2a',
+ }}
+ >
+ <MemoryGraph
+ documents={documents}
+ variant="consumer"
+ showSpacesSelector={false}
+ >
+ <div style={{
+ textAlign: 'center',
+ padding: '2rem',
+ color: '#888',
+ }}>
+ <p>No memories to display</p>
+ </div>
+ </MemoryGraph>
+ </div>
+ );
+}
+```
+
+## With Loading States
+
+```tsx
+'use client';
+
+import { MemoryGraph } from '@supermemory/memory-graph';
+import { useEffect, useState } from 'react';
+
+export default function LoadingGraph() {
+ const [documents, setDocuments] = useState([]);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState<Error | null>(null);
+
+ useEffect(() => {
+ fetch('/api/graph')
+ .then(res => {
+ if (!res.ok) throw new Error('Failed to load graph');
+ return res.json();
+ })
+ .then(data => {
+ setDocuments(data.documents);
+ setIsLoading(false);
+ })
+ .catch(err => {
+ setError(err);
+ setIsLoading(false);
+ });
+ }, []);
+
+ return (
+ <div style={{ height: '100vh' }}>
+ <MemoryGraph
+ documents={documents}
+ isLoading={isLoading}
+ error={error}
+ >
+ <div style={{
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ height: '100%',
+ color: '#888',
+ }}>
+ <div>
+ <h2>Welcome to your Memory Graph</h2>
+ <p>Add some content to get started</p>
+ <button
+ style={{
+ marginTop: 16,
+ padding: '8px 16px',
+ borderRadius: 6,
+ background: '#2563eb',
+ color: 'white',
+ border: 'none',
+ cursor: 'pointer',
+ }}
+ onClick={() => window.location.href = '/add-memory'}
+ >
+ Add First Memory
+ </button>
+ </div>
+ </div>
+ </MemoryGraph>
+ </div>
+ );
+}
+```
+
+## React Server Component
+
+```tsx
+// Next.js App Router with Server Component
+import { MemoryGraphClient } from './memory-graph-client';
+
+async function getGraphData() {
+ const res = await fetch('https://api.supermemory.ai/v3/documents/documents', {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ page: 1,
+ limit: 500,
+ sort: 'createdAt',
+ order: 'desc',
+ }),
+ cache: 'no-store', // or use revalidation
+ });
+
+ return res.json();
+}
+
+export default async function GraphPage() {
+ const data = await getGraphData();
+
+ return <MemoryGraphClient initialDocuments={data.documents} />;
+}
+```
+
+```tsx
+// memory-graph-client.tsx
+'use client';
+
+import { MemoryGraph } from '@supermemory/memory-graph';
+import type { DocumentWithMemories } from '@supermemory/memory-graph';
+
+interface Props {
+ initialDocuments: DocumentWithMemories[];
+}
+
+export function MemoryGraphClient({ initialDocuments }: Props) {
+ return (
+ <div style={{ height: '100vh' }}>
+ <MemoryGraph
+ documents={initialDocuments}
+ isLoading={false}
+ />
+ </div>
+ );
+}
+```
+
+## Mobile-Responsive Layout
+
+```tsx
+'use client';
+
+import { MemoryGraph } from '@supermemory/memory-graph';
+import { useState, useEffect } from 'react';
+
+export default function ResponsiveGraph({ documents }) {
+ const [isMobile, setIsMobile] = useState(false);
+
+ useEffect(() => {
+ const checkMobile = () => {
+ setIsMobile(window.innerWidth < 768);
+ };
+
+ checkMobile();
+ window.addEventListener('resize', checkMobile);
+ return () => window.removeEventListener('resize', checkMobile);
+ }, []);
+
+ return (
+ <div style={{
+ height: isMobile ? '60vh' : '100vh',
+ width: '100%',
+ }}>
+ <MemoryGraph
+ documents={documents}
+ variant={isMobile ? 'consumer' : 'console'}
+ showSpacesSelector={!isMobile}
+ />
+ </div>
+ );
+}
+```
diff --git a/apps/docs/memory-graph/installation.mdx b/apps/docs/memory-graph/installation.mdx
new file mode 100644
index 00000000..0051825f
--- /dev/null
+++ b/apps/docs/memory-graph/installation.mdx
@@ -0,0 +1,28 @@
+---
+title: 'Installation'
+description: 'Install and set up the Memory Graph component'
+---
+
+## Installation
+
+Install the package using your preferred package manager:
+
+```bash npm
+npm install @supermemory/memory-graph
+```
+
+## Requirements
+
+- **React**: 18.0.0 or higher
+- **react-dom**: 18.0.0 or higher
+
+## Next Steps
+
+<CardGroup cols={2}>
+ <Card title="Quick Start" icon="rocket" href="/memory-graph/quickstart">
+ Get the graph running with real data
+ </Card>
+ <Card title="API Reference" icon="code" href="/memory-graph/api-reference">
+ Explore all available props and types
+ </Card>
+</CardGroup>
diff --git a/apps/docs/memory-graph/npm.mdx b/apps/docs/memory-graph/npm.mdx
new file mode 100644
index 00000000..73185178
--- /dev/null
+++ b/apps/docs/memory-graph/npm.mdx
@@ -0,0 +1,5 @@
+---
+title: "NPM link"
+url: "https://www.npmjs.com/package/@supermemory/memory-graph"
+icon: npm
+---
diff --git a/apps/docs/memory-graph/overview.mdx b/apps/docs/memory-graph/overview.mdx
new file mode 100644
index 00000000..c3260d21
--- /dev/null
+++ b/apps/docs/memory-graph/overview.mdx
@@ -0,0 +1,38 @@
+---
+title: 'Overview'
+description: 'Interactive visualization for documents, memories and connections'
+---
+
+## What is Memory Graph?
+
+Memory Graph is a React component that visualizes your Supermemory documents and memories as an interactive network. Documents appear as rectangular nodes, memories as hexagonal nodes, and connections between them show relationships and similarity.
+
+The graph renders using Canvas 2D, providing smooth interactions with hundreds of nodes through pan, zoom, and drag operations.
+
+## When to Use It
+
+Use Memory Graph when you need to:
+
+- **Visualize knowledge graphs** - Show how documents and memories connect
+- **Navigate memory spaces** - Filter and browse by workspace or tag
+- **Create memory browsers** - Give users a visual overview of their stored content
+
+## Performance
+
+The graph handles hundreds of nodes efficiently through:
+- Canvas-based rendering (not DOM elements)
+- Viewport culling (only draws visible nodes)
+- Level-of-detail optimization (simplifies rendering when zoomed out)
+- Change-based rendering (only redraws when state changes)
+- Throttled viewport calculations
+
+For very large datasets (1000+ documents), use pagination to load data in chunks.
+
+## Browser Support
+
+Works in all modern browsers that support:
+- Canvas 2D API
+- ES2020 JavaScript
+- CSS custom properties
+
+Tested on Chrome, Firefox, Safari, and Edge (latest versions).
diff --git a/apps/docs/memory-graph/quickstart.mdx b/apps/docs/memory-graph/quickstart.mdx
new file mode 100644
index 00000000..d05a0925
--- /dev/null
+++ b/apps/docs/memory-graph/quickstart.mdx
@@ -0,0 +1,207 @@
+---
+title: 'Quick Start'
+description: 'Get Memory Graph running in 2 minutes'
+---
+
+## Basic Setup
+
+Here's a minimal example to get the graph running:
+
+```tsx
+'use client'; // For Next.js App Router
+
+import { MemoryGraph } from '@supermemory/memory-graph';
+import type { DocumentWithMemories } from '@supermemory/memory-graph';
+import { useEffect, useState } from 'react';
+
+export default function GraphPage() {
+ const [documents, setDocuments] = useState<DocumentWithMemories[]>([]);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState<Error | null>(null);
+
+ useEffect(() => {
+ fetch('/api/graph')
+ .then(res => res.json())
+ .then(data => {
+ setDocuments(data.documents);
+ setIsLoading(false);
+ })
+ .catch(err => {
+ setError(err);
+ setIsLoading(false);
+ });
+ }, []);
+
+ return (
+ <div style={{ height: '100vh' }}>
+ <MemoryGraph
+ documents={documents}
+ isLoading={isLoading}
+ error={error}
+ variant="console"
+ />
+ </div>
+ );
+}
+```
+
+## Backend API Route
+
+Create an API route to fetch documents from Supermemory:
+
+<CodeGroup>
+
+```typescript Next.js App Router
+// app/api/graph/route.ts
+import { NextResponse } from 'next/server';
+
+export async function GET() {
+ const response = await fetch('https://api.supermemory.ai/v3/documents/documents', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
+ },
+ body: JSON.stringify({
+ page: 1,
+ limit: 500,
+ sort: 'createdAt',
+ order: 'desc',
+ }),
+ });
+
+ const data = await response.json();
+ return NextResponse.json(data);
+}
+```
+
+```typescript Next.js Pages Router
+// pages/api/graph.ts
+import type { NextApiRequest, NextApiResponse } from 'next';
+
+export default async function handler(
+ req: NextApiRequest,
+ res: NextApiResponse
+) {
+ const response = await fetch('https://api.supermemory.ai/v3/documents/documents', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
+ },
+ body: JSON.stringify({
+ page: 1,
+ limit: 500,
+ sort: 'createdAt',
+ order: 'desc',
+ }),
+ });
+
+ const data = await response.json();
+ res.json(data);
+}
+```
+
+```javascript Express
+// routes/graph.js
+app.get('/api/graph', async (req, res) => {
+ const response = await fetch('https://api.supermemory.ai/v3/documents/documents', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
+ },
+ body: JSON.stringify({
+ page: 1,
+ limit: 500,
+ sort: 'createdAt',
+ order: 'desc',
+ }),
+ });
+
+ const data = await response.json();
+ res.json(data);
+});
+```
+
+</CodeGroup>
+
+<Warning>
+ Never expose your Supermemory API key to the client. Always fetch data through your backend.
+</Warning>
+
+## Environment Variables
+
+Add your API key to `.env.local`:
+
+```bash
+SUPERMEMORY_API_KEY=your_api_key_here
+```
+
+Get your API key from the [Supermemory dashboard](https://console.supermemory.ai).
+
+## Common Customizations
+
+### Embedded Mode
+
+For a widget-style view, use the consumer variant:
+
+```tsx
+<MemoryGraph
+ documents={documents}
+ isLoading={isLoading}
+ variant="consumer"
+/>
+```
+
+### CSS Import
+
+The component includes bundled styles. You don't need to import CSS separately. Styles are automatically injected when the component mounts.
+
+If you want explicit control, you can import the stylesheet:
+
+```typescript
+import '@supermemory/memory-graph/styles.css';
+```
+
+<Note>
+ The automatic CSS injection works for most setups. Only use the explicit import if you need custom control over style loading order.
+</Note>
+
+
+### Custom Empty State
+
+Show custom content when no documents exist:
+
+```tsx
+<MemoryGraph
+ documents={documents}
+ isLoading={isLoading}
+>
+ <div style={{ textAlign: 'center', padding: '2rem' }}>
+ <h2>No memories yet</h2>
+ <p>Add content to see your knowledge graph</p>
+ </div>
+</MemoryGraph>
+```
+
+### Hide Space Selector
+
+```tsx
+<MemoryGraph
+ documents={documents}
+ isLoading={isLoading}
+ showSpacesSelector={false}
+/>
+```
+
+## Next Steps
+
+<CardGroup cols={2}>
+ <Card title="Examples" icon="code" href="/memory-graph/examples">
+ See more usage examples
+ </Card>
+ <Card title="API Reference" icon="book" href="/memory-graph/api-reference">
+ Full API documentation
+ </Card>
+</CardGroup>
diff --git a/packages/memory-graph/README.md b/packages/memory-graph/README.md
index eae06940..83710f5a 100644
--- a/packages/memory-graph/README.md
+++ b/packages/memory-graph/README.md
@@ -1,378 +1,94 @@
# @supermemory/memory-graph
-> Interactive graph visualization component for Supermemory - visualize and explore your memory connections
+Interactive graph visualization for documents and their memory connections.
[![npm version](https://img.shields.io/npm/v/@supermemory/memory-graph.svg)](https://www.npmjs.com/package/@supermemory/memory-graph)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
-## Features
-
-- **WebGL-powered rendering** - Smooth performance with hundreds of nodes
-- **Interactive exploration** - Pan, zoom, drag nodes, and explore connections
-- **Semantic connections** - Visualizes relationships based on content similarity
-- **Space filtering with search** - Dynamically search and filter by spaces/tags
-- **Memory limit control** - Limit memories per document (50-3000) for performance
-- **Controlled/uncontrolled modes** - Flexible state management for integration
-- **Responsive design** - Works seamlessly on mobile and desktop
-- **Zero configuration** - Works out of the box with automatic CSS injection
-- **Lightweight** - Tree-shakeable and optimized bundle
-- **TypeScript** - Full TypeScript support with exported types
-
## Installation
```bash
npm install @supermemory/memory-graph
# or
-yarn add @supermemory/memory-graph
+bun add @supermemory/memory-graph
# or
pnpm add @supermemory/memory-graph
-# or
-bun add @supermemory/memory-graph
```
## Quick Start
-The component accepts document data directly - you fetch the data from your backend, which proxies requests to the Supermemory API with proper authentication.
-
```tsx
-import { MemoryGraph } from '@supermemory/memory-graph'
-import type { DocumentWithMemories } from '@supermemory/memory-graph'
+import { MemoryGraph } from '@supermemory/memory-graph';
+import type { DocumentWithMemories } from '@supermemory/memory-graph';
function App() {
- const [documents, setDocuments] = useState<DocumentWithMemories[]>([])
- const [isLoading, setIsLoading] = useState(true)
- const [error, setError] = useState<Error | null>(null)
+ const [documents, setDocuments] = useState<DocumentWithMemories[]>([]);
+ const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
- // Fetch from YOUR backend (which proxies to Supermemory API)
- fetch('/api/supermemory-graph')
+ fetch('/api/graph')
.then(res => res.json())
.then(data => {
- setDocuments(data.documents)
- setIsLoading(false)
- })
- .catch(err => {
- setError(err)
- setIsLoading(false)
- })
- }, [])
+ setDocuments(data.documents);
+ setIsLoading(false);
+ });
+ }, []);
return (
- <MemoryGraph
- documents={documents}
- isLoading={isLoading}
- error={error}
- />
- )
-}
-```
-
-## Backend Proxy Example
-
-Create an API route in your backend that authenticates and proxies requests to Supermemory:
-
-### Next.js API Route
-
-```typescript
-// app/api/supermemory-graph/route.ts
-import { NextResponse } from 'next/server'
-
-export async function GET(request: Request) {
- // Add your own auth check here
- const user = await getAuthenticatedUser(request)
- if (!user) {
- return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
- }
-
- const response = await fetch('https://api.supermemory.ai/v3/documents/documents', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
- },
- body: JSON.stringify({
- page: 1,
- limit: 500,
- sort: 'createdAt',
- order: 'desc',
- }),
- })
-
- const data = await response.json()
- return NextResponse.json(data)
-}
-```
-
-## API Reference
-
-### Props
-
-| Prop | Type | Default | Description |
-|------|------|---------|-------------|
-| `documents` | `DocumentWithMemories[]` | **required** | Array of documents to display |
-| `isLoading` | `boolean` | `false` | Whether data is currently loading |
-| `error` | `Error \| null` | `null` | Error that occurred during fetching |
-| `variant` | `"console" \| "consumer"` | `"console"` | Visual variant |
-| `showSpacesSelector` | `boolean` | Based on variant | Show/hide the spaces filter |
-| `children` | `ReactNode` | - | Content to show when no documents |
-| `highlightDocumentIds` | `string[]` | `[]` | Document IDs to highlight |
-| `highlightsVisible` | `boolean` | `true` | Whether highlights are visible |
-
-### Space & Memory Control Props (Optional)
-
-| Prop | Type | Default | Description |
-|------|------|---------|-------------|
-| `selectedSpace` | `string` | `"all"` | Currently selected space (controlled) |
-| `onSpaceChange` | `(spaceId: string) => void` | - | Callback when space changes |
-| `onSearchSpaces` | `(query: string) => Promise<string[]>` | - | Async space search function |
-| `memoryLimit` | `number` | `500` | Max memories per document when space selected |
-| `onMemoryLimitChange` | `(limit: number) => void` | - | Callback when limit changes |
-| `isExperimental` | `boolean` | `false` | Enable experimental features |
-
-### Pagination Props (Optional)
-
-For large datasets, you can implement pagination:
-
-| Prop | Type | Default | Description |
-|------|------|---------|-------------|
-| `isLoadingMore` | `boolean` | `false` | Whether loading more data |
-| `hasMore` | `boolean` | `false` | Whether more data is available |
-| `totalLoaded` | `number` | `documents.length` | Total documents loaded |
-| `loadMoreDocuments` | `() => Promise<void>` | - | Callback to load more |
-
-### Types
-
-```typescript
-import type {
- DocumentWithMemories,
- MemoryEntry,
- DocumentsResponse,
- MemoryGraphProps,
- MemoryLimit,
- MemoryCountSelectorProps,
- GraphNode,
- GraphEdge,
- MemoryRelation
-} from '@supermemory/memory-graph'
-
-// Memory limit can be one of these values
-type MemoryLimit = 50 | 100 | 250 | 500 | 1000 | 2000 | 3000
-```
-
-## Advanced Usage
-
-### With Pagination
-
-```tsx
-import { MemoryGraph } from '@supermemory/memory-graph'
-
-function GraphWithPagination() {
- const [documents, setDocuments] = useState([])
- const [page, setPage] = useState(1)
- const [hasMore, setHasMore] = useState(true)
- const [isLoadingMore, setIsLoadingMore] = useState(false)
-
- const loadMore = async () => {
- setIsLoadingMore(true)
- const res = await fetch(`/api/supermemory-graph?page=${page + 1}`)
- const data = await res.json()
- setDocuments(prev => [...prev, ...data.documents])
- setHasMore(data.pagination.currentPage < data.pagination.totalPages)
- setPage(p => p + 1)
- setIsLoadingMore(false)
- }
-
- return (
- <MemoryGraph
- documents={documents}
- isLoading={isLoading}
- isLoadingMore={isLoadingMore}
- hasMore={hasMore}
- loadMoreDocuments={loadMore}
- totalLoaded={documents.length}
- />
- )
-}
-```
-
-### Custom Empty State
-
-```tsx
-<MemoryGraph documents={[]} isLoading={false}>
- <div className="empty-state">
- <h2>No memories yet</h2>
- <p>Start adding content to see your knowledge graph</p>
- </div>
-</MemoryGraph>
-```
-
-### Controlled Space Selection & Memory Limiting
-
-Control the selected space and memory limit externally for integration with your app's state management:
-
-```tsx
-import { MemoryGraph } from '@supermemory/memory-graph'
-
-function ControlledGraph() {
- const [selectedSpace, setSelectedSpace] = useState("all")
- const [memoryLimit, setMemoryLimit] = useState(500)
- const [searchResults, setSearchResults] = useState([])
-
- // Handle space search via your API
- const handleSpaceSearch = async (query: string) => {
- const response = await fetch(`/api/spaces/search?q=${query}`)
- const spaces = await response.json()
- setSearchResults(spaces)
- return spaces
- }
-
- return (
- <div>
- {/* Display current state */}
- <div className="controls">
- <p>Selected Space: {selectedSpace}</p>
- <p>Memory Limit: {memoryLimit}</p>
- <button onClick={() => {
- setSelectedSpace("all")
- setMemoryLimit(500)
- }}>
- Reset Filters
- </button>
- </div>
-
- {/* Controlled graph */}
+ <div style={{ height: '100vh' }}>
<MemoryGraph
documents={documents}
- selectedSpace={selectedSpace}
- onSpaceChange={setSelectedSpace}
- onSearchSpaces={handleSpaceSearch}
- memoryLimit={memoryLimit}
- onMemoryLimitChange={setMemoryLimit}
+ isLoading={isLoading}
variant="console"
- showSpacesSelector={true}
/>
</div>
- )
-}
-```
-
-### Uncontrolled Mode (Automatic)
-
-If you don't provide `selectedSpace` or `memoryLimit` props, the component manages its own state:
-
-```tsx
-<MemoryGraph
- documents={documents}
- // Component manages space selection and memory limit internally
- onSearchSpaces={handleSpaceSearch} // Still can provide search function
- showSpacesSelector={true}
-/>
-```
-
-### Space Search Integration
-
-Implement server-side space search for dynamic filtering:
-
-```tsx
-// Frontend
-const handleSpaceSearch = async (query: string): Promise<string[]> => {
- const response = await fetch('/api/spaces/search', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ query })
- })
- return response.json()
-}
-
-<MemoryGraph
- documents={documents}
- onSearchSpaces={handleSpaceSearch}
- showSpacesSelector={true}
-/>
-
-// Backend (Next.js example)
-// app/api/spaces/search/route.ts
-export async function POST(request: Request) {
- const { query } = await request.json()
-
- const response = await fetch('https://api.supermemory.ai/v3/search/spaces', {
- method: 'GET',
- headers: {
- 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
- },
- params: { q: query }
- })
-
- return response.json()
+ );
}
```
-### Variants
-
-The `variant` prop controls the visual layout and initial viewport settings:
-
-| Variant | Initial Zoom | Spaces Selector | Legend Position | Use Case |
-|---------|-------------|-----------------|-----------------|----------|
-| `console` | 0.8 | Shown | Bottom-right | Full-page dashboard views |
-| `consumer` | 0.5 | Hidden | Top-right | Embedded/widget views |
+## Features
-```tsx
-// Full dashboard view
-<MemoryGraph
- documents={documents}
- variant="console"
-/>
+- **Interactive canvas visualization** - Pan, zoom, and drag nodes using Canvas 2D rendering
+- **Document and memory nodes** - Documents as rectangles, memories as hexagons
+- **Relationship visualization** - Edges show document similarity and memory version chains
+- **Space filtering** - Filter by workspace or view all memories
+- **Two variants** - Full-featured console mode or embedded consumer mode
+- **Pagination support** - Load more documents on demand
+- **TypeScript support** - Full type definitions included
-// Embedded widget
-<MemoryGraph
- documents={documents}
- variant="consumer"
-/>
-```
+## Essential Props
-## Interactive Controls
+| Prop | Type | Description |
+|------|------|-------------|
+| `documents` | `DocumentWithMemories[]` | Array of documents with their memory entries |
+| `isLoading` | `boolean` | Show loading state |
+| `variant` | `"console" \| "consumer"` | Display mode (default: "console") |
+| `error` | `Error \| null` | Error to display |
+| `loadMoreDocuments` | `() => Promise<void>` | Function to load more data |
+| `highlightDocumentIds` | `string[]` | IDs of documents to highlight |
-- **Pan**: Click and drag the background
-- **Zoom**: Mouse wheel or pinch on mobile
-- **Select Node**: Click on any document or memory
-- **Drag Nodes**: Click and drag individual nodes
-- **Fit to View**: Auto-fit button to center all content
-- **Space Filter**: Click the space selector to filter by space
-- **Space Search**: Type in the search box and press Enter to find spaces
-- **Memory Limit**: Select a limit (50-3K) when filtering by space
+## Documentation
-## Browser Support
+Full documentation available at [docs.supermemory.ai](https://docs.supermemory.ai):
-- Chrome/Edge (latest)
-- Firefox (latest)
-- Safari (latest)
-- Mobile browsers with WebGL support
+- [Overview](https://docs.supermemory.ai/memory-graph/overview) - What it is and when to use it
+- [Installation](https://docs.supermemory.ai/memory-graph/installation) - Setup and requirements
+- [Quick Start](https://docs.supermemory.ai/memory-graph/quickstart) - Get running in 2 minutes
+- [API Reference](https://docs.supermemory.ai/memory-graph/api-reference) - Complete API documentation
+- [Examples](https://docs.supermemory.ai/memory-graph/examples) - Common use cases
+- [Troubleshooting](https://docs.supermemory.ai/memory-graph/troubleshooting) - Common issues
## Requirements
- React 18+
-- Modern browser with WebGL support
-
-## Development
-
-```bash
-# Install dependencies
-bun install
-
-# Build the package
-bun run build
-
-# Watch mode for development
-bun run dev
-
-# Type checking
-bun run check-types
-```
+- Modern browser
## License
MIT
-## Support
+## Links
-- Issues: [GitHub Issues](https://github.com/supermemoryai/supermemory/issues)
+- [GitHub](https://github.com/supermemoryai/supermemory/tree/main/packages/memory-graph)
+- [Issues](https://github.com/supermemoryai/supermemory/issues)
+- [Supermemory](https://supermemory.ai)