@omiron33/omi-neuron-web 0.1.4 → 0.1.6
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/dist/{NeuronWeb-DG5ICk2K.d.cts → NeuronWeb-DHP0heLZ.d.cts} +4 -2
- package/dist/{NeuronWeb-DbcYoeQE.d.ts → NeuronWeb-jS_bg9lu.d.ts} +4 -2
- package/dist/{chunk-KC7V76I3.cjs → chunk-U7K7KQZG.cjs} +320 -69
- package/dist/chunk-U7K7KQZG.cjs.map +1 -0
- package/dist/{chunk-GPDX3O37.js → chunk-YFJMQCGE.js} +321 -70
- package/dist/chunk-YFJMQCGE.js.map +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/visualization/index.cjs +6 -6
- package/dist/visualization/index.d.cts +4 -2
- package/dist/visualization/index.d.ts +4 -2
- package/dist/visualization/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-GPDX3O37.js.map +0 -1
- package/dist/chunk-KC7V76I3.cjs.map +0 -1
|
@@ -36,7 +36,7 @@ var DEFAULT_THEME = {
|
|
|
36
36
|
edgeActive: "#c6d4ff",
|
|
37
37
|
edgeSelected: "#ffffff",
|
|
38
38
|
labelText: "#ffffff",
|
|
39
|
-
labelBackground: "rgba(
|
|
39
|
+
labelBackground: "rgba(5, 6, 31, 0.8)"
|
|
40
40
|
},
|
|
41
41
|
typography: {
|
|
42
42
|
labelFontFamily: "system-ui, sans-serif",
|
|
@@ -55,8 +55,8 @@ var DEFAULT_THEME = {
|
|
|
55
55
|
edgeFlowSpeed: 1.2,
|
|
56
56
|
fogEnabled: true,
|
|
57
57
|
fogColor: "#020314",
|
|
58
|
-
fogNear:
|
|
59
|
-
fogFar:
|
|
58
|
+
fogNear: 24,
|
|
59
|
+
fogFar: 160
|
|
60
60
|
},
|
|
61
61
|
animation: {
|
|
62
62
|
focusDuration: 800,
|
|
@@ -74,8 +74,8 @@ var SceneManager = class {
|
|
|
74
74
|
this.container = container;
|
|
75
75
|
this.config = config;
|
|
76
76
|
this.scene = new THREE__namespace.Scene();
|
|
77
|
-
this.camera = new THREE__namespace.PerspectiveCamera(
|
|
78
|
-
this.renderer = new THREE__namespace.WebGLRenderer({ antialias: true });
|
|
77
|
+
this.camera = new THREE__namespace.PerspectiveCamera(config.cameraFov ?? 52, 1, 0.1, 220);
|
|
78
|
+
this.renderer = new THREE__namespace.WebGLRenderer({ antialias: true, alpha: true });
|
|
79
79
|
this.labelRenderer = new CSS2DRenderer_js.CSS2DRenderer();
|
|
80
80
|
this.controls = new OrbitControls_js.OrbitControls(this.camera, this.renderer.domElement);
|
|
81
81
|
}
|
|
@@ -92,6 +92,7 @@ var SceneManager = class {
|
|
|
92
92
|
ambientLight = null;
|
|
93
93
|
keyLight = null;
|
|
94
94
|
fillLight = null;
|
|
95
|
+
resizeObserver = null;
|
|
95
96
|
initialize() {
|
|
96
97
|
const { cameraPosition, cameraTarget, backgroundColor } = this.config;
|
|
97
98
|
this.scene.background = new THREE__namespace.Color(backgroundColor);
|
|
@@ -106,9 +107,14 @@ var SceneManager = class {
|
|
|
106
107
|
this.controls.update();
|
|
107
108
|
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, this.config.pixelRatioCap));
|
|
108
109
|
this.renderer.outputColorSpace = THREE__namespace.SRGBColorSpace;
|
|
109
|
-
this.renderer.toneMapping = THREE__namespace.
|
|
110
|
-
this.renderer.toneMappingExposure = 1
|
|
110
|
+
this.renderer.toneMapping = THREE__namespace.NoToneMapping;
|
|
111
|
+
this.renderer.toneMappingExposure = 1;
|
|
111
112
|
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
|
|
113
|
+
this.renderer.domElement.style.position = "absolute";
|
|
114
|
+
this.renderer.domElement.style.top = "0";
|
|
115
|
+
this.renderer.domElement.style.left = "0";
|
|
116
|
+
this.renderer.domElement.style.width = "100%";
|
|
117
|
+
this.renderer.domElement.style.height = "100%";
|
|
112
118
|
this.labelRenderer.setSize(this.container.clientWidth, this.container.clientHeight);
|
|
113
119
|
this.labelRenderer.domElement.style.position = "absolute";
|
|
114
120
|
this.labelRenderer.domElement.style.top = "0";
|
|
@@ -123,11 +129,17 @@ var SceneManager = class {
|
|
|
123
129
|
this.initStarfield();
|
|
124
130
|
}
|
|
125
131
|
window.addEventListener("resize", this.resize);
|
|
132
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
133
|
+
this.resizeObserver = new ResizeObserver(() => this.resize());
|
|
134
|
+
this.resizeObserver.observe(this.container);
|
|
135
|
+
}
|
|
126
136
|
this.startAnimationLoop();
|
|
127
137
|
}
|
|
128
138
|
dispose() {
|
|
129
139
|
this.stopAnimationLoop();
|
|
130
140
|
window.removeEventListener("resize", this.resize);
|
|
141
|
+
this.resizeObserver?.disconnect();
|
|
142
|
+
this.resizeObserver = null;
|
|
131
143
|
this.renderer.dispose();
|
|
132
144
|
this.scene.clear();
|
|
133
145
|
this.container.innerHTML = "";
|
|
@@ -165,6 +177,7 @@ var SceneManager = class {
|
|
|
165
177
|
resize = () => {
|
|
166
178
|
const width = this.container.clientWidth;
|
|
167
179
|
const height = this.container.clientHeight;
|
|
180
|
+
if (!width || !height) return;
|
|
168
181
|
this.camera.aspect = width / height;
|
|
169
182
|
this.camera.updateProjectionMatrix();
|
|
170
183
|
this.renderer.setSize(width, height);
|
|
@@ -219,20 +232,17 @@ var SceneManager = class {
|
|
|
219
232
|
const geometry = new THREE__namespace.BufferGeometry();
|
|
220
233
|
const positions = new Float32Array(count * 3);
|
|
221
234
|
for (let i = 0; i < count; i += 1) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
positions[i * 3] = radius * Math.sin(phi) * Math.cos(theta);
|
|
226
|
-
positions[i * 3 + 1] = radius * Math.sin(phi) * Math.sin(theta);
|
|
227
|
-
positions[i * 3 + 2] = radius * Math.cos(phi);
|
|
235
|
+
positions[i * 3] = THREE__namespace.MathUtils.randFloatSpread(70);
|
|
236
|
+
positions[i * 3 + 1] = THREE__namespace.MathUtils.randFloatSpread(70);
|
|
237
|
+
positions[i * 3 + 2] = THREE__namespace.MathUtils.randFloatSpread(70);
|
|
228
238
|
}
|
|
229
239
|
geometry.setAttribute("position", new THREE__namespace.BufferAttribute(positions, 3));
|
|
230
240
|
const material = new THREE__namespace.PointsMaterial({
|
|
231
241
|
color: this.config.starfieldColor,
|
|
232
|
-
size: 0.
|
|
242
|
+
size: 0.22,
|
|
233
243
|
sizeAttenuation: true,
|
|
234
244
|
transparent: true,
|
|
235
|
-
opacity: 0.
|
|
245
|
+
opacity: 0.5,
|
|
236
246
|
depthWrite: false
|
|
237
247
|
});
|
|
238
248
|
this.starfield = new THREE__namespace.Points(geometry, material);
|
|
@@ -273,38 +283,53 @@ var NodeRenderer = class {
|
|
|
273
283
|
this.scene = scene;
|
|
274
284
|
this.config = config;
|
|
275
285
|
this.scene.add(this.group);
|
|
286
|
+
this.glowTexture = this.createGlowTexture();
|
|
287
|
+
if (config.labelOffset) {
|
|
288
|
+
this.labelOffset.set(...config.labelOffset);
|
|
289
|
+
}
|
|
276
290
|
}
|
|
277
291
|
group = new THREE__namespace.Group();
|
|
278
292
|
nodeStates = /* @__PURE__ */ new Map();
|
|
279
293
|
hoveredNodeId = null;
|
|
280
294
|
selectedNodeId = null;
|
|
295
|
+
glowTexture = null;
|
|
296
|
+
labelOffset = new THREE__namespace.Vector3(0, 0.65, 0);
|
|
281
297
|
renderNodes(nodes) {
|
|
282
298
|
this.clear();
|
|
299
|
+
const shouldRenderLabels = this.config.maxVisibleLabels > 0 && this.config.labelDistance > 0;
|
|
283
300
|
nodes.forEach((node) => {
|
|
284
301
|
const color = new THREE__namespace.Color(
|
|
285
302
|
this.config.domainColors[node.domain] ?? this.config.defaultColor
|
|
286
303
|
);
|
|
287
|
-
const
|
|
288
|
-
|
|
304
|
+
const material = new THREE__namespace.SpriteMaterial({
|
|
305
|
+
map: this.glowTexture ?? void 0,
|
|
289
306
|
color,
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
emissiveIntensity: 1
|
|
307
|
+
transparent: true,
|
|
308
|
+
opacity: 0.78,
|
|
309
|
+
depthWrite: false
|
|
294
310
|
});
|
|
295
|
-
const
|
|
311
|
+
const sprite = new THREE__namespace.Sprite(material);
|
|
296
312
|
const position = new THREE__namespace.Vector3();
|
|
297
313
|
if (node.position) {
|
|
298
314
|
position.set(...node.position);
|
|
299
315
|
}
|
|
300
|
-
|
|
316
|
+
sprite.position.copy(position);
|
|
301
317
|
const tierScale = node.tier ? this.config.tierScales[node.tier] ?? 1 : 1;
|
|
302
318
|
const baseScale = this.config.baseScale * tierScale;
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
this.group.add(
|
|
319
|
+
sprite.scale.setScalar(baseScale);
|
|
320
|
+
sprite.userData = { nodeId: node.id, nodeSlug: node.slug };
|
|
321
|
+
this.group.add(sprite);
|
|
322
|
+
let labelObject = null;
|
|
323
|
+
if (shouldRenderLabels) {
|
|
324
|
+
const labelElement = this.createLabelElement(node, color);
|
|
325
|
+
labelObject = new CSS2DRenderer_js.CSS2DObject(labelElement);
|
|
326
|
+
labelObject.position.copy(sprite.position).add(this.labelOffset);
|
|
327
|
+
this.scene.add(labelObject);
|
|
328
|
+
}
|
|
306
329
|
this.nodeStates.set(node.id, {
|
|
307
|
-
|
|
330
|
+
sprite,
|
|
331
|
+
material,
|
|
332
|
+
label: labelObject,
|
|
308
333
|
basePosition: position.clone(),
|
|
309
334
|
baseScale,
|
|
310
335
|
phase: Math.random() * Math.PI * 2,
|
|
@@ -320,7 +345,7 @@ var NodeRenderer = class {
|
|
|
320
345
|
if (!state) return;
|
|
321
346
|
if (updates.position) {
|
|
322
347
|
state.basePosition.set(...updates.position);
|
|
323
|
-
state.
|
|
348
|
+
state.sprite.position.set(...updates.position);
|
|
324
349
|
}
|
|
325
350
|
if (updates.tier) {
|
|
326
351
|
const tierScale = this.config.tierScales[updates.tier] ?? 1;
|
|
@@ -331,18 +356,24 @@ var NodeRenderer = class {
|
|
|
331
356
|
this.config.domainColors[updates.domain] ?? this.config.defaultColor
|
|
332
357
|
);
|
|
333
358
|
state.baseColor = color;
|
|
334
|
-
|
|
335
|
-
material.color = color;
|
|
336
|
-
material.emissive = color.clone().multiplyScalar(this.config.glowIntensity * 0.4);
|
|
359
|
+
state.material.color = color;
|
|
337
360
|
}
|
|
338
361
|
}
|
|
339
362
|
removeNode(nodeId) {
|
|
340
363
|
const state = this.nodeStates.get(nodeId);
|
|
341
364
|
if (!state) return;
|
|
342
|
-
|
|
365
|
+
if (state.label) {
|
|
366
|
+
this.scene.remove(state.label);
|
|
367
|
+
}
|
|
368
|
+
this.group.remove(state.sprite);
|
|
343
369
|
this.nodeStates.delete(nodeId);
|
|
344
370
|
}
|
|
345
371
|
clear() {
|
|
372
|
+
this.nodeStates.forEach((state) => {
|
|
373
|
+
if (state.label) {
|
|
374
|
+
this.scene.remove(state.label);
|
|
375
|
+
}
|
|
376
|
+
});
|
|
346
377
|
this.group.clear();
|
|
347
378
|
this.nodeStates.clear();
|
|
348
379
|
this.hoveredNodeId = null;
|
|
@@ -350,29 +381,130 @@ var NodeRenderer = class {
|
|
|
350
381
|
}
|
|
351
382
|
showNodes(nodeIds) {
|
|
352
383
|
nodeIds.forEach((id) => {
|
|
353
|
-
const
|
|
354
|
-
if (
|
|
384
|
+
const state = this.nodeStates.get(id);
|
|
385
|
+
if (state) state.sprite.visible = true;
|
|
355
386
|
});
|
|
356
387
|
}
|
|
357
388
|
hideNodes(nodeIds) {
|
|
358
389
|
nodeIds.forEach((id) => {
|
|
359
|
-
const
|
|
360
|
-
if (
|
|
390
|
+
const state = this.nodeStates.get(id);
|
|
391
|
+
if (state) state.sprite.visible = false;
|
|
361
392
|
});
|
|
362
393
|
}
|
|
363
394
|
setVisibleNodes(nodeIds) {
|
|
364
395
|
if (!nodeIds) {
|
|
365
396
|
this.nodeStates.forEach((state) => {
|
|
366
|
-
state.
|
|
397
|
+
state.sprite.visible = true;
|
|
367
398
|
});
|
|
368
399
|
return;
|
|
369
400
|
}
|
|
370
401
|
const visibleSet = new Set(nodeIds);
|
|
371
402
|
this.nodeStates.forEach((state, id) => {
|
|
372
|
-
state.
|
|
403
|
+
state.sprite.visible = visibleSet.has(id);
|
|
373
404
|
});
|
|
374
405
|
}
|
|
375
|
-
updateLabelVisibility() {
|
|
406
|
+
updateLabelVisibility(camera) {
|
|
407
|
+
if (this.config.maxVisibleLabels <= 0 || this.config.labelDistance <= 0) {
|
|
408
|
+
this.nodeStates.forEach((state) => {
|
|
409
|
+
if (state.label) state.label.visible = false;
|
|
410
|
+
});
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const entries = [];
|
|
414
|
+
this.nodeStates.forEach((state) => {
|
|
415
|
+
if (!state.label) return;
|
|
416
|
+
if (!state.sprite.visible) {
|
|
417
|
+
state.label.visible = false;
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
const distance = camera.position.distanceTo(state.sprite.position);
|
|
421
|
+
entries.push({ state, distance });
|
|
422
|
+
});
|
|
423
|
+
entries.sort((a, b) => a.distance - b.distance);
|
|
424
|
+
entries.forEach((entry, index) => {
|
|
425
|
+
const visible = entry.distance <= this.config.labelDistance && index < this.config.maxVisibleLabels;
|
|
426
|
+
entry.state.label.visible = visible;
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
createLabelElement(node, accent) {
|
|
430
|
+
const wrapper = document.createElement("div");
|
|
431
|
+
wrapper.style.borderRadius = "10px";
|
|
432
|
+
wrapper.style.border = "1px solid rgba(255, 255, 255, 0.12)";
|
|
433
|
+
wrapper.style.background = this.config.labelBackground;
|
|
434
|
+
wrapper.style.color = this.config.labelTextColor;
|
|
435
|
+
wrapper.style.fontFamily = this.config.labelFontFamily;
|
|
436
|
+
wrapper.style.fontSize = `${this.config.labelFontSize}px`;
|
|
437
|
+
wrapper.style.fontWeight = this.config.labelFontWeight;
|
|
438
|
+
wrapper.style.padding = "6px 8px";
|
|
439
|
+
wrapper.style.boxShadow = "0 10px 30px rgba(5, 10, 20, 0.35)";
|
|
440
|
+
wrapper.style.backdropFilter = "blur(10px)";
|
|
441
|
+
wrapper.style.pointerEvents = "none";
|
|
442
|
+
wrapper.style.maxWidth = "220px";
|
|
443
|
+
const isInsight = node.tier === "insight" || node.domain === "insight";
|
|
444
|
+
if (isInsight) {
|
|
445
|
+
const accentBright = accent.clone().lerp(new THREE__namespace.Color("#ffffff"), 0.35);
|
|
446
|
+
wrapper.style.border = `1px solid ${this.toRgba(accentBright, 0.6)}`;
|
|
447
|
+
wrapper.style.background = this.toRgba(accent, 0.2);
|
|
448
|
+
wrapper.style.color = this.toRgba(accentBright, 0.95);
|
|
449
|
+
}
|
|
450
|
+
const badgeRow = document.createElement("div");
|
|
451
|
+
badgeRow.style.display = "flex";
|
|
452
|
+
badgeRow.style.flexWrap = "wrap";
|
|
453
|
+
badgeRow.style.gap = "4px";
|
|
454
|
+
badgeRow.style.marginBottom = "4px";
|
|
455
|
+
const makeBadge = (text, tone) => {
|
|
456
|
+
const badge = document.createElement("span");
|
|
457
|
+
badge.textContent = text;
|
|
458
|
+
badge.style.display = "inline-flex";
|
|
459
|
+
badge.style.alignItems = "center";
|
|
460
|
+
badge.style.gap = "4px";
|
|
461
|
+
badge.style.borderRadius = "999px";
|
|
462
|
+
badge.style.padding = "2px 6px";
|
|
463
|
+
badge.style.fontSize = "0.6rem";
|
|
464
|
+
badge.style.fontWeight = "600";
|
|
465
|
+
badge.style.textTransform = "uppercase";
|
|
466
|
+
badge.style.letterSpacing = "0.2em";
|
|
467
|
+
if (tone === "accent") {
|
|
468
|
+
badge.style.border = `1px solid ${this.toRgba(accent, 0.6)}`;
|
|
469
|
+
badge.style.background = this.toRgba(accent, 0.4);
|
|
470
|
+
badge.style.color = "#f5f7ff";
|
|
471
|
+
} else {
|
|
472
|
+
badge.style.border = "1px solid rgba(255, 255, 255, 0.2)";
|
|
473
|
+
badge.style.background = "rgba(255, 255, 255, 0.08)";
|
|
474
|
+
badge.style.color = "rgba(255, 255, 255, 0.8)";
|
|
475
|
+
}
|
|
476
|
+
return badge;
|
|
477
|
+
};
|
|
478
|
+
if (isInsight) {
|
|
479
|
+
badgeRow.appendChild(makeBadge("Insight", "accent"));
|
|
480
|
+
const statusRaw = node.metadata?.status ?? node.metadata?.draftNodeStatus ?? node.metadata?.studyPathStatus;
|
|
481
|
+
if (statusRaw) {
|
|
482
|
+
const formatted = statusRaw.replace(/[_-]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
483
|
+
badgeRow.appendChild(makeBadge(formatted, "muted"));
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if (badgeRow.childElementCount > 0) {
|
|
487
|
+
wrapper.appendChild(badgeRow);
|
|
488
|
+
}
|
|
489
|
+
const title = document.createElement("div");
|
|
490
|
+
title.textContent = node.label;
|
|
491
|
+
title.style.fontSize = "0.8rem";
|
|
492
|
+
title.style.fontWeight = "600";
|
|
493
|
+
wrapper.appendChild(title);
|
|
494
|
+
if (node.ref) {
|
|
495
|
+
const reference = document.createElement("div");
|
|
496
|
+
reference.textContent = node.ref;
|
|
497
|
+
reference.style.fontSize = "0.65rem";
|
|
498
|
+
reference.style.opacity = "0.7";
|
|
499
|
+
wrapper.appendChild(reference);
|
|
500
|
+
}
|
|
501
|
+
return wrapper;
|
|
502
|
+
}
|
|
503
|
+
toRgba(color, alpha) {
|
|
504
|
+
const r = Math.round(color.r * 255);
|
|
505
|
+
const g = Math.round(color.g * 255);
|
|
506
|
+
const b = Math.round(color.b * 255);
|
|
507
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
376
508
|
}
|
|
377
509
|
highlightNode(nodeId) {
|
|
378
510
|
this.setHoveredNode(nodeId);
|
|
@@ -387,14 +519,14 @@ var NodeRenderer = class {
|
|
|
387
519
|
}
|
|
388
520
|
getNodePosition(nodeId) {
|
|
389
521
|
const state = this.nodeStates.get(nodeId);
|
|
390
|
-
return state ? state.
|
|
522
|
+
return state ? state.sprite.position.clone() : null;
|
|
391
523
|
}
|
|
392
524
|
getNodeObject(nodeId) {
|
|
393
525
|
const state = this.nodeStates.get(nodeId);
|
|
394
|
-
return state?.
|
|
526
|
+
return state?.sprite ?? null;
|
|
395
527
|
}
|
|
396
528
|
getNodeObjects() {
|
|
397
|
-
return Array.from(this.nodeStates.values()).map((state) => state.
|
|
529
|
+
return Array.from(this.nodeStates.values()).map((state) => state.sprite);
|
|
398
530
|
}
|
|
399
531
|
setHoveredNode(nodeId) {
|
|
400
532
|
if (this.hoveredNodeId === nodeId) return;
|
|
@@ -432,13 +564,16 @@ var NodeRenderer = class {
|
|
|
432
564
|
const drift = Math.sin(elapsed * this.config.ambientMotionSpeed + state.phase) * this.config.ambientMotionAmplitude;
|
|
433
565
|
const driftX = Math.cos(elapsed * this.config.ambientMotionSpeed * 0.6 + state.phase) * this.config.ambientMotionAmplitude * 0.45;
|
|
434
566
|
const driftZ = Math.sin(elapsed * this.config.ambientMotionSpeed * 0.4 + state.phase) * this.config.ambientMotionAmplitude * 0.35;
|
|
435
|
-
state.
|
|
567
|
+
state.sprite.position.set(
|
|
436
568
|
state.basePosition.x + driftX,
|
|
437
569
|
state.basePosition.y + drift,
|
|
438
570
|
state.basePosition.z + driftZ
|
|
439
571
|
);
|
|
440
572
|
} else {
|
|
441
|
-
state.
|
|
573
|
+
state.sprite.position.copy(state.basePosition);
|
|
574
|
+
}
|
|
575
|
+
if (state.label) {
|
|
576
|
+
state.label.position.copy(state.sprite.position).add(this.labelOffset);
|
|
442
577
|
}
|
|
443
578
|
const hoverScale = state.hovered ? this.config.hoverScale : 1;
|
|
444
579
|
const selectedScale = state.selected ? this.config.selectedScale : 1;
|
|
@@ -452,17 +587,42 @@ var NodeRenderer = class {
|
|
|
452
587
|
}
|
|
453
588
|
}
|
|
454
589
|
const targetScale = state.baseScale * hoverScale * selectedScale * (1 + pulseScale);
|
|
455
|
-
const currentScale = state.
|
|
590
|
+
const currentScale = state.sprite.scale.x;
|
|
456
591
|
const nextScale = currentScale + (targetScale - currentScale) * 0.18;
|
|
457
|
-
state.
|
|
458
|
-
const material = state.
|
|
459
|
-
const
|
|
460
|
-
|
|
592
|
+
state.sprite.scale.setScalar(nextScale);
|
|
593
|
+
const material = state.material;
|
|
594
|
+
const baseOpacity = 0.78;
|
|
595
|
+
const hoverOpacity = Math.min(0.95, baseOpacity + 0.12);
|
|
596
|
+
const selectedOpacity = 1;
|
|
597
|
+
material.opacity = state.selected ? selectedOpacity : state.hovered ? hoverOpacity : baseOpacity;
|
|
598
|
+
material.color.copy(state.baseColor);
|
|
599
|
+
if (state.selected) {
|
|
600
|
+
material.color.lerp(new THREE__namespace.Color("#ffffff"), 0.25);
|
|
601
|
+
}
|
|
461
602
|
});
|
|
462
603
|
}
|
|
463
604
|
dispose() {
|
|
464
605
|
this.clear();
|
|
465
606
|
this.scene.remove(this.group);
|
|
607
|
+
this.glowTexture?.dispose();
|
|
608
|
+
this.glowTexture = null;
|
|
609
|
+
}
|
|
610
|
+
createGlowTexture() {
|
|
611
|
+
const size = 256;
|
|
612
|
+
const canvas = document.createElement("canvas");
|
|
613
|
+
canvas.width = size;
|
|
614
|
+
canvas.height = size;
|
|
615
|
+
const ctx = canvas.getContext("2d");
|
|
616
|
+
if (!ctx) return null;
|
|
617
|
+
const gradient = ctx.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2);
|
|
618
|
+
gradient.addColorStop(0, "rgba(255,255,255,0.95)");
|
|
619
|
+
gradient.addColorStop(0.4, "rgba(255,255,255,0.45)");
|
|
620
|
+
gradient.addColorStop(1, "rgba(255,255,255,0)");
|
|
621
|
+
ctx.fillStyle = gradient;
|
|
622
|
+
ctx.fillRect(0, 0, size, size);
|
|
623
|
+
const texture = new THREE__namespace.CanvasTexture(canvas);
|
|
624
|
+
texture.colorSpace = THREE__namespace.SRGBColorSpace;
|
|
625
|
+
return texture;
|
|
466
626
|
}
|
|
467
627
|
};
|
|
468
628
|
var EdgeRenderer = class {
|
|
@@ -586,6 +746,35 @@ var EdgeRenderer = class {
|
|
|
586
746
|
|
|
587
747
|
// src/visualization/layouts/fuzzy-layout.ts
|
|
588
748
|
var GOLDEN_ANGLE = Math.PI * (3 - Math.sqrt(5));
|
|
749
|
+
var ATLAS_POSITION_OVERRIDES = {
|
|
750
|
+
uap: [6, 2, 2],
|
|
751
|
+
ez1: [2, 4, 0],
|
|
752
|
+
neph: [-3, 3, 2],
|
|
753
|
+
jude6: [-1, 1.5, 2.5],
|
|
754
|
+
"2p24": [1.2, 0.3, 2.6],
|
|
755
|
+
aiimg: [4.6, -1.6, 1.8],
|
|
756
|
+
rev13: [2.7, -2.8, 0.6],
|
|
757
|
+
xhuman: [0.4, -3.4, -1.8],
|
|
758
|
+
dan243: [-1.6, -2.1, -2.9],
|
|
759
|
+
llm: [3.4, 0.3, -2.4],
|
|
760
|
+
babel: [0.9, 1.4, -3.4],
|
|
761
|
+
warfare: [-4.6, 0.4, -1.5],
|
|
762
|
+
eph612: [-5.5, -1.7, 0.5],
|
|
763
|
+
berea: [-0.2, 4.6, -1.3],
|
|
764
|
+
pharm: [-3.1, -2.4, 1.2],
|
|
765
|
+
testsp: [5.4, 3.2, 1.6]
|
|
766
|
+
};
|
|
767
|
+
function generateSpherePosition(index, total, radius) {
|
|
768
|
+
if (total <= 1) {
|
|
769
|
+
return [0, 0, 0];
|
|
770
|
+
}
|
|
771
|
+
const offset = 2 / total;
|
|
772
|
+
const increment = Math.PI * (3 - Math.sqrt(5));
|
|
773
|
+
const y = 1 - index * offset;
|
|
774
|
+
const r = Math.sqrt(Math.max(0, 1 - y * y));
|
|
775
|
+
const phi = index * increment;
|
|
776
|
+
return [Math.cos(phi) * r * radius, y * radius, Math.sin(phi) * r * radius];
|
|
777
|
+
}
|
|
589
778
|
function hashString(input) {
|
|
590
779
|
let hash = 2166136261;
|
|
591
780
|
for (let i = 0; i < input.length; i += 1) {
|
|
@@ -607,17 +796,53 @@ function buildSeed(baseSeed, nodeKey) {
|
|
|
607
796
|
return mulberry32(hashString(`${baseSeed}:${nodeKey}`));
|
|
608
797
|
}
|
|
609
798
|
function applyFuzzyLayout(nodes, options = {}) {
|
|
610
|
-
const mode = options.mode ?? "
|
|
799
|
+
const mode = options.mode ?? "atlas";
|
|
611
800
|
if (mode === "positioned") {
|
|
612
801
|
return nodes;
|
|
613
802
|
}
|
|
614
|
-
const needsLayout =
|
|
615
|
-
if (!needsLayout) {
|
|
803
|
+
const needsLayout = nodes.some((node) => !node.position);
|
|
804
|
+
if (mode === "auto" && !needsLayout) {
|
|
616
805
|
return nodes;
|
|
617
806
|
}
|
|
807
|
+
const spread = options.spread ?? 1;
|
|
808
|
+
const overrides = { ...ATLAS_POSITION_OVERRIDES, ...options.overrides ?? {} };
|
|
809
|
+
if (mode === "atlas" || mode === "auto") {
|
|
810
|
+
const baseRadius2 = (options.radius ?? 12) * spread;
|
|
811
|
+
const insightRadius = (options.insightRadius ?? Math.max(5, baseRadius2 * 0.4)) * spread;
|
|
812
|
+
const canonicalNodes = nodes.filter(
|
|
813
|
+
(node) => node.tier !== "insight" && node.domain !== "insight"
|
|
814
|
+
);
|
|
815
|
+
const insightNodes = nodes.filter(
|
|
816
|
+
(node) => node.tier === "insight" || node.domain === "insight"
|
|
817
|
+
);
|
|
818
|
+
const canonicalPositions = /* @__PURE__ */ new Map();
|
|
819
|
+
const insightPositions = /* @__PURE__ */ new Map();
|
|
820
|
+
canonicalNodes.forEach((node, index) => {
|
|
821
|
+
canonicalPositions.set(
|
|
822
|
+
node.id,
|
|
823
|
+
generateSpherePosition(index, canonicalNodes.length, baseRadius2)
|
|
824
|
+
);
|
|
825
|
+
});
|
|
826
|
+
insightNodes.forEach((node, index) => {
|
|
827
|
+
insightPositions.set(
|
|
828
|
+
node.id,
|
|
829
|
+
generateSpherePosition(index, insightNodes.length || 1, insightRadius)
|
|
830
|
+
);
|
|
831
|
+
});
|
|
832
|
+
return nodes.map((node) => {
|
|
833
|
+
const override = overrides[node.id] ?? overrides[node.slug];
|
|
834
|
+
if (node.position && !override) {
|
|
835
|
+
return node;
|
|
836
|
+
}
|
|
837
|
+
if (override) {
|
|
838
|
+
return { ...node, position: [...override] };
|
|
839
|
+
}
|
|
840
|
+
const fallback = (node.tier === "insight" || node.domain === "insight" ? insightPositions.get(node.id) : canonicalPositions.get(node.id)) ?? [0, 0, 0];
|
|
841
|
+
return { ...node, position: fallback };
|
|
842
|
+
});
|
|
843
|
+
}
|
|
618
844
|
const baseSeed = options.seed ?? "omi-neuron-web";
|
|
619
845
|
const count = Math.max(nodes.length, 1);
|
|
620
|
-
const spread = options.spread ?? 1.2;
|
|
621
846
|
const baseRadius = (options.radius ?? Math.max(4, Math.sqrt(count) * 2.4)) * spread;
|
|
622
847
|
const jitter = (options.jitter ?? baseRadius * 0.12) * spread;
|
|
623
848
|
const zSpread = (options.zSpread ?? baseRadius * 0.6) * spread;
|
|
@@ -820,6 +1045,8 @@ function NeuronWeb({
|
|
|
820
1045
|
graphData,
|
|
821
1046
|
className,
|
|
822
1047
|
style,
|
|
1048
|
+
fullHeight,
|
|
1049
|
+
isFullScreen,
|
|
823
1050
|
isLoading,
|
|
824
1051
|
error,
|
|
825
1052
|
renderEmptyState,
|
|
@@ -859,17 +1086,18 @@ function NeuronWeb({
|
|
|
859
1086
|
}, [performanceMode, graphData.nodes.length]);
|
|
860
1087
|
const sceneManager = useSceneManager(containerRef, {
|
|
861
1088
|
backgroundColor: resolvedTheme.colors.background,
|
|
1089
|
+
cameraFov: 52,
|
|
862
1090
|
cameraPosition: [4, 8, 20],
|
|
863
1091
|
cameraTarget: [0, 0, 0],
|
|
864
1092
|
minZoom: 4,
|
|
865
1093
|
maxZoom: 42,
|
|
866
1094
|
enableStarfield: resolvedTheme.effects.starfieldEnabled,
|
|
867
|
-
starfieldCount: 1200,
|
|
1095
|
+
starfieldCount: resolvedPerformanceMode === "normal" ? 1200 : 700,
|
|
868
1096
|
starfieldColor: resolvedTheme.effects.starfieldColor,
|
|
869
1097
|
pixelRatioCap: 2,
|
|
870
|
-
ambientLightIntensity: 0.
|
|
871
|
-
keyLightIntensity:
|
|
872
|
-
fillLightIntensity: 0.
|
|
1098
|
+
ambientLightIntensity: 0.9,
|
|
1099
|
+
keyLightIntensity: 0.6,
|
|
1100
|
+
fillLightIntensity: 0.4,
|
|
873
1101
|
fogEnabled: resolvedTheme.effects.fogEnabled,
|
|
874
1102
|
fogColor: resolvedTheme.effects.fogColor,
|
|
875
1103
|
fogNear: resolvedTheme.effects.fogNear,
|
|
@@ -880,16 +1108,22 @@ function NeuronWeb({
|
|
|
880
1108
|
return new NodeRenderer(sceneManager.scene, {
|
|
881
1109
|
domainColors: resolvedTheme.colors.domainColors,
|
|
882
1110
|
defaultColor: resolvedTheme.colors.defaultDomainColor,
|
|
883
|
-
baseScale:
|
|
1111
|
+
baseScale: 1.15,
|
|
884
1112
|
tierScales: {
|
|
885
|
-
primary: 1.
|
|
886
|
-
secondary: 1.
|
|
887
|
-
tertiary:
|
|
888
|
-
insight: 1
|
|
1113
|
+
primary: 1.25,
|
|
1114
|
+
secondary: 1.1,
|
|
1115
|
+
tertiary: 0.95,
|
|
1116
|
+
insight: 1.05
|
|
889
1117
|
},
|
|
890
1118
|
glowIntensity: resolvedTheme.effects.glowEnabled ? resolvedTheme.effects.glowIntensity : 0,
|
|
891
|
-
labelDistance:
|
|
892
|
-
maxVisibleLabels:
|
|
1119
|
+
labelDistance: resolvedPerformanceMode === "normal" ? 26 : 0,
|
|
1120
|
+
maxVisibleLabels: resolvedPerformanceMode === "normal" ? 80 : 0,
|
|
1121
|
+
labelOffset: [0, 0.65, 0],
|
|
1122
|
+
labelFontFamily: resolvedTheme.typography.labelFontFamily,
|
|
1123
|
+
labelFontSize: resolvedTheme.typography.labelFontSize,
|
|
1124
|
+
labelFontWeight: resolvedTheme.typography.labelFontWeight,
|
|
1125
|
+
labelTextColor: resolvedTheme.colors.labelText,
|
|
1126
|
+
labelBackground: resolvedTheme.colors.labelBackground,
|
|
893
1127
|
ambientMotionEnabled: resolvedTheme.effects.ambientMotionEnabled && resolvedPerformanceMode === "normal",
|
|
894
1128
|
ambientMotionAmplitude: resolvedTheme.effects.ambientMotionAmplitude,
|
|
895
1129
|
ambientMotionSpeed: resolvedTheme.effects.ambientMotionSpeed,
|
|
@@ -905,7 +1139,7 @@ function NeuronWeb({
|
|
|
905
1139
|
defaultColor: resolvedTheme.colors.edgeDefault,
|
|
906
1140
|
activeColor: resolvedTheme.colors.edgeActive,
|
|
907
1141
|
selectedColor: resolvedTheme.colors.edgeSelected,
|
|
908
|
-
baseOpacity: 0.
|
|
1142
|
+
baseOpacity: 0.45,
|
|
909
1143
|
strengthOpacityScale: true,
|
|
910
1144
|
edgeFlowEnabled: resolvedTheme.effects.edgeFlowEnabled && resolvedPerformanceMode === "normal",
|
|
911
1145
|
edgeFlowSpeed: resolvedTheme.effects.edgeFlowSpeed
|
|
@@ -986,6 +1220,7 @@ function NeuronWeb({
|
|
|
986
1220
|
if (!sceneManager || !nodeRenderer || !edgeRenderer) return;
|
|
987
1221
|
return sceneManager.addFrameListener((delta, elapsed) => {
|
|
988
1222
|
nodeRenderer.update(delta, elapsed);
|
|
1223
|
+
nodeRenderer.updateLabelVisibility(sceneManager.camera);
|
|
989
1224
|
edgeRenderer.update(delta, elapsed);
|
|
990
1225
|
animationController?.update();
|
|
991
1226
|
if (hoverCardRef.current && hoveredNodeId) {
|
|
@@ -1106,14 +1341,30 @@ function NeuronWeb({
|
|
|
1106
1341
|
if (!resolvedNodes.length) {
|
|
1107
1342
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, "aria-label": ariaLabel, children: renderEmptyState ? renderEmptyState() : /* @__PURE__ */ jsxRuntime.jsx("div", { children: "No data" }) });
|
|
1108
1343
|
}
|
|
1344
|
+
const resolvedStyle = {
|
|
1345
|
+
position: isFullScreen ? "fixed" : "relative",
|
|
1346
|
+
inset: isFullScreen ? 0 : void 0,
|
|
1347
|
+
width: isFullScreen ? "100vw" : "100%",
|
|
1348
|
+
height: isFullScreen ? "100vh" : "100%",
|
|
1349
|
+
minHeight: !isFullScreen && fullHeight ? "100vh" : void 0,
|
|
1350
|
+
overflow: "hidden",
|
|
1351
|
+
background: resolvedTheme.colors.background,
|
|
1352
|
+
...style
|
|
1353
|
+
};
|
|
1109
1354
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1110
1355
|
"div",
|
|
1111
1356
|
{
|
|
1112
1357
|
className,
|
|
1113
|
-
style:
|
|
1358
|
+
style: resolvedStyle,
|
|
1114
1359
|
"aria-label": ariaLabel,
|
|
1115
1360
|
children: [
|
|
1116
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1361
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1362
|
+
"div",
|
|
1363
|
+
{
|
|
1364
|
+
ref: containerRef,
|
|
1365
|
+
style: { position: "absolute", inset: 0, width: "100%", height: "100%" }
|
|
1366
|
+
}
|
|
1367
|
+
),
|
|
1117
1368
|
hoverCardEnabled && hoveredNode && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1118
1369
|
"div",
|
|
1119
1370
|
{
|
|
@@ -1216,5 +1467,5 @@ exports.NeuronWeb = NeuronWeb;
|
|
|
1216
1467
|
exports.SceneManager = SceneManager;
|
|
1217
1468
|
exports.ThemeEngine = ThemeEngine;
|
|
1218
1469
|
exports.applyFuzzyLayout = applyFuzzyLayout;
|
|
1219
|
-
//# sourceMappingURL=chunk-
|
|
1220
|
-
//# sourceMappingURL=chunk-
|
|
1470
|
+
//# sourceMappingURL=chunk-U7K7KQZG.cjs.map
|
|
1471
|
+
//# sourceMappingURL=chunk-U7K7KQZG.cjs.map
|