GitLab Pipeline VisualizerVS Code extension that visualizes Features
Usage
Commands
Development
Press F5 to launch the Extension Development Host for testing. Layout Algorithm LogA chronological record of every layout technique attempted, the math/idea behind each, outcomes, and current status. Phase 1 — Naive Layout (v0.1.0–v0.1.5)Approach: Simple vertical stacking within fixed-width stage columns, left-to-right stage ordering, basic cubic Bézier curves for edges.
Result: Functional but looked amateur. Lots of edge crossings. Jobs in large stages formed a long vertical column with no relation to their connections. Phase 2 — Sugiyama Framework (v0.1.6–v0.1.7)Idea: The Sugiyama method (Sugiyama, Tagawa, Toda 1981) is the standard four-step approach for layered directed graph drawing:
Math — Median Heuristic: For a node $v$ in layer $L_i$ with neighbors $N(v)$ in layer $L_{i-1}$, the median position is: $$\text{med}(v) = \text{positions}(N(v))\left[\lfloor |N(v)|/2 \rfloor\right]$$ Nodes are sorted by their median. Ties are broken by current position. Math — Catmull-Rom Splines:
For consecutive points $P_0, P_1, P_2, P_3$, the segment from $P_1$ to $P_2$ uses control points:
$$CP_1 = P_1 + \frac{P_2 - P_0}{6}, \quad CP_2 = P_2 - \frac{P_3 - P_1}{6}$$
Producing a Result: Edge crossings reduced dramatically. Smooth curves. But dummy nodes inflated stage heights massively (each dummy was treated as a full-height job). Phase 3 — Dummy Node Height Fix (v0.1.8)Problem: Dummy nodes were given Fix: Introduced Result: ✅ Stage sizes back to normal. Phase 4 — Barycenter Relaxation for Y Coordinates (v0.1.8)Problem: Median heuristic produced "crooked" lines — edges had unnecessary vertical zigzags because median is discontinuous (jumps between neighbor positions). Fix: Replaced median with barycenter (mean) pull plus damped relaxation over 12 iterations, with α decaying from 0.8 to 0.44. Added dummy chain straightening: for each chain of dummy nodes, snap them onto the straight line between their real source and target endpoints. Math — Barycenter: $$\bar{y}(v) = \frac{1}{|N(v)|} \sum_{u \in N(v)} y(u)$$ Then: $y(v) \leftarrow y(v) + \alpha \cdot (\bar{y}(v) - y(v))$, with $\alpha$ decaying each iteration. Math — Dummy Chain Straightening: For a chain $[s, d_1, d_2, \ldots, d_k, t]$, set each $d_i$ to: $$y(d_i) = y(s) + \frac{i}{k+1} \cdot (y(t) - y(s))$$ Result: ✅ Much straighter edges. Cleaner overall appearance. Phase 5 — Same-Stage Dependencies (v0.1.8–v0.1.9)Problem: GitLab CI allows Fix:
Result: ✅ Intra-stage dependencies render correctly without disrupting cross-stage layout. Phase 6 — Absolute Job Positioning (v0.1.9)Problem: Stage boxes were computed first, then jobs placed relative to them. This "trapped" jobs inside predetermined stage geometry, preventing the Sugiyama algorithm from actually moving them to optimal positions. Fix: Reversed the approach: the algorithm assigns absolute Y positions to jobs. Stage boxes then wrap around wherever the jobs actually landed (using the bounding box of all jobs in the stage, plus padding). Result: ✅ Jobs now truly positioned by the algorithm; stages are just visual containers. Phase 7 — Compaction Pass (v0.1.10)Problem: After relaxation, jobs within a stage were too spread out vertically, leaving large empty gaps. Fix: Post-layout compaction: re-pack jobs vertically with standard Result: ✅ Compact stages, ❌ but this effectively undid the algorithm's Y-positioning, reverting to a near-vertical-stack. Phase 8 — Multi-Column Grid Layout (v0.1.11) ❌ REJECTEDProblem: Stages with many jobs (10+) produced very tall, narrow columns. User wanted horizontal spreading. Approach: Column-major grid fill. Constants Result: ❌ User rejected. Grid is too rigid — jobs with different connectivity patterns all get the same fixed positions. 3-job stages shouldn't necessarily be a vertical stack either. The user demanded: "search how to position nodes in a graph, don't use a fixed grid". Phase 9 — Force-Directed Micro-Layout Per Stage (v0.1.12) ✅ CURRENTIdea: Within each stage, run a mini force-directed simulation so jobs find natural 2D positions based on their connectivity to other stages. Forces applied per stage (80 iterations, cooling schedule):
Velocity integration with damping: $$v_t = (v_{t-1} + F) \cdot \delta \cdot \alpha, \quad \delta = 0.85, \quad \alpha = 1 - t/T$$ Stage width adapts: Result: ✅ Jobs position freely based on connectivity. Multi-column layouts emerge naturally for large stages; simple vertical stacks for small stages. Phase 10 — Edge Angle Penalization (v0.1.13) ✅ CURRENTProblem: Edges were visually "crooked" — steep angles over short horizontal distances, and some curves bending backward (right-to-left). Three sub-techniques: 10a. X-Monotone Spline Control PointsClamp Catmull-Rom control points to stay between $P_1.x$ and $P_2.x$: $$cp_{1x} = \text{clamp}(cp_{1x},; P_1.x,; P_2.x)$$ This guarantees the cubic Bézier segment never curves backward. 10b. Segment-Length-Based TensionShort segments produce sharp bends with full Catmull-Rom tension. Scale tension by segment length: $$\tau = \min\left(1, \frac{|P_2 - P_1|}{200}\right)$$ Then: $CP_1 = P_1 + \tau \cdot \frac{P_2 - P_0}{6}$. Short segments → nearly straight lines. Also clamp Y overshoot: $|cp_y - p_y| \leq 0.75 \cdot |P_2.y - P_1.y| + 20$. 10c. Global Edge-Angle Refinement (25 iterations)Post-layout pass that evaluates every cross-stage edge's steepness and applies corrective Y forces to the source and target jobs: $$\text{ratio} = \frac{\Delta y}{\Delta x}, \quad F = K_{angle} \cdot \text{ratio} \cdot \alpha \cdot m_{backward}$$ where $K_{angle} = 0.06$, $m_{backward} = 3.0$ if $\Delta x < 0$ (backward edge), else $1.0$. Source is pushed toward target's Y and vice versa. Overlap resolution runs each iteration to prevent nodes from stacking. Result: ✅ Edges flow more horizontally. No backward-curving splines. Phase 11 — Edge-Node Avoidance Routing (v0.1.14–v0.1.15) ❌ REJECTEDProblem: Edges sometimes draw directly over/through job boxes that aren't their source or target. Approach: Cohen–Sutherland segment-rectangle intersection detection + bypass waypoints. Also X-monotonicity clamping of intermediate waypoints. Bugs encountered (v0.1.14):
Fixes (v0.1.15): Key parsing fixed, same-stage arcs redesigned as rectangular detours, direction-aware clamping. Result: ❌ Still produced messy edges. Fundamental problem: dummy-node waypoints + bypass insertion + Catmull-Rom splines = too many systems fighting each other. Bypass waypoints created new crossings, tension scaling distorted curves, X-monotonicity clamping moved waypoints into unexpected positions. Phase 12 — Port-Based Direct S-Curve Routing (v0.1.16) ✅ CURRENTInsight: Modern pipeline visualizers (GitLab UI, GitHub Actions, Azure Pipelines) don't route edges through intermediate waypoints at all. They use simple port-to-port Bézier S-curves. The Sugiyama dummy nodes are only needed for crossing minimization ordering — they should NOT appear in the final edge drawing. Approach — three components: 12a. Port AssignmentEach node's right side (outgoing) and left side (incoming) gets evenly-spaced connection ports. Ports are sorted by the Y position of the connected node, which naturally minimizes edge crossings at connection points. For a node with $k$ outgoing edges, port $i$ (0-indexed, sorted by target Y) is placed at: $$y_{port}(i) = y_{top} + m + \frac{(h - 2m) \cdot i}{k - 1}$$ where $m = 8$ px margin, $h = $ node height. Single edges connect at center. 12b. Horizontal S-Curve BézierEach cross-stage edge is exactly 2 points — source right port and target left port. Rendered as a single cubic Bézier with purely horizontal control points: $$C_1 = (x_1 + \text{offset},; y_1), \quad C_2 = (x_2 - \text{offset},; y_2)$$ $$\text{offset} = \max(|x_2 - x_1| \times 0.4,; 30)$$ This guarantees: left-to-right flow, smooth curves, no intermediate waypoints to go wrong, no backward bends. 12c. Same-Stage ArcsKept as 4-point rectangular detours: exit right → horizontal to arc point → vertical → enter left. Eliminated: All dummy-node waypoints in edges, edge-node avoidance (Cohen–Sutherland), X-monotonicity clamping, tension-scaled Catmull-Rom, Y-overshoot clamping. Dummy nodes still used for crossing minimization ordering. Result: ✅ Clean, professional-looking edges. Every edge is a simple smooth S-curve from source to target. Roadmap
|