@andespindola/brainlink 0.1.0-beta.132 → 0.1.0-beta.134

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.
@@ -16,9 +16,13 @@ const hierarchyMicroEnterCoverage = 0.58
16
16
  const hierarchyMicroExitCoverage = 0.38
17
17
  const hierarchyMicroEnterScale = 0.18
18
18
  const hierarchyMicroExitScale = 0.12
19
- const hierarchyFocusedOnlyProgress = 0.5
20
- const hierarchyFocusedOnlyCoverage = 0.4
19
+ const hierarchyFocusAcquireCoverage = 0.52
20
+ const hierarchyFocusAcquireScale = 0.16
21
+ const hierarchyChildRevealPower = 4
22
+ const hierarchyFocusedOnlyProgress = 0.64
21
23
  const hierarchyChildGraphFitMargin = 1.28
24
+ const hierarchyChildRevealGrowthRatio = 0.3
25
+ const hierarchyChildRevealGrowthFloor = 2
22
26
  const minNodePixelRadius = 2.3
23
27
  const viewportPaddingPx = 280
24
28
  const worldCoordinateLimit = 5_000_000
@@ -86,6 +90,8 @@ const state = {
86
90
  lastZoomFocus: { x: 0, y: 0, at: 0 },
87
91
  hierarchyFocusGroupId: null,
88
92
  hierarchyFocusStack: [],
93
+ hierarchyRevealFocusGroupId: null,
94
+ hierarchyRevealBudget: 1,
89
95
  zoomTransition: {
90
96
  active: false,
91
97
  source: 'generic',
@@ -1461,6 +1467,16 @@ const updateHierarchyFocusGroup = (groups, viewport) => {
1461
1467
  ? groups.find(group => group.id === state.hierarchyFocusGroupId) ?? null
1462
1468
  : null
1463
1469
  const currentCoverage = current ? groupViewportCoverage(current, viewport) : 0
1470
+ const hasActiveFocusedTransition =
1471
+ Boolean(current) &&
1472
+ state.zoomTransition.active &&
1473
+ state.zoomTransition.source === 'group' &&
1474
+ state.selected?.isGroupNode &&
1475
+ state.selected.groupId === current.id
1476
+
1477
+ if (hasActiveFocusedTransition) {
1478
+ return current
1479
+ }
1464
1480
 
1465
1481
  if (
1466
1482
  current &&
@@ -1479,8 +1495,8 @@ const updateHierarchyFocusGroup = (groups, viewport) => {
1479
1495
 
1480
1496
  if (
1481
1497
  candidate &&
1482
- state.transform.scale >= hierarchyMicroExitScale &&
1483
- candidate.coverage >= hierarchyMicroExitCoverage
1498
+ state.transform.scale >= hierarchyFocusAcquireScale &&
1499
+ candidate.coverage >= hierarchyFocusAcquireCoverage
1484
1500
  ) {
1485
1501
  state.hierarchyFocusGroupId = candidate.group.id
1486
1502
  if (candidate.group.childGroupIds.length > 0 && state.hierarchyFocusStack.at(-1) !== candidate.group.id) {
@@ -1496,11 +1512,45 @@ const updateHierarchyFocusGroup = (groups, viewport) => {
1496
1512
  return null
1497
1513
  }
1498
1514
 
1515
+ const updateHierarchyChildRevealBudget = (focusGroupId, targetLimit) => {
1516
+ if (state.hierarchyRevealFocusGroupId !== focusGroupId) {
1517
+ state.hierarchyRevealFocusGroupId = focusGroupId
1518
+ state.hierarchyRevealBudget = 1
1519
+ }
1520
+
1521
+ if (state.hierarchyRevealBudget > targetLimit) {
1522
+ state.hierarchyRevealBudget = targetLimit
1523
+ return targetLimit
1524
+ }
1525
+
1526
+ const remaining = Math.max(0, targetLimit - state.hierarchyRevealBudget)
1527
+ const growth = Math.max(
1528
+ hierarchyChildRevealGrowthFloor,
1529
+ Math.floor(remaining * hierarchyChildRevealGrowthRatio)
1530
+ )
1531
+ state.hierarchyRevealBudget = Math.min(targetLimit, state.hierarchyRevealBudget + growth)
1532
+ return state.hierarchyRevealBudget
1533
+ }
1534
+
1499
1535
  const hierarchyViewportProgress = (group, viewport) => {
1500
1536
  const coverage = groupViewportCoverage(group, viewport)
1501
- const coverageProgress = (coverage - hierarchyMicroExitCoverage) / (hierarchyMicroEnterCoverage - hierarchyMicroExitCoverage)
1502
- const scaleProgress = (state.transform.scale - hierarchyMicroExitScale) / (hierarchyMicroEnterScale - hierarchyMicroExitScale)
1503
- return smoothProgress(Math.min(coverageProgress, scaleProgress))
1537
+ const coverageProgress = (coverage - hierarchyFocusAcquireCoverage) / (hierarchyMicroEnterCoverage - hierarchyFocusAcquireCoverage)
1538
+ const scaleProgress = (state.transform.scale - hierarchyFocusAcquireScale) / (hierarchyMicroEnterScale - hierarchyFocusAcquireScale)
1539
+ const viewportProgress = smoothProgress(Math.min(coverageProgress, scaleProgress))
1540
+ const hasActiveFocusedTransition =
1541
+ state.zoomTransition.active &&
1542
+ state.zoomTransition.source === 'group' &&
1543
+ state.selected?.isGroupNode &&
1544
+ state.selected.groupId === group.id
1545
+
1546
+ if (!hasActiveFocusedTransition) {
1547
+ return viewportProgress
1548
+ }
1549
+
1550
+ const targetSpan = Math.max(state.zoomTransition.targetScale - hierarchyFocusAcquireScale, 0.0001)
1551
+ const transitionScaleProgress = (state.transform.scale - hierarchyFocusAcquireScale) / targetSpan
1552
+ const transitionProgress = Math.pow(Math.max(0, Math.min(1, transitionScaleProgress)), 2.8)
1553
+ return Math.max(viewportProgress, transitionProgress)
1504
1554
  }
1505
1555
 
1506
1556
  const groupEdgesForRenderedGroups = (groupNodes) => {
@@ -1556,6 +1606,8 @@ const computeHierarchyRenderVisibility = (viewport) => {
1556
1606
  if (state.groups.length === 0 || state.visibleNodes.length <= 1000) {
1557
1607
  state.hierarchyFocusGroupId = null
1558
1608
  state.hierarchyFocusStack = []
1609
+ state.hierarchyRevealFocusGroupId = null
1610
+ state.hierarchyRevealBudget = 1
1559
1611
  return false
1560
1612
  }
1561
1613
 
@@ -1565,6 +1617,8 @@ const computeHierarchyRenderVisibility = (viewport) => {
1565
1617
  const groupNodes = groups.map(createGroupRenderNode)
1566
1618
 
1567
1619
  if (!focus || progress <= 0.02) {
1620
+ state.hierarchyRevealFocusGroupId = null
1621
+ state.hierarchyRevealBudget = 1
1568
1622
  state.renderNodes = groupNodes
1569
1623
  state.renderEdges = groupEdgesForRenderedGroups(groupNodes)
1570
1624
  return true
@@ -1575,7 +1629,9 @@ const computeHierarchyRenderVisibility = (viewport) => {
1575
1629
  const focusChildGroups = focus.childGroupIds
1576
1630
  .map(groupId => state.groupById.get(groupId))
1577
1631
  .filter(Boolean)
1578
- const childLimit = Math.min(renderNodeBudget, Math.max(1, Math.floor(renderNodeBudget * progress)))
1632
+ const childRevealProgress = Math.pow(Math.max(0, Math.min(1, progress)), hierarchyChildRevealPower)
1633
+ const childTargetLimit = Math.min(renderNodeBudget, Math.max(1, Math.floor(renderNodeBudget * childRevealProgress)))
1634
+ const childLimit = updateHierarchyChildRevealBudget(focus.id, childTargetLimit)
1579
1635
  const focusRenderNode = groupNodes.find(node => node.groupId === focus.id) ?? createGroupRenderNode(focus)
1580
1636
  const arrangedChildren = focusChildGroups.length > 0
1581
1637
  ? arrangeChildGroupNodes(focusChildGroups, focus, focusRenderNode)
@@ -1584,9 +1640,7 @@ const computeHierarchyRenderVisibility = (viewport) => {
1584
1640
  .map(node => interpolateNodeFromGroup(node, focusRenderNode, progress))
1585
1641
  const childIds = new Set(childNodes.map(node => node.id))
1586
1642
  const childById = new Map(childNodes.map(node => [node.id, node]))
1587
- const isMicroView =
1588
- progress >= hierarchyFocusedOnlyProgress ||
1589
- groupViewportCoverage(focus, viewport) >= hierarchyFocusedOnlyCoverage
1643
+ const isMicroView = progress >= hierarchyFocusedOnlyProgress
1590
1644
  const visibleGroupNodes = isMicroView
1591
1645
  ? []
1592
1646
  : groupNodes.filter(node => node.groupId !== focus.id || progress < 0.92)
@@ -2077,6 +2131,8 @@ const resetView = () => fitView({ useFiltered: false, preferHubCenter: false })
2077
2131
  const resetHierarchyFocus = () => {
2078
2132
  state.hierarchyFocusGroupId = null
2079
2133
  state.hierarchyFocusStack = []
2134
+ state.hierarchyRevealFocusGroupId = null
2135
+ state.hierarchyRevealBudget = 1
2080
2136
  }
2081
2137
 
2082
2138
  const focusPrimaryHub = () => {
@@ -3287,6 +3343,8 @@ const loadGraph = async (options = { reset: false }) => {
3287
3343
  state.groups = layout.groups
3288
3344
  state.hierarchyFocusGroupId = null
3289
3345
  state.hierarchyFocusStack = []
3346
+ state.hierarchyRevealFocusGroupId = null
3347
+ state.hierarchyRevealBudget = 1
3290
3348
  state.groupById = new Map(state.groups.map(group => [group.id, group]))
3291
3349
  state.leafGroups = state.groups.filter(group => group.nodeIds.length > 0)
3292
3350
  state.nodeLeafGroupById = new Map(state.leafGroups.flatMap(group => group.nodeIds.map(nodeId => [nodeId, group])))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andespindola/brainlink",
3
- "version": "0.1.0-beta.132",
3
+ "version": "0.1.0-beta.134",
4
4
  "description": "Local-first knowledge memory for agents with Markdown, backlinks, indexing and context retrieval.",
5
5
  "type": "module",
6
6
  "license": "MIT",