diff --git a/decnet_web/src/components/MazeNET/Canvas.tsx b/decnet_web/src/components/MazeNET/Canvas.tsx index 3f75de8f..e9ff65e3 100644 --- a/decnet_web/src/components/MazeNET/Canvas.tsx +++ b/decnet_web/src/components/MazeNET/Canvas.tsx @@ -68,6 +68,15 @@ const Canvas = forwardRef(function Canvas( const selectNet = useCallback((id: string) => setSelection({ type: 'net', id }), [setSelection]); const selectNode = useCallback((id: string) => setSelection({ type: 'node', id }), [setSelection]); + // Flowing-dash edge animation is the single most expensive thing + // on the canvas — each animated invalidates its bounding + // box every frame, and inter-LAN paths are long so the invalidated + // rects overlap most of the viewport. Past ~60 edges the compositor + // spends every frame repainting. Drop the animation class above + // the threshold; edges stay fully visible, just static. + const ANIMATE_EDGE_LIMIT = 60; + const animateEdges = edges.length <= ANIMATE_EDGE_LIMIT; + const activeNetIds = useMemo(() => { const nodeNet = new Map(nodes.map((n) => [n.id, n.netId])); const ids = new Set(); @@ -158,7 +167,7 @@ const Canvas = forwardRef(function Canvas( { ev.stopPropagation(); setSelection({ type: 'edge', id: e.id }); }} onContextMenu={onEdgeContextMenu?.(e.id)}> - {e.label && ( @@ -252,6 +261,11 @@ const Canvas = forwardRef(function Canvas( PAN: {Math.round(pan.x)},{Math.round(pan.y)} ZOOM: {Math.round(zoom * 100)}% AS-OF {lastEventAt ? fmtTime(lastEventAt) : '--:--:--'} + {!animateEdges && ( + + MOTION: OFF + + )}