Skip to content

Diagram Readability (v0.25.0): grid, guarded orthogonal routing, connection editing, Templates and node outlines #344

Description

@MerciHanrim

Summary

Diagrams become hard to read as they grow: connections run through nodes, labels sit on nodes and on each other, ports that should line up are a few pixels apart, and nothing snaps to the grid the canvas already draws. This umbrella issue tracks the whole Diagram Readability migration. Its six steps ship together as one release, v0.25.0, so that coordinates, routes, Templates, node outlines and the visual baselines change once rather than several times. The release notes, the change declaration and the baselines are settled once, after the last step.

Current state (main 10098d6, every Template in all 18 languages)

  • The canvas draws a 16 px dot grid, but nothing snaps to it: positions are stored as floats, new nodes get a random ±40 px jitter, arrow keys move 5 / 20 px.
  • Ports sit at the centre of each side, and a node's height depends on its text, so the same node's ports move between languages.
  • A connection is a Bézier curve that ignores nodes unless it is switched to the orthogonal router, which avoids other nodes' boxes but not labels and not the connection's own end nodes; when it finds no path it draws a plain L / Z through whatever is in the way.
  • Labels sit at the middle of their connection with no collision handling.
  • Summed over the 18 languages, Early MMO (97 nodes, 144 connections) has 1,632 lines through nodes, 336 labels on nodes, 235 labels on labels and 83 near-miss jogs; its nodes overlap each other in seven long languages. The 3-zone gacha is nearly clean only because its 77 routes and 12 waypoints were tuned by hand. The three small Templates are clean apart from about one 1 px jog per language.

Measured direction

  • Curves everywhere make the complex Templates worse (MMO: 2,341 lines through nodes).
  • Today's router everywhere cuts lines through nodes by 76 % but leaves the labels and sends backward connections through their own end node.
  • The guarded orthogonal route (labels placed in free slots, a reroute around a label kept only when it is not worse) gives, on the grid, MMO 388 lines through nodes, 17 labels on nodes, 0 labels on labels, 0 jogs; Gacha matches its hand-tuned routes without waypoints. Every line through a node that remains is a router fallback.
  • It raises crossings and bends in MMO on today's layout; the Template re-placement has to bring them back.

