Files
git.stella-ops.org/docs/workflow/engine/16-elksharp-rendering-architecture.md
master e91cf98f8f Add ElkSharp rendering architecture docs, ADRs, tutorial, AGENTS rules
Five documentation deliverables for the ElkSharp rendering improvements:

1. docs/workflow/engine/16-elksharp-rendering-architecture.md (453 lines)
   Full pipeline: Sugiyama stages, edge routing strategies, hybrid
   deterministic mode, gateway geometry, 18-category scoring system,
   corridor routing, Y-gutter expansion, diagnostics.

2. docs/workflow/engine/17-elksharp-architectural-decisions.md (259 lines)
   Six ADRs: short-stub normalization, gateway vertex entries, Y-gutter
   expansion, corridor rerouting, FinalScore adjustment, alongside
   detection.

3. docs/workflow/tutorials/10-rendering/README.md (234 lines)
   Practical tutorial: setup, layout options, SVG/PNG rendering,
   diagnostics capture, violation reports, full end-to-end example.

4. src/__Libraries/StellaOps.ElkSharp/AGENTS.md — 7 new local rules
   for Y-gutter, corridor reroute, gateway vertices, FinalScore
   adjustments, short-stub normalization, alongside detection,
   target-join spread.

5. docs/workflow/ENGINE.md — replaced monolithic ElkSharp paragraph
   with structured pipeline overview, effort-level table, and links
   to the new architecture docs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 11:37:32 +03:00

18 KiB

ElkSharp Rendering Architecture

Overview

ElkSharp is a deterministic, in-process Sugiyama-based graph layout engine for workflow visualization. It replaces external layout dependencies (ElkJs/Node.js) with a pure C# implementation that produces identical output for identical input, regardless of host platform, thread scheduling, or execution environment.

The engine handles the full pipeline from abstract workflow graphs to positioned nodes and routed edges, suitable for SVG/PNG/JSON rendering. It supports left-to-right and top-to-bottom layout directions, three effort levels (Draft, Balanced, Best), compound node hierarchies, and gateway-specific polygon geometry (diamond decisions, hexagon forks/joins).


Sugiyama Pipeline

The core layout algorithm follows the Sugiyama framework for layered graph drawing, extended with workflow-specific constraints.

1. Layer Assignment

Depth-first traversal assigns a layer index to each node. The layer index determines the horizontal position (in left-to-right mode) or vertical position (in top-to-bottom mode) of each node.

  • Start nodes are assigned layer 0.
  • Each successor is assigned max(predecessor layers) + 1.
  • Backward edges (cycles, repeat connectors) are identified and handled separately so they do not influence forward layer assignment.

2. Dummy Node Insertion

Edges that span more than one layer are split into chains of single-layer segments. Each intermediate layer receives a "dummy node" -- a zero-size virtual node that serves as a routing waypoint.

  • Dummy nodes inherit the edge's channel classification (forward, backward, sink).
  • After routing, dummy chains are reconstructed back into the original multi-layer edge with bend points at each dummy position.

3. Node Ordering

Barycenter-based median ordering minimizes edge crossings within each layer.

  • The algorithm sweeps forward and backward across layers, computing each node's barycenter (average position of connected nodes in adjacent layers).
  • Nodes are sorted by barycenter within their layer.
  • Iteration count depends on effort level:
    • Draft: 8 iterations
    • Balanced: 14 iterations
    • Best: 24 iterations
  • Tie-breaking is deterministic (stable sort by node ID) to ensure reproducibility.

4. Initial Placement

After ordering, nodes receive Y-coordinates (in left-to-right mode) based on the median of incoming connection Y-centers.

  • Enforced linear spacing ensures minimum NodeSpacing between adjacent nodes.
  • Nodes with no incoming connections use the median of outgoing connection positions.
  • Grid alignment snaps positions to the nearest grid line for visual consistency.

5. Placement Refinement

Multiple refinement passes adjust positions to reduce visual clutter:

  • Preferred-center pull: Nodes shift toward the center of their connected neighbors' Y-range, weighted by connection count.
  • Snap-to-grid: Positions align to a grid derived from NodeSpacing.
  • Compact-toward-incoming: Nodes pull toward their primary incoming edge direction to reduce edge length and crossings.

Refinement iteration count scales with effort level (3 / 6 / 10 for Draft / Balanced / Best).

6. Y-Gutter Expansion

After edge routing identifies under-node violations (edges running through or alongside nodes), the engine shifts entire Y-bands downward to create routing corridors.

  • Runs after X-gutter expansion and before compact passes.
  • Scans routed edges for horizontal segments that violate under-node or alongside clearance rules.
  • Identifies blocking nodes and computes the required clearance gap.
  • Shifts ALL nodes below the violation Y downward by the clearance amount. This preserves relative ordering within each layer.
  • Re-routes edges with the expanded corridors.
  • Up to 2 iterations to handle cascading violations.

The key insight is that shifting individual nodes disrupts the Sugiyama median-based optimization, causing cascading layout degradation. Shifting entire Y-bands (like X-gutter expansion does for inter-layer gaps) preserves within-layer relationships.

7. X-Gutter Expansion

Inter-layer horizontal gaps are widened to provide edge corridor space.

  • The base gap is LayerSpacing (default 60px).
  • When edge density between two layers exceeds a threshold, the gap is scaled up to 1.8x to accommodate additional routing channels.
  • Expansion is computed before edge routing so that the router has adequate space for orthogonal paths.

Edge Routing

Channel Assignment

Each edge is classified into one of three routing channels:

  • Forward: Source layer < target layer (the common case).
  • Backward: Source layer > target layer (repeat/loop connectors).
  • Sink: Edges to terminal nodes (End events) that may use special corridors.

Channel classification determines routing priority, corridor eligibility, and post-processing rules.

Base Routing

Orthogonal bend-point construction builds an initial route from source to target:

  1. Exit the source node perpendicular to its boundary.
  2. Route horizontally through inter-layer gutters.
  3. Enter the target node perpendicular to its boundary.
  4. Insert 90-degree bends at each direction change.

The base router respects node obstacles, avoiding routes that cross through node rectangles or polygons.

Dummy Edge Reconstruction

After routing, multi-layer dummy chains are merged back to original edges:

  • Bend points from each dummy segment are concatenated.
  • Redundant collinear points are removed.
  • The result is a single edge with bend points at each layer transition.

Anchor Snapping

Edge endpoints are projected onto actual node shape boundaries:

  • Rectangle: Standard side intersection (left, right, top, bottom).
  • Diamond (decision gateways): Intersection with the diamond's four edges, producing diagonal approach stubs.
  • Hexagon (fork/join gateways): Intersection with the hexagon's six edges, with asymmetric shoulder geometry.

Anchor snapping runs after routing so that bend points near the boundary produce clean visual connections.


Iterative Optimization (Hybrid Deterministic Path)

The Best effort level activates hybrid deterministic optimization, which repairs routing violations without disrupting the Sugiyama node placement.

1. Baseline Evaluation

The baseline route is scored using an 18-category violation taxonomy. Each edge receives a violation list with severity-weighted penalties. The total score is the sum of all edge scores.

2. Repair Planning

Penalized edges are identified from the violation severity map. The planner extracts the specific violations for each edge and determines which edges need repair and in what priority order.

High-severity violations (node crossings, under-node, shared lanes) take priority over medium-severity (backtracking, detours) and soft-severity (edge crossings, proximity, bends).

3. Conflict-Zone Batching

Independent repair candidates are grouped by shared source, shared target, or shared corridor zone. Edges in the same conflict zone are batched together so that their repairs are coordinated rather than competing.

Batching ensures that fixing one edge does not create a new violation for a nearby edge in the same zone.

4. Parallel A* Candidate Construction

Each repair batch constructs candidate reroutes using A* 8-direction pathfinding:

  • Candidates are built on full-core parallel threads.
  • Each candidate is a complete reroute for the batch's edge set.
  • The A* grid derives intermediate spacing from approximately one-third of the average service-task node size.
  • Node-obstacle blocked step masks are precomputed per route so neighbor expansion does not rescan every node.
  • Merge back into the route is deterministic and single-threaded.

5. Winner Refinement

The best candidate from each batch undergoes a refinement pipeline:

  1. Under-node repair: Shift lanes that pass through node bounding boxes.
  2. Local-bundle spread: Separate parallel edges that share the same lane.
  3. Shared-lane elimination: Push edges apart that overlap on the same axis.
  4. Boundary-slot snap: Align endpoints to the discrete slot lattice.
  5. Detour collapse: Remove unnecessary overshoots where a shorter path exists.
  6. Post-slot restabilization: Re-validate slot assignments after detour changes.
  7. Corridor reroute: Move long horizontal sweeps to top/bottom corridors.
  8. Elevation adjustment: Shift edges vertically to clear obstructions.
  9. Target-join spread: Push convergent approach lanes apart by minClearance - currentGap + 8px (half applied to each edge).

Winner promotion uses weighted score comparison (Score.Value) to ensure the refinement actually improved the layout.


Gateway Geometry

Gateways use non-rectangular shapes that require specialized boundary logic.

Decision Gateway (Diamond)

  • 4 vertices: left tip, top, right tip, bottom.
  • Left and right tips are the horizontal extremes.
  • Top and bottom are the vertical extremes.
  • Source exits leave from face interiors (not tips).
  • Target entries may use left/right tips as convergence points.
  • ForceDecisionSourceExitOffVertex blocks source exits from tip vertices.

Fork/Join Gateway (Hexagon)

  • 6 vertices: left tip, upper-left shoulder, upper-right shoulder, right tip, lower-right shoulder, lower-left shoulder.
  • Shoulders create flat top and bottom faces suitable for multiple slot entries.
  • Asymmetric geometry: the shoulder offset from the tip varies by gateway size.

Boundary Slot Capacity

Shape Face Max Slots
Gateway (diamond/hexagon) Any face 2
Rectangle Left / Right 3
Rectangle Top / Bottom 5

Slots are evenly distributed within the face's safe boundary inset. Scoring and final repair share the same realizable slot coordinates.

Gateway Vertex Entry Rules

Left and right tip vertices are allowed for target entries but blocked for source exits. This is enforced by a 3-way coordination mechanism:

  1. IsAllowedGatewayTipVertex: Returns true for left/right tips when the edge is a target entry (incoming).
  2. HasValidGatewayBoundaryAngle: Accepts any external approach angle at allowed tip vertices.
  3. CountBoundarySlotViolations: Skips slot-occupancy checks when all entries at a vertex share the same allowed tip point.

All three checks must stay synchronized -- changing one without the others causes cascading boundary-slot violations.


Scoring System

Violation Categories

The scoring system uses 18 violation categories with severity-weighted penalties.

Hard Violations (100,000 per instance)

Category Description
Node crossings Edge segment passes through a node bounding box
Under-node Edge runs beneath or through a node's vertical extent
Shared lanes Two edges share the same routing lane segment
Boundary slots More edges than slots on a node face
Target joins Multiple edges converge to the same target arrival point
Gateway exits Source exit from a blocked gateway vertex
Collector corridors Repeat-collector lane conflicts
Below-graph Edge segment routes below the graph's maximum Y extent

Medium Violations (50,000 per instance)

Category Description
Backtracking Edge reverses direction in the target-approach window
Detours Unnecessary overshoot where a shorter path exists

Soft Violations (200-650 per instance)

Category Description
Edge crossings Two edge segments intersect (200 per crossing)
Proximity Edge passes too close to a node boundary (400)
Labels Edge label overlaps another element (300)
Bends Excessive number of bend points (200 per extra bend)
Diagonals Non-orthogonal segment exceeds one node-shape length (650)

FinalScore Adjustments

The FinalScore applies detection exclusions that are NOT used during the iterative search. This separation is critical: the search uses the raw scoring as its heuristic, and changing it alters the search trajectory (causing speed regressions).

FinalScore excludes these borderline detection artifacts:

  • Valid gateway face approaches: The exterior approach point is closer to the face center than the predecessor bend point (a legitimate face entry, not a violation).
  • Gateway-exit under-node: The lane runs within 16px of the source node's bottom boundary (a tight but valid exit, not a true under-node crossing).
  • Convergent target joins from distant sources: Sources separated by > 15px on the Y-axis with significant X separation (natural convergence, not a shared-lane conflict).
  • Borderline shared lanes: Gap between parallel edges is within 3px of the tolerance threshold (measurement noise, not a real overlap).

Corridor Routing

Long-range edges that would cross many intermediate nodes are routed through corridors outside the main node field.

Top Corridor (Long Sweeps)

For forward edges spanning more than 40% of the graph width:

  • Route through the top corridor at graphMinY - 56.
  • Exit the source with a 24px perpendicular stub.
  • Route horizontally across the top corridor.
  • Descend to the target.

The 24px exit stub is critical: it prevents NormalizeBoundaryAngles from collapsing the vertical corridor segment back into the source boundary.

Bottom Corridor (Near-Boundary Sweeps)

For edges that need to route near the graph's lower boundary:

  • Route through the bottom corridor at graphMaxY + 32.
  • Same perpendicular exit stub pattern.

Below-Graph Detection

The below-graph violation detector (HasCorridorBendPoints) exempts edges that intentionally use corridor routing. Without this exemption, corridor edges would be penalized as below-graph violations and rerouted back into the node field.


Y-Gutter Expansion (Routing-Aware Placement Feedback Loop)

Y-gutter expansion is a post-routing placement correction that creates vertical routing space where the initial Sugiyama placement left insufficient clearance.

Algorithm

  1. Detection: After edge routing, scan all routed edge segments for horizontal segments that violate under-node or alongside clearance rules.

  2. Identification: For each violation, identify the blocking node and compute the required clearance:

    • Under-node: The edge passes through the node's bounding box.
    • Alongside (flush): The edge runs within +/-4px of a node's top or bottom boundary (the "alongside" extension catches edges "glued" to boundaries that the standard gap > 0.5px check misses).
  3. Expansion: Shift ALL nodes below the violation Y downward by the computed clearance amount. This preserves relative ordering within each layer, unlike individual node shifting which disrupts Sugiyama optimization.

  4. Re-routing: Re-route edges with the expanded corridors.

  5. Iteration: Repeat up to 2 times to handle cascading violations (where fixing one violation exposes another).

Design Rationale

The same pattern is used for X-gutter expansion (widening inter-layer gaps). Band-level shifting is fundamentally different from individual node adjustment:

  • Individual node shifts break the barycenter ordering that the Sugiyama algorithm optimized, causing cascading position changes.
  • Post-refinement clearance insertion fails because subsequent optimization passes override the inserted space.
  • Band-level shifts preserve within-layer relationships while creating the needed routing corridors.

Timing

Y-gutter expansion runs:

  • AFTER X-gutter expansion (inter-layer gaps are already set).
  • BEFORE compact passes (so compaction respects the new corridors).
  • BEFORE the iterative optimization loop (so the optimizer works with adequate routing space).

Effort Levels

Level Ordering Iterations Placement Iterations Routing
Draft 8 3 Baseline only
Balanced 14 6 Baseline + light repair
Best 24 10 Hybrid deterministic with full-core parallel repair
  • Draft: Fastest layout for previews and interactive editing. No iterative optimization. Suitable for graphs under ~20 nodes.
  • Balanced: Good quality for medium graphs. Light repair fixes the worst violations without full A* search.
  • Best: Production quality for rendered artifacts (SVG, PNG). Full hybrid deterministic optimization with parallel candidate construction. Typical runtime: 12-15 seconds for complex workflow graphs.

Layout Options

Option Type Default Description
Direction Enum LeftToRight Layout direction. TopToBottom uses the legacy iterative path.
NodeSpacing int 40 Vertical gap between nodes (px). Scaled by edge density up to 1.8x.
LayerSpacing int 60 Horizontal gap between layers (px).
Effort Enum Best Layout quality vs. speed tradeoff.

Edge Density Scaling

When the number of edges between two adjacent layers exceeds a threshold, both NodeSpacing and LayerSpacing are scaled up to accommodate additional routing channels. The maximum scale factor is 1.8x, applied per-layer-pair.


Diagnostics

The layout engine emits detailed diagnostics when running in Best effort mode:

  • Live progress log: Baseline state, strategy starts, per-attempt scores, and adaptation decisions logged during execution.
  • Per-attempt phase timings: Routing time, post-processing time, and route-pass counts for each optimization attempt.
  • SVG/PNG/JSON artifacts: The document-processing artifact test produces rendered output alongside diagnostic data.
  • Violation reports: Per-edge violation lists with category, severity, geometry details, and FinalScore adjustments.

Diagnostics are detailed enough to prove routing progress and to profile optimization performance for regression detection.