@andespindola/brainlink 0.1.0-beta.92 → 0.1.0-beta.94
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 +1 -1
- package/dist/application/frontend/client-js.js +35 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -602,7 +602,7 @@ The graph UI shows:
|
|
|
602
602
|
- WebGL node and edge acceleration when supported, falling back to Canvas 2D without changing graph behavior
|
|
603
603
|
- compact macro-to-micro density progression so reset keeps the graph mass oriented and zoom-in separates local neighborhoods progressively
|
|
604
604
|
- 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
|
|
605
|
-
- graph LOD progression: graphs up to 1000 notes render directly; larger graphs use a compact memory-hub-centered mesh of
|
|
605
|
+
- graph LOD progression: graphs up to 1000 notes render directly; larger graphs use a compact memory-hub-centered mesh of alpha-particle 1000-note points, zoom-in keeps focused child clusters latent at the parent position before fading them in and only then separating them through 500-note, 250-note, 125-note and 60-note subgraphs with aggregated real links plus local sibling mesh links, and in massive graphs keeps this subgraph mode active much longer with finer wheel steps so deep zoom does not abruptly switch to a broad sampled node cloud
|
|
606
606
|
|
|
607
607
|
The server indexes before starting by default. Use `--no-index` to skip that step:
|
|
608
608
|
|
|
@@ -28,14 +28,15 @@ const ecosystemClusterEdgeLimit = 520
|
|
|
28
28
|
const ecosystemHubEdgeLimit = 120
|
|
29
29
|
const ecosystemSiblingEdgeLimit = 180
|
|
30
30
|
const ecosystemClusterScaleThreshold = 0.78
|
|
31
|
+
const massiveEcosystemClusterScaleThreshold = 2.4
|
|
31
32
|
const ecosystemSubgraphScaleThreshold = 0.18
|
|
32
33
|
const ecosystemMicroScaleThreshold = 0.08
|
|
33
34
|
const ecosystemFocusedParentLimit = 2
|
|
34
35
|
const ecosystemExpansionLevels = [
|
|
35
|
-
{ parentSize: 1000, childSize: 500, start: 0.
|
|
36
|
-
{ parentSize: 500, childSize: 250, start: 0.
|
|
37
|
-
{ parentSize: 250, childSize: 125, start: 0.
|
|
38
|
-
{ parentSize: 125, childSize: 60, start: 0.
|
|
36
|
+
{ parentSize: 1000, childSize: 500, start: 0.04, end: 0.62 },
|
|
37
|
+
{ parentSize: 500, childSize: 250, start: 0.16, end: 0.72 },
|
|
38
|
+
{ parentSize: 250, childSize: 125, start: 0.3, end: 0.78 },
|
|
39
|
+
{ parentSize: 125, childSize: 60, start: 0.46, end: 0.86 }
|
|
39
40
|
]
|
|
40
41
|
const zoomRecoveryGuardMs = 4200
|
|
41
42
|
const zoomCapTargetViewportShare = 0.72
|
|
@@ -894,11 +895,11 @@ const smoothStep = value => {
|
|
|
894
895
|
const zoomProgress = (scale, start, end) =>
|
|
895
896
|
smoothStep((scale - start) / Math.max(end - start, 0.0001))
|
|
896
897
|
|
|
897
|
-
const semanticZoomSpread = progress => Math.pow(progress, 2
|
|
898
|
+
const semanticZoomSpread = progress => Math.pow(progress, 4.2)
|
|
898
899
|
|
|
899
|
-
const
|
|
900
|
+
const opacityForProgress = progress => Math.pow(progress, 2.1)
|
|
900
901
|
|
|
901
|
-
const expandFocusedClusters = (parentClusters, childSize, spread, viewport) => {
|
|
902
|
+
const expandFocusedClusters = (parentClusters, childSize, progress, spread, viewport) => {
|
|
902
903
|
const focusPoint = ecosystemFocusPoint()
|
|
903
904
|
const expandedParentIds = new Set(nearestEcosystemParentIds(
|
|
904
905
|
parentClusters,
|
|
@@ -908,7 +909,7 @@ const expandFocusedClusters = (parentClusters, childSize, spread, viewport) => {
|
|
|
908
909
|
const childClusters = state.ecosystemClustersBySize.get(childSize) ?? []
|
|
909
910
|
const visibleChildClusters = childClusters
|
|
910
911
|
.filter(cluster => expandedParentIds.has(cluster.parentId))
|
|
911
|
-
.map(cluster => spreadChildClusterFromParent(cluster, spread))
|
|
912
|
+
.map(cluster => spreadChildClusterFromParent(cluster, progress, spread))
|
|
912
913
|
.filter(cluster => isClusterInViewport(cluster, viewport))
|
|
913
914
|
|
|
914
915
|
return {
|
|
@@ -917,11 +918,11 @@ const expandFocusedClusters = (parentClusters, childSize, spread, viewport) => {
|
|
|
917
918
|
}
|
|
918
919
|
}
|
|
919
920
|
|
|
920
|
-
const spreadChildClusterFromParent = (cluster, spread) => {
|
|
921
|
+
const spreadChildClusterFromParent = (cluster, progress, spread) => {
|
|
921
922
|
if (!Number.isFinite(cluster.parentX) || !Number.isFinite(cluster.parentY)) {
|
|
922
923
|
return {
|
|
923
924
|
...cluster,
|
|
924
|
-
lodOpacity:
|
|
925
|
+
lodOpacity: opacityForProgress(progress)
|
|
925
926
|
}
|
|
926
927
|
}
|
|
927
928
|
|
|
@@ -929,7 +930,7 @@ const spreadChildClusterFromParent = (cluster, spread) => {
|
|
|
929
930
|
...cluster,
|
|
930
931
|
x: cluster.parentX + (cluster.x - cluster.parentX) * spread,
|
|
931
932
|
y: cluster.parentY + (cluster.y - cluster.parentY) * spread,
|
|
932
|
-
lodOpacity:
|
|
933
|
+
lodOpacity: opacityForProgress(progress)
|
|
933
934
|
}
|
|
934
935
|
}
|
|
935
936
|
|
|
@@ -946,11 +947,8 @@ const selectHierarchicalEcosystemClusters = viewport => {
|
|
|
946
947
|
continue
|
|
947
948
|
}
|
|
948
949
|
const progress = zoomProgress(state.transform.scale, level.start, level.end)
|
|
949
|
-
if (progress <= 0.025) {
|
|
950
|
-
continue
|
|
951
|
-
}
|
|
952
950
|
const spread = semanticZoomSpread(progress)
|
|
953
|
-
const expansion = expandFocusedClusters(parentClusters, level.childSize, spread, viewport)
|
|
951
|
+
const expansion = expandFocusedClusters(parentClusters, level.childSize, progress, spread, viewport)
|
|
954
952
|
visibleClusters.push(...expansion.childClusters)
|
|
955
953
|
}
|
|
956
954
|
|
|
@@ -1005,11 +1003,12 @@ const ecosystemSiblingEdgesForClusters = (clusters, existingEdges) => {
|
|
|
1005
1003
|
}
|
|
1006
1004
|
|
|
1007
1005
|
const ecosystemEdgesForClusters = clusters => {
|
|
1008
|
-
const
|
|
1006
|
+
const edgeClusters = clusters.filter(cluster => cluster.isHub || clusterOpacity(cluster) > 0.018)
|
|
1007
|
+
const clusterById = new Map(edgeClusters.map(cluster => [cluster.id, cluster]))
|
|
1009
1008
|
const clusterIds = new Set(clusterById.keys())
|
|
1010
1009
|
const levelsBySize = []
|
|
1011
|
-
for (let index = 0; index <
|
|
1012
|
-
const cluster =
|
|
1010
|
+
for (let index = 0; index < edgeClusters.length; index += 1) {
|
|
1011
|
+
const cluster = edgeClusters[index]
|
|
1013
1012
|
if (!cluster.size || cluster.isHub) continue
|
|
1014
1013
|
if (!levelsBySize.some(level => level.size === cluster.size)) {
|
|
1015
1014
|
levelsBySize.push({
|
|
@@ -1060,7 +1059,7 @@ const ecosystemEdgesForClusters = clusters => {
|
|
|
1060
1059
|
})
|
|
1061
1060
|
}
|
|
1062
1061
|
|
|
1063
|
-
ecosystemSiblingEdgesForClusters(
|
|
1062
|
+
ecosystemSiblingEdgesForClusters(edgeClusters, edgeByClusterPair)
|
|
1064
1063
|
const edges = Array.from(edgeByClusterPair.values())
|
|
1065
1064
|
.sort((left, right) => right.weight - left.weight)
|
|
1066
1065
|
.slice(0, ecosystemClusterEdgeLimit)
|
|
@@ -1078,7 +1077,7 @@ const ecosystemEdgesForClusters = clusters => {
|
|
|
1078
1077
|
? [edge.sourceCluster.id]
|
|
1079
1078
|
: []
|
|
1080
1079
|
))
|
|
1081
|
-
const syntheticHubEdges =
|
|
1080
|
+
const syntheticHubEdges = edgeClusters
|
|
1082
1081
|
.filter(cluster => cluster.id !== hubCluster.id && !existingHubTargets.has(cluster.id))
|
|
1083
1082
|
.slice(0, ecosystemHubEdgeLimit)
|
|
1084
1083
|
.map(cluster => ({
|
|
@@ -2530,11 +2529,11 @@ const clusterRadiusPx = cluster => {
|
|
|
2530
2529
|
return 10
|
|
2531
2530
|
}
|
|
2532
2531
|
if (cluster.isHub) {
|
|
2533
|
-
return
|
|
2532
|
+
return 3.2
|
|
2534
2533
|
}
|
|
2535
2534
|
if (String(cluster.id).startsWith('ecosystem-')) {
|
|
2536
|
-
const base = cluster.size >= 1000 ?
|
|
2537
|
-
return Math.max(0.
|
|
2535
|
+
const base = cluster.size >= 1000 ? 0.68 : cluster.size >= 500 ? 0.64 : cluster.size >= 250 ? 0.6 : cluster.size >= 125 ? 0.56 : 0.52
|
|
2536
|
+
return Math.max(0.5, Math.min(1.55, base + Math.log10(cluster.count + 1) * 0.12))
|
|
2538
2537
|
}
|
|
2539
2538
|
return Math.max(8, Math.min(28, 8 + Math.log2(cluster.count + 1) * 3))
|
|
2540
2539
|
}
|
|
@@ -2703,9 +2702,12 @@ const computeRenderVisibility = () => {
|
|
|
2703
2702
|
return
|
|
2704
2703
|
}
|
|
2705
2704
|
|
|
2705
|
+
const ecosystemScaleThreshold = state.visibleNodes.length > massiveGraphNodeThreshold
|
|
2706
|
+
? massiveEcosystemClusterScaleThreshold
|
|
2707
|
+
: ecosystemClusterScaleThreshold
|
|
2706
2708
|
if (
|
|
2707
2709
|
state.visibleNodes.length > ecosystemActivationNodeThreshold &&
|
|
2708
|
-
state.transform.scale <=
|
|
2710
|
+
state.transform.scale <= ecosystemScaleThreshold &&
|
|
2709
2711
|
state.ecosystemClusters.length > 0
|
|
2710
2712
|
) {
|
|
2711
2713
|
const clusters = selectHierarchicalEcosystemClusters(viewport)
|
|
@@ -3159,10 +3161,16 @@ const wheelZoomFactor = event => {
|
|
|
3159
3161
|
return 1
|
|
3160
3162
|
}
|
|
3161
3163
|
|
|
3162
|
-
const
|
|
3164
|
+
const isMassiveEcosystemZoom =
|
|
3165
|
+
state.visibleNodes.length > massiveGraphNodeThreshold &&
|
|
3166
|
+
state.transform.scale <= massiveEcosystemClusterScaleThreshold
|
|
3167
|
+
const sensitivityMultiplier = isMassiveEcosystemZoom ? 0.62 : 1
|
|
3168
|
+
const capMultiplier = isMassiveEcosystemZoom ? 0.48 : 1
|
|
3169
|
+
const sensitivity = wheelZoomExponent * (isModifierZoom ? wheelZoomModifierBoost : 1) * sensitivityMultiplier
|
|
3170
|
+
const exponentCap = wheelZoomExponentCap * capMultiplier
|
|
3163
3171
|
const exponent = Math.max(
|
|
3164
|
-
-
|
|
3165
|
-
Math.min(
|
|
3172
|
+
-exponentCap,
|
|
3173
|
+
Math.min(exponentCap, -normalizedDelta * sensitivity)
|
|
3166
3174
|
)
|
|
3167
3175
|
return Math.exp(exponent)
|
|
3168
3176
|
}
|
package/package.json
CHANGED