@ltm-blueverse/alpha-semantic-hub 0.7.0

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.
Files changed (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1674 -0
  3. package/explorer/README.md +282 -0
  4. package/explorer/src/App.css +0 -0
  5. package/explorer/src/App.tsx +2035 -0
  6. package/explorer/src/ErrorBoundary.tsx +112 -0
  7. package/explorer/src/ExploreWorkspaceTabs.tsx +29 -0
  8. package/explorer/src/assets/hero.png +0 -0
  9. package/explorer/src/assets/react.svg +1 -0
  10. package/explorer/src/assets/vite.svg +1 -0
  11. package/explorer/src/explorerCapabilities.ts +24 -0
  12. package/explorer/src/index.css +71 -0
  13. package/explorer/src/main.tsx +7 -0
  14. package/explorer/src/store/edgePairKeys.d.ts +2 -0
  15. package/explorer/src/store/edgePairKeys.js +7 -0
  16. package/explorer/src/store/graphStore.ts +183 -0
  17. package/explorer/src/store/registryStore.ts +78 -0
  18. package/explorer/src/types.d.ts +16 -0
  19. package/explorer/src/ui/primitives.css +414 -0
  20. package/explorer/src/ui/primitives.tsx +170 -0
  21. package/explorer/src/workspaces/DecisionWorkspace/DecisionWorkspace.tsx +279 -0
  22. package/explorer/src/workspaces/DiffMergeWorkspace/DiffMergeWorkspace.tsx +121 -0
  23. package/explorer/src/workspaces/EnrichWorkspace/EntityResolutionTab.tsx +454 -0
  24. package/explorer/src/workspaces/EnrichWorkspace/RegistryTab.tsx +285 -0
  25. package/explorer/src/workspaces/GraphWorkspace/GraphCanvas.tsx +2673 -0
  26. package/explorer/src/workspaces/GraphWorkspace/GraphInspectorPanel.tsx +771 -0
  27. package/explorer/src/workspaces/GraphWorkspace/GraphLoadingOverlay.tsx +410 -0
  28. package/explorer/src/workspaces/GraphWorkspace/GraphWorkspace.tsx +3584 -0
  29. package/explorer/src/workspaces/GraphWorkspace/MarkdownContentViewer.tsx +705 -0
  30. package/explorer/src/workspaces/GraphWorkspace/SigmaSceneAdapter.tsx +55 -0
  31. package/explorer/src/workspaces/GraphWorkspace/TimelinePanel.tsx +193 -0
  32. package/explorer/src/workspaces/GraphWorkspace/behaviors/clickSelectionBehavior.ts +29 -0
  33. package/explorer/src/workspaces/GraphWorkspace/behaviors/fitViewBehavior.ts +15 -0
  34. package/explorer/src/workspaces/GraphWorkspace/behaviors/focusCameraBehavior.ts +25 -0
  35. package/explorer/src/workspaces/GraphWorkspace/behaviors/hoverActivationBehavior.ts +15 -0
  36. package/explorer/src/workspaces/GraphWorkspace/behaviors/pathHighlightBehavior.ts +52 -0
  37. package/explorer/src/workspaces/GraphWorkspace/behaviors/searchFocusBehavior.ts +36 -0
  38. package/explorer/src/workspaces/GraphWorkspace/behaviors/types.ts +41 -0
  39. package/explorer/src/workspaces/GraphWorkspace/behaviors/viewModeSwitchBehavior.ts +29 -0
  40. package/explorer/src/workspaces/GraphWorkspace/graphAnalytics.ts +779 -0
  41. package/explorer/src/workspaces/GraphWorkspace/graphColorLegend.ts +36 -0
  42. package/explorer/src/workspaces/GraphWorkspace/graphConfig.ts +102 -0
  43. package/explorer/src/workspaces/GraphWorkspace/graphEntityShape.ts +34 -0
  44. package/explorer/src/workspaces/GraphWorkspace/graphLoading.ts +84 -0
  45. package/explorer/src/workspaces/GraphWorkspace/graphSceneLayers.ts +775 -0
  46. package/explorer/src/workspaces/GraphWorkspace/graphSceneState.ts +2753 -0
  47. package/explorer/src/workspaces/GraphWorkspace/graphStructureLayer.ts +335 -0
  48. package/explorer/src/workspaces/GraphWorkspace/graphTheme.ts +1078 -0
  49. package/explorer/src/workspaces/GraphWorkspace/graphViewCopy.ts +41 -0
  50. package/explorer/src/workspaces/GraphWorkspace/localGraphTransition.ts +9 -0
  51. package/explorer/src/workspaces/GraphWorkspace/markdownEditorState.ts +114 -0
  52. package/explorer/src/workspaces/GraphWorkspace/markdownResourceClient.ts +103 -0
  53. package/explorer/src/workspaces/GraphWorkspace/markdownUrlSafety.ts +29 -0
  54. package/explorer/src/workspaces/GraphWorkspace/nodeMarkdownSync.ts +81 -0
  55. package/explorer/src/workspaces/GraphWorkspace/pluginRegistryPredicates.ts +24 -0
  56. package/explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPlugin.tsx +353 -0
  57. package/explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPluginPhaseC.tsx +522 -0
  58. package/explorer/src/workspaces/GraphWorkspace/plugins/index.ts +16 -0
  59. package/explorer/src/workspaces/GraphWorkspace/plugins/legendPlugin.tsx +120 -0
  60. package/explorer/src/workspaces/GraphWorkspace/plugins/neighborhoodPanelPlugin.tsx +231 -0
  61. package/explorer/src/workspaces/GraphWorkspace/plugins/temporalOverlayPlugin.tsx +142 -0
  62. package/explorer/src/workspaces/GraphWorkspace/plugins/types.ts +106 -0
  63. package/explorer/src/workspaces/GraphWorkspace/realtimeGraphAttributes.ts +50 -0
  64. package/explorer/src/workspaces/GraphWorkspace/scene.ts +79 -0
  65. package/explorer/src/workspaces/GraphWorkspace/sigmaNativeRendering.ts +421 -0
  66. package/explorer/src/workspaces/GraphWorkspace/smallGraphLayout.ts +135 -0
  67. package/explorer/src/workspaces/GraphWorkspace/temporalLifecyclePredicates.ts +31 -0
  68. package/explorer/src/workspaces/GraphWorkspace/temporalScrubberBounds.ts +46 -0
  69. package/explorer/src/workspaces/GraphWorkspace/temporalSnapshotGuards.ts +113 -0
  70. package/explorer/src/workspaces/GraphWorkspace/types.ts +395 -0
  71. package/explorer/src/workspaces/GraphWorkspace/useLoadGraph.ts +746 -0
  72. package/explorer/src/workspaces/GraphWorkspace/useMarkdownEditor.ts +177 -0
  73. package/explorer/src/workspaces/ImportExportWorkspace/ImportExportWorkspace.tsx +196 -0
  74. package/explorer/src/workspaces/LineageWorkspace/LineageDiagram.tsx +177 -0
  75. package/explorer/src/workspaces/ManageWorkspace/KGOverviewTab.tsx +291 -0
  76. package/explorer/src/workspaces/ManageWorkspace/OntologySummaryTab.tsx +346 -0
  77. package/explorer/src/workspaces/MemoryWorkspace.tsx +464 -0
  78. package/explorer/src/workspaces/OntologyWorkspace/AlignmentsTab.tsx +437 -0
  79. package/explorer/src/workspaces/OntologyWorkspace/HealthTab.tsx +214 -0
  80. package/explorer/src/workspaces/OntologyWorkspace/OntologyEditor.tsx +770 -0
  81. package/explorer/src/workspaces/OntologyWorkspace/OntologyLoader.tsx +913 -0
  82. package/explorer/src/workspaces/OntologyWorkspace/OntologyManager.tsx +930 -0
  83. package/explorer/src/workspaces/OntologyWorkspace/OntologySearch.tsx +590 -0
  84. package/explorer/src/workspaces/OntologyWorkspace/ProposalReview.tsx +429 -0
  85. package/explorer/src/workspaces/OntologyWorkspace/SKOSVocabularyManager.tsx +696 -0
  86. package/explorer/src/workspaces/OntologyWorkspace/ShaclStudio.tsx +363 -0
  87. package/explorer/src/workspaces/OntologyWorkspace/VersionsTab.tsx +546 -0
  88. package/explorer/src/workspaces/OntologyWorkspace/api.ts +164 -0
  89. package/explorer/src/workspaces/OntologyWorkspace/index.tsx +101 -0
  90. package/explorer/src/workspaces/OntologyWorkspace/ontologyEditorModel.ts +87 -0
  91. package/explorer/src/workspaces/OntologyWorkspace/ontologyUrlState.ts +94 -0
  92. package/explorer/src/workspaces/OntologyWorkspace/types.ts +119 -0
  93. package/explorer/src/workspaces/ReasoningWorkspace.tsx +243 -0
  94. package/explorer/src/workspaces/SparqlWorkspace/SparqlWorkspace.tsx +271 -0
  95. package/explorer/src/workspaces/VocabularyWorkspace/ConceptTree.tsx +97 -0
  96. package/explorer/src/workspaces/VocabularyWorkspace/ImportDropzone.tsx +95 -0
  97. package/explorer/src/workspaces/VocabularyWorkspace/PropertyPanel.tsx +116 -0
  98. package/explorer/src/workspaces/VocabularyWorkspace/Sidebar.tsx +112 -0
  99. package/explorer/src/workspaces/VocabularyWorkspace/VocabularyWorkspace.tsx +70 -0
  100. package/explorer/src/workspaces/VocabularyWorkspace/queries.ts +52 -0
  101. package/explorer/src/workspaces/VocabularyWorkspace/types.ts +24 -0
  102. package/package.json +31 -0
  103. package/plugins/.claude-plugin/README.md +262 -0
  104. package/plugins/.claude-plugin/marketplace.json +20 -0
  105. package/plugins/.claude-plugin/plugin.json +33 -0
  106. package/plugins/.cline-plugin/README.md +32 -0
  107. package/plugins/.cline-plugin/marketplace.json +17 -0
  108. package/plugins/.cline-plugin/plugin.json +35 -0
  109. package/plugins/.codex-plugin/marketplace.json +21 -0
  110. package/plugins/.codex-plugin/plugin.json +35 -0
  111. package/plugins/.continue-plugin/README.md +34 -0
  112. package/plugins/.continue-plugin/marketplace.json +17 -0
  113. package/plugins/.continue-plugin/plugin.json +33 -0
  114. package/plugins/.cursor-plugin/marketplace.json +18 -0
  115. package/plugins/.cursor-plugin/plugin.json +32 -0
  116. package/plugins/.openclaw-plugin/README.md +62 -0
  117. package/plugins/.openclaw-plugin/marketplace.json +18 -0
  118. package/plugins/.openclaw-plugin/plugin.json +46 -0
  119. package/plugins/.pi-plugin/README.md +35 -0
  120. package/plugins/.vscode-plugin/README.md +48 -0
  121. package/plugins/.vscode-plugin/marketplace.json +17 -0
  122. package/plugins/.vscode-plugin/plugin.json +35 -0
  123. package/plugins/.windsurf-plugin/README.md +39 -0
  124. package/plugins/.windsurf-plugin/marketplace.json +17 -0
  125. package/plugins/.windsurf-plugin/plugin.json +35 -0
  126. package/plugins/agents/decision-advisor.md +126 -0
  127. package/plugins/agents/explainability.md +129 -0
  128. package/plugins/agents/kg-assistant.md +73 -0
  129. package/plugins/hooks/hooks.json +12 -0
  130. package/plugins/skills/causal/SKILL.md +74 -0
  131. package/plugins/skills/change/SKILL.md +80 -0
  132. package/plugins/skills/decision/SKILL.md +197 -0
  133. package/plugins/skills/deduplicate/SKILL.md +41 -0
  134. package/plugins/skills/embed/SKILL.md +230 -0
  135. package/plugins/skills/explain/SKILL.md +44 -0
  136. package/plugins/skills/export/SKILL.md +67 -0
  137. package/plugins/skills/extract/SKILL.md +93 -0
  138. package/plugins/skills/ingest/SKILL.md +38 -0
  139. package/plugins/skills/ontology/SKILL.md +89 -0
  140. package/plugins/skills/policy/SKILL.md +66 -0
  141. package/plugins/skills/provenance/SKILL.md +70 -0
  142. package/plugins/skills/query/SKILL.md +84 -0
  143. package/plugins/skills/reason/SKILL.md +201 -0
  144. package/plugins/skills/temporal/SKILL.md +164 -0
  145. package/plugins/skills/validate/SKILL.md +228 -0
  146. package/plugins/skills/visualize/SKILL.md +249 -0
@@ -0,0 +1,1078 @@
1
+ export type GraphZoomTier = "overview" | "structure" | "inspection";
2
+ export type GraphNodeVisualState = "default" | "hovered" | "selected" | "neighbor" | "path" | "inactive" | "muted";
3
+ export type GraphEdgeVisualState = "default" | "backbone" | "hovered" | "selected" | "neighbor" | "path" | "inactive" | "muted";
4
+ export type GraphNodeShapeVariant = "default" | "temporal" | "inferred" | "provenance" | "selected";
5
+ export type GraphEntityShapeVariant = "entity" | "biomolecule" | "condition" | "compound" | "process" | "community";
6
+ export type GraphEdgeVariant = "line" | "directional" | "bidirectionalCurve" | "parallelCurve" | "pathSignal";
7
+ export type GraphArrowVisibilityPolicy = "hidden" | "contextual" | "always";
8
+ export type GraphLabelVisibilityPolicy = "none" | "priority" | "local" | "always";
9
+ export type GraphBadgeKind = "inferred" | "temporal" | "provenance";
10
+
11
+ type GraphNodeColorMode = "base" | "selected" | "hovered" | "path" | "muted";
12
+ type GraphEdgeColorMode = "overview" | "backbone" | "structure" | "inspection" | "hover" | "path" | "focus" | "muted";
13
+ const IS_DEV = Boolean((import.meta as { env?: { DEV?: boolean } }).env?.DEV);
14
+
15
+ export interface GraphTheme {
16
+ palette: {
17
+ semantic: string[];
18
+ overview: {
19
+ nodeBase: string;
20
+ nodeCore: string;
21
+ nodeMuted: string;
22
+ nodeBorder: string;
23
+ nodeTintMix: number;
24
+ nodeCoreMix: number;
25
+ nodeShellAlpha: number;
26
+ nodeCoreAlpha: number;
27
+ edgeBackbone: string;
28
+ edgeStructure: string;
29
+ edgeInspection: string;
30
+ };
31
+ accent: {
32
+ selected: string;
33
+ hovered: string;
34
+ path: string;
35
+ temporal: string;
36
+ provenance: string;
37
+ inferred: string;
38
+ };
39
+ muted: {
40
+ fallback: string;
41
+ nodeAlpha: number;
42
+ edgeOverview: string;
43
+ edgeStructure: string;
44
+ edgeInspection: string;
45
+ edgeFocus: string;
46
+ };
47
+ background: {
48
+ canvas: string;
49
+ shell: string;
50
+ shellBorder: string;
51
+ shellGlow: string;
52
+ grid: string;
53
+ vignette: string;
54
+ nodeBorder: string;
55
+ };
56
+ };
57
+ ui: {
58
+ text: {
59
+ strong: string;
60
+ body: string;
61
+ muted: string;
62
+ subtle: string;
63
+ inverse: string;
64
+ };
65
+ surface: {
66
+ app: string;
67
+ stage: string;
68
+ card: string;
69
+ cardSubtle: string;
70
+ cardStrong: string;
71
+ panel: string;
72
+ panelBorder: string;
73
+ divider: string;
74
+ shadow: string;
75
+ };
76
+ scene: {
77
+ background: string;
78
+ radialGlow: string;
79
+ grid: string;
80
+ gridStrong: string;
81
+ vignette: string;
82
+ };
83
+ control: {
84
+ defaultBg: string;
85
+ defaultBorder: string;
86
+ defaultText: string;
87
+ hoverBg: string;
88
+ activeBg: string;
89
+ activeBorder: string;
90
+ activeText: string;
91
+ primaryBg: string;
92
+ primaryBorder: string;
93
+ primaryText: string;
94
+ disabledText: string;
95
+ inputBg: string;
96
+ inputBorder: string;
97
+ focusRing: string;
98
+ dangerText: string;
99
+ };
100
+ timeline: {
101
+ background: string;
102
+ border: string;
103
+ gridMinor: string;
104
+ gridMajor: string;
105
+ text: string;
106
+ textStrong: string;
107
+ playhead: string;
108
+ playheadSoft: string;
109
+ };
110
+ };
111
+ zoomTiers: Record<GraphZoomTier, {
112
+ maxRatio: number;
113
+ nodeScale: number;
114
+ labelThreshold: number;
115
+ labelBudget: number;
116
+ edgePriorityThreshold: number;
117
+ arrowPriorityThreshold: number;
118
+ edgeSizeScale: number;
119
+ showBadges: boolean;
120
+ showCurves: boolean;
121
+ showContextualArrows: boolean;
122
+ }>;
123
+ labels: {
124
+ forceVisibleStates: readonly GraphNodeVisualState[];
125
+ policies: Record<GraphLabelVisibilityPolicy, {
126
+ minZoomTier: GraphZoomTier;
127
+ }>;
128
+ chip: {
129
+ fontFamily: string;
130
+ fontWeight: number;
131
+ fontSize: number;
132
+ maxFontSize: number;
133
+ sizeScale: number;
134
+ paddingX: number;
135
+ paddingY: number;
136
+ radius: number;
137
+ offsetX: number;
138
+ offsetY: number;
139
+ background: string;
140
+ borderColor: string;
141
+ borderAlpha: number;
142
+ textColor: string;
143
+ shadowColor: string;
144
+ shadowAlpha: number;
145
+ shadowBlur: number;
146
+ };
147
+ hoverCard: {
148
+ fontFamily: string;
149
+ titleWeight: number;
150
+ titleSize: number;
151
+ metaWeight: number;
152
+ metaSize: number;
153
+ paddingX: number;
154
+ paddingY: number;
155
+ radius: number;
156
+ offsetX: number;
157
+ offsetY: number;
158
+ metaGap: number;
159
+ background: string;
160
+ borderColor: string;
161
+ borderAlpha: number;
162
+ textColor: string;
163
+ metaColor: string;
164
+ shadowColor: string;
165
+ shadowAlpha: number;
166
+ shadowBlur: number;
167
+ };
168
+ };
169
+ nodes: {
170
+ backgroundScale: number;
171
+ mutedAlpha: number;
172
+ strokeHierarchy: Record<GraphZoomTier, {
173
+ base: number;
174
+ emphasis: number;
175
+ muted: number;
176
+ }>;
177
+ states: Record<GraphNodeVisualState, {
178
+ color: GraphNodeColorMode;
179
+ sizeMultiplier: number;
180
+ minSize: number;
181
+ forceLabel: boolean;
182
+ zIndex: number;
183
+ borderBoost: number;
184
+ }>;
185
+ variants: Record<GraphNodeShapeVariant, {
186
+ sizeMultiplier: number;
187
+ borderBoost: number;
188
+ haloBoost: number;
189
+ badgeKind?: GraphBadgeKind;
190
+ badgeVisibleFrom: GraphZoomTier;
191
+ }>;
192
+ entityShapes: Record<GraphEntityShapeVariant, {
193
+ label: string;
194
+ shapeKind: number;
195
+ aspectRatio: number;
196
+ fillAlpha: number;
197
+ shellAlpha: number;
198
+ coreScale: number;
199
+ borderBoost: number;
200
+ minSize: number;
201
+ }>;
202
+ selectedRing: {
203
+ color: string;
204
+ width: number;
205
+ nativeSize: number;
206
+ glowAlpha: number;
207
+ visibleFrom: GraphZoomTier;
208
+ };
209
+ badges: Record<GraphBadgeKind, {
210
+ color: string;
211
+ label: string;
212
+ }>;
213
+ badge: {
214
+ radius: number;
215
+ offset: number;
216
+ fontSize: number;
217
+ textColor: string;
218
+ background: string;
219
+ stroke: string;
220
+ glowAlpha: number;
221
+ };
222
+ };
223
+ edges: {
224
+ states: Record<GraphEdgeVisualState, {
225
+ color: GraphEdgeColorMode;
226
+ sizeMultiplier: number;
227
+ minSize: number;
228
+ zIndex: number;
229
+ forceArrow: boolean;
230
+ hide: boolean;
231
+ }>;
232
+ variants: Record<GraphEdgeVariant, {
233
+ baseType: "line" | "arrow";
234
+ arrowPolicy: GraphArrowVisibilityPolicy;
235
+ curveStrength: number;
236
+ sizeMultiplier: number;
237
+ glowAlpha: number;
238
+ }>;
239
+ visibility: Record<"full" | "grouped" | "focused", Record<GraphZoomTier, {
240
+ defaultPriorityThreshold: number;
241
+ backgroundSampleRate: number;
242
+ defaultAlpha: number;
243
+ mutedAlpha: number;
244
+ inactiveAlpha: number;
245
+ neighborAlpha: number;
246
+ sizeMultiplier: number;
247
+ hideMuted: boolean;
248
+ }>>;
249
+ contextCaps: Record<"full" | "grouped" | "focused", Record<GraphZoomTier, number>>;
250
+ fullGraphStructure: {
251
+ ambientBackboneAlpha: number;
252
+ backboneAlpha: number;
253
+ bridgeAlpha: number;
254
+ bridgeCurvePriorityThreshold: number;
255
+ bridgeCurveStrength: number;
256
+ backboneMaxSize: number;
257
+ bridgeMaxSize: number;
258
+ structureEdgeAlpha: number;
259
+ inspectionEdgeAlpha: number;
260
+ };
261
+ fullGraphStructureLayer: {
262
+ mode: "off" | "auto" | "always";
263
+ minimumLiteralEdges: number;
264
+ minimumCurves: number;
265
+ maxCurves: number;
266
+ bridgeAlpha: number;
267
+ backboneAlpha: number;
268
+ bridgeLineWidth: number;
269
+ backboneLineWidth: number;
270
+ curveStrength: number;
271
+ };
272
+ };
273
+ interaction: {
274
+ localContextAlpha: number;
275
+ hoverContextAlpha: number;
276
+ selectedEdgeAlpha: number;
277
+ pathEdgeAlpha: number;
278
+ localContextMaxSize: number;
279
+ selectedEdgeMaxSize: number;
280
+ pathEdgeMaxSize: number;
281
+ pathOverlayAlpha: number;
282
+ };
283
+ overlays: {
284
+ hoverGlowAlpha: number;
285
+ pathGlowAlpha: number;
286
+ glowRadiusMultiplier: number;
287
+ minGlowRadius: number;
288
+ pulseRadius: number;
289
+ curveLineWidth: number;
290
+ curveGlowWidth: number;
291
+ badgeGlowRadius: number;
292
+ };
293
+ focus: {
294
+ maxNeighbors: number;
295
+ ringCapacity: number;
296
+ ringGap: number;
297
+ primaryLabels: number;
298
+ };
299
+ motion: {
300
+ cameraMs: number;
301
+ };
302
+ grouped: {
303
+ initialLayout: {
304
+ innerRadius: number;
305
+ ringSpacing: number;
306
+ minNodeSpacing: number;
307
+ nodePadding: number;
308
+ overlapIterations: number;
309
+ primaryLabelCount: number;
310
+ };
311
+ style: {
312
+ nodeSizeScale: number;
313
+ nodeBorderBoost: number;
314
+ fillAlpha: number;
315
+ shellAlpha: number;
316
+ edgeSizeScale: number;
317
+ edgeAlpha: number;
318
+ glowAlpha: number;
319
+ edgeVisibilityRatio: number;
320
+ topIncidentEdges: number;
321
+ };
322
+ layout: {
323
+ iterations: number;
324
+ gravity: number;
325
+ scalingRatio: number;
326
+ edgeWeightInfluence: number;
327
+ slowDown: number;
328
+ settleMs: number;
329
+ };
330
+ };
331
+ effects: {
332
+ pathPulse: {
333
+ minZoomTier: GraphZoomTier;
334
+ maxSegments: number;
335
+ speed: number;
336
+ radius: number;
337
+ glowAlpha: number;
338
+ };
339
+ pathFlow: {
340
+ minZoomTier: GraphZoomTier;
341
+ maxSegments: number;
342
+ speed: number;
343
+ spacing: number;
344
+ opacity: number;
345
+ radius: number;
346
+ };
347
+ lens: {
348
+ minZoomTier: GraphZoomTier;
349
+ radius: number;
350
+ feather: number;
351
+ glowAlpha: number;
352
+ edgeAlpha: number;
353
+ edgeLineWidth: number;
354
+ };
355
+ temporalEmphasis: {
356
+ minZoomTier: GraphZoomTier;
357
+ maxHighlights: number;
358
+ radiusMultiplier: number;
359
+ glowAlpha: number;
360
+ };
361
+ semanticRegions: {
362
+ minZoomTier: GraphZoomTier;
363
+ maxRegions: number;
364
+ minVisibleSamples: number;
365
+ fogResolutionScale: number;
366
+ splatRadius: number;
367
+ blurPasses: number;
368
+ densityThreshold: number;
369
+ contourThreshold: number;
370
+ minMaskPixels: number;
371
+ minOccupancyRatio: number;
372
+ dominantMassRatio: number;
373
+ outerContourMinMaskPixels: number;
374
+ fogAlpha: number;
375
+ innerContourAlpha: number;
376
+ outerContourAlpha: number;
377
+ };
378
+ contours: {
379
+ minZoomTier: GraphZoomTier;
380
+ maxContours: number;
381
+ baseRadius: number;
382
+ glowAlpha: number;
383
+ };
384
+ legend: {
385
+ maxGroups: number;
386
+ };
387
+ diagnostics: {
388
+ enabledInDev: boolean;
389
+ };
390
+ };
391
+ }
392
+
393
+ export const GRAPH_THEME: GraphTheme = {
394
+ palette: {
395
+ semantic: [
396
+ "#3E79F2",
397
+ "#149287",
398
+ "#2F9F61",
399
+ "#555FD6",
400
+ "#8A56D8",
401
+ "#B65473",
402
+ "#C9922E",
403
+ ],
404
+ overview: {
405
+ nodeBase: "#0B1320",
406
+ nodeCore: "#5A7A9E",
407
+ nodeMuted: "#121927",
408
+ nodeBorder: "#7A92AE",
409
+ nodeTintMix: 0.14,
410
+ nodeCoreMix: 0.72,
411
+ nodeShellAlpha: 0.97,
412
+ nodeCoreAlpha: 1,
413
+ edgeBackbone: "rgba(84, 123, 145, 0.24)",
414
+ edgeStructure: "rgba(49, 63, 78, 0.08)",
415
+ edgeInspection: "rgba(76, 102, 128, 0.12)",
416
+ },
417
+ accent: {
418
+ selected: "#F2D288",
419
+ hovered: "#8FE7FF",
420
+ path: "#D79056",
421
+ temporal: "#49D7FF",
422
+ provenance: "#C9A5FF",
423
+ inferred: "#D07B4D",
424
+ },
425
+ muted: {
426
+ fallback: "rgba(96, 112, 136, 0.18)",
427
+ nodeAlpha: 0.12,
428
+ edgeOverview: "rgba(32, 45, 55, 0.035)",
429
+ edgeStructure: "rgba(42, 58, 72, 0.055)",
430
+ edgeInspection: "rgba(62, 84, 104, 0.075)",
431
+ edgeFocus: "rgba(132, 178, 202, 0.26)",
432
+ },
433
+ background: {
434
+ canvas: "#0A0D11",
435
+ shell: "rgba(17, 21, 27, 0.82)",
436
+ shellBorder: "rgba(170, 184, 205, 0.14)",
437
+ shellGlow: "rgba(0, 0, 0, 0.28)",
438
+ grid: "rgba(170, 184, 205, 0.026)",
439
+ vignette: "rgba(3, 4, 7, 0.76)",
440
+ nodeBorder: "#0B0F15",
441
+ },
442
+ },
443
+ ui: {
444
+ text: {
445
+ strong: "#F3F0E8",
446
+ body: "#D5D9DD",
447
+ muted: "#9AA3AE",
448
+ subtle: "#6F7A86",
449
+ inverse: "#0B0D10",
450
+ },
451
+ surface: {
452
+ app: "#08090B",
453
+ stage: "#0B0E12",
454
+ card: "linear-gradient(180deg, rgba(28, 31, 36, 0.88), rgba(16, 18, 23, 0.78))",
455
+ cardSubtle: "linear-gradient(180deg, rgba(23, 26, 31, 0.72), rgba(13, 15, 19, 0.64))",
456
+ cardStrong: "linear-gradient(180deg, rgba(34, 37, 43, 0.94), rgba(18, 21, 26, 0.9))",
457
+ panel: "linear-gradient(180deg, rgba(21, 24, 30, 0.92), rgba(12, 14, 18, 0.9))",
458
+ panelBorder: "rgba(211, 205, 190, 0.13)",
459
+ divider: "rgba(211, 205, 190, 0.1)",
460
+ shadow: "0 22px 60px rgba(0, 0, 0, 0.34), inset 0 1px 0 rgba(255, 255, 255, 0.045)",
461
+ },
462
+ scene: {
463
+ background: "linear-gradient(180deg, #0B0E12 0%, #07080B 100%)",
464
+ radialGlow: "radial-gradient(circle at 50% 18%, rgba(88, 224, 204, 0.07), transparent 30%), radial-gradient(circle at 78% 0%, rgba(217, 168, 92, 0.055), transparent 26%)",
465
+ grid: "rgba(210, 206, 196, 0.024)",
466
+ gridStrong: "rgba(210, 206, 196, 0.052)",
467
+ vignette: "radial-gradient(ellipse at center, transparent 42%, rgba(2, 3, 5, 0.82) 100%)",
468
+ },
469
+ control: {
470
+ defaultBg: "rgba(255, 255, 255, 0.035)",
471
+ defaultBorder: "rgba(211, 205, 190, 0.11)",
472
+ defaultText: "#D7D1C4",
473
+ hoverBg: "rgba(255, 255, 255, 0.065)",
474
+ activeBg: "linear-gradient(180deg, rgba(74, 181, 166, 0.24), rgba(38, 118, 116, 0.18))",
475
+ activeBorder: "rgba(98, 226, 205, 0.42)",
476
+ activeText: "#E8FFFA",
477
+ primaryBg: "linear-gradient(180deg, rgba(55, 145, 132, 0.42), rgba(24, 86, 88, 0.28))",
478
+ primaryBorder: "rgba(99, 228, 206, 0.34)",
479
+ primaryText: "#F2FFFB",
480
+ disabledText: "rgba(154, 163, 174, 0.42)",
481
+ inputBg: "rgba(5, 7, 10, 0.52)",
482
+ inputBorder: "rgba(211, 205, 190, 0.13)",
483
+ focusRing: "rgba(98, 226, 205, 0.16)",
484
+ dangerText: "#FF9A8D",
485
+ },
486
+ timeline: {
487
+ background: "linear-gradient(180deg, rgba(14, 18, 24, 0.86), rgba(8, 11, 15, 0.92))",
488
+ border: "rgba(170, 184, 205, 0.12)",
489
+ gridMinor: "rgba(170, 184, 205, 0.04)",
490
+ gridMajor: "rgba(170, 184, 205, 0.09)",
491
+ text: "#7A92AE",
492
+ textStrong: "#A5B7CD",
493
+ playhead: "#8FE7FF",
494
+ playheadSoft: "rgba(143, 231, 255, 0.12)",
495
+ },
496
+ },
497
+ zoomTiers: {
498
+ overview: {
499
+ maxRatio: Number.POSITIVE_INFINITY,
500
+ nodeScale: 0.72,
501
+ labelThreshold: 0.998,
502
+ labelBudget: 2,
503
+ edgePriorityThreshold: 0.72,
504
+ arrowPriorityThreshold: Number.POSITIVE_INFINITY,
505
+ edgeSizeScale: 0.62,
506
+ showBadges: false,
507
+ showCurves: true,
508
+ showContextualArrows: false,
509
+ },
510
+ structure: {
511
+ maxRatio: 1.2,
512
+ nodeScale: 0.94,
513
+ labelThreshold: 0.95,
514
+ labelBudget: 12,
515
+ edgePriorityThreshold: 0.4,
516
+ arrowPriorityThreshold: 0.75,
517
+ edgeSizeScale: 0.92,
518
+ showBadges: false,
519
+ showCurves: true,
520
+ showContextualArrows: false,
521
+ },
522
+ inspection: {
523
+ maxRatio: 0.5,
524
+ nodeScale: 1,
525
+ labelThreshold: 0.8,
526
+ labelBudget: 40,
527
+ edgePriorityThreshold: 0,
528
+ arrowPriorityThreshold: 0.45,
529
+ edgeSizeScale: 1.18,
530
+ showBadges: true,
531
+ showCurves: true,
532
+ showContextualArrows: true,
533
+ },
534
+ },
535
+ labels: {
536
+ forceVisibleStates: ["hovered", "selected", "path"],
537
+ policies: {
538
+ none: { minZoomTier: "inspection" },
539
+ priority: { minZoomTier: "overview" },
540
+ local: { minZoomTier: "structure" },
541
+ always: { minZoomTier: "overview" },
542
+ },
543
+ chip: {
544
+ fontFamily: "\"IBM Plex Sans\", Inter, system-ui, sans-serif",
545
+ fontWeight: 500,
546
+ fontSize: 10,
547
+ maxFontSize: 11,
548
+ sizeScale: 0.25,
549
+ paddingX: 6,
550
+ paddingY: 3,
551
+ radius: 6,
552
+ offsetX: 12,
553
+ offsetY: 10,
554
+ background: "rgba(8, 14, 24, 0.9)",
555
+ borderColor: "rgba(154, 181, 212, 0.16)",
556
+ borderAlpha: 0.28,
557
+ textColor: "#EAF3FF",
558
+ shadowColor: "rgba(0, 0, 0, 0.6)",
559
+ shadowAlpha: 0.26,
560
+ shadowBlur: 12,
561
+ },
562
+ hoverCard: {
563
+ fontFamily: "\"IBM Plex Sans\", Inter, system-ui, sans-serif",
564
+ titleWeight: 700,
565
+ titleSize: 13,
566
+ metaWeight: 500,
567
+ metaSize: 10,
568
+ paddingX: 10,
569
+ paddingY: 7,
570
+ radius: 12,
571
+ offsetX: 16,
572
+ offsetY: 16,
573
+ metaGap: 5,
574
+ background: "rgba(8, 14, 24, 0.94)",
575
+ borderColor: "rgba(154, 181, 212, 0.18)",
576
+ borderAlpha: 0.32,
577
+ textColor: "#F6FBFF",
578
+ metaColor: "rgba(184, 214, 255, 0.58)",
579
+ shadowColor: "rgba(0, 0, 0, 0.62)",
580
+ shadowAlpha: 0.34,
581
+ shadowBlur: 15,
582
+ },
583
+ },
584
+ nodes: {
585
+ backgroundScale: 0.52,
586
+ mutedAlpha: 0.16,
587
+ strokeHierarchy: {
588
+ overview: { base: 0.05, emphasis: 0.34, muted: 0.02 },
589
+ structure: { base: 1.05, emphasis: 1.45, muted: 0.55 },
590
+ inspection: { base: 1.2, emphasis: 1.7, muted: 0.6 },
591
+ },
592
+ states: {
593
+ default: { color: "base", sizeMultiplier: 0.7, minSize: 0.64, forceLabel: false, zIndex: 0, borderBoost: -0.46 },
594
+ hovered: { color: "hovered", sizeMultiplier: 1.08, minSize: 10.4, forceLabel: true, zIndex: 4, borderBoost: 0.2 },
595
+ selected: { color: "selected", sizeMultiplier: 1.02, minSize: 9.2, forceLabel: true, zIndex: 3, borderBoost: 0.22 },
596
+ neighbor: { color: "base", sizeMultiplier: 0.76, minSize: 4, forceLabel: false, zIndex: 2, borderBoost: -0.08 },
597
+ path: { color: "path", sizeMultiplier: 0.96, minSize: 5.6, forceLabel: true, zIndex: 2, borderBoost: 0.08 },
598
+ inactive: { color: "muted", sizeMultiplier: 0.52, minSize: 0.58, forceLabel: false, zIndex: 0, borderBoost: -0.42 },
599
+ muted: { color: "muted", sizeMultiplier: 0.52, minSize: 0.58, forceLabel: false, zIndex: 0, borderBoost: -0.42 },
600
+ },
601
+ variants: {
602
+ default: { sizeMultiplier: 1, borderBoost: 0, haloBoost: 0, badgeVisibleFrom: "inspection" },
603
+ temporal: { sizeMultiplier: 1.02, borderBoost: 0.12, haloBoost: 0.1, badgeKind: "temporal", badgeVisibleFrom: "inspection" },
604
+ inferred: { sizeMultiplier: 1.05, borderBoost: 0.16, haloBoost: 0.14, badgeKind: "inferred", badgeVisibleFrom: "inspection" },
605
+ provenance: { sizeMultiplier: 1.03, borderBoost: 0.14, haloBoost: 0.12, badgeKind: "provenance", badgeVisibleFrom: "inspection" },
606
+ selected: { sizeMultiplier: 1.06, borderBoost: 0.22, haloBoost: 0.16, badgeVisibleFrom: "overview" },
607
+ },
608
+ entityShapes: {
609
+ entity: {
610
+ label: "Entity",
611
+ shapeKind: 0,
612
+ aspectRatio: 1,
613
+ fillAlpha: 0.9,
614
+ shellAlpha: 0.14,
615
+ coreScale: 0,
616
+ borderBoost: 0.08,
617
+ minSize: 0,
618
+ },
619
+ biomolecule: {
620
+ label: "Biomolecule",
621
+ shapeKind: 1,
622
+ aspectRatio: 1,
623
+ fillAlpha: 0.9,
624
+ shellAlpha: 0.16,
625
+ coreScale: 0.18,
626
+ borderBoost: 0.16,
627
+ minSize: 1.2,
628
+ },
629
+ condition: {
630
+ label: "Condition",
631
+ shapeKind: 2,
632
+ aspectRatio: 1.04,
633
+ fillAlpha: 0.88,
634
+ shellAlpha: 0.15,
635
+ coreScale: 0.16,
636
+ borderBoost: 0.18,
637
+ minSize: 1.6,
638
+ },
639
+ compound: {
640
+ label: "Compound",
641
+ shapeKind: 3,
642
+ aspectRatio: 1.48,
643
+ fillAlpha: 0.88,
644
+ shellAlpha: 0.15,
645
+ coreScale: 0.14,
646
+ borderBoost: 0.14,
647
+ minSize: 1.4,
648
+ },
649
+ process: {
650
+ label: "Process",
651
+ shapeKind: 4,
652
+ aspectRatio: 1.1,
653
+ fillAlpha: 0.87,
654
+ shellAlpha: 0.14,
655
+ coreScale: 0.14,
656
+ borderBoost: 0.16,
657
+ minSize: 1.4,
658
+ },
659
+ community: {
660
+ label: "Community",
661
+ shapeKind: 5,
662
+ aspectRatio: 1,
663
+ fillAlpha: 0.68,
664
+ shellAlpha: 0.28,
665
+ coreScale: 0.78,
666
+ borderBoost: 0.34,
667
+ minSize: 2,
668
+ },
669
+ },
670
+ selectedRing: {
671
+ color: "#E7C57C",
672
+ width: 1.9,
673
+ nativeSize: 2.2,
674
+ glowAlpha: 0.2,
675
+ visibleFrom: "overview",
676
+ },
677
+ badges: {
678
+ inferred: { color: "#C98658", label: "I" },
679
+ temporal: { color: "#52CDEF", label: "T" },
680
+ provenance: { color: "#A289D0", label: "P" },
681
+ },
682
+ badge: {
683
+ radius: 7,
684
+ offset: 3,
685
+ fontSize: 8,
686
+ textColor: "#08111d",
687
+ background: "rgba(10, 5, 8, 0.84)",
688
+ stroke: "rgba(255,255,255,0.14)",
689
+ glowAlpha: 0.24,
690
+ },
691
+ },
692
+ edges: {
693
+ states: {
694
+ default: { color: "structure", sizeMultiplier: 0.48, minSize: 0.2, zIndex: 0, forceArrow: false, hide: false },
695
+ backbone: { color: "backbone", sizeMultiplier: 0.62, minSize: 0.36, zIndex: 1, forceArrow: false, hide: false },
696
+ hovered: { color: "hover", sizeMultiplier: 1.42, minSize: 1.85, zIndex: 5, forceArrow: true, hide: false },
697
+ selected: { color: "hover", sizeMultiplier: 1.42, minSize: 1.85, zIndex: 5, forceArrow: true, hide: false },
698
+ neighbor: { color: "focus", sizeMultiplier: 0.96, minSize: 0.86, zIndex: 1, forceArrow: false, hide: false },
699
+ path: { color: "path", sizeMultiplier: 1.82, minSize: 2.55, zIndex: 6, forceArrow: true, hide: false },
700
+ inactive: { color: "muted", sizeMultiplier: 0.24, minSize: 0.18, zIndex: 0, forceArrow: false, hide: false },
701
+ muted: { color: "muted", sizeMultiplier: 0.24, minSize: 0.18, zIndex: 0, forceArrow: false, hide: false },
702
+ },
703
+ variants: {
704
+ line: { baseType: "line", arrowPolicy: "hidden", curveStrength: 0, sizeMultiplier: 1, glowAlpha: 0 },
705
+ directional: { baseType: "line", arrowPolicy: "contextual", curveStrength: 0, sizeMultiplier: 1.04, glowAlpha: 0.08 },
706
+ bidirectionalCurve: { baseType: "line", arrowPolicy: "contextual", curveStrength: 0.18, sizeMultiplier: 1.08, glowAlpha: 0.1 },
707
+ parallelCurve: { baseType: "line", arrowPolicy: "contextual", curveStrength: 0.24, sizeMultiplier: 1.1, glowAlpha: 0.12 },
708
+ pathSignal: { baseType: "arrow", arrowPolicy: "always", curveStrength: 0.16, sizeMultiplier: 1.18, glowAlpha: 0.2 },
709
+ },
710
+ visibility: {
711
+ full: {
712
+ overview: {
713
+ defaultPriorityThreshold: 0.96,
714
+ backgroundSampleRate: 0.035,
715
+ defaultAlpha: 0.026,
716
+ mutedAlpha: 0.012,
717
+ inactiveAlpha: 0.01,
718
+ neighborAlpha: 0.26,
719
+ sizeMultiplier: 0.5,
720
+ hideMuted: true,
721
+ },
722
+ structure: {
723
+ defaultPriorityThreshold: 0.82,
724
+ backgroundSampleRate: 0.16,
725
+ defaultAlpha: 0.04,
726
+ mutedAlpha: 0.014,
727
+ inactiveAlpha: 0.012,
728
+ neighborAlpha: 0.32,
729
+ sizeMultiplier: 0.62,
730
+ hideMuted: true,
731
+ },
732
+ inspection: {
733
+ defaultPriorityThreshold: 0.72,
734
+ backgroundSampleRate: 0.28,
735
+ defaultAlpha: 0.052,
736
+ mutedAlpha: 0.012,
737
+ inactiveAlpha: 0.01,
738
+ neighborAlpha: 0.38,
739
+ sizeMultiplier: 0.64,
740
+ hideMuted: true,
741
+ },
742
+ },
743
+ grouped: {
744
+ overview: {
745
+ defaultPriorityThreshold: 0.42,
746
+ backgroundSampleRate: 1,
747
+ defaultAlpha: 0.18,
748
+ mutedAlpha: 0.06,
749
+ inactiveAlpha: 0.04,
750
+ neighborAlpha: 0.36,
751
+ sizeMultiplier: 0.72,
752
+ hideMuted: false,
753
+ },
754
+ structure: {
755
+ defaultPriorityThreshold: 0.34,
756
+ backgroundSampleRate: 1,
757
+ defaultAlpha: 0.2,
758
+ mutedAlpha: 0.07,
759
+ inactiveAlpha: 0.05,
760
+ neighborAlpha: 0.42,
761
+ sizeMultiplier: 0.78,
762
+ hideMuted: false,
763
+ },
764
+ inspection: {
765
+ defaultPriorityThreshold: 0.28,
766
+ backgroundSampleRate: 1,
767
+ defaultAlpha: 0.22,
768
+ mutedAlpha: 0.08,
769
+ inactiveAlpha: 0.06,
770
+ neighborAlpha: 0.46,
771
+ sizeMultiplier: 0.82,
772
+ hideMuted: false,
773
+ },
774
+ },
775
+ focused: {
776
+ overview: {
777
+ defaultPriorityThreshold: 0.72,
778
+ backgroundSampleRate: 0.7,
779
+ defaultAlpha: 0.1,
780
+ mutedAlpha: 0.03,
781
+ inactiveAlpha: 0.02,
782
+ neighborAlpha: 0.06,
783
+ sizeMultiplier: 0.72,
784
+ hideMuted: true,
785
+ },
786
+ structure: {
787
+ defaultPriorityThreshold: 0.6,
788
+ backgroundSampleRate: 0.8,
789
+ defaultAlpha: 0.12,
790
+ mutedAlpha: 0.035,
791
+ inactiveAlpha: 0.025,
792
+ neighborAlpha: 0.08,
793
+ sizeMultiplier: 0.8,
794
+ hideMuted: true,
795
+ },
796
+ inspection: {
797
+ defaultPriorityThreshold: 0.52,
798
+ backgroundSampleRate: 0.9,
799
+ defaultAlpha: 0.14,
800
+ mutedAlpha: 0.04,
801
+ inactiveAlpha: 0.03,
802
+ neighborAlpha: 0.1,
803
+ sizeMultiplier: 0.88,
804
+ hideMuted: true,
805
+ },
806
+ },
807
+ },
808
+ contextCaps: {
809
+ full: {
810
+ overview: 0,
811
+ structure: 12,
812
+ inspection: 24,
813
+ },
814
+ grouped: {
815
+ overview: 6,
816
+ structure: 8,
817
+ inspection: 10,
818
+ },
819
+ focused: {
820
+ overview: 24,
821
+ structure: 36,
822
+ inspection: 48,
823
+ },
824
+ },
825
+ fullGraphStructure: {
826
+ ambientBackboneAlpha: 0.12,
827
+ backboneAlpha: 0.08,
828
+ bridgeAlpha: 0.14,
829
+ bridgeCurvePriorityThreshold: 0.78,
830
+ bridgeCurveStrength: 0.1,
831
+ backboneMaxSize: 0.5,
832
+ bridgeMaxSize: 0.7,
833
+ structureEdgeAlpha: 0.12,
834
+ inspectionEdgeAlpha: 0.1,
835
+ },
836
+ // Staged rollout — set mode to "auto" to enable cross-community curve rendering.
837
+ // Currently "off" so the canvas overlay layer is inactive in production.
838
+ fullGraphStructureLayer: {
839
+ mode: "off",
840
+ minimumLiteralEdges: 24,
841
+ minimumCurves: 8,
842
+ maxCurves: 64,
843
+ bridgeAlpha: 0.16,
844
+ backboneAlpha: 0.1,
845
+ bridgeLineWidth: 0.9,
846
+ backboneLineWidth: 0.62,
847
+ curveStrength: 0.12,
848
+ },
849
+ },
850
+ interaction: {
851
+ localContextAlpha: 0.32,
852
+ hoverContextAlpha: 0.32,
853
+ selectedEdgeAlpha: 0.6,
854
+ pathEdgeAlpha: 0.76,
855
+ localContextMaxSize: 0.6,
856
+ selectedEdgeMaxSize: 1.0,
857
+ pathEdgeMaxSize: 1.4,
858
+ pathOverlayAlpha: 0.16,
859
+ },
860
+ overlays: {
861
+ hoverGlowAlpha: 0.18,
862
+ pathGlowAlpha: 0.16,
863
+ glowRadiusMultiplier: 4.8,
864
+ minGlowRadius: 16,
865
+ pulseRadius: 11,
866
+ curveLineWidth: 1.7,
867
+ curveGlowWidth: 6,
868
+ badgeGlowRadius: 14,
869
+ },
870
+ focus: {
871
+ maxNeighbors: 16,
872
+ ringCapacity: 6,
873
+ ringGap: 250,
874
+ primaryLabels: 6,
875
+ },
876
+ motion: {
877
+ cameraMs: 380,
878
+ },
879
+ grouped: {
880
+ initialLayout: {
881
+ innerRadius: 92,
882
+ ringSpacing: 138,
883
+ minNodeSpacing: 112,
884
+ nodePadding: 28,
885
+ overlapIterations: 18,
886
+ primaryLabelCount: 6,
887
+ },
888
+ style: {
889
+ nodeSizeScale: 0.9,
890
+ nodeBorderBoost: 0.42,
891
+ fillAlpha: 0.68,
892
+ shellAlpha: 0.28,
893
+ edgeSizeScale: 0.62,
894
+ edgeAlpha: 0.32,
895
+ glowAlpha: 0.14,
896
+ edgeVisibilityRatio: 0.18,
897
+ topIncidentEdges: 2,
898
+ },
899
+ layout: {
900
+ iterations: 18,
901
+ gravity: 0.06,
902
+ scalingRatio: 18,
903
+ edgeWeightInfluence: 0.08,
904
+ slowDown: 34,
905
+ settleMs: 1500,
906
+ },
907
+ },
908
+ effects: {
909
+ pathPulse: {
910
+ minZoomTier: "structure",
911
+ maxSegments: 18,
912
+ speed: 0.22,
913
+ radius: 11,
914
+ glowAlpha: 0.92,
915
+ },
916
+ pathFlow: {
917
+ minZoomTier: "structure",
918
+ maxSegments: 14,
919
+ speed: 0.36,
920
+ spacing: 0.26,
921
+ opacity: 0.92,
922
+ radius: 3.8,
923
+ },
924
+ lens: {
925
+ minZoomTier: "structure",
926
+ radius: 136,
927
+ feather: 78,
928
+ glowAlpha: 0.18,
929
+ edgeAlpha: 0.42,
930
+ edgeLineWidth: 1.8,
931
+ },
932
+ temporalEmphasis: {
933
+ minZoomTier: "structure",
934
+ maxHighlights: 48,
935
+ radiusMultiplier: 4.2,
936
+ glowAlpha: 0.12,
937
+ },
938
+ semanticRegions: {
939
+ minZoomTier: "overview",
940
+ maxRegions: 3,
941
+ minVisibleSamples: 14,
942
+ fogResolutionScale: 0.22,
943
+ splatRadius: 13,
944
+ blurPasses: 2,
945
+ densityThreshold: 0.16,
946
+ contourThreshold: 0.28,
947
+ minMaskPixels: 170,
948
+ minOccupancyRatio: 0.0022,
949
+ dominantMassRatio: 0.62,
950
+ outerContourMinMaskPixels: 240,
951
+ fogAlpha: 0.11,
952
+ innerContourAlpha: 0.16,
953
+ outerContourAlpha: 0.045,
954
+ },
955
+ contours: {
956
+ minZoomTier: "overview",
957
+ maxContours: 3,
958
+ baseRadius: 88,
959
+ glowAlpha: 0.055,
960
+ },
961
+ legend: {
962
+ maxGroups: 8,
963
+ },
964
+ diagnostics: {
965
+ enabledInDev: IS_DEV,
966
+ },
967
+ },
968
+ };
969
+
970
+ const ZOOM_TIER_ORDER: GraphZoomTier[] = ["overview", "structure", "inspection"];
971
+
972
+ export function hashString(value: string): number {
973
+ let hash = 0;
974
+ for (let index = 0; index < value.length; index += 1) {
975
+ hash = (hash << 5) - hash + value.charCodeAt(index);
976
+ hash |= 0;
977
+ }
978
+ return Math.abs(hash);
979
+ }
980
+
981
+ export function clamp(min: number, value: number, max: number): number {
982
+ return Math.min(max, Math.max(min, value));
983
+ }
984
+
985
+ export function withAlpha(color: string | undefined, alpha: number): string {
986
+ if (!color) {
987
+ return `rgba(130, 145, 165, ${alpha})`;
988
+ }
989
+
990
+ if (color.startsWith("#")) {
991
+ const hex = color.slice(1);
992
+ const normalized = hex.length === 3
993
+ ? hex.split("").map((char) => `${char}${char}`).join("")
994
+ : hex;
995
+
996
+ if (normalized.length === 6) {
997
+ const red = Number.parseInt(normalized.slice(0, 2), 16);
998
+ const green = Number.parseInt(normalized.slice(2, 4), 16);
999
+ const blue = Number.parseInt(normalized.slice(4, 6), 16);
1000
+ return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
1001
+ }
1002
+ }
1003
+
1004
+ if (color.startsWith("rgba(")) {
1005
+ return color.replace(/rgba\((.*?),\s*[\d.]+\)/, `rgba($1, ${alpha})`);
1006
+ }
1007
+
1008
+ if (color.startsWith("rgb(")) {
1009
+ return color.replace("rgb(", "rgba(").replace(")", `, ${alpha})`);
1010
+ }
1011
+
1012
+ return `rgba(130, 145, 165, ${alpha})`;
1013
+ }
1014
+
1015
+ export function darkenHex(hexColor: string, amount: number): string {
1016
+ if (!hexColor.startsWith("#")) {
1017
+ return hexColor;
1018
+ }
1019
+
1020
+ const hex = hexColor.slice(1);
1021
+ const normalized = hex.length === 3
1022
+ ? hex.split("").map((char) => `${char}${char}`).join("")
1023
+ : hex;
1024
+
1025
+ if (normalized.length !== 6) {
1026
+ return hexColor;
1027
+ }
1028
+
1029
+ const clampChannel = (value: number) => clamp(0, value, 255);
1030
+ const red = clampChannel(Number.parseInt(normalized.slice(0, 2), 16) - amount);
1031
+ const green = clampChannel(Number.parseInt(normalized.slice(2, 4), 16) - amount);
1032
+ const blue = clampChannel(Number.parseInt(normalized.slice(4, 6), 16) - amount);
1033
+
1034
+ return `#${[red, green, blue].map((value) => value.toString(16).padStart(2, "0")).join("")}`;
1035
+ }
1036
+
1037
+ export function blendHex(baseColor: string, tintColor: string, amount: number): string {
1038
+ if (!baseColor.startsWith("#") || !tintColor.startsWith("#")) {
1039
+ return tintColor || baseColor;
1040
+ }
1041
+
1042
+ const normalize = (value: string) => {
1043
+ const hex = value.slice(1);
1044
+ return hex.length === 3
1045
+ ? hex.split("").map((char) => `${char}${char}`).join("")
1046
+ : hex;
1047
+ };
1048
+
1049
+ const base = normalize(baseColor);
1050
+ const tint = normalize(tintColor);
1051
+ if (base.length !== 6 || tint.length !== 6) {
1052
+ return tintColor || baseColor;
1053
+ }
1054
+
1055
+ const mix = clamp(0, amount, 1);
1056
+ const mixChannel = (left: number, right: number) => Math.round(left + (right - left) * mix);
1057
+ const channels = [0, 2, 4].map((offset) => {
1058
+ const left = Number.parseInt(base.slice(offset, offset + 2), 16);
1059
+ const right = Number.parseInt(tint.slice(offset, offset + 2), 16);
1060
+ return mixChannel(left, right).toString(16).padStart(2, "0");
1061
+ });
1062
+
1063
+ return `#${channels.join("")}`;
1064
+ }
1065
+
1066
+ export function getZoomTier(ratio: number): GraphZoomTier {
1067
+ if (ratio <= GRAPH_THEME.zoomTiers.inspection.maxRatio) {
1068
+ return "inspection";
1069
+ }
1070
+ if (ratio <= GRAPH_THEME.zoomTiers.structure.maxRatio) {
1071
+ return "structure";
1072
+ }
1073
+ return "overview";
1074
+ }
1075
+
1076
+ export function zoomTierAtLeast(current: GraphZoomTier, minimum: GraphZoomTier): boolean {
1077
+ return ZOOM_TIER_ORDER.indexOf(current) >= ZOOM_TIER_ORDER.indexOf(minimum);
1078
+ }