Skip to content

Commit c7d90e6

Browse files
Dhravyaclaude
authored andcommitted
fix: memory graph progressively loads all data and remove background
- Switch to infinite query with viewport-triggered pagination (loads more when user zooms out 3x past node bounds) - Remove maxNodes cap so all data renders - Remove background color and dot pattern from graph - Make document-memory edges light grey Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5b0a1b8 commit c7d90e6

File tree

6 files changed

+58
-44
lines changed

6 files changed

+58
-44
lines changed

apps/web/components/graph-layout-view.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const GraphLayoutView = memo<GraphLayoutViewProps>(({ isChatOpen }) => {
4242
variant="consumer"
4343
highlightDocumentIds={allHighlightDocumentIds}
4444
highlightsVisible={isChatOpen}
45-
maxNodes={200}
45+
maxNodes={undefined}
4646
canvasRef={canvasRef}
4747
/>
4848
</div>

apps/web/components/memory-graph/hooks/use-graph-api.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,7 @@ export function useGraphApi(options: UseGraphApiOptions = {}) {
126126
},
127127
getNextPageParam: (lastPage) => {
128128
const { currentPage, totalPages } = lastPage.pagination
129-
if (currentPage < totalPages) {
130-
return currentPage + 1
131-
}
132-
return undefined
129+
return currentPage < totalPages ? currentPage + 1 : undefined
133130
},
134131
staleTime: 30 * 1000,
135132
enabled,

apps/web/components/memory-graph/memory-graph-wrapper.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function MemoryGraph({
2727
error: externalError = null,
2828
variant = "console",
2929
containerTags,
30-
maxNodes = 200,
30+
maxNodes,
3131
canvasRef,
3232
...rest
3333
}: MemoryGraphWrapperProps) {
@@ -59,7 +59,7 @@ export function MemoryGraph({
5959
})
6060

6161
return (
62-
<div ref={containerRef} className="w-full h-full">
62+
<div ref={containerRef} className="w-full h-full [&>div]:!bg-none">
6363
<MemoryGraphBase
6464
documents={documents}
6565
isLoading={externalIsLoading || apiIsLoading}
@@ -71,6 +71,10 @@ export function MemoryGraph({
7171
maxNodes={maxNodes}
7272
canvasRef={canvasRef}
7373
totalCount={totalCount}
74+
colors={{
75+
bg: "transparent",
76+
edgeDerives: "#9ca3af",
77+
} as any}
7478
{...rest}
7579
>
7680
{children}

apps/web/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@
4444
"@react-router/fs-routes": "^7.6.2",
4545
"@react-router/node": "^7.6.2",
4646
"@react-router/serve": "^7.6.2",
47+
"@repo/lib": "workspace:*",
48+
"@repo/validation": "workspace:*",
4749
"@sentry/nextjs": "^10.33.0",
50+
"@supermemory/memory-graph": "^0.2.0",
4851
"@tailwindcss/typography": "^0.5.16",
4952
"@tanstack/react-form": "^1.12.4",
5053
"@tanstack/react-query": "^5.90.14",
@@ -104,10 +107,7 @@
104107
"tw-animate-css": "^1.3.4",
105108
"use-debounce": "^10.1.0",
106109
"vaul": "^1.1.2",
107-
"zustand": "^5.0.7",
108-
"@repo/lib": "workspace:*",
109-
"@repo/validation": "workspace:*",
110-
"@supermemory/memory-graph": "workspace:*"
110+
"zustand": "^5.0.7"
111111
},
112112
"devDependencies": {
113113
"@biomejs/biome": "^2.2.2",

bun.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/memory-graph/src/components/memory-graph.tsx

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -185,17 +185,56 @@ export function MemoryGraph({
185185
// Drag end handled by InputHandler
186186
}, [])
187187

188+
// Load more when user zooms out enough that visible area dwarfs the node extent
189+
const loadMoreTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
190+
const loadMoreRef = useRef({ hasMore, isLoadingMore, onLoadMore })
191+
loadMoreRef.current = { hasMore, isLoadingMore, onLoadMore }
192+
188193
const handleViewportChange = useCallback(
189194
(zoom: number, popoverVisible: boolean) => {
190195
setZoomDisplay(Math.round(zoom * 100))
191-
// Only increment viewportVersion (which triggers popover repositioning
192-
// via activePopoverPosition useMemo) when a popover is actually visible.
193-
// This avoids 60fps React reconciliation during plain panning/zooming.
194196
if (popoverVisible) {
195197
setViewportVersion((v) => v + 1)
196198
}
199+
200+
const { hasMore: more, isLoadingMore: loading, onLoadMore: load } = loadMoreRef.current
201+
if (!more || loading || !load || !viewportRef.current) return
202+
203+
const vp = viewportRef.current
204+
const currentNodes = nodes
205+
if (currentNodes.length === 0) return
206+
207+
const topLeft = vp.screenToWorld(0, 0)
208+
const bottomRight = vp.screenToWorld(containerSize.width, containerSize.height)
209+
const viewW = bottomRight.x - topLeft.x
210+
const viewH = bottomRight.y - topLeft.y
211+
212+
let minX = Infinity
213+
let minY = Infinity
214+
let maxX = -Infinity
215+
let maxY = -Infinity
216+
for (const n of currentNodes) {
217+
if (n.x < minX) minX = n.x
218+
if (n.y < minY) minY = n.y
219+
if (n.x > maxX) maxX = n.x
220+
if (n.y > maxY) maxY = n.y
221+
}
222+
223+
const nodeW = maxX - minX || 1
224+
const nodeH = maxY - minY || 1
225+
226+
// Only trigger when the visible area is 3x larger than the node extent
227+
// (i.e. user has zoomed out significantly past the data)
228+
const zoomedOut = viewW > nodeW * 3 || viewH > nodeH * 3
229+
230+
if (zoomedOut && !loadMoreTimerRef.current) {
231+
loadMoreTimerRef.current = setTimeout(() => {
232+
loadMoreTimerRef.current = null
233+
loadMoreRef.current.onLoadMore?.()
234+
}, 500)
235+
}
197236
},
198-
[],
237+
[nodes, containerSize.width, containerSize.height],
199238
)
200239

201240
// Navigation
@@ -509,7 +548,7 @@ export function MemoryGraph({
509548
display: "flex",
510549
alignItems: "center",
511550
justifyContent: "center",
512-
backgroundColor: colors.bg,
551+
backgroundColor: "transparent",
513552
borderRadius: 12,
514553
}
515554

@@ -535,9 +574,7 @@ export function MemoryGraph({
535574
height: "100%",
536575
borderRadius: 12,
537576
overflow: "hidden",
538-
backgroundColor: colors.bg,
539-
backgroundImage: `radial-gradient(circle, ${colors.textMuted} 0.5px, transparent 0.5px)`,
540-
backgroundSize: "16px 16px",
577+
backgroundColor: "transparent",
541578
}
542579

543580
const canvasContainerStyle: React.CSSProperties = {
@@ -576,30 +613,6 @@ export function MemoryGraph({
576613
colors={colors}
577614
/>
578615

579-
{!isLoading && hasMore && onLoadMore && (
580-
<button
581-
type="button"
582-
onClick={onLoadMore}
583-
style={{
584-
position: "absolute",
585-
top: 16,
586-
right: 16,
587-
zIndex: 30,
588-
borderRadius: 12,
589-
border: `1px solid ${colors.controlBorder}`,
590-
backgroundColor: colors.controlBg,
591-
color: colors.textSecondary,
592-
paddingLeft: 16,
593-
paddingRight: 16,
594-
paddingTop: 8,
595-
paddingBottom: 8,
596-
fontSize: 13,
597-
cursor: "pointer",
598-
}}
599-
>
600-
{isLoadingMore ? "Loading..." : "Load more"}
601-
</button>
602-
)}
603616

604617
{!isLoading && !nodes.some((n) => n.type === "document") && children && (
605618
<div style={emptyStateStyle}>{children}</div>

0 commit comments

Comments
 (0)