diff options
| author | Vidya Rupak <[email protected]> | 2025-12-21 13:33:50 -0700 |
|---|---|---|
| committer | Vidya Rupak <[email protected]> | 2025-12-21 13:33:50 -0700 |
| commit | c07cdf53590366b860a2c0a4cd5a9d7e3aed742e (patch) | |
| tree | 6679072902935d23631f49a28c01563acea24079 | |
| parent | updated color scheme for better visual clarity (diff) | |
| download | supermemory-c07cdf53590366b860a2c0a4cd5a9d7e3aed742e.tar.xz supermemory-c07cdf53590366b860a2c0a4cd5a9d7e3aed742e.zip | |
refactor: replaced concentric ring layout with physics driven approach.
| -rw-r--r-- | packages/memory-graph/src/hooks/use-force-simulation.ts | 8 | ||||
| -rw-r--r-- | packages/memory-graph/src/hooks/use-graph-data.ts | 60 |
2 files changed, 21 insertions, 47 deletions
diff --git a/packages/memory-graph/src/hooks/use-force-simulation.ts b/packages/memory-graph/src/hooks/use-force-simulation.ts index 3b5bfe97..f5774d12 100644 --- a/packages/memory-graph/src/hooks/use-force-simulation.ts +++ b/packages/memory-graph/src/hooks/use-force-simulation.ts @@ -98,9 +98,11 @@ export function useForceSimulation( // Store reference simulationRef.current = simulation - // Stop simulation immediately after creation - // It will only run when explicitly reheated (on drag) - simulation.stop() + // Quick pre-settle to avoid initial chaos, then animate the rest + // This gives best of both worlds: fast initial render + smooth settling + simulation.alpha(1) + for (let i = 0; i < 50; ++i) simulation.tick() // Just 50 ticks = ~5-10ms + simulation.alphaTarget(0).restart() // Continue animating to full stability } // Cleanup on unmount diff --git a/packages/memory-graph/src/hooks/use-graph-data.ts b/packages/memory-graph/src/hooks/use-graph-data.ts index 2fd6009c..49d37594 100644 --- a/packages/memory-graph/src/hooks/use-graph-data.ts +++ b/packages/memory-graph/src/hooks/use-graph-data.ts @@ -144,7 +144,7 @@ export function useGraphData( }) // Enhanced Layout with Space Separation - const { centerX, centerY, clusterRadius, spaceSpacing, documentSpacing } = + const { centerX, centerY, clusterRadius } = LAYOUT_CONSTANTS /* 1. Build DOCUMENT nodes with space-aware clustering */ @@ -152,39 +152,17 @@ export function useGraphData( let spaceIndex = 0 documentsBySpace.forEach((spaceDocs) => { - const spaceAngle = (spaceIndex / documentsBySpace.size) * Math.PI * 2 - const spaceOffsetX = Math.cos(spaceAngle) * spaceSpacing - const spaceOffsetY = Math.sin(spaceAngle) * spaceSpacing - const spaceCenterX = centerX + spaceOffsetX - const spaceCenterY = centerY + spaceOffsetY - spaceDocs.forEach((doc, docIndex) => { - // Create proper circular layout with concentric rings - const docsPerRing = 6 // Start with 6 docs in inner ring - let currentRing = 0 - let docsInCurrentRing = docsPerRing - let totalDocsInPreviousRings = 0 - - // Find which ring this document belongs to - while (totalDocsInPreviousRings + docsInCurrentRing <= docIndex) { - totalDocsInPreviousRings += docsInCurrentRing - currentRing++ - docsInCurrentRing = docsPerRing + currentRing * 4 // Each ring has more docs - } - - // Position within the ring - const positionInRing = docIndex - totalDocsInPreviousRings - const angleInRing = (positionInRing / docsInCurrentRing) * Math.PI * 2 + // Simple grid-like layout that physics will naturally organize + // Start documents near the center with some random offset + const gridSize = Math.ceil(Math.sqrt(spaceDocs.length)) + const row = Math.floor(docIndex / gridSize) + const col = docIndex % gridSize - // Radius increases significantly with each ring - const baseRadius = documentSpacing * 0.8 - const radius = - currentRing === 0 - ? baseRadius - : baseRadius + currentRing * documentSpacing * 1.2 - - const defaultX = spaceCenterX + Math.cos(angleInRing) * radius - const defaultY = spaceCenterY + Math.sin(angleInRing) * radius + // Loose grid spacing - physics will organize it better + const spacing = 200 + const defaultX = centerX + (col - gridSize / 2) * spacing + (Math.random() - 0.5) * 50 + const defaultY = centerY + (row - gridSize / 2) * spacing + (Math.random() - 0.5) * 50 const customPos = nodePositions.get(doc.id) @@ -232,19 +210,13 @@ export function useGraphData( const memoryId = `${memory.id}` const customMemPos = nodePositions.get(memoryId) - const clusterAngle = (memIndex / doc.memoryEntries.length) * Math.PI * 2 - const variation = Math.sin(memIndex * 2.5) * 0.3 + 0.7 - const distance = clusterRadius * variation - - const seed = - memIndex * 12345 + Number.parseInt(docNode.id.slice(0, 6), 36) - const offsetX = Math.sin(seed) * 0.5 * 40 - const offsetY = Math.cos(seed) * 0.5 * 40 + // Simple circular positioning around parent doc + // Physics will naturally cluster them better + const angle = (memIndex / doc.memoryEntries.length) * Math.PI * 2 + const distance = clusterRadius * 1 // Closer to parent, let physics separate - const defaultMemX = - docNode.x + Math.cos(clusterAngle) * distance + offsetX - const defaultMemY = - docNode.y + Math.sin(clusterAngle) * distance + offsetY + const defaultMemX = docNode.x + Math.cos(angle) * distance + const defaultMemY = docNode.y + Math.sin(angle) * distance // Calculate final position let finalMemX = defaultMemX |