Skip to content

v0.16.0 — magnetic docking - #21

Merged
Coldbari merged 1 commit into
mainfrom
feat/magnetic-docking
Sep 1, 2026
Merged

v0.16.0 — magnetic docking#21
Coldbari merged 1 commit into
mainfrom
feat/magnetic-docking

Conversation

@Coldbari

@Coldbari Coldbari commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Connect by touching instead of by drawing.

Drag a symbol — in from the palette, or one already on the sheet — so one of its
connection points comes within ~18 screen px of another symbol's, and a ring
marks the point it has caught while every connection point lights up. Let go and
the symbol clicks into place, the two points landing on exactly the same spot,
with the line already drawn.

Because a line stores ports and not coordinates, pulling the pair apart
afterwards stretches the pipe instead of breaking it.

Details that make it behave

  • Line class comes from the ports, not the toolbar. A controller docking
    onto a valve's signal boss gets signal.electric even with a process class
    selected. Incompatible pairings never dock.
  • Reach is judged in screen px, so it feels the same at any zoom — clamped
    in sheet space so an extreme zoom can neither make it unhittable nor grabby
    enough to swallow neighbouring symbols.
  • An already-joined pair won't dock again, so nudging a docked symbol can't
    stack a second identical line on the first.
  • One undo step for the symbol and the line it docked onto, whether it came
    from the palette (addBatch) or a drag across the sheet (dockNode).
  • The hint ring lives inside .joint-layers, the group carrying the pan/zoom
    transform, so it sits on the sheet rather than floating over the viewport.

One change on top of the original work

Added a prefers-reduced-motion guard so the ring stops pulsing for users who
ask for less motion — it still marks the spot. The rest of this stylesheet
already honours that, so the new animation was the odd one out.

Verification

  • npm run build — clean
  • npm test724 passing (10 new: findDock / dockEdge / dockRadius,
    covering rotation, zoom clamping, closest-candidate selection, incompatible
    ports, and the already-joined guard)
  • npx playwright test62 passing, 1 skipped (3 new: a palette drop that
    docks, a drop clear of everything that simply lands, and a drag that docks
    then stretches when pulled away)

🤖 Generated with Claude Code

Connect by touching instead of by drawing.

Drag a symbol — in from the palette, or one already on the sheet — so one of
its connection points comes within about 18 screen px of another symbol's, and
a ring marks the point it has caught while every connection point on the sheet
lights up. Let go and the symbol clicks into place, the two points landing on
exactly the same spot, with the line already drawn between them.

Because a line stores PORTS and not coordinates, pulling the pair apart
afterwards stretches the pipe instead of breaking it.

Details that make it behave

- The line class comes from the two port kinds, not the toolbar: a controller
  docking onto a valve's signal boss gets signal.electric even with a process
  class selected. Incompatible pairings never dock at all.
- The reach is judged in SCREEN px so it feels the same at any zoom, clamped in
  sheet space so an extreme zoom can neither make it unhittable nor grabby
  enough to swallow neighbouring symbols.
- A pair that is already joined will not dock again, so nudging a docked symbol
  cannot stack a second identical line on the first.
- The symbol and the line it docked onto are ONE undo step, whether they came
  from the palette (addBatch) or from a drag across the sheet (dockNode).
- The hint ring lives inside .joint-layers, the group carrying the pan/zoom
  transform, so it sits on the sheet rather than floating over the viewport.
- The palette exports the drag in flight, because dragover is not allowed to
  read dataTransfer — browsers only hand the payload over on drop — and the
  canvas needs to know WHAT is being dragged to preview where it would dock.

Also honours prefers-reduced-motion: the ring still marks the spot, it just
stops pulsing.

Tests: 10 unit cases over findDock/dockEdge/dockRadius covering rotation, zoom
clamping, closest-candidate selection, incompatible ports and the
already-joined guard; 3 e2e covering a palette drop that docks, a drop clear of
everything that simply lands, and a drag that docks then stretches when pulled
away.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Coldbari
Coldbari merged commit be431e9 into main Sep 1, 2026
4 checks passed
@Coldbari
Coldbari deleted the feat/magnetic-docking branch September 2, 2026 06:17
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