@andespindola/brainlink 0.1.0-beta.107 → 0.1.0-beta.108
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 +2 -0
- package/dist/application/frontend/client-js.js +69 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -601,6 +601,8 @@ The graph UI shows:
|
|
|
601
601
|
- floating graph totals (notes, links, tags) below the Brainlink title
|
|
602
602
|
- graph rendering safeguards (batched canvas drawing across graph sizes, edge draw caps, lower redraw rate, zoom-aware interaction)
|
|
603
603
|
- adaptive CPU safeguards for large graphs: idle frame pacing, throttled background physics updates and cached viewport dimensions to reduce redraw/layout overhead while preserving interaction responsiveness
|
|
604
|
+
- hierarchical hot-path optimizations reduce per-frame allocations and repeated scans during layered cluster expansion and edge projection
|
|
605
|
+
- hierarchical edge projection now caches hub membership and node-to-cluster resolution per frame to keep large recursive subgraph rendering smooth during continuous zoom and pan
|
|
604
606
|
- WebGL node and edge acceleration when supported, falling back to Canvas 2D without changing graph behavior
|
|
605
607
|
- compact macro-to-micro density progression so reset keeps the graph mass oriented and zoom-in separates local neighborhoods progressively
|
|
606
608
|
- graph camera treats hub-centered navigation as structural only when the hub is dominant; diffuse stress graphs reset and zoom around the full graph mass
|
|
@@ -91,6 +91,8 @@ const state = {
|
|
|
91
91
|
ecosystemClustersBySize: new Map(),
|
|
92
92
|
ecosystemNodeClusterBySize: new Map(),
|
|
93
93
|
ecosystemLevelSizes: [],
|
|
94
|
+
ecosystemLevelIndexBySize: new Map(),
|
|
95
|
+
ecosystemHubNodeIds: new Set(),
|
|
94
96
|
ecosystemExpansionLevels: [],
|
|
95
97
|
ecosystemBaseSize: ecosystemLevelNodeCap,
|
|
96
98
|
ecosystemHubCluster: null,
|
|
@@ -617,6 +619,11 @@ const recomputeVisibility = () => {
|
|
|
617
619
|
state.ecosystemClustersBySize = ecosystemGraph.clustersBySize
|
|
618
620
|
state.ecosystemNodeClusterBySize = ecosystemGraph.nodeClusterBySize
|
|
619
621
|
state.ecosystemLevelSizes = ecosystemGraph.levelSizes
|
|
622
|
+
state.ecosystemLevelIndexBySize = ecosystemGraph.levelSizes.reduce((map, size, index) => {
|
|
623
|
+
map.set(size, index)
|
|
624
|
+
return map
|
|
625
|
+
}, new Map())
|
|
626
|
+
state.ecosystemHubNodeIds = new Set(ecosystemGraph.hubCluster?.nodeIds ?? [])
|
|
620
627
|
state.ecosystemExpansionLevels = ecosystemGraph.expansionLevels
|
|
621
628
|
state.ecosystemBaseSize = ecosystemGraph.baseSize
|
|
622
629
|
state.ecosystemHubCluster = ecosystemGraph.hubCluster
|
|
@@ -1105,10 +1112,18 @@ const expandFocusedClusters = (parentClusters, focusPoint, childSize, progress,
|
|
|
1105
1112
|
ecosystemFocusedParentLimit
|
|
1106
1113
|
))
|
|
1107
1114
|
const childClusters = state.ecosystemClustersBySize.get(childSize) ?? []
|
|
1108
|
-
const visibleChildClusters =
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
.
|
|
1115
|
+
const visibleChildClusters = []
|
|
1116
|
+
for (let index = 0; index < childClusters.length; index += 1) {
|
|
1117
|
+
const cluster = childClusters[index]
|
|
1118
|
+
if (!expandedParentIds.has(cluster.parentId)) {
|
|
1119
|
+
continue
|
|
1120
|
+
}
|
|
1121
|
+
const spreadCluster = spreadChildClusterFromParent(cluster, childSize, progress, spread)
|
|
1122
|
+
if (!isClusterInViewport(spreadCluster, viewport)) {
|
|
1123
|
+
continue
|
|
1124
|
+
}
|
|
1125
|
+
visibleChildClusters.push(spreadCluster)
|
|
1126
|
+
}
|
|
1112
1127
|
|
|
1113
1128
|
return {
|
|
1114
1129
|
expandedParentIds,
|
|
@@ -1137,11 +1152,21 @@ const selectHierarchicalEcosystemClusters = viewport => {
|
|
|
1137
1152
|
const visibleBaseClusters = filterEcosystemClustersByViewport(baseClusters, viewport)
|
|
1138
1153
|
const hubClusters = state.ecosystemHubCluster ? [state.ecosystemHubCluster] : []
|
|
1139
1154
|
const visibleClusters = [...visibleBaseClusters]
|
|
1155
|
+
const clustersBySize = new Map()
|
|
1156
|
+
for (let index = 0; index < visibleBaseClusters.length; index += 1) {
|
|
1157
|
+
const cluster = visibleBaseClusters[index]
|
|
1158
|
+
const levelClusters = clustersBySize.get(cluster.size)
|
|
1159
|
+
if (levelClusters) {
|
|
1160
|
+
levelClusters.push(cluster)
|
|
1161
|
+
} else {
|
|
1162
|
+
clustersBySize.set(cluster.size, [cluster])
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1140
1165
|
const focusPoint = ecosystemFocusPoint()
|
|
1141
1166
|
|
|
1142
1167
|
for (let index = 0; index < state.ecosystemExpansionLevels.length; index += 1) {
|
|
1143
1168
|
const level = state.ecosystemExpansionLevels[index]
|
|
1144
|
-
const parentClusters =
|
|
1169
|
+
const parentClusters = clustersBySize.get(level.parentSize) ?? []
|
|
1145
1170
|
if (parentClusters.length === 0) {
|
|
1146
1171
|
continue
|
|
1147
1172
|
}
|
|
@@ -1154,18 +1179,20 @@ const selectHierarchicalEcosystemClusters = viewport => {
|
|
|
1154
1179
|
const spread = semanticZoomSpread(progress, level.childSize)
|
|
1155
1180
|
const expansion = expandFocusedClusters(parentClusters, focusPoint, level.childSize, progress, spread, viewport)
|
|
1156
1181
|
visibleClusters.push(...expansion.childClusters)
|
|
1182
|
+
if (expansion.childClusters.length > 0) {
|
|
1183
|
+
const levelClusters = clustersBySize.get(level.childSize)
|
|
1184
|
+
if (levelClusters) {
|
|
1185
|
+
levelClusters.push(...expansion.childClusters)
|
|
1186
|
+
} else {
|
|
1187
|
+
clustersBySize.set(level.childSize, [...expansion.childClusters])
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1157
1190
|
}
|
|
1158
1191
|
|
|
1159
1192
|
return [...hubClusters, ...visibleClusters]
|
|
1160
1193
|
}
|
|
1161
1194
|
|
|
1162
|
-
const ecosystemLevelIndexBySize = () =>
|
|
1163
|
-
const indexBySize = new Map()
|
|
1164
|
-
for (let index = 0; index < state.ecosystemLevelSizes.length; index += 1) {
|
|
1165
|
-
indexBySize.set(state.ecosystemLevelSizes[index], index)
|
|
1166
|
-
}
|
|
1167
|
-
return indexBySize
|
|
1168
|
-
}
|
|
1195
|
+
const ecosystemLevelIndexBySize = () => state.ecosystemLevelIndexBySize
|
|
1169
1196
|
|
|
1170
1197
|
const ecosystemDepthForCluster = (cluster, levelIndexMap) => {
|
|
1171
1198
|
if (cluster.isHub) {
|
|
@@ -1216,20 +1243,20 @@ const applyEcosystemDepthProjection = (clusters, edges, anchor) => {
|
|
|
1216
1243
|
clusterById.set(projectedCluster.id, projectedCluster)
|
|
1217
1244
|
}
|
|
1218
1245
|
|
|
1219
|
-
const projectedEdges =
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1246
|
+
const projectedEdges = []
|
|
1247
|
+
for (let index = 0; index < edges.length; index += 1) {
|
|
1248
|
+
const edge = edges[index]
|
|
1249
|
+
const sourceCluster = clusterById.get(edge.sourceCluster.id)
|
|
1250
|
+
const targetCluster = clusterById.get(edge.targetCluster.id)
|
|
1251
|
+
if (!sourceCluster || !targetCluster) {
|
|
1252
|
+
continue
|
|
1253
|
+
}
|
|
1254
|
+
projectedEdges.push({
|
|
1255
|
+
...edge,
|
|
1256
|
+
sourceCluster,
|
|
1257
|
+
targetCluster
|
|
1231
1258
|
})
|
|
1232
|
-
|
|
1259
|
+
}
|
|
1233
1260
|
|
|
1234
1261
|
return {
|
|
1235
1262
|
clusters: projectedClusters,
|
|
@@ -1289,28 +1316,37 @@ const ecosystemEdgesForClusters = clusters => {
|
|
|
1289
1316
|
const clusterById = new Map(edgeClusters.map(cluster => [cluster.id, cluster]))
|
|
1290
1317
|
const clusterIds = new Set(clusterById.keys())
|
|
1291
1318
|
const levelsBySize = []
|
|
1319
|
+
const seenSizes = new Set()
|
|
1292
1320
|
for (let index = 0; index < edgeClusters.length; index += 1) {
|
|
1293
1321
|
const cluster = edgeClusters[index]
|
|
1294
1322
|
if (!cluster.size || cluster.isHub) continue
|
|
1295
|
-
if (
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
}
|
|
1323
|
+
if (seenSizes.has(cluster.size)) continue
|
|
1324
|
+
seenSizes.add(cluster.size)
|
|
1325
|
+
levelsBySize.push({
|
|
1326
|
+
size: cluster.size,
|
|
1327
|
+
lookup: state.ecosystemNodeClusterBySize.get(cluster.size) ?? new Map()
|
|
1328
|
+
})
|
|
1301
1329
|
}
|
|
1302
1330
|
levelsBySize.sort((left, right) => left.size - right.size)
|
|
1331
|
+
const resolvedNodeClusterById = new Map()
|
|
1303
1332
|
const resolveClusterForNode = nodeId => {
|
|
1304
|
-
if (
|
|
1333
|
+
if (resolvedNodeClusterById.has(nodeId)) {
|
|
1334
|
+
return resolvedNodeClusterById.get(nodeId)
|
|
1335
|
+
}
|
|
1336
|
+
if (state.ecosystemHubNodeIds.has(nodeId) && state.ecosystemHubCluster && clusterIds.has(state.ecosystemHubCluster.id)) {
|
|
1337
|
+
resolvedNodeClusterById.set(nodeId, state.ecosystemHubCluster)
|
|
1305
1338
|
return state.ecosystemHubCluster
|
|
1306
1339
|
}
|
|
1307
1340
|
for (let index = 0; index < levelsBySize.length; index += 1) {
|
|
1308
1341
|
const lookup = levelsBySize[index].lookup
|
|
1309
1342
|
const cluster = lookup.get(nodeId)
|
|
1310
1343
|
if (cluster && clusterIds.has(cluster.id)) {
|
|
1311
|
-
|
|
1344
|
+
const resolvedCluster = clusterById.get(cluster.id) ?? cluster
|
|
1345
|
+
resolvedNodeClusterById.set(nodeId, resolvedCluster)
|
|
1346
|
+
return resolvedCluster
|
|
1312
1347
|
}
|
|
1313
1348
|
}
|
|
1349
|
+
resolvedNodeClusterById.set(nodeId, null)
|
|
1314
1350
|
return null
|
|
1315
1351
|
}
|
|
1316
1352
|
|
package/package.json
CHANGED