- Derives: soft blue/steel (#7094B8) -- cool desaturated blue for structural
doc-to-memory links, visible but not attention-grabbing
- Updates: purple (#A78BFA) -- unchanged, glow + arrowheads for version chains
- Extends: sky blue (#38BDF8) -- bright blue with glow + dashed pattern for
cross-references between memories
Previously derives and extends both used similar teal/cyan colors, making
extends edges invisible among the 220 derives edges. Now each type has a
completely different appearance (steel blue vs purple vs bright cyan dashed).
Also fixed extends edge zoom culling threshold from 0.3 to 0.08 -- extends
edges were being hidden at normal zoom levels (10-26%).
All edge types get glow for luminous aesthetic. Extends edges use dashed
lines matching the legend icon.
- All 107 tests pass, types clean
Previously maxNodes limited only the number of documents, ignoring their
memories. With ~2-6 memories per document, setting maxNodes=200 could result
in 600-1400+ actual nodes, defeating the performance guard.
Now iterates documents and accumulates total node count (1 doc + N memories),
stopping when the limit would be exceeded. This matches the documented
behavior of 'Max nodes to display'.
Addresses Sentry review comment on memory-graph.tsx#L62.
Visual fixes:
- Increase edge opacity and width so derives/updates/extends are visually
distinct (was too faint to differentiate on dark background)
- Increase non-latest memory opacity from 0.3 to 0.5 for better contrast
Bug fix:
- Fix slideshow setTimeout race condition: track coolDown timer and clear
it on cleanup to prevent stale timeouts from freezing animation
Refactor + tests:
- Extract computeEdges() as a pure testable function from useGraphData hook
- Add 23 new edge computation tests covering memoryRelations, parentMemoryId
fallback, invalid relation types, and forward-reference scenarios
- Fix MCP transformData to pre-populate nodeIds before edge computation,
preventing silently dropped edges for forward-referenced memories
- Use MemoryRelation type for edgeType fields in GraphApiEdge and GraphEdge
- Use MemoryRelation type in use-graph-api.ts instead of inline literals
- Remove redundant MemoryRelation re-export from types.ts (already in index.tsx)
- Remove unnecessary type assertion cast in mock-data.ts
- Add defensive comments for runtime typeof checks
- Remove duplicate MemoryRelation definition from types.ts, import from api-types.ts
- Add MemoryRelation to re-exports in types.ts and index.tsx
- Make MemoryEntry.memory required and content optional to match backend MemoryEntrySchema
Updated MCP app edge computation to use memoryRelations from backend
instead of fabricating extends edges from spaceId grouping. Falls back
to parentMemoryId for backwards compatibility.
- Exclude 'extends' edges from force simulation (visual-only, no pull)
- Apply same filter in update() to prevent re-adding extends on refresh
- Stronger derives link strength (0.35) to keep memories near parent doc
- Each document forms its own mini-cluster with orbiting memories
- Clusters spread evenly across the entire canvas
When colorOverrides were provided, useGraphTheme returned a new object
on every render, breaking downstream useMemo dependencies and causing
the d3 simulation to re-update on every frame. Now uses useMemo with
a stable serialization key for the overrides object.
- Golden-angle spiral initial layout for documents, memories orbit nearby
- Adaptive spiral scale based on document count
- Strong centering force (0.25) to unify disconnected components
- Moderate charge repulsion (-1500) for organic spread within the mass
- Extract groupByColor helper to deduplicate renderer batch logic
- Remove duplicate extends/fallback in edgeStyle()
- Refactor simulation to use all FORCE_CONFIG constants (no hardcoded values)
- Memory orbit radius scales with hash for organic feel
The layout now matches the reference: documents distributed throughout
with memories radiating outward, forming one unified constellation.
- Move all 14 icon drawing functions + roundRect to document-icons.ts
- Narrow drawDocIcon parameter from GraphThemeColors to iconColor: string
- Renderer.ts reduced from 1110 to 717 lines (focused on scene orchestration)
- Add google_drive, video, mcp, word to mock data for better icon coverage
- Add 10 new icon drawing functions: Notion, Google Docs, Slides, Cloud,
X/Twitter, Play/Video, Image, Text/Note, and more
- Extend drawDocIcon switch to handle all 19+ document types from web app:
word, excel, google_sheet, google_slide, powerpoint, onedrive, google_drive,
tweet, youtube, video, image, text, note, onenote, mcp
- Update mock data with additional document types for better demo coverage
- All icons are pure canvas vector drawings (no image assets needed)
- Remove x/y from GraphApiDocument (client computes via force simulation)
- Remove similarity from GraphApiEdge, add edgeType enum
- Replace viewport/bounds/stats API calls with single paginated documents endpoint
- Derive edges client-side from document structure (doc-memory, version, same-space)
- Update MCP client/server to use documents endpoint
- Update MCP UI app for new type shapes
- Update all tests for new API contract
- Progressive loading via useInfiniteQuery (100 docs/page)
Pass popoverVisible flag from graph-canvas tick loop to the
onViewportChange callback. The handler always updates zoomDisplay
(so NavigationControls shows correct zoom %) but only increments
viewportVersion (triggering popover repositioning) when a node is
actually selected or hovered. This avoids 60fps React reconciliation
during plain panning while keeping the zoom indicator responsive.
Only fire onViewportChange (which triggers React state update +
reconciliation) when a popover is actually visible (selectedNodeId
or hoveredNodeId is set). This avoids forcing 60fps React re-renders
during plain panning/zooming when no popover needs repositioning.
Also separate prevVp* tracking from the callback gate so viewport
state is always current when a node is first hovered/selected.
Use refs for containerSize and onSlideshowNodeChange inside the
slideshow useEffect to avoid resetting the 3.5s interval when the
container is resized. The interval now only resets when
isSlideshowActive or nodes.length changes.
- Use viewportVersion (not zoomDisplay) as activePopoverPosition dependency
- Fire onViewportChange based on actual viewport state diff (panX/panY/zoom)
instead of only during animated transitions (vpMoving)
- Also fire during simulation so popover tracks settling nodes
- Remove dead lastReportedZoom variable
- Remove no-op node ID tracking effect and prevIdsRef
- Change bun:test import to vitest for CI compatibility
- Add viewportVersion counter for popover recalculation during pan
- Add hex color guard in lightenColor for non-6-digit formats
- Optimize version edge filtering with batch property
- Simplify stroke style conditions in drawDocumentNode
- Drop shadows on selected/hovered nodes (document + memory) for depth
- Subtle gradient fill on document nodes
- Improved dimming contrast for superseded memories (0.3 alpha + strikethrough)
- Hover glow ring with dashed outline for interactivity feedback
- X icon overlay on forgotten memory nodes (size > 14px)
- Glow pass behind version edges for visual emphasis
- lightenColor utility with cache + guard for non-6-digit hex
- Use memData.isForgotten instead of fragile color comparison
- Optimize version edge batch: skip filter, use first.isVersion flag
- Add 10 unit tests for lightenColor (hex parsing, clamping, cache, edge cases)
- Rename tip -> cursor for consistency with backward walk
- Fix misleading test descriptions to reflect bidirectional behavior
- Add test for circular parent references (cycle protection)
- Add test for branching children (first-child-wins behavior)
- Document linear chain assumption in forward walk comment
- Added childrenMap for forward traversal from parent to children
- getChain now walks backward to root AND forward to latest descendant
- Clicking v1 root node now shows the complete version chain UI
- Standalone v1 nodes (no children) still return null (no chain to show)
- Updated tests to reflect bidirectional behavior + added v1 root test
Memory nodes with isLatest=false are now visually dimmed:
- Full-size nodes: 35% opacity with dashed border stroke
- Zoomed-out dots: 35% opacity with thinner stroke
- Selected/hovered superseded nodes render at full opacity
so users can still inspect them
prepack/postpack fire for both 'pack' and 'publish', and postpack
always runs after packing regardless of publish success, preventing
the working tree from being left in dist-exports state on failure.
- Package exports now point to source files (./src/index.tsx) for workspace
consumers, allowing Next.js/Turbopack to resolve without pre-building
- Added publishConfig swap script that switches exports to dist/ during
npm publish (prepublishOnly) and back to source after (postpublish)
- Added @supermemory/memory-graph to transpilePackages in web app next.config.ts
so Next.js transpiles the source files correctly
- Fix slideshow useEffect: use nodesRef instead of nodes in deps to prevent
interval teardown/recreation on every render
- Fix edges useMemo: compute allNodeIds from normalizedDocs directly instead
of depending on nodes (which changes identity every render)
- Fix popover position: add zoomDisplay to deps so position updates on pan/zoom
- Implement maxNodes prop: limit documents before passing to useGraphData
- Fix SpatialIndex hash: include node IDs and use 10x position granularity
to prevent false cache hits during physics simulation
Added workspace management to the onboarding flow with automatic organization creation and workspace validation throughout the app.
### What changed?
- Wrapped the app layout with an `EnsureWorkspace` component that redirects users without organizations to onboarding
- Enhanced the welcome page to automatically create an organization with a generated slug when users complete their name input
- Expanded the auth context to track organizations list, restoration state, and provide organization refetching capabilities
- Added utility functions for generating unique organization slugs and usernames from display names
- Implemented proper organization restoration logic that handles saved preferences and multiple organization scenarios
The subscription check on plugins, connections, and usage pages was hardcoded to only look at `api_pro`. Users on scale or enterprise plans saw "Upgrade to Pro" and couldn't create plugin keys or manage connections.
Also, the check only looked at product `status` but not the `allowed` flag from autumn — so users who downgraded but were still in their billing period got locked out early.