import dagre from 'dagre' interface NodeInfo { id: string label: string } interface EdgeInfo { source: string target: string } const NODE_W = 180 const NODE_H = 60 const POSITIONS_KEY = 'editor_positions' export function loadSavedPositions(): Record { try { return JSON.parse(localStorage.getItem(POSITIONS_KEY) || '{}') } catch { return {} } } export function savePosition(nodeId: string, x: number, y: number) { const saved = loadSavedPositions() saved[nodeId] = { x, y } localStorage.setItem(POSITIONS_KEY, JSON.stringify(saved)) } export function computePositions( nodes: NodeInfo[], edges: EdgeInfo[], _startScene: string, ): Map { const saved = loadSavedPositions() const result = new Map() const unsaved: NodeInfo[] = [] for (const n of nodes) { if (saved[n.id]) { result.set(n.id, saved[n.id]) } else { unsaved.push(n) } } if (unsaved.length === 0) return result const g = new dagre.graphlib.Graph() g.setGraph({ rankdir: 'LR', nodesep: 100, ranksep: 200, marginx: 60, marginy: 60, }) g.setDefaultEdgeLabel(() => ({})) for (const n of unsaved) { g.setNode(n.id, { width: NODE_W, height: NODE_H }) } const nodeIds = new Set(unsaved.map((n) => n.id)) for (const e of edges) { if (nodeIds.has(e.source) && nodeIds.has(e.target)) { g.setEdge(e.source, e.target) } } dagre.layout(g) for (const n of unsaved) { const node = g.node(n.id) if (node) { result.set(n.id, { x: node.x - NODE_W / 2, y: node.y - NODE_H / 2 }) } } return result }