"use client"; import "@xyflow/react/dist/style.css"; import { useCallback, useRef, useState } from "react"; import { Background, BackgroundVariant, type Edge, getNodesBounds, type Node, ReactFlow, ReactFlowProvider, useEdgesState, useNodesState, useReactFlow, } from "@xyflow/react"; import { toPng } from "html-to-image"; import { ingestionEdges, ingestionNodes, runtimeEdges, runtimeNodes, } from "./flows"; import { nodeTypes } from "./nodes"; const EXPORT_PADDING = 48; const EXPORT_PIXEL_RATIO = 2; function DiagramCanvasInner({ initialNodes, initialEdges, fileName, height, dark, }: { initialNodes: Node[]; initialEdges: Edge[]; fileName: string; height: number; dark: boolean; }) { const wrapperRef = useRef(null); const [nodes, , onNodesChange] = useNodesState(initialNodes); const [edges, , onEdgesChange] = useEdgesState(initialEdges); const { getNodes } = useReactFlow(); const [busy, setBusy] = useState(false); const download = useCallback(async () => { const viewport = wrapperRef.current?.querySelector( ".react-flow__viewport", ); if (!viewport) return; setBusy(true); try { await document.fonts.ready; const bounds = getNodesBounds(getNodes()); const outW = Math.ceil(bounds.width + EXPORT_PADDING * 2); const outH = Math.ceil(bounds.height + EXPORT_PADDING * 2); const tx = EXPORT_PADDING - bounds.x; const ty = EXPORT_PADDING - bounds.y; const dataUrl = await toPng(viewport, { width: outW, height: outH, pixelRatio: EXPORT_PIXEL_RATIO, // transparent background so one PNG works on light and dark GitHub style: { width: `${outW}px`, height: `${outH}px`, transform: `translate(${tx}px, ${ty}px) scale(1)`, }, }); const link = document.createElement("a"); link.download = fileName; link.href = dataUrl; link.click(); } finally { setBusy(false); } }, [fileName, getNodes]); return (
); } function btnStyle(disabled: boolean): React.CSSProperties { return { fontFamily: "var(--font-inter), system-ui, sans-serif", fontSize: 13, fontWeight: 600, padding: "7px 14px", borderRadius: 8, border: "1px solid #0e7490", background: disabled ? "#9bbdc6" : "#0e7490", color: "#ffffff", cursor: disabled ? "default" : "pointer", }; } function DiagramCanvas(props: { initialNodes: Node[]; initialEdges: Edge[]; fileName: string; height: number; dark: boolean; }) { return ( ); } export function DiagramStudio() { const [dark, setDark] = useState(false); return (

ktx diagram studio

Static diagrams. Export is a transparent 2× PNG framed to the node bounds — the dark-background toggle is only for previewing.

1 · Ingestion — building the context layer

2 · Serving — answering agents at runtime

); } const sectionTitle: React.CSSProperties = { fontFamily: "var(--font-display), system-ui, sans-serif", fontSize: 18, fontWeight: 600, color: "#1b1b18", marginBottom: 12, };