Skip to content

Draw connections on a canvas instead of as reconciled SVG elements - #330

Merged
dovvnloading merged 1 commit into
mainfrom
feat/canvas-connection-rendering
Aug 14, 2026
Merged

Draw connections on a canvas instead of as reconciled SVG elements#330
dovvnloading merged 1 commit into
mainfrom
feat/canvas-connection-rendering

Conversation

@dovvnloading

Copy link
Copy Markdown
Owner

Problem

Connections were rendered by the flow library as one SVG element per link, positioned from the library's own node records and reconciled by React. During a drag that put the node card and the line attached to it on two different update paths, and the line was drawn on screen for a position the node had already left. The gap grew with pointer speed, pointed opposite the direction of travel, and closed as soon as movement stopped.

Ten prior attempts failed to change what the user saw: reducing re-renders, preserving measurements, suspending culling, correcting positions inside the library's change pipeline, handing node state to the library, writing the SVG path imperatively, and rewriting it before every paint. Each of those changed when or what was computed. None removed the underlying fact that connection geometry was stored somewhere that could fall behind the gesture.

Change

Connections are drawn by a single canvas layer that redraws every frame from the current node positions and the current viewport transform. The library is handed an empty edge list, so its edge machinery is inert rather than merely invisible and is no longer part of the drag path.

There is no per-link element and no retained geometry, so a link cannot be drawn from a position that is out of date - there is no stored position to be out of date. This is the immediate-mode approach long-standing node editors use, for this exact reason.

Preserved: hover, selection, orthogonal routing, and faded connections. Hit testing runs against the geometry the canvas last drew, so what is visible and what is clickable cannot disagree. Deleting a selected connection is handled here now, since the library no longer reports edge deletions.

Test plan

  • Full frontend check passes: schema, types, lint (0 errors), 1931/1931 tests, production build, bundle size
  • Confirmed resolved on the affected machine by the reporter

Connections were rendered by the flow library as one SVG element per link,
positioned from the library's own node records and reconciled by React.
During a drag that put a node card and the line attached to it on two
different update paths, and the line was drawn on screen for a position
the node had already left - a gap that grew with pointer speed and closed
when movement stopped.

Ten attempts to make those two paths agree did not change what the user
saw: reducing re-renders, preserving measurements, suspending culling,
correcting positions inside the library's change pipeline, handing node
state to the library, writing the SVG path imperatively, and rewriting it
before every paint. Each addressed when or what was computed, none
removed the fact that connection geometry was stored somewhere that could
fall behind the gesture.

Connections are now drawn by a single canvas layer that redraws each
frame from the current node positions and viewport transform. The library
is handed no edges at all, so its edge machinery is inert rather than
merely invisible. There is no per-link element and no retained geometry,
so a link cannot be drawn from a stale position - there is no stored
position to be stale. This is the immediate-mode approach long-standing
node editors use, and the reporter confirms it resolves the symptom.

Hover, selection, orthogonal routing and faded connections are preserved.
Hit testing runs against the geometry the canvas last drew, so what is
visible and what is clickable cannot disagree. Deleting a selected
connection is handled here now, since the library no longer reports edge
deletions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dovvnloading
dovvnloading merged commit 858f831 into main Aug 14, 2026
@dovvnloading
dovvnloading deleted the feat/canvas-connection-rendering branch August 15, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant