Politur: Gedaechnis-Graph-Visualisierung veredelt (Neon-Glow, radialer Hintergrundverlauf und reaktives Zoom-Scaling)

This commit is contained in:
Hitonabi
2026-07-09 12:14:32 +02:00
parent c20c070a6b
commit 3ea0e2d540
6 changed files with 42 additions and 27 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -7,8 +7,8 @@
<link rel="manifest" href="/manifest.webmanifest" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Mission Control 2.0</title>
<script type="module" crossorigin src="/assets/index-Cp5Tizb9.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DMTEFdKw.css">
<script type="module" crossorigin src="/assets/index-r382vnGM.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-B1ESaWd9.css">
</head>
<body>
<div id="root"></div>
+29 -14
View File
@@ -9,16 +9,16 @@ import { type MemoryGraph } from "@/lib/api"
// Fakten flüssig. Im App-Look gestylt; Hover hebt den Knoten + seine Nachbarn hervor, der Rest dimmt.
const CAT_COLOR: Record<string, string> = {
identity: "#22d3ee", knowledge: "#6366f1", rules: "#a78bfa", events: "#fbbf24",
identity: "#00f5ff", knowledge: "#3b82f6", rules: "#d946ef", events: "#fbbf24",
}
const CAT_LABEL: Record<string, string> = {
identity: "Identität", knowledge: "Wissen", rules: "Regeln", events: "Ereignisse",
}
const AUTO = new Set(["auto", "agent", "hermes"])
const DIM_NODE = "#1f2937"
const DIM_EDGE = "#0f172a"
const EDGE = "#243044"
const EDGE_HI = "#4b5563"
const DIM_NODE = "#1e293b"
const DIM_EDGE = "rgba(15, 23, 42, 0.05)"
const EDGE = "rgba(255, 255, 255, 0.07)"
const EDGE_HI = "rgba(99, 102, 241, 0.85)"
export function GraphView({ data, onDelete }: { data: MemoryGraph; onDelete: (id: string) => void }) {
const [selected, setSelected] = useState<string | null>(null)
@@ -43,39 +43,53 @@ export function GraphView({ data, onDelete }: { data: MemoryGraph; onDelete: (id
const a = (2 * Math.PI * i) / N
graph.addNode(n.id, {
x: Math.cos(a), y: Math.sin(a), // Startposition (Kreis) für ForceAtlas2
size: 4 + Math.min(degree[n.id] || 0, 12) * 1.4,
size: 5 + Math.min(degree[n.id] || 0, 12) * 1.5,
color: CAT_COLOR[n.category] || "#64748b",
label: n.content.length > 48 ? n.content.slice(0, 47) + "…" : n.content,
})
})
data.edges.forEach((e) => {
if (graph.hasNode(e.source) && graph.hasNode(e.target) && !graph.hasEdge(e.source, e.target))
graph.addEdge(e.source, e.target, { size: 0.6 + (e.weight || 0), color: EDGE })
graph.addEdge(e.source, e.target, { size: 0.8 + (e.weight || 0) * 0.5, color: EDGE })
})
forceAtlas2.assign(graph, { iterations: 220, settings: forceAtlas2.inferSettings(graph) })
graphRef.current = graph
const renderer = new Sigma(graph, containerRef.current, {
renderLabels: true,
labelColor: { color: "#cbd5e1" },
labelColor: { color: "#e2e8f0" },
labelSize: 11,
labelWeight: "500",
labelDensity: 0.6,
labelWeight: "600",
labelDensity: 0.5,
labelRenderedSizeThreshold: N > 120 ? 12 : 0, // bei vielen Knoten nur große labeln (entklumpen)
defaultEdgeColor: EDGE,
minCameraRatio: 0.1,
maxCameraRatio: 4,
nodeReducer: (id, attrs) => {
const a = active.current
if (!a) return attrs
if (id === a || graph.areNeighbors(a, id)) return attrs
const isSel = id === selectedRef.current
if (!a) {
if (isSel) return { ...attrs, size: attrs.size * 1.35, highlighted: true }
return attrs
}
if (id === a) {
return { ...attrs, size: attrs.size * 1.45, highlighted: true }
}
if (graph.areNeighbors(a, id)) {
if (isSel) return { ...attrs, size: attrs.size * 1.35, highlighted: true }
return attrs
}
return { ...attrs, color: DIM_NODE, label: "" }
},
edgeReducer: (edge, attrs) => {
const a = active.current
if (!a) return attrs
const ext = graph.extremities(edge)
if (ext[0] === a || ext[1] === a) return { ...attrs, color: EDGE_HI, size: (attrs.size || 1) * 1.6 }
if (ext[0] === a || ext[1] === a) return { ...attrs, color: EDGE_HI, size: (attrs.size || 1) * 2.2 }
return { ...attrs, color: DIM_EDGE }
},
})
@@ -147,7 +161,8 @@ export function GraphView({ data, onDelete }: { data: MemoryGraph; onDelete: (id
return (
<div className="grid grid-cols-1 lg:grid-cols-[1fr_300px] gap-3">
<div className="relative h-[calc(100vh-13rem)] min-h-[560px] rounded-2xl border border-border/60 bg-[#070a0f] overflow-hidden">
<div className="relative h-[calc(100vh-13rem)] min-h-[560px] rounded-2xl border border-border/60 overflow-hidden"
style={{ background: "radial-gradient(circle at center, rgba(59, 130, 246, 0.06) 0%, #030712 100%)" }}>
<div ref={containerRef} className="absolute inset-0" />
<button onClick={relayout} title="Knoten neu anordnen"
className="absolute right-3 top-3 z-10 flex items-center gap-1.5 rounded-lg border border-border/60 bg-background/50 px-2.5 py-1.5 text-[11px] text-muted-foreground hover:text-foreground backdrop-blur-sm transition-colors">