@luispm/zflow-graph 0.1.0 → 0.2.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.
- package/README.md +108 -7
- package/dist/adapters/yjs.esm.js +39 -16
- package/dist/adapters/yjs.esm.min.js +2 -2
- package/dist/adapters/yjs.umd.js +39 -16
- package/dist/webgl-renderer.esm.js +55 -31
- package/dist/webgl-renderer.esm.min.js +2 -2
- package/dist/webgl-renderer.umd.js +55 -31
- package/dist/zflow.esm.js +406 -53
- package/dist/zflow.esm.js.map +1 -1
- package/dist/zflow.esm.min.js +2 -2
- package/dist/zflow.umd.js +406 -53
- package/dist/zflow.umd.js.map +1 -1
- package/dist/zflow.umd.min.js +2 -2
- package/docs/01-getting-started.md +25 -0
- package/docs/07-recipes.md +102 -0
- package/docs/08-api.md +65 -0
- package/package.json +7 -5
package/dist/zflow.esm.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! @luispm/zflow-graph v0.
|
|
2
|
-
const t=[{name:"input",color:"#5b8def",badge:"I",w:140,h:60,nin:0,nout:1,shape:"rect"},{name:"process",color:"#e8b04b",badge:"P",w:160,h:80,nin:1,nout:1,shape:"rect"},{name:"filter",color:"#5be0d0",badge:"F",w:160,h:80,nin:1,nout:1,shape:"rect"},{name:"decision",color:"#c062e8",badge:"D",w:130,h:130,nin:1,nout:2,shape:"diamond"},{name:"output",color:"#5bd17a",badge:"O",w:140,h:60,nin:1,nout:0,shape:"rect"},{name:"aggregator",color:"#f0b93a",badge:"∑",w:160,h:120,nin:3,nout:1,shape:"hexagon"},{name:"branch",color:"#e8462b",badge:"B",w:130,h:130,nin:1,nout:3,shape:"ellipse"},{name:"if",color:"#c062e8",badge:"?",w:150,h:70,nin:1,nout:2,shape:"diamond",portIn:["value"],portOut:["true","false"],execute:(t,e)=>{const s=e.value??e[0],i=t.params?.condition;let o;if("function"==typeof i)o=i(s);else if("string"==typeof i)try{o=Function("value","v",`"use strict"; return (${i});`)(s,s)}catch{o=!1}else o=Boolean(s);return o?{true:s}:{false:s}}},{name:"forEach",color:"#5be0d0",badge:"↻",w:160,h:70,nin:1,nout:1,shape:"rect",portIn:["array"],portOut:["item"],execute:async(t,e)=>{const s=e.array??e[0]??[];if(!Array.isArray(s)||0===s.length)return null;for(let e=0;e<s.length;e++){if(t.signal.aborted)return;t.setProgress((e+1)/s.length),t.emit({item:s[e]}),await new Promise(t=>setTimeout(t,30))}return{item:s[s.length-1]}}},{name:"const",color:"#8b95a7",badge:"K",w:130,h:56,nin:0,nout:1,shape:"rect",portOut:["value"],execute:t=>({value:t.params?.value??0})},{name:"log",color:"#5b8def",badge:"◷",w:160,h:60,nin:1,nout:0,shape:"rect",portIn:["value"],execute:(t,e)=>(t.log(e.value??e[0]),{received:e.value??e[0]})}],e={bg:"#07090f",panel:"rgba(20,28,40,0.92)",border:"rgba(255,255,255,0.10)",fg:"#e6edf3",muted:"#8b95a7",accent:"#f0b93a",hi:"rgba(240,185,58,0.10)",grid:"rgba(255,255,255,0.04)",gridDot:"rgba(255,255,255,0.10)"},s={bg:"#f6f8fb",panel:"rgba(255,255,255,0.96)",border:"rgba(0,0,0,0.10)",fg:"#1d2330",muted:"#5a6577",accent:"#b8860b",hi:"rgba(184,134,11,0.12)",grid:"rgba(0,0,0,0.04)",gridDot:"rgba(0,0,0,0.16)"},i=["tl","t","tr","r","br","b","bl","l"],o=new Set(["l","tl","bl"]),n=new Set(["r","tr","br"]),r=new Set(["t","tl","tr"]),h=new Set(["b","bl","br"]),a={tl:"nwse-resize",br:"nwse-resize",tr:"nesw-resize",bl:"nesw-resize",t:"ns-resize",b:"ns-resize",l:"ew-resize",r:"ew-resize"};class l{static async create(t){const e=new l;return await e._init(t),e}async _init(i){if(!i||!i.container)throw new Error("zflow: container is required");let o;if(this.container=i.container,this.options=Object.assign({theme:"dark",background:"#07090f",edgeStyle:"bezier",snapToGrid:!1,gridSize:20,contextMenu:!0,keyboard:!0,minimap:!1,animateEdges:!1,edgeFlowSpeed:60,commandPalette:!0,search:!0,inlineMarkdown:!0},i),this._theme="light"===this.options.theme?s:e,"light"===this.options.theme&&(this.options.background=this._theme.bg),i.wasmBytes)o=i.wasmBytes instanceof Uint8Array?i.wasmBytes:new Uint8Array(i.wasmBytes);else{if(!i.wasmUrl)throw new Error("zflow: pass either { wasmUrl } or { wasmBytes }");o=new Uint8Array(await(await fetch(i.wasmUrl)).arrayBuffer())}const{instance:n}=await WebAssembly.instantiate(o,{});if(this.w=n.exports,0===this.w.init())throw new Error("zflow: WASM init OOM");const r=this.w.nodeCap(),h=this.w.edgeCap();this.V={posX:new Float32Array(this.w.memory.buffer,this.w.posXPtr(),r),posY:new Float32Array(this.w.memory.buffer,this.w.posYPtr(),r),sizeW:new Float32Array(this.w.memory.buffer,this.w.sizeWPtr(),r),sizeH:new Float32Array(this.w.memory.buffer,this.w.sizeHPtr(),r),kind:new Uint8Array(this.w.memory.buffer,this.w.kindPtr(),r),nIn:new Uint8Array(this.w.memory.buffer,this.w.nInPtr(),r),nOut:new Uint8Array(this.w.memory.buffer,this.w.nOutPtr(),r),selected:new Uint8Array(this.w.memory.buffer,this.w.selectedPtr(),r),edgeFromN:new Uint32Array(this.w.memory.buffer,this.w.edgeFromNodePtr(),h),edgeToN:new Uint32Array(this.w.memory.buffer,this.w.edgeToNodePtr(),h),edgeFromP:new Uint8Array(this.w.memory.buffer,this.w.edgeFromPortPtr(),h),edgeToP:new Uint8Array(this.w.memory.buffer,this.w.edgeToPortPtr(),h),edgeSel:new Uint8Array(this.w.memory.buffer,this.w.edgeSelectedPtr(),h),queryRes:new Uint32Array(this.w.memory.buffer,this.w.queryResultsPtr(),r)},this.kinds=t.map(t=>({...t})),this.kindByName=new Map,this.kinds.forEach((t,e)=>this.kindByName.set(t.name,e)),this.titles=new Map,this.colors=new Map,this.descriptions=new Map,this.tags=new Map,this.status=new Map,this.progress=new Map,this.image=new Map,this.checked=new Map,this.tasks=new Map,this.icon=new Map,this.links=new Map,this.portIn=new Map,this.portOut=new Map,this.zOrder=new Map,this.bookmarks=new Map,this.edgeLabels=new Map,this._imageCache=new Map,this._nodeAddedAt=new Map,this._dyingNodes=[],this._dyingEdges=[],this.notes=[],this._noteSeq=0,this.frames=[],this._frameSeq=0,this.canvas=document.createElement("canvas"),this.canvas.style.cssText=`display:block;width:100%;height:100%;background:${this.options.background};cursor:default;outline:none;touch-action:none;user-select:none;`,this.canvas.tabIndex=0,this.container.style.position=this.container.style.position||"relative",this.container.appendChild(this.canvas),this.ctx=this.canvas.getContext("2d",{alpha:!1}),this.cam={x:0,y:0,zoom:1},this._panVel={x:0,y:0,lastTs:0},this._clipboard=null,this._nudgeTimer=null,this.listeners=new Map,this._mode="idle",this._dragStart=null,this._dragLast=null,this._hoveredNode=-1,this._hoveredEdge=-1,this._hoveredNodeSince=0,this._previewedNode=-1,this._resizingHandle=null,this._marquee=null,this._lasso=null,this._alignGuides=null,this._edgeStart=null,this._edgeCursor=null,this._draggingNote=-1,this._noteDragLast=null,this._draggingFrame=-1,this._frameDragLast=null,this._resizingFrame=null,this._editingNote=-1,this._editingNoteEl=null,this._editingTitle=-1,this._editingTitleEl=null,this._focusFrame=-1,this._htmlOverlays=new Map,this._previewEl=null,this._pathHighlightEnabled=!1,this._focusedSet=null,this._lastFocusComputed=-2,this._menuEl=null,this.locked=new Set,this.readOnly=!1,this.snapToNodes=!0,this._reachableSet=null,this.remoteCursors=new Map,this._edgeWaypoints=new Map,this._draggingWaypoint=null,this.frameCollapsed=new Set,this._paletteGhost=null,this.metrics=new Map,this.metricMax=new Map,this._metricCap=32,this.animatedEdges=new Set,this._edgePhase=0,this._connValidator=null,this._templates=new Map,this._searchEl=null,this._searchQuery="",this._searchHits=[],this._cmdPaletteEl=null,this._minimapEl=null,this._minimapCtx=null,this._historyThumbs=[],this.options.minimap&&this._setupMinimap(),this._plugins=[],this._hooks={beforeRender:[],afterRender:[],onNodeAdd:[],onNodeDelete:[],onEdgeAdd:[],onBeforeExec:[],onAfterExec:[],onConnect:[],onSelectionChange:[],onChange:[]},this._values=new Map,this._running=!1,this._runAbort=null,this._runSeq=0,this._runOrder=null,this._execHooks=new Map,this._streamSrc=new Map,this._runStepDelay=250,this._valueBubbles=[],this._activeEdges=new Map,this._memoize=!1,this._memoKeys=new Map,this._retryStats=new Map,this.breakpoints=new Set,this._paused=!1,this._resumeNext=null,this._stepMode=!1,this._subflows=new Map,this._resize(),this._resizeObs=new ResizeObserver(()=>this._resize()),this._resizeObs.observe(this.container),this._attachEvents(),this.options.keyboard&&this._attachKeyboard(),this._loop()}dispose(){cancelAnimationFrame(this._raf),this._resizeObs?.disconnect(),this.canvas?.remove(),this._menuEl?.remove(),this._keyHandler&&window.removeEventListener("keydown",this._keyHandler),this.listeners.clear()}addNode(t={}){if(this.readOnly)return-1;this._runOrder=null;const e=this._resolveKind(t.kind??"process"),s=this.kinds[e],i=this.w.addNode(t.x??0,t.y??0,t.w??s.w,t.h??s.h,e,t.nin??s.nin,t.nout??s.nout);return i<0?-1:(t.title&&this.titles.set(i,t.title),t.color&&this.colors.set(i,t.color),t.description&&this.descriptions.set(i,t.description),t.tags&&this.tags.set(i,t.tags.slice()),t.status&&this.status.set(i,t.status),void 0!==t.progress&&this.progress.set(i,t.progress),t.image&&this.image.set(i,t.image),void 0!==t.checked&&this.checked.set(i,!!t.checked),t.tasks&&this.tasks.set(i,t.tasks.map(t=>({...t}))),t.icon&&this.icon.set(i,t.icon),t.links&&this.links.set(i,t.links.map(t=>({...t}))),t.portIn&&this.portIn.set(i,t.portIn.slice()),t.portOut&&this.portOut.set(i,t.portOut.slice()),!1!==t.animate&&this._nodeAddedAt.set(i,performance.now()),this._hooks&&this._runHook("onNodeAdd",i,t),this._emit("change"),i)}addNodesBulk(t){if(this.readOnly)return[];this._runOrder=null;const e=new Array(t.length),s=this._suspendEvents;this._suspendEvents=!0;for(let s=0;s<t.length;s++){const i=t[s],o=this._resolveKind(i.kind),n=this.w.addNode(o,i.x??0,i.y??0);n<0?e[s]=-1:(void 0!==i.w&&(this.V.sizeW[n]=i.w),void 0!==i.h&&(this.V.sizeH[n]=i.h),i.title&&this.titles.set(n,i.title),i.color&&this.colors.set(n,i.color),e[s]=n)}return this._suspendEvents=s,this._gl&&this._gl.markAllDirty(),this._emit("change"),e}addEdgesBulk(t){if(this.readOnly)return[];this._runOrder=null;const e=new Array(t.length),s=this._suspendEvents;this._suspendEvents=!0;for(let s=0;s<t.length;s++){const i=t[s];e[s]=this.w.addEdge(i.from,i.fp??0,i.to,i.tp??0),i.label&&e[s]>=0&&this.edgeLabels.set(e[s],i.label)}return this._suspendEvents=s,this._gl&&this._gl.markAllDirty(),this._adjDirty=!0,this._emit("change"),e}addEdge(t={}){if(this.readOnly)return-1;this._runOrder=null,this._adjDirty=!0;const e=this.w.addEdge(t.from,t.fp??0,t.to,t.tp??0);return e>=0&&(t.label&&this.edgeLabels.set(e,t.label),this._hooks&&this._runHook("onEdgeAdd",e,t),this._emit("change")),e}moveNode(t,e,s){this.w.moveNode(t,e,s),this._emit("change")}_guardWrite(){return!this.readOnly}deleteSelection(){if(this.readOnly)return;this._runOrder=null,this._captureDying();const t=this.w.deleteSelected();return t>0&&(this.w.snapshot(),this._emit("change")),t}_captureDying(){const t=performance.now(),e=new Uint8Array(this.w.nodeCount_());for(let t=0;t<this.w.nodeCount_();t++)this.V.selected[t]&&(e[t]=1);for(let s=0;s<this.w.nodeCount_();s++){if(!e[s])continue;const i=this.kinds[this.V.kind[s]];this._dyingNodes.push({x:this.V.posX[s],y:this.V.posY[s],w:this.V.sizeW[s],h:this.V.sizeH[s],shape:i.shape,color:this.colors.get(s)||i.color,t0:t})}for(let s=0;s<this.w.edgeCount_();s++){const i=this.V.edgeFromN[s],o=this.V.edgeToN[s];if(!this.V.edgeSel[s]&&!e[i]&&!e[o])continue;const n=this._portWorld(i,1,this.V.edgeFromP[s]),r=this._portWorld(o,0,this.V.edgeToP[s]);this._dyingEdges.push({ap:n,bp:r,colA:this.colors.get(i)||this.kinds[this.V.kind[i]].color,colB:this.colors.get(o)||this.kinds[this.V.kind[o]].color,t0:t})}}duplicateSelection(t=40,e=40){const s=this.w.duplicateSelected(t,e);return s>0&&(this.w.snapshot(),this._emit("change")),s}setSelected(t,e){this.w.setSelected(t,e?1:0),this._emit("select",this.getSelection())}toggleSelected(t){this.w.toggleSelected(t),this._emit("select",this.getSelection())}clearSelection(){this.w.clearSelection(),this._emit("select",[])}selectAll(){this.w.selectAll(),this._emit("select",this.getSelection())}getSelection(){const t=[],e=this.w.nodeCount_();for(let s=0;s<e;s++)this.V.selected[s]&&t.push(s);return t}nodeCount(){return this.w.nodeCount_()}edgeCount(){return this.w.edgeCount_()}setNodeTitle(t,e){e?this.titles.set(t,e):this.titles.delete(t),this._emit("change")}setNodeColor(t,e){e?this.colors.set(t,e):this.colors.delete(t),this._emit("change")}setNodeDescription(t,e){e?this.descriptions.set(t,e):this.descriptions.delete(t),this._emit("change")}setNodeTags(t,e){e&&e.length?this.tags.set(t,e.slice()):this.tags.delete(t),this._emit("change")}setNodeStatus(t,e){e?this.status.set(t,e):this.status.delete(t),this._emit("change")}setNodeProgress(t,e){null!=e?this.progress.set(t,e):this.progress.delete(t),this._emit("change")}setEdgeLabel(t,e){e?this.edgeLabels.set(t,e):this.edgeLabels.delete(t),this._emit("change")}setEdgeStyle(t){this.options.edgeStyle="orthogonal"===t?"orthogonal":"bezier"}setSnapToGrid(t){this.options.snapToGrid=!!t}setNodeImage(t,e){e?this.image.set(t,e):this.image.delete(t),this._emit("change")}setNodeChecked(t,e){null==e?this.checked.delete(t):this.checked.set(t,!!e),this._emit("change")}setNodeTasks(t,e){e&&e.length?this.tasks.set(t,e.map(t=>({...t}))):this.tasks.delete(t),this._emit("change")}setNodeIcon(t,e){e?this.icon.set(t,e):this.icon.delete(t),this._emit("change")}setNodeLinks(t,e){e&&e.length?this.links.set(t,e.map(t=>({...t}))):this.links.delete(t),this._emit("change")}setPortInLabels(t,e){e&&e.some(Boolean)?this.portIn.set(t,e.slice()):this.portIn.delete(t),this._emit("change")}setPortOutLabels(t,e){e&&e.some(Boolean)?this.portOut.set(t,e.slice()):this.portOut.delete(t),this._emit("change")}_nextZ=0;bringToFront(t){const e=t||this.getSelection();for(const t of e)this.zOrder.set(t,++this._nextZ)}sendToBack(t){const e=t||this.getSelection();for(const t of e)this.zOrder.set(t,--this._nextZ)}setBookmark(t,e){this.bookmarks.set(t,e??this.getSelection()[0])}jumpBookmark(t){const e=this.bookmarks.get(t);void 0===e||e>=this.w.nodeCount_()||(this.clearSelection(),this.w.setSelected(e,1),this.panTo(this.V.posX[e],this.V.posY[e]),this._emit("select",this.getSelection()))}setHoverPreview(t){this.options.hoverPreview=!!t,t||this._hidePreview()}use(t){if(!t)throw new Error("use(plugin): plugin required");"function"==typeof t&&(t=t(this)||{}),this._plugins.push(t);for(const e of Object.keys(this._hooks))"function"==typeof t[e]&&this._hooks[e].push(t[e]);if("function"==typeof t.extendAPI&&t.extendAPI(this),"function"==typeof t.init&&t.init(this),Array.isArray(t.kinds))for(const e of t.kinds)this.registerKind(e);return Array.isArray(t.commands)&&(this._extraCommands=(this._extraCommands||[]).concat(t.commands)),this._emit("plugin:installed",t.name||t),()=>this._removePlugin(t)}_removePlugin(t){const e=this._plugins.indexOf(t);if(-1!==e){this._plugins.splice(e,1);for(const e of Object.keys(this._hooks))if("function"==typeof t[e]){const s=this._hooks[e],i=s.indexOf(t[e]);-1!==i&&s.splice(i,1)}"function"==typeof t.dispose&&t.dispose(this)}}_runHook(t,...e){const s=this._hooks[t];if(!s||!s.length)return null;let i;for(const o of s)try{const t=o(this,...e);if(!1===t)return!1;void 0!==t&&(i=t)}catch(e){console.error(`plugin ${t} hook error`,e)}return i}async enableWebGL(t=!1){if(this._gl)return!0;if(!t&&this.w.nodeCount_()<(this.options.webglThreshold||2e3))return!1;try{const t=await Promise.resolve().then(function(){return N});return this._gl=new t.WebGLRenderer(this),this._gl.disabled?(this._gl=null,!1):(this.options.renderer="webgl",this._emit("renderer","webgl"),!0)}catch(t){return console.warn("zflow: WebGL renderer failed",t),!1}}disableWebGL(){this._gl&&(this._gl.dispose(),this._gl=null,this.canvas.style.background=this.options.background,this.canvas.style.zIndex="",this.canvas.style.position="",this.options.renderer="canvas2d",this._emit("renderer","canvas2d"))}setRunStepDelay(t){this._runStepDelay=Math.max(0,0|t)}setMemoization(t){this._memoize=!!t,t||this._memoKeys?.clear()}validateConnection(t,e,s,i){if(t===s)return"self-loop";const o=this.kinds[this.V.kind[t]],n=this.kinds[this.V.kind[s]],r=o.outputs?.[e],h=n.inputs?.[i];if(r&&h&&!function(t,e){if(!t||!e)return!0;if(t===e)return!0;if("any"===t||"any"===e)return!0;if("string"===e)return!0;const s=new Set(["number","int","float","integer"]);return!(!s.has(t)||!s.has(e))}(r.type,h.type))return`type mismatch: ${r.type} → ${h.type}`;if(this._connValidator){if(!1===this._connValidator(t,e,s,i))return"rejected by validator"}return null}editNodeExpression(t,e="title"){this._exprEditorEl&&this._closeExprEditor();const s="title"===e?this.titles.get(t)||"":"desc"===e&&this.descriptions.get(t)||"",i=document.createElement("div");i.style.cssText="position:absolute;z-index:600;background:#161b27;border:1px solid #f0b93a;border-radius:6px;box-shadow:0 8px 24px rgba(0,0,0,0.5);font-family:Inter, ui-sans-serif;font-size:12px;color:#e6edf3;width:280px;",i.innerHTML='\n <input id="zf-expr" type="text" style="width:260px;padding:8px 10px;background:transparent;border:0;color:#e6edf3;outline:none;font-family:ui-monospace,Consolas,monospace;font-size:12px;">\n <div id="zf-expr-preview" style="padding:4px 10px;border-top:1px solid rgba(255,255,255,0.08);color:#5be0d0;font-family:ui-monospace,Consolas,monospace;font-size:11px;min-height:14px;"></div>\n <div id="zf-expr-list" style="max-height:160px;overflow:auto;border-top:1px solid rgba(255,255,255,0.08);display:none;"></div>',this.container.appendChild(i),this._exprEditorEl=i;const o=this.V.posX[t],n=this.V.posY[t],r=.5*this.V.sizeH[t],h=this._w2s(o-.5*this.V.sizeW[t],n-r),a=window.devicePixelRatio||1;i.style.left=h.x/a+"px",i.style.top=Math.max(8,h.y/a-110)+"px";const l=i.querySelector("#zf-expr"),d=i.querySelector("#zf-expr-list"),c=i.querySelector("#zf-expr-preview");l.value=s;const u=()=>{try{const t=this.evalExpression(l.value);c.style.color="#5be0d0",c.textContent="= "+_(t)}catch(t){c.style.color="#e8462b",c.textContent=String(t.message||t)}},m=()=>{const e=l.selectionStart,s=l.value.slice(0,e).match(/\{\{\s*([\w_.]*)$/);if(!s)return void(d.style.display="none");const i=s[1].toLowerCase(),o=[];for(let e=0;e<this.w.nodeCount_();e++){if(e===t)continue;const s=this.titles.get(e)||this.kinds[this.V.kind[e]].name,n=this._values.get(e),r=n&&"object"==typeof n?Object.keys(n).map(t=>`node_${e}.${t}`):[`node_${e}`];for(const t of r)t.toLowerCase().startsWith(i)&&o.push({text:t,label:`${t} · ${s}`})}o.length?(d.style.display="block",d._items=o.slice(0,8),d._cursor=0,d.innerHTML=d._items.map((t,e)=>`<div data-i="${e}" data-text="${b(t.text)}" style="padding:6px 10px;cursor:pointer;${0===e?"background:rgba(240,185,58,0.18);":""}">${b(t.label)}</div>`).join("")):d.style.display="none"},p=t=>{const e=l.selectionStart,s=l.value.slice(0,e).replace(/\{\{\s*[\w_.]*$/,"{{")+t+"}}";l.value=s+l.value.slice(e),l.selectionStart=l.selectionEnd=s.length,u(),d.style.display="none"},g=()=>d.querySelectorAll("[data-i]").forEach((t,e)=>t.style.background=e===d._cursor?"rgba(240,185,58,0.18)":"transparent");l.addEventListener("input",()=>{u(),m()}),l.addEventListener("keydown",s=>{const i="none"!==d.style.display&&d._items;return i&&"ArrowDown"===s.code?(d._cursor=(d._cursor+1)%d._items.length,g(),void s.preventDefault()):i&&"ArrowUp"===s.code?(d._cursor=(d._cursor-1+d._items.length)%d._items.length,g(),void s.preventDefault()):!i||"Tab"!==s.code&&"Enter"!==s.code?("Enter"===s.code&&("title"===e?this.setNodeTitle(t,l.value):"desc"===e&&this.setNodeDescription(t,l.value),this._closeExprEditor()),void("Escape"===s.code&&this._closeExprEditor())):(p(d._items[d._cursor].text),void s.preventDefault())}),d.addEventListener("mousedown",t=>{const e=t.target.closest("[data-i]");e&&(p(e.dataset.text),l.focus(),t.preventDefault())}),setTimeout(()=>{l.focus(),l.select(),u()},10);const f=t=>{this._exprEditorEl&&!this._exprEditorEl.contains(t.target)&&this._closeExprEditor()};setTimeout(()=>document.addEventListener("mousedown",f,{once:!1}),60),this._exprEditorEl._cleanup=()=>document.removeEventListener("mousedown",f)}_closeExprEditor(){this._exprEditorEl&&(this._exprEditorEl._cleanup?.(),this._exprEditorEl.remove(),this._exprEditorEl=null)}evalExpression(t,e={}){if("string"!=typeof t)return t;const s=t.replace(/\{\{\s*([^}]+?)\s*\}\}/g,(t,s)=>{const[i,...o]=s.split(".");let n;if(/^node_(\d+)$/.test(i))n=this._values.get(parseInt(i.slice(5),10));else{if(!(i in e))return"null";n=e[i]}for(const t of o)n=null==n?void 0:n[t];return JSON.stringify(n??null)});if(s===t)return t;try{return Function(`"use strict"; return (${s})`)()}catch{return s}}setKindExecutor(t,e){const s=this.kindByName.get(t);if(void 0===s)throw new Error(`unknown kind: ${t}`);const i=this.kinds[s].execute;return this.kinds[s].execute=e,this._runOrder=null,i}setNodeInput(t,e){this._values.set(t,e),this.setNodeStatus(t,"ok")}getNodeValue(t){return this._values.get(t)}clearRuntimeState(){this._values.clear();for(const t of this._streamSrc.values())try{t()}catch{}this._streamSrc.clear();const t=this.w.nodeCount_();for(let e=0;e<t;e++)this.status.delete(e),this.progress.delete(e);this._emit("change")}_topoOrder(){if(this._runOrder)return this._runOrder;const t=this.w.nodeCount_(),e=this.w.edgeCount_(),s=new Int32Array(t),i=Array.from({length:t},()=>[]);for(let t=0;t<e;t++){const e=this.V.edgeFromN[t],o=this.V.edgeToN[t];e!==o&&(s[o]++,i[e].push({to:o,fp:this.V.edgeFromP[t],tp:this.V.edgeToP[t],idx:t}))}const o=[];for(let e=0;e<t;e++)0===s[e]&&o.push(e);const n=[];for(;o.length;){const t=o.shift();n.push(t);for(const e of i[t])0===--s[e.to]&&o.push(e.to)}if(n.length<t){const e=new Set(n);for(let s=0;s<t;s++)e.has(s)||n.push(s)}return this._runOrder=n,this._runOut=i,n}_gatherInputs(t){const e={},s=this.kinds[this.V.kind[t]],i=this.portIn.get(t)||s.portIn||[],o=this.w.edgeCount_();for(let s=0;s<o;s++){if(this.V.edgeToN[s]!==t)continue;const o=this.V.edgeToP[s],n=this.V.edgeFromN[s],r=this.V.edgeFromP[s],h=this._values.get(n);if(void 0===h)continue;let a;if(h&&"object"==typeof h&&!Array.isArray(h)){const t=this.kinds[this.V.kind[n]],e=(this.portOut.get(n)||t.portOut||[])[r];if(e){if(!(e in h))continue;a=h[e]}else a=r in h?h[r]:"value"in h?h.value:"out"in h?h.out:h;if(void 0===a)continue}else a=h;e[i[o]||`in${o}`]=a,e[o]=a}return e}_collectDownstream(t){const e=this.w.edgeCount_(),s=[],i=new Set,o=this._topoOrder(),n=new Map(o.map((t,e)=>[t,e])),r=[t];for(;r.length;){const t=r.pop();for(let o=0;o<e;o++)this.V.edgeFromN[o]!==t||i.has(this.V.edgeToN[o])||(i.add(this.V.edgeToN[o]),s.push(this.V.edgeToN[o]),r.push(this.V.edgeToN[o]))}return s.sort((t,e)=>n.get(t)-n.get(e)),s}async run({from:t=null,signal:e=null,filter:s=null}={}){if(this._running)return;this._running=!0;const i=++this._runSeq,o=new AbortController;this._runAbort=o,e&&e.addEventListener("abort",()=>o.abort()),this._topoOrder();let n=this._runOrder;if(null!==t){const e=new Set([t]),s=[t];for(;s.length;){const t=s.shift();for(const i of this._runOut[t])e.has(i.to)||(e.add(i.to),s.push(i.to))}n=n.filter(t=>e.has(t))}"function"==typeof s&&(n=n.filter(s));const r={executed:0,errors:[],values:new Map};this._emit("run:start",{order:n});for(const t of n){if(o.signal.aborted||i!==this._runSeq)break;const e=this.kinds[this.V.kind[t]],s=e.execute;if("function"!=typeof s){if(!this._values.has(t))continue;r.values.set(t,this._values.get(t));continue}const n=this._gatherInputs(t);if(e.nin>0&&0===Object.keys(n).length){let e=!1;const s=this.w.edgeCount_();for(let i=0;i<s;i++)if(this.V.edgeToN[i]===t){e=!0;break}if(e)continue}if(this._memoize){const e=g(n);if(this._memoKeys.get(t)===e&&this._values.has(t)){r.executed++,this._emit("node:cached",{id:t});continue}this._memoKeys.set(t,e)}const h=this.w.edgeCount_();for(let e=0;e<h;e++)this.V.edgeToN[e]===t&&this._values.has(this.V.edgeFromN[e])&&this._activeEdges.set(e,performance.now()+800);if(this.setNodeStatus(t,"running"),this.setNodeProgress(t,0),this._emit("node:exec",{id:t,inputs:n}),this._hooks){if(!1===this._runHook("onBeforeExec",t,n)){this.setNodeStatus(t,"idle");continue}}if((this.breakpoints.has(t)||this._stepMode)&&(await this._awaitContinue(t),o.signal.aborted||i!==this._runSeq))break;if(this._runStepDelay>0&&(await new Promise(t=>setTimeout(t,this._runStepDelay)),o.signal.aborted||i!==this._runSeq))break;const a={nodeId:t,signal:o.signal,params:this._nodeParams?.get(t)||{},emit:e=>{this._values.set(t,e),this._emit("node:emit",{id:t,outputs:e}),"number"==typeof e&&this.pushNodeMetric(t,e)},log:(...e)=>this._emit("node:log",{id:t,args:e}),setProgress:e=>this.setNodeProgress(t,e),metric:e=>this.pushNodeMetric(t,e),get:t=>this._values.get(t)},l=e.retry||null,d=l?l.n??3:1,c=l?l.delay??100:0;let u,m=0,p=null,y=!1;for(;m<d;){m++,this._retryStats.set(t,m);try{const e=s(a,n);if(e&&"function"==typeof e[Symbol.asyncIterator]){let s;const i=this._collectDownstream(t);for await(const n of e){if(o.signal.aborted)break;s=n,this._values.set(t,n),this._emit("node:emit",{id:t,outputs:n}),"number"==typeof n&&this.pushNodeMetric(t,n),this._valueBubbles.push({nodeId:t,text:f(n),t0:performance.now(),dur:700});for(const e of i){if(o.signal.aborted)break;const s=this.kinds[this.V.kind[e]];if("function"!=typeof s.execute)continue;if("AsyncGeneratorFunction"===s.execute.constructor.name)continue;const i=this._gatherInputs(e),n=this.w.edgeCount_();for(let s=0;s<n;s++)this.V.edgeToN[s]===e&&this.V.edgeFromN[s]===t&&this._activeEdges.set(s,performance.now()+500);this.setNodeStatus(e,"running");try{const t=s.execute({...a,nodeId:e,params:this._nodeParams?.get(e)||{}},i),o=t&&"function"==typeof t.then?await t:t;null!=o&&(this._values.set(e,o),this._emit("node:emit",{id:e,outputs:o}),this._valueBubbles.push({nodeId:e,text:f(o),t0:performance.now(),dur:700}),"number"==typeof o&&this.pushNodeMetric(e,o)),this.setNodeStatus(e,"ok")}catch(t){this.setNodeStatus(e,"error")}}await new Promise(t=>setTimeout(t,60))}u=s}else u=e&&"function"==typeof e.then?await e:e;if(o.signal.aborted||i!==this._runSeq)break;y=!0,p=null;break}catch(e){p=e,this._emit("node:retry",{id:t,attempt:m,error:e}),m<d&&await new Promise(t=>setTimeout(t,c))}}try{if(!y)throw p;if(o.signal.aborted||i!==this._runSeq)break;if(null!=u){let e;if(this._values.set(t,u),r.values.set(t,u),"number"==typeof u)e=_(u);else if(u&&"object"==typeof u){e=Object.entries(u).filter(([,t])=>null!=t).map(([t,e])=>`${t}: ${_(e)}`).join(" ")}else e=_(u);if(this._valueBubbles.push({nodeId:t,text:e,t0:performance.now(),dur:1400}),"number"==typeof u)this.pushNodeMetric(t,u);else if(u&&"object"==typeof u)for(const e of Object.values(u))if("number"==typeof e){this.pushNodeMetric(t,e);break}}this.setNodeStatus(t,"ok"),this.setNodeProgress(t,1),r.executed++,this._hooks&&this._runHook("onAfterExec",t,u),this._emit("node:done",{id:t,outputs:u})}catch(e){if(this.setNodeStatus(t,"error"),r.errors.push({id:t,error:e}),this._emit("node:error",{id:t,error:e}),this.options.stopOnError)break}}return this._running=!1,this._runAbort=null,this._emit("run:done",r),r}runFrom(t){return this.run({from:t})}setBreakpoint(t,e=!0){e?this.breakpoints.add(t):this.breakpoints.delete(t)}toggleBreakpoint(t){this.breakpoints.has(t)?this.breakpoints.delete(t):this.breakpoints.add(t)}clearBreakpoints(){this.breakpoints.clear()}setStepMode(t){this._stepMode=!!t}stepOver(){if(this._resumeNext){const t=this._resumeNext;this._resumeNext=null,t()}}resume(){if(this._paused=!1,this._stepMode=!1,this._resumeNext){const t=this._resumeNext;this._resumeNext=null,t()}}isPaused(){return this._paused}_awaitContinue(t){return new Promise(e=>{this._paused=!0,this._emit("run:paused",{nodeId:t}),this._resumeNext=e})}registerSubflowFromFrame(t,e={}){const s=this.frames.find(e=>e.id===t);if(!s)throw new Error("frame not found");const i=[],o=this.w.nodeCount_();for(let t=0;t<o;t++)this.V.posX[t]>=s.x&&this.V.posX[t]<=s.x+s.w&&this.V.posY[t]>=s.y&&this.V.posY[t]<=s.y+s.h&&i.push(t);if(!i.length)throw new Error("frame is empty");const n=new Set(i),r=new Map,h=i.map((t,e)=>(r.set(t,e),{kind:this.kinds[this.V.kind[t]].name,x:this.V.posX[t]-s.x,y:this.V.posY[t]-s.y,w:this.V.sizeW[t],h:this.V.sizeH[t],title:this.titles.get(t),color:this.colors.get(t),params:this._nodeParams?.get(t)})),a=[],l=this.w.edgeCount_();for(let t=0;t<l;t++)n.has(this.V.edgeFromN[t])&&n.has(this.V.edgeToN[t])&&a.push({from:r.get(this.V.edgeFromN[t]),to:r.get(this.V.edgeToN[t]),fp:this.V.edgeFromP[t],tp:this.V.edgeToP[t]});const d=new Set,c=new Set;for(const t of a)d.add(t.to),c.add(t.from);const u=i.map((t,e)=>e).filter(t=>!d.has(t)),m=i.map((t,e)=>e).filter(t=>!c.has(t)),p=e.name||`subflow_${s.label||t}`.replace(/\s+/g,"_"),g=u.map(t=>{const e=i[t];return this.titles.get(e)||this.kinds[this.V.kind[e]].name}),f=m.map(t=>{const e=i[t];return this.titles.get(e)||this.kinds[this.V.kind[e]].name});this._subflows.set(p,{nodes:h,edges:a,inputs:u,outputs:m,inputLabels:g,outputLabels:f});const _=this;return this.registerKind({name:p,color:e.color||"#5be0d0",badge:e.badge||"Σ",w:180,h:90,nin:Math.max(1,u.length),nout:Math.max(1,m.length),shape:"rect",portIn:g,portOut:f,inputs:g.map(t=>({name:t,type:"any"})),outputs:f.map(t=>({name:t,type:"any"})),execute:async(t,e)=>{const s=_._subflows.get(p),i=new Map;for(let t=0;t<s.inputs.length;t++){const o=e[t]??e[`in${t}`]??e[s.inputLabels[t]];i.set(s.inputs[t],o)}const o=s.nodes.map(()=>0),n=s.nodes.map(()=>[]);for(const t of s.edges)o[t.to]++,n[t.from].push(t);const r=[];for(let t=0;t<s.nodes.length;t++)0===o[t]&&r.push(t);for(;r.length;){const e=r.shift(),h=s.nodes[e],a=_.kinds[_.kindByName.get(h.kind)];let l;if(i.has(e)||"function"!=typeof a?.execute)l=i.get(e);else{const o={};for(const t of s.edges)if(t.to===e&&i.has(t.from)){const e=i.get(t.from),s=e&&"object"==typeof e?e.value??e[t.fp]??e:e;o[`in${t.tp}`]=s,o[t.tp]=s}l=await a.execute({...t,params:h.params||{}},o),i.set(e,l)}for(const t of n[e])0===--o[t.to]&&r.push(t.to)}const h={};for(let t=0;t<s.outputs.length;t++){const e=i.get(s.outputs[t]),o=e&&"object"==typeof e&&"value"in e?e.value:e;h[t]=o,h[s.outputLabels[t]]=o}return h}}),p}runFrame(t){const e=this.frames.find(e=>e.id===t);if(!e)return Promise.resolve({executed:0,errors:[]});const s=new Set,i=this.w.nodeCount_();for(let t=0;t<i;t++)this.V.posX[t]>=e.x&&this.V.posX[t]<=e.x+e.w&&this.V.posY[t]>=e.y&&this.V.posY[t]<=e.y+e.h&&s.add(t);return this.run({filter:t=>s.has(t)})}stop(){this._runAbort&&this._runAbort.abort(),this._running=!1}isRunning(){return this._running}setNodeParams(t,e){this._nodeParams||(this._nodeParams=new Map),this._nodeParams.set(t,e)}getNodeParams(t){return this._nodeParams?.get(t)}startLoop(t=500){this._loopStop=!1;const e=async()=>{this._loopStop||(await this.run(),this._loopStop||setTimeout(e,t))};e()}stopLoop(){this._loopStop=!0,this.stop()}lockNode(t,e=!0){e?this.locked.add(t):this.locked.delete(t)}isLocked(t){return this.locked.has(t)}setReadOnly(t){this.readOnly=!!t}setReachableFrom(t){if(null==t||t<0)return void(this._reachableSet=null);const e=new Set([t]),s=[t],i=this.w.edgeCount_();for(;s.length;){const t=s.shift();for(let o=0;o<i;o++)this.V.edgeFromN[o]!==t||e.has(this.V.edgeToN[o])||(e.add(this.V.edgeToN[o]),s.push(this.V.edgeToN[o]))}this._reachableSet=e}clearReachable(){this._reachableSet=null}setRemoteCursor(t,e,s,i=t,o="#5be0d0"){null!==e?this.remoteCursors.set(t,{x:e,y:s,name:i,color:o,t:performance.now()}):this.remoteCursors.delete(t)}clearRemoteCursors(){this.remoteCursors.clear()}setEdgeWaypoints(t,e){e&&e.length?this._edgeWaypoints.set(t,e.map(t=>({x:t.x,y:t.y}))):this._edgeWaypoints.delete(t)}clearEdgeWaypoints(t){this._edgeWaypoints.delete(t)}toggleFrameCollapse(t){this.frameCollapsed.has(t)?this.frameCollapsed.delete(t):this.frameCollapsed.add(t),this._emit("change")}isFrameCollapsed(t){return this.frameCollapsed.has(t)}_nodeHiddenByCollapse(t){if(!this.frameCollapsed.size)return!1;for(const e of this.frameCollapsed){const s=this.frames[e];if(s&&(this.V.posX[t]>=s.x&&this.V.posX[t]<=s.x+s.w&&this.V.posY[t]>=s.y+26&&this.V.posY[t]<=s.y+s.h))return!0}return!1}makeDraggable(t,e){if(!t||!e||!e.kind)throw new Error("makeDraggable: spec.kind required");t.style.cursor="grab",t.addEventListener("mousedown",s=>{if(s.preventDefault(),this.readOnly)return;const i=t.cloneNode(!0);Object.assign(i.style,{position:"fixed",pointerEvents:"none",opacity:"0.75",zIndex:"900",transform:"translate(-50%,-50%) scale(1.02)"}),document.body.appendChild(i);const o=t=>{i.style.left=t.clientX+"px",i.style.top=t.clientY+"px"};o(s);const n=t=>{window.removeEventListener("mousemove",o),window.removeEventListener("mouseup",n),i.remove();const s=this.canvas.getBoundingClientRect();if(t.clientX<s.left||t.clientX>s.right||t.clientY<s.top||t.clientY>s.bottom)return;const r=this._s2w(t.clientX,t.clientY),h={...e,x:r.x,y:r.y};delete h.element;const a=this.addNode(h);this._emit("palette:drop",{id:a,x:r.x,y:r.y,spec:e})};window.addEventListener("mousemove",o),window.addEventListener("mouseup",n)})}setTheme(t){this._theme="light"===t?s:e,this.options.theme=t,this.options.background=this._theme.bg,this.canvas.style.background=this._theme.bg,this._emit("theme",t)}toggleTheme(){this.setTheme("light"===this.options.theme?"dark":"light")}pushNodeMetric(t,e){let s=this.metrics.get(t);s||(s={data:new Float32Array(this._metricCap),idx:0,count:0},this.metrics.set(t,s)),s.data[s.idx]=e,s.idx=(s.idx+1)%this._metricCap,s.count<this._metricCap&&s.count++;const i=this.metricMax.get(t)||1;this.metricMax.set(t,Math.max(.99*i,Math.abs(e),1))}clearNodeMetric(t){this.metrics.delete(t),this.metricMax.delete(t)}setEdgeAnimated(t,e){e?this.animatedEdges.add(t):this.animatedEdges.delete(t)}setAllEdgesAnimated(t){if(!t)return void this.animatedEdges.clear();const e=this.w.edgeCount_();for(let t=0;t<e;t++)this.animatedEdges.add(t)}setConnectionValidator(t){this._connValidator="function"==typeof t?t:null}registerTemplate(t,e){this._templates.set(t,e)}insertTemplate(t,e=0,s=0){const i=this._templates.get(t);return i?i(this,e,s):-1}listTemplates(){return[...this._templates.keys()]}search(t){if(this._searchQuery=(t||"").toLowerCase(),this._searchHits=[],!this._searchQuery)return[];const e=this.w.nodeCount_();for(let t=0;t<e;t++){const e=(this.titles.get(t)||"").toLowerCase(),s=(this.descriptions.get(t)||"").toLowerCase(),i=this.kinds[this.V.kind[t]].name.toLowerCase(),o=(this.tags.get(t)||[]).join(" ").toLowerCase();(e.includes(this._searchQuery)||s.includes(this._searchQuery)||i.includes(this._searchQuery)||o.includes(this._searchQuery))&&this._searchHits.push(t)}return this._searchHits.slice()}jumpToSearchHit(t){if(!this._searchHits.length)return;const e=this._searchHits[(t%this._searchHits.length+this._searchHits.length)%this._searchHits.length];this.clearSelection(),this.w.setSelected(e,1),this.panTo(this.V.posX[e],this.V.posY[e])}clearSearch(){this._searchQuery="",this._searchHits=[]}openCommandPalette(){if(this._cmdPaletteEl)return this._cmdPaletteEl.remove(),void(this._cmdPaletteEl=null);const t=this._builtinCommands(),e=document.createElement("div");e.style.cssText=`position:absolute;top:80px;left:50%;transform:translateX(-50%);width:480px;max-height:60vh;overflow:hidden;background:${this._theme.panel};border:1px solid ${this._theme.border};border-radius:10px;box-shadow:0 16px 48px rgba(0,0,0,0.6);z-index:500;color:${this._theme.fg};font-family:Inter, ui-sans-serif;`,e.innerHTML=`\n <input id="zf-cmd-q" type="text" placeholder="Type a command…" style="width:100%;padding:14px 16px;background:transparent;color:${this._theme.fg};border:0;border-bottom:1px solid ${this._theme.border};outline:none;font-size:14px;">\n <div id="zf-cmd-list" style="max-height:46vh;overflow:auto;"></div>`,this.container.appendChild(e),this._cmdPaletteEl=e;const s=e.querySelector("#zf-cmd-q"),i=e.querySelector("#zf-cmd-list");let o=0,n=t;const r=()=>{i.innerHTML=n.map((t,e)=>`\n <div data-i="${e}" style="padding:9px 16px;cursor:pointer;display:flex;justify-content:space-between;align-items:center;background:${e===o?this._theme.hi:"transparent"};">\n <span>${b(t.label)}</span>\n <span style="color:${this._theme.muted};font-family:ui-monospace,Consolas,monospace;font-size:11px;">${t.hotkey||""}</span>\n </div>`).join("")};r();const h=t=>{const e=n[t];e&&e.run(),this.openCommandPalette()};i.addEventListener("mousedown",t=>{const e=t.target.closest("[data-i]");e&&h(parseInt(e.dataset.i,10))}),s.addEventListener("input",()=>{const e=s.value.toLowerCase();n=e?t.filter(t=>t.label.toLowerCase().includes(e)):t,o=0,r()}),s.addEventListener("keydown",t=>{"ArrowDown"===t.code&&(o=Math.min(n.length-1,o+1),r(),t.preventDefault()),"ArrowUp"===t.code&&(o=Math.max(0,o-1),r(),t.preventDefault()),"Enter"===t.code&&h(o),"Escape"===t.code&&this.openCommandPalette()}),s.focus()}_builtinCommands(){return[{label:"Auto layout (Sugiyama)",hotkey:"L",run:()=>this.runAutoLayout()},{label:"Force layout",hotkey:"F",run:()=>this.runForceLayout()},{label:"Fit view",hotkey:"0",run:()=>this.fitView()},{label:"Toggle theme (light/dark)",hotkey:"Ctrl+T",run:()=>this.toggleTheme()},{label:"Toggle minimap",hotkey:"Ctrl+M",run:()=>this.setMinimap(!this.options.minimap)},{label:"Toggle edge animation",hotkey:"Ctrl+E",run:()=>this.setAllEdgesAnimated(0===this.animatedEdges.size)},{label:"Toggle edge style",hotkey:"",run:()=>this.setEdgeStyle("bezier"===this.options.edgeStyle?"orthogonal":"bezier")},{label:"Toggle snap-to-grid",hotkey:"G",run:()=>this.setSnapToGrid(!this.options.snapToGrid)},{label:"Toggle path highlight",hotkey:"",run:()=>this.setPathHighlight(!this._pathHighlightEnabled)},{label:"Toggle hover preview",hotkey:"",run:()=>this.setHoverPreview(!this.options.hoverPreview)},{label:"Find…",hotkey:"Ctrl+F",run:()=>this.openSearch()},{label:"Highlight critical path",hotkey:"",run:()=>{const t=this.criticalPath();for(const e of t)this.w.setEdgeSelected_(e,1)}},{label:"Find SCCs (cycle groups)",hotkey:"",run:()=>{const t=this.findSCCs();for(const e of t)for(const t of e)this.w.setSelected(t,1)}},{label:"Color nodes by degree",hotkey:"",run:()=>this.colorByDegree()},{label:"Clear node colors",hotkey:"",run:()=>this.clearNodeColors()},{label:"Group selection",hotkey:"Ctrl+G",run:()=>this.groupSelection()},{label:"Add sticky note",hotkey:"",run:()=>this.addNote(-this.cam.x,-this.cam.y)},{label:"Select all",hotkey:"Ctrl+A",run:()=>this.selectAll()},{label:"Duplicate selection",hotkey:"Ctrl+D",run:()=>this.duplicateSelection()},{label:"Delete selection",hotkey:"Del",run:()=>this.deleteSelection()},{label:"Export PNG",hotkey:"",run:async()=>{const t=await this.exportPNG();window.open(URL.createObjectURL(t))}},{label:"Export SVG",hotkey:"",run:()=>{const t=new Blob([this.exportSVG()],{type:"image/svg+xml"});window.open(URL.createObjectURL(t))}},{label:"Export JSON",hotkey:"",run:()=>{const t=new Blob([JSON.stringify(this.toJSON(),null,2)],{type:"application/json"});window.open(URL.createObjectURL(t))}},{label:"Undo",hotkey:"Ctrl+Z",run:()=>this.undo()},{label:"Redo",hotkey:"Ctrl+Y",run:()=>this.redo()},{label:"Run graph",hotkey:"F5",run:()=>this.run()},{label:"Stop run",hotkey:"Shift+F5",run:()=>this.stop()},{label:"Clear runtime state",hotkey:"",run:()=>this.clearRuntimeState()},...[...this._templates.keys()].map(t=>({label:`Insert template: ${t}`,hotkey:"",run:()=>this.insertTemplate(t,-this.cam.x,-this.cam.y)})),...(this._extraCommands||[]).map(t=>({label:t.label,hotkey:t.hotkey||"",run:t.run}))]}openSearch(){if(this._searchEl)return this._searchEl.remove(),this._searchEl=null,void this.clearSearch();const t=document.createElement("div");t.style.cssText=`position:absolute;top:14px;left:50%;transform:translateX(-50%);background:${this._theme.panel};color:${this._theme.fg};border:1px solid ${this._theme.border};border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:8px;z-index:500;font-family:Inter, ui-sans-serif;box-shadow:0 8px 24px rgba(0,0,0,0.4);`,t.innerHTML=`<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${this._theme.muted}" stroke-width="2"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>\n <input id="zf-s" type="text" placeholder="Find nodes…" style="background:transparent;border:0;outline:none;color:${this._theme.fg};font-size:13px;width:240px;">\n <span id="zf-sn" style="color:${this._theme.muted};font-size:11px;font-family:ui-monospace,Consolas,monospace;"></span>`,this.container.appendChild(t),this._searchEl=t;const e=t.querySelector("#zf-s"),s=t.querySelector("#zf-sn");let i=0;const o=()=>{const t=this.search(e.value);s.textContent=t.length?`${i+1}/${t.length}`:e.value?"0":"",t.length&&this.jumpToSearchHit(i)};e.addEventListener("input",()=>{i=0,o()}),e.addEventListener("keydown",t=>{"Enter"===t.code&&(i=(i+(t.shiftKey?-1:1)+this._searchHits.length)%Math.max(this._searchHits.length,1),o(),t.preventDefault()),"Escape"===t.code&&this.openSearch()}),e.focus()}setMinimap(t){this.options.minimap=!!t,t?this._setupMinimap():this._minimapEl&&(this._minimapEl.remove(),this._minimapEl=null,this._minimapCtx=null)}_setupMinimap(){if(this._minimapEl)return;const t=document.createElement("canvas");t.width=200*(window.devicePixelRatio||1),t.height=140*(window.devicePixelRatio||1),t.style.cssText=`position:absolute;right:14px;bottom:14px;width:200px;height:140px;background:${this._theme.panel};border:1px solid ${this._theme.border};border-radius:8px;cursor:pointer;z-index:50;box-shadow:0 4px 16px rgba(0,0,0,0.4);`,this.container.appendChild(t),t.addEventListener("mousedown",e=>{const s=t.getBoundingClientRect(),i=(e.clientX-s.left)/s.width,o=(e.clientY-s.top)/s.height,n=this._graphBounds();n&&(this.cam.x=-(n.minX+i*(n.maxX-n.minX)),this.cam.y=-(n.minY+o*(n.maxY-n.minY)))}),this._minimapEl=t,this._minimapCtx=t.getContext("2d",{alpha:!1})}_graphBounds(){const t=this.w.nodeCount_();if(0===t)return null;let e=1/0,s=-1/0,i=1/0,o=-1/0;for(let n=0;n<t;n++){const t=.5*this.V.sizeW[n],r=.5*this.V.sizeH[n];this.V.posX[n]-t<e&&(e=this.V.posX[n]-t),this.V.posX[n]+t>s&&(s=this.V.posX[n]+t),this.V.posY[n]-r<i&&(i=this.V.posY[n]-r),this.V.posY[n]+r>o&&(o=this.V.posY[n]+r)}const n=.1*(s-e)+40,r=.1*(o-i)+40;return{minX:e-n,maxX:s+n,minY:i-r,maxY:o+r}}_drawValueBubbles(){if(!this._valueBubbles.length)return;const t=performance.now(),e=this.ctx;for(let s=this._valueBubbles.length-1;s>=0;s--){const i=this._valueBubbles[s],o=(t-i.t0)/i.dur;if(o>=1){this._valueBubbles.splice(s,1);continue}const n=o<.15?o/.15:o>.7?(1-o)/.3:1,r=30*o,h=i.nodeId;if(h>=this.w.nodeCount_())continue;const a=this.V.posX[h],l=this.V.posY[h],d=.5*this.V.sizeH[h],c=this._w2s(a,l-d);e.save(),e.globalAlpha=n,e.font="600 12px ui-monospace, Consolas, monospace";const u=e.measureText(i.text).width+2*8,m=22,p=c.x-u/2,g=c.y-m-10-r;e.shadowColor="rgba(0,0,0,0.5)",e.shadowBlur=8,e.fillStyle="#161b27",this._roundRect(p,g,u,m,5),e.fill(),e.shadowBlur=0,e.strokeStyle="#5b8def",e.lineWidth=1.4,this._roundRect(p,g,u,m,5),e.stroke(),e.fillStyle="#5be0d0",e.textBaseline="middle",e.textAlign="center",e.fillText(i.text,c.x,g+m/2),e.fillStyle="#161b27",e.strokeStyle="#5b8def",e.beginPath(),e.moveTo(c.x-5,g+m),e.lineTo(c.x+5,g+m),e.lineTo(c.x,g+m+6),e.closePath(),e.fill(),e.stroke(),e.restore()}}_drawWaypoints(){for(const[t,e]of this._edgeWaypoints)for(const t of e){const e=this._w2s(t.x,t.y);this.ctx.fillStyle="#f0b93a",this.ctx.beginPath(),this.ctx.arc(e.x,e.y,5,0,2*Math.PI),this.ctx.fill(),this.ctx.strokeStyle="#0b0f17",this.ctx.lineWidth=1.2,this.ctx.stroke()}}_hitWaypoint(t,e){const s=8/this.cam.zoom;for(const[i,o]of this._edgeWaypoints)for(let n=0;n<o.length;n++)if(Math.hypot(o[n].x-t,o[n].y-e)<s)return{edgeIdx:i,wpIdx:n};return null}_drawRemoteCursors(){if(!this.remoteCursors.size)return;const t=performance.now();for(const[e,s]of this.remoteCursors){if(t-s.t>3e4){this.remoteCursors.delete(e);continue}const i=this._w2s(s.x,s.y),o=this.ctx;o.save(),o.fillStyle=s.color,o.beginPath(),o.moveTo(i.x,i.y),o.lineTo(i.x+12,i.y+4),o.lineTo(i.x+5,i.y+6),o.lineTo(i.x+4,i.y+13),o.closePath(),o.fill(),o.font="600 11px Inter, ui-sans-serif";const n=o.measureText(s.name).width;o.fillStyle=s.color,this._roundRect(i.x+12,i.y+12,n+12,16,4),o.fill(),o.fillStyle="#0b0f17",o.textBaseline="middle",o.fillText(s.name,i.x+18,i.y+20),o.restore()}}_getImage(t){let e=this._imageCache.get(t);return e||(e={img:new Image,ready:!1},e.img.crossOrigin="anonymous",e.img.onload=()=>{e.ready=!0},e.img.onerror=()=>{e.ready=!1},e.img.src=t,this._imageCache.set(t,e)),e}_drawMinimap(){if(!this._minimapEl||!this._minimapCtx)return;const t=this._minimapCtx,e=this._minimapEl.width,s=this._minimapEl.height;t.fillStyle=this._theme.panel,t.fillRect(0,0,e,s);const i=this._graphBounds();if(!i)return;const o=e/(i.maxX-i.minX),n=s/(i.maxY-i.minY),r=Math.min(o,n),h=.5*(e-r*(i.maxX-i.minX)),a=.5*(s-r*(i.maxY-i.minY)),l=this.w.nodeCount_();for(let e=0;e<l;e++){const s=this.kinds[this.V.kind[e]],o=.5*this.V.sizeW[e]*r,n=.5*this.V.sizeH[e]*r,l=h+(this.V.posX[e]-i.minX)*r,d=a+(this.V.posY[e]-i.minY)*r;t.fillStyle=this.colors.get(e)||s.color,t.fillRect(l-o,d-n,Math.max(2,2*o),Math.max(2,2*n))}const d=window.devicePixelRatio||1,c=this.canvas.width/d/this.cam.zoom,u=this.canvas.height/d/this.cam.zoom,m=h+(-this.cam.x-.5*c-i.minX)*r,p=a+(-this.cam.y-.5*u-i.minY)*r;t.strokeStyle=this._theme.accent,t.lineWidth=2,t.strokeRect(m,p,c*r,u*r)}setPathHighlight(t){this._pathHighlightEnabled=!!t,t||(this._focusedSet=null)}registerKind(t){const e=this.kinds.length,s={name:t.name??`custom${e}`,color:t.color??"#94a3b8",badge:t.badge??"C",w:t.w??140,h:t.h??60,nin:t.nin??1,nout:t.nout??1,shape:t.shape??"rect",html:!0===t.html,template:t.template||null,execute:"function"==typeof t.execute?t.execute:null,portIn:Array.isArray(t.portIn)?t.portIn.slice():null,portOut:Array.isArray(t.portOut)?t.portOut.slice():null,inputs:Array.isArray(t.inputs)?t.inputs.slice():null,outputs:Array.isArray(t.outputs)?t.outputs.slice():null,retry:t.retry||null};return this.kinds.push(s),this.kindByName.set(s.name,e),this._runOrder=null,e}addNote(t,e,s="",i={}){const o=[{fill:"rgba(254,249,195,0.94)",text:"#5b3d12",border:"#caa54a"},{fill:"rgba(252,231,243,0.94)",text:"#831843",border:"#db5895"},{fill:"rgba(220,252,231,0.94)",text:"#14532d",border:"#5cad75"},{fill:"rgba(219,234,254,0.94)",text:"#1e3a8a",border:"#5b8def"}],n=i.color||o[this.notes.length%o.length],r={id:++this._noteSeq,x:t,y:e,w:i.w||220,h:i.h||130,text:s,color:n};return this.notes.push(r),this._emit("change"),r.id}deleteNote(t){this.notes=this.notes.filter(e=>e.id!==t),this._emit("change")}addFrame(t,e,s,i,o="Group",n="#5b8def"){const r={id:++this._frameSeq,x:t,y:e,w:s,h:i,label:o,color:n};return this.frames.push(r),this._emit("change"),r.id}groupSelection(t){const e=this.getSelection();if(0===e.length)return-1;let s=1/0,i=-1/0,o=1/0,n=-1/0;for(const t of e){const e=.5*this.V.sizeW[t],r=.5*this.V.sizeH[t];this.V.posX[t]-e<s&&(s=this.V.posX[t]-e),this.V.posX[t]+e>i&&(i=this.V.posX[t]+e),this.V.posY[t]-r<o&&(o=this.V.posY[t]-r),this.V.posY[t]+r>n&&(n=this.V.posY[t]+r)}return this.addFrame(s-30,o-30-26,i-s+60,n-o+60+26,t||`Group ${this.frames.length+1}`)}deleteFrame(t){this.frames=this.frames.filter(e=>e.id!==t),this._emit("change")}enterSubflow(t){const e=this.frames.findIndex(e=>e.id===t);if(-1===e)return;this._focusFrame=e;const s=this.frames[e];this.cam.x=-(s.x+s.w/2),this.cam.y=-(s.y+s.h/2),this.cam.zoom=.9*Math.min(this.canvas.width/(s.w+80),this.canvas.height/(s.h+80)),this._emit("subflow",s.id)}exitSubflow(){-1!==this._focusFrame&&(this._focusFrame=-1,this.fitView(),this._emit("subflow",null))}_isInsideFocusFrame(t){if(-1===this._focusFrame)return!0;const e=this.frames[this._focusFrame];return this.V.posX[t]>=e.x&&this.V.posX[t]<=e.x+e.w&&this.V.posY[t]>=e.y&&this.V.posY[t]<=e.y+e.h}_resolveKind(t){if("number"==typeof t)return t;const e=this.kindByName.get(t);if(void 0===e)throw new Error(`zflow: unknown kind "${t}"`);return e}runAutoLayout(){const t=this.w.autoLayout();return this.w.snapshot(),this._emit("change"),t}runForceLayout(t=220){this._forceRaf&&cancelAnimationFrame(this._forceRaf),this.w.forceLayoutReset();let e=0;const s=()=>{this.w.forceLayoutTick(.05),e++,e<t?this._forceRaf=requestAnimationFrame(s):(this._forceRaf=null,this.w.snapshot(),this._emit("change"))};this._forceRaf=requestAnimationFrame(s)}fitView(t=80){const e=this.w.nodeCount_();if(0===e)return;let s=1/0,i=-1/0,o=1/0,n=-1/0;for(let t=0;t<e;t++){const e=.5*this.V.sizeW[t],r=.5*this.V.sizeH[t];this.V.posX[t]-e<s&&(s=this.V.posX[t]-e),this.V.posX[t]+e>i&&(i=this.V.posX[t]+e),this.V.posY[t]-r<o&&(o=this.V.posY[t]-r),this.V.posY[t]+r>n&&(n=this.V.posY[t]+r)}const r=i-s+2*t,h=n-o+2*t;this.cam.x=-(s+(i-s)/2),this.cam.y=-(o+(n-o)/2),this.cam.zoom=.85*Math.min(this.canvas.width/r,this.canvas.height/h)}zoomTo(t){this.cam.zoom=Math.max(.2,Math.min(3,t))}panTo(t,e){this.cam.x=-t,this.cam.y=-e}undo(){this.w.undo()&&this._emit("change")}redo(){this.w.redo()&&this._emit("change")}snapshot(){this.w.snapshot()}criticalPath(){const t=this.w.nodeCount_(),e=this.w.edgeCount_();if(0===t)return[];const s=new Uint32Array(t);for(let t=0;t<e;t++)s[this.V.edgeToN[t]]++;const i=[];for(let e=0;e<t;e++)0===s[e]&&i.push(e);const o=new Int32Array(t),n=new Int32Array(t);n.fill(-1);const r=this._buildAdj();let h=0;for(;h<i.length;){const t=i[h++];for(const e of r.get(t)||[])o[t]+1>o[e.to]&&(o[e.to]=o[t]+1,n[e.to]=e.edge),s[e.to]--,0===s[e.to]&&i.push(e.to)}let a=0;for(let e=1;e<t;e++)o[e]>o[a]&&(a=e);if(0===o[a])return[];const l=[];let d=a;for(;-1!==n[d];)l.push(n[d]),d=this.V.edgeFromN[n[d]];return l}findSCCs(){const t=this.w.nodeCount_(),e=this._buildAdj(),s=new Int32Array(t).fill(-1),i=new Int32Array(t),o=new Uint8Array(t),n=[],r=[];let h=0;for(let a=0;a<t;a++){if(-1!==s[a])continue;const t=[{v:a,child:0}];for(s[a]=h,i[a]=h++,n.push(a),o[a]=1;t.length;){const a=t[t.length-1],l=e.get(a.v)||[];if(a.child<l.length){const e=l[a.child++].to;-1===s[e]?(s[e]=h,i[e]=h++,n.push(e),o[e]=1,t.push({v:e,child:0})):o[e]&&s[e]<i[a.v]&&(i[a.v]=s[e])}else{if(i[a.v]===s[a.v]){const t=[];for(;n.length;){const e=n.pop();if(o[e]=0,t.push(e),e===a.v)break}t.length>=2&&r.push(t)}const e=a.v;t.pop(),t.length&&i[e]<i[t[t.length-1].v]&&(i[t[t.length-1].v]=i[e])}}}return r}colorByDegree(){const t=this.w.nodeCount_(),e=this.w.edgeCount_(),s=new Uint16Array(t);for(let t=0;t<e;t++)s[this.V.edgeFromN[t]]++,s[this.V.edgeToN[t]]++;let i=1;for(let e=0;e<t;e++)s[e]>i&&(i=s[e]);const o=["#3b5fc4","#5b8def","#5be0d0","#5bd17a","#f0b93a","#fb923c","#e8462b"],n=t=>{if(t<=0)return o[0];if(t>=1)return o[o.length-1];const e=t*(o.length-1),s=Math.floor(e),i=Math.min(o.length-1,s+1),n=e-s,r=y(o[s]),h=y(o[i]);return`rgb(${Math.round(r[0]*(1-n)+h[0]*n)},${Math.round(r[1]*(1-n)+h[1]*n)},${Math.round(r[2]*(1-n)+h[2]*n)})`};for(let e=0;e<t;e++)this.colors.set(e,n(s[e]/i));this._emit("change")}clearNodeColors(){this.colors.clear(),this._emit("change")}importMermaid(t){const e=v(t);if(!e||0===e.nodes.size)return 0;const s={rect:"process",rhombus:"decision",circle:"branch",round:"process",subroutine:"aggregator",default:"process"},i=new Map;let o=0;for(const[t,n]of e.nodes){const e=this.addNode({kind:s[n.shape]||"process",x:o%8*200-700,y:110*Math.floor(o/8),title:n.label});if(e<0)break;i.set(t,e),o++}for(const t of e.edges){const e=i.get(t.from),s=i.get(t.to);void 0!==e&&void 0!==s&&this.addEdge({from:e,to:s,label:t.label})}return this.runAutoLayout(),this.fitView(),e.nodes.size}importDot(t){const e=k(t);if(!e||0===e.nodes.size)return 0;const s=new Map;let i=0;for(const[t,o]of e.nodes){const e=this.addNode({kind:"process",x:i%8*200-700,y:110*Math.floor(i/8),title:o.label});if(e<0)break;s.set(t,e),i++}for(const t of e.edges){const e=s.get(t.from),i=s.get(t.to);if(void 0===e||void 0===i)continue;const o=this.addEdge({from:e,to:i});o>=0&&t.label&&this.setEdgeLabel(o,t.label)}return this.runAutoLayout(),this.fitView(),e.nodes.size}shortestPathSafe(t,e){return this.shortestPath(t,e)||[]}shortestPath(t,e){const s=this._buildAdj(),i=new Map;i.set(t,null);const o=[t];for(;o.length;){const t=o.shift();if(t===e)break;for(const e of s.get(t)||[])i.has(e.to)||(i.set(e.to,{from:t,edgeIdx:e.edge}),o.push(e.to))}if(!i.has(e))return[];const n=[];let r=e;for(;i.get(r);)n.push(i.get(r).edgeIdx),r=i.get(r).from;return n.reverse()}findCycles(){const t=this.w.nodeCount_(),e=new Uint8Array(t),s=new Set,i=this._buildAdj();for(let o=0;o<t;o++){if(0!==e[o])continue;const t=[{u:o,iter:(i.get(o)||[])[Symbol.iterator]()}];for(e[o]=1;t.length;){const o=t[t.length-1],n=o.iter.next();if(n.done){e[o.u]=2,t.pop();continue}const r=n.value;1===e[r.to]?s.add(r.edge):0===e[r.to]&&(e[r.to]=1,t.push({u:r.to,iter:(i.get(r.to)||[])[Symbol.iterator]()}))}}return[...s]}_ensureAdj(){if(!this._adjDirty&&this._nodeAdj)return;const t=this.w.nodeCount_(),e=this.w.edgeCount_(),s=new Array(t);for(let e=0;e<t;e++)s[e]=[];for(let i=0;i<e;i++){const e=this.V.edgeFromN[i],o=this.V.edgeToN[i];e<t&&s[e].push(i),o<t&&e!==o&&s[o].push(i)}this._nodeAdj=s,this._adjDirty=!1}_buildAdj(){const t=this.w.edgeCount_(),e=new Map;for(let s=0;s<t;s++){const t=this.V.edgeFromN[s];e.has(t)||e.set(t,[]),e.get(t).push({to:this.V.edgeToN[s],edge:s})}return e}toJSON(){const t=this.w.nodeCount_(),e=this.w.edgeCount_(),s=[];for(let e=0;e<t;e++){const t={id:e,kind:this.kinds[this.V.kind[e]].name,x:this.V.posX[e],y:this.V.posY[e],w:this.V.sizeW[e],h:this.V.sizeH[e],nin:this.V.nIn[e],nout:this.V.nOut[e]};this.titles.has(e)&&(t.title=this.titles.get(e)),this.colors.has(e)&&(t.color=this.colors.get(e)),this.descriptions.has(e)&&(t.description=this.descriptions.get(e)),this.tags.has(e)&&(t.tags=this.tags.get(e)),this.status.has(e)&&(t.status=this.status.get(e)),this.progress.has(e)&&(t.progress=this.progress.get(e)),s.push(t)}const i=[];for(let t=0;t<e;t++){const e={from:this.V.edgeFromN[t],fp:this.V.edgeFromP[t],to:this.V.edgeToN[t],tp:this.V.edgeToP[t]};this.edgeLabels.has(t)&&(e.label=this.edgeLabels.get(t)),i.push(e)}return{version:1,nodes:s,edges:i,camera:{...this.cam},edgeStyle:this.options.edgeStyle}}loadJSON(t){this.w.reset(),this.titles.clear(),this.colors.clear(),this.descriptions.clear(),this.tags.clear(),this.status.clear(),this.progress.clear(),this.edgeLabels.clear();const e=new Map;for(const s of t.nodes||[]){const t=this.addNode({kind:s.kind,x:s.x,y:s.y,w:s.w,h:s.h,title:s.title,color:s.color,description:s.description,tags:s.tags,status:s.status,progress:s.progress});e.set(s.id??t,t)}for(const s of t.edges||[])this.addEdge({from:e.get(s.from)??s.from,fp:s.fp,to:e.get(s.to)??s.to,tp:s.tp,label:s.label});t.camera&&Object.assign(this.cam,t.camera),t.edgeStyle&&(this.options.edgeStyle=t.edgeStyle),this.w.snapshot(),this._emit("change")}async exportPNG(){return new Promise(t=>this.canvas.toBlob(t,"image/png"))}exportSVG(){const t=this.w.nodeCount_(),e=this.w.edgeCount_();if(0===t)return'<svg xmlns="http://www.w3.org/2000/svg"/>';let s=1/0,i=-1/0,o=1/0,n=-1/0;for(let e=0;e<t;e++){const t=.5*this.V.sizeW[e],r=.5*this.V.sizeH[e];this.V.posX[e]-t<s&&(s=this.V.posX[e]-t),this.V.posX[e]+t>i&&(i=this.V.posX[e]+t),this.V.posY[e]-r<o&&(o=this.V.posY[e]-r),this.V.posY[e]+r>n&&(n=this.V.posY[e]+r)}const r=i-s+80,h=n-o+80,a=[`<svg xmlns="http://www.w3.org/2000/svg" viewBox="${s-40} ${o-40} ${r} ${h}" width="${r}" height="${h}" style="background:${this.options.background}">`];for(let t=0;t<e;t++){const e=this.V.edgeFromN[t],s=this.V.edgeToN[t],i=this._portWorld(e,1,this.V.edgeFromP[t]),o=this._portWorld(s,0,this.V.edgeToP[t]),n=this.colors.get(e)||this.kinds[this.V.kind[e]].color,r=this.colors.get(s)||this.kinds[this.V.kind[s]].color,h=`g${t}`;if(a.push(`<defs><linearGradient id="${h}" x1="${i.x}" y1="${i.y}" x2="${o.x}" y2="${o.y}" gradientUnits="userSpaceOnUse"><stop offset="0%" stop-color="${n}"/><stop offset="100%" stop-color="${r}"/></linearGradient></defs>`),"orthogonal"===this.options.edgeStyle){const t=this._orthoPath(i,o),e=`M ${t[0].x} ${t[0].y} `+t.slice(1).map(t=>`L ${t.x} ${t.y}`).join(" ");a.push(`<path d="${e}" stroke="url(#${h})" stroke-width="1.7" fill="none" stroke-linejoin="round"/>`)}else{const t=o.x-i.x,e=o.y-i.y,s=Math.max(50,.5*Math.abs(t)+.4*Math.abs(e));a.push(`<path d="M ${i.x} ${i.y} C ${i.x+s} ${i.y} ${o.x-s} ${o.y} ${o.x} ${o.y}" stroke="url(#${h})" stroke-width="1.7" fill="none"/>`)}}for(let e=0;e<t;e++){const t=this.kinds[this.V.kind[e]],s=this.colors.get(e)||t.color,i=this.V.posX[e]-this.V.sizeW[e]/2,o=this.V.posY[e]-this.V.sizeH[e]/2,n=this.V.sizeW[e],r=this.V.sizeH[e];if("diamond"===t.shape){const t=this.V.posX[e],h=this.V.posY[e];a.push(`<polygon points="${t},${o} ${i+n},${h} ${t},${o+r} ${i},${h}" fill="#161b27" stroke="${s}" stroke-width="1.4"/>`)}else"ellipse"===t.shape?a.push(`<ellipse cx="${this.V.posX[e]}" cy="${this.V.posY[e]}" rx="${n/2}" ry="${r/2}" fill="#161b27" stroke="${s}" stroke-width="1.4"/>`):(a.push(`<rect x="${i}" y="${o}" width="${n}" height="${r}" rx="8" fill="#161b27" stroke="${s}" stroke-width="1.4"/>`),"rect"===t.shape&&a.push(`<rect x="${i}" y="${o}" width="${n}" height="22" rx="8" fill="${s}"/>`));const h=this.titles.get(e)||`${t.name} #${e}`;a.push(`<text x="${this.V.posX[e]}" y="${o+("rect"===t.shape?14:r/2)}" font-family="Inter, system-ui, sans-serif" font-size="11" font-weight="600" text-anchor="middle" fill="${"rect"===t.shape?"#0b0f17":s}">${w(h)}</text>`)}return a.push("</svg>"),a.join("\n")}on(t,e){return this.listeners.has(t)||this.listeners.set(t,[]),this.listeners.get(t).push(e),()=>{const s=this.listeners.get(t),i=s.indexOf(e);i>=0&&s.splice(i,1)}}_emit(t,...e){if(this._suspendEvents&&"change"!==t)return;const s=this.listeners.get(t);if(s)for(const t of s.slice())try{t(...e)}catch(t){console.error(t)}}_resize(){const t=window.devicePixelRatio||1,e=this.container.getBoundingClientRect();this.canvas.width=Math.floor(e.width*t),this.canvas.height=Math.floor(e.height*t),this.canvas.style.width=e.width+"px",this.canvas.style.height=e.height+"px"}_w2s(t,e){return{x:this.canvas.width/2+(t+this.cam.x)*this.cam.zoom,y:this.canvas.height/2+(e+this.cam.y)*this.cam.zoom}}_s2w(t,e){const s=window.devicePixelRatio||1,i=this.canvas.getBoundingClientRect(),o=(t-i.left)*s,n=(e-i.top)*s;return{x:(o-this.canvas.width/2)/this.cam.zoom-this.cam.x,y:(n-this.canvas.height/2)/this.cam.zoom-this.cam.y}}_attachEvents(){const t=this.canvas;t.addEventListener("contextmenu",t=>t.preventDefault()),t.addEventListener("mousedown",t=>{this._hideMenu(),this._editingNoteEl&&-1!==this._editingNote&&this._editingNoteEl.blur(),this._editingTitleEl&&-1!==this._editingTitle&&this._editingTitleEl.blur();const e=this._s2w(t.clientX,t.clientY);if(2===t.button)return void this._onRightClick(t,e);if(1===t.button)return void this._startPan(t);const s=this.w.hitTestPort(e.x,e.y,11);if(-1!==s){const t=s>>>24&255,i=s>>>16&255,o=65535&s;return this._mode="connecting",this._edgeStart={nodeId:o,side:t,idx:i},this._edgeCursor=e,void(this.canvas.style.cursor="crosshair")}const i=this._hitHandle(e.x,e.y);if(i&&!this.readOnly&&!this.locked.has(i.nodeId))return this._mode="resize",void(this._resizingHandle={...i,lastX:e.x,lastY:e.y});const o=this._hitWaypoint(e.x,e.y);if(o&&!this.readOnly)return this._draggingWaypoint=o,void(this._mode="drag-waypoint");const n=this._hitFrameCorner(e.x,e.y);if(n)return this._mode="resize-frame",void(this._resizingFrame={...n,lastX:e.x,lastY:e.y});const r=this._hitFrameHeader(e.x,e.y);if(-1!==r)return this._mode="drag-frame",this._draggingFrame=r,void(this._frameDragLast=e);const h=this._hitNote(e.x,e.y);if(-1!==h)return this._mode="drag-note",this._draggingNote=h,void(this._noteDragLast=e);const a=this._hitTaskCheckbox(e.x,e.y);if(a){const t=this.tasks.get(a.nodeId);if(t&&t[a.taskIdx]){t[a.taskIdx].done=!t[a.taskIdx].done;const e=t.filter(t=>t.done).length;this.progress.set(a.nodeId,e/t.length),this._emit("change")}return}const l=this.w.hitTestNode(e.x,e.y);if(-1!==l)return t.shiftKey||0!==this.V.selected[l]?t.shiftKey&&this.w.toggleSelected(l):(this.w.clearSelection(),this.w.setSelected(l,1)),this.readOnly||this.locked.has(l)||(this._mode="drag",this._dragLast=e),void this._emit("select",this.getSelection());const d=this._hitTestEdge(e.x,e.y,6/this.cam.zoom);return-1!==d?(t.shiftKey||this.w.clearSelection(),this.w.setEdgeSelected(d,1),void this._emit("select",this.getSelection())):t.altKey?(t.shiftKey||this.w.clearSelection(),this._mode="lasso",void(this._lasso=[{x:e.x,y:e.y}])):(t.shiftKey||this.w.clearSelection(),this._mode="marquee",void(this._marquee={x0:e.x,y0:e.y,x1:e.x,y1:e.y}))}),t.addEventListener("mousemove",e=>{const s=this._s2w(e.clientX,e.clientY);if("pan"===this._mode){const t=window.devicePixelRatio||1,s=(e.clientX-this._dragStart.sx)*t/this.cam.zoom,i=(e.clientY-this._dragStart.sy)*t/this.cam.zoom;this.cam.x+=s,this.cam.y+=i;const o=performance.now(),n=Math.max(1,o-(this._panVel.lastTs||o))/1e3;return this._panVel.x=s/n,this._panVel.y=i/n,this._panVel.lastTs=o,this._dragStart.sx=e.clientX,void(this._dragStart.sy=e.clientY)}if("resize"===this._mode&&this._resizingHandle){const t=s.x-this._resizingHandle.lastX,e=s.y-this._resizingHandle.lastY;return this._applyResize(this._resizingHandle.corner,t,e),this._resizingHandle.lastX=s.x,void(this._resizingHandle.lastY=s.y)}if("drag-waypoint"===this._mode&&this._draggingWaypoint){const{edgeIdx:t,wpIdx:e}=this._draggingWaypoint,i=this._edgeWaypoints.get(t);return void(i&&i[e]&&(i[e].x=s.x,i[e].y=s.y))}if("drag"===this._mode){if(this._gl){this._ensureAdj();for(let t=0;t<this.w.nodeCount_();t++)if(this.V.selected[t]){this._gl.markNodeDirty(t);const e=this._nodeAdj[t];if(e)for(let t=0;t<e.length;t++)this._gl.markEdgeDirty(e[t])}}let t=s.x-this._dragLast.x,e=s.y-this._dragLast.y;if(this.options.snapToGrid){for(let s=0;s<this.w.nodeCount_();s++)if(this.V.selected[s]){const i=this.options.gridSize,o=Math.round((this.V.posX[s]+t)/i)*i,n=Math.round((this.V.posY[s]+e)/i)*i;t=o-this.V.posX[s],e=n-this.V.posY[s];break}this._alignGuides=null}else{const s=this._computeAlignSnap(t,e);t+=s.dx,e+=s.dy,this._alignGuides={v:null!==s.guideX?[s.guideX]:[],h:null!==s.guideY?[s.guideY]:[]}}return this.w.moveSelectedBy(t,e),void(this._dragLast={x:this._dragLast.x+t,y:this._dragLast.y+e})}if("drag-frame"===this._mode){const t=s.x-this._frameDragLast.x,e=s.y-this._frameDragLast.y,i=this.frames[this._draggingFrame];i.x+=t,i.y+=e;for(let s=0;s<this.w.nodeCount_();s++)this.V.posX[s]>=i.x&&this.V.posX[s]<=i.x+i.w&&this.V.posY[s]>=i.y&&this.V.posY[s]<=i.y+i.h&&(this.V.posX[s]+=t,this.V.posY[s]+=e);return void(this._frameDragLast=s)}if("resize-frame"===this._mode&&this._resizingFrame){const t=s.x-this._resizingFrame.lastX,e=s.y-this._resizingFrame.lastY;return this._applyFrameResize(this._resizingFrame.idx,this._resizingFrame.corner,t,e),this._resizingFrame.lastX=s.x,void(this._resizingFrame.lastY=s.y)}if("drag-note"===this._mode){const t=s.x-this._noteDragLast.x,e=s.y-this._noteDragLast.y,i=this.notes[this._draggingNote];return i.x+=t,i.y+=e,void(this._noteDragLast=s)}if("connecting"===this._mode)return void(this._edgeCursor=s);if("lasso"===this._mode&&this._lasso){const t=this._lasso[this._lasso.length-1];return void(Math.hypot(s.x-t.x,s.y-t.y)>6/this.cam.zoom&&this._lasso.push({x:s.x,y:s.y}))}if("marquee"===this._mode)return this._marquee.x1=s.x,this._marquee.y1=s.y,void this.w.selectInRect(this._marquee.x0,this._marquee.y0,this._marquee.x1,this._marquee.y1,1);const i=this.w.hitTestNode(s.x,s.y);i!==this._hoveredNode&&(this._hoveredNode=i,this._hoveredNodeSince=performance.now(),this._lastFocusComputed=-2),this._hoveredEdge=-1===i?this._hitTestEdge(s.x,s.y,6/this.cam.zoom):-1;const o=this._hitHandle(s.x,s.y);t.style.cursor=o?a[o.corner]:""}),t.addEventListener("mouseup",()=>{if("connecting"===this._mode&&this._edgeCursor){const t=this.w.hitTestPort(this._edgeCursor.x,this._edgeCursor.y,14);if(-1!==t){const e=t>>>16&255,s=65535&t;if((t>>>24&255)!==this._edgeStart.side&&s!==this._edgeStart.nodeId){const t=1===this._edgeStart.side?this._edgeStart.nodeId:s,i=1===this._edgeStart.side?this._edgeStart.idx:e,o=0===this._edgeStart.side?this._edgeStart.nodeId:s,n=0===this._edgeStart.side?this._edgeStart.idx:e,r=this.validateConnection(t,i,o,n);null===r?this.addEdge({from:t,fp:i,to:o,tp:n}):(this._emit("connection:rejected",{fromN:t,fromP:i,toN:o,toP:n,reason:r}),this._flashReject={x:this._edgeCursor.x,y:this._edgeCursor.y,msg:r,t0:performance.now()})}}}else if("lasso"===this._mode&&this._lasso&&this._lasso.length>2){for(let t=0;t<this.w.nodeCount_();t++)x(this.V.posX[t],this.V.posY[t],this._lasso)&&this.w.setSelected(t,1);this._emit("select",this.getSelection())}else"drag-waypoint"===this._mode?(this._draggingWaypoint=null,this._emit("change")):"drag"!==this._mode&&"resize"!==this._mode&&"drag-frame"!==this._mode&&"resize-frame"!==this._mode&&"drag-note"!==this._mode&&"marquee"!==this._mode||("marquee"!==this._mode&&(this.w.snapshot(),this._emit("change")),this._emit("select",this.getSelection()));this._mode="idle",this._edgeStart=null,this._edgeCursor=null,this._marquee=null,this._lasso=null,this._alignGuides=null,this._resizingHandle=null,this._resizingFrame=null,this._draggingFrame=-1,this._draggingNote=-1,this.canvas.classList.remove("panning"),this.canvas.style.cursor=""});const e=new Map;let s=null,i=null;this._pointerSynthesizing=!1,t.addEventListener("pointerdown",o=>{if("mouse"!==o.pointerType)if(t.setPointerCapture(o.pointerId),e.set(o.pointerId,{x:o.clientX,y:o.clientY}),2===e.size)s=p(e),this._mode="pinch";else if(1===e.size){const e=o.clientX,s=o.clientY;i=setTimeout(()=>{i=null;const t=this._s2w(e,s);this._onRightClick({clientX:e,clientY:s,preventDefault(){}},t)},550),this._pointerSynthesizing=!0,t.dispatchEvent(new MouseEvent("mousedown",{clientX:e,clientY:s,button:0,bubbles:!0})),this._pointerSynthesizing=!1}}),t.addEventListener("pointermove",o=>{if("mouse"!==o.pointerType&&e.has(o.pointerId))if(e.set(o.pointerId,{x:o.clientX,y:o.clientY}),2===e.size&&s){const t=p(e),i=t.dist/s.dist,o=this._s2w(t.mid.x,t.mid.y);this.cam.zoom=Math.max(.2,Math.min(3,this.cam.zoom*i));const n=this._s2w(t.mid.x,t.mid.y);this.cam.x+=n.x-o.x,this.cam.y+=n.y-o.y;const r=window.devicePixelRatio||1;this.cam.x+=(t.mid.x-s.mid.x)*r/this.cam.zoom,this.cam.y+=(t.mid.y-s.mid.y)*r/this.cam.zoom,s=t}else 1===e.size&&(i&&Math.hypot(o.movementX||0,o.movementY||0)>4&&(clearTimeout(i),i=null),this._pointerSynthesizing=!0,t.dispatchEvent(new MouseEvent("mousemove",{clientX:o.clientX,clientY:o.clientY,button:0,bubbles:!0})),this._pointerSynthesizing=!1)});const o=o=>{"mouse"!==o.pointerType&&(e.delete(o.pointerId),i&&(clearTimeout(i),i=null),e.size<2&&(s=null,"pinch"===this._mode&&(this._mode="idle")),0===e.size&&(this._pointerSynthesizing=!0,t.dispatchEvent(new MouseEvent("mouseup",{clientX:o.clientX,clientY:o.clientY,button:0,bubbles:!0})),this._pointerSynthesizing=!1))};t.addEventListener("pointerup",o),t.addEventListener("pointercancel",o),t.addEventListener("wheel",t=>{t.preventDefault();const e=t.ctrlKey;if(e||1===t.deltaMode){const s=this._s2w(t.clientX,t.clientY);this.cam.zoom=Math.max(.2,Math.min(3,this.cam.zoom*Math.exp(-t.deltaY*(e?.012:.05))));const i=this._s2w(t.clientX,t.clientY);return this.cam.x+=i.x-s.x,void(this.cam.y+=i.y-s.y)}const s=window.devicePixelRatio||1;this.cam.x-=t.deltaX*s/this.cam.zoom,this.cam.y-=t.deltaY*s/this.cam.zoom},{passive:!1}),t.addEventListener("dblclick",t=>{const e=this._s2w(t.clientX,t.clientY),s=this._hitFrameHeader(e.x,e.y);if(-1!==s)return void this.enterSubflow(this.frames[s].id);const i=this._hitNote(e.x,e.y);if(-1!==i)return void this._startEditingNote(i);const o=this.w.hitTestNode(e.x,e.y);if(-1!==o)return!1!==this.options.dblclickEditsTitle&&this._startEditingTitle(o),void this._emit("node:dblclick",o);const n=this._hitTestEdge(e.x,e.y,6/this.cam.zoom);-1===n?this._emit("canvas:dblclick",e):this._emit("edge:dblclick",n)})}_startPan(t){this._mode="pan",this._dragStart={sx:t.clientX,sy:t.clientY},this._panVel.x=0,this._panVel.y=0,this._panVel.lastTs=performance.now(),this.canvas.style.cursor="grabbing"}_attachKeyboard(){const t=t=>{if(!(this.container.contains(document.activeElement)||document.activeElement===document.body))return;const e=document.activeElement;if(e&&("INPUT"===e.tagName||"TEXTAREA"===e.tagName))return;const s=t.ctrlKey||t.metaKey;if("Delete"!==t.code&&"Backspace"!==t.code){if(s&&"KeyZ"===t.code&&!t.shiftKey)return this.undo(),void t.preventDefault();if(s&&("KeyY"===t.code||"KeyZ"===t.code&&t.shiftKey))return this.redo(),void t.preventDefault();if(s&&"KeyA"===t.code)return this.selectAll(),void t.preventDefault();if(s&&"KeyD"===t.code)return this.duplicateSelection(),void t.preventDefault();if(s&&"KeyC"===t.code)return this._copy(),void t.preventDefault();if(s&&"KeyV"===t.code)return this._paste(),void t.preventDefault();if(s&&"KeyG"===t.code)return this.groupSelection(),void t.preventDefault();if(s&&"BracketRight"===t.code)return this.bringToFront(),void t.preventDefault();if(s&&"BracketLeft"===t.code)return this.sendToBack(),void t.preventDefault();if(s&&"KeyK"===t.code)return this.openCommandPalette(),void t.preventDefault();if(s&&"KeyF"===t.code&&this.options.search)return this.openSearch(),void t.preventDefault();if(s&&"KeyT"===t.code)return this.toggleTheme(),void t.preventDefault();if(s&&"KeyM"===t.code)return this.setMinimap(!this.options.minimap),void t.preventDefault();if(s&&"KeyE"===t.code)return this.setAllEdgesAnimated(0===this.animatedEdges.size),void t.preventDefault();if(!s&&"Digit0"===t.code)return this.fitView(),void t.preventDefault();if(!s&&"KeyL"===t.code&&!this._editingTitle&&-1===this._editingNote)return this.runAutoLayout(),void t.preventDefault();if("F5"===t.code&&!t.shiftKey)return this.run(),void t.preventDefault();if("F5"===t.code&&t.shiftKey)return this.stop(),void t.preventDefault();if("Tab"===t.code&&!s){const e=this.w.nodeCount_();if(0===e)return;let s=this.getSelection()[0]??-1,i=t.shiftKey?s-1:s+1;return-1===s&&(i=0),i<0&&(i=e-1),i>=e&&(i=0),this.clearSelection(),this.w.setSelected(i,1),this.panTo(this.V.posX[i],this.V.posY[i]),void t.preventDefault()}if(!s&&/^Digit[1-9]$/.test(t.code)){const e=parseInt(t.code.slice(5),10);return t.altKey?this.jumpBookmark(e):this.setBookmark(e),void t.preventDefault()}if("Escape"===t.code)return"connecting"===this._mode?(this._mode="idle",this._edgeStart=null,this._edgeCursor=null,void(this.canvas.style.cursor="")):-1!==this._focusFrame?void this.exitSubflow():(this.clearSelection(),void this._hideMenu());if(t.code.startsWith("Arrow")){const e=t.shiftKey?1:10,s="ArrowLeft"===t.code?-e:"ArrowRight"===t.code?e:0,i="ArrowUp"===t.code?-e:"ArrowDown"===t.code?e:0;this.getSelection().length>0&&(this.w.moveSelectedBy(s,i),this._nudgeTimer&&clearTimeout(this._nudgeTimer),this._nudgeTimer=setTimeout(()=>{this.w.snapshot(),this._emit("change")},400),t.preventDefault())}}else this.deleteSelection()>0&&t.preventDefault()};window.addEventListener("keydown",t),this._keyHandler=t}_copy(){const t=this.getSelection();if(0===t.length)return;const e=new Set(t),s=t.map(t=>({origId:t,kind:this.kinds[this.V.kind[t]].name,x:this.V.posX[t],y:this.V.posY[t],w:this.V.sizeW[t],h:this.V.sizeH[t],title:this.titles.get(t),color:this.colors.get(t),description:this.descriptions.get(t),tags:this.tags.get(t),status:this.status.get(t),progress:this.progress.get(t)})),i=[];for(let t=0;t<this.w.edgeCount_();t++)e.has(this.V.edgeFromN[t])&&e.has(this.V.edgeToN[t])&&i.push({from:this.V.edgeFromN[t],fp:this.V.edgeFromP[t],to:this.V.edgeToN[t],tp:this.V.edgeToP[t],label:this.edgeLabels.get(t)});let o=1/0,n=1/0;for(const t of s)t.x<o&&(o=t.x),t.y<n&&(n=t.y);this._clipboard={nodes:s,edges:i,anchor:{x:o,y:n}}}_paste(){if(!this._clipboard)return;const t=this._clipboard,e=-this.cam.x,s=-this.cam.y,i=e-t.anchor.x,o=s-t.anchor.y,n=new Map;this.clearSelection();for(const e of t.nodes){const t=this.addNode({kind:e.kind,x:e.x+i,y:e.y+o,w:e.w,h:e.h,title:e.title,color:e.color,description:e.description,tags:e.tags,status:e.status,progress:e.progress});n.set(e.origId,t),this.w.setSelected(t,1)}for(const e of t.edges){const t=n.get(e.from),s=n.get(e.to);void 0!==t&&void 0!==s&&this.addEdge({from:t,fp:e.fp,to:s,tp:e.tp,label:e.label})}this._clipboard={...t,anchor:{x:t.anchor.x-24,y:t.anchor.y-24}},this.w.snapshot(),this._emit("change")}_hitFrameHeader(t,e){for(let s=this.frames.length-1;s>=0;s--){const i=this.frames[s];if(!(t<i.x||t>i.x+i.w)&&!(e<i.y||e>i.y+26))return s}return-1}_hitFrameCorner(t,e){const s=14/this.cam.zoom;for(let i=this.frames.length-1;i>=0;i--){const o=this.frames[i],n={tl:{x:o.x,y:o.y},tr:{x:o.x+o.w,y:o.y},bl:{x:o.x,y:o.y+o.h},br:{x:o.x+o.w,y:o.y+o.h}};for(const o of["br","bl","tr","tl"]){const r=n[o];if(Math.abs(t-r.x)<s&&Math.abs(e-r.y)<s)return{idx:i,corner:o}}}return null}_applyFrameResize(t,e,s,i){const o=this.frames[t];"br"===e&&(o.w+=s,o.h+=i),"bl"===e&&(o.x+=s,o.w-=s,o.h+=i),"tr"===e&&(o.w+=s,o.y+=i,o.h-=i),"tl"===e&&(o.x+=s,o.w-=s,o.y+=i,o.h-=i),o.w<120&&("bl"!==e&&"tl"!==e||(o.x-=120-o.w),o.w=120),o.h<80&&("tl"!==e&&"tr"!==e||(o.y-=80-o.h),o.h=80)}_hitNote(t,e){for(let s=this.notes.length-1;s>=0;s--){const i=this.notes[s];if(t>=i.x&&t<=i.x+i.w&&e>=i.y&&e<=i.y+i.h)return s}return-1}_hitTaskCheckbox(t,e){for(let s=this.w.nodeCount_()-1;s>=0;s--){const i=this.tasks.get(s);if(!i||!i.length)continue;const o=this.V.posX[s],n=this.V.posY[s],r=.5*this.V.sizeW[s],h=.5*this.V.sizeH[s];if(t<o-r||t>o+r||e<n-h||e>n+h)continue;const a=o-r+8;let l=n-h+32;this.descriptions.get(s)&&(l+=30);const d=14,c=10;for(let o=0;o<i.length;o++){if(t>=a&&t<=a+c&&e>=l&&e<=l+c)return{nodeId:s,taskIdx:o};if(l+=d,l>n+h-6)break}}return null}_hitHandle(t,e){const s=this.getSelection();if(1!==s.length)return null;const o=s[0],n=this.V.posX[o],r=this.V.posY[o],h=.5*this.V.sizeW[o],a=.5*this.V.sizeH[o],l=6/this.cam.zoom,d={tl:{x:n-h,y:r-a},t:{x:n,y:r-a},tr:{x:n+h,y:r-a},r:{x:n+h,y:r},br:{x:n+h,y:r+a},b:{x:n,y:r+a},bl:{x:n-h,y:r+a},l:{x:n-h,y:r}};for(const s of i){const i=d[s];if(Math.abs(t-i.x)<l&&Math.abs(e-i.y)<l)return{nodeId:o,corner:s}}return null}_applyResize(t,e,s){const i=this._resizingHandle.nodeId;let a=this.V.sizeW[i],l=this.V.sizeH[i],d=0,c=0;o.has(t)&&(a-=e,d=.5*e),n.has(t)&&(a+=e,d=.5*e),r.has(t)&&(l-=s,c=.5*s),h.has(t)&&(l+=s,c=.5*s),a<60&&(a=60,d=0),l<60&&(l=60,c=0),this.V.sizeW[i]=a,this.V.sizeH[i]=l,this.V.posX[i]+=d,this.V.posY[i]+=c}_computeAlignSnap(t,e){const s=this.w.nodeCount_(),i=[],o=[];for(let t=0;t<s;t++){if(this.V.selected[t])continue;const e=this.V.posX[t],s=this.V.posY[t],n=.5*this.V.sizeW[t],r=.5*this.V.sizeH[t];i.push(e,e-n,e+n),o.push(s,s-r,s+r)}let n=0,r=0,h=null,a=null,l=7,d=7;for(let c=0;c<s;c++){if(!this.V.selected[c])continue;const s=this.V.posX[c]+t,u=this.V.posY[c]+e;for(const t of i){const e=s-t;Math.abs(e)<l&&(l=Math.abs(e),n=-e,h=t)}for(const t of o){const e=u-t;Math.abs(e)<d&&(d=Math.abs(e),r=-e,a=t)}}return{dx:l<=6?n:0,dy:d<=6?r:0,guideX:h,guideY:a}}_hitTestEdge(t,e,s){const i=s*s,o=this.w.edgeCount_();let n=-1,r=i;for(let i=0;i<o;i++){const o=this._portWorld(this.V.edgeFromN[i],1,this.V.edgeFromP[i]),h=this._portWorld(this.V.edgeToN[i],0,this.V.edgeToP[i]),a=Math.min(o.x,h.x)-s,l=Math.max(o.x,h.x)+s,u=Math.min(o.y,h.y)-s-80,m=Math.max(o.y,h.y)+s+80;if(!(t<a||t>l||e<u||e>m))if("orthogonal"===this.options.edgeStyle){const s=this._orthoPath(o,h);for(let o=0;o<s.length-1;o++){const h=c(t,e,s[o].x,s[o].y,s[o+1].x,s[o+1].y);h<r&&(r=h,n=i)}}else{const s=h.x-o.x,a=h.y-o.y,l=Math.max(50,.5*Math.abs(s)+.4*Math.abs(a));for(let s=0;s<=16;s++){const a=d(s/16,o.x,o.y,o.x+l,o.y,h.x-l,h.y,h.x,h.y),c=a.x-t,u=a.y-e,m=c*c+u*u;m<r&&(r=m,n=i)}}}return n}_onRightClick(t,e){if(!this.options.contextMenu)return;const s=this.w.hitTestNode(e.x,e.y),i=-1===s?this._hitTestEdge(e.x,e.y,6/this.cam.zoom):-1;let o;if(-1!==s)0===this.V.selected[s]&&(this.w.clearSelection(),this.w.setSelected(s,1)),o=[{label:"Duplicate",kbd:"Ctrl+D",fn:()=>this.duplicateSelection()},{label:"Delete",kbd:"Del",danger:!0,fn:()=>this.deleteSelection()},{sep:!0},{label:"Deselect",kbd:"Esc",fn:()=>this.clearSelection()}];else if(-1!==i){const t=this.V.edgeFromN[i],e=this.V.edgeToN[i];o=[{label:"Select endpoints",fn:()=>{this.clearSelection(),this.w.setSelected(t,1),this.w.setSelected(e,1),this._emit("select",this.getSelection())}},{label:"Set label…",fn:()=>{const t=prompt("Edge label",this.edgeLabels.get(i)||"");null!==t&&this.setEdgeLabel(i,t)}},{sep:!0},{label:"Delete edge",danger:!0,fn:()=>{this.w.deleteEdge(i),this.edgeLabels.delete(i),this.w.snapshot(),this._emit("change")}}]}else o=[{label:"Add Process node here",fn:()=>this.addNode({kind:"process",x:e.x,y:e.y})},{sep:!0},{label:"Select all",kbd:"Ctrl+A",fn:()=>this.selectAll()},{label:"Auto-layout",fn:()=>this.runAutoLayout()},{label:"Fit view",fn:()=>this.fitView()}];this._showMenu(t.clientX,t.clientY,o)}_startEditingTitle(t){if(this._editingTitle=t,!this._editingTitleEl){const t=document.createElement("input");t.type="text",Object.assign(t.style,{position:"absolute",background:"#161b27",color:"#e6edf3",border:"1px solid #f0b93a",borderRadius:"4px",fontFamily:"Inter, ui-sans-serif",fontSize:"12px",fontWeight:"600",padding:"4px 8px",outline:"none",zIndex:"300",boxShadow:"0 4px 12px rgba(0,0,0,0.35)"}),this.container.appendChild(t),t.addEventListener("blur",()=>this._stopEditingTitle()),t.addEventListener("keydown",e=>{"Enter"!==e.code&&"Escape"!==e.code||t.blur()}),this._editingTitleEl=t}this._positionTitleEditor(),this._editingTitleEl.value=this.titles.get(t)||"",this._editingTitleEl.placeholder=`${this.kinds[this.V.kind[t]].name} #${t}`,this._editingTitleEl.style.display="block",setTimeout(()=>{this._editingTitleEl.focus(),this._editingTitleEl.select()},20)}_positionTitleEditor(){if(-1===this._editingTitle||!this._editingTitleEl)return;const t=this._editingTitle,e=this.V.posX[t],s=this.V.posY[t],i=.5*this.V.sizeW[t],o=.5*this.V.sizeH[t],n=this._w2s(e-i,s-o),r=window.devicePixelRatio||1;this._editingTitleEl.style.left=n.x/r+"px",this._editingTitleEl.style.top=n.y/r-32+"px",this._editingTitleEl.style.width=Math.max(120,this.V.sizeW[t]*this.cam.zoom/r)+"px"}_stopEditingTitle(){if(-1===this._editingTitle)return;const t=this._editingTitleEl.value.trim();t?this.titles.set(this._editingTitle,t):this.titles.delete(this._editingTitle),this._editingTitleEl.style.display="none",this._editingTitle=-1,this._emit("change")}_startEditingNote(t){if(this._editingNote=t,!this._editingNoteEl){const t=document.createElement("textarea");t.spellcheck=!1,Object.assign(t.style,{position:"absolute",resize:"none",outline:"none",border:"1px solid #f0b93a",borderRadius:"4px",padding:"8px 10px",fontFamily:"Inter, ui-sans-serif",fontSize:"12px",lineHeight:"16px",zIndex:"300"}),this.container.appendChild(t),t.addEventListener("blur",()=>this._stopEditingNote()),t.addEventListener("keydown",e=>{"Escape"===e.code&&t.blur()}),this._editingNoteEl=t}this._positionNoteEditor();const e=this.notes[t];this._editingNoteEl.style.background=e.color.fill,this._editingNoteEl.style.color=e.color.text,this._editingNoteEl.value=e.text,this._editingNoteEl.style.display="block",setTimeout(()=>this._editingNoteEl.focus(),20)}_positionNoteEditor(){if(-1===this._editingNote||!this._editingNoteEl)return;const t=this.notes[this._editingNote],e=this._w2s(t.x,t.y),s=window.devicePixelRatio||1;this._editingNoteEl.style.left=e.x/s+"px",this._editingNoteEl.style.top=e.y/s+"px",this._editingNoteEl.style.width=t.w*this.cam.zoom/s+"px",this._editingNoteEl.style.height=t.h*this.cam.zoom/s+"px"}_stopEditingNote(){-1!==this._editingNote&&(this.notes[this._editingNote].text=this._editingNoteEl.value,this._editingNoteEl.style.display="none",this._editingNote=-1,this._emit("change"))}_showMenu(t,e,s){this._hideMenu();const i=document.createElement("div");i.style.cssText="position:fixed;min-width:200px;padding:4px;background:#161b27;border:1px solid rgba(255,255,255,0.16);border-radius:8px;box-shadow:0 12px 32px rgba(0,0,0,0.45);z-index:99999;color:#e6edf3;font:13px/1.45 ui-sans-serif, system-ui, sans-serif;";for(const t of s){if(t.sep){const t=document.createElement("div");t.style.cssText="height:1px;background:rgba(255,255,255,0.08);margin:4px;",i.appendChild(t);continue}const e=document.createElement("div");e.style.cssText="padding:6px 10px;border-radius:6px;cursor:pointer;display:flex;justify-content:space-between;gap:12px;"+(t.danger?"color:#ffb4a4;":""),e.innerHTML=`<span>${b(t.label)}</span>${t.kbd?`<span style="color:#5a6577;font-family:ui-monospace,Consolas,monospace;font-size:11px;">${b(t.kbd)}</span>`:""}`,e.onmouseenter=()=>e.style.background=t.danger?"rgba(232,70,43,0.18)":"rgba(255,255,255,0.04)",e.onmouseleave=()=>e.style.background="",e.onclick=()=>{t.fn(),this._hideMenu()},i.appendChild(e)}i.style.left=Math.min(t,window.innerWidth-220)+"px",i.style.top=Math.min(e,window.innerHeight-280)+"px",document.body.appendChild(i),this._menuEl=i,setTimeout(()=>{const t=e=>{i.contains(e.target)||(this._hideMenu(),document.removeEventListener("mousedown",t,!0))};document.addEventListener("mousedown",t,!0)},0)}_hideMenu(){this._menuEl&&(this._menuEl.remove(),this._menuEl=null)}_loop(){this._render(),this._raf=requestAnimationFrame(()=>this._loop())}_render(){if("pan"!==this._mode){this._panVel.x*this._panVel.x+this._panVel.y*this._panVel.y<16?(this._panVel.x=0,this._panVel.y=0):(this.cam.x+=this._panVel.x*(1/60),this.cam.y+=this._panVel.y*(1/60),this._panVel.x*=.91,this._panVel.y*=.91)}const t=this.ctx;this._hooks?.beforeRender?.length&&this._runHook("beforeRender",t),this._gl?(t.clearRect(0,0,this.canvas.width,this.canvas.height),this._gl.render()):(t.fillStyle=this.options.background,t.fillRect(0,0,this.canvas.width,this.canvas.height)),this._drawGrid(),this._drawFrames(),this._drawNotes(),this._refreshFocus(),this._refreshPreview(),this._positionTitleEditor(),this._positionNoteEditor(),this._drawDying(),this._drawWaypoints(),this._drawRemoteCursors(),this._drawValueBubbles(),this.options.minimap&&this._drawMinimap();const e=this.w.nodeCount_(),s=this.w.edgeCount_();this._edgePhase=(this._edgePhase+(this.options.edgeFlowSpeed||60)*(1/60))%1e3;for(let e=0;e<s;e++){const s=this.V.edgeFromN[e],i=this.V.edgeToN[e],o=this._portWorld(s,1,this.V.edgeFromP[e]),n=this._portWorld(i,0,this.V.edgeToP[e]);let r=!1;!this._focusedSet||this._focusedSet.has(s)&&this._focusedSet.has(i)||(r=!0),-1!==this._hoveredEdge&&this._hoveredEdge!==e&&(r=!0),-1===this._focusFrame||this._isInsideFocusFrame(s)&&this._isInsideFocusFrame(i)||(r=!0),r&&(t.globalAlpha=.18),this._currentEdgeIdx=e,this._drawEdge(o,n,this.colors.get(s)||this.kinds[this.V.kind[s]].color,this.colors.get(i)||this.kinds[this.V.kind[i]].color,0!==this.V.edgeSel[e],!1,this.edgeLabels.get(e)),t.globalAlpha=1}if(this._currentEdgeIdx=void 0,this._flashReject&&performance.now()-this._flashReject.t0>=1400&&(this._flashReject=null),this._flashReject&&performance.now()-this._flashReject.t0<1400){const t=this._flashReject,e=this._w2s(t.x,t.y),s=this.ctx,i=1-(performance.now()-t.t0)/1400;s.save(),s.globalAlpha=i,s.fillStyle="#e8462b",s.font="600 12px Inter, ui-sans-serif";const o=s.measureText(t.msg).width,n=e.x-o/2-8,r=e.y-36,h=o+16,a=22;s.fillStyle="#1a0e0e",this._roundRect(n,r,h,a,4),s.fill(),s.strokeStyle="#e8462b",s.lineWidth=1.4,this._roundRect(n,r,h,a,4),s.stroke(),s.fillStyle="#e8462b",s.textAlign="center",s.textBaseline="middle",s.fillText(t.msg,e.x,r+a/2),s.restore()}if("connecting"===this._mode&&this._edgeStart&&this._edgeCursor){const t=this._portWorld(this._edgeStart.nodeId,1,this._edgeStart.idx);this._drawEdge(t,this._edgeCursor,"#8b95a7","#8b95a7",!1,!0)}const i=this.canvas.width/(2*this.cam.zoom),o=this.canvas.height/(2*this.cam.zoom),n=-this.cam.x-i-80,r=-this.cam.x+i+80,h=-this.cam.y-o-80,a=-this.cam.y+o+80;let l;if(e>300){const t=this.w.queryRect(n,h,r,a);l=Array.from(this.V.queryRes.subarray(0,t))}else{l=[];for(let t=0;t<e;t++)l.push(t)}l.sort((t,e)=>{const s=this.zOrder.get(t)||0,i=this.zOrder.get(e)||0;return s===i?t-e:s-i});for(const e of l){const s=.5*this.V.sizeW[e],i=.5*this.V.sizeH[e];if(this.V.posX[e]+s<n||this.V.posX[e]-s>r)continue;if(this.V.posY[e]+i<h||this.V.posY[e]-i>a)continue;if(this.kinds[this.V.kind[e]].html)continue;if(this._nodeHiddenByCollapse(e))continue;let o=!1;if(this._focusedSet&&!this._focusedSet.has(e)&&(o=!0),this._reachableSet&&!this._reachableSet.has(e)&&(o=!0),-1!==this._hoveredEdge){const t=this.V.edgeFromN[this._hoveredEdge],s=this.V.edgeToN[this._hoveredEdge];e!==t&&e!==s&&(o=!0)}-1===this._focusFrame||this._isInsideFocusFrame(e)||(o=!0),o&&(t.globalAlpha=.22);const l=this._openPopAnim(e);this._gl?this._drawNodeOverlay(e):this._drawNode(e),l&&t.restore(),o&&(t.globalAlpha=1)}this._syncHTMLOverlays(),this._drawMultiSelectBBox(),this._drawMarquee(),this._drawLasso(),this._drawAlignGuides(),this._drawResizeHandles(),this._drawFrameHandles()}_openPopAnim(t){const e=this._nodeAddedAt.get(t);if(void 0===e)return!1;const s=(performance.now()-e)/280;if(s>=1)return this._nodeAddedAt.delete(t),!1;const i=1-Math.pow(1-s,3),o=this._w2s(this.V.posX[t],this.V.posY[t]);return this.ctx.save(),this.ctx.globalAlpha=i,this.ctx.translate(o.x,o.y),this.ctx.scale(.85+.15*i,.85+.15*i),this.ctx.translate(-o.x,-o.y),!0}_drawDying(){const t=performance.now();for(let e=this._dyingEdges.length-1;e>=0;e--){const s=this._dyingEdges[e],i=(t-s.t0)/220;i>=1?this._dyingEdges.splice(e,1):(this.ctx.save(),this.ctx.globalAlpha=.7*(1-i),this._drawEdge(s.ap,s.bp,s.colA,s.colB,!1,!0),this.ctx.restore())}for(let e=this._dyingNodes.length-1;e>=0;e--){const s=this._dyingNodes[e],i=(t-s.t0)/220;if(i>=1){this._dyingNodes.splice(e,1);continue}const o=1-Math.pow(1-i,3),n=1-o,r=1-.18*o,h=.5*s.w*r,a=.5*s.h*r,l=this._w2s(s.x-h,s.y-a),d=s.w*r*this.cam.zoom,c=s.h*r*this.cam.zoom;this.ctx.save(),this.ctx.globalAlpha=n,this.ctx.fillStyle="#161b27",this._shapePath(s.shape,l.x,l.y,d,c),this.ctx.fill(),this.ctx.strokeStyle=u(s.color,.6),this.ctx.lineWidth=1.4*this.cam.zoom,this._shapePath(s.shape,l.x,l.y,d,c),this.ctx.stroke(),this.ctx.restore()}}_drawMultiSelectBBox(){if("idle"!==this._mode)return;const t=this.getSelection();if(t.length<2)return;let e=1/0,s=-1/0,i=1/0,o=-1/0;for(const n of t){const t=.5*this.V.sizeW[n],r=.5*this.V.sizeH[n];this.V.posX[n]-t<e&&(e=this.V.posX[n]-t),this.V.posX[n]+t>s&&(s=this.V.posX[n]+t),this.V.posY[n]-r<i&&(i=this.V.posY[n]-r),this.V.posY[n]+r>o&&(o=this.V.posY[n]+r)}const n=this._w2s(e-10,i-10),r=this._w2s(s+10,o+10);this.ctx.strokeStyle="rgba(240,185,58,0.55)",this.ctx.lineWidth=1.2,this.ctx.setLineDash([5,4]),this.ctx.strokeRect(n.x,n.y,r.x-n.x,r.y-n.y),this.ctx.setLineDash([])}_drawLasso(){if(!this._lasso||this._lasso.length<2)return;this.ctx.strokeStyle="rgba(192,98,232,0.85)",this.ctx.fillStyle="rgba(192,98,232,0.10)",this.ctx.lineWidth=1.4,this.ctx.setLineDash([4,4]),this.ctx.beginPath();const t=this._w2s(this._lasso[0].x,this._lasso[0].y);this.ctx.moveTo(t.x,t.y);for(let t=1;t<this._lasso.length;t++){const e=this._w2s(this._lasso[t].x,this._lasso[t].y);this.ctx.lineTo(e.x,e.y)}this.ctx.closePath(),this.ctx.fill(),this.ctx.stroke(),this.ctx.setLineDash([])}_drawFrames(){for(let t=0;t<this.frames.length;t++){const e=this.frames[t],s=this.frameCollapsed.has(t),i=this._w2s(e.x,e.y),o=e.w*this.cam.zoom,n=(s?26:e.h)*this.cam.zoom;this.ctx.fillStyle=u(e.color,.05),this._roundRect(i.x,i.y,o,n,12*this.cam.zoom),this.ctx.fill(),this.ctx.strokeStyle=u(e.color,.45),this.ctx.lineWidth=1.4*this.cam.zoom,this.ctx.setLineDash([8*this.cam.zoom,4*this.cam.zoom]),this._roundRect(i.x,i.y,o,n,12*this.cam.zoom),this.ctx.stroke(),this.ctx.setLineDash([]);const r=26*this.cam.zoom;if(this.ctx.save(),this._roundRect(i.x,i.y,o,n,12*this.cam.zoom),this.ctx.clip(),this.ctx.fillStyle=u(e.color,.16),this.ctx.fillRect(i.x,i.y,o,r),this.ctx.restore(),this.cam.zoom>.4){this.ctx.fillStyle=e.color,this.ctx.font=`600 ${12*this.cam.zoom}px Inter, ui-sans-serif`,this.ctx.textBaseline="middle",this.ctx.textAlign="left";const t=s?"▸":"▾";this.ctx.fillText(`${t} ${e.label}`,i.x+10*this.cam.zoom,i.y+.5*r)}}}_drawFrameHandles(){for(const t of this.frames){const e=this._w2s(t.x,t.y),s=this._w2s(t.x+t.w,t.y+t.h),i=6*this.cam.zoom;this.ctx.fillStyle=t.color;for(const[t,o]of[[e.x,e.y],[s.x,e.y],[e.x,s.y],[s.x,s.y]])this.ctx.fillRect(t-i/2,o-i/2,i,i)}}_drawNotes(){for(const t of this.notes){const e=this._w2s(t.x,t.y),s=t.w*this.cam.zoom,i=t.h*this.cam.zoom;if(this.ctx.save(),this.ctx.shadowColor="rgba(0,0,0,0.4)",this.ctx.shadowBlur=12*this.cam.zoom,this.ctx.shadowOffsetY=4*this.cam.zoom,this.ctx.fillStyle=t.color.fill,this._roundRect(e.x,e.y,s,i,4*this.cam.zoom),this.ctx.fill(),this.ctx.restore(),this.ctx.strokeStyle=t.color.border,this.ctx.lineWidth=1*this.cam.zoom,this._roundRect(e.x,e.y,s,i,4*this.cam.zoom),this.ctx.stroke(),this.cam.zoom>.4&&t.text){this.ctx.fillStyle=t.color.text,this.ctx.font=`500 ${12*this.cam.zoom}px Inter, ui-sans-serif`,this.ctx.textBaseline="top",this.ctx.textAlign="left";const o=16*this.cam.zoom,n=10*this.cam.zoom,r=8*this.cam.zoom,h=s-2*n;let a=e.y+r;for(const s of t.text.split("\n")){const t=s.split(/\s+/);let r="";for(const s of t){const t=r?r+" "+s:s;if(this.ctx.measureText(t).width>h&&r){if(this.ctx.fillText(r,e.x+n,a),a+=o,r=s,a>e.y+i-o)break}else r=t}r&&a<e.y+i-.5*o&&(this.ctx.fillText(r,e.x+n,a),a+=o)}}}}_refreshFocus(){if(!this._pathHighlightEnabled)return void(this._focusedSet=null);if("idle"!==this._mode||this._hoveredNode<0)return this._focusedSet=null,void(this._lastFocusComputed=-2);if(performance.now()-this._hoveredNodeSince<200)return;if(this._hoveredNode===this._lastFocusComputed)return;const t=new Set([this._hoveredNode]),e=[this._hoveredNode],s=this.w.edgeCount_();for(;e.length;){const i=e.shift();for(let o=0;o<s;o++)this.V.edgeFromN[o]!==i||t.has(this.V.edgeToN[o])||(t.add(this.V.edgeToN[o]),e.push(this.V.edgeToN[o])),this.V.edgeToN[o]!==i||t.has(this.V.edgeFromN[o])||(t.add(this.V.edgeFromN[o]),e.push(this.V.edgeFromN[o]))}this._focusedSet=t,this._lastFocusComputed=this._hoveredNode}_refreshPreview(){this.options.hoverPreview?"idle"!==this._mode||this._hoveredNode<0?this._hidePreview():performance.now()-this._hoveredNodeSince<600||(this._previewedNode!==this._hoveredNode?(this._showPreview(this._hoveredNode),this._previewedNode=this._hoveredNode):this._positionPreview(this._hoveredNode)):this._hidePreview()}_showPreview(t){if(!this._previewEl){const t=document.createElement("div");t.style.cssText="position:absolute;width:260px;padding:12px 14px;background:#161b27;border:1px solid rgba(255,255,255,0.16);border-radius:8px;box-shadow:0 12px 32px rgba(0,0,0,0.45);color:#e6edf3;font:13px/1.45 ui-sans-serif, system-ui, sans-serif;pointer-events:none;opacity:0;transition:opacity 140ms;z-index:200;",this.container.appendChild(t),this._previewEl=t}const e=this.kinds[this.V.kind[t]],s=this.titles.get(t)||e.name,i=this.descriptions.get(t),o=this.tags.get(t)||[],n=this.status.get(t),r=this.progress.get(t),h=[`<div style="display:flex;align-items:center;gap:8px;padding-bottom:8px;margin-bottom:8px;border-bottom:1px solid rgba(255,255,255,0.08);">\n <span style="width:24px;height:24px;border-radius:5px;background:${u(e.color,.18)};color:${e.color};display:grid;place-items:center;font:700 12px Inter">${this.icon.get(t)||e.badge}</span>\n <div><div style="font-weight:600">${b(s)}</div><div style="color:#8b95a7;font-family:ui-monospace,Consolas,monospace;font-size:11px;">#${t} · ${e.name}</div></div>\n </div>`];if(i&&h.push(`<div style="font-size:12px;color:#8b95a7;margin-bottom:8px;">${b(i)}</div>`),n||void 0!==r){const t=[];n&&t.push(`<span style="padding:2px 7px;border-radius:10px;background:rgba(255,255,255,0.06);">${n}</span>`),void 0!==r&&t.push(`<span style="padding:2px 7px;border-radius:10px;background:rgba(255,255,255,0.06);">${Math.round(100*r)}%</span>`),h.push(`<div style="display:flex;gap:6px;margin-bottom:8px;font-size:11px;">${t.join("")}</div>`)}o.length&&h.push(`<div style="display:flex;flex-wrap:wrap;gap:4px;">${o.map(t=>`<span style="font-size:10.5px;padding:2px 7px;border-radius:3px;background:${u(e.color,.18)};color:${e.color};">${b(t)}</span>`).join("")}</div>`),this._previewEl.innerHTML=h.join(""),this._positionPreview(t),this._previewEl.style.opacity="1"}_positionPreview(t){if(!this._previewEl)return;const e=this.V.posX[t],s=this.V.posY[t],i=.5*this.V.sizeW[t],o=.5*this.V.sizeH[t],n=this._w2s(e+i,s-o),r=this._w2s(e-i,s-o),h=this.container.getBoundingClientRect(),a=window.devicePixelRatio||1;let l=n.x/a+12,d=n.y/a;l+280>h.width&&(l=r.x/a-280-12),l<8&&(l=8),this._previewEl.style.left=l+"px",this._previewEl.style.top=Math.max(8,d)+"px"}_hidePreview(){this._previewEl&&(this._previewEl.style.opacity="0"),this._previewedNode=-1}_syncHTMLOverlays(){const t=new Set,e=this.w.nodeCount_();for(let s=0;s<e;s++){const e=this.kinds[this.V.kind[s]];if(!e.html)continue;t.add(s);let i=this._htmlOverlays.get(s);i||(i=document.createElement("div"),i.className="zflow-html-node",i.style.cssText="position:absolute;border:1px solid rgba(255,255,255,0.16);border-radius:8px;background:#161b27;color:#e6edf3;overflow:hidden;font-family:Inter, ui-sans-serif;font-size:12px;transform-origin:top left;",i.innerHTML=e.template||`<div style="padding:8px;">${b(e.name)} #${s}</div>`,this.container.appendChild(i),this._htmlOverlays.set(s,i));const o=this.V.posX[s],n=this.V.posY[s],r=.5*this.V.sizeW[s],h=.5*this.V.sizeH[s],a=this._w2s(o-r,n-h),l=window.devicePixelRatio||1;i.style.left=a.x/l+"px",i.style.top=a.y/l+"px",i.style.width=this.V.sizeW[s]*this.cam.zoom/l+"px",i.style.height=this.V.sizeH[s]*this.cam.zoom/l+"px"}for(const[e,s]of this._htmlOverlays)t.has(e)||(s.remove(),this._htmlOverlays.delete(e))}_drawGrid(){const t=this.ctx,e=40*this.cam.zoom;if(e<6)return;const s=this.canvas.width/2+this.cam.x*this.cam.zoom,i=this.canvas.height/2+this.cam.y*this.cam.zoom,o=s-Math.ceil(s/e)*e,n=i-Math.ceil(i/e)*e;t.fillStyle=this.options.snapToGrid?"rgba(240,185,58,0.10)":"rgba(255,255,255,0.045)";const r=window.devicePixelRatio||1;for(let s=o;s<this.canvas.width;s+=e)for(let i=n;i<this.canvas.height;i+=e)t.fillRect(s,i,1.4*r,1.4*r)}_drawMarquee(){if(!this._marquee)return;const t=this._w2s(this._marquee.x0,this._marquee.y0),e=this._w2s(this._marquee.x1,this._marquee.y1),s=Math.min(t.x,e.x),i=Math.min(t.y,e.y),o=Math.abs(e.x-t.x),n=Math.abs(e.y-t.y),r=this.ctx;r.fillStyle="rgba(240,185,58,0.10)",r.fillRect(s,i,o,n),r.strokeStyle="rgba(240,185,58,0.7)",r.setLineDash([4,4]),r.lineWidth=1.2,r.strokeRect(s,i,o,n),r.setLineDash([])}_drawAlignGuides(){if(!this._alignGuides)return;const t=this.ctx;t.strokeStyle="rgba(192,98,232,0.85)",t.lineWidth=1.2,t.setLineDash([2,4]);for(const e of this._alignGuides.v){const s=this._w2s(e,0).x;t.beginPath(),t.moveTo(s,0),t.lineTo(s,this.canvas.height),t.stroke()}for(const e of this._alignGuides.h){const s=this._w2s(0,e).y;t.beginPath(),t.moveTo(0,s),t.lineTo(this.canvas.width,s),t.stroke()}t.setLineDash([])}_drawResizeHandles(){if("idle"!==this._mode)return;const t=this.getSelection();if(1!==t.length)return;const e=t[0],s=this.V.posX[e],o=this.V.posY[e],n=.5*this.V.sizeW[e],r=.5*this.V.sizeH[e],h={tl:{x:s-n,y:o-r},t:{x:s,y:o-r},tr:{x:s+n,y:o-r},r:{x:s+n,y:o},br:{x:s+n,y:o+r},b:{x:s,y:o+r},bl:{x:s-n,y:o+r},l:{x:s-n,y:o}},a=this.ctx,l=4*this.cam.zoom;a.fillStyle="#f0b93a",a.strokeStyle="#07090f",a.lineWidth=1*this.cam.zoom;for(const t of i){const e=this._w2s(h[t].x,h[t].y);a.beginPath(),a.rect(e.x-l,e.y-l,2*l,2*l),a.fill(),a.stroke()}}_portWorld(t,e,s){const i=this.V.posX[t],o=this.V.posY[t],n=.5*this.V.sizeW[t],r=.5*this.V.sizeH[t],h=(s+1)/((0===e?this.V.nIn[t]:this.V.nOut[t])+1);return{x:0===e?i-n:i+n,y:o-r+this.V.sizeH[t]*h}}_orthoPath(t,e){if(e.x-t.x>60){const s=(t.x+e.x)/2;return[t,{x:s,y:t.y},{x:s,y:e.y},e]}const s=(t.y+e.y)/2;return[t,{x:t.x+30,y:t.y},{x:t.x+30,y:s},{x:e.x-30,y:s},{x:e.x-30,y:e.y},e]}_drawEdge(t,e,s,i,o,n,r){const h=this._w2s(t.x,t.y),a=this._w2s(e.x,e.y),l=this.ctx,c=l.createLinearGradient(h.x,h.y,a.x,a.y);c.addColorStop(0,s),c.addColorStop(1,i);const m=void 0!==this._currentEdgeIdx&&this._activeEdges.has(this._currentEdgeIdx)&&this._activeEdges.get(this._currentEdgeIdx)>performance.now();let p;if(l.strokeStyle=o?"#f0b93a":m?"#5b8def":n?"#8b95a7":c,l.lineWidth=(o?2.4:m?3:1.6)*this.cam.zoom,m&&(l.shadowColor="#5b8def",l.shadowBlur=10*this.cam.zoom),l.lineJoin="round","orthogonal"===this.options.edgeStyle){const t=this._orthoPath(h,a);l.beginPath(),l.moveTo(t[0].x,t[0].y);for(let e=1;e<t.length;e++)l.lineTo(t[e].x,t[e].y);l.stroke(),p=t[Math.floor(t.length/2)]}else{const t=a.x-h.x,e=a.y-h.y,s=Math.max(50,.5*Math.abs(t)+.4*Math.abs(e));l.beginPath(),l.moveTo(h.x,h.y),l.bezierCurveTo(h.x+s,h.y,a.x-s,a.y,a.x,a.y),l.stroke(),p=d(.5,h.x,h.y,h.x+s,h.y,a.x-s,a.y,a.x,a.y)}if(!n&&void 0!==this._currentEdgeIdx&&this.animatedEdges.has(this._currentEdgeIdx)){const t=4;for(let e=0;e<t;e++){const s=(this._edgePhase/1e3+e/t)%1;let o;if("orthogonal"===this.options.edgeStyle){const t=a.x-h.x,e=a.y-h.y,i=Math.max(50,.5*Math.abs(t)+.4*Math.abs(e));o=d(s,h.x,h.y,h.x+i,h.y,a.x-i,a.y,a.x,a.y)}else{const t=a.x-h.x,e=a.y-h.y,i=Math.max(50,.5*Math.abs(t)+.4*Math.abs(e));o=d(s,h.x,h.y,h.x+i,h.y,a.x-i,a.y,a.x,a.y)}l.fillStyle=i,l.beginPath(),l.arc(o.x,o.y,3.2*this.cam.zoom,0,2*Math.PI),l.fill()}}if(!n&&r&&this.cam.zoom>.45){l.font=`600 ${10.5*this.cam.zoom}px ui-monospace, Consolas, monospace`;const t=l.measureText(r).width+2*(5*this.cam.zoom),e=16*this.cam.zoom;l.fillStyle="#0b0f17",this._roundRect(p.x-t/2,p.y-e/2,t,e,5*this.cam.zoom),l.fill(),l.strokeStyle=o?"#f0b93a":u(s,.6),l.lineWidth=1*this.cam.zoom,l.stroke(),l.fillStyle="#e6edf3",l.textAlign="center",l.textBaseline="middle",l.fillText(r,p.x,p.y)}}_drawNodeOverlay(t){const e=this.cam.zoom;if(e<.25)return;if(this.w.nodeCount_()>5e3&&e<.55)return;const s=this.V.posX[t],i=this.V.posY[t],o=.5*this.V.sizeW[t],n=.5*this.V.sizeH[t],r=this._w2s(s-o,i-n),h=this.V.sizeW[t]*e,a=this.V.sizeH[t]*e,l=this.kinds[this.V.kind[t]],d=this.colors.get(t)||l.color,c=this.ctx;if(e>.4){const s=this.titles.get(t)||l.name;c.font=`600 ${12*e}px Inter, ui-sans-serif`,c.fillStyle="#0b0f17",c.textAlign="center",c.textBaseline="middle",c.fillText(s,r.x+h/2,r.y+11*e)}if(e>.35)for(let s=0;s<2;s++){const i=0===s?this.V.nIn[t]:this.V.nOut[t];for(let o=0;o<i;o++){const i=this._portWorld(t,s,o),n=this._w2s(i.x,i.y);c.fillStyle=d,c.strokeStyle="#07090f",c.lineWidth=1.5*e,c.beginPath(),c.arc(n.x,n.y,4.5*e,0,2*Math.PI),c.fill(),c.stroke()}}this.breakpoints.has(t)&&(c.fillStyle="#e8462b",c.beginPath(),c.arc(r.x-4*e,r.y+a/2,4.5*e,0,2*Math.PI),c.fill())}_drawNode(t){const e=this.V.posX[t],s=this.V.posY[t],i=.5*this.V.sizeW[t],o=.5*this.V.sizeH[t],n=this._w2s(e-i,s-o),r=this.V.sizeW[t]*this.cam.zoom,h=this.V.sizeH[t]*this.cam.zoom,a=this.kinds[this.V.kind[t]],l=this.colors.get(t)||a.color,d=0!==this.V.selected[t],c=this._hoveredNode===t&&"idle"===this._mode,p=this.ctx;if(p.save(),p.shadowColor="rgba(0,0,0,0.45)",p.shadowBlur=(c?14:10)*this.cam.zoom,p.shadowOffsetY=4*this.cam.zoom,p.fillStyle="#161b27",this._shapePath(a.shape,n.x,n.y,r,h),p.fill(),p.restore(),"rect"===a.shape&&(p.save(),this._shapePath(a.shape,n.x,n.y,r,h),p.clip(),p.fillStyle=l,p.fillRect(n.x,n.y,r,22*this.cam.zoom),p.restore()),"running"===this.status.get(t)){const t=.5+.5*Math.sin(performance.now()/180);p.save(),p.shadowColor="#5b8def",p.shadowBlur=(18+14*t)*this.cam.zoom,p.strokeStyle=`rgba(91,141,239,${.6+.4*t})`,p.lineWidth=(2.2+t)*this.cam.zoom,this._shapePath(a.shape,n.x-2,n.y-2,r+4,h+4),p.stroke(),p.restore()}if(d?(p.save(),p.shadowColor="rgba(240,185,58,0.55)",p.shadowBlur=14*this.cam.zoom,p.strokeStyle="#f0b93a",p.lineWidth=1.6*this.cam.zoom,this._shapePath(a.shape,n.x,n.y,r,h),p.stroke(),p.restore()):(p.strokeStyle=c?u(l,.55):"rgba(255,255,255,0.08)",p.lineWidth=(c?1.3:1)*this.cam.zoom,this._shapePath(a.shape,n.x,n.y,r,h),p.stroke()),this.cam.zoom>.42){const e=this.titles.get(t)||`${a.name} #${t}`;p.textBaseline="middle",p.font=`600 ${11*this.cam.zoom}px Inter, ui-sans-serif`,"rect"===a.shape?(p.fillStyle="#0b0f17",p.textAlign="left",p.fillText(e,n.x+10*this.cam.zoom,n.y+11*this.cam.zoom)):(p.fillStyle=l,p.textAlign="center",p.fillText(e,n.x+r/2,n.y+h/2))}const g=this.progress.get(t);if(void 0!==g&&g>0){const t=3*this.cam.zoom,e=n.y+h-t-2*this.cam.zoom,s=n.x+8*this.cam.zoom,i=r-16*this.cam.zoom;p.fillStyle="rgba(255,255,255,0.06)",p.fillRect(s,e,i,t),p.fillStyle=l,p.fillRect(s,e,i*Math.min(1,Math.max(0,g)),t)}const f=this.tags.get(t);if(f&&f.length&&this.cam.zoom>.5){let t=n.x+8*this.cam.zoom;const e=n.y+h-24*this.cam.zoom;p.font=`500 ${9*this.cam.zoom}px Inter, ui-sans-serif`,p.textBaseline="middle";for(const s of f){const i=p.measureText(s).width+10*this.cam.zoom;if(t+i>n.x+r-8*this.cam.zoom)break;p.fillStyle=u(l,.18),this._roundRect(t,e,i,14*this.cam.zoom,3*this.cam.zoom),p.fill(),p.fillStyle=l,p.textAlign="left",p.fillText(s,t+5*this.cam.zoom,e+7*this.cam.zoom),t+=i+4*this.cam.zoom}}const _=this.metrics.get(t);if(_&&_.count>1&&"rect"===a.shape&&this.cam.zoom>.45){const e=this.metricMax.get(t)||1,s=n.x+8*this.cam.zoom,i=n.y+h-22*this.cam.zoom,o=r-16*this.cam.zoom,a=16*this.cam.zoom;p.strokeStyle=u(l,.85),p.lineWidth=1.5*this.cam.zoom,p.beginPath();for(let t=0;t<_.count;t++){const n=_.data[(_.idx+this._metricCap-_.count+t)%this._metricCap],r=s+t/Math.max(1,_.count-1)*o,h=i+a-Math.min(Math.max(n/e,0),1)*a;0===t?p.moveTo(r,h):p.lineTo(r,h)}p.stroke()}if(this.breakpoints.has(t)){const t=n.x-4*this.cam.zoom,e=n.y+h/2;p.save(),p.shadowColor="#e8462b",p.shadowBlur=8*this.cam.zoom,p.fillStyle="#e8462b",p.beginPath(),p.arc(t,e,4.5*this.cam.zoom,0,2*Math.PI),p.fill(),p.restore()}const y=this.status.get(t);if(y&&"rect"===a.shape){const t=m[y]||"#8b95a7",e=n.x+r-12*this.cam.zoom,s=n.y+11*this.cam.zoom;p.save(),p.shadowColor=t,p.shadowBlur=6*this.cam.zoom,p.fillStyle=t,p.beginPath(),p.arc(e,s,3.5*this.cam.zoom,0,2*Math.PI),p.fill(),p.restore()}if(this.locked.has(t)){const t=n.x+6*this.cam.zoom,e=n.y+6*this.cam.zoom,s=10*this.cam.zoom;p.fillStyle="rgba(0,0,0,0.55)",this._roundRect(t,e,s,s,2*this.cam.zoom),p.fill(),p.strokeStyle="#f0b93a",p.lineWidth=1.2*this.cam.zoom,p.strokeRect(t+2.5*this.cam.zoom,e+5*this.cam.zoom,s-5*this.cam.zoom,s-6*this.cam.zoom),p.beginPath(),p.arc(t+.5*s,e+5*this.cam.zoom,2*this.cam.zoom,Math.PI,0),p.stroke()}const x=this.image.get(t);if(x&&"rect"===a.shape&&this.cam.zoom>.5){const t=this._getImage(x);if(t&&t.ready){const e=n.x+8*this.cam.zoom,s=n.y+28*this.cam.zoom,i=r-16*this.cam.zoom,o=Math.min(54*this.cam.zoom,.45*h);p.save(),this._roundRect(e,s,i,o,4*this.cam.zoom),p.clip(),p.drawImage(t.img,e,s,i,o),p.restore()}}const b=this.descriptions.get(t);if(b&&"rect"===a.shape&&this.cam.zoom>.5&&!x){const t=!1!==this.options.inlineMarkdown?function(t){if(!t)return[{t:"",style:"p"}];const e=[],s=/(\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`|\[[^\]]+\]\([^)]+\))/g;let i,o=0;for(;null!==(i=s.exec(t));){i.index>o&&e.push({t:t.slice(o,i.index),style:"p"});const s=i[1];if(s.startsWith("**"))e.push({t:s.slice(2,-2),style:"b"});else if(s.startsWith("`"))e.push({t:s.slice(1,-1),style:"c"});else if(s.startsWith("[")){const t=s.indexOf("](");e.push({t:s.slice(1,t),style:"a",href:s.slice(t+2,-1)})}else e.push({t:s.slice(1,-1),style:"i"});o=i.index+s.length}o<t.length&&e.push({t:t.slice(o),style:"p"});return e}(b):[{t:b,style:"p"}];let e=n.x+8*this.cam.zoom;const s=n.y+44*this.cam.zoom;p.font=`400 ${10*this.cam.zoom}px Inter, ui-sans-serif`,p.textBaseline="top";const i=n.x+r-8*this.cam.zoom;for(const o of t){let t=10*this.cam.zoom+"px ";t="b"===o.style?`700 ${10*this.cam.zoom}px Inter, ui-sans-serif`:"i"===o.style?`italic 400 ${10*this.cam.zoom}px Inter, ui-sans-serif`:"c"===o.style?10*this.cam.zoom+"px ui-monospace, Consolas, monospace":(o.style,`400 ${10*this.cam.zoom}px Inter, ui-sans-serif`),p.font=t,p.fillStyle="a"===o.style?"#5be0d0":"c"===o.style?"#f0b93a":"#c8d1de";const n=p.measureText(o.t).width;if(e+n>i)break;p.fillText(o.t,e,s),e+=n}}this._searchHits&&this._searchHits.includes(t)&&(p.save(),p.shadowColor="#5be0d0",p.shadowBlur=18*this.cam.zoom,p.strokeStyle="#5be0d0",p.lineWidth=1.6*this.cam.zoom,this._shapePath(a.shape,n.x-3,n.y-3,r+6,h+6),p.stroke(),p.restore());for(let e=0;e<2;e++){const s=0===e?this.V.nIn[t]:this.V.nOut[t];for(let i=0;i<s;i++){const s=this._portWorld(t,e,i),o=this._w2s(s.x,s.y);p.fillStyle=l,p.strokeStyle="#07090f",p.lineWidth=1.5*this.cam.zoom,p.beginPath(),p.arc(o.x,o.y,4.5*this.cam.zoom,0,2*Math.PI),p.fill(),p.stroke()}}}_shapePath(t,e,s,i,o){const n=this.ctx;if("diamond"===t){const t=e+i/2,r=s+o/2;return n.beginPath(),n.moveTo(t,s),n.lineTo(e+i,r),n.lineTo(t,s+o),n.lineTo(e,r),void n.closePath()}if("ellipse"===t)return n.beginPath(),void n.ellipse(e+i/2,s+o/2,i/2,o/2,0,0,2*Math.PI);if("hexagon"===t){const t=e+i/2,r=s+o/2,h=i/2,a=.45*h;return n.beginPath(),n.moveTo(t-h+a,s),n.lineTo(t+h-a,s),n.lineTo(e+i,r),n.lineTo(t+h-a,s+o),n.lineTo(t-h+a,s+o),n.lineTo(e,r),void n.closePath()}this._roundRect(e,s,i,o,8)}_roundRect(t,e,s,i,o){const n=this.ctx;n.beginPath(),n.moveTo(t+o,e),n.lineTo(t+s-o,e),n.quadraticCurveTo(t+s,e,t+s,e+o),n.lineTo(t+s,e+i-o),n.quadraticCurveTo(t+s,e+i,t+s-o,e+i),n.lineTo(t+o,e+i),n.quadraticCurveTo(t,e+i,t,e+i-o),n.lineTo(t,e+o),n.quadraticCurveTo(t,e,t+o,e),n.closePath()}}function d(t,e,s,i,o,n,r,h,a){const l=1-t,d=l*l,c=t*t,u=d*l,m=3*d*t,p=3*l*c,g=c*t;return{x:u*e+m*i+p*n+g*h,y:u*s+m*o+p*r+g*a}}function c(t,e,s,i,o,n){const r=o-s,h=n-i,a=r*r+h*h;if(0===a){const o=t-s,n=e-i;return o*o+n*n}let l=((t-s)*r+(e-i)*h)/a;l=Math.max(0,Math.min(1,l));const d=t-(s+l*r),c=e-(i+l*h);return d*d+c*c}function u(t,e){if(t.startsWith("rgb"))return t.replace(")",`, ${e})`).replace("rgb(","rgba(");return`rgba(${parseInt(t.slice(1,3),16)},${parseInt(t.slice(3,5),16)},${parseInt(t.slice(5,7),16)},${e})`}const m={ok:"#5bd17a",live:"#5bd17a",running:"#5b8def",idle:"#8b95a7",warn:"#f0b93a",error:"#e8462b",failed:"#e8462b",stopped:"#8b95a7"};function p(t){const[e,s]=[...t.values()],i=s.x-e.x,o=s.y-e.y;return{dist:Math.hypot(i,o)||1,mid:{x:(e.x+s.x)/2,y:(e.y+s.y)/2}}}function g(t){let e=2166136261;const s=t=>{if(null==t)return void(e=16777619*(255^e)>>>0);const i=typeof t;if("number"!==i)if("string"!==i)if("boolean"!==i)if(Array.isArray(t))for(const e of t)s(e);else if("object"!==i);else for(const i of Object.keys(t).sort()){for(let t=0;t<i.length;t++)e=16777619*(e^i.charCodeAt(t))>>>0;s(t[i])}else e=16777619*(e^(t?1:0))>>>0;else for(let s=0;s<t.length;s++)e=16777619*(e^t.charCodeAt(s))>>>0;else e=16777619*(e^(1e6*t|0))>>>0};return s(t),e>>>0}function f(t){return"number"==typeof t?_(t):t&&"object"==typeof t?Object.entries(t).filter(([,t])=>null!=t).map(([t,e])=>`${t}: ${_(e)}`).join(" "):_(t)}function _(t){if(null==t)return"∅";if("number"==typeof t)return Number.isInteger(t)?String(t):t.toFixed(2);if("boolean"==typeof t)return t?"true":"false";if("string"==typeof t)return t.length>22?t.slice(0,22)+"…":t;try{const e=JSON.stringify(t);return e.length>30?e.slice(0,30)+"…":e}catch{return"[obj]"}}function y(t){return[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)]}function x(t,e,s){let i=!1;for(let o=0,n=s.length-1;o<s.length;n=o++){const r=s[o].x,h=s[o].y,a=s[n].x,l=s[n].y;h>e!=l>e&&t<(a-r)*(e-h)/(l-h)+r&&(i=!i)}return i}function b(t){return String(t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function w(t){return b(t)}function v(t){const e=new Map,s=[],i=t.split("\n").map(t=>t.replace(/\/\/.*$/,"").trim()).filter(Boolean);let o=0;i[0]&&/^(graph|flowchart)\b/i.test(i[0])&&(o=1);const n=/([A-Za-z_][A-Za-z0-9_]*)(?:(\[\[)([^\]]+)\]\]|\[([^\]]+)\]|\(\(([^)]+)\)\)|\(([^)]+)\)|\{([^}]+)\})?/;function r(t,s){const i=t.slice(s).match(n);if(!i||0!==i.index)return null;const o=i[1];let r="default",h=o;return i[2]?(r="subroutine",h=i[3]):i[4]?(r="rect",h=i[4]):i[5]?(r="circle",h=i[5]):i[6]?(r="round",h=i[6]):i[7]&&(r="rhombus",h=i[7]),e.has(o)&&"default"!==e.get(o).shape||e.set(o,{label:h,shape:r}),{id:o,end:s+i[0].length}}for(let t=o;t<i.length;t++){const e=i[t],o=r(e,0);if(!o)continue;let n=e.slice(o.end).trim();const h=n.match(/^([-=.~]+>?|---|===)\s*(?:\|([^|]+)\|\s*)?/);if(!h)continue;n=n.slice(h[0].length).trim();const a=r(e,e.length-n.length);a&&s.push({from:o.id,to:a.id,label:h[2]||null})}return{nodes:e,edges:s}}function k(t){const e=new Map,s=[];t=(t=t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/^\s*#.*$/gm,"").replace(/\/\/.*$/gm,"")).replace(/^\s*(?:strict\s+)?(?:di)?graph\s+\w*\s*\{/i,"").replace(/\}\s*$/,"");const i=[];let o="",n=0;for(const e of t)"["===e&&n++,"]"===e&&n--,";"!==e&&"\n"!==e||0!==n?o+=e:(o.trim()&&i.push(o.trim()),o="");o.trim()&&i.push(o.trim());const r=/"([^"]+)"|([A-Za-z_][A-Za-z0-9_]*)/;function h(t,e){const s=t.slice(e).match(r);return s&&0===s.index?{id:s[1]||s[2],end:e+s[0].length}:null}function a(t,e){const s=t.slice(e).match(/^\s*\[([^\]]*)\]/);if(!s)return null;const i=s[1].match(/label\s*=\s*"([^"]*)"|label\s*=\s*([A-Za-z_][A-Za-z0-9_]*)/);return{label:i?i[1]||i[2]:null,end:e+s[0].length}}for(const t of i){let i=0;const o=h(t,i);if(!o)continue;for(i=o.end;" "===t[i]||"\t"===t[i];)i++;const n=t.slice(i).match(/^(->|--)\s*/);if(n){i+=n[0].length;const r=h(t,i);if(!r)continue;i=r.end;const l=a(t,i);e.has(o.id)||e.set(o.id,{label:o.id}),e.has(r.id)||e.set(r.id,{label:r.id}),s.push({from:o.id,to:r.id,label:l?l.label:null})}else{const s=a(t,i),n=s&&s.label?s.label:o.id;e.has(o.id)&&e.get(o.id).label!==o.id||e.set(o.id,{label:n})}}return{nodes:e,edges:s}}function S(t,e,s){const i=t.createShader(s);if(t.shaderSource(i,e),t.compileShader(i),!t.getShaderParameter(i,t.COMPILE_STATUS))throw new Error("GL compile: "+t.getShaderInfoLog(i));return i}function z(t,e,s){const i=t.createProgram();if(t.attachShader(i,S(t,e,t.VERTEX_SHADER)),t.attachShader(i,S(t,s,t.FRAGMENT_SHADER)),t.linkProgram(i),!t.getProgramParameter(i,t.LINK_STATUS))throw new Error("GL link: "+t.getProgramInfoLog(i));return i}function E(t){return[parseInt(t.slice(1,3),16)/255,parseInt(t.slice(3,5),16)/255,parseInt(t.slice(5,7),16)/255]}function V(t,e,s,i,o,n,r,h,a){const l=1-t,d=l*l,c=t*t,u=d*l,m=3*d*t,p=3*l*c,g=c*t;return{x:u*e+m*i+p*n+g*h,y:u*s+m*o+p*r+g*a}}function C(t,e,s){return{x:t.x+(e.x-t.x)*s,y:t.y+(e.y-t.y)*s}}var N=Object.freeze({__proto__:null,WebGLRenderer:class{constructor(t){if(this.flow=t,this.glCanvas=document.createElement("canvas"),this.glCanvas.style.cssText="position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0;",t.container.insertBefore(this.glCanvas,t.canvas),t.canvas.style.background="transparent",t.canvas.style.position="absolute",t.canvas.style.zIndex="1",this.gl=this.glCanvas.getContext("webgl",{antialias:!0,alpha:!0,premultipliedAlpha:!1}),!this.gl)return this.disabled=!0,void console.warn("zflow: WebGL unavailable");this.instExt=this.gl.getExtension("ANGLE_instanced_arrays"),this.cap=t.w.nodeCap(),this.edgeCap=t.w.edgeCap(),this._resize(),this._setupShaders(),this._setupBuffers(),this._hookDirty(),this._resizeObs=new ResizeObserver(()=>this._resize()),this._resizeObs.observe(t.container),this._dirty=new Set,this._dirtyEdges=new Set,this._fullRebuildNeeded=!0,this._lastNodeCount=0,this._lastEdgeCount=0}_hookDirty(){const t=this.flow;t.on("change",()=>{this._fullRebuildNeeded=!0});const e=t.w.moveSelectedBy;e&&(t.w.moveSelectedBy=(s,i)=>{e.call(t.w,s,i);for(let e=0;e<t.w.nodeCount_();e++)t.V.selected[e]&&this._dirty.add(e)})}_resize(){const t=window.devicePixelRatio||1,e=this.flow.container.getBoundingClientRect();this.glCanvas.width=e.width*t,this.glCanvas.height=e.height*t,this.gl?.viewport(0,0,this.glCanvas.width,this.glCanvas.height)}_setupShaders(){const t=this.gl;this.progNode=z(t,"\nattribute vec2 aQuad;\nattribute vec2 aCenter;\nattribute vec2 aSize;\nattribute vec3 aColor;\nattribute float aSelected;\nuniform vec2 uCam;\nuniform float uZoom;\nuniform vec2 uScreen;\nvarying vec3 vColor;\nvarying float vSelected;\nvarying vec2 vUv;\nvoid main() {\n vUv = aQuad;\n vSelected = aSelected;\n vColor = aColor;\n vec2 worldPos = aCenter + aQuad * aSize;\n vec2 screen = (worldPos + uCam) * uZoom;\n vec2 ndc = (screen / uScreen) * 2.0;\n gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);\n}","\nprecision mediump float;\nvarying vec3 vColor;\nvarying float vSelected;\nvarying vec2 vUv;\nvoid main() {\n vec2 q = abs(vUv);\n float d = max(q.x, q.y);\n float alpha = smoothstep(1.0, 0.92, d);\n float header = step(0.7, vUv.y) * 0.18;\n vec3 col = vColor + vec3(header);\n if (vSelected > 0.5) col = mix(col, vec3(0.94, 0.73, 0.23), 0.55);\n gl_FragColor = vec4(col, alpha);\n}"),this.progEdge=z(t,"\nattribute vec2 aPos;\nattribute vec3 aColor;\nuniform vec2 uCam;\nuniform float uZoom;\nuniform vec2 uScreen;\nvarying vec3 vColor;\nvoid main() {\n vColor = aColor;\n vec2 screen = (aPos + uCam) * uZoom;\n vec2 ndc = (screen / uScreen) * 2.0;\n gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);\n}","\nprecision mediump float;\nvarying vec3 vColor;\nvoid main() { gl_FragColor = vec4(vColor, 0.85); }"),this.locN={aQuad:t.getAttribLocation(this.progNode,"aQuad"),aCenter:t.getAttribLocation(this.progNode,"aCenter"),aSize:t.getAttribLocation(this.progNode,"aSize"),aColor:t.getAttribLocation(this.progNode,"aColor"),aSel:t.getAttribLocation(this.progNode,"aSelected"),uCam:t.getUniformLocation(this.progNode,"uCam"),uZoom:t.getUniformLocation(this.progNode,"uZoom"),uScreen:t.getUniformLocation(this.progNode,"uScreen")},this.locE={aPos:t.getAttribLocation(this.progEdge,"aPos"),aColor:t.getAttribLocation(this.progEdge,"aColor"),uCam:t.getUniformLocation(this.progEdge,"uCam"),uZoom:t.getUniformLocation(this.progEdge,"uZoom"),uScreen:t.getUniformLocation(this.progEdge,"uScreen")}}_setupBuffers(){const t=this.gl;this.quadBuf=t.createBuffer(),t.bindBuffer(t.ARRAY_BUFFER,this.quadBuf),t.bufferData(t.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,-1,1,1,-1,1]),t.STATIC_DRAW),this.nodeData=new Float32Array(8*this.cap),this.nodeBuf=t.createBuffer(),t.bindBuffer(t.ARRAY_BUFFER,this.nodeBuf),t.bufferData(t.ARRAY_BUFFER,this.nodeData.byteLength,t.DYNAMIC_DRAW),this.edgeData=new Float32Array(48*this.edgeCap*5),this.edgeBuf=t.createBuffer(),t.bindBuffer(t.ARRAY_BUFFER,this.edgeBuf),t.bufferData(t.ARRAY_BUFFER,this.edgeData.byteLength,t.DYNAMIC_DRAW)}_writeNode(t){const e=this.flow,s=e.kinds[e.V.kind[t]],i=e.colors.get(t)||s.color,o=8*t;this.nodeData[o]=e.V.posX[t],this.nodeData[o+1]=e.V.posY[t],this.nodeData[o+2]=.5*e.V.sizeW[t],this.nodeData[o+3]=.5*e.V.sizeH[t];const[n,r,h]=E(i);this.nodeData[o+4]=n,this.nodeData[o+5]=r,this.nodeData[o+6]=h,this.nodeData[o+7]=0!==e.V.selected[t]?1:0}_writeEdge(t){const e=this.flow,s=e.V.edgeFromN[t],i=e.V.edgeToN[t],o=e._portWorld(s,1,e.V.edgeFromP[t]),n=e._portWorld(i,0,e.V.edgeToP[t]),r=E(e.colors.get(s)||e.kinds[e.V.kind[s]].color),h=48*t*5,a="orthogonal"===e.options.edgeStyle,l=Math.max(50,.5*Math.abs(n.x-o.x)+.4*Math.abs(n.y-o.y));let d={x:o.x,y:o.y},c=h;for(let t=1;t<=24;t++){const e=t/24;let s;if(a){const t=.5*(o.x+n.x);s=e<.33?C(o,{x:t,y:o.y},e/.33):e<.67?C({x:t,y:o.y},{x:t,y:n.y},(e-.33)/.34):C({x:t,y:n.y},n,(e-.67)/.33)}else s=V(e,o.x,o.y,o.x+l,o.y,n.x-l,n.y,n.x,n.y);this.edgeData[c++]=d.x,this.edgeData[c++]=d.y,this.edgeData[c++]=r[0],this.edgeData[c++]=r[1],this.edgeData[c++]=r[2],this.edgeData[c++]=s.x,this.edgeData[c++]=s.y,this.edgeData[c++]=r[0],this.edgeData[c++]=r[1],this.edgeData[c++]=r[2],d=s}}render(){if(this.disabled)return;const t=this.gl,e=this.flow,s=e.w.nodeCount_(),i=e.w.edgeCount_(),o=window.devicePixelRatio||1;t.clearColor(.027,.035,.06,1),t.clear(t.COLOR_BUFFER_BIT),t.enable(t.BLEND),t.blendFunc(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA);const n=e.cam.x+this.glCanvas.width/(2*o*e.cam.zoom),r=e.cam.y+this.glCanvas.height/(2*o*e.cam.zoom);if(this._fullRebuildNeeded||s!==this._lastNodeCount){for(let t=0;t<s;t++)this._writeNode(t);t.bindBuffer(t.ARRAY_BUFFER,this.nodeBuf),t.bufferSubData(t.ARRAY_BUFFER,0,this.nodeData.subarray(0,8*s)),this._dirty.clear()}else if(this._dirty.size){t.bindBuffer(t.ARRAY_BUFFER,this.nodeBuf);const e=[...this._dirty].sort((t,e)=>t-e);let s=e[0],i=e[0];for(let o=1;o<e.length;o++)if(e[o]===i+1)i=e[o];else{for(let t=s;t<=i;t++)this._writeNode(t);t.bufferSubData(t.ARRAY_BUFFER,8*s*4,this.nodeData.subarray(8*s,8*(i+1))),s=e[o],i=e[o]}for(let t=s;t<=i;t++)this._writeNode(t);t.bufferSubData(t.ARRAY_BUFFER,8*s*4,this.nodeData.subarray(8*s,8*(i+1))),this._dirty.clear()}if((this._fullRebuildNeeded||i!==this._lastEdgeCount||0===this._dirty.size)&&(this._fullRebuildNeeded||i!==this._lastEdgeCount)){for(let t=0;t<i;t++)this._writeEdge(t);t.bindBuffer(t.ARRAY_BUFFER,this.edgeBuf),t.bufferSubData(t.ARRAY_BUFFER,0,this.edgeData.subarray(0,48*i*5))}if(this._lastNodeCount=s,this._lastEdgeCount=i,this._fullRebuildNeeded=!1,i>0&&(t.useProgram(this.progEdge),t.bindBuffer(t.ARRAY_BUFFER,this.edgeBuf),t.enableVertexAttribArray(this.locE.aPos),t.vertexAttribPointer(this.locE.aPos,2,t.FLOAT,!1,20,0),t.enableVertexAttribArray(this.locE.aColor),t.vertexAttribPointer(this.locE.aColor,3,t.FLOAT,!1,20,8),t.uniform2f(this.locE.uCam,n,r),t.uniform1f(this.locE.uZoom,e.cam.zoom*o),t.uniform2f(this.locE.uScreen,this.glCanvas.width,this.glCanvas.height),t.lineWidth(1.6),t.drawArrays(t.LINES,0,48*i)),s>0){t.useProgram(this.progNode),t.bindBuffer(t.ARRAY_BUFFER,this.quadBuf),t.enableVertexAttribArray(this.locN.aQuad),t.vertexAttribPointer(this.locN.aQuad,2,t.FLOAT,!1,0,0),this.instExt&&this.instExt.vertexAttribDivisorANGLE(this.locN.aQuad,0),t.bindBuffer(t.ARRAY_BUFFER,this.nodeBuf);const i=32;if(t.enableVertexAttribArray(this.locN.aCenter),t.vertexAttribPointer(this.locN.aCenter,2,t.FLOAT,!1,i,0),t.enableVertexAttribArray(this.locN.aSize),t.vertexAttribPointer(this.locN.aSize,2,t.FLOAT,!1,i,8),t.enableVertexAttribArray(this.locN.aColor),t.vertexAttribPointer(this.locN.aColor,3,t.FLOAT,!1,i,16),t.enableVertexAttribArray(this.locN.aSel),t.vertexAttribPointer(this.locN.aSel,1,t.FLOAT,!1,i,28),this.instExt&&(this.instExt.vertexAttribDivisorANGLE(this.locN.aCenter,1),this.instExt.vertexAttribDivisorANGLE(this.locN.aSize,1),this.instExt.vertexAttribDivisorANGLE(this.locN.aColor,1),this.instExt.vertexAttribDivisorANGLE(this.locN.aSel,1)),t.uniform2f(this.locN.uCam,n,r),t.uniform1f(this.locN.uZoom,e.cam.zoom*o),t.uniform2f(this.locN.uScreen,this.glCanvas.width,this.glCanvas.height),this.instExt)this.instExt.drawArraysInstancedANGLE(t.TRIANGLES,0,6,s),this.instExt.vertexAttribDivisorANGLE(this.locN.aCenter,0),this.instExt.vertexAttribDivisorANGLE(this.locN.aSize,0),this.instExt.vertexAttribDivisorANGLE(this.locN.aColor,0),this.instExt.vertexAttribDivisorANGLE(this.locN.aSel,0);else for(let e=0;e<s;e++){const s=8*e;t.vertexAttrib2f(this.locN.aCenter,this.nodeData[s],this.nodeData[s+1]),t.vertexAttrib2f(this.locN.aSize,this.nodeData[s+2],this.nodeData[s+3]),t.vertexAttrib3f(this.locN.aColor,this.nodeData[s+4],this.nodeData[s+5],this.nodeData[s+6]),t.vertexAttrib1f(this.locN.aSel,this.nodeData[s+7]),t.drawArrays(t.TRIANGLES,0,6)}}}markNodeDirty(t){this._dirty.add(t)}markEdgeDirty(t){this._dirtyEdges.add(t),this._fullRebuildNeeded=!0}markAllDirty(){this._fullRebuildNeeded=!0}dispose(){this._resizeObs?.disconnect(),this.glCanvas?.remove()}}});export{l as ZFlow,k as parseDot,v as parseMermaid};
|
|
1
|
+
/*! @luispm/zflow-graph v0.2.0 | MIT | (c) 2026 */
|
|
2
|
+
const t=[{name:"input",color:"#5b8def",badge:"I",w:140,h:60,nin:0,nout:1,shape:"rect"},{name:"process",color:"#e8b04b",badge:"P",w:160,h:80,nin:1,nout:1,shape:"rect"},{name:"filter",color:"#5be0d0",badge:"F",w:160,h:80,nin:1,nout:1,shape:"rect"},{name:"decision",color:"#c062e8",badge:"D",w:130,h:130,nin:1,nout:2,shape:"diamond"},{name:"output",color:"#5bd17a",badge:"O",w:140,h:60,nin:1,nout:0,shape:"rect"},{name:"aggregator",color:"#f0b93a",badge:"∑",w:160,h:120,nin:3,nout:1,shape:"hexagon"},{name:"branch",color:"#e8462b",badge:"B",w:130,h:130,nin:1,nout:3,shape:"ellipse"},{name:"if",color:"#c062e8",badge:"?",w:150,h:70,nin:1,nout:2,shape:"diamond",portIn:["value"],portOut:["true","false"],execute:(t,e)=>{const s=e.value??e[0],i=t.params?.condition;let o;if("function"==typeof i)o=i(s);else if("string"==typeof i)try{o=Function("value","v",`"use strict"; return (${i});`)(s,s)}catch{o=!1}else o=Boolean(s);return o?{true:s}:{false:s}}},{name:"forEach",color:"#5be0d0",badge:"↻",w:160,h:70,nin:1,nout:1,shape:"rect",portIn:["array"],portOut:["item"],execute:async(t,e)=>{const s=e.array??e[0]??[];if(!Array.isArray(s)||0===s.length)return null;for(let e=0;e<s.length;e++){if(t.signal.aborted)return;t.setProgress((e+1)/s.length),t.emit({item:s[e]}),await new Promise(t=>setTimeout(t,30))}return{item:s[s.length-1]}}},{name:"const",color:"#8b95a7",badge:"K",w:130,h:56,nin:0,nout:1,shape:"rect",portOut:["value"],execute:t=>({value:t.params?.value??0})},{name:"log",color:"#5b8def",badge:"◷",w:160,h:60,nin:1,nout:0,shape:"rect",portIn:["value"],execute:(t,e)=>(t.log(e.value??e[0]),{received:e.value??e[0]})}],e={bg:"#07090f",panel:"rgba(20,28,40,0.92)",border:"rgba(255,255,255,0.10)",fg:"#e6edf3",muted:"#8b95a7",accent:"#f0b93a",hi:"rgba(240,185,58,0.10)",grid:"rgba(255,255,255,0.04)",gridDot:"rgba(255,255,255,0.10)"},s={bg:"#f6f8fb",panel:"rgba(255,255,255,0.96)",border:"rgba(0,0,0,0.10)",fg:"#1d2330",muted:"#5a6577",accent:"#b8860b",hi:"rgba(184,134,11,0.12)",grid:"rgba(0,0,0,0.04)",gridDot:"rgba(0,0,0,0.16)"},i=["tl","t","tr","r","br","b","bl","l"],o=new Set(["l","tl","bl"]),n=new Set(["r","tr","br"]),r=new Set(["t","tl","tr"]),h=new Set(["b","bl","br"]),a={tl:"nwse-resize",br:"nwse-resize",tr:"nesw-resize",bl:"nesw-resize",t:"ns-resize",b:"ns-resize",l:"ew-resize",r:"ew-resize"};class l{static async create(t){const e=new l;return await e._init(t),e}async _init(i){if(!i||!i.container)throw new Error("zflow: container is required");let o;if(this.container=i.container,this.options=Object.assign({theme:"dark",background:"#07090f",edgeStyle:"bezier",snapToGrid:!1,gridSize:20,contextMenu:!0,keyboard:!0,minimap:!1,animateEdges:!1,edgeFlowSpeed:60,commandPalette:!0,search:!0,inlineMarkdown:!0},i),this._theme="light"===this.options.theme?s:e,"light"===this.options.theme&&(this.options.background=this._theme.bg),i.wasmBytes)o=i.wasmBytes instanceof Uint8Array?i.wasmBytes:new Uint8Array(i.wasmBytes);else{if(!i.wasmUrl)throw new Error("zflow: pass either { wasmUrl } or { wasmBytes }");o=new Uint8Array(await(await fetch(i.wasmUrl)).arrayBuffer())}const{instance:n}=await WebAssembly.instantiate(o,{});if(this.w=n.exports,0===this.w.init())throw new Error("zflow: WASM init OOM");const r=this.w.nodeCap(),h=this.w.edgeCap();this.V={posX:new Float32Array(this.w.memory.buffer,this.w.posXPtr(),r),posY:new Float32Array(this.w.memory.buffer,this.w.posYPtr(),r),sizeW:new Float32Array(this.w.memory.buffer,this.w.sizeWPtr(),r),sizeH:new Float32Array(this.w.memory.buffer,this.w.sizeHPtr(),r),kind:new Uint8Array(this.w.memory.buffer,this.w.kindPtr(),r),nIn:new Uint8Array(this.w.memory.buffer,this.w.nInPtr(),r),nOut:new Uint8Array(this.w.memory.buffer,this.w.nOutPtr(),r),selected:new Uint8Array(this.w.memory.buffer,this.w.selectedPtr(),r),edgeFromN:new Uint32Array(this.w.memory.buffer,this.w.edgeFromNodePtr(),h),edgeToN:new Uint32Array(this.w.memory.buffer,this.w.edgeToNodePtr(),h),edgeFromP:new Uint8Array(this.w.memory.buffer,this.w.edgeFromPortPtr(),h),edgeToP:new Uint8Array(this.w.memory.buffer,this.w.edgeToPortPtr(),h),edgeSel:new Uint8Array(this.w.memory.buffer,this.w.edgeSelectedPtr(),h),queryRes:new Uint32Array(this.w.memory.buffer,this.w.queryResultsPtr(),r)},this.kinds=t.map(t=>({...t})),this.kindByName=new Map,this.kinds.forEach((t,e)=>this.kindByName.set(t.name,e)),this.titles=new Map,this.colors=new Map,this.descriptions=new Map,this.data=new Map,this.tags=new Map,this.status=new Map,this.progress=new Map,this.image=new Map,this.checked=new Map,this.tasks=new Map,this.icon=new Map,this.links=new Map,this.portIn=new Map,this.portOut=new Map,this.zOrder=new Map,this.bookmarks=new Map,this.edgeLabels=new Map,this._imageCache=new Map,this._nodeAddedAt=new Map,this._dyingNodes=[],this._dyingEdges=[],this.notes=[],this._noteSeq=0,this.frames=[],this._frameSeq=0,this.canvas=document.createElement("canvas"),this.canvas.style.cssText=`display:block;width:100%;height:100%;background:${this.options.background};cursor:default;outline:none;touch-action:none;user-select:none;`,this.canvas.tabIndex=0,this.container.style.position=this.container.style.position||"relative",this.container.appendChild(this.canvas),this.ctx=this.canvas.getContext("2d",{alpha:!1}),this.cam={x:0,y:0,zoom:1},this._panVel={x:0,y:0,lastTs:0},this._clipboard=null,this._nudgeTimer=null,this.listeners=new Map,this._mode="idle",this._dragStart=null,this._dragLast=null,this._hoveredNode=-1,this._hoveredEdge=-1,this._hoveredNodeSince=0,this._previewedNode=-1,this._resizingHandle=null,this._marquee=null,this._lasso=null,this._alignGuides=null,this._edgeStart=null,this._edgeCursor=null,this._draggingNote=-1,this._noteDragLast=null,this._draggingFrame=-1,this._frameDragLast=null,this._resizingFrame=null,this._editingNote=-1,this._editingNoteEl=null,this._editingTitle=-1,this._editingTitleEl=null,this._focusFrame=-1,this._htmlOverlays=new Map,this._previewEl=null,this._pathHighlightEnabled=!1,this._focusedSet=null,this._lastFocusComputed=-2,this._menuEl=null,this.locked=new Set,this.readOnly=!1,this.snapToNodes=!0,this._reachableSet=null,this.remoteCursors=new Map,this._edgeWaypoints=new Map,this._draggingWaypoint=null,this.frameCollapsed=new Set,this._paletteGhost=null,this.metrics=new Map,this.metricMax=new Map,this._metricCap=32,this.animatedEdges=new Set,this._edgePhase=0,this._connValidator=null,this._templates=new Map,this._searchEl=null,this._searchQuery="",this._searchHits=[],this._cmdPaletteEl=null,this._minimapEl=null,this._minimapCtx=null,this._historyThumbs=[],this.options.minimap&&this._setupMinimap(),this._plugins=[],this._hooks={beforeRender:[],afterRender:[],onNodeAdd:[],onNodeDelete:[],onEdgeAdd:[],onBeforeExec:[],onAfterExec:[],onConnect:[],onSelectionChange:[],onChange:[]},this._values=new Map,this._running=!1,this._runAbort=null,this._runSeq=0,this._runOrder=null,this._execHooks=new Map,this._streamSrc=new Map,this._runStepDelay=250,this._valueBubbles=[],this._activeEdges=new Map,this._memoize=!1,this._memoKeys=new Map,this._retryStats=new Map,this.breakpoints=new Set,this._paused=!1,this._resumeNext=null,this._stepMode=!1,this._subflows=new Map,this._resize(),this._resizeObs=new ResizeObserver(()=>this._resize()),this._resizeObs.observe(this.container),this._attachEvents(),this.options.keyboard&&this._attachKeyboard(),this._loop()}dispose(){cancelAnimationFrame(this._raf),this._resizeObs?.disconnect(),this.canvas?.remove(),this._menuEl?.remove(),this._keyHandler&&window.removeEventListener("keydown",this._keyHandler),this.listeners.clear()}addNode(t={}){if(this.readOnly)return-1;this._runOrder=null;const e=this._resolveKind(t.kind??"process"),s=this.kinds[e],i=this.w.addNode(t.x??0,t.y??0,t.w??s.w,t.h??s.h,e,t.nin??s.nin,t.nout??s.nout);return i<0?-1:(t.title&&this.titles.set(i,t.title),t.color&&this.colors.set(i,t.color),t.description&&this.descriptions.set(i,t.description),t.tags&&this.tags.set(i,t.tags.slice()),t.status&&this.status.set(i,t.status),void 0!==t.progress&&this.progress.set(i,t.progress),t.image&&this.image.set(i,t.image),void 0!==t.checked&&this.checked.set(i,!!t.checked),t.tasks&&this.tasks.set(i,t.tasks.map(t=>({...t}))),t.icon&&this.icon.set(i,t.icon),t.links&&this.links.set(i,t.links.map(t=>({...t}))),t.portIn&&this.portIn.set(i,t.portIn.slice()),t.portOut&&this.portOut.set(i,t.portOut.slice()),void 0!==t.data&&this.data.set(i,t.data),!1!==t.animate&&this._nodeAddedAt.set(i,performance.now()),this._hooks&&this._runHook("onNodeAdd",i,t),this._emit("change"),i)}addNodesBulk(t){if(this.readOnly)return[];this._runOrder=null;const e=new Array(t.length),s=this._suspendEvents;this._suspendEvents=!0;for(let s=0;s<t.length;s++){const i=t[s],o=this._resolveKind(i.kind??"process"),n=this.kinds[o],r=this.w.addNode(i.x??0,i.y??0,i.w??n.w,i.h??n.h,o,i.nin??n.nin,i.nout??n.nout);r<0?e[s]=-1:(i.title&&this.titles.set(r,i.title),i.color&&this.colors.set(r,i.color),void 0!==i.data&&this.data.set(r,i.data),e[s]=r)}return this._suspendEvents=s,this._gl&&this._gl.markAllDirty(),this._emit("change"),e}addEdgesBulk(t){if(this.readOnly)return[];this._runOrder=null;const e=new Array(t.length),s=this._suspendEvents;this._suspendEvents=!0;for(let s=0;s<t.length;s++){const i=t[s];e[s]=this.w.addEdge(i.from,i.fp??0,i.to,i.tp??0),i.label&&e[s]>=0&&this.edgeLabels.set(e[s],i.label)}return this._suspendEvents=s,this._gl&&this._gl.markAllDirty(),this._adjDirty=!0,this._emit("change"),e}addEdge(t={}){if(this.readOnly)return-1;this._runOrder=null,this._adjDirty=!0;const e=this.w.addEdge(t.from,t.fp??0,t.to,t.tp??0);return e>=0&&(t.label&&this.edgeLabels.set(e,t.label),this._hooks&&this._runHook("onEdgeAdd",e,t),this._emit("change")),e}moveNode(t,e,s){this.w.moveNode(t,e,s),this._emit("change")}_guardWrite(){return!this.readOnly}deleteSelection(){if(this.readOnly)return;this._runOrder=null,this._captureDying();const t=this._buildNodeRemap(),e=this._buildEdgeRemap(),s=this.w.deleteSelected();return s>0&&(this._applyNodeRemap(t),this._applyEdgeRemap(e),this.w.snapshot(),this._emit("change")),s}_buildNodeRemap(){const t=this.w.nodeCount_(),e=new Map;let s=0;for(let i=0;i<t;i++)this.V.selected[i]?e.set(i,null):e.set(i,s++);return e}_buildEdgeRemap(){const t=this.w.edgeCount_(),e=new Map;let s=0;for(let i=0;i<t;i++){const t=this.V.edgeFromN[i],o=this.V.edgeToN[i];this.V.selected[t]||this.V.selected[o]||this.V.edgeSel[i]?e.set(i,null):e.set(i,s++)}return e}_applyNodeRemap(t){const e=[this.titles,this.colors,this.descriptions,this.tags,this.status,this.progress,this.image,this.checked,this.tasks,this.icon,this.links,this.portIn,this.portOut,this.zOrder,this.data];for(const s of e)this._remapKeyedMap(s,t);this._remapKeyedSet(this.locked,t),this._remapKeyedSet(this.breakpoints,t),this._remapKeyedMap(this._values,t),this._remapKeyedMap(this._memoKeys,t),this._remapKeyedMap(this.metrics,t),this._remapKeyedMap(this.metricMax,t);const s=new Map;for(const[e,i]of this.bookmarks){const o=t.get(i);null!=o&&s.set(e,o)}this.bookmarks=s}_applyEdgeRemap(t){this._remapKeyedMap(this.edgeLabels,t),this._remapKeyedSet(this.animatedEdges,t),this._remapKeyedMap(this._edgeWaypoints,t),this._remapKeyedMap(this._activeEdges,t)}_remapKeyedMap(t,e){const s=new Map;for(const[i,o]of t){const t=e.get(i);null!=t&&s.set(t,o)}t.clear();for(const[e,i]of s)t.set(e,i)}_remapKeyedSet(t,e){const s=new Set;for(const i of t){const t=e.get(i);null!=t&&s.add(t)}t.clear();for(const e of s)t.add(e)}_captureDying(){const t=performance.now(),e=new Uint8Array(this.w.nodeCount_());for(let t=0;t<this.w.nodeCount_();t++)this.V.selected[t]&&(e[t]=1);for(let s=0;s<this.w.nodeCount_();s++){if(!e[s])continue;const i=this.kinds[this.V.kind[s]];this._dyingNodes.push({x:this.V.posX[s],y:this.V.posY[s],w:this.V.sizeW[s],h:this.V.sizeH[s],shape:i.shape,color:this.colors.get(s)||i.color,t0:t})}for(let s=0;s<this.w.edgeCount_();s++){const i=this.V.edgeFromN[s],o=this.V.edgeToN[s];if(!this.V.edgeSel[s]&&!e[i]&&!e[o])continue;const n=this._portWorld(i,1,this.V.edgeFromP[s]),r=this._portWorld(o,0,this.V.edgeToP[s]);this._dyingEdges.push({ap:n,bp:r,colA:this.colors.get(i)||this.kinds[this.V.kind[i]].color,colB:this.colors.get(o)||this.kinds[this.V.kind[o]].color,t0:t})}}duplicateSelection(t=40,e=40){const s=this.w.duplicateSelected(t,e);return s>0&&(this.w.snapshot(),this._emit("change")),s}setSelected(t,e){this.w.setSelected(t,e?1:0),this._emit("select",this.getSelection())}toggleSelected(t){this.w.toggleSelected(t),this._emit("select",this.getSelection())}clearSelection(){this.w.clearSelection(),this._emit("select",[])}selectAll(){this.w.selectAll(),this._emit("select",this.getSelection())}setSelection(t){if(this.w.clearSelection(),Array.isArray(t))for(const e of t)e>=0&&e<this.w.nodeCount_()&&this.w.setSelected(e,1);this._emit("select",this.getSelection())}deleteNode(t){if(this.readOnly)return 0;if(t<0||t>=this.w.nodeCount_())return 0;const e=this.getSelection();this.w.clearSelection(),this.w.setSelected(t,1);const s=this.deleteSelection();if(e.length){this.w.clearSelection();for(const s of e){if(s===t)continue;const e=s>t?s-1:s;e<this.w.nodeCount_()&&this.w.setSelected(e,1)}this._emit("select",this.getSelection())}return s}transaction(t){if("function"!=typeof t)return;if(this._inTransaction)return t();this._inTransaction=!0;const e=this._suspendEvents;let s;this._suspendEvents=!0;try{s=t()}finally{this._suspendEvents=e,this._inTransaction=!1}return this.w.snapshot(),this._emit("change"),s}getSelection(){const t=[],e=this.w.nodeCount_();for(let s=0;s<e;s++)this.V.selected[s]&&t.push(s);return t}nodeCount(){return this.w.nodeCount_()}edgeCount(){return this.w.edgeCount_()}setNodeTitle(t,e){e?this.titles.set(t,e):this.titles.delete(t),this._emit("change")}setNodeColor(t,e){e?this.colors.set(t,e):this.colors.delete(t),this._emit("change")}setNodeDescription(t,e){e?this.descriptions.set(t,e):this.descriptions.delete(t),this._emit("change")}setNodeTags(t,e){e&&e.length?this.tags.set(t,e.slice()):this.tags.delete(t),this._emit("change")}setNodeStatus(t,e){e?this.status.set(t,e):this.status.delete(t),this._emit("change")}setNodeProgress(t,e){null!=e?this.progress.set(t,e):this.progress.delete(t),this._emit("change")}setEdgeLabel(t,e){e?this.edgeLabels.set(t,e):this.edgeLabels.delete(t),this._emit("change")}setEdgeStyle(t){this.options.edgeStyle="orthogonal"===t?"orthogonal":"bezier"}setSnapToGrid(t){this.options.snapToGrid=!!t}setNodeImage(t,e){e?this.image.set(t,e):this.image.delete(t),this._emit("change")}setNodeChecked(t,e){null==e?this.checked.delete(t):this.checked.set(t,!!e),this._emit("change")}setNodeTasks(t,e){e&&e.length?this.tasks.set(t,e.map(t=>({...t}))):this.tasks.delete(t),this._emit("change")}setNodeIcon(t,e){e?this.icon.set(t,e):this.icon.delete(t),this._emit("change")}setNodeLinks(t,e){e&&e.length?this.links.set(t,e.map(t=>({...t}))):this.links.delete(t),this._emit("change")}setPortInLabels(t,e){e&&e.some(Boolean)?this.portIn.set(t,e.slice()):this.portIn.delete(t),this._emit("change")}setPortOutLabels(t,e){e&&e.some(Boolean)?this.portOut.set(t,e.slice()):this.portOut.delete(t),this._emit("change")}setNodeData(t,e){null==e?this.data.delete(t):this.data.set(t,e),this._emit("change")}getNodeData(t){return this.data.get(t)}_nextZ=0;bringToFront(t){const e=t||this.getSelection();for(const t of e)this.zOrder.set(t,++this._nextZ)}sendToBack(t){const e=t||this.getSelection();for(const t of e)this.zOrder.set(t,--this._nextZ)}setBookmark(t,e){this.bookmarks.set(t,e??this.getSelection()[0])}jumpBookmark(t){const e=this.bookmarks.get(t);void 0===e||e>=this.w.nodeCount_()||(this.clearSelection(),this.w.setSelected(e,1),this.panTo(this.V.posX[e],this.V.posY[e]),this._emit("select",this.getSelection()))}setHoverPreview(t){this.options.hoverPreview=!!t,t||this._hidePreview()}use(t){if(!t)throw new Error("use(plugin): plugin required");"function"==typeof t&&(t=t(this)||{}),this._plugins.push(t);for(const e of Object.keys(this._hooks))"function"==typeof t[e]&&this._hooks[e].push(t[e]);if("function"==typeof t.extendAPI&&t.extendAPI(this),"function"==typeof t.init&&t.init(this),Array.isArray(t.kinds))for(const e of t.kinds)this.registerKind(e);return Array.isArray(t.commands)&&(this._extraCommands=(this._extraCommands||[]).concat(t.commands)),this._emit("plugin:installed",t.name||t),()=>this._removePlugin(t)}_removePlugin(t){const e=this._plugins.indexOf(t);if(-1!==e){this._plugins.splice(e,1);for(const e of Object.keys(this._hooks))if("function"==typeof t[e]){const s=this._hooks[e],i=s.indexOf(t[e]);-1!==i&&s.splice(i,1)}"function"==typeof t.dispose&&t.dispose(this)}}_runHook(t,...e){const s=this._hooks[t];if(!s||!s.length)return null;let i;for(const o of s)try{const t=o(this,...e);if(!1===t)return!1;void 0!==t&&(i=t)}catch(e){console.error(`plugin ${t} hook error`,e)}return i}async enableWebGL(t=!1){if(this._gl)return!0;if(!t&&this.w.nodeCount_()<(this.options.webglThreshold||2e3))return!1;try{const t=await Promise.resolve().then(function(){return A});return this._gl=new t.WebGLRenderer(this),this._gl.disabled?(this._gl=null,!1):(this.options.renderer="webgl",this._emit("renderer","webgl"),!0)}catch(t){return console.warn("zflow: WebGL renderer failed",t),!1}}disableWebGL(){this._gl&&(this._gl.dispose(),this._gl=null,this.canvas.style.background=this.options.background,this.canvas.style.zIndex="",this.canvas.style.position="",this.options.renderer="canvas2d",this._emit("renderer","canvas2d"))}setRunStepDelay(t){this._runStepDelay=Math.max(0,0|t)}setMemoization(t){this._memoize=!!t,t||this._memoKeys?.clear()}validateConnection(t,e,s,i){if(t===s)return"self-loop";const o=this.kinds[this.V.kind[t]],n=this.kinds[this.V.kind[s]],r=o.outputs?.[e],h=n.inputs?.[i];if(r&&h&&!function(t,e){if(!t||!e)return!0;if(t===e)return!0;if("any"===t||"any"===e)return!0;if("string"===e)return!0;const s=new Set(["number","int","float","integer"]);return!(!s.has(t)||!s.has(e))}(r.type,h.type))return`type mismatch: ${r.type} → ${h.type}`;if(this._connValidator){if(!1===this._connValidator(t,e,s,i))return"rejected by validator"}return null}editNodeExpression(t,e="title"){this._exprEditorEl&&this._closeExprEditor();const s="title"===e?this.titles.get(t)||"":"desc"===e&&this.descriptions.get(t)||"",i=document.createElement("div");i.style.cssText="position:absolute;z-index:600;background:#161b27;border:1px solid #f0b93a;border-radius:6px;box-shadow:0 8px 24px rgba(0,0,0,0.5);font-family:Inter, ui-sans-serif;font-size:12px;color:#e6edf3;width:280px;",i.innerHTML='\n <input id="zf-expr" type="text" style="width:260px;padding:8px 10px;background:transparent;border:0;color:#e6edf3;outline:none;font-family:ui-monospace,Consolas,monospace;font-size:12px;">\n <div id="zf-expr-preview" style="padding:4px 10px;border-top:1px solid rgba(255,255,255,0.08);color:#5be0d0;font-family:ui-monospace,Consolas,monospace;font-size:11px;min-height:14px;"></div>\n <div id="zf-expr-list" style="max-height:160px;overflow:auto;border-top:1px solid rgba(255,255,255,0.08);display:none;"></div>',this.container.appendChild(i),this._exprEditorEl=i;const o=this.V.posX[t],n=this.V.posY[t],r=.5*this.V.sizeH[t],h=this._w2s(o-.5*this.V.sizeW[t],n-r),a=window.devicePixelRatio||1;i.style.left=h.x/a+"px",i.style.top=Math.max(8,h.y/a-110)+"px";const l=i.querySelector("#zf-expr"),d=i.querySelector("#zf-expr-list"),c=i.querySelector("#zf-expr-preview");l.value=s;const u=()=>{try{const t=this.evalExpression(l.value);c.style.color="#5be0d0",c.textContent="= "+_(t)}catch(t){c.style.color="#e8462b",c.textContent=String(t.message||t)}},p=()=>{const e=l.selectionStart,s=l.value.slice(0,e).match(/\{\{\s*([\w_.]*)$/);if(!s)return void(d.style.display="none");const i=s[1].toLowerCase(),o=[];for(let e=0;e<this.w.nodeCount_();e++){if(e===t)continue;const s=this.titles.get(e)||this.kinds[this.V.kind[e]].name,n=this._values.get(e),r=n&&"object"==typeof n?Object.keys(n).map(t=>`node_${e}.${t}`):[`node_${e}`];for(const t of r)t.toLowerCase().startsWith(i)&&o.push({text:t,label:`${t} · ${s}`})}o.length?(d.style.display="block",d._items=o.slice(0,8),d._cursor=0,d.innerHTML=d._items.map((t,e)=>`<div data-i="${e}" data-text="${w(t.text)}" style="padding:6px 10px;cursor:pointer;${0===e?"background:rgba(240,185,58,0.18);":""}">${w(t.label)}</div>`).join("")):d.style.display="none"},m=t=>{const e=l.selectionStart,s=l.value.slice(0,e).replace(/\{\{\s*[\w_.]*$/,"{{")+t+"}}";l.value=s+l.value.slice(e),l.selectionStart=l.selectionEnd=s.length,u(),d.style.display="none"},g=()=>d.querySelectorAll("[data-i]").forEach((t,e)=>t.style.background=e===d._cursor?"rgba(240,185,58,0.18)":"transparent");l.addEventListener("input",()=>{u(),p()}),l.addEventListener("keydown",s=>{const i="none"!==d.style.display&&d._items;return i&&"ArrowDown"===s.code?(d._cursor=(d._cursor+1)%d._items.length,g(),void s.preventDefault()):i&&"ArrowUp"===s.code?(d._cursor=(d._cursor-1+d._items.length)%d._items.length,g(),void s.preventDefault()):!i||"Tab"!==s.code&&"Enter"!==s.code?("Enter"===s.code&&("title"===e?this.setNodeTitle(t,l.value):"desc"===e&&this.setNodeDescription(t,l.value),this._closeExprEditor()),void("Escape"===s.code&&this._closeExprEditor())):(m(d._items[d._cursor].text),void s.preventDefault())}),d.addEventListener("mousedown",t=>{const e=t.target.closest("[data-i]");e&&(m(e.dataset.text),l.focus(),t.preventDefault())}),setTimeout(()=>{l.focus(),l.select(),u()},10);const f=t=>{this._exprEditorEl&&!this._exprEditorEl.contains(t.target)&&this._closeExprEditor()};setTimeout(()=>document.addEventListener("mousedown",f,{once:!1}),60),this._exprEditorEl._cleanup=()=>document.removeEventListener("mousedown",f)}_closeExprEditor(){this._exprEditorEl&&(this._exprEditorEl._cleanup?.(),this._exprEditorEl.remove(),this._exprEditorEl=null)}evalExpression(t,e={}){if("string"!=typeof t)return t;const s=t.replace(/\{\{\s*([^}]+?)\s*\}\}/g,(t,s)=>{const[i,...o]=s.split(".");let n;if(/^node_(\d+)$/.test(i))n=this._values.get(parseInt(i.slice(5),10));else{if(!(i in e))return"null";n=e[i]}for(const t of o)n=null==n?void 0:n[t];return JSON.stringify(n??null)});if(s===t)return t;try{return Function(`"use strict"; return (${s})`)()}catch{return s}}setKindExecutor(t,e){const s=this.kindByName.get(t);if(void 0===s)throw new Error(`unknown kind: ${t}`);const i=this.kinds[s].execute;return this.kinds[s].execute=e,this._runOrder=null,i}setNodeInput(t,e){this._values.set(t,e),this.setNodeStatus(t,"ok")}getNodeValue(t){return this._values.get(t)}clearRuntimeState(){this._values.clear();for(const t of this._streamSrc.values())try{t()}catch{}this._streamSrc.clear();const t=this.w.nodeCount_();for(let e=0;e<t;e++)this.status.delete(e),this.progress.delete(e);this._emit("change")}_topoOrder(){if(this._runOrder)return this._runOrder;const t=this.w.nodeCount_(),e=this.w.edgeCount_(),s=new Int32Array(t),i=Array.from({length:t},()=>[]);for(let t=0;t<e;t++){const e=this.V.edgeFromN[t],o=this.V.edgeToN[t];e!==o&&(s[o]++,i[e].push({to:o,fp:this.V.edgeFromP[t],tp:this.V.edgeToP[t],idx:t}))}const o=[];for(let e=0;e<t;e++)0===s[e]&&o.push(e);const n=[];for(;o.length;){const t=o.shift();n.push(t);for(const e of i[t])0===--s[e.to]&&o.push(e.to)}if(n.length<t){const e=new Set(n);for(let s=0;s<t;s++)e.has(s)||n.push(s)}return this._runOrder=n,this._runOut=i,n}_gatherInputs(t){const e={},s=this.kinds[this.V.kind[t]],i=this.portIn.get(t)||s.portIn||[],o=this.w.edgeCount_();for(let s=0;s<o;s++){if(this.V.edgeToN[s]!==t)continue;const o=this.V.edgeToP[s],n=this.V.edgeFromN[s],r=this.V.edgeFromP[s],h=this._values.get(n);if(void 0===h)continue;let a;if(h&&"object"==typeof h&&!Array.isArray(h)){const t=this.kinds[this.V.kind[n]],e=(this.portOut.get(n)||t.portOut||[])[r];if(e){if(!(e in h))continue;a=h[e]}else a=r in h?h[r]:"value"in h?h.value:"out"in h?h.out:h;if(void 0===a)continue}else a=h;e[i[o]||`in${o}`]=a,e[o]=a}return e}_collectDownstream(t){const e=this.w.edgeCount_(),s=[],i=new Set,o=this._topoOrder(),n=new Map(o.map((t,e)=>[t,e])),r=[t];for(;r.length;){const t=r.pop();for(let o=0;o<e;o++)this.V.edgeFromN[o]!==t||i.has(this.V.edgeToN[o])||(i.add(this.V.edgeToN[o]),s.push(this.V.edgeToN[o]),r.push(this.V.edgeToN[o]))}return s.sort((t,e)=>n.get(t)-n.get(e)),s}async run({from:t=null,signal:e=null,filter:s=null}={}){if(this._running)return;this._running=!0;const i=++this._runSeq,o=new AbortController;this._runAbort=o,e&&e.addEventListener("abort",()=>o.abort()),this._topoOrder();let n=this._runOrder;if(null!==t){const e=new Set([t]),s=[t];for(;s.length;){const t=s.shift();for(const i of this._runOut[t])e.has(i.to)||(e.add(i.to),s.push(i.to))}n=n.filter(t=>e.has(t))}"function"==typeof s&&(n=n.filter(s));const r={executed:0,errors:[],values:new Map};this._emit("run:start",{order:n});for(const t of n){if(o.signal.aborted||i!==this._runSeq)break;const e=this.kinds[this.V.kind[t]],s=e.execute;if("function"!=typeof s){if(!this._values.has(t))continue;r.values.set(t,this._values.get(t));continue}const n=this._gatherInputs(t);if(e.nin>0&&0===Object.keys(n).length){let e=!1;const s=this.w.edgeCount_();for(let i=0;i<s;i++)if(this.V.edgeToN[i]===t){e=!0;break}if(e)continue}if(this._memoize){const e=g(n);if(this._memoKeys.get(t)===e&&this._values.has(t)){r.executed++,this._emit("node:cached",{id:t});continue}this._memoKeys.set(t,e)}const h=this.w.edgeCount_();for(let e=0;e<h;e++)this.V.edgeToN[e]===t&&this._values.has(this.V.edgeFromN[e])&&this._activeEdges.set(e,performance.now()+800);if(this.setNodeStatus(t,"running"),this.setNodeProgress(t,0),this._emit("node:exec",{id:t,inputs:n}),this._hooks){if(!1===this._runHook("onBeforeExec",t,n)){this.setNodeStatus(t,"idle");continue}}if((this.breakpoints.has(t)||this._stepMode)&&(await this._awaitContinue(t),o.signal.aborted||i!==this._runSeq))break;if(this._runStepDelay>0&&(await new Promise(t=>setTimeout(t,this._runStepDelay)),o.signal.aborted||i!==this._runSeq))break;const a={nodeId:t,signal:o.signal,params:this._nodeParams?.get(t)||{},emit:e=>{this._values.set(t,e),this._emit("node:emit",{id:t,outputs:e}),"number"==typeof e&&this.pushNodeMetric(t,e)},log:(...e)=>this._emit("node:log",{id:t,args:e}),setProgress:e=>this.setNodeProgress(t,e),metric:e=>this.pushNodeMetric(t,e),get:t=>this._values.get(t)},l=e.retry||null,d=l?l.n??3:1,c=l?l.delay??100:0;let u,p=0,m=null,y=!1;for(;p<d;){p++,this._retryStats.set(t,p);try{const e=s(a,n);if(e&&"function"==typeof e[Symbol.asyncIterator]){let s;const i=this._collectDownstream(t);for await(const n of e){if(o.signal.aborted)break;s=n,this._values.set(t,n),this._emit("node:emit",{id:t,outputs:n}),"number"==typeof n&&this.pushNodeMetric(t,n),this._valueBubbles.push({nodeId:t,text:f(n),t0:performance.now(),dur:700});for(const e of i){if(o.signal.aborted)break;const s=this.kinds[this.V.kind[e]];if("function"!=typeof s.execute)continue;if("AsyncGeneratorFunction"===s.execute.constructor.name)continue;const i=this._gatherInputs(e),n=this.w.edgeCount_();for(let s=0;s<n;s++)this.V.edgeToN[s]===e&&this.V.edgeFromN[s]===t&&this._activeEdges.set(s,performance.now()+500);this.setNodeStatus(e,"running");try{const t=s.execute({...a,nodeId:e,params:this._nodeParams?.get(e)||{}},i),o=t&&"function"==typeof t.then?await t:t;null!=o&&(this._values.set(e,o),this._emit("node:emit",{id:e,outputs:o}),this._valueBubbles.push({nodeId:e,text:f(o),t0:performance.now(),dur:700}),"number"==typeof o&&this.pushNodeMetric(e,o)),this.setNodeStatus(e,"ok")}catch(t){this.setNodeStatus(e,"error")}}await new Promise(t=>setTimeout(t,60))}u=s}else u=e&&"function"==typeof e.then?await e:e;if(o.signal.aborted||i!==this._runSeq)break;y=!0,m=null;break}catch(e){m=e,this._emit("node:retry",{id:t,attempt:p,error:e}),p<d&&await new Promise(t=>setTimeout(t,c))}}try{if(!y)throw m;if(o.signal.aborted||i!==this._runSeq)break;if(null!=u){let e;if(this._values.set(t,u),r.values.set(t,u),"number"==typeof u)e=_(u);else if(u&&"object"==typeof u){e=Object.entries(u).filter(([,t])=>null!=t).map(([t,e])=>`${t}: ${_(e)}`).join(" ")}else e=_(u);if(this._valueBubbles.push({nodeId:t,text:e,t0:performance.now(),dur:1400}),"number"==typeof u)this.pushNodeMetric(t,u);else if(u&&"object"==typeof u)for(const e of Object.values(u))if("number"==typeof e){this.pushNodeMetric(t,e);break}}this.setNodeStatus(t,"ok"),this.setNodeProgress(t,1),r.executed++,this._hooks&&this._runHook("onAfterExec",t,u),this._emit("node:done",{id:t,outputs:u})}catch(e){if(this.setNodeStatus(t,"error"),r.errors.push({id:t,error:e}),this._emit("node:error",{id:t,error:e}),this.options.stopOnError)break}}return this._running=!1,this._runAbort=null,this._emit("run:done",r),r}runFrom(t){return this.run({from:t})}setBreakpoint(t,e=!0){e?this.breakpoints.add(t):this.breakpoints.delete(t)}toggleBreakpoint(t){this.breakpoints.has(t)?this.breakpoints.delete(t):this.breakpoints.add(t)}clearBreakpoints(){this.breakpoints.clear()}setStepMode(t){this._stepMode=!!t}stepOver(){if(this._resumeNext){const t=this._resumeNext;this._resumeNext=null,t()}}resume(){if(this._paused=!1,this._stepMode=!1,this._resumeNext){const t=this._resumeNext;this._resumeNext=null,t()}}isPaused(){return this._paused}_awaitContinue(t){return new Promise(e=>{this._paused=!0,this._emit("run:paused",{nodeId:t}),this._resumeNext=e})}registerSubflowFromFrame(t,e={}){const s=this.frames.find(e=>e.id===t);if(!s)throw new Error("frame not found");const i=[],o=this.w.nodeCount_();for(let t=0;t<o;t++)this.V.posX[t]>=s.x&&this.V.posX[t]<=s.x+s.w&&this.V.posY[t]>=s.y&&this.V.posY[t]<=s.y+s.h&&i.push(t);if(!i.length)throw new Error("frame is empty");const n=new Set(i),r=new Map,h=i.map((t,e)=>(r.set(t,e),{kind:this.kinds[this.V.kind[t]].name,x:this.V.posX[t]-s.x,y:this.V.posY[t]-s.y,w:this.V.sizeW[t],h:this.V.sizeH[t],title:this.titles.get(t),color:this.colors.get(t),params:this._nodeParams?.get(t)})),a=[],l=this.w.edgeCount_();for(let t=0;t<l;t++)n.has(this.V.edgeFromN[t])&&n.has(this.V.edgeToN[t])&&a.push({from:r.get(this.V.edgeFromN[t]),to:r.get(this.V.edgeToN[t]),fp:this.V.edgeFromP[t],tp:this.V.edgeToP[t]});const d=new Set,c=new Set;for(const t of a)d.add(t.to),c.add(t.from);const u=i.map((t,e)=>e).filter(t=>!d.has(t)),p=i.map((t,e)=>e).filter(t=>!c.has(t)),m=e.name||`subflow_${s.label||t}`.replace(/\s+/g,"_"),g=u.map(t=>{const e=i[t];return this.titles.get(e)||this.kinds[this.V.kind[e]].name}),f=p.map(t=>{const e=i[t];return this.titles.get(e)||this.kinds[this.V.kind[e]].name});this._subflows.set(m,{nodes:h,edges:a,inputs:u,outputs:p,inputLabels:g,outputLabels:f});const _=this;return this.registerKind({name:m,color:e.color||"#5be0d0",badge:e.badge||"Σ",w:180,h:90,nin:Math.max(1,u.length),nout:Math.max(1,p.length),shape:"rect",portIn:g,portOut:f,inputs:g.map(t=>({name:t,type:"any"})),outputs:f.map(t=>({name:t,type:"any"})),execute:async(t,e)=>{const s=_._subflows.get(m),i=new Map;for(let t=0;t<s.inputs.length;t++){const o=e[t]??e[`in${t}`]??e[s.inputLabels[t]];i.set(s.inputs[t],o)}const o=s.nodes.map(()=>0),n=s.nodes.map(()=>[]);for(const t of s.edges)o[t.to]++,n[t.from].push(t);const r=[];for(let t=0;t<s.nodes.length;t++)0===o[t]&&r.push(t);for(;r.length;){const e=r.shift(),h=s.nodes[e],a=_.kinds[_.kindByName.get(h.kind)];let l;if(i.has(e)||"function"!=typeof a?.execute)l=i.get(e);else{const o={};for(const t of s.edges)if(t.to===e&&i.has(t.from)){const e=i.get(t.from),s=e&&"object"==typeof e?e.value??e[t.fp]??e:e;o[`in${t.tp}`]=s,o[t.tp]=s}l=await a.execute({...t,params:h.params||{}},o),i.set(e,l)}for(const t of n[e])0===--o[t.to]&&r.push(t.to)}const h={};for(let t=0;t<s.outputs.length;t++){const e=i.get(s.outputs[t]),o=e&&"object"==typeof e&&"value"in e?e.value:e;h[t]=o,h[s.outputLabels[t]]=o}return h}}),m}runFrame(t){const e=this.frames.find(e=>e.id===t);if(!e)return Promise.resolve({executed:0,errors:[]});const s=new Set,i=this.w.nodeCount_();for(let t=0;t<i;t++)this.V.posX[t]>=e.x&&this.V.posX[t]<=e.x+e.w&&this.V.posY[t]>=e.y&&this.V.posY[t]<=e.y+e.h&&s.add(t);return this.run({filter:t=>s.has(t)})}stop(){this._runAbort&&this._runAbort.abort(),this._running=!1}isRunning(){return this._running}setNodeParams(t,e){this._nodeParams||(this._nodeParams=new Map),this._nodeParams.set(t,e)}getNodeParams(t){return this._nodeParams?.get(t)}startLoop(t=500){this._loopStop=!1;const e=async()=>{this._loopStop||(await this.run(),this._loopStop||setTimeout(e,t))};e()}stopLoop(){this._loopStop=!0,this.stop()}lockNode(t,e=!0){e?this.locked.add(t):this.locked.delete(t)}isLocked(t){return this.locked.has(t)}setReadOnly(t){this.readOnly=!!t}setReachableFrom(t){if(null==t||t<0)return void(this._reachableSet=null);const e=new Set([t]),s=[t],i=this.w.edgeCount_();for(;s.length;){const t=s.shift();for(let o=0;o<i;o++)this.V.edgeFromN[o]!==t||e.has(this.V.edgeToN[o])||(e.add(this.V.edgeToN[o]),s.push(this.V.edgeToN[o]))}this._reachableSet=e}clearReachable(){this._reachableSet=null}setRemoteCursor(t,e,s,i=t,o="#5be0d0"){null!==e?this.remoteCursors.set(t,{x:e,y:s,name:i,color:o,t:performance.now()}):this.remoteCursors.delete(t)}clearRemoteCursors(){this.remoteCursors.clear()}setEdgeWaypoints(t,e){e&&e.length?this._edgeWaypoints.set(t,e.map(t=>({x:t.x,y:t.y}))):this._edgeWaypoints.delete(t)}clearEdgeWaypoints(t){this._edgeWaypoints.delete(t)}toggleFrameCollapse(t){this.frameCollapsed.has(t)?this.frameCollapsed.delete(t):this.frameCollapsed.add(t),this._emit("change")}isFrameCollapsed(t){return this.frameCollapsed.has(t)}_nodeHiddenByCollapse(t){if(!this.frameCollapsed.size)return!1;for(const e of this.frameCollapsed){const s=this.frames[e];if(s&&(this.V.posX[t]>=s.x&&this.V.posX[t]<=s.x+s.w&&this.V.posY[t]>=s.y+26&&this.V.posY[t]<=s.y+s.h))return!0}return!1}makeDraggable(t,e){if(!t||!e||!e.kind)throw new Error("makeDraggable: spec.kind required");t.style.cursor="grab",t.addEventListener("mousedown",s=>{if(s.preventDefault(),this.readOnly)return;const i=t.cloneNode(!0);Object.assign(i.style,{position:"fixed",pointerEvents:"none",opacity:"0.75",zIndex:"900",transform:"translate(-50%,-50%) scale(1.02)"}),document.body.appendChild(i);const o=t=>{i.style.left=t.clientX+"px",i.style.top=t.clientY+"px"};o(s);const n=t=>{window.removeEventListener("mousemove",o),window.removeEventListener("mouseup",n),i.remove();const s=this.canvas.getBoundingClientRect();if(t.clientX<s.left||t.clientX>s.right||t.clientY<s.top||t.clientY>s.bottom)return;const r=this._s2w(t.clientX,t.clientY),h={...e,x:r.x,y:r.y};delete h.element;const a=this.addNode(h);this._emit("palette:drop",{id:a,x:r.x,y:r.y,spec:e})};window.addEventListener("mousemove",o),window.addEventListener("mouseup",n)})}setTheme(t){this._theme="light"===t?s:e,this.options.theme=t,this.options.background=this._theme.bg,this.canvas.style.background=this._theme.bg,this._emit("theme",t)}toggleTheme(){this.setTheme("light"===this.options.theme?"dark":"light")}pushNodeMetric(t,e){let s=this.metrics.get(t);s||(s={data:new Float32Array(this._metricCap),idx:0,count:0},this.metrics.set(t,s)),s.data[s.idx]=e,s.idx=(s.idx+1)%this._metricCap,s.count<this._metricCap&&s.count++;const i=this.metricMax.get(t)||1;this.metricMax.set(t,Math.max(.99*i,Math.abs(e),1))}clearNodeMetric(t){this.metrics.delete(t),this.metricMax.delete(t)}setEdgeAnimated(t,e){e?this.animatedEdges.add(t):this.animatedEdges.delete(t)}setAllEdgesAnimated(t){if(!t)return void this.animatedEdges.clear();const e=this.w.edgeCount_();for(let t=0;t<e;t++)this.animatedEdges.add(t)}setConnectionValidator(t){this._connValidator="function"==typeof t?t:null}registerTemplate(t,e){this._templates.set(t,e)}insertTemplate(t,e=0,s=0){const i=this._templates.get(t);return i?i(this,e,s):-1}listTemplates(){return[...this._templates.keys()]}search(t){if(this._searchQuery=(t||"").toLowerCase(),this._searchHits=[],!this._searchQuery)return[];const e=this.w.nodeCount_();for(let t=0;t<e;t++){const e=(this.titles.get(t)||"").toLowerCase(),s=(this.descriptions.get(t)||"").toLowerCase(),i=this.kinds[this.V.kind[t]].name.toLowerCase(),o=(this.tags.get(t)||[]).join(" ").toLowerCase();(e.includes(this._searchQuery)||s.includes(this._searchQuery)||i.includes(this._searchQuery)||o.includes(this._searchQuery))&&this._searchHits.push(t)}return this._searchHits.slice()}jumpToSearchHit(t){if(!this._searchHits.length)return;const e=this._searchHits[(t%this._searchHits.length+this._searchHits.length)%this._searchHits.length];this.clearSelection(),this.w.setSelected(e,1),this.panTo(this.V.posX[e],this.V.posY[e])}clearSearch(){this._searchQuery="",this._searchHits=[]}openCommandPalette(){if(this._cmdPaletteEl)return this._cmdPaletteEl.remove(),void(this._cmdPaletteEl=null);const t=this._builtinCommands(),e=document.createElement("div");e.style.cssText=`position:absolute;top:80px;left:50%;transform:translateX(-50%);width:480px;max-height:60vh;overflow:hidden;background:${this._theme.panel};border:1px solid ${this._theme.border};border-radius:10px;box-shadow:0 16px 48px rgba(0,0,0,0.6);z-index:500;color:${this._theme.fg};font-family:Inter, ui-sans-serif;`,e.innerHTML=`\n <input id="zf-cmd-q" type="text" placeholder="Type a command…" style="width:100%;padding:14px 16px;background:transparent;color:${this._theme.fg};border:0;border-bottom:1px solid ${this._theme.border};outline:none;font-size:14px;">\n <div id="zf-cmd-list" style="max-height:46vh;overflow:auto;"></div>`,this.container.appendChild(e),this._cmdPaletteEl=e;const s=e.querySelector("#zf-cmd-q"),i=e.querySelector("#zf-cmd-list");let o=0,n=t;const r=()=>{i.innerHTML=n.map((t,e)=>`\n <div data-i="${e}" style="padding:9px 16px;cursor:pointer;display:flex;justify-content:space-between;align-items:center;background:${e===o?this._theme.hi:"transparent"};">\n <span>${w(t.label)}</span>\n <span style="color:${this._theme.muted};font-family:ui-monospace,Consolas,monospace;font-size:11px;">${t.hotkey||""}</span>\n </div>`).join("")};r();const h=t=>{const e=n[t];e&&e.run(),this.openCommandPalette()};i.addEventListener("mousedown",t=>{const e=t.target.closest("[data-i]");e&&h(parseInt(e.dataset.i,10))}),s.addEventListener("input",()=>{const e=s.value.toLowerCase();n=e?t.filter(t=>t.label.toLowerCase().includes(e)):t,o=0,r()}),s.addEventListener("keydown",t=>{"ArrowDown"===t.code&&(o=Math.min(n.length-1,o+1),r(),t.preventDefault()),"ArrowUp"===t.code&&(o=Math.max(0,o-1),r(),t.preventDefault()),"Enter"===t.code&&h(o),"Escape"===t.code&&this.openCommandPalette()}),s.focus()}_builtinCommands(){return[{label:"Auto layout (Sugiyama)",hotkey:"L",run:()=>this.runAutoLayout()},{label:"Force layout",hotkey:"F",run:()=>this.runForceLayout()},{label:"Fit view",hotkey:"0",run:()=>this.fitView()},{label:"Toggle theme (light/dark)",hotkey:"Ctrl+T",run:()=>this.toggleTheme()},{label:"Toggle minimap",hotkey:"Ctrl+M",run:()=>this.setMinimap(!this.options.minimap)},{label:"Toggle edge animation",hotkey:"Ctrl+E",run:()=>this.setAllEdgesAnimated(0===this.animatedEdges.size)},{label:"Toggle edge style",hotkey:"",run:()=>this.setEdgeStyle("bezier"===this.options.edgeStyle?"orthogonal":"bezier")},{label:"Toggle snap-to-grid",hotkey:"G",run:()=>this.setSnapToGrid(!this.options.snapToGrid)},{label:"Toggle path highlight",hotkey:"",run:()=>this.setPathHighlight(!this._pathHighlightEnabled)},{label:"Toggle hover preview",hotkey:"",run:()=>this.setHoverPreview(!this.options.hoverPreview)},{label:"Find…",hotkey:"Ctrl+F",run:()=>this.openSearch()},{label:"Highlight critical path",hotkey:"",run:()=>{const t=this.criticalPath();for(const e of t)this.w.setEdgeSelected_(e,1)}},{label:"Find SCCs (cycle groups)",hotkey:"",run:()=>{const t=this.findSCCs();for(const e of t)for(const t of e)this.w.setSelected(t,1)}},{label:"Color nodes by degree",hotkey:"",run:()=>this.colorByDegree()},{label:"Clear node colors",hotkey:"",run:()=>this.clearNodeColors()},{label:"Group selection",hotkey:"Ctrl+G",run:()=>this.groupSelection()},{label:"Add sticky note",hotkey:"",run:()=>this.addNote(-this.cam.x,-this.cam.y)},{label:"Select all",hotkey:"Ctrl+A",run:()=>this.selectAll()},{label:"Duplicate selection",hotkey:"Ctrl+D",run:()=>this.duplicateSelection()},{label:"Delete selection",hotkey:"Del",run:()=>this.deleteSelection()},{label:"Export PNG",hotkey:"",run:async()=>{const t=await this.exportPNG();window.open(URL.createObjectURL(t))}},{label:"Export SVG",hotkey:"",run:()=>{const t=new Blob([this.exportSVG()],{type:"image/svg+xml"});window.open(URL.createObjectURL(t))}},{label:"Export JSON",hotkey:"",run:()=>{const t=new Blob([JSON.stringify(this.toJSON(),null,2)],{type:"application/json"});window.open(URL.createObjectURL(t))}},{label:"Undo",hotkey:"Ctrl+Z",run:()=>this.undo()},{label:"Redo",hotkey:"Ctrl+Y",run:()=>this.redo()},{label:"Run graph",hotkey:"F5",run:()=>this.run()},{label:"Stop run",hotkey:"Shift+F5",run:()=>this.stop()},{label:"Clear runtime state",hotkey:"",run:()=>this.clearRuntimeState()},...[...this._templates.keys()].map(t=>({label:`Insert template: ${t}`,hotkey:"",run:()=>this.insertTemplate(t,-this.cam.x,-this.cam.y)})),...(this._extraCommands||[]).map(t=>({label:t.label,hotkey:t.hotkey||"",run:t.run}))]}openSearch(){if(this._searchEl)return this._searchEl.remove(),this._searchEl=null,void this.clearSearch();const t=document.createElement("div");t.style.cssText=`position:absolute;top:14px;left:50%;transform:translateX(-50%);background:${this._theme.panel};color:${this._theme.fg};border:1px solid ${this._theme.border};border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:8px;z-index:500;font-family:Inter, ui-sans-serif;box-shadow:0 8px 24px rgba(0,0,0,0.4);`,t.innerHTML=`<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${this._theme.muted}" stroke-width="2"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>\n <input id="zf-s" type="text" placeholder="Find nodes…" style="background:transparent;border:0;outline:none;color:${this._theme.fg};font-size:13px;width:240px;">\n <span id="zf-sn" style="color:${this._theme.muted};font-size:11px;font-family:ui-monospace,Consolas,monospace;"></span>`,this.container.appendChild(t),this._searchEl=t;const e=t.querySelector("#zf-s"),s=t.querySelector("#zf-sn");let i=0;const o=()=>{const t=this.search(e.value);s.textContent=t.length?`${i+1}/${t.length}`:e.value?"0":"",t.length&&this.jumpToSearchHit(i)};e.addEventListener("input",()=>{i=0,o()}),e.addEventListener("keydown",t=>{"Enter"===t.code&&(i=(i+(t.shiftKey?-1:1)+this._searchHits.length)%Math.max(this._searchHits.length,1),o(),t.preventDefault()),"Escape"===t.code&&this.openSearch()}),e.focus()}setMinimap(t){this.options.minimap=!!t,t?this._setupMinimap():this._minimapEl&&(this._minimapEl.remove(),this._minimapEl=null,this._minimapCtx=null)}_setupMinimap(){if(this._minimapEl)return;const t=document.createElement("canvas");t.width=200*(window.devicePixelRatio||1),t.height=140*(window.devicePixelRatio||1),t.style.cssText=`position:absolute;right:14px;bottom:14px;width:200px;height:140px;background:${this._theme.panel};border:1px solid ${this._theme.border};border-radius:8px;cursor:pointer;z-index:50;box-shadow:0 4px 16px rgba(0,0,0,0.4);`,this.container.appendChild(t),t.addEventListener("mousedown",e=>{const s=t.getBoundingClientRect(),i=(e.clientX-s.left)/s.width,o=(e.clientY-s.top)/s.height,n=this._graphBounds();n&&(this.cam.x=-(n.minX+i*(n.maxX-n.minX)),this.cam.y=-(n.minY+o*(n.maxY-n.minY)))}),this._minimapEl=t,this._minimapCtx=t.getContext("2d",{alpha:!1})}_graphBounds(){const t=this.w.nodeCount_();if(0===t)return null;let e=1/0,s=-1/0,i=1/0,o=-1/0;for(let n=0;n<t;n++){const t=.5*this.V.sizeW[n],r=.5*this.V.sizeH[n];this.V.posX[n]-t<e&&(e=this.V.posX[n]-t),this.V.posX[n]+t>s&&(s=this.V.posX[n]+t),this.V.posY[n]-r<i&&(i=this.V.posY[n]-r),this.V.posY[n]+r>o&&(o=this.V.posY[n]+r)}const n=.1*(s-e)+40,r=.1*(o-i)+40;return{minX:e-n,maxX:s+n,minY:i-r,maxY:o+r}}_drawValueBubbles(){if(!this._valueBubbles.length)return;const t=performance.now(),e=this.ctx;for(let s=this._valueBubbles.length-1;s>=0;s--){const i=this._valueBubbles[s],o=(t-i.t0)/i.dur;if(o>=1){this._valueBubbles.splice(s,1);continue}const n=o<.15?o/.15:o>.7?(1-o)/.3:1,r=30*o,h=i.nodeId;if(h>=this.w.nodeCount_())continue;const a=this.V.posX[h],l=this.V.posY[h],d=.5*this.V.sizeH[h],c=this._w2s(a,l-d);e.save(),e.globalAlpha=n,e.font="600 12px ui-monospace, Consolas, monospace";const u=e.measureText(i.text).width+2*8,p=22,m=c.x-u/2,g=c.y-p-10-r;e.shadowColor="rgba(0,0,0,0.5)",e.shadowBlur=8,e.fillStyle="#161b27",this._roundRect(m,g,u,p,5),e.fill(),e.shadowBlur=0,e.strokeStyle="#5b8def",e.lineWidth=1.4,this._roundRect(m,g,u,p,5),e.stroke(),e.fillStyle="#5be0d0",e.textBaseline="middle",e.textAlign="center",e.fillText(i.text,c.x,g+p/2),e.fillStyle="#161b27",e.strokeStyle="#5b8def",e.beginPath(),e.moveTo(c.x-5,g+p),e.lineTo(c.x+5,g+p),e.lineTo(c.x,g+p+6),e.closePath(),e.fill(),e.stroke(),e.restore()}}_drawWaypoints(){for(const[t,e]of this._edgeWaypoints)for(const t of e){const e=this._w2s(t.x,t.y);this.ctx.fillStyle="#f0b93a",this.ctx.beginPath(),this.ctx.arc(e.x,e.y,5,0,2*Math.PI),this.ctx.fill(),this.ctx.strokeStyle="#0b0f17",this.ctx.lineWidth=1.2,this.ctx.stroke()}}_hitWaypoint(t,e){const s=8/this.cam.zoom;for(const[i,o]of this._edgeWaypoints)for(let n=0;n<o.length;n++)if(Math.hypot(o[n].x-t,o[n].y-e)<s)return{edgeIdx:i,wpIdx:n};return null}_drawRemoteCursors(){if(!this.remoteCursors.size)return;const t=performance.now();for(const[e,s]of this.remoteCursors){if(t-s.t>3e4){this.remoteCursors.delete(e);continue}const i=this._w2s(s.x,s.y),o=this.ctx;o.save(),o.fillStyle=s.color,o.beginPath(),o.moveTo(i.x,i.y),o.lineTo(i.x+12,i.y+4),o.lineTo(i.x+5,i.y+6),o.lineTo(i.x+4,i.y+13),o.closePath(),o.fill(),o.font="600 11px Inter, ui-sans-serif";const n=o.measureText(s.name).width;o.fillStyle=s.color,this._roundRect(i.x+12,i.y+12,n+12,16,4),o.fill(),o.fillStyle="#0b0f17",o.textBaseline="middle",o.fillText(s.name,i.x+18,i.y+20),o.restore()}}_getImage(t){let e=this._imageCache.get(t);return e||(e={img:new Image,ready:!1},e.img.crossOrigin="anonymous",e.img.onload=()=>{e.ready=!0},e.img.onerror=()=>{e.ready=!1},e.img.src=t,this._imageCache.set(t,e)),e}_drawMinimap(){if(!this._minimapEl||!this._minimapCtx)return;const t=this._minimapCtx,e=this._minimapEl.width,s=this._minimapEl.height;t.fillStyle=this._theme.panel,t.fillRect(0,0,e,s);const i=this._graphBounds();if(!i)return;const o=e/(i.maxX-i.minX),n=s/(i.maxY-i.minY),r=Math.min(o,n),h=.5*(e-r*(i.maxX-i.minX)),a=.5*(s-r*(i.maxY-i.minY)),l=this.w.nodeCount_();for(let e=0;e<l;e++){const s=this.kinds[this.V.kind[e]],o=.5*this.V.sizeW[e]*r,n=.5*this.V.sizeH[e]*r,l=h+(this.V.posX[e]-i.minX)*r,d=a+(this.V.posY[e]-i.minY)*r;t.fillStyle=this.colors.get(e)||s.color,t.fillRect(l-o,d-n,Math.max(2,2*o),Math.max(2,2*n))}const d=window.devicePixelRatio||1,c=this.canvas.width/d/this.cam.zoom,u=this.canvas.height/d/this.cam.zoom,p=h+(-this.cam.x-.5*c-i.minX)*r,m=a+(-this.cam.y-.5*u-i.minY)*r;t.strokeStyle=this._theme.accent,t.lineWidth=2,t.strokeRect(p,m,c*r,u*r)}setPathHighlight(t){this._pathHighlightEnabled=!!t,t||(this._focusedSet=null)}registerKind(t){const e=this.kinds.length,s={name:t.name??`custom${e}`,color:t.color??"#94a3b8",badge:t.badge??"C",w:t.w??140,h:t.h??60,nin:t.nin??1,nout:t.nout??1,shape:t.shape??"rect",html:!0===t.html,template:t.template||null,execute:"function"==typeof t.execute?t.execute:null,portIn:Array.isArray(t.portIn)?t.portIn.slice():null,portOut:Array.isArray(t.portOut)?t.portOut.slice():null,inputs:Array.isArray(t.inputs)?t.inputs.slice():null,outputs:Array.isArray(t.outputs)?t.outputs.slice():null,retry:t.retry||null};return this.kinds.push(s),this.kindByName.set(s.name,e),this._runOrder=null,e}addNote(t,e,s="",i={}){const o=[{fill:"rgba(254,249,195,0.94)",text:"#5b3d12",border:"#caa54a"},{fill:"rgba(252,231,243,0.94)",text:"#831843",border:"#db5895"},{fill:"rgba(220,252,231,0.94)",text:"#14532d",border:"#5cad75"},{fill:"rgba(219,234,254,0.94)",text:"#1e3a8a",border:"#5b8def"}],n=i.color||o[this.notes.length%o.length],r={id:++this._noteSeq,x:t,y:e,w:i.w||220,h:i.h||130,text:s,color:n};return this.notes.push(r),this._emit("change"),r.id}deleteNote(t){this.notes=this.notes.filter(e=>e.id!==t),this._emit("change")}addFrame(t,e,s,i,o="Group",n="#5b8def"){const r={id:++this._frameSeq,x:t,y:e,w:s,h:i,label:o,color:n};return this.frames.push(r),this._emit("change"),r.id}groupSelection(t){const e=this.getSelection();if(0===e.length)return-1;let s=1/0,i=-1/0,o=1/0,n=-1/0;for(const t of e){const e=.5*this.V.sizeW[t],r=.5*this.V.sizeH[t];this.V.posX[t]-e<s&&(s=this.V.posX[t]-e),this.V.posX[t]+e>i&&(i=this.V.posX[t]+e),this.V.posY[t]-r<o&&(o=this.V.posY[t]-r),this.V.posY[t]+r>n&&(n=this.V.posY[t]+r)}return this.addFrame(s-30,o-30-26,i-s+60,n-o+60+26,t||`Group ${this.frames.length+1}`)}deleteFrame(t){this.frames=this.frames.filter(e=>e.id!==t),this._emit("change")}enterSubflow(t){const e=this.frames.findIndex(e=>e.id===t);if(-1===e)return;this._focusFrame=e;const s=this.frames[e];this.cam.x=-(s.x+s.w/2),this.cam.y=-(s.y+s.h/2),this.cam.zoom=.9*Math.min(this.canvas.width/(s.w+80),this.canvas.height/(s.h+80)),this._emit("subflow",s.id)}exitSubflow(){-1!==this._focusFrame&&(this._focusFrame=-1,this.fitView(),this._emit("subflow",null))}_isInsideFocusFrame(t){if(-1===this._focusFrame)return!0;const e=this.frames[this._focusFrame];return this.V.posX[t]>=e.x&&this.V.posX[t]<=e.x+e.w&&this.V.posY[t]>=e.y&&this.V.posY[t]<=e.y+e.h}_resolveKind(t){if("number"==typeof t)return t;const e=this.kindByName.get(t);if(void 0===e)throw new Error(`zflow: unknown kind "${t}"`);return e}runAutoLayout(){const t=this.w.autoLayout();return this.w.snapshot(),this._emit("change"),t}runForceLayout(t=220){this._forceRaf&&cancelAnimationFrame(this._forceRaf),this.w.forceLayoutReset();let e=0;const s=()=>{this.w.forceLayoutTick(.05),e++,e<t?this._forceRaf=requestAnimationFrame(s):(this._forceRaf=null,this.w.snapshot(),this._emit("change"))};this._forceRaf=requestAnimationFrame(s)}fitView(t=80){const e=this.w.nodeCount_();if(0===e)return;let s=1/0,i=-1/0,o=1/0,n=-1/0;for(let t=0;t<e;t++){const e=.5*this.V.sizeW[t],r=.5*this.V.sizeH[t];this.V.posX[t]-e<s&&(s=this.V.posX[t]-e),this.V.posX[t]+e>i&&(i=this.V.posX[t]+e),this.V.posY[t]-r<o&&(o=this.V.posY[t]-r),this.V.posY[t]+r>n&&(n=this.V.posY[t]+r)}const r=i-s+2*t,h=n-o+2*t;this.cam.x=-(s+(i-s)/2),this.cam.y=-(o+(n-o)/2),this.cam.zoom=.85*Math.min(this.canvas.width/r,this.canvas.height/h)}zoomTo(t){this.cam.zoom=Math.max(.2,Math.min(3,t))}panTo(t,e){this.cam.x=-t,this.cam.y=-e}undo(){this.w.undo()&&this._emit("change")}redo(){this.w.redo()&&this._emit("change")}snapshot(){this.w.snapshot()}criticalPath(){const t=this.w.nodeCount_(),e=this.w.edgeCount_();if(0===t)return[];const s=new Uint32Array(t);for(let t=0;t<e;t++)s[this.V.edgeToN[t]]++;const i=[];for(let e=0;e<t;e++)0===s[e]&&i.push(e);const o=new Int32Array(t),n=new Int32Array(t);n.fill(-1);const r=this._buildAdj();let h=0;for(;h<i.length;){const t=i[h++];for(const e of r.get(t)||[])o[t]+1>o[e.to]&&(o[e.to]=o[t]+1,n[e.to]=e.edge),s[e.to]--,0===s[e.to]&&i.push(e.to)}let a=0;for(let e=1;e<t;e++)o[e]>o[a]&&(a=e);if(0===o[a])return[];const l=[];let d=a;for(;-1!==n[d];)l.push(n[d]),d=this.V.edgeFromN[n[d]];return l}findSCCs(){const t=this.w.nodeCount_(),e=this._buildAdj(),s=new Int32Array(t).fill(-1),i=new Int32Array(t),o=new Uint8Array(t),n=[],r=[];let h=0;for(let a=0;a<t;a++){if(-1!==s[a])continue;const t=[{v:a,child:0}];for(s[a]=h,i[a]=h++,n.push(a),o[a]=1;t.length;){const a=t[t.length-1],l=e.get(a.v)||[];if(a.child<l.length){const e=l[a.child++].to;-1===s[e]?(s[e]=h,i[e]=h++,n.push(e),o[e]=1,t.push({v:e,child:0})):o[e]&&s[e]<i[a.v]&&(i[a.v]=s[e])}else{if(i[a.v]===s[a.v]){const t=[];for(;n.length;){const e=n.pop();if(o[e]=0,t.push(e),e===a.v)break}t.length>=2&&r.push(t)}const e=a.v;t.pop(),t.length&&i[e]<i[t[t.length-1].v]&&(i[t[t.length-1].v]=i[e])}}}return r}colorByDegree(){const t=this.w.nodeCount_(),e=this.w.edgeCount_(),s=new Uint16Array(t);for(let t=0;t<e;t++)s[this.V.edgeFromN[t]]++,s[this.V.edgeToN[t]]++;let i=1;for(let e=0;e<t;e++)s[e]>i&&(i=s[e]);const o=["#3b5fc4","#5b8def","#5be0d0","#5bd17a","#f0b93a","#fb923c","#e8462b"],n=t=>{if(t<=0)return o[0];if(t>=1)return o[o.length-1];const e=t*(o.length-1),s=Math.floor(e),i=Math.min(o.length-1,s+1),n=e-s,r=y(o[s]),h=y(o[i]);return`rgb(${Math.round(r[0]*(1-n)+h[0]*n)},${Math.round(r[1]*(1-n)+h[1]*n)},${Math.round(r[2]*(1-n)+h[2]*n)})`};for(let e=0;e<t;e++)this.colors.set(e,n(s[e]/i));this._emit("change")}clearNodeColors(){this.colors.clear(),this._emit("change")}importMermaid(t){const e=k(t);if(!e||0===e.nodes.size)return 0;const s={rect:"process",rhombus:"decision",circle:"branch",round:"process",subroutine:"aggregator",default:"process"},i=new Map;let o=0;for(const[t,n]of e.nodes){const e=this.addNode({kind:s[n.shape]||"process",x:o%8*200-700,y:110*Math.floor(o/8),title:n.label});if(e<0)break;i.set(t,e),o++}for(const t of e.edges){const e=i.get(t.from),s=i.get(t.to);void 0!==e&&void 0!==s&&this.addEdge({from:e,to:s,label:t.label})}return this.runAutoLayout(),this.fitView(),e.nodes.size}importDot(t){const e=S(t);if(!e||0===e.nodes.size)return 0;const s=new Map;let i=0;for(const[t,o]of e.nodes){const e=this.addNode({kind:"process",x:i%8*200-700,y:110*Math.floor(i/8),title:o.label});if(e<0)break;s.set(t,e),i++}for(const t of e.edges){const e=s.get(t.from),i=s.get(t.to);if(void 0===e||void 0===i)continue;const o=this.addEdge({from:e,to:i});o>=0&&t.label&&this.setEdgeLabel(o,t.label)}return this.runAutoLayout(),this.fitView(),e.nodes.size}shortestPathSafe(t,e){return this.shortestPath(t,e)||[]}shortestPath(t,e){const s=this._buildAdj(),i=new Map;i.set(t,null);const o=[t];for(;o.length;){const t=o.shift();if(t===e)break;for(const e of s.get(t)||[])i.has(e.to)||(i.set(e.to,{from:t,edgeIdx:e.edge}),o.push(e.to))}if(!i.has(e))return[];const n=[];let r=e;for(;i.get(r);)n.push(i.get(r).edgeIdx),r=i.get(r).from;return n.reverse()}findCycles(){const t=this.w.nodeCount_(),e=new Uint8Array(t),s=new Set,i=this._buildAdj();for(let o=0;o<t;o++){if(0!==e[o])continue;const t=[{u:o,iter:(i.get(o)||[])[Symbol.iterator]()}];for(e[o]=1;t.length;){const o=t[t.length-1],n=o.iter.next();if(n.done){e[o.u]=2,t.pop();continue}const r=n.value;1===e[r.to]?s.add(r.edge):0===e[r.to]&&(e[r.to]=1,t.push({u:r.to,iter:(i.get(r.to)||[])[Symbol.iterator]()}))}}return[...s]}_ensureAdj(){if(!this._adjDirty&&this._nodeAdj)return;const t=this.w.nodeCount_(),e=this.w.edgeCount_(),s=new Array(t);for(let e=0;e<t;e++)s[e]=[];for(let i=0;i<e;i++){const e=this.V.edgeFromN[i],o=this.V.edgeToN[i];e<t&&s[e].push(i),o<t&&e!==o&&s[o].push(i)}this._nodeAdj=s,this._adjDirty=!1}_buildAdj(){const t=this.w.edgeCount_(),e=new Map;for(let s=0;s<t;s++){const t=this.V.edgeFromN[s];e.has(t)||e.set(t,[]),e.get(t).push({to:this.V.edgeToN[s],edge:s})}return e}toJSON(){const t=this.w.nodeCount_(),e=this.w.edgeCount_(),s=[];for(let e=0;e<t;e++){const t={id:e,kind:this.kinds[this.V.kind[e]].name,x:this.V.posX[e],y:this.V.posY[e],w:this.V.sizeW[e],h:this.V.sizeH[e],nin:this.V.nIn[e],nout:this.V.nOut[e]};this.titles.has(e)&&(t.title=this.titles.get(e)),this.colors.has(e)&&(t.color=this.colors.get(e)),this.descriptions.has(e)&&(t.description=this.descriptions.get(e)),this.tags.has(e)&&(t.tags=this.tags.get(e)),this.status.has(e)&&(t.status=this.status.get(e)),this.progress.has(e)&&(t.progress=this.progress.get(e)),this.data.has(e)&&(t.data=this.data.get(e)),s.push(t)}const i=[];for(let t=0;t<e;t++){const e={from:this.V.edgeFromN[t],fp:this.V.edgeFromP[t],to:this.V.edgeToN[t],tp:this.V.edgeToP[t]};this.edgeLabels.has(t)&&(e.label=this.edgeLabels.get(t)),i.push(e)}return{version:1,nodes:s,edges:i,camera:{...this.cam},edgeStyle:this.options.edgeStyle}}loadGraph(t={}){const e=Array.isArray(t.nodes)?t.nodes:[],s=Array.isArray(t.edges)?t.edges:[],i=new Map;return this.transaction(()=>{this.w.reset(),this.titles.clear(),this.colors.clear(),this.descriptions.clear(),this.tags.clear(),this.status.clear(),this.progress.clear(),this.edgeLabels.clear(),this.data.clear(),this.bookmarks.clear(),this.locked.clear(),this.breakpoints.clear(),this._values.clear?.();for(const t of e){const e=t.id,s=void 0!==e?{...t,data:{...t.data||{},__id:e}}:t,o=this.addNode(s);o<0||void 0!==e&&i.set(e,o)}for(const t of s){const e="number"==typeof t.from&&t.from<this.w.nodeCount_()?t.from:i.get(t.from),s="number"==typeof t.to&&t.to<this.w.nodeCount_()?t.to:i.get(t.to);void 0!==e&&void 0!==s&&this.addEdge({from:e,to:s,fp:t.fp,tp:t.tp,label:t.label})}}),this._gl&&this._gl.markAllDirty(),i}findNodeByUserId(t){const e=this.w.nodeCount_();for(let s=0;s<e;s++){const e=this.data.get(s);if(e&&e.__id===t)return s}return-1}loadJSON(t){this.w.reset(),this.titles.clear(),this.colors.clear(),this.descriptions.clear(),this.tags.clear(),this.status.clear(),this.progress.clear(),this.edgeLabels.clear(),this.data.clear();const e=new Map;for(const s of t.nodes||[]){const t=this.addNode({kind:s.kind,x:s.x,y:s.y,w:s.w,h:s.h,title:s.title,color:s.color,description:s.description,tags:s.tags,status:s.status,progress:s.progress,data:s.data});e.set(s.id??t,t)}for(const s of t.edges||[])this.addEdge({from:e.get(s.from)??s.from,fp:s.fp,to:e.get(s.to)??s.to,tp:s.tp,label:s.label});t.camera&&Object.assign(this.cam,t.camera),t.edgeStyle&&(this.options.edgeStyle=t.edgeStyle),this.w.snapshot(),this._emit("change")}async exportPNG(){return new Promise(t=>this.canvas.toBlob(t,"image/png"))}exportSVG(){const t=this.w.nodeCount_(),e=this.w.edgeCount_();if(0===t&&0===this.notes.length&&0===this.frames.length)return'<svg xmlns="http://www.w3.org/2000/svg"/>';let s=1/0,i=-1/0,o=1/0,n=-1/0;const r=(t,e,r,h)=>{t<s&&(s=t),r>i&&(i=r),e<o&&(o=e),h>n&&(n=h)};for(let e=0;e<t;e++){const t=.5*this.V.sizeW[e],s=.5*this.V.sizeH[e];r(this.V.posX[e]-t,this.V.posY[e]-s,this.V.posX[e]+t,this.V.posY[e]+s)}for(const t of this.frames)r(t.x,t.y,t.x+t.w,t.y+t.h);for(const t of this.notes)r(t.x,t.y,t.x+t.w,t.y+t.h);const h=i-s+80,a=n-o+80,l=[`<svg xmlns="http://www.w3.org/2000/svg" viewBox="${s-40} ${o-40} ${h} ${a}" width="${h}" height="${a}" style="background:${this.options.background}">`],d=[];for(let t=0;t<e;t++){const e=this.V.edgeFromN[t],s=this.V.edgeToN[t],i=this._portWorld(e,1,this.V.edgeFromP[t]),o=this._portWorld(s,0,this.V.edgeToP[t]),n=this.colors.get(e)||this.kinds[this.V.kind[e]].color,r=this.colors.get(s)||this.kinds[this.V.kind[s]].color;d.push(`<linearGradient id="zfg${t}" x1="${i.x}" y1="${i.y}" x2="${o.x}" y2="${o.y}" gradientUnits="userSpaceOnUse"><stop offset="0%" stop-color="${n}"/><stop offset="100%" stop-color="${r}"/></linearGradient>`)}d.length&&l.push(`<defs>${d.join("")}</defs>`);for(const t of this.frames){const e=u(t.color,.05),s=u(t.color,.45),i=u(t.color,.16);l.push(`<rect x="${t.x}" y="${t.y}" width="${t.w}" height="${t.h}" rx="12" fill="${e}" stroke="${s}" stroke-width="1.4" stroke-dasharray="8 4"/>`),l.push(`<rect x="${t.x}" y="${t.y}" width="${t.w}" height="26" rx="12" fill="${i}"/>`),l.push(`<text x="${t.x+10}" y="${t.y+17}" font-family="Inter, system-ui, sans-serif" font-size="12" font-weight="600" fill="${t.color}">${b(t.label||"")}</text>`)}for(const t of this.notes){const e=t.color&&t.color.fill||"#fef9c3",s=t.color&&t.color.border||"#caa54a",i=t.color&&t.color.text||"#5b3d12";if(l.push(`<rect x="${t.x}" y="${t.y}" width="${t.w}" height="${t.h}" rx="4" fill="${e}" stroke="${s}" stroke-width="1"/>`),t.text){const e=v(t.text,t.w-20,7),s=t.y+18;for(let o=0;o<e.length;o++)l.push(`<text x="${t.x+10}" y="${s+16*o}" font-family="Inter, system-ui, sans-serif" font-size="12" fill="${i}">${b(e[o])}</text>`)}}for(let t=0;t<e;t++){const e=this.V.edgeFromN[t],s=this.V.edgeToN[t],i=this._portWorld(e,1,this.V.edgeFromP[t]),o=this._portWorld(s,0,this.V.edgeToP[t]),n=0!==this.V.edgeSel[t],r=n?"#f0b93a":`url(#zfg${t})`,h=n?2.4:1.7;let a;if("orthogonal"===this.options.edgeStyle){const t=this._orthoPath(i,o);a=`M ${t[0].x} ${t[0].y} `+t.slice(1).map(t=>`L ${t.x} ${t.y}`).join(" ")}else{const t=o.x-i.x,e=o.y-i.y,s=Math.max(50,.5*Math.abs(t)+.4*Math.abs(e));a=`M ${i.x} ${i.y} C ${i.x+s} ${i.y} ${o.x-s} ${o.y} ${o.x} ${o.y}`}l.push(`<path d="${a}" stroke="${r}" stroke-width="${h}" fill="none" stroke-linejoin="round"/>`);const d=this.edgeLabels.get(t);if(d){const t=(i.x+o.x)/2,s=(i.y+o.y)/2,r=Math.max(20,6.5*d.length);l.push(`<rect x="${t-r/2-5}" y="${s-9}" width="${r+10}" height="16" rx="5" fill="#0b0f17" stroke="${n?"#f0b93a":u(this.colors.get(e)||this.kinds[this.V.kind[e]].color,.6)}" stroke-width="1"/>`),l.push(`<text x="${t}" y="${s+3}" font-family="ui-monospace, Consolas, monospace" font-size="10.5" font-weight="600" fill="#e6edf3" text-anchor="middle">${b(d)}</text>`)}}for(let e=0;e<t;e++){const t=this.kinds[this.V.kind[e]],s=this.colors.get(e)||t.color,i=this.V.posX[e]-this.V.sizeW[e]/2,o=this.V.posY[e]-this.V.sizeH[e]/2,n=this.V.sizeW[e],r=this.V.sizeH[e],h=0!==this.V.selected[e],a=h?"#f0b93a":s,d=h?2:1.4;if("diamond"===t.shape){const t=this.V.posX[e],s=this.V.posY[e];l.push(`<polygon points="${t},${o} ${i+n},${s} ${t},${o+r} ${i},${s}" fill="#161b27" stroke="${a}" stroke-width="${d}"/>`)}else if("ellipse"===t.shape)l.push(`<ellipse cx="${this.V.posX[e]}" cy="${this.V.posY[e]}" rx="${n/2}" ry="${r/2}" fill="#161b27" stroke="${a}" stroke-width="${d}"/>`);else if("hexagon"===t.shape){const t=this.V.posX[e],s=this.V.posY[e],h=n/2,c=.45*h;l.push(`<polygon points="${t-h+c},${o} ${t+h-c},${o} ${i+n},${s} ${t+h-c},${o+r} ${t-h+c},${o+r} ${i},${s}" fill="#161b27" stroke="${a}" stroke-width="${d}"/>`)}else l.push(`<rect x="${i}" y="${o}" width="${n}" height="${r}" rx="8" fill="#161b27" stroke="${a}" stroke-width="${d}"/>`),"rect"===t.shape&&l.push(`<path d="M ${i+8} ${o} L ${i+n-8} ${o} Q ${i+n} ${o} ${i+n} ${o+8} L ${i+n} ${o+22} L ${i} ${o+22} L ${i} ${o+8} Q ${i} ${o} ${i+8} ${o} Z" fill="${s}"/>`);const c=this.titles.get(e)||`${t.name} #${e}`,m="rect"===t.shape?o+14:o+r/2,g="rect"===t.shape?"#0b0f17":s;l.push(`<text x="${this.V.posX[e]}" y="${m}" font-family="Inter, system-ui, sans-serif" font-size="11" font-weight="600" text-anchor="middle" fill="${g}" dominant-baseline="middle">${b(c)}</text>`);const f=this.progress.get(e);if(void 0!==f&&f>0&&"rect"===t.shape){const t=o+r-5,e=i+8,h=n-16,a=3,d=h*Math.min(1,Math.max(0,f));l.push(`<rect x="${e}" y="${t}" width="${h}" height="${a}" fill="rgba(255,255,255,0.06)"/>`),l.push(`<rect x="${e}" y="${t}" width="${d}" height="${a}" fill="${s}"/>`)}const _=this.status.get(e);if(_&&"rect"===t.shape){const t=p[_]||"#8b95a7";l.push(`<circle cx="${i+n-12}" cy="${o+11}" r="3.5" fill="${t}"/>`)}const y=this.tags.get(e);if(y&&y.length){let t=i+8;const e=o+r-24,h=u(s,.18);for(const o of y){const r=6*o.length+12;if(t+r>i+n-8)break;l.push(`<rect x="${t}" y="${e}" width="${r}" height="14" rx="3" fill="${h}"/>`),l.push(`<text x="${t+r/2}" y="${e+7}" font-family="Inter, system-ui, sans-serif" font-size="9" text-anchor="middle" fill="${s}" dominant-baseline="middle">${b(o)}</text>`),t+=r+4}}const x=this.V.nIn[e],w=this.V.nOut[e];for(let t=0;t<x;t++){const e=o+r*((t+1)/(x+1));l.push(`<circle cx="${i}" cy="${e}" r="4.5" fill="${s}" stroke="#07090f" stroke-width="1.5"/>`)}for(let t=0;t<w;t++){const e=o+r*((t+1)/(w+1));l.push(`<circle cx="${i+n}" cy="${e}" r="4.5" fill="${s}" stroke="#07090f" stroke-width="1.5"/>`)}}return l.push("</svg>"),l.join("\n")}on(t,e){return this.listeners.has(t)||this.listeners.set(t,[]),this.listeners.get(t).push(e),()=>{const s=this.listeners.get(t),i=s.indexOf(e);i>=0&&s.splice(i,1)}}_emit(t,...e){if(this._suspendEvents)return;const s=this.listeners.get(t);if(s)for(const t of s.slice())try{t(...e)}catch(t){console.error(t)}}_resize(){const t=window.devicePixelRatio||1,e=this.container.getBoundingClientRect();this.canvas.width=Math.floor(e.width*t),this.canvas.height=Math.floor(e.height*t),this.canvas.style.width=e.width+"px",this.canvas.style.height=e.height+"px"}_w2s(t,e){return{x:this.canvas.width/2+(t+this.cam.x)*this.cam.zoom,y:this.canvas.height/2+(e+this.cam.y)*this.cam.zoom}}_s2w(t,e){const s=window.devicePixelRatio||1,i=this.canvas.getBoundingClientRect(),o=(t-i.left)*s,n=(e-i.top)*s;return{x:(o-this.canvas.width/2)/this.cam.zoom-this.cam.x,y:(n-this.canvas.height/2)/this.cam.zoom-this.cam.y}}worldToScreen(t,e){return this._w2s(t,e)}screenToWorld(t,e){return this._s2w(t,e)}getCamera(){return{x:this.cam.x,y:this.cam.y,zoom:this.cam.zoom}}getNodePosition(t){return t<0||t>=this.w.nodeCount_()?null:{x:this.V.posX[t],y:this.V.posY[t],w:this.V.sizeW[t],h:this.V.sizeH[t]}}startEditTitle(t){t>=0&&t<this.w.nodeCount_()&&this._startEditingTitle(t)}_attachEvents(){const t=this.canvas;t.addEventListener("contextmenu",t=>t.preventDefault()),t.addEventListener("mousedown",t=>{this._hideMenu(),this._editingNoteEl&&-1!==this._editingNote&&this._editingNoteEl.blur(),this._editingTitleEl&&-1!==this._editingTitle&&this._editingTitleEl.blur();const e=this._s2w(t.clientX,t.clientY);if(2===t.button)return void this._onRightClick(t,e);if(1===t.button)return void this._startPan(t);const s=this.w.hitTestPort(e.x,e.y,11);if(-1!==s){const t=s>>>24&255,i=s>>>16&255,o=65535&s;return this._mode="connecting",this._edgeStart={nodeId:o,side:t,idx:i},this._edgeCursor=e,void(this.canvas.style.cursor="crosshair")}const i=this._hitHandle(e.x,e.y);if(i&&!this.readOnly&&!this.locked.has(i.nodeId))return this._mode="resize",void(this._resizingHandle={...i,lastX:e.x,lastY:e.y});const o=this._hitWaypoint(e.x,e.y);if(o&&!this.readOnly)return this._draggingWaypoint=o,void(this._mode="drag-waypoint");const n=this._hitFrameCorner(e.x,e.y);if(n)return this._mode="resize-frame",void(this._resizingFrame={...n,lastX:e.x,lastY:e.y});const r=this._hitFrameHeader(e.x,e.y);if(-1!==r)return this._mode="drag-frame",this._draggingFrame=r,void(this._frameDragLast=e);const h=this._hitNote(e.x,e.y);if(-1!==h)return this._mode="drag-note",this._draggingNote=h,void(this._noteDragLast=e);const a=this._hitTaskCheckbox(e.x,e.y);if(a){const t=this.tasks.get(a.nodeId);if(t&&t[a.taskIdx]){t[a.taskIdx].done=!t[a.taskIdx].done;const e=t.filter(t=>t.done).length;this.progress.set(a.nodeId,e/t.length),this._emit("change")}return}const l=this.w.hitTestNode(e.x,e.y);if(-1!==l)return t.shiftKey||0!==this.V.selected[l]?t.shiftKey&&this.w.toggleSelected(l):(this.w.clearSelection(),this.w.setSelected(l,1)),this.readOnly||this.locked.has(l)||(this._mode="drag",this._dragLast=e),void this._emit("select",this.getSelection());const d=this._hitTestEdge(e.x,e.y,6/this.cam.zoom);return-1!==d?(t.shiftKey||this.w.clearSelection(),this.w.setEdgeSelected(d,1),void this._emit("select",this.getSelection())):t.altKey?(t.shiftKey||this.w.clearSelection(),this._mode="lasso",void(this._lasso=[{x:e.x,y:e.y}])):(t.shiftKey||this.w.clearSelection(),this._mode="marquee",void(this._marquee={x0:e.x,y0:e.y,x1:e.x,y1:e.y}))}),t.addEventListener("mousemove",e=>{const s=this._s2w(e.clientX,e.clientY);if("pan"===this._mode){const t=window.devicePixelRatio||1,s=(e.clientX-this._dragStart.sx)*t/this.cam.zoom,i=(e.clientY-this._dragStart.sy)*t/this.cam.zoom;this.cam.x+=s,this.cam.y+=i;const o=performance.now(),n=Math.max(1,o-(this._panVel.lastTs||o))/1e3;return this._panVel.x=s/n,this._panVel.y=i/n,this._panVel.lastTs=o,this._dragStart.sx=e.clientX,void(this._dragStart.sy=e.clientY)}if("resize"===this._mode&&this._resizingHandle){const t=s.x-this._resizingHandle.lastX,e=s.y-this._resizingHandle.lastY;return this._applyResize(this._resizingHandle.corner,t,e),this._resizingHandle.lastX=s.x,void(this._resizingHandle.lastY=s.y)}if("drag-waypoint"===this._mode&&this._draggingWaypoint){const{edgeIdx:t,wpIdx:e}=this._draggingWaypoint,i=this._edgeWaypoints.get(t);return void(i&&i[e]&&(i[e].x=s.x,i[e].y=s.y))}if("drag"===this._mode){if(this._gl){this._ensureAdj();for(let t=0;t<this.w.nodeCount_();t++)if(this.V.selected[t]){this._gl.markNodeDirty(t);const e=this._nodeAdj[t];if(e)for(let t=0;t<e.length;t++)this._gl.markEdgeDirty(e[t])}}let t=s.x-this._dragLast.x,e=s.y-this._dragLast.y;if(this.options.snapToGrid){for(let s=0;s<this.w.nodeCount_();s++)if(this.V.selected[s]){const i=this.options.gridSize,o=Math.round((this.V.posX[s]+t)/i)*i,n=Math.round((this.V.posY[s]+e)/i)*i;t=o-this.V.posX[s],e=n-this.V.posY[s];break}this._alignGuides=null}else{const s=this._computeAlignSnap(t,e);t+=s.dx,e+=s.dy,this._alignGuides={v:null!==s.guideX?[s.guideX]:[],h:null!==s.guideY?[s.guideY]:[]}}return this.w.moveSelectedBy(t,e),void(this._dragLast={x:this._dragLast.x+t,y:this._dragLast.y+e})}if("drag-frame"===this._mode){const t=s.x-this._frameDragLast.x,e=s.y-this._frameDragLast.y,i=this.frames[this._draggingFrame];i.x+=t,i.y+=e;for(let s=0;s<this.w.nodeCount_();s++)this.V.posX[s]>=i.x&&this.V.posX[s]<=i.x+i.w&&this.V.posY[s]>=i.y&&this.V.posY[s]<=i.y+i.h&&(this.V.posX[s]+=t,this.V.posY[s]+=e);return void(this._frameDragLast=s)}if("resize-frame"===this._mode&&this._resizingFrame){const t=s.x-this._resizingFrame.lastX,e=s.y-this._resizingFrame.lastY;return this._applyFrameResize(this._resizingFrame.idx,this._resizingFrame.corner,t,e),this._resizingFrame.lastX=s.x,void(this._resizingFrame.lastY=s.y)}if("drag-note"===this._mode){const t=s.x-this._noteDragLast.x,e=s.y-this._noteDragLast.y,i=this.notes[this._draggingNote];return i.x+=t,i.y+=e,void(this._noteDragLast=s)}if("connecting"===this._mode)return void(this._edgeCursor=s);if("lasso"===this._mode&&this._lasso){const t=this._lasso[this._lasso.length-1];return void(Math.hypot(s.x-t.x,s.y-t.y)>6/this.cam.zoom&&this._lasso.push({x:s.x,y:s.y}))}if("marquee"===this._mode)return this._marquee.x1=s.x,this._marquee.y1=s.y,void this.w.selectInRect(this._marquee.x0,this._marquee.y0,this._marquee.x1,this._marquee.y1,1);const i=this.w.hitTestNode(s.x,s.y);i!==this._hoveredNode&&(this._hoveredNode=i,this._hoveredNodeSince=performance.now(),this._lastFocusComputed=-2),this._hoveredEdge=-1===i?this._hitTestEdge(s.x,s.y,6/this.cam.zoom):-1;const o=this._hitHandle(s.x,s.y);t.style.cursor=o?a[o.corner]:""}),t.addEventListener("mouseup",()=>{if("connecting"===this._mode&&this._edgeCursor){const t=this.w.hitTestPort(this._edgeCursor.x,this._edgeCursor.y,14);if(-1!==t){const e=t>>>16&255,s=65535&t;if((t>>>24&255)!==this._edgeStart.side&&s!==this._edgeStart.nodeId){const t=1===this._edgeStart.side?this._edgeStart.nodeId:s,i=1===this._edgeStart.side?this._edgeStart.idx:e,o=0===this._edgeStart.side?this._edgeStart.nodeId:s,n=0===this._edgeStart.side?this._edgeStart.idx:e,r=this.validateConnection(t,i,o,n);null===r?this.addEdge({from:t,fp:i,to:o,tp:n}):(this._emit("connection:rejected",{fromN:t,fromP:i,toN:o,toP:n,reason:r}),this._flashReject={x:this._edgeCursor.x,y:this._edgeCursor.y,msg:r,t0:performance.now()})}}}else if("lasso"===this._mode&&this._lasso&&this._lasso.length>2){for(let t=0;t<this.w.nodeCount_();t++)x(this.V.posX[t],this.V.posY[t],this._lasso)&&this.w.setSelected(t,1);this._emit("select",this.getSelection())}else"drag-waypoint"===this._mode?(this._draggingWaypoint=null,this._emit("change")):"drag"!==this._mode&&"resize"!==this._mode&&"drag-frame"!==this._mode&&"resize-frame"!==this._mode&&"drag-note"!==this._mode&&"marquee"!==this._mode||("marquee"!==this._mode&&(this.w.snapshot(),this._emit("change")),this._emit("select",this.getSelection()));this._mode="idle",this._edgeStart=null,this._edgeCursor=null,this._marquee=null,this._lasso=null,this._alignGuides=null,this._resizingHandle=null,this._resizingFrame=null,this._draggingFrame=-1,this._draggingNote=-1,this.canvas.classList.remove("panning"),this.canvas.style.cursor=""});const e=new Map;let s=null,i=null;this._pointerSynthesizing=!1,t.addEventListener("pointerdown",o=>{if("mouse"!==o.pointerType)if(t.setPointerCapture(o.pointerId),e.set(o.pointerId,{x:o.clientX,y:o.clientY}),2===e.size)s=m(e),this._mode="pinch";else if(1===e.size){const e=o.clientX,s=o.clientY;i=setTimeout(()=>{i=null;const t=this._s2w(e,s);this._onRightClick({clientX:e,clientY:s,preventDefault(){}},t)},550),this._pointerSynthesizing=!0,t.dispatchEvent(new MouseEvent("mousedown",{clientX:e,clientY:s,button:0,bubbles:!0})),this._pointerSynthesizing=!1}}),t.addEventListener("pointermove",o=>{if("mouse"!==o.pointerType&&e.has(o.pointerId))if(e.set(o.pointerId,{x:o.clientX,y:o.clientY}),2===e.size&&s){const t=m(e),i=t.dist/s.dist,o=this._s2w(t.mid.x,t.mid.y);this.cam.zoom=Math.max(.2,Math.min(3,this.cam.zoom*i));const n=this._s2w(t.mid.x,t.mid.y);this.cam.x+=n.x-o.x,this.cam.y+=n.y-o.y;const r=window.devicePixelRatio||1;this.cam.x+=(t.mid.x-s.mid.x)*r/this.cam.zoom,this.cam.y+=(t.mid.y-s.mid.y)*r/this.cam.zoom,s=t}else 1===e.size&&(i&&Math.hypot(o.movementX||0,o.movementY||0)>4&&(clearTimeout(i),i=null),this._pointerSynthesizing=!0,t.dispatchEvent(new MouseEvent("mousemove",{clientX:o.clientX,clientY:o.clientY,button:0,bubbles:!0})),this._pointerSynthesizing=!1)});const o=o=>{"mouse"!==o.pointerType&&(e.delete(o.pointerId),i&&(clearTimeout(i),i=null),e.size<2&&(s=null,"pinch"===this._mode&&(this._mode="idle")),0===e.size&&(this._pointerSynthesizing=!0,t.dispatchEvent(new MouseEvent("mouseup",{clientX:o.clientX,clientY:o.clientY,button:0,bubbles:!0})),this._pointerSynthesizing=!1))};t.addEventListener("pointerup",o),t.addEventListener("pointercancel",o),t.addEventListener("wheel",t=>{t.preventDefault();const e=t.ctrlKey;if(e||1===t.deltaMode){const s=this._s2w(t.clientX,t.clientY);this.cam.zoom=Math.max(.2,Math.min(3,this.cam.zoom*Math.exp(-t.deltaY*(e?.012:.05))));const i=this._s2w(t.clientX,t.clientY);return this.cam.x+=i.x-s.x,void(this.cam.y+=i.y-s.y)}const s=window.devicePixelRatio||1;this.cam.x-=t.deltaX*s/this.cam.zoom,this.cam.y-=t.deltaY*s/this.cam.zoom},{passive:!1}),t.addEventListener("dblclick",t=>{const e=this._s2w(t.clientX,t.clientY),s=this._hitFrameHeader(e.x,e.y);if(-1!==s)return void this.enterSubflow(this.frames[s].id);const i=this._hitNote(e.x,e.y);if(-1!==i)return void this._startEditingNote(i);const o=this.w.hitTestNode(e.x,e.y);if(-1!==o)return!1!==this.options.dblclickEditsTitle&&this._startEditingTitle(o),void this._emit("node:dblclick",o);const n=this._hitTestEdge(e.x,e.y,6/this.cam.zoom);-1===n?this._emit("canvas:dblclick",e):this._emit("edge:dblclick",n)})}_startPan(t){this._mode="pan",this._dragStart={sx:t.clientX,sy:t.clientY},this._panVel.x=0,this._panVel.y=0,this._panVel.lastTs=performance.now(),this.canvas.style.cursor="grabbing"}_attachKeyboard(){const t=t=>{if(!(this.container.contains(document.activeElement)||document.activeElement===document.body))return;const e=document.activeElement;if(e&&("INPUT"===e.tagName||"TEXTAREA"===e.tagName))return;const s=t.ctrlKey||t.metaKey;if("Delete"!==t.code&&"Backspace"!==t.code){if(s&&"KeyZ"===t.code&&!t.shiftKey)return this.undo(),void t.preventDefault();if(s&&("KeyY"===t.code||"KeyZ"===t.code&&t.shiftKey))return this.redo(),void t.preventDefault();if(s&&"KeyA"===t.code)return this.selectAll(),void t.preventDefault();if(s&&"KeyD"===t.code)return this.duplicateSelection(),void t.preventDefault();if(s&&"KeyC"===t.code)return this._copy(),void t.preventDefault();if(s&&"KeyV"===t.code)return this._paste(),void t.preventDefault();if(s&&"KeyG"===t.code)return this.groupSelection(),void t.preventDefault();if(s&&"BracketRight"===t.code)return this.bringToFront(),void t.preventDefault();if(s&&"BracketLeft"===t.code)return this.sendToBack(),void t.preventDefault();if(s&&"KeyK"===t.code)return this.openCommandPalette(),void t.preventDefault();if(s&&"KeyF"===t.code&&this.options.search)return this.openSearch(),void t.preventDefault();if(s&&"KeyT"===t.code)return this.toggleTheme(),void t.preventDefault();if(s&&"KeyM"===t.code)return this.setMinimap(!this.options.minimap),void t.preventDefault();if(s&&"KeyE"===t.code)return this.setAllEdgesAnimated(0===this.animatedEdges.size),void t.preventDefault();if(!s&&"Digit0"===t.code)return this.fitView(),void t.preventDefault();if(!s&&"KeyL"===t.code&&!this._editingTitle&&-1===this._editingNote)return this.runAutoLayout(),void t.preventDefault();if("F5"===t.code&&!t.shiftKey)return this.run(),void t.preventDefault();if("F5"===t.code&&t.shiftKey)return this.stop(),void t.preventDefault();if("Tab"===t.code&&!s){const e=this.w.nodeCount_();if(0===e)return;let s=this.getSelection()[0]??-1,i=t.shiftKey?s-1:s+1;return-1===s&&(i=0),i<0&&(i=e-1),i>=e&&(i=0),this.clearSelection(),this.w.setSelected(i,1),this.panTo(this.V.posX[i],this.V.posY[i]),void t.preventDefault()}if(!s&&/^Digit[1-9]$/.test(t.code)){const e=parseInt(t.code.slice(5),10);return t.altKey?this.jumpBookmark(e):this.setBookmark(e),void t.preventDefault()}if("Escape"===t.code)return"connecting"===this._mode?(this._mode="idle",this._edgeStart=null,this._edgeCursor=null,void(this.canvas.style.cursor="")):-1!==this._focusFrame?void this.exitSubflow():(this.clearSelection(),void this._hideMenu());if(t.code.startsWith("Arrow")){const e=t.shiftKey?1:10,s="ArrowLeft"===t.code?-e:"ArrowRight"===t.code?e:0,i="ArrowUp"===t.code?-e:"ArrowDown"===t.code?e:0;this.getSelection().length>0&&(this.w.moveSelectedBy(s,i),this._nudgeTimer&&clearTimeout(this._nudgeTimer),this._nudgeTimer=setTimeout(()=>{this.w.snapshot(),this._emit("change")},400),t.preventDefault())}}else this.deleteSelection()>0&&t.preventDefault()};window.addEventListener("keydown",t),this._keyHandler=t}_copy(){const t=this.getSelection();if(0===t.length)return;const e=new Set(t),s=t.map(t=>({origId:t,kind:this.kinds[this.V.kind[t]].name,x:this.V.posX[t],y:this.V.posY[t],w:this.V.sizeW[t],h:this.V.sizeH[t],title:this.titles.get(t),color:this.colors.get(t),description:this.descriptions.get(t),tags:this.tags.get(t),status:this.status.get(t),progress:this.progress.get(t),data:this.data.get(t)})),i=[];for(let t=0;t<this.w.edgeCount_();t++)e.has(this.V.edgeFromN[t])&&e.has(this.V.edgeToN[t])&&i.push({from:this.V.edgeFromN[t],fp:this.V.edgeFromP[t],to:this.V.edgeToN[t],tp:this.V.edgeToP[t],label:this.edgeLabels.get(t)});let o=1/0,n=1/0;for(const t of s)t.x<o&&(o=t.x),t.y<n&&(n=t.y);this._clipboard={nodes:s,edges:i,anchor:{x:o,y:n}}}_paste(){if(!this._clipboard)return;const t=this._clipboard,e=-this.cam.x,s=-this.cam.y,i=e-t.anchor.x,o=s-t.anchor.y,n=new Map;this.clearSelection();for(const e of t.nodes){const t=this.addNode({kind:e.kind,x:e.x+i,y:e.y+o,w:e.w,h:e.h,title:e.title,color:e.color,description:e.description,tags:e.tags,status:e.status,progress:e.progress,data:e.data});n.set(e.origId,t),this.w.setSelected(t,1)}for(const e of t.edges){const t=n.get(e.from),s=n.get(e.to);void 0!==t&&void 0!==s&&this.addEdge({from:t,fp:e.fp,to:s,tp:e.tp,label:e.label})}this._clipboard={...t,anchor:{x:t.anchor.x-24,y:t.anchor.y-24}},this.w.snapshot(),this._emit("change")}_hitFrameHeader(t,e){for(let s=this.frames.length-1;s>=0;s--){const i=this.frames[s];if(!(t<i.x||t>i.x+i.w)&&!(e<i.y||e>i.y+26))return s}return-1}_hitFrameCorner(t,e){const s=14/this.cam.zoom;for(let i=this.frames.length-1;i>=0;i--){const o=this.frames[i],n={tl:{x:o.x,y:o.y},tr:{x:o.x+o.w,y:o.y},bl:{x:o.x,y:o.y+o.h},br:{x:o.x+o.w,y:o.y+o.h}};for(const o of["br","bl","tr","tl"]){const r=n[o];if(Math.abs(t-r.x)<s&&Math.abs(e-r.y)<s)return{idx:i,corner:o}}}return null}_applyFrameResize(t,e,s,i){const o=this.frames[t];"br"===e&&(o.w+=s,o.h+=i),"bl"===e&&(o.x+=s,o.w-=s,o.h+=i),"tr"===e&&(o.w+=s,o.y+=i,o.h-=i),"tl"===e&&(o.x+=s,o.w-=s,o.y+=i,o.h-=i),o.w<120&&("bl"!==e&&"tl"!==e||(o.x-=120-o.w),o.w=120),o.h<80&&("tl"!==e&&"tr"!==e||(o.y-=80-o.h),o.h=80)}_hitNote(t,e){for(let s=this.notes.length-1;s>=0;s--){const i=this.notes[s];if(t>=i.x&&t<=i.x+i.w&&e>=i.y&&e<=i.y+i.h)return s}return-1}_hitTaskCheckbox(t,e){for(let s=this.w.nodeCount_()-1;s>=0;s--){const i=this.tasks.get(s);if(!i||!i.length)continue;const o=this.V.posX[s],n=this.V.posY[s],r=.5*this.V.sizeW[s],h=.5*this.V.sizeH[s];if(t<o-r||t>o+r||e<n-h||e>n+h)continue;const a=o-r+8;let l=n-h+32;this.descriptions.get(s)&&(l+=30);const d=14,c=10;for(let o=0;o<i.length;o++){if(t>=a&&t<=a+c&&e>=l&&e<=l+c)return{nodeId:s,taskIdx:o};if(l+=d,l>n+h-6)break}}return null}_hitHandle(t,e){const s=this.getSelection();if(1!==s.length)return null;const o=s[0],n=this.V.posX[o],r=this.V.posY[o],h=.5*this.V.sizeW[o],a=.5*this.V.sizeH[o],l=6/this.cam.zoom,d={tl:{x:n-h,y:r-a},t:{x:n,y:r-a},tr:{x:n+h,y:r-a},r:{x:n+h,y:r},br:{x:n+h,y:r+a},b:{x:n,y:r+a},bl:{x:n-h,y:r+a},l:{x:n-h,y:r}};for(const s of i){const i=d[s];if(Math.abs(t-i.x)<l&&Math.abs(e-i.y)<l)return{nodeId:o,corner:s}}return null}_applyResize(t,e,s){const i=this._resizingHandle.nodeId;let a=this.V.sizeW[i],l=this.V.sizeH[i],d=0,c=0;o.has(t)&&(a-=e,d=.5*e),n.has(t)&&(a+=e,d=.5*e),r.has(t)&&(l-=s,c=.5*s),h.has(t)&&(l+=s,c=.5*s),a<60&&(a=60,d=0),l<60&&(l=60,c=0),this.V.sizeW[i]=a,this.V.sizeH[i]=l,this.V.posX[i]+=d,this.V.posY[i]+=c}_computeAlignSnap(t,e){const s=this.w.nodeCount_(),i=[],o=[];for(let t=0;t<s;t++){if(this.V.selected[t])continue;const e=this.V.posX[t],s=this.V.posY[t],n=.5*this.V.sizeW[t],r=.5*this.V.sizeH[t];i.push(e,e-n,e+n),o.push(s,s-r,s+r)}let n=0,r=0,h=null,a=null,l=7,d=7;for(let c=0;c<s;c++){if(!this.V.selected[c])continue;const s=this.V.posX[c]+t,u=this.V.posY[c]+e;for(const t of i){const e=s-t;Math.abs(e)<l&&(l=Math.abs(e),n=-e,h=t)}for(const t of o){const e=u-t;Math.abs(e)<d&&(d=Math.abs(e),r=-e,a=t)}}return{dx:l<=6?n:0,dy:d<=6?r:0,guideX:h,guideY:a}}_hitTestEdge(t,e,s){const i=s*s,o=this.w.edgeCount_();let n=-1,r=i;for(let i=0;i<o;i++){const o=this._portWorld(this.V.edgeFromN[i],1,this.V.edgeFromP[i]),h=this._portWorld(this.V.edgeToN[i],0,this.V.edgeToP[i]),a=Math.min(o.x,h.x)-s,l=Math.max(o.x,h.x)+s,u=Math.min(o.y,h.y)-s-80,p=Math.max(o.y,h.y)+s+80;if(!(t<a||t>l||e<u||e>p))if("orthogonal"===this.options.edgeStyle){const s=this._orthoPath(o,h);for(let o=0;o<s.length-1;o++){const h=c(t,e,s[o].x,s[o].y,s[o+1].x,s[o+1].y);h<r&&(r=h,n=i)}}else{const s=h.x-o.x,a=h.y-o.y,l=Math.max(50,.5*Math.abs(s)+.4*Math.abs(a));for(let s=0;s<=16;s++){const a=d(s/16,o.x,o.y,o.x+l,o.y,h.x-l,h.y,h.x,h.y),c=a.x-t,u=a.y-e,p=c*c+u*u;p<r&&(r=p,n=i)}}}return n}_onRightClick(t,e){if(!this.options.contextMenu)return;const s=this.w.hitTestNode(e.x,e.y),i=-1===s?this._hitTestEdge(e.x,e.y,6/this.cam.zoom):-1;let o;if(-1!==s)0===this.V.selected[s]&&(this.w.clearSelection(),this.w.setSelected(s,1)),o=[{label:"Duplicate",kbd:"Ctrl+D",fn:()=>this.duplicateSelection()},{label:"Delete",kbd:"Del",danger:!0,fn:()=>this.deleteSelection()},{sep:!0},{label:"Deselect",kbd:"Esc",fn:()=>this.clearSelection()}];else if(-1!==i){const t=this.V.edgeFromN[i],e=this.V.edgeToN[i];o=[{label:"Select endpoints",fn:()=>{this.clearSelection(),this.w.setSelected(t,1),this.w.setSelected(e,1),this._emit("select",this.getSelection())}},{label:"Set label…",fn:()=>{const t=prompt("Edge label",this.edgeLabels.get(i)||"");null!==t&&this.setEdgeLabel(i,t)}},{sep:!0},{label:"Delete edge",danger:!0,fn:()=>{this.w.deleteEdge(i),this.edgeLabels.delete(i),this.w.snapshot(),this._emit("change")}}]}else o=[{label:"Add Process node here",fn:()=>this.addNode({kind:"process",x:e.x,y:e.y})},{sep:!0},{label:"Select all",kbd:"Ctrl+A",fn:()=>this.selectAll()},{label:"Auto-layout",fn:()=>this.runAutoLayout()},{label:"Fit view",fn:()=>this.fitView()}];this._showMenu(t.clientX,t.clientY,o)}_startEditingTitle(t){if(this._editingTitle=t,!this._editingTitleEl){const t=document.createElement("input");t.type="text",Object.assign(t.style,{position:"absolute",background:"#161b27",color:"#e6edf3",border:"1px solid #f0b93a",borderRadius:"4px",fontFamily:"Inter, ui-sans-serif",fontSize:"12px",fontWeight:"600",padding:"4px 8px",outline:"none",zIndex:"300",boxShadow:"0 4px 12px rgba(0,0,0,0.35)"}),this.container.appendChild(t),t.addEventListener("blur",()=>this._stopEditingTitle()),t.addEventListener("keydown",e=>{"Enter"!==e.code&&"Escape"!==e.code||t.blur()}),this._editingTitleEl=t}this._positionTitleEditor(),this._editingTitleEl.value=this.titles.get(t)||"",this._editingTitleEl.placeholder=`${this.kinds[this.V.kind[t]].name} #${t}`,this._editingTitleEl.style.display="block",setTimeout(()=>{this._editingTitleEl.focus(),this._editingTitleEl.select()},20)}_positionTitleEditor(){if(-1===this._editingTitle||!this._editingTitleEl)return;const t=this._editingTitle,e=this.V.posX[t],s=this.V.posY[t],i=.5*this.V.sizeW[t],o=.5*this.V.sizeH[t],n=this._w2s(e-i,s-o),r=window.devicePixelRatio||1;this._editingTitleEl.style.left=n.x/r+"px",this._editingTitleEl.style.top=n.y/r-32+"px",this._editingTitleEl.style.width=Math.max(120,this.V.sizeW[t]*this.cam.zoom/r)+"px"}_stopEditingTitle(){if(-1===this._editingTitle)return;const t=this._editingTitleEl.value.trim();t?this.titles.set(this._editingTitle,t):this.titles.delete(this._editingTitle),this._editingTitleEl.style.display="none",this._editingTitle=-1,this._emit("change")}_startEditingNote(t){if(this._editingNote=t,!this._editingNoteEl){const t=document.createElement("textarea");t.spellcheck=!1,Object.assign(t.style,{position:"absolute",resize:"none",outline:"none",border:"1px solid #f0b93a",borderRadius:"4px",padding:"8px 10px",fontFamily:"Inter, ui-sans-serif",fontSize:"12px",lineHeight:"16px",zIndex:"300"}),this.container.appendChild(t),t.addEventListener("blur",()=>this._stopEditingNote()),t.addEventListener("keydown",e=>{"Escape"===e.code&&t.blur()}),this._editingNoteEl=t}this._positionNoteEditor();const e=this.notes[t];this._editingNoteEl.style.background=e.color.fill,this._editingNoteEl.style.color=e.color.text,this._editingNoteEl.value=e.text,this._editingNoteEl.style.display="block",setTimeout(()=>this._editingNoteEl.focus(),20)}_positionNoteEditor(){if(-1===this._editingNote||!this._editingNoteEl)return;const t=this.notes[this._editingNote],e=this._w2s(t.x,t.y),s=window.devicePixelRatio||1;this._editingNoteEl.style.left=e.x/s+"px",this._editingNoteEl.style.top=e.y/s+"px",this._editingNoteEl.style.width=t.w*this.cam.zoom/s+"px",this._editingNoteEl.style.height=t.h*this.cam.zoom/s+"px"}_stopEditingNote(){-1!==this._editingNote&&(this.notes[this._editingNote].text=this._editingNoteEl.value,this._editingNoteEl.style.display="none",this._editingNote=-1,this._emit("change"))}_showMenu(t,e,s){this._hideMenu();const i=document.createElement("div");i.style.cssText="position:fixed;min-width:200px;padding:4px;background:#161b27;border:1px solid rgba(255,255,255,0.16);border-radius:8px;box-shadow:0 12px 32px rgba(0,0,0,0.45);z-index:99999;color:#e6edf3;font:13px/1.45 ui-sans-serif, system-ui, sans-serif;";for(const t of s){if(t.sep){const t=document.createElement("div");t.style.cssText="height:1px;background:rgba(255,255,255,0.08);margin:4px;",i.appendChild(t);continue}const e=document.createElement("div");e.style.cssText="padding:6px 10px;border-radius:6px;cursor:pointer;display:flex;justify-content:space-between;gap:12px;"+(t.danger?"color:#ffb4a4;":""),e.innerHTML=`<span>${w(t.label)}</span>${t.kbd?`<span style="color:#5a6577;font-family:ui-monospace,Consolas,monospace;font-size:11px;">${w(t.kbd)}</span>`:""}`,e.onmouseenter=()=>e.style.background=t.danger?"rgba(232,70,43,0.18)":"rgba(255,255,255,0.04)",e.onmouseleave=()=>e.style.background="",e.onclick=()=>{t.fn(),this._hideMenu()},i.appendChild(e)}i.style.left=Math.min(t,window.innerWidth-220)+"px",i.style.top=Math.min(e,window.innerHeight-280)+"px",document.body.appendChild(i),this._menuEl=i,setTimeout(()=>{const t=e=>{i.contains(e.target)||(this._hideMenu(),document.removeEventListener("mousedown",t,!0))};document.addEventListener("mousedown",t,!0)},0)}_hideMenu(){this._menuEl&&(this._menuEl.remove(),this._menuEl=null)}_loop(){this._render(),this._raf=requestAnimationFrame(()=>this._loop())}_render(){if("pan"!==this._mode){this._panVel.x*this._panVel.x+this._panVel.y*this._panVel.y<16?(this._panVel.x=0,this._panVel.y=0):(this.cam.x+=this._panVel.x*(1/60),this.cam.y+=this._panVel.y*(1/60),this._panVel.x*=.91,this._panVel.y*=.91)}const t=this.ctx;this._hooks?.beforeRender?.length&&this._runHook("beforeRender",t),this._gl?(t.clearRect(0,0,this.canvas.width,this.canvas.height),this._gl.render()):(t.fillStyle=this.options.background,t.fillRect(0,0,this.canvas.width,this.canvas.height)),this._drawGrid(),this._drawFrames(),this._drawNotes(),this._refreshFocus(),this._refreshPreview(),this._positionTitleEditor(),this._positionNoteEditor(),this._drawDying(),this._drawWaypoints(),this._drawRemoteCursors(),this._drawValueBubbles(),this.options.minimap&&this._drawMinimap();const e=this.w.nodeCount_(),s=this.w.edgeCount_();this._edgePhase=(this._edgePhase+(this.options.edgeFlowSpeed||60)*(1/60))%1e3;for(let e=0;e<s;e++){const s=this.V.edgeFromN[e],i=this.V.edgeToN[e],o=this._portWorld(s,1,this.V.edgeFromP[e]),n=this._portWorld(i,0,this.V.edgeToP[e]);let r=!1;!this._focusedSet||this._focusedSet.has(s)&&this._focusedSet.has(i)||(r=!0),-1!==this._hoveredEdge&&this._hoveredEdge!==e&&(r=!0),-1===this._focusFrame||this._isInsideFocusFrame(s)&&this._isInsideFocusFrame(i)||(r=!0),r&&(t.globalAlpha=.18),this._currentEdgeIdx=e,this._drawEdge(o,n,this.colors.get(s)||this.kinds[this.V.kind[s]].color,this.colors.get(i)||this.kinds[this.V.kind[i]].color,0!==this.V.edgeSel[e],!1,this.edgeLabels.get(e)),t.globalAlpha=1}if(this._currentEdgeIdx=void 0,this._flashReject&&performance.now()-this._flashReject.t0>=1400&&(this._flashReject=null),this._flashReject&&performance.now()-this._flashReject.t0<1400){const t=this._flashReject,e=this._w2s(t.x,t.y),s=this.ctx,i=1-(performance.now()-t.t0)/1400;s.save(),s.globalAlpha=i,s.fillStyle="#e8462b",s.font="600 12px Inter, ui-sans-serif";const o=s.measureText(t.msg).width,n=e.x-o/2-8,r=e.y-36,h=o+16,a=22;s.fillStyle="#1a0e0e",this._roundRect(n,r,h,a,4),s.fill(),s.strokeStyle="#e8462b",s.lineWidth=1.4,this._roundRect(n,r,h,a,4),s.stroke(),s.fillStyle="#e8462b",s.textAlign="center",s.textBaseline="middle",s.fillText(t.msg,e.x,r+a/2),s.restore()}if("connecting"===this._mode&&this._edgeStart&&this._edgeCursor){const t=this._portWorld(this._edgeStart.nodeId,1,this._edgeStart.idx);this._drawEdge(t,this._edgeCursor,"#8b95a7","#8b95a7",!1,!0)}const i=this.canvas.width/(2*this.cam.zoom),o=this.canvas.height/(2*this.cam.zoom),n=-this.cam.x-i-80,r=-this.cam.x+i+80,h=-this.cam.y-o-80,a=-this.cam.y+o+80;let l;if(e>300){const t=this.w.queryRect(n,h,r,a);l=Array.from(this.V.queryRes.subarray(0,t))}else{l=[];for(let t=0;t<e;t++)l.push(t)}l.sort((t,e)=>{const s=this.zOrder.get(t)||0,i=this.zOrder.get(e)||0;return s===i?t-e:s-i});for(const e of l){const s=.5*this.V.sizeW[e],i=.5*this.V.sizeH[e];if(this.V.posX[e]+s<n||this.V.posX[e]-s>r)continue;if(this.V.posY[e]+i<h||this.V.posY[e]-i>a)continue;if(this.kinds[this.V.kind[e]].html)continue;if(this._nodeHiddenByCollapse(e))continue;let o=!1;if(this._focusedSet&&!this._focusedSet.has(e)&&(o=!0),this._reachableSet&&!this._reachableSet.has(e)&&(o=!0),-1!==this._hoveredEdge){const t=this.V.edgeFromN[this._hoveredEdge],s=this.V.edgeToN[this._hoveredEdge];e!==t&&e!==s&&(o=!0)}-1===this._focusFrame||this._isInsideFocusFrame(e)||(o=!0),o&&(t.globalAlpha=.22);const l=this._openPopAnim(e);this._gl?this._drawNodeOverlay(e):this._drawNode(e),l&&t.restore(),o&&(t.globalAlpha=1)}this._syncHTMLOverlays(),this._drawMultiSelectBBox(),this._drawMarquee(),this._drawLasso(),this._drawAlignGuides(),this._drawResizeHandles(),this._drawFrameHandles()}_openPopAnim(t){const e=this._nodeAddedAt.get(t);if(void 0===e)return!1;const s=(performance.now()-e)/280;if(s>=1)return this._nodeAddedAt.delete(t),!1;const i=1-Math.pow(1-s,3),o=this._w2s(this.V.posX[t],this.V.posY[t]);return this.ctx.save(),this.ctx.globalAlpha=i,this.ctx.translate(o.x,o.y),this.ctx.scale(.85+.15*i,.85+.15*i),this.ctx.translate(-o.x,-o.y),!0}_drawDying(){const t=performance.now();for(let e=this._dyingEdges.length-1;e>=0;e--){const s=this._dyingEdges[e],i=(t-s.t0)/220;i>=1?this._dyingEdges.splice(e,1):(this.ctx.save(),this.ctx.globalAlpha=.7*(1-i),this._drawEdge(s.ap,s.bp,s.colA,s.colB,!1,!0),this.ctx.restore())}for(let e=this._dyingNodes.length-1;e>=0;e--){const s=this._dyingNodes[e],i=(t-s.t0)/220;if(i>=1){this._dyingNodes.splice(e,1);continue}const o=1-Math.pow(1-i,3),n=1-o,r=1-.18*o,h=.5*s.w*r,a=.5*s.h*r,l=this._w2s(s.x-h,s.y-a),d=s.w*r*this.cam.zoom,c=s.h*r*this.cam.zoom;this.ctx.save(),this.ctx.globalAlpha=n,this.ctx.fillStyle="#161b27",this._shapePath(s.shape,l.x,l.y,d,c),this.ctx.fill(),this.ctx.strokeStyle=u(s.color,.6),this.ctx.lineWidth=1.4*this.cam.zoom,this._shapePath(s.shape,l.x,l.y,d,c),this.ctx.stroke(),this.ctx.restore()}}_drawMultiSelectBBox(){if("idle"!==this._mode)return;const t=this.getSelection();if(t.length<2)return;let e=1/0,s=-1/0,i=1/0,o=-1/0;for(const n of t){const t=.5*this.V.sizeW[n],r=.5*this.V.sizeH[n];this.V.posX[n]-t<e&&(e=this.V.posX[n]-t),this.V.posX[n]+t>s&&(s=this.V.posX[n]+t),this.V.posY[n]-r<i&&(i=this.V.posY[n]-r),this.V.posY[n]+r>o&&(o=this.V.posY[n]+r)}const n=this._w2s(e-10,i-10),r=this._w2s(s+10,o+10);this.ctx.strokeStyle="rgba(240,185,58,0.55)",this.ctx.lineWidth=1.2,this.ctx.setLineDash([5,4]),this.ctx.strokeRect(n.x,n.y,r.x-n.x,r.y-n.y),this.ctx.setLineDash([])}_drawLasso(){if(!this._lasso||this._lasso.length<2)return;this.ctx.strokeStyle="rgba(192,98,232,0.85)",this.ctx.fillStyle="rgba(192,98,232,0.10)",this.ctx.lineWidth=1.4,this.ctx.setLineDash([4,4]),this.ctx.beginPath();const t=this._w2s(this._lasso[0].x,this._lasso[0].y);this.ctx.moveTo(t.x,t.y);for(let t=1;t<this._lasso.length;t++){const e=this._w2s(this._lasso[t].x,this._lasso[t].y);this.ctx.lineTo(e.x,e.y)}this.ctx.closePath(),this.ctx.fill(),this.ctx.stroke(),this.ctx.setLineDash([])}_drawFrames(){for(let t=0;t<this.frames.length;t++){const e=this.frames[t],s=this.frameCollapsed.has(t),i=this._w2s(e.x,e.y),o=e.w*this.cam.zoom,n=(s?26:e.h)*this.cam.zoom;this.ctx.fillStyle=u(e.color,.05),this._roundRect(i.x,i.y,o,n,12*this.cam.zoom),this.ctx.fill(),this.ctx.strokeStyle=u(e.color,.45),this.ctx.lineWidth=1.4*this.cam.zoom,this.ctx.setLineDash([8*this.cam.zoom,4*this.cam.zoom]),this._roundRect(i.x,i.y,o,n,12*this.cam.zoom),this.ctx.stroke(),this.ctx.setLineDash([]);const r=26*this.cam.zoom;if(this.ctx.save(),this._roundRect(i.x,i.y,o,n,12*this.cam.zoom),this.ctx.clip(),this.ctx.fillStyle=u(e.color,.16),this.ctx.fillRect(i.x,i.y,o,r),this.ctx.restore(),this.cam.zoom>.4){this.ctx.fillStyle=e.color,this.ctx.font=`600 ${12*this.cam.zoom}px Inter, ui-sans-serif`,this.ctx.textBaseline="middle",this.ctx.textAlign="left";const t=s?"▸":"▾";this.ctx.fillText(`${t} ${e.label}`,i.x+10*this.cam.zoom,i.y+.5*r)}}}_drawFrameHandles(){for(const t of this.frames){const e=this._w2s(t.x,t.y),s=this._w2s(t.x+t.w,t.y+t.h),i=6*this.cam.zoom;this.ctx.fillStyle=t.color;for(const[t,o]of[[e.x,e.y],[s.x,e.y],[e.x,s.y],[s.x,s.y]])this.ctx.fillRect(t-i/2,o-i/2,i,i)}}_drawNotes(){for(const t of this.notes){const e=this._w2s(t.x,t.y),s=t.w*this.cam.zoom,i=t.h*this.cam.zoom;if(this.ctx.save(),this.ctx.shadowColor="rgba(0,0,0,0.4)",this.ctx.shadowBlur=12*this.cam.zoom,this.ctx.shadowOffsetY=4*this.cam.zoom,this.ctx.fillStyle=t.color.fill,this._roundRect(e.x,e.y,s,i,4*this.cam.zoom),this.ctx.fill(),this.ctx.restore(),this.ctx.strokeStyle=t.color.border,this.ctx.lineWidth=1*this.cam.zoom,this._roundRect(e.x,e.y,s,i,4*this.cam.zoom),this.ctx.stroke(),this.cam.zoom>.4&&t.text){this.ctx.fillStyle=t.color.text,this.ctx.font=`500 ${12*this.cam.zoom}px Inter, ui-sans-serif`,this.ctx.textBaseline="top",this.ctx.textAlign="left";const o=16*this.cam.zoom,n=10*this.cam.zoom,r=8*this.cam.zoom,h=s-2*n;let a=e.y+r;for(const s of t.text.split("\n")){const t=s.split(/\s+/);let r="";for(const s of t){const t=r?r+" "+s:s;if(this.ctx.measureText(t).width>h&&r){if(this.ctx.fillText(r,e.x+n,a),a+=o,r=s,a>e.y+i-o)break}else r=t}r&&a<e.y+i-.5*o&&(this.ctx.fillText(r,e.x+n,a),a+=o)}}}}_refreshFocus(){if(!this._pathHighlightEnabled)return void(this._focusedSet=null);if("idle"!==this._mode||this._hoveredNode<0)return this._focusedSet=null,void(this._lastFocusComputed=-2);if(performance.now()-this._hoveredNodeSince<200)return;if(this._hoveredNode===this._lastFocusComputed)return;const t=new Set([this._hoveredNode]),e=[this._hoveredNode],s=this.w.edgeCount_();for(;e.length;){const i=e.shift();for(let o=0;o<s;o++)this.V.edgeFromN[o]!==i||t.has(this.V.edgeToN[o])||(t.add(this.V.edgeToN[o]),e.push(this.V.edgeToN[o])),this.V.edgeToN[o]!==i||t.has(this.V.edgeFromN[o])||(t.add(this.V.edgeFromN[o]),e.push(this.V.edgeFromN[o]))}this._focusedSet=t,this._lastFocusComputed=this._hoveredNode}_refreshPreview(){this.options.hoverPreview?"idle"!==this._mode||this._hoveredNode<0?this._hidePreview():performance.now()-this._hoveredNodeSince<600||(this._previewedNode!==this._hoveredNode?(this._showPreview(this._hoveredNode),this._previewedNode=this._hoveredNode):this._positionPreview(this._hoveredNode)):this._hidePreview()}_showPreview(t){if(!this._previewEl){const t=document.createElement("div");t.style.cssText="position:absolute;width:260px;padding:12px 14px;background:#161b27;border:1px solid rgba(255,255,255,0.16);border-radius:8px;box-shadow:0 12px 32px rgba(0,0,0,0.45);color:#e6edf3;font:13px/1.45 ui-sans-serif, system-ui, sans-serif;pointer-events:none;opacity:0;transition:opacity 140ms;z-index:200;",this.container.appendChild(t),this._previewEl=t}const e=this.kinds[this.V.kind[t]],s=this.titles.get(t)||e.name,i=this.descriptions.get(t),o=this.tags.get(t)||[],n=this.status.get(t),r=this.progress.get(t),h=[`<div style="display:flex;align-items:center;gap:8px;padding-bottom:8px;margin-bottom:8px;border-bottom:1px solid rgba(255,255,255,0.08);">\n <span style="width:24px;height:24px;border-radius:5px;background:${u(e.color,.18)};color:${e.color};display:grid;place-items:center;font:700 12px Inter">${this.icon.get(t)||e.badge}</span>\n <div><div style="font-weight:600">${w(s)}</div><div style="color:#8b95a7;font-family:ui-monospace,Consolas,monospace;font-size:11px;">#${t} · ${e.name}</div></div>\n </div>`];if(i&&h.push(`<div style="font-size:12px;color:#8b95a7;margin-bottom:8px;">${w(i)}</div>`),n||void 0!==r){const t=[];n&&t.push(`<span style="padding:2px 7px;border-radius:10px;background:rgba(255,255,255,0.06);">${n}</span>`),void 0!==r&&t.push(`<span style="padding:2px 7px;border-radius:10px;background:rgba(255,255,255,0.06);">${Math.round(100*r)}%</span>`),h.push(`<div style="display:flex;gap:6px;margin-bottom:8px;font-size:11px;">${t.join("")}</div>`)}o.length&&h.push(`<div style="display:flex;flex-wrap:wrap;gap:4px;">${o.map(t=>`<span style="font-size:10.5px;padding:2px 7px;border-radius:3px;background:${u(e.color,.18)};color:${e.color};">${w(t)}</span>`).join("")}</div>`),this._previewEl.innerHTML=h.join(""),this._positionPreview(t),this._previewEl.style.opacity="1"}_positionPreview(t){if(!this._previewEl)return;const e=this.V.posX[t],s=this.V.posY[t],i=.5*this.V.sizeW[t],o=.5*this.V.sizeH[t],n=this._w2s(e+i,s-o),r=this._w2s(e-i,s-o),h=this.container.getBoundingClientRect(),a=window.devicePixelRatio||1;let l=n.x/a+12,d=n.y/a;l+280>h.width&&(l=r.x/a-280-12),l<8&&(l=8),this._previewEl.style.left=l+"px",this._previewEl.style.top=Math.max(8,d)+"px"}_hidePreview(){this._previewEl&&(this._previewEl.style.opacity="0"),this._previewedNode=-1}_syncHTMLOverlays(){const t=new Set,e=this.w.nodeCount_();for(let s=0;s<e;s++){const e=this.kinds[this.V.kind[s]];if(!e.html)continue;t.add(s);let i=this._htmlOverlays.get(s);i||(i=document.createElement("div"),i.className="zflow-html-node",i.style.cssText="position:absolute;border:1px solid rgba(255,255,255,0.16);border-radius:8px;background:#161b27;color:#e6edf3;overflow:hidden;font-family:Inter, ui-sans-serif;font-size:12px;transform-origin:top left;",i.innerHTML=e.template||`<div style="padding:8px;">${w(e.name)} #${s}</div>`,this.container.appendChild(i),this._htmlOverlays.set(s,i));const o=this.V.posX[s],n=this.V.posY[s],r=.5*this.V.sizeW[s],h=.5*this.V.sizeH[s],a=this._w2s(o-r,n-h),l=window.devicePixelRatio||1;i.style.left=a.x/l+"px",i.style.top=a.y/l+"px",i.style.width=this.V.sizeW[s]*this.cam.zoom/l+"px",i.style.height=this.V.sizeH[s]*this.cam.zoom/l+"px"}for(const[e,s]of this._htmlOverlays)t.has(e)||(s.remove(),this._htmlOverlays.delete(e))}_drawGrid(){const t=this.ctx,e=40*this.cam.zoom;if(e<6)return;const s=this.canvas.width/2+this.cam.x*this.cam.zoom,i=this.canvas.height/2+this.cam.y*this.cam.zoom,o=s-Math.ceil(s/e)*e,n=i-Math.ceil(i/e)*e;t.fillStyle=this.options.snapToGrid?"rgba(240,185,58,0.10)":"rgba(255,255,255,0.045)";const r=window.devicePixelRatio||1;for(let s=o;s<this.canvas.width;s+=e)for(let i=n;i<this.canvas.height;i+=e)t.fillRect(s,i,1.4*r,1.4*r)}_drawMarquee(){if(!this._marquee)return;const t=this._w2s(this._marquee.x0,this._marquee.y0),e=this._w2s(this._marquee.x1,this._marquee.y1),s=Math.min(t.x,e.x),i=Math.min(t.y,e.y),o=Math.abs(e.x-t.x),n=Math.abs(e.y-t.y),r=this.ctx;r.fillStyle="rgba(240,185,58,0.10)",r.fillRect(s,i,o,n),r.strokeStyle="rgba(240,185,58,0.7)",r.setLineDash([4,4]),r.lineWidth=1.2,r.strokeRect(s,i,o,n),r.setLineDash([])}_drawAlignGuides(){if(!this._alignGuides)return;const t=this.ctx;t.strokeStyle="rgba(192,98,232,0.85)",t.lineWidth=1.2,t.setLineDash([2,4]);for(const e of this._alignGuides.v){const s=this._w2s(e,0).x;t.beginPath(),t.moveTo(s,0),t.lineTo(s,this.canvas.height),t.stroke()}for(const e of this._alignGuides.h){const s=this._w2s(0,e).y;t.beginPath(),t.moveTo(0,s),t.lineTo(this.canvas.width,s),t.stroke()}t.setLineDash([])}_drawResizeHandles(){if("idle"!==this._mode)return;const t=this.getSelection();if(1!==t.length)return;const e=t[0],s=this.V.posX[e],o=this.V.posY[e],n=.5*this.V.sizeW[e],r=.5*this.V.sizeH[e],h={tl:{x:s-n,y:o-r},t:{x:s,y:o-r},tr:{x:s+n,y:o-r},r:{x:s+n,y:o},br:{x:s+n,y:o+r},b:{x:s,y:o+r},bl:{x:s-n,y:o+r},l:{x:s-n,y:o}},a=this.ctx,l=4*this.cam.zoom;a.fillStyle="#f0b93a",a.strokeStyle="#07090f",a.lineWidth=1*this.cam.zoom;for(const t of i){const e=this._w2s(h[t].x,h[t].y);a.beginPath(),a.rect(e.x-l,e.y-l,2*l,2*l),a.fill(),a.stroke()}}_portWorld(t,e,s){const i=this.V.posX[t],o=this.V.posY[t],n=.5*this.V.sizeW[t],r=.5*this.V.sizeH[t],h=(s+1)/((0===e?this.V.nIn[t]:this.V.nOut[t])+1);return{x:0===e?i-n:i+n,y:o-r+this.V.sizeH[t]*h}}_orthoPath(t,e){if(e.x-t.x>60){const s=(t.x+e.x)/2;return[t,{x:s,y:t.y},{x:s,y:e.y},e]}const s=(t.y+e.y)/2;return[t,{x:t.x+30,y:t.y},{x:t.x+30,y:s},{x:e.x-30,y:s},{x:e.x-30,y:e.y},e]}_drawEdge(t,e,s,i,o,n,r){const h=this._w2s(t.x,t.y),a=this._w2s(e.x,e.y),l=this.ctx,c=l.createLinearGradient(h.x,h.y,a.x,a.y);c.addColorStop(0,s),c.addColorStop(1,i);const p=void 0!==this._currentEdgeIdx&&this._activeEdges.has(this._currentEdgeIdx)&&this._activeEdges.get(this._currentEdgeIdx)>performance.now();let m;if(l.strokeStyle=o?"#f0b93a":p?"#5b8def":n?"#8b95a7":c,l.lineWidth=(o?2.4:p?3:1.6)*this.cam.zoom,p&&(l.shadowColor="#5b8def",l.shadowBlur=10*this.cam.zoom),l.lineJoin="round","orthogonal"===this.options.edgeStyle){const t=this._orthoPath(h,a);l.beginPath(),l.moveTo(t[0].x,t[0].y);for(let e=1;e<t.length;e++)l.lineTo(t[e].x,t[e].y);l.stroke(),m=t[Math.floor(t.length/2)]}else{const t=a.x-h.x,e=a.y-h.y,s=Math.max(50,.5*Math.abs(t)+.4*Math.abs(e));l.beginPath(),l.moveTo(h.x,h.y),l.bezierCurveTo(h.x+s,h.y,a.x-s,a.y,a.x,a.y),l.stroke(),m=d(.5,h.x,h.y,h.x+s,h.y,a.x-s,a.y,a.x,a.y)}if(!n&&void 0!==this._currentEdgeIdx&&this.animatedEdges.has(this._currentEdgeIdx)){const t=4;for(let e=0;e<t;e++){const s=(this._edgePhase/1e3+e/t)%1;let o;if("orthogonal"===this.options.edgeStyle){const t=a.x-h.x,e=a.y-h.y,i=Math.max(50,.5*Math.abs(t)+.4*Math.abs(e));o=d(s,h.x,h.y,h.x+i,h.y,a.x-i,a.y,a.x,a.y)}else{const t=a.x-h.x,e=a.y-h.y,i=Math.max(50,.5*Math.abs(t)+.4*Math.abs(e));o=d(s,h.x,h.y,h.x+i,h.y,a.x-i,a.y,a.x,a.y)}l.fillStyle=i,l.beginPath(),l.arc(o.x,o.y,3.2*this.cam.zoom,0,2*Math.PI),l.fill()}}if(!n&&r&&this.cam.zoom>.45){l.font=`600 ${10.5*this.cam.zoom}px ui-monospace, Consolas, monospace`;const t=l.measureText(r).width+2*(5*this.cam.zoom),e=16*this.cam.zoom;l.fillStyle="#0b0f17",this._roundRect(m.x-t/2,m.y-e/2,t,e,5*this.cam.zoom),l.fill(),l.strokeStyle=o?"#f0b93a":u(s,.6),l.lineWidth=1*this.cam.zoom,l.stroke(),l.fillStyle="#e6edf3",l.textAlign="center",l.textBaseline="middle",l.fillText(r,m.x,m.y)}}_drawNodeOverlay(t){const e=this.cam.zoom;if(e<.25)return;if(this.w.nodeCount_()>5e3&&e<.55)return;const s=this.V.posX[t],i=this.V.posY[t],o=.5*this.V.sizeW[t],n=.5*this.V.sizeH[t],r=this._w2s(s-o,i-n),h=this.V.sizeW[t]*e,a=this.V.sizeH[t]*e,l=this.kinds[this.V.kind[t]],d=this.colors.get(t)||l.color,c=this.ctx;if(e>.4){const s=this.titles.get(t)||l.name;c.font=`600 ${12*e}px Inter, ui-sans-serif`,c.fillStyle="#0b0f17",c.textAlign="center",c.textBaseline="middle",c.fillText(s,r.x+h/2,r.y+11*e)}if(e>.35)for(let s=0;s<2;s++){const i=0===s?this.V.nIn[t]:this.V.nOut[t];for(let o=0;o<i;o++){const i=this._portWorld(t,s,o),n=this._w2s(i.x,i.y);c.fillStyle=d,c.strokeStyle="#07090f",c.lineWidth=1.5*e,c.beginPath(),c.arc(n.x,n.y,4.5*e,0,2*Math.PI),c.fill(),c.stroke()}}this.breakpoints.has(t)&&(c.fillStyle="#e8462b",c.beginPath(),c.arc(r.x-4*e,r.y+a/2,4.5*e,0,2*Math.PI),c.fill())}_drawNode(t){const e=this.V.posX[t],s=this.V.posY[t],i=.5*this.V.sizeW[t],o=.5*this.V.sizeH[t],n=this._w2s(e-i,s-o),r=this.V.sizeW[t]*this.cam.zoom,h=this.V.sizeH[t]*this.cam.zoom,a=this.kinds[this.V.kind[t]],l=this.colors.get(t)||a.color,d=0!==this.V.selected[t],c=this._hoveredNode===t&&"idle"===this._mode,m=this.ctx;if(m.save(),m.shadowColor="rgba(0,0,0,0.45)",m.shadowBlur=(c?14:10)*this.cam.zoom,m.shadowOffsetY=4*this.cam.zoom,m.fillStyle="#161b27",this._shapePath(a.shape,n.x,n.y,r,h),m.fill(),m.restore(),"rect"===a.shape&&(m.save(),this._shapePath(a.shape,n.x,n.y,r,h),m.clip(),m.fillStyle=l,m.fillRect(n.x,n.y,r,22*this.cam.zoom),m.restore()),"running"===this.status.get(t)){const t=.5+.5*Math.sin(performance.now()/180);m.save(),m.shadowColor="#5b8def",m.shadowBlur=(18+14*t)*this.cam.zoom,m.strokeStyle=`rgba(91,141,239,${.6+.4*t})`,m.lineWidth=(2.2+t)*this.cam.zoom,this._shapePath(a.shape,n.x-2,n.y-2,r+4,h+4),m.stroke(),m.restore()}if(d?(m.save(),m.shadowColor="rgba(240,185,58,0.55)",m.shadowBlur=14*this.cam.zoom,m.strokeStyle="#f0b93a",m.lineWidth=1.6*this.cam.zoom,this._shapePath(a.shape,n.x,n.y,r,h),m.stroke(),m.restore()):(m.strokeStyle=c?u(l,.55):"rgba(255,255,255,0.08)",m.lineWidth=(c?1.3:1)*this.cam.zoom,this._shapePath(a.shape,n.x,n.y,r,h),m.stroke()),this.cam.zoom>.42){const e=this.titles.get(t)||`${a.name} #${t}`;m.textBaseline="middle",m.font=`600 ${11*this.cam.zoom}px Inter, ui-sans-serif`,"rect"===a.shape?(m.fillStyle="#0b0f17",m.textAlign="left",m.fillText(e,n.x+10*this.cam.zoom,n.y+11*this.cam.zoom)):(m.fillStyle=l,m.textAlign="center",m.fillText(e,n.x+r/2,n.y+h/2))}const g=this.progress.get(t);if(void 0!==g&&g>0){const t=3*this.cam.zoom,e=n.y+h-t-2*this.cam.zoom,s=n.x+8*this.cam.zoom,i=r-16*this.cam.zoom;m.fillStyle="rgba(255,255,255,0.06)",m.fillRect(s,e,i,t),m.fillStyle=l,m.fillRect(s,e,i*Math.min(1,Math.max(0,g)),t)}const f=this.tags.get(t);if(f&&f.length&&this.cam.zoom>.5){let t=n.x+8*this.cam.zoom;const e=n.y+h-24*this.cam.zoom;m.font=`500 ${9*this.cam.zoom}px Inter, ui-sans-serif`,m.textBaseline="middle";for(const s of f){const i=m.measureText(s).width+10*this.cam.zoom;if(t+i>n.x+r-8*this.cam.zoom)break;m.fillStyle=u(l,.18),this._roundRect(t,e,i,14*this.cam.zoom,3*this.cam.zoom),m.fill(),m.fillStyle=l,m.textAlign="left",m.fillText(s,t+5*this.cam.zoom,e+7*this.cam.zoom),t+=i+4*this.cam.zoom}}const _=this.metrics.get(t);if(_&&_.count>1&&"rect"===a.shape&&this.cam.zoom>.45){const e=this.metricMax.get(t)||1,s=n.x+8*this.cam.zoom,i=n.y+h-22*this.cam.zoom,o=r-16*this.cam.zoom,a=16*this.cam.zoom;m.strokeStyle=u(l,.85),m.lineWidth=1.5*this.cam.zoom,m.beginPath();for(let t=0;t<_.count;t++){const n=_.data[(_.idx+this._metricCap-_.count+t)%this._metricCap],r=s+t/Math.max(1,_.count-1)*o,h=i+a-Math.min(Math.max(n/e,0),1)*a;0===t?m.moveTo(r,h):m.lineTo(r,h)}m.stroke()}if(this.breakpoints.has(t)){const t=n.x-4*this.cam.zoom,e=n.y+h/2;m.save(),m.shadowColor="#e8462b",m.shadowBlur=8*this.cam.zoom,m.fillStyle="#e8462b",m.beginPath(),m.arc(t,e,4.5*this.cam.zoom,0,2*Math.PI),m.fill(),m.restore()}const y=this.status.get(t);if(y&&"rect"===a.shape){const t=p[y]||"#8b95a7",e=n.x+r-12*this.cam.zoom,s=n.y+11*this.cam.zoom;m.save(),m.shadowColor=t,m.shadowBlur=6*this.cam.zoom,m.fillStyle=t,m.beginPath(),m.arc(e,s,3.5*this.cam.zoom,0,2*Math.PI),m.fill(),m.restore()}if(this.locked.has(t)){const t=n.x+6*this.cam.zoom,e=n.y+6*this.cam.zoom,s=10*this.cam.zoom;m.fillStyle="rgba(0,0,0,0.55)",this._roundRect(t,e,s,s,2*this.cam.zoom),m.fill(),m.strokeStyle="#f0b93a",m.lineWidth=1.2*this.cam.zoom,m.strokeRect(t+2.5*this.cam.zoom,e+5*this.cam.zoom,s-5*this.cam.zoom,s-6*this.cam.zoom),m.beginPath(),m.arc(t+.5*s,e+5*this.cam.zoom,2*this.cam.zoom,Math.PI,0),m.stroke()}const x=this.image.get(t);if(x&&"rect"===a.shape&&this.cam.zoom>.5){const t=this._getImage(x);if(t&&t.ready){const e=n.x+8*this.cam.zoom,s=n.y+28*this.cam.zoom,i=r-16*this.cam.zoom,o=Math.min(54*this.cam.zoom,.45*h);m.save(),this._roundRect(e,s,i,o,4*this.cam.zoom),m.clip(),m.drawImage(t.img,e,s,i,o),m.restore()}}const w=this.descriptions.get(t);if(w&&"rect"===a.shape&&this.cam.zoom>.5&&!x){const t=!1!==this.options.inlineMarkdown?function(t){if(!t)return[{t:"",style:"p"}];const e=[],s=/(\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`|\[[^\]]+\]\([^)]+\))/g;let i,o=0;for(;null!==(i=s.exec(t));){i.index>o&&e.push({t:t.slice(o,i.index),style:"p"});const s=i[1];if(s.startsWith("**"))e.push({t:s.slice(2,-2),style:"b"});else if(s.startsWith("`"))e.push({t:s.slice(1,-1),style:"c"});else if(s.startsWith("[")){const t=s.indexOf("](");e.push({t:s.slice(1,t),style:"a",href:s.slice(t+2,-1)})}else e.push({t:s.slice(1,-1),style:"i"});o=i.index+s.length}o<t.length&&e.push({t:t.slice(o),style:"p"});return e}(w):[{t:w,style:"p"}];let e=n.x+8*this.cam.zoom;const s=n.y+44*this.cam.zoom;m.font=`400 ${10*this.cam.zoom}px Inter, ui-sans-serif`,m.textBaseline="top";const i=n.x+r-8*this.cam.zoom;for(const o of t){let t=10*this.cam.zoom+"px ";t="b"===o.style?`700 ${10*this.cam.zoom}px Inter, ui-sans-serif`:"i"===o.style?`italic 400 ${10*this.cam.zoom}px Inter, ui-sans-serif`:"c"===o.style?10*this.cam.zoom+"px ui-monospace, Consolas, monospace":(o.style,`400 ${10*this.cam.zoom}px Inter, ui-sans-serif`),m.font=t,m.fillStyle="a"===o.style?"#5be0d0":"c"===o.style?"#f0b93a":"#c8d1de";const n=m.measureText(o.t).width;if(e+n>i)break;m.fillText(o.t,e,s),e+=n}}this._searchHits&&this._searchHits.includes(t)&&(m.save(),m.shadowColor="#5be0d0",m.shadowBlur=18*this.cam.zoom,m.strokeStyle="#5be0d0",m.lineWidth=1.6*this.cam.zoom,this._shapePath(a.shape,n.x-3,n.y-3,r+6,h+6),m.stroke(),m.restore());for(let e=0;e<2;e++){const s=0===e?this.V.nIn[t]:this.V.nOut[t];for(let i=0;i<s;i++){const s=this._portWorld(t,e,i),o=this._w2s(s.x,s.y);m.fillStyle=l,m.strokeStyle="#07090f",m.lineWidth=1.5*this.cam.zoom,m.beginPath(),m.arc(o.x,o.y,4.5*this.cam.zoom,0,2*Math.PI),m.fill(),m.stroke()}}}_shapePath(t,e,s,i,o){const n=this.ctx;if("diamond"===t){const t=e+i/2,r=s+o/2;return n.beginPath(),n.moveTo(t,s),n.lineTo(e+i,r),n.lineTo(t,s+o),n.lineTo(e,r),void n.closePath()}if("ellipse"===t)return n.beginPath(),void n.ellipse(e+i/2,s+o/2,i/2,o/2,0,0,2*Math.PI);if("hexagon"===t){const t=e+i/2,r=s+o/2,h=i/2,a=.45*h;return n.beginPath(),n.moveTo(t-h+a,s),n.lineTo(t+h-a,s),n.lineTo(e+i,r),n.lineTo(t+h-a,s+o),n.lineTo(t-h+a,s+o),n.lineTo(e,r),void n.closePath()}this._roundRect(e,s,i,o,8)}_roundRect(t,e,s,i,o){const n=this.ctx;n.beginPath(),n.moveTo(t+o,e),n.lineTo(t+s-o,e),n.quadraticCurveTo(t+s,e,t+s,e+o),n.lineTo(t+s,e+i-o),n.quadraticCurveTo(t+s,e+i,t+s-o,e+i),n.lineTo(t+o,e+i),n.quadraticCurveTo(t,e+i,t,e+i-o),n.lineTo(t,e+o),n.quadraticCurveTo(t,e,t+o,e),n.closePath()}}function d(t,e,s,i,o,n,r,h,a){const l=1-t,d=l*l,c=t*t,u=d*l,p=3*d*t,m=3*l*c,g=c*t;return{x:u*e+p*i+m*n+g*h,y:u*s+p*o+m*r+g*a}}function c(t,e,s,i,o,n){const r=o-s,h=n-i,a=r*r+h*h;if(0===a){const o=t-s,n=e-i;return o*o+n*n}let l=((t-s)*r+(e-i)*h)/a;l=Math.max(0,Math.min(1,l));const d=t-(s+l*r),c=e-(i+l*h);return d*d+c*c}function u(t,e){if(t.startsWith("rgb"))return t.replace(")",`, ${e})`).replace("rgb(","rgba(");return`rgba(${parseInt(t.slice(1,3),16)},${parseInt(t.slice(3,5),16)},${parseInt(t.slice(5,7),16)},${e})`}const p={ok:"#5bd17a",live:"#5bd17a",running:"#5b8def",idle:"#8b95a7",warn:"#f0b93a",error:"#e8462b",failed:"#e8462b",stopped:"#8b95a7"};function m(t){const[e,s]=[...t.values()],i=s.x-e.x,o=s.y-e.y;return{dist:Math.hypot(i,o)||1,mid:{x:(e.x+s.x)/2,y:(e.y+s.y)/2}}}function g(t){let e=2166136261;const s=t=>{if(null==t)return void(e=16777619*(255^e)>>>0);const i=typeof t;if("number"!==i)if("string"!==i)if("boolean"!==i)if(Array.isArray(t))for(const e of t)s(e);else if("object"!==i);else for(const i of Object.keys(t).sort()){for(let t=0;t<i.length;t++)e=16777619*(e^i.charCodeAt(t))>>>0;s(t[i])}else e=16777619*(e^(t?1:0))>>>0;else for(let s=0;s<t.length;s++)e=16777619*(e^t.charCodeAt(s))>>>0;else e=16777619*(e^(1e6*t|0))>>>0};return s(t),e>>>0}function f(t){return"number"==typeof t?_(t):t&&"object"==typeof t?Object.entries(t).filter(([,t])=>null!=t).map(([t,e])=>`${t}: ${_(e)}`).join(" "):_(t)}function _(t){if(null==t)return"∅";if("number"==typeof t)return Number.isInteger(t)?String(t):t.toFixed(2);if("boolean"==typeof t)return t?"true":"false";if("string"==typeof t)return t.length>22?t.slice(0,22)+"…":t;try{const e=JSON.stringify(t);return e.length>30?e.slice(0,30)+"…":e}catch{return"[obj]"}}function y(t){return[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)]}function x(t,e,s){let i=!1;for(let o=0,n=s.length-1;o<s.length;n=o++){const r=s[o].x,h=s[o].y,a=s[n].x,l=s[n].y;h>e!=l>e&&t<(a-r)*(e-h)/(l-h)+r&&(i=!i)}return i}function w(t){return String(t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function b(t){return w(t)}function v(t,e,s=7){const i=[],o=Math.max(4,Math.floor(e/s));for(const e of String(t).split("\n")){if(e.length<=o){i.push(e);continue}let t="";for(const s of e.split(/\s+/)){const e=t?t+" "+s:s;e.length>o&&t?(i.push(t),t=s):t=e}t&&i.push(t)}return i}function k(t){const e=new Map,s=[],i=t.split("\n").map(t=>t.replace(/\/\/.*$/,"").trim()).filter(Boolean);let o=0;i[0]&&/^(graph|flowchart)\b/i.test(i[0])&&(o=1);const n=/([A-Za-z_][A-Za-z0-9_]*)(?:(\[\[)([^\]]+)\]\]|\[([^\]]+)\]|\(\(([^)]+)\)\)|\(([^)]+)\)|\{([^}]+)\})?/;function r(t,s){const i=t.slice(s).match(n);if(!i||0!==i.index)return null;const o=i[1];let r="default",h=o;return i[2]?(r="subroutine",h=i[3]):i[4]?(r="rect",h=i[4]):i[5]?(r="circle",h=i[5]):i[6]?(r="round",h=i[6]):i[7]&&(r="rhombus",h=i[7]),e.has(o)&&"default"!==e.get(o).shape||e.set(o,{label:h,shape:r}),{id:o,end:s+i[0].length}}for(let t=o;t<i.length;t++){const e=i[t],o=r(e,0);if(!o)continue;let n=e.slice(o.end).trim();const h=n.match(/^([-=.~]+>?|---|===)\s*(?:\|([^|]+)\|\s*)?/);if(!h)continue;n=n.slice(h[0].length).trim();const a=r(e,e.length-n.length);a&&s.push({from:o.id,to:a.id,label:h[2]||null})}return{nodes:e,edges:s}}function S(t){const e=new Map,s=[];t=(t=t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/^\s*#.*$/gm,"").replace(/\/\/.*$/gm,"")).replace(/^\s*(?:strict\s+)?(?:di)?graph\s+\w*\s*\{/i,"").replace(/\}\s*$/,"");const i=[];let o="",n=0;for(const e of t)"["===e&&n++,"]"===e&&n--,";"!==e&&"\n"!==e||0!==n?o+=e:(o.trim()&&i.push(o.trim()),o="");o.trim()&&i.push(o.trim());const r=/"([^"]+)"|([A-Za-z_][A-Za-z0-9_]*)/;function h(t,e){const s=t.slice(e).match(r);return s&&0===s.index?{id:s[1]||s[2],end:e+s[0].length}:null}function a(t,e){const s=t.slice(e).match(/^\s*\[([^\]]*)\]/);if(!s)return null;const i=s[1].match(/label\s*=\s*"([^"]*)"|label\s*=\s*([A-Za-z_][A-Za-z0-9_]*)/);return{label:i?i[1]||i[2]:null,end:e+s[0].length}}for(const t of i){let i=0;const o=h(t,i);if(!o)continue;for(i=o.end;" "===t[i]||"\t"===t[i];)i++;const n=t.slice(i).match(/^(->|--)\s*/);if(n){i+=n[0].length;const r=h(t,i);if(!r)continue;i=r.end;const l=a(t,i);e.has(o.id)||e.set(o.id,{label:o.id}),e.has(r.id)||e.set(r.id,{label:r.id}),s.push({from:o.id,to:r.id,label:l?l.label:null})}else{const s=a(t,i),n=s&&s.label?s.label:o.id;e.has(o.id)&&e.get(o.id).label!==o.id||e.set(o.id,{label:n})}}return{nodes:e,edges:s}}function z(t,e,s){const i=t.createShader(s);if(t.shaderSource(i,e),t.compileShader(i),!t.getShaderParameter(i,t.COMPILE_STATUS))throw new Error("GL compile: "+t.getShaderInfoLog(i));return i}function E(t,e,s){const i=t.createProgram();if(t.attachShader(i,z(t,e,t.VERTEX_SHADER)),t.attachShader(i,z(t,s,t.FRAGMENT_SHADER)),t.linkProgram(i),!t.getProgramParameter(i,t.LINK_STATUS))throw new Error("GL link: "+t.getProgramInfoLog(i));return i}function V(t){return[parseInt(t.slice(1,3),16)/255,parseInt(t.slice(3,5),16)/255,parseInt(t.slice(5,7),16)/255]}function C(t,e,s,i,o,n,r,h,a){const l=1-t,d=l*l,c=t*t,u=d*l,p=3*d*t,m=3*l*c,g=c*t;return{x:u*e+p*i+m*n+g*h,y:u*s+p*o+m*r+g*a}}function N(t,e,s){return{x:t.x+(e.x-t.x)*s,y:t.y+(e.y-t.y)*s}}var A=Object.freeze({__proto__:null,WebGLRenderer:class{constructor(t){if(this.flow=t,this.glCanvas=document.createElement("canvas"),this.glCanvas.style.cssText="position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0;",t.container.insertBefore(this.glCanvas,t.canvas),t.canvas.style.background="transparent",t.canvas.style.position="absolute",t.canvas.style.zIndex="1",this.gl=this.glCanvas.getContext("webgl",{antialias:!0,alpha:!0,premultipliedAlpha:!1}),!this.gl)return this.disabled=!0,void console.warn("zflow: WebGL unavailable");this.instExt=this.gl.getExtension("ANGLE_instanced_arrays"),this.cap=t.w.nodeCap(),this.edgeCap=t.w.edgeCap(),this._resize(),this._setupShaders(),this._setupBuffers(),this._hookDirty(),this._resizeObs=new ResizeObserver(()=>this._resize()),this._resizeObs.observe(t.container),this._dirty=new Set,this._dirtyEdges=new Set,this._fullRebuildNeeded=!0,this._lastNodeCount=0,this._lastEdgeCount=0}_hookDirty(){const t=this.flow;t.on("change",()=>{this._fullRebuildNeeded=!0});const e=t.w.moveSelectedBy;e&&(t.w.moveSelectedBy=(s,i)=>{e.call(t.w,s,i),t._ensureAdj?.();const o=t._nodeAdj;for(let e=0;e<t.w.nodeCount_();e++)if(t.V.selected[e]&&(this._dirty.add(e),o&&o[e]))for(let t=0;t<o[e].length;t++)this._dirtyEdges.add(o[e][t])});const s=t.w.moveNode;s&&(t.w.moveNode=(e,i,o)=>{s.call(t.w,e,i,o),this._dirty.add(e),t._ensureAdj?.();const n=t._nodeAdj;if(n&&n[e])for(let t=0;t<n[e].length;t++)this._dirtyEdges.add(n[e][t])})}_resize(){const t=window.devicePixelRatio||1,e=this.flow.container.getBoundingClientRect();this.glCanvas.width=e.width*t,this.glCanvas.height=e.height*t,this.gl?.viewport(0,0,this.glCanvas.width,this.glCanvas.height)}_setupShaders(){const t=this.gl;this.progNode=E(t,"\nattribute vec2 aQuad;\nattribute vec2 aCenter;\nattribute vec2 aSize;\nattribute vec3 aColor;\nattribute float aSelected;\nuniform vec2 uCam;\nuniform float uZoom;\nuniform vec2 uScreen;\nvarying vec3 vColor;\nvarying float vSelected;\nvarying vec2 vUv;\nvoid main() {\n vUv = aQuad;\n vSelected = aSelected;\n vColor = aColor;\n vec2 worldPos = aCenter + aQuad * aSize;\n vec2 screen = (worldPos + uCam) * uZoom;\n vec2 ndc = (screen / uScreen) * 2.0;\n gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);\n}","\nprecision mediump float;\nvarying vec3 vColor;\nvarying float vSelected;\nvarying vec2 vUv;\nvoid main() {\n vec2 q = abs(vUv);\n float d = max(q.x, q.y);\n float alpha = smoothstep(1.0, 0.92, d);\n float header = step(0.7, vUv.y) * 0.18;\n vec3 col = vColor + vec3(header);\n if (vSelected > 0.5) col = mix(col, vec3(0.94, 0.73, 0.23), 0.55);\n gl_FragColor = vec4(col, alpha);\n}"),this.progEdge=E(t,"\nattribute vec2 aPos;\nattribute vec3 aColor;\nuniform vec2 uCam;\nuniform float uZoom;\nuniform vec2 uScreen;\nvarying vec3 vColor;\nvoid main() {\n vColor = aColor;\n vec2 screen = (aPos + uCam) * uZoom;\n vec2 ndc = (screen / uScreen) * 2.0;\n gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);\n}","\nprecision mediump float;\nvarying vec3 vColor;\nvoid main() { gl_FragColor = vec4(vColor, 0.85); }"),this.locN={aQuad:t.getAttribLocation(this.progNode,"aQuad"),aCenter:t.getAttribLocation(this.progNode,"aCenter"),aSize:t.getAttribLocation(this.progNode,"aSize"),aColor:t.getAttribLocation(this.progNode,"aColor"),aSel:t.getAttribLocation(this.progNode,"aSelected"),uCam:t.getUniformLocation(this.progNode,"uCam"),uZoom:t.getUniformLocation(this.progNode,"uZoom"),uScreen:t.getUniformLocation(this.progNode,"uScreen")},this.locE={aPos:t.getAttribLocation(this.progEdge,"aPos"),aColor:t.getAttribLocation(this.progEdge,"aColor"),uCam:t.getUniformLocation(this.progEdge,"uCam"),uZoom:t.getUniformLocation(this.progEdge,"uZoom"),uScreen:t.getUniformLocation(this.progEdge,"uScreen")}}_setupBuffers(){const t=this.gl;this.quadBuf=t.createBuffer(),t.bindBuffer(t.ARRAY_BUFFER,this.quadBuf),t.bufferData(t.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,-1,1,1,-1,1]),t.STATIC_DRAW),this.nodeData=new Float32Array(8*this.cap),this.nodeBuf=t.createBuffer(),t.bindBuffer(t.ARRAY_BUFFER,this.nodeBuf),t.bufferData(t.ARRAY_BUFFER,this.nodeData.byteLength,t.DYNAMIC_DRAW),this.edgeData=new Float32Array(48*this.edgeCap*5),this.edgeBuf=t.createBuffer(),t.bindBuffer(t.ARRAY_BUFFER,this.edgeBuf),t.bufferData(t.ARRAY_BUFFER,this.edgeData.byteLength,t.DYNAMIC_DRAW)}_writeNode(t){const e=this.flow,s=e.kinds[e.V.kind[t]],i=e.colors.get(t)||s.color,o=8*t;this.nodeData[o]=e.V.posX[t],this.nodeData[o+1]=e.V.posY[t],this.nodeData[o+2]=.5*e.V.sizeW[t],this.nodeData[o+3]=.5*e.V.sizeH[t];const[n,r,h]=V(i);this.nodeData[o+4]=n,this.nodeData[o+5]=r,this.nodeData[o+6]=h,this.nodeData[o+7]=0!==e.V.selected[t]?1:0}_writeEdge(t){const e=this.flow,s=e.V.edgeFromN[t],i=e.V.edgeToN[t],o=e._portWorld(s,1,e.V.edgeFromP[t]),n=e._portWorld(i,0,e.V.edgeToP[t]),r=V(e.colors.get(s)||e.kinds[e.V.kind[s]].color),h=48*t*5,a="orthogonal"===e.options.edgeStyle,l=Math.max(50,.5*Math.abs(n.x-o.x)+.4*Math.abs(n.y-o.y));let d={x:o.x,y:o.y},c=h;for(let t=1;t<=24;t++){const e=t/24;let s;if(a){const t=.5*(o.x+n.x);s=e<.33?N(o,{x:t,y:o.y},e/.33):e<.67?N({x:t,y:o.y},{x:t,y:n.y},(e-.33)/.34):N({x:t,y:n.y},n,(e-.67)/.33)}else s=C(e,o.x,o.y,o.x+l,o.y,n.x-l,n.y,n.x,n.y);this.edgeData[c++]=d.x,this.edgeData[c++]=d.y,this.edgeData[c++]=r[0],this.edgeData[c++]=r[1],this.edgeData[c++]=r[2],this.edgeData[c++]=s.x,this.edgeData[c++]=s.y,this.edgeData[c++]=r[0],this.edgeData[c++]=r[1],this.edgeData[c++]=r[2],d=s}}render(){if(this.disabled)return;const t=this.gl,e=this.flow,s=e.w.nodeCount_(),i=e.w.edgeCount_(),o=window.devicePixelRatio||1;t.clearColor(.027,.035,.06,1),t.clear(t.COLOR_BUFFER_BIT),t.enable(t.BLEND),t.blendFunc(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA);const n=e.cam.x+this.glCanvas.width/(2*o*e.cam.zoom),r=e.cam.y+this.glCanvas.height/(2*o*e.cam.zoom),h=this._fullRebuildNeeded||s!==this._lastNodeCount,a=this._fullRebuildNeeded||i!==this._lastEdgeCount;if(h){for(let t=0;t<s;t++)this._writeNode(t);t.bindBuffer(t.ARRAY_BUFFER,this.nodeBuf),t.bufferSubData(t.ARRAY_BUFFER,0,this.nodeData.subarray(0,8*s)),this._dirty.clear()}else this._dirty.size&&this._uploadRuns(this._dirty,this.nodeBuf,this.nodeData,8,t=>this._writeNode(t));if(a){for(let t=0;t<i;t++)this._writeEdge(t);t.bindBuffer(t.ARRAY_BUFFER,this.edgeBuf),t.bufferSubData(t.ARRAY_BUFFER,0,this.edgeData.subarray(0,240*i)),this._dirtyEdges.clear()}else if(this._dirtyEdges.size){for(const t of this._dirtyEdges)t>=i&&this._dirtyEdges.delete(t);this._uploadRuns(this._dirtyEdges,this.edgeBuf,this.edgeData,240,t=>this._writeEdge(t))}if(this._lastNodeCount=s,this._lastEdgeCount=i,this._fullRebuildNeeded=!1,i>0&&(t.useProgram(this.progEdge),t.bindBuffer(t.ARRAY_BUFFER,this.edgeBuf),t.enableVertexAttribArray(this.locE.aPos),t.vertexAttribPointer(this.locE.aPos,2,t.FLOAT,!1,20,0),t.enableVertexAttribArray(this.locE.aColor),t.vertexAttribPointer(this.locE.aColor,3,t.FLOAT,!1,20,8),t.uniform2f(this.locE.uCam,n,r),t.uniform1f(this.locE.uZoom,e.cam.zoom*o),t.uniform2f(this.locE.uScreen,this.glCanvas.width,this.glCanvas.height),t.lineWidth(1.6),t.drawArrays(t.LINES,0,48*i)),s>0){t.useProgram(this.progNode),t.bindBuffer(t.ARRAY_BUFFER,this.quadBuf),t.enableVertexAttribArray(this.locN.aQuad),t.vertexAttribPointer(this.locN.aQuad,2,t.FLOAT,!1,0,0),this.instExt&&this.instExt.vertexAttribDivisorANGLE(this.locN.aQuad,0),t.bindBuffer(t.ARRAY_BUFFER,this.nodeBuf);const i=32;if(t.enableVertexAttribArray(this.locN.aCenter),t.vertexAttribPointer(this.locN.aCenter,2,t.FLOAT,!1,i,0),t.enableVertexAttribArray(this.locN.aSize),t.vertexAttribPointer(this.locN.aSize,2,t.FLOAT,!1,i,8),t.enableVertexAttribArray(this.locN.aColor),t.vertexAttribPointer(this.locN.aColor,3,t.FLOAT,!1,i,16),t.enableVertexAttribArray(this.locN.aSel),t.vertexAttribPointer(this.locN.aSel,1,t.FLOAT,!1,i,28),this.instExt&&(this.instExt.vertexAttribDivisorANGLE(this.locN.aCenter,1),this.instExt.vertexAttribDivisorANGLE(this.locN.aSize,1),this.instExt.vertexAttribDivisorANGLE(this.locN.aColor,1),this.instExt.vertexAttribDivisorANGLE(this.locN.aSel,1)),t.uniform2f(this.locN.uCam,n,r),t.uniform1f(this.locN.uZoom,e.cam.zoom*o),t.uniform2f(this.locN.uScreen,this.glCanvas.width,this.glCanvas.height),this.instExt)this.instExt.drawArraysInstancedANGLE(t.TRIANGLES,0,6,s),this.instExt.vertexAttribDivisorANGLE(this.locN.aCenter,0),this.instExt.vertexAttribDivisorANGLE(this.locN.aSize,0),this.instExt.vertexAttribDivisorANGLE(this.locN.aColor,0),this.instExt.vertexAttribDivisorANGLE(this.locN.aSel,0);else for(let e=0;e<s;e++){const s=8*e;t.vertexAttrib2f(this.locN.aCenter,this.nodeData[s],this.nodeData[s+1]),t.vertexAttrib2f(this.locN.aSize,this.nodeData[s+2],this.nodeData[s+3]),t.vertexAttrib3f(this.locN.aColor,this.nodeData[s+4],this.nodeData[s+5],this.nodeData[s+6]),t.vertexAttrib1f(this.locN.aSel,this.nodeData[s+7]),t.drawArrays(t.TRIANGLES,0,6)}}}markNodeDirty(t){this._dirty.add(t)}markEdgeDirty(t){this._dirtyEdges.add(t)}markAllDirty(){this._fullRebuildNeeded=!0}_uploadRuns(t,e,s,i,o){const n=this.gl;n.bindBuffer(n.ARRAY_BUFFER,e);const r=[...t].sort((t,e)=>t-e);let h=r[0],a=r[0];for(let t=1;t<r.length;t++)if(r[t]!==a+1){for(let t=h;t<=a;t++)o(t);n.bufferSubData(n.ARRAY_BUFFER,h*i*4,s.subarray(h*i,(a+1)*i)),h=r[t],a=r[t]}else a=r[t];for(let t=h;t<=a;t++)o(t);n.bufferSubData(n.ARRAY_BUFFER,h*i*4,s.subarray(h*i,(a+1)*i)),t.clear()}dispose(){this._resizeObs?.disconnect(),this.glCanvas?.remove()}}});export{l as ZFlow,S as parseDot,k as parseMermaid};
|