@andespindola/brainlink 0.1.0-beta.117 → 0.1.0-beta.118

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 renderNodeBudget = 900
8
8
  const zoomedMassiveRenderNodeBudget = 2200
9
9
  const massiveOverviewRenderNodeBudget = 1800
10
10
  const massiveOverviewScaleThreshold = 0.065
11
+ const massiveSegmentedScaleThreshold = 0.45
12
+ const massiveSegmentRepresentativeBudget = 760
11
13
  const massiveAutoFitMacroScale = 0.018
12
14
  const minNodePixelRadius = 2.3
13
15
  const viewportPaddingPx = 280
@@ -1316,6 +1318,77 @@ const sampleMassiveOverviewNodes = (limit) => {
1316
1318
  return ensureHubNodesInRenderedSet(sampled)
1317
1319
  }
1318
1320
 
1321
+ const representativeNodeFromBucket = bucket => {
1322
+ if (!bucket || bucket.length === 0) {
1323
+ return null
1324
+ }
1325
+
1326
+ let representative = bucket[0]
1327
+ let representativeDegree = state.nodeDegrees.get(representative.id) ?? 0
1328
+
1329
+ for (let index = 1; index < bucket.length; index += 1) {
1330
+ const candidate = bucket[index]
1331
+ const candidateDegree = state.nodeDegrees.get(candidate.id) ?? 0
1332
+ if (candidateDegree <= representativeDegree) {
1333
+ continue
1334
+ }
1335
+ representative = candidate
1336
+ representativeDegree = candidateDegree
1337
+ }
1338
+
1339
+ return representative
1340
+ }
1341
+
1342
+ const sampleMassiveSegmentRepresentatives = (limit) => {
1343
+ const spatial = state.visibleNodeSpatial
1344
+ if (!spatial || spatial.buckets.size === 0 || limit <= 0) {
1345
+ return []
1346
+ }
1347
+
1348
+ const keys = [...spatial.buckets.keys()].sort()
1349
+ const maxNodes = Math.min(limit, keys.length)
1350
+ const step = Math.max(1, Math.ceil(keys.length / maxNodes))
1351
+ const representatives = []
1352
+
1353
+ for (let index = 0; index < keys.length && representatives.length < maxNodes; index += step) {
1354
+ const representative = representativeNodeFromBucket(spatial.buckets.get(keys[index]))
1355
+ if (representative) {
1356
+ representatives.push(representative)
1357
+ }
1358
+ }
1359
+
1360
+ return representatives
1361
+ }
1362
+
1363
+ const massiveSegmentRepresentativeLimit = (scale, limit) => {
1364
+ if (scale >= massiveSegmentedScaleThreshold) {
1365
+ return 0
1366
+ }
1367
+ if (scale < 0.09) {
1368
+ return Math.min(massiveSegmentRepresentativeBudget, Math.floor(limit * 0.5))
1369
+ }
1370
+ if (scale < 0.18) {
1371
+ return Math.min(620, Math.floor(limit * 0.42))
1372
+ }
1373
+ if (scale < 0.28) {
1374
+ return Math.min(460, Math.floor(limit * 0.34))
1375
+ }
1376
+ return Math.min(260, Math.floor(limit * 0.22))
1377
+ }
1378
+
1379
+ const sampleMassiveSegmentedNodes = (limit, viewport) => {
1380
+ const representativeLimit = massiveSegmentRepresentativeLimit(state.transform.scale, limit)
1381
+ const representatives = sampleMassiveSegmentRepresentatives(representativeLimit)
1382
+ const localLimit = Math.max(1, limit - representatives.length)
1383
+ const localMargin = Math.max(520, Math.min(5200, 780 / Math.max(state.transform.scale, 0.0001)))
1384
+ const localViewport = expandViewportBounds(viewport, localMargin)
1385
+ const localViewportNodes = viewportNodesFromSpatialIndex(localViewport)
1386
+ const localSource = localViewportNodes.length > 0 ? localViewportNodes : state.visibleNodes
1387
+ const localNodes = selectStableSampleNodes(localSource, localLimit)
1388
+
1389
+ return mergeUniqueNodes(representatives, localNodes, limit)
1390
+ }
1391
+
1319
1392
  const enrichSampleWithNeighbors = (nodes) => {
1320
1393
  if (nodes.length === 0) {
1321
1394
  return {
@@ -2146,7 +2219,16 @@ const computeRenderVisibility = () => {
2146
2219
  }
2147
2220
 
2148
2221
  const viewportNodes = viewportNodesFromSpatialIndex(viewport)
2149
- const sourceNodes = viewportNodes.length > 0 ? viewportNodes : sampleMassiveOverviewNodes(sampleLimit)
2222
+ const segmentedNodes =
2223
+ state.transform.scale < massiveSegmentedScaleThreshold
2224
+ ? sampleMassiveSegmentedNodes(sampleLimit, viewport)
2225
+ : []
2226
+ const sourceNodes =
2227
+ segmentedNodes.length > 0
2228
+ ? segmentedNodes
2229
+ : viewportNodes.length > 0
2230
+ ? viewportNodes
2231
+ : sampleMassiveOverviewNodes(sampleLimit)
2150
2232
  const carryMargin = Math.max(240, Math.min(1200, 340 / Math.max(state.transform.scale, 0.0001)))
2151
2233
  const carryViewport = expandViewportBounds(viewport, carryMargin)
2152
2234
  const carryOverLimit = Math.max(180, Math.min(sampleLimit, Math.floor(sampleLimit * 0.5)))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andespindola/brainlink",
3
- "version": "0.1.0-beta.117",
3
+ "version": "0.1.0-beta.118",
4
4
  "description": "Local-first knowledge memory for agents with Markdown, backlinks, indexing and context retrieval.",
5
5
  "type": "module",
6
6
  "license": "MIT",