@andespindola/brainlink 0.1.0-beta.70 → 0.1.0-beta.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,8 @@ const renderEdgeBudget = 2400
8
8
  const clusterActivationNodeThreshold = 600
9
9
  const clusterZoomThreshold = 0.18
10
10
  const macroGalaxyZoomThreshold = 0.012
11
+ const macroGalaxyEnterHysteresis = 0.86
12
+ const macroGalaxyExitHysteresis = 1.24
11
13
  const massiveAutoFitMacroScale = 0.006
12
14
  const defaultMacroScale = 0.006
13
15
  const clusterCellPixelSize = 64
@@ -25,6 +27,9 @@ const meshEdgeMaxBudget = 1400
25
27
  const layeredCoreScaleThreshold = 0.55
26
28
  const dragNeighborhoodMaxAffected = 180
27
29
  const dragSettleRounds = 3
30
+ const wheelZoomExponent = 0.0018
31
+ const wheelZoomExponentCap = 0.09
32
+ const wheelZoomModifierBoost = 1.22
28
33
  const state = {
29
34
  graph: { nodes: [], edges: [] },
30
35
  nodes: [],
@@ -65,7 +70,8 @@ const state = {
65
70
  filterReady: false,
66
71
  lastHoverHitAt: 0,
67
72
  lastManualZoomAt: 0,
68
- lastZoomFocus: { x: 0, y: 0, at: 0 }
73
+ lastZoomFocus: { x: 0, y: 0, at: 0 },
74
+ macroViewActive: false
69
75
  }
70
76
 
71
77
  const byId = id => document.getElementById(id)
@@ -662,6 +668,29 @@ const viewportCenterWorldPoint = () => {
662
668
  }
663
669
  }
664
670
 
671
+ const visibilityScaleBucket = (scale) => {
672
+ const safeScale = Math.max(zoomRange.min, scale)
673
+ if (safeScale < 0.01) return Math.round(safeScale * 300_000)
674
+ if (safeScale < 0.05) return Math.round(safeScale * 120_000)
675
+ if (safeScale < 0.2) return Math.round(safeScale * 40_000)
676
+ return Math.round(safeScale * 8_000)
677
+ }
678
+
679
+ const shouldRenderMacroGalaxyView = () => {
680
+ if (state.visibleNodes.length <= 1) {
681
+ state.macroViewActive = false
682
+ return false
683
+ }
684
+
685
+ const enterThreshold = macroGalaxyZoomThreshold * macroGalaxyEnterHysteresis
686
+ const exitThreshold = macroGalaxyZoomThreshold * macroGalaxyExitHysteresis
687
+ const shouldRender = state.macroViewActive
688
+ ? state.transform.scale <= exitThreshold
689
+ : state.transform.scale <= enterThreshold
690
+ state.macroViewActive = shouldRender
691
+ return shouldRender
692
+ }
693
+
665
694
  const mergeUniqueNodes = (leftNodes, rightNodes, limit) => {
666
695
  const merged = []
667
696
  const ids = new Set()
@@ -1733,7 +1762,7 @@ const computeRenderVisibility = () => {
1733
1762
  Math.round(viewport.maxX * 10) + ':' +
1734
1763
  Math.round(viewport.minY * 10) + ':' +
1735
1764
  Math.round(viewport.maxY * 10) + ':' +
1736
- Math.round(state.transform.scale * 1000)
1765
+ visibilityScaleBucket(state.transform.scale)
1737
1766
 
1738
1767
  if (!state.renderVisibilityDirty && viewportKey === state.lastViewportKey) {
1739
1768
  return
@@ -1741,8 +1770,7 @@ const computeRenderVisibility = () => {
1741
1770
  state.lastViewportKey = viewportKey
1742
1771
  state.renderVisibilityDirty = false
1743
1772
 
1744
- const shouldRenderMacroGalaxy =
1745
- state.transform.scale <= macroGalaxyZoomThreshold && state.visibleNodes.length > 1
1773
+ const shouldRenderMacroGalaxy = shouldRenderMacroGalaxyView()
1746
1774
 
1747
1775
  if (shouldRenderMacroGalaxy) {
1748
1776
  const viewportNodes = viewportNodesFromSpatialIndex(viewport)
@@ -1797,10 +1825,19 @@ const computeRenderVisibility = () => {
1797
1825
  selectAccessBridgeNodes(sourceWithCarry, bridgeLimit),
1798
1826
  Math.min(renderNodeBudget, sampleLimit + bridgeLimit)
1799
1827
  )
1800
- const sampled = selectStableSampleNodes(
1828
+ const sampledRaw = selectStableSampleNodes(
1801
1829
  bridgedNodes,
1802
1830
  Math.min(sampleLimit, renderNodeBudget)
1803
1831
  )
1832
+ const continuityBudget = Math.max(24, Math.min(sampleLimit - 8, Math.floor(sampleLimit * 0.42)))
1833
+ const previousVisibleNodes = (state.renderNodes ?? [])
1834
+ .filter((node) => sourceWithCarry.some((candidate) => candidate.id === node.id))
1835
+ const continuityNodes = selectStableSampleNodes(previousVisibleNodes, continuityBudget)
1836
+ const sampled = mergeUniqueNodes(
1837
+ continuityNodes,
1838
+ sampledRaw,
1839
+ Math.min(sampleLimit, renderNodeBudget)
1840
+ )
1804
1841
  const sampledIds = new Set(sampled.map((node) => node.id))
1805
1842
  let sampledEdges = state.transform.scale >= 0.035 ? collectVisibleEdgesForNodes(sampledIds) : []
1806
1843
  let sampledNodes = ensureHubNodesInRenderedSet(sampled)
@@ -2184,16 +2221,18 @@ const zoomAtPoint = (screenX, screenY, factor, source = 'generic') => {
2184
2221
  const wheelZoomFactor = event => {
2185
2222
  const isModifierZoom = event.metaKey || event.ctrlKey
2186
2223
  const deltaModeFactor = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? 120 : 1
2187
- const absoluteDelta = Math.min(Math.abs(event.deltaY * deltaModeFactor), 1600)
2224
+ const normalizedDelta = event.deltaY * deltaModeFactor
2188
2225
 
2189
- if (absoluteDelta <= 0.0001) {
2226
+ if (!Number.isFinite(normalizedDelta) || Math.abs(normalizedDelta) <= 0.0001) {
2190
2227
  return 1
2191
2228
  }
2192
2229
 
2193
- const baseStep = Math.max(0.012, Math.min(0.11, absoluteDelta / 980))
2194
- const adjustedStep = baseStep * (isModifierZoom ? 1.24 : 1)
2195
-
2196
- return event.deltaY < 0 ? 1 + adjustedStep : 1 / (1 + adjustedStep)
2230
+ const sensitivity = wheelZoomExponent * (isModifierZoom ? wheelZoomModifierBoost : 1)
2231
+ const exponent = Math.max(
2232
+ -wheelZoomExponentCap,
2233
+ Math.min(wheelZoomExponentCap, -normalizedDelta * sensitivity)
2234
+ )
2235
+ return Math.exp(exponent)
2197
2236
  }
2198
2237
 
2199
2238
  const handleWheelZoom = event => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andespindola/brainlink",
3
- "version": "0.1.0-beta.70",
3
+ "version": "0.1.0-beta.72",
4
4
  "description": "Local-first knowledge memory for agents with Markdown, backlinks, indexing and context retrieval.",
5
5
  "type": "module",
6
6
  "license": "MIT",