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>
This commit is contained in:
234
docs/workflow/tutorials/10-rendering/README.md
Normal file
234
docs/workflow/tutorials/10-rendering/README.md
Normal file
@@ -0,0 +1,234 @@
|
||||
# Tutorial 10: Rendering Workflow Diagrams
|
||||
|
||||
This tutorial shows how to use the Stella Ops workflow rendering system to produce
|
||||
visual diagrams from workflow definitions.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A workflow canonical definition (from the compiler or imported JSON).
|
||||
- Reference to `StellaOps.Workflow.Renderer` and `StellaOps.ElkSharp` assemblies.
|
||||
|
||||
---
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### 1. Create the Layout Engine
|
||||
|
||||
```csharp
|
||||
var engine = new ElkSharpWorkflowRenderLayoutEngine();
|
||||
```
|
||||
|
||||
### 2. Configure Layout Options
|
||||
|
||||
```csharp
|
||||
var request = new WorkflowRenderLayoutRequest
|
||||
{
|
||||
Direction = WorkflowRenderLayoutDirection.LeftToRight,
|
||||
Effort = WorkflowRenderLayoutEffort.Best,
|
||||
NodeSpacing = 40,
|
||||
LayerSpacing = 60,
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Compute the Layout
|
||||
|
||||
```csharp
|
||||
var layout = await engine.LayoutAsync(graph, request);
|
||||
```
|
||||
|
||||
The `graph` parameter is a `WorkflowRenderGraph` produced by the
|
||||
`WorkflowRenderGraphCompiler` from a canonical workflow definition.
|
||||
|
||||
### 4. Render to SVG
|
||||
|
||||
```csharp
|
||||
var svgRenderer = new WorkflowRenderSvgRenderer();
|
||||
var svgDoc = svgRenderer.Render(layout, "My Workflow");
|
||||
await File.WriteAllTextAsync("workflow.svg", svgDoc.Svg);
|
||||
```
|
||||
|
||||
### 5. Export to PNG
|
||||
|
||||
```csharp
|
||||
var pngExporter = new WorkflowRenderPngExporter();
|
||||
await pngExporter.ExportAsync(svgDoc, "workflow.png", scale: 2f);
|
||||
```
|
||||
|
||||
The `scale` parameter controls the pixel density (2f = 2x resolution for HiDPI).
|
||||
|
||||
---
|
||||
|
||||
## Layout Options Reference
|
||||
|
||||
### Direction
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `LeftToRight` | Nodes flow left to right (default for workflows). |
|
||||
| `TopToBottom` | Nodes flow top to bottom. Uses the legacy iterative path. |
|
||||
|
||||
### Effort Levels
|
||||
|
||||
| Level | Speed | Quality | Use Case |
|
||||
|-------|-------|---------|----------|
|
||||
| `Draft` | Fast (~1s) | Basic | Interactive editing, previews |
|
||||
| `Balanced` | Medium (~3-5s) | Good | Medium graphs, dev-time rendering |
|
||||
| `Best` | Slow (~12-15s) | Production | Final artifacts, export, CI rendering |
|
||||
|
||||
**Draft** uses 8 ordering iterations, 3 placement iterations, and baseline routing
|
||||
only. No iterative optimization is performed.
|
||||
|
||||
**Balanced** uses 14 ordering iterations, 6 placement iterations, and light repair
|
||||
that fixes the worst violations without full A* search.
|
||||
|
||||
**Best** uses 24 ordering iterations, 10 placement iterations, and the hybrid
|
||||
deterministic optimization pipeline with full-core parallel repair candidates.
|
||||
|
||||
### Spacing
|
||||
|
||||
- **NodeSpacing** (default 40): Vertical gap between nodes in pixels. The engine
|
||||
may scale this up to 1.8x when edge density is high.
|
||||
- **LayerSpacing** (default 60): Horizontal gap between layers in pixels.
|
||||
|
||||
---
|
||||
|
||||
## Reading the Layout Result
|
||||
|
||||
The `LayoutAsync` result contains positioned nodes and routed edges.
|
||||
|
||||
### Nodes
|
||||
|
||||
```csharp
|
||||
foreach (var node in layout.Nodes)
|
||||
{
|
||||
Console.WriteLine($"Node {node.Id}: ({node.X}, {node.Y}) " +
|
||||
$"size {node.Width}x{node.Height} " +
|
||||
$"shape={node.Shape}");
|
||||
}
|
||||
```
|
||||
|
||||
Node shapes include `Rectangle` (service tasks), `Diamond` (decision gateways),
|
||||
`Hexagon` (fork/join gateways), `Circle` (start/end events), and others.
|
||||
|
||||
### Edges
|
||||
|
||||
```csharp
|
||||
foreach (var edge in layout.Edges)
|
||||
{
|
||||
Console.WriteLine($"Edge {edge.SourceId} -> {edge.TargetId}");
|
||||
foreach (var point in edge.BendPoints)
|
||||
{
|
||||
Console.WriteLine($" bend: ({point.X}, {point.Y})");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bend points define the orthogonal path from source to target. Two consecutive
|
||||
bend points with the same Y form a horizontal segment; two with the same X
|
||||
form a vertical segment.
|
||||
|
||||
---
|
||||
|
||||
## Diagnostics
|
||||
|
||||
When using `Best` effort, the engine captures detailed diagnostics about the
|
||||
optimization process.
|
||||
|
||||
### Enabling Diagnostics
|
||||
|
||||
Diagnostics are captured automatically in `Best` mode. Access them through
|
||||
the layout result.
|
||||
|
||||
### Violation Report
|
||||
|
||||
The violation report lists each edge's violations with category, severity,
|
||||
and geometric details.
|
||||
|
||||
```csharp
|
||||
if (layout.Diagnostics?.ViolationReport != null)
|
||||
{
|
||||
foreach (var entry in layout.Diagnostics.ViolationReport)
|
||||
{
|
||||
Console.WriteLine($"Edge {entry.EdgeId}: " +
|
||||
$"{entry.Category} (penalty {entry.Penalty})");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Violation Categories
|
||||
|
||||
The scoring system uses 18 categories. Hard violations (100K penalty) include
|
||||
node crossings, under-node routing, shared lanes, and boundary slot conflicts.
|
||||
Medium violations (50K) include backtracking and detours. Soft violations
|
||||
(200-650) include edge crossings, proximity, and excessive bends.
|
||||
|
||||
A FinalScore of 0 for hard violations indicates a clean layout with no visual
|
||||
defects. See the [Rendering Architecture](../../engine/16-elksharp-rendering-architecture.md)
|
||||
for the full violation taxonomy.
|
||||
|
||||
### Phase Timings
|
||||
|
||||
```csharp
|
||||
if (layout.Diagnostics?.PhaseTimings != null)
|
||||
{
|
||||
foreach (var phase in layout.Diagnostics.PhaseTimings)
|
||||
{
|
||||
Console.WriteLine($"{phase.Name}: {phase.Duration.TotalMilliseconds}ms");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Phase timings cover ordering, placement, gutter expansion, base routing,
|
||||
iterative optimization, and post-processing.
|
||||
|
||||
---
|
||||
|
||||
## End-to-End Example
|
||||
|
||||
```csharp
|
||||
// Compile a workflow definition to a render graph
|
||||
var compiler = new WorkflowRenderGraphCompiler();
|
||||
var graph = compiler.Compile(workflowDefinition);
|
||||
|
||||
// Configure and run layout
|
||||
var engine = new ElkSharpWorkflowRenderLayoutEngine();
|
||||
var request = new WorkflowRenderLayoutRequest
|
||||
{
|
||||
Direction = WorkflowRenderLayoutDirection.LeftToRight,
|
||||
Effort = WorkflowRenderLayoutEffort.Best,
|
||||
NodeSpacing = 40,
|
||||
LayerSpacing = 60,
|
||||
};
|
||||
var layout = await engine.LayoutAsync(graph, request);
|
||||
|
||||
// Render to SVG
|
||||
var svgRenderer = new WorkflowRenderSvgRenderer();
|
||||
var svgDoc = svgRenderer.Render(layout, workflowDefinition.Name);
|
||||
await File.WriteAllTextAsync($"{workflowDefinition.Name}.svg", svgDoc.Svg);
|
||||
|
||||
// Export to PNG at 2x resolution
|
||||
var pngExporter = new WorkflowRenderPngExporter();
|
||||
await pngExporter.ExportAsync(svgDoc, $"{workflowDefinition.Name}.png", scale: 2f);
|
||||
|
||||
// Check for violations
|
||||
var hardViolations = layout.Diagnostics?.ViolationReport?
|
||||
.Where(v => v.Penalty >= 100_000)
|
||||
.ToList();
|
||||
if (hardViolations?.Any() == true)
|
||||
{
|
||||
Console.WriteLine($"WARNING: {hardViolations.Count} hard violations detected");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Further Reading
|
||||
|
||||
- [ElkSharp Rendering Architecture](../../engine/16-elksharp-rendering-architecture.md) --
|
||||
Full technical details of the Sugiyama pipeline, edge routing, and iterative optimization.
|
||||
- [Architectural Decisions](../../engine/17-elksharp-architectural-decisions.md) --
|
||||
ADR records for key design choices.
|
||||
- [ENGINE.md](../../ENGINE.md) -- Workflow engine overview including layout engine
|
||||
configuration and render pipeline.
|
||||
Reference in New Issue
Block a user