Skip to content

feat(library): route straight edges and tidy syntax trees - #835

Draft
FelixTJDietrich wants to merge 6 commits into
mainfrom
feat/straight-edge-autolayout
Draft

feat(library): route straight edges and tidy syntax trees#835
FelixTJDietrich wants to merge 6 commits into
mainfrom
feat/straight-edge-autolayout

Conversation

@FelixTJDietrich

@FelixTJDietrich FelixTJDietrich commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds automatic routing for straight-edge diagram families and a tidy
layout for syntax trees:

  • Clear connections stay straight. A connection reroutes only when it actually
    meets a node; connector crossings keep the existing line-jump presentation.
  • Necessary detours keep breathing room around nodes, favor short and gentle
    paths, and never replace a readable crossing with a disproportionate trip
    around the diagram.
  • Connections choose facing sides and spread sibling endpoints across shared
    borders instead of stacking on one point.
  • Hand-placed routes remain exactly as drawn. Automatic bends are derived and
    never written into the diagram model.
  • Syntax trees gain a Tidy tree layout toolbar action and the additive
    ApollonEditor.layoutSyntaxTree() API.

The branch is rebased directly onto the current main, which includes the
straight-edge editing work from #834.

Follow-up to the node-overlap report in #282, which was closed by the manual
straight-edge editing work in #834. Long-text wrapping is outside this PR and is
not claimed as fixed.

Why this is intentionally conservative

Automatic routing should help without making a diagram feel restless:

  • The direct line has a 1 px collision guard, while a generated detour receives
    the full 10 px minimum clearance. A nearby node therefore does not trigger a
    route change just because it enters the preferred clearance halo.
  • Other connections do not become routing obstacles. Crossings therefore remain
    direct and predictable, while the existing line jumps preserve readability.
  • A 5% deterministic endpoint-side deadband prevents small movements near a
    node corner from flipping the connection to another side.
  • While a node is moving, its valid straight-edge topology is kept for the full
    gesture. It changes immediately only if keeping it would cross a node, then
    settles to the exact route on release.
  • Node drags involving straight connections use the routing worker even in small
    diagrams. The display-only handoff preserves diagonal polylines instead of
    briefly turning them into step edges.

Compatibility and failure behavior

  • Existing hand-authored straight routes bypass automatic obstacle routing.
  • Existing orthogonal routing is unchanged.
  • Native-handle previews and commits use the same validated handle point, even
    when the pointer is off-center or nodes overlap.
  • Tidy layout is one undoable operation. Valid trees and forests are arranged;
    cyclic, multi-parent, and otherwise malformed components stay where the user
    placed them.
  • The toolbar waits for controlled node positions to reach React Flow and then
    performs the same inset-aware fit as the public API.
  • layoutSyntaxTree() is additive and is a no-op for other diagram types.

Release note

Keep straight connections clear, stable, and responsive automatically. They now
choose facing sides, spread sibling links across shared borders, and route around
nodes without reorganizing when other connections cross them; clear shots remain
straight and hand-placed routes stay exactly as drawn. Syntax trees also gain a
one-click tidy layout that arranges valid parent-child forests while leaving
malformed portions untouched.

Implementation notes

  • Routing uses a deterministic, integer-based visibility graph and A* search,
    including deterministic tie-breaking.
  • The visibility graph starts with obstacles that block the direct route, adds
    newly relevant node bodies locally, and has a bounded full-field fallback.
  • Third-party node bodies are never exempted when an endpoint starts inside
    their clearance halo.
  • Coordinated endpoint seats keep straight-edge fans evenly distributed.
  • In a new crossing-heavy 12-edge Chromium regression fixture, local profiling
    reduced the worst solve from 2,629.7 ms to 20.5 ms. This is a regression
    fixture result, not a general-purpose benchmark.
  • Bundle cost remains explicit and within the existing budgets:
    • main entry: 125.72 kB / 126 kB
    • routing worker: 41.45 kB / 44 kB
    • model chunk: 5.08 kB / 8 kB
    • export chunk: 413.41 kB / 700 kB

Steps for testing

  1. Open a crowded use-case, syntax-tree, or Petri-net diagram and confirm that
    straight connections avoid intervening nodes.
  2. Move a node close to a clear connection without touching it; the edge should
    remain straight. Move it into the line; the edge should take a compact,
    well-cleared detour.
  3. Move a node repeatedly near an endpoint-side boundary and confirm the edge
    does not jump sides on small movements.
  4. Create sibling connections and confirm their endpoints fan out. Cross two
    connections and confirm they remain direct and use the existing line jump.
  5. Add or move a manual bend, then place a node over that route. The authored
    route should remain exactly as drawn.
  6. Drop a connection off-center within a native handle and confirm the committed
    endpoint exactly matches the preview.
  7. Apply Tidy tree layout to a valid forest and confirm one-step undo and an
    inset-aware fit. Repeat with cyclic or multi-parent content and confirm the
    malformed components are not rearranged.
  8. Call ApollonEditor.layoutSyntaxTree() on a syntax tree and on another
    diagram type; confirm layout in the former and a no-op in the latter.

Verification

  • pnpm lint && pnpm format:check && pnpm build && pnpm test
    • 95 test files passed
    • 1,860 tests passed; 1 skipped
  • Fresh production-build Chromium interaction run:
    • 17/17 targeted connection and straight-edge UX tests passed
  • Fresh production-build crossing-heavy performance regression:
    • passed 5/5 Chromium runs and 5/5 Firefox runs at the 34 ms p95 frame budget
  • pnpm --filter @tumaet/apollon size
    • all four published bundle budgets passed

Screenshots / screencasts

A syntax tree after applying the tidy tree layout, with a balanced hierarchy and clear straight connections

Captured from this branch's production build after choosing Tidy tree layout.
Deterministic geometry fixtures cover route quality and failure cases beyond this
representative diagram.

Checklist

  • Linked the applicable portion of Syntax tree diagram: long text overlaps nodes (needs line wrapping) #282
  • Added a user-facing changeset
  • Used a Conventional Commit PR title matching the user-visible feature
  • Added unit and browser interaction coverage
  • Passed the complete local pre-PR gate
  • Kept published bundles within their documented budgets
  • Documented the additive public API inline
  • Included a representative screenshot

@FelixTJDietrich
FelixTJDietrich force-pushed the feat/straight-edge-autolayout branch 3 times, most recently from fa52ca3 to 9dd8f0e Compare July 28, 2026 09:59
Base automatically changed from feat/straight-edge-customization to main July 28, 2026 12:33

@Claudia-Anthropica Claudia-Anthropica left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FelixTJDietrich The deterministic routing and tidy-tree work is thoughtfully structured, but the new straight router can still pass through a nearby node and can miss sibling-only crossings. Native-handle commits can also diverge from the preview; I left the concrete fixes inline.

Comment thread library/lib/utils/geometry/straightPolylineRouter.ts Outdated
Comment thread library/lib/utils/geometry/straightPolylineRouter.ts Outdated
Comment thread library/lib/hooks/useConnect.ts Outdated
Comment thread library/lib/chrome/builtins/ZoomControls.tsx Outdated
@github-project-automation github-project-automation Bot moved this from Backlog to In progress in Apollon Development Jul 28, 2026
@FelixTJDietrich
FelixTJDietrich force-pushed the feat/straight-edge-autolayout branch from 9dd8f0e to 20db1b6 Compare July 28, 2026 13:14

@Claudia-Anthropica Claudia-Anthropica left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FelixTJDietrich The follow-up fixes address the obstacle-halo, sibling-crossing, and native-handle preview/commit issues from my previous review, with focused regressions covering each path. The relevant local unit suites pass, so this looks good to merge.

@Claudia-Anthropica Claudia-Anthropica left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FelixTJDietrich The new commits preserve obstacle-body safety while stabilizing straight-edge routing, aimed-outline previews, and worker-backed interaction performance. The previous findings remain resolved, all captured CI checks pass, and I found no current blocking defect.

@FelixTJDietrich
FelixTJDietrich marked this pull request as draft August 20, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

2 participants