From 9bed9304978ba164acd3bbee240087b4c78767bf Mon Sep 17 00:00:00 2001 From: anti Date: Fri, 24 Apr 2026 19:01:25 -0400 Subject: [PATCH] perf(web/mazenet): auto-disable edge flow animation above 60 edges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .maze-edge-dash CSS animation invalidates each path's bounding box every frame. Inter-LAN paths span the viewport so invalidations overlap, and past ~60 edges the compositor spends every frame repainting — the dominant cost on the 12+ LAN screenshot, even dwarfing pan-drag overhead. Drop the animation class when edges.length > 60. Edges stay fully visible and traffic-tinted, just static. A MOTION: OFF segment in the status bar surfaces the auto-disable so it doesn't look like a broken animation. Threshold is a constant in Canvas.tsx; if it needs to become a user toggle later, lift it to state + localStorage in one place. --- decnet_web/src/components/MazeNET/Canvas.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) 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 + + )}