@andespindola/brainlink 0.1.0-beta.162 → 0.1.0-beta.163
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.
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export const createClientCss = () => `:root {
|
|
2
|
-
color-scheme:
|
|
3
|
-
--bg: #
|
|
4
|
-
--panel: #
|
|
5
|
-
--panel-strong: #
|
|
6
|
-
--line: #
|
|
7
|
-
--text: #
|
|
8
|
-
--muted: #
|
|
9
|
-
--accent: #
|
|
10
|
-
--accent-weak: rgba(
|
|
11
|
-
--danger: #
|
|
2
|
+
color-scheme: light;
|
|
3
|
+
--bg: #eef2f7;
|
|
4
|
+
--panel: #ffffff;
|
|
5
|
+
--panel-strong: #f7f9fc;
|
|
6
|
+
--line: #d9e1ec;
|
|
7
|
+
--text: #172033;
|
|
8
|
+
--muted: #657386;
|
|
9
|
+
--accent: #0b6fcb;
|
|
10
|
+
--accent-weak: rgba(11, 111, 203, 0.12);
|
|
11
|
+
--danger: #d84949;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
* {
|
|
@@ -63,7 +63,8 @@ select {
|
|
|
63
63
|
min-height: 72px;
|
|
64
64
|
padding: 10px 16px;
|
|
65
65
|
border-bottom: 1px solid var(--line);
|
|
66
|
-
background:
|
|
66
|
+
background: rgba(255, 255, 255, 0.96);
|
|
67
|
+
box-shadow: 0 1px 8px rgba(23, 32, 51, 0.08);
|
|
67
68
|
backdrop-filter: blur(8px);
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -82,8 +83,10 @@ select {
|
|
|
82
83
|
width: 100%;
|
|
83
84
|
height: 100%;
|
|
84
85
|
background:
|
|
85
|
-
|
|
86
|
-
linear-gradient(
|
|
86
|
+
linear-gradient(rgba(23, 32, 51, 0.035) 1px, transparent 1px),
|
|
87
|
+
linear-gradient(90deg, rgba(23, 32, 51, 0.035) 1px, transparent 1px),
|
|
88
|
+
#f6f8fb;
|
|
89
|
+
background-size: 28px 28px, 28px 28px, auto;
|
|
87
90
|
overflow: hidden;
|
|
88
91
|
}
|
|
89
92
|
|
|
@@ -126,23 +129,23 @@ select {
|
|
|
126
129
|
.graph-label {
|
|
127
130
|
position: absolute;
|
|
128
131
|
max-width: 220px;
|
|
129
|
-
transform: translate(-50%, calc(-100% -
|
|
130
|
-
padding: 4px
|
|
131
|
-
border: 1px solid rgba(
|
|
132
|
+
transform: translate(-50%, calc(-100% - 12px));
|
|
133
|
+
padding: 4px 8px;
|
|
134
|
+
border: 1px solid rgba(101, 115, 134, 0.24);
|
|
132
135
|
border-radius: 6px;
|
|
133
|
-
background: rgba(
|
|
136
|
+
background: rgba(255, 255, 255, 0.92);
|
|
134
137
|
color: var(--text);
|
|
135
138
|
font-size: 11px;
|
|
136
139
|
line-height: 1.25;
|
|
137
140
|
white-space: nowrap;
|
|
138
141
|
overflow: hidden;
|
|
139
142
|
text-overflow: ellipsis;
|
|
140
|
-
box-shadow: 0 8px 22px rgba(
|
|
143
|
+
box-shadow: 0 8px 22px rgba(23, 32, 51, 0.12);
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
.graph-label.is-focused {
|
|
144
|
-
border-color: rgba(
|
|
145
|
-
color: #
|
|
147
|
+
border-color: rgba(11, 111, 203, 0.56);
|
|
148
|
+
color: #0b4f92;
|
|
146
149
|
}
|
|
147
150
|
|
|
148
151
|
.graph-tooltip {
|
|
@@ -152,12 +155,12 @@ select {
|
|
|
152
155
|
padding: 8px 10px;
|
|
153
156
|
border: 1px solid var(--line);
|
|
154
157
|
border-radius: 6px;
|
|
155
|
-
background: rgba(
|
|
158
|
+
background: rgba(255, 255, 255, 0.96);
|
|
156
159
|
color: var(--text);
|
|
157
160
|
font-size: 12px;
|
|
158
161
|
line-height: 1.35;
|
|
159
162
|
pointer-events: none;
|
|
160
|
-
box-shadow: 0 16px 40px rgba(
|
|
163
|
+
box-shadow: 0 16px 40px rgba(23, 32, 51, 0.18);
|
|
161
164
|
}
|
|
162
165
|
|
|
163
166
|
.graph-tooltip strong,
|
|
@@ -181,8 +184,8 @@ select {
|
|
|
181
184
|
height: 120px;
|
|
182
185
|
border: 1px solid rgba(129, 146, 170, 0.28);
|
|
183
186
|
border-radius: 8px;
|
|
184
|
-
background: rgba(
|
|
185
|
-
box-shadow: 0 16px 42px rgba(
|
|
187
|
+
background: rgba(255, 255, 255, 0.88);
|
|
188
|
+
box-shadow: 0 16px 42px rgba(23, 32, 51, 0.16);
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
.eyebrow {
|
|
@@ -215,7 +218,7 @@ select {
|
|
|
215
218
|
border: 1px solid var(--line);
|
|
216
219
|
border-radius: 8px;
|
|
217
220
|
outline: none;
|
|
218
|
-
background: rgba(
|
|
221
|
+
background: rgba(255, 255, 255, 0.94);
|
|
219
222
|
color: var(--text);
|
|
220
223
|
padding: 0 14px;
|
|
221
224
|
}
|
|
@@ -236,7 +239,7 @@ select {
|
|
|
236
239
|
height: 38px;
|
|
237
240
|
border: 1px solid var(--line);
|
|
238
241
|
border-radius: 8px;
|
|
239
|
-
background: rgba(
|
|
242
|
+
background: rgba(255, 255, 255, 0.94);
|
|
240
243
|
color: var(--text);
|
|
241
244
|
cursor: pointer;
|
|
242
245
|
}
|
|
@@ -257,7 +260,7 @@ select {
|
|
|
257
260
|
padding: 10px 12px;
|
|
258
261
|
border: 1px solid var(--line);
|
|
259
262
|
border-radius: 10px;
|
|
260
|
-
background: rgba(
|
|
263
|
+
background: rgba(255, 255, 255, 0.94);
|
|
261
264
|
display: grid;
|
|
262
265
|
gap: 3px;
|
|
263
266
|
}
|
|
@@ -332,7 +335,7 @@ li small {
|
|
|
332
335
|
padding: 12px;
|
|
333
336
|
border: 1px solid var(--line);
|
|
334
337
|
border-radius: 8px;
|
|
335
|
-
background: #
|
|
338
|
+
background: #f8fafc;
|
|
336
339
|
color: var(--text);
|
|
337
340
|
white-space: pre-wrap;
|
|
338
341
|
overflow: auto;
|
|
@@ -362,7 +365,7 @@ li small {
|
|
|
362
365
|
border-radius: 8px;
|
|
363
366
|
background: var(--panel);
|
|
364
367
|
color: var(--text);
|
|
365
|
-
box-shadow: 0 24px 80px rgba(
|
|
368
|
+
box-shadow: 0 24px 80px rgba(23, 32, 51, 0.22);
|
|
366
369
|
overflow: hidden;
|
|
367
370
|
}
|
|
368
371
|
|
|
@@ -466,7 +469,7 @@ li small {
|
|
|
466
469
|
padding: 10px;
|
|
467
470
|
border: 1px solid var(--line);
|
|
468
471
|
border-radius: 8px;
|
|
469
|
-
background:
|
|
472
|
+
background: #f8fafc;
|
|
470
473
|
display: grid;
|
|
471
474
|
grid-template-rows: auto minmax(0, 1fr);
|
|
472
475
|
gap: 8px;
|
|
@@ -369,14 +369,39 @@ const parseColor = (hex) => {
|
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
const graphTheme = {
|
|
372
|
-
node: parseColor('#
|
|
373
|
-
nodeCluster: parseColor('#
|
|
374
|
-
nodeHighlight: parseColor('#
|
|
375
|
-
nodeSelected: parseColor('#
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
372
|
+
node: parseColor('#4c8eda'),
|
|
373
|
+
nodeCluster: parseColor('#2f6fb4'),
|
|
374
|
+
nodeHighlight: parseColor('#f2b441'),
|
|
375
|
+
nodeSelected: parseColor('#172033'),
|
|
376
|
+
nodePalette: [
|
|
377
|
+
parseColor('#4c8eda'),
|
|
378
|
+
parseColor('#65b96e'),
|
|
379
|
+
parseColor('#f0a33a'),
|
|
380
|
+
parseColor('#d95f8d'),
|
|
381
|
+
parseColor('#8d72d9'),
|
|
382
|
+
parseColor('#55bfc4'),
|
|
383
|
+
parseColor('#ec6b56'),
|
|
384
|
+
parseColor('#9aa6b2'),
|
|
385
|
+
parseColor('#b78255'),
|
|
386
|
+
parseColor('#6f9fd8')
|
|
387
|
+
],
|
|
388
|
+
edge: [0.23, 0.31, 0.42, 0.18],
|
|
389
|
+
edgeHeavy: [0.23, 0.31, 0.42, 0.34],
|
|
390
|
+
clear: parseColor('#f6f8fb')
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const segmentPalette = ['#4c8eda', '#65b96e', '#f0a33a', '#d95f8d', '#8d72d9', '#55bfc4', '#ec6b56', '#9aa6b2', '#b78255', '#6f9fd8']
|
|
394
|
+
|
|
395
|
+
const segmentColorIndex = (segment) => {
|
|
396
|
+
const value = String(segment || '')
|
|
397
|
+
let hash = 0
|
|
398
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
399
|
+
hash = ((hash << 5) - hash + value.charCodeAt(index)) | 0
|
|
400
|
+
}
|
|
401
|
+
return Math.abs(hash) % segmentPalette.length
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const segmentColor = (segment) => segmentPalette[segmentColorIndex(segment)] || segmentPalette[0]
|
|
380
405
|
|
|
381
406
|
const clampScale = (scale) => Math.max(zoomRange.min, Math.min(zoomRange.max, scale))
|
|
382
407
|
|
|
@@ -518,7 +543,7 @@ const drawFallback = () => {
|
|
|
518
543
|
canvas.width = Math.floor(width * ratio)
|
|
519
544
|
canvas.height = Math.floor(height * ratio)
|
|
520
545
|
ctx2dFallback.setTransform(ratio, 0, 0, ratio, 0, 0)
|
|
521
|
-
ctx2dFallback.fillStyle = '#
|
|
546
|
+
ctx2dFallback.fillStyle = '#f6f8fb'
|
|
522
547
|
ctx2dFallback.fillRect(0, 0, width, height)
|
|
523
548
|
|
|
524
549
|
const nodes = Array.isArray(state.chunk.nodes) ? state.chunk.nodes : []
|
|
@@ -528,7 +553,7 @@ const drawFallback = () => {
|
|
|
528
553
|
nodeById.set(nodes[i][0], nodes[i])
|
|
529
554
|
}
|
|
530
555
|
|
|
531
|
-
ctx2dFallback.strokeStyle = 'rgba(
|
|
556
|
+
ctx2dFallback.strokeStyle = 'rgba(59,79,108,0.18)'
|
|
532
557
|
ctx2dFallback.lineWidth = 1
|
|
533
558
|
for (let i = 0; i < edges.length; i += 1) {
|
|
534
559
|
const edge = edges[i]
|
|
@@ -547,7 +572,7 @@ const drawFallback = () => {
|
|
|
547
572
|
const node = nodes[i]
|
|
548
573
|
const p = worldToScreen(node[2], node[3])
|
|
549
574
|
const selected = state.selectedNodeId === node[0]
|
|
550
|
-
const color = node[
|
|
575
|
+
const color = segmentColor(node[5] || node[4] || node[1])
|
|
551
576
|
const radius = Math.max(2.4, Math.min(14, 4 + node[7] * 0.55))
|
|
552
577
|
|
|
553
578
|
ctx2dFallback.beginPath()
|
|
@@ -556,7 +581,7 @@ const drawFallback = () => {
|
|
|
556
581
|
ctx2dFallback.fill()
|
|
557
582
|
}
|
|
558
583
|
|
|
559
|
-
ctx2dFallback.fillStyle = '#
|
|
584
|
+
ctx2dFallback.fillStyle = '#172033'
|
|
560
585
|
ctx2dFallback.font = '12px Inter, system-ui, sans-serif'
|
|
561
586
|
ctx2dFallback.textAlign = 'center'
|
|
562
587
|
ctx2dFallback.fillText('Fallback canvas mode', Math.max(width, 320) / 2, 24)
|
|
@@ -718,7 +743,7 @@ const drawMiniMap = () => {
|
|
|
718
743
|
miniMap.height = Math.floor(height * ratio)
|
|
719
744
|
ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
|
|
720
745
|
ctx.clearRect(0, 0, width, height)
|
|
721
|
-
ctx.fillStyle = 'rgba(
|
|
746
|
+
ctx.fillStyle = 'rgba(255, 255, 255, 0.88)'
|
|
722
747
|
ctx.fillRect(0, 0, width, height)
|
|
723
748
|
|
|
724
749
|
const xs = nodes.map((node) => Number(node[2])).filter(Number.isFinite)
|
|
@@ -738,7 +763,7 @@ const drawMiniMap = () => {
|
|
|
738
763
|
})
|
|
739
764
|
state.miniMapView = { minX, minY, scale, offsetX, offsetY, width, height }
|
|
740
765
|
|
|
741
|
-
ctx.fillStyle = 'rgba(
|
|
766
|
+
ctx.fillStyle = 'rgba(76, 142, 218, 0.62)'
|
|
742
767
|
nodes.forEach((node) => {
|
|
743
768
|
const point = toMini(Number(node[2]), Number(node[3]))
|
|
744
769
|
ctx.fillRect(point.x - 1, point.y - 1, 2, 2)
|
|
@@ -748,7 +773,7 @@ const drawMiniMap = () => {
|
|
|
748
773
|
const worldBottomRight = screenToWorld(state.viewport.width, state.viewport.height)
|
|
749
774
|
const topLeft = toMini(Math.min(worldTopLeft.x, worldBottomRight.x), Math.min(worldTopLeft.y, worldBottomRight.y))
|
|
750
775
|
const bottomRight = toMini(Math.max(worldTopLeft.x, worldBottomRight.x), Math.max(worldTopLeft.y, worldBottomRight.y))
|
|
751
|
-
ctx.strokeStyle = 'rgba(
|
|
776
|
+
ctx.strokeStyle = 'rgba(11, 111, 203, 0.86)'
|
|
752
777
|
ctx.lineWidth = 1
|
|
753
778
|
ctx.strokeRect(topLeft.x, topLeft.y, Math.max(3, bottomRight.x - topLeft.x), Math.max(3, bottomRight.y - topLeft.y))
|
|
754
779
|
}
|
|
@@ -14,6 +14,7 @@ const state = {
|
|
|
14
14
|
y: new Float32Array(0),
|
|
15
15
|
relevance: new Float32Array(0),
|
|
16
16
|
radius: new Float32Array(0),
|
|
17
|
+
colorIndex: new Uint8Array(0),
|
|
17
18
|
visible: new Uint8Array(0),
|
|
18
19
|
highlighted: new Uint8Array(0),
|
|
19
20
|
focused: new Uint8Array(0),
|
|
@@ -39,13 +40,25 @@ let pointPositionsBuffer = new Float32Array(0)
|
|
|
39
40
|
let pointSizesBuffer = new Float32Array(0)
|
|
40
41
|
|
|
41
42
|
const defaultTheme = {
|
|
42
|
-
node: [0.
|
|
43
|
-
nodeCluster: [0.
|
|
44
|
-
nodeHighlight: [0.95, 0.
|
|
45
|
-
nodeSelected: [0.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
node: [0.30, 0.56, 0.85, 1],
|
|
44
|
+
nodeCluster: [0.18, 0.44, 0.71, 1],
|
|
45
|
+
nodeHighlight: [0.95, 0.70, 0.25, 1],
|
|
46
|
+
nodeSelected: [0.09, 0.13, 0.20, 1],
|
|
47
|
+
nodePalette: [
|
|
48
|
+
[0.30, 0.56, 0.85, 1],
|
|
49
|
+
[0.40, 0.73, 0.43, 1],
|
|
50
|
+
[0.94, 0.64, 0.23, 1],
|
|
51
|
+
[0.85, 0.37, 0.55, 1],
|
|
52
|
+
[0.55, 0.45, 0.85, 1],
|
|
53
|
+
[0.33, 0.75, 0.77, 1],
|
|
54
|
+
[0.93, 0.42, 0.34, 1],
|
|
55
|
+
[0.60, 0.65, 0.70, 1],
|
|
56
|
+
[0.72, 0.51, 0.33, 1],
|
|
57
|
+
[0.44, 0.62, 0.85, 1]
|
|
58
|
+
],
|
|
59
|
+
edge: [0.23, 0.31, 0.42, 0.18],
|
|
60
|
+
edgeHeavy: [0.23, 0.31, 0.42, 0.34],
|
|
61
|
+
clear: [0.96, 0.97, 0.98, 1]
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
const theme = { ...defaultTheme }
|
|
@@ -181,6 +194,7 @@ const ensureNodeCapacity = (count) => {
|
|
|
181
194
|
state.y = new Float32Array(nextCapacity)
|
|
182
195
|
state.relevance = new Float32Array(nextCapacity)
|
|
183
196
|
state.radius = new Float32Array(nextCapacity)
|
|
197
|
+
state.colorIndex = new Uint8Array(nextCapacity)
|
|
184
198
|
state.visible = new Uint8Array(nextCapacity)
|
|
185
199
|
state.highlighted = new Uint8Array(nextCapacity)
|
|
186
200
|
state.focused = new Uint8Array(nextCapacity)
|
|
@@ -199,11 +213,21 @@ const ensureEdgeCapacity = (count) => {
|
|
|
199
213
|
}
|
|
200
214
|
|
|
201
215
|
const nodeRadius = (relevance, kind) => {
|
|
202
|
-
const base = kind === 'cluster' ?
|
|
203
|
-
const modifier = Math.min(
|
|
216
|
+
const base = kind === 'cluster' ? 8.8 : 5.4
|
|
217
|
+
const modifier = Math.min(5.6, Math.max(0, relevance * 0.62))
|
|
204
218
|
return base + modifier
|
|
205
219
|
}
|
|
206
220
|
|
|
221
|
+
const segmentColorIndex = (segment) => {
|
|
222
|
+
const value = String(segment || '')
|
|
223
|
+
let hash = 0
|
|
224
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
225
|
+
hash = ((hash << 5) - hash + value.charCodeAt(index)) | 0
|
|
226
|
+
}
|
|
227
|
+
const palette = Array.isArray(theme.nodePalette) && theme.nodePalette.length > 0 ? theme.nodePalette : [theme.node]
|
|
228
|
+
return Math.abs(hash) % palette.length
|
|
229
|
+
}
|
|
230
|
+
|
|
207
231
|
const loadChunk = (chunk) => {
|
|
208
232
|
const nodes = Array.isArray(chunk?.nodes) ? chunk.nodes : []
|
|
209
233
|
const edges = Array.isArray(chunk?.edges) ? chunk.edges : []
|
|
@@ -223,6 +247,7 @@ const loadChunk = (chunk) => {
|
|
|
223
247
|
const title = typeof row?.[1] === 'string' ? row[1] : id
|
|
224
248
|
const x = Number.isFinite(row?.[2]) ? Number(row[2]) : 0
|
|
225
249
|
const y = Number.isFinite(row?.[3]) ? Number(row[3]) : 0
|
|
250
|
+
const segment = typeof row?.[5] === 'string' ? row[5] : ''
|
|
226
251
|
const kind = row?.[6] === 'cluster' ? 'cluster' : 'node'
|
|
227
252
|
const relevance = Number.isFinite(row?.[7]) ? Number(row[7]) : 0
|
|
228
253
|
|
|
@@ -233,6 +258,7 @@ const loadChunk = (chunk) => {
|
|
|
233
258
|
state.y[index] = y
|
|
234
259
|
state.relevance[index] = relevance
|
|
235
260
|
state.radius[index] = nodeRadius(relevance, kind)
|
|
261
|
+
state.colorIndex[index] = segmentColorIndex(segment || title)
|
|
236
262
|
state.visible[index] = 0
|
|
237
263
|
state.highlighted[index] = highlightedIds.has(id) ? 1 : 0
|
|
238
264
|
state.focused[index] = focusedIds.has(id) ? 1 : 0
|
|
@@ -349,6 +375,13 @@ const drawNodeLayer = (predicate, color, radiusBoost = 1) => {
|
|
|
349
375
|
gl.drawArrays(gl.POINTS, 0, positionCursor / 2)
|
|
350
376
|
}
|
|
351
377
|
|
|
378
|
+
const drawColoredNodeLayer = (predicate, radiusBoost = 1) => {
|
|
379
|
+
const palette = Array.isArray(theme.nodePalette) && theme.nodePalette.length > 0 ? theme.nodePalette : [theme.node]
|
|
380
|
+
for (let colorIndex = 0; colorIndex < palette.length; colorIndex += 1) {
|
|
381
|
+
drawNodeLayer((index) => predicate(index) && state.colorIndex[index] === colorIndex, palette[colorIndex], radiusBoost)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
352
385
|
const clear = () => {
|
|
353
386
|
if (!gl || !canvas) return
|
|
354
387
|
gl.viewport(0, 0, canvas.width, canvas.height)
|
|
@@ -398,15 +431,13 @@ const renderFrame = (now) => {
|
|
|
398
431
|
scheduleSettledRender(now)
|
|
399
432
|
}
|
|
400
433
|
|
|
401
|
-
|
|
402
|
-
(index) => state.visible[index] === 1 && state.selected[index] === 0 && state.highlighted[index] === 0,
|
|
403
|
-
theme.node,
|
|
434
|
+
drawColoredNodeLayer(
|
|
435
|
+
(index) => state.visible[index] === 1 && state.kinds[index] !== 'cluster' && state.selected[index] === 0 && state.highlighted[index] === 0 && state.focused[index] === 0,
|
|
404
436
|
1
|
|
405
437
|
)
|
|
406
438
|
|
|
407
|
-
|
|
439
|
+
drawColoredNodeLayer(
|
|
408
440
|
(index) => state.visible[index] === 1 && state.kinds[index] === 'cluster' && state.selected[index] === 0,
|
|
409
|
-
theme.nodeCluster,
|
|
410
441
|
1.15
|
|
411
442
|
)
|
|
412
443
|
|
package/package.json
CHANGED