@andespindola/brainlink 0.1.0-beta.80 → 0.1.0-beta.82
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.
- package/README.md +4 -2
- package/dist/application/frontend/client-js.js +37 -52
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,9 +82,10 @@ Legacy `.jsonl.gz` packs are upgraded to `.blpk` automatically on first search/c
|
|
|
82
82
|
- Local HTTP API.
|
|
83
83
|
- Realtime graph UI with agent selector and colored knowledge groups.
|
|
84
84
|
- Graph renderer optimized for large datasets with viewport-driven node culling and edge lookup by visible nodes.
|
|
85
|
-
-
|
|
85
|
+
- Canvas graph rendering uses the same batched node and edge pipeline for every graph size, reducing per-frame draw calls while keeping selected and hovered items highlighted.
|
|
86
86
|
- Large graph layout API automatically uses compact payload encoding with link-coverage-aware edge selection to reduce initial client load without hiding major relationships.
|
|
87
87
|
- Large-segment layout spacing now grows logarithmically to keep initial visual density consistent between medium and very large vaults (for example, ~1k vs ~50k notes).
|
|
88
|
+
- Graph coordinates are visually compacted across graph sizes so reset starts from a stable macro mass and zoom-in progressively expands toward local detail.
|
|
88
89
|
- Zoomed-out graph LOD clusters dense regions and progressively expands the focused viewport as zoom increases, including very large vaults.
|
|
89
90
|
- Graph reset starts in macro "galaxy" overview mode and progressively reveals nearby nodes as zoom increases, including smaller vaults.
|
|
90
91
|
- Graph filtering runs in a dedicated browser worker to keep the UI thread responsive during heavy datasets.
|
|
@@ -595,7 +596,8 @@ The graph UI shows:
|
|
|
595
596
|
- keyboard shortcuts: `+` zoom in, `-` zoom out, `0` reset fit
|
|
596
597
|
- double-click on canvas zooms in at cursor position
|
|
597
598
|
- floating graph totals (notes, links, tags) below the Brainlink title
|
|
598
|
-
-
|
|
599
|
+
- graph rendering safeguards (batched canvas drawing across graph sizes, edge draw caps, lower redraw rate, zoom-aware interaction)
|
|
600
|
+
- compact macro-to-micro density progression so reset keeps the graph mass oriented and zoom-in separates local neighborhoods progressively
|
|
599
601
|
- massive-graph LOD progression: very low zoom uses spatial overview sampling plus hub-neighborhood edge previews to preserve whole-vault shape and orientation, then progressively raises the focused node budget as zoom increases so dense local areas keep nearby notes and links visible
|
|
600
602
|
|
|
601
603
|
The server indexes before starting by default. Use `--no-index` to skip that step:
|
|
@@ -930,57 +930,42 @@ const drawEdgeBatch = (edges, options) => {
|
|
|
930
930
|
ctx.stroke()
|
|
931
931
|
}
|
|
932
932
|
|
|
933
|
-
const
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
const selectedEdges = []
|
|
938
|
-
|
|
939
|
-
for (let index = 0; index < state.renderEdges.length; index += 1) {
|
|
940
|
-
const edge = state.renderEdges[index]
|
|
941
|
-
const isSelected = state.selected && (edge.source === state.selected.id || edge.target === state.selected.id)
|
|
942
|
-
if (isSelected) {
|
|
943
|
-
selectedEdges.push(edge)
|
|
944
|
-
} else if (edge.inferred) {
|
|
945
|
-
inferredEdges.push(edge)
|
|
946
|
-
} else {
|
|
947
|
-
regularEdges.push(edge)
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
const scale = state.transform.scale
|
|
952
|
-
const regularOpacity = edgeOpacityForScale({ inferred: false }, scale)
|
|
953
|
-
const inferredOpacity = edgeOpacityForScale({ inferred: true }, scale)
|
|
954
|
-
drawEdgeBatch(regularEdges, {
|
|
955
|
-
strokeStyle: 'rgba(153, 165, 181, ' + regularOpacity + ')',
|
|
956
|
-
lineWidth: 1.05
|
|
957
|
-
})
|
|
958
|
-
drawEdgeBatch(inferredEdges, {
|
|
959
|
-
strokeStyle: 'rgba(203, 213, 225, ' + inferredOpacity + ')',
|
|
960
|
-
lineWidth: 0.84
|
|
961
|
-
})
|
|
933
|
+
const regularEdgeBatchOptions = (edge) => ({
|
|
934
|
+
strokeStyle: edgeStrokeFor(edge, false),
|
|
935
|
+
lineWidth: edgeWidthFor(edge, false)
|
|
936
|
+
})
|
|
962
937
|
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
}
|
|
938
|
+
const regularEdgeBatchKey = (edge) => {
|
|
939
|
+
const options = regularEdgeBatchOptions(edge)
|
|
940
|
+
return options.strokeStyle + '|' + options.lineWidth.toFixed(2)
|
|
941
|
+
}
|
|
968
942
|
|
|
943
|
+
const drawGraphEdges = () => {
|
|
944
|
+
const edgeBatches = new Map()
|
|
969
945
|
const selectedEdges = []
|
|
970
|
-
|
|
946
|
+
|
|
971
947
|
for (let index = 0; index < state.renderEdges.length; index += 1) {
|
|
972
948
|
const edge = state.renderEdges[index]
|
|
973
949
|
const isSelected = state.selected && (edge.source === state.selected.id || edge.target === state.selected.id)
|
|
974
950
|
if (isSelected) {
|
|
975
951
|
selectedEdges.push(edge)
|
|
952
|
+
continue
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
const key = regularEdgeBatchKey(edge)
|
|
956
|
+
const batch = edgeBatches.get(key)
|
|
957
|
+
if (batch) {
|
|
958
|
+
batch.edges.push(edge)
|
|
976
959
|
} else {
|
|
977
|
-
|
|
960
|
+
edgeBatches.set(key, {
|
|
961
|
+
edges: [edge],
|
|
962
|
+
options: regularEdgeBatchOptions(edge)
|
|
963
|
+
})
|
|
978
964
|
}
|
|
979
965
|
}
|
|
980
966
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
}
|
|
967
|
+
edgeBatches.forEach((batch) => drawEdgeBatch(batch.edges, batch.options))
|
|
968
|
+
|
|
984
969
|
for (let index = 0; index < selectedEdges.length; index += 1) {
|
|
985
970
|
drawGraphEdge(selectedEdges[index])
|
|
986
971
|
}
|
|
@@ -1049,11 +1034,6 @@ const drawNodeBatch = (nodes) => {
|
|
|
1049
1034
|
}
|
|
1050
1035
|
|
|
1051
1036
|
const drawGraphNodes = () => {
|
|
1052
|
-
if (state.nodes.length <= largeGraphNodeThreshold) {
|
|
1053
|
-
state.renderNodes.forEach(node => drawSingleNode(node))
|
|
1054
|
-
return
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
1037
|
const regularNodes = []
|
|
1058
1038
|
const priorityNodes = []
|
|
1059
1039
|
|
|
@@ -1399,10 +1379,10 @@ const ensureHubNodesInRenderedSet = (nodes) => {
|
|
|
1399
1379
|
}
|
|
1400
1380
|
|
|
1401
1381
|
const zoomCapByNodeCount = (nodeCount) => {
|
|
1402
|
-
if (nodeCount > 50000) return
|
|
1403
|
-
if (nodeCount > 20000) return
|
|
1404
|
-
if (nodeCount > 6000) return 2
|
|
1405
|
-
if (nodeCount > 2000) return
|
|
1382
|
+
if (nodeCount > 50000) return 5.4
|
|
1383
|
+
if (nodeCount > 20000) return 4.8
|
|
1384
|
+
if (nodeCount > 6000) return 4.2
|
|
1385
|
+
if (nodeCount > 2000) return 4
|
|
1406
1386
|
return zoomRange.max
|
|
1407
1387
|
}
|
|
1408
1388
|
|
|
@@ -1561,10 +1541,15 @@ const focusPrimaryHub = () => {
|
|
|
1561
1541
|
}
|
|
1562
1542
|
|
|
1563
1543
|
const layoutDensityScaleForNodeCount = (nodeCount) => {
|
|
1564
|
-
if (nodeCount > 50000) return 0.
|
|
1565
|
-
if (nodeCount > 20000) return 0.
|
|
1566
|
-
if (nodeCount > 6000) return 0.
|
|
1567
|
-
return
|
|
1544
|
+
if (nodeCount > 50000) return 0.26
|
|
1545
|
+
if (nodeCount > 20000) return 0.3
|
|
1546
|
+
if (nodeCount > 6000) return 0.36
|
|
1547
|
+
if (nodeCount > 2000) return 0.42
|
|
1548
|
+
if (nodeCount > 600) return 0.5
|
|
1549
|
+
if (nodeCount > 180) return 0.58
|
|
1550
|
+
if (nodeCount > 60) return 0.68
|
|
1551
|
+
if (nodeCount > 20) return 0.78
|
|
1552
|
+
return 0.88
|
|
1568
1553
|
}
|
|
1569
1554
|
|
|
1570
1555
|
const createLayout = graph => {
|
package/package.json
CHANGED