Decisions (2026-10-09)

  • Ports: the resource port row sits 28 px below the node's top whatever its height or language; the node grows downward; the drawn port is projected onto the outline, the routing lane is on the 16 px grid.
  • Re-placement: an ordinary document, file or share link with an older layoutVersion is re-placed once, deterministically, when it is opened, before its history starts (not an undo entry), from a canonical geometry that does not depend on the language or on font measurement; the new layoutVersion is stored. A position chosen freely with Alt is kept. Tidy to grid re-places the current document as one undo step. Bundled Templates are re-placed and reviewed in their source.
  • Records are not converted: revision and proposal payloads always keep their recorded coordinates, and a Project autosave based on a revision is not converted either. Tidy to grid on such a document changes only the current document, as one cosmetic change and one undo step; the base revision and the proposal source stay as recorded, so Review shows the real layout differences.
  • Rows 8–16 px apart merge only when the nodes are directly connected by a flow or in the same logical layer, without reversing an order or creating an overlap; otherwise the next grid row.
  • Default shape: the guarded orthogonal route for new and converted connections; node avoidance before label avoidance; no fallback through a node (search again with less clearance, then a safe outer detour); labels in free slots; unrelated connections pay a cost for sharing a trunk.
  • Modifiers: Alt = free move for nodes, selections and frames; Ctrl / Command = move a frame only (Alt's role before); Shift = multi-selection and the large keyboard step, unchanged.
  • Acceptance: node and label collisions go down and, for every Template, crossings and shared trunks are not worse than today.

Connection shapes and route editing

  • Auto orthogonal (the guarded router) is the default; Curved (today's Bézier) and Straight (a direct line) are choices; Manual orthogonal keeps the author's bend points.
  • Editing an automatic route by hand turns it into Manual orthogonal; Reset to automatic returns it to the router's route.
  • Bend points snap to the 16 px grid, Alt moves one freely; each add, move or delete is one undo step; nothing changes a route while the canvas is locked.
  • Shapes and bend points are saved in files and share links and never change the engine digest or a simulation result.
  • The phone draws every route but offers no route editing.
  • Bundled Templates use automatic routes, with a manual bend point only where the router cannot resolve a case.
  • Out of scope for v0.25.0: editing Bézier control points, and further line decorations.

Steps (all in v0.25.0)

  • Step 1: grid, fixed port row, snapping and modifiers, layoutVersion with the one-time conversion, Tidy to grid.
  • Step 2: automatic orthogonal routing and label placement (own end nodes as obstacles, no node-crossing fallback, label slots, guarded label obstacles, trunk cost).
  • Step 3: connection shape choice and manual route editing.
  • Step 4: re-place and review all five bundled Templates, with room for each node's widest language.
  • Step 5: node outline and text containment (fix(canvas): text stays inside the Pool, Source, Drain, Converter and Gate outlines at every width #337) on that base, keeping the 28 px port row.
  • Step 6: an automated collision check for connections, labels and outlines over all 18 languages, then the final baselines.

Compatibility

The file gains layoutVersion. Ordinary documents are converted once on open; the conversion moves positions and connection routes; it never changes the engine digest or any simulation result. Off-grid positions remain valid input. The visual baselines are reviewed as one exact list, once, before they are updated.

Out of scope

  • Automatic layout from scratch (ranking, layering): the author's arrangement is kept.
  • Phone-specific layout (phone geometry is identical to desktop).

Activity

  1. changed the title [-]Diagram Readability: grid placement, guarded orthogonal routing and label placement[/-] [+]Diagram Readability (v0.25.0): grid, guarded orthogonal routing, connection editing, Templates and node outlines[/+] on Oct 9, 2026
  2. MerciHanrim commented on Oct 10, 2026

    @MerciHanrim
    OwnerAuthor

    Released: v0.25.0

    Diagram Readability shipped as one migration in v0.25.0, from PR #345 (head 1b2824d, squash commit 24d0d91 on main, the same tree). The contract is in docs/diagram-layout.md, docs/edge-routing.md §ER14–§ER16 and docs/specs/SEMANTICS-R10.md.

    The six steps

    1. The grid and the conversion. A 16 px grid and a fixed port row 28 px below a node's top; snapping for new nodes, drags, frames and arrow keys (16 / 64 px); Alt is a free move and Ctrl / ⌘ moves a frame alone. An ordinary older document is re-placed once when it opens, before its history starts (layoutVersion 1); revisions, proposals and a revision-based Project autosave are excluded from the automatic conversion and keep their recorded layout. Tidy to grid re-places the current document as one undo step. Smart guides were added on the same base: port row, centre and edges, then the grid.
    2. Automatic orthogonal routing. The guarded router never crosses a node fill, own end nodes included; same-port fans share only a 16 px stub and branch past it; labels take a free slot on their own route; unresolved cases are reported, never hidden.
    3. Connection shapes and bend points. Orthogonal (the default), Curved and Straight, with bend points that make an orthogonal route manual and Reset to automatic; one undo step each; Straight is loop-revision/10. The phone shows every shape and bend point without editing.
    4. The Templates. All five placed for the grid by each node's widest box over the 18 languages with a 48 x 32 px clearance and 32 px between frames, every connection automatic, with readable opening views for the coffee roastery and early MMO Templates.
    5. Text inside the outline (fix(canvas): text stays inside the Pool, Source, Drain, Converter and Gate outlines at every width #337). The Pool, Source, Drain, Converter and Gate are drawn for their own width and every painted element keeps 8 px inside the drawn outline; the Templates were placed again by the new widest boxes, and the conversion keeps frame membership with a frozen pre-outline box.
    6. Collisions and baselines. An automated check over all 18 languages, on the bundled Templates and at users' coordinates (the Templates as saved before v0.25.0, converted): no blocked or outer-corridor route, no fan overlap past its stub, no connection through a node, no label on a node, no frame cutting a node and no node overlap. Of the 76 visual baselines, 57 were replaced, 6 intentionally retained and 13 byte-identical. The MMO opening view keeps its four core start nodes whole in every language, with the minimap open or collapsed.

    Verification

    • CI on main (24d0d91): 2,105 browser tests in six shards, the production-bundle suite (16) and the PWA suite (19), no failure and no retry.
    • Production (build 24d0d91), in a fresh browser context: the right version and build, no page, console or request errors, What's new with the five v0.25.0 items, new nodes on the grid, orthogonal routes, Tidy to grid and the Route choices in place.
    • The CI split grew to six time-cut shards with refreshed weights (docs/ci-e2e-shards.md); the zh-Hant startup retries seen on the PR's CI runs are recorded on test(e2e): the zh-Hant descriptive-copy wrapping test slows down on CI and ended a browser session #305, which stays open.

    Not in this release

    Editing curve control points directly and further line decorations are out of scope for v0.25.0; they are a candidate for a later design survey.

    Closing as completed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions