# How Archify's Layout Algorithm Handles Automatic Routing: A Deep Dive into the Auto-Route Engine

> Explore Archify's auto-route engine and learn how its layout algorithm handles automatic routing when route fields are omitted or set to auto.

- Repository: [tt-a1i/archify](https://github.com/tt-a1i/archify)
- Tags: deep-dive
- Published: 2026-08-06

---

**Archify's automatic routing engine activates when a relationship's `route` field is omitted or set to `"auto"` and no explicit path constraints (via points, sides, or channels) are provided by the author.**

The automatic routing system in `tt-a1i/archify` is implemented across multiple modules in the renderer pipeline. When drawing architecture diagrams, clean connection routing is essential—Archify balances flexibility (allowing manual override) with intelligence (inferring optimal paths automatically).

---

## When "Auto" Routing Kicks In

In `/archify/renderers/architecture/render-architecture.mjs` (lines 79–86), the renderer checks whether to engage automatic routing:

- The `route` field is missing or explicitly `"auto"`
- No `via` points are specified
- No `channelX/Y`, `fromSide`, `toSide`, or label-position constraints exist

If all these conditions hold, Archify delegates to its automatic routing engine rather than using explicit or forced routing modes.

---

## Inferring Endpoint Sides Automatically

Before calculating paths, Archify must determine **which side of each component** to connect from and to.

### Default Side Selection (`defaultFromSide` / `defaultToSide`)

In `/archify/renderers/shared/geometry.mjs` (lines 1554–1567), the system examines the relative center positions of the two connected components. It selects the "natural" side based on geometric relationships:

```javascript
// Pseudocode based on geometry.mjs implementation
function defaultFromSide(fromCenter, toCenter) {
  const dx = toCenter[0] - fromCenter[0];
  const dy = toCenter[1] - fromCenter[1];
  // Choose side based on dominant axis and direction
  if (Math.abs(dx) > Math.abs(dy)) {
    return dx > 0 ? 'right' : 'left';
  } else {
    return dy > 0 ? 'bottom' : 'top';
  }
}

```

### Explicit Override Support (`chosenSide`)

Lines 1170–1172 in the same file implement `chosenSide`, which allows author-specified sides to override these defaults:

```javascript
function chosenSide(explicit, fallback) {
  return explicit !== undefined ? explicit : fallback;
}

```

---

## Port Spreading for Clean Fan-Out/Fan-In

When multiple connections share the same component side, **collapsing lines** create visual clutter. The `automaticPortSpread` function (lines 1102–1154 in `/archify/renderers/shared/geometry.mjs`) distributes anchor points with a small pixel offset:

- Prevents overlapping connections
- Maintains visual separation without excessive gap
- Applies to both outgoing (fan-out) and incoming (fan-in) edges

---

## The Core Routing Routine: `routeVia`

The automatic routing engine centers on `routeVia`, which handles all routing modes including `"auto"`. Here's the implementation structure from `geometry.mjs`:

```javascript
function routeVia(conn, from, to, start, end, fromSide, toSide) {
  if (conn.via) return conn.via;                // explicit control points
  
  switch (conn.route || 'auto') {
    case 'straight':
      return [];                                // direct straight line
    
    case 'orthogonal-h':
      // forced horizontal dogleg routing
      // ...
    
    case 'orthogonal-v':
      // forced vertical dogleg routing
      // ...
    
    case 'auto':
    default: {
      // 4-a. Check if direct line respects chosen sides
      const deltaX = Math.abs(start[0] - end[0]);
      const deltaY = Math.abs(start[1] - end[1]);
      
      if ((deltaX /* condition for side-respecting direct line */)) {
        // Use direct connection
      }
      // 4-b. Otherwise, compute minimal orthogonal path
      // with appropriate doglegs to respect fromSide/toSide
    }
  }
}

```

### Automatic Path Selection Logic

The `"auto"` case follows a decision hierarchy:

1. **Direct line test**: If a straight connection from the calculated start and end points respects the chosen sides (doesn't require entering/exiting from wrong faces), use it
2. **Minimal orthogonal path**: Otherwise, compute the shortest orthogonal route with one or two doglegs that properly respects `fromSide` and `toSide`
3. **Dogleg preference**: The algorithm biases toward solutions that minimize total wire length and number of bends

---

## Summary

- **Automatic routing triggers** when `route: "auto"` (or omitted) and no explicit constraints exist—checked in `render-architecture.mjs`
- **Side inference** uses relative component positions via `defaultFromSide`/`defaultToSide` in `geometry.mjs`, with `chosenSide` allowing override
- **Port spreading** via `automaticPortSpread` prevents overlapping lines on busy component sides
- **Path calculation** in `routeVia` prefers direct connections when valid, falling back to minimal orthogonal doglegs that respect inferred or specified side constraints

---

## Frequently Asked Questions

### What determines whether Archify uses automatic routing or manual routing?

Archify checks `route` field value and presence of explicit constraints in `render-architecture.mjs` lines 79–86. If `route` is `"auto"` or missing and no `via`, `channelX/Y`, or side specifications exist, automatic routing activates. Any explicit control point or side override disables the auto-engine for that connection.

### How does Archify prevent lines from overlapping when multiple connections share a side?

The `automaticPortSpread` function in `geometry.mjs` (lines 1102–1154) automatically distributes anchor points along the shared side with small pixel offsets. This creates visual separation without requiring manual port positioning from diagram authors.

### Can I override the automatically chosen side for a connection?

Yes. The `chosenSide` helper (lines 1170–1172) checks for explicit `fromSide` or `toSide` values before falling back to `defaultFromSide`/`defaultToSide`. Providing either side in your relationship definition overrides the geometric inference while still allowing automatic path calculation between those fixed endpoints.

### What path does `routeVia` generate in "auto" mode?

`routeVia` first tests whether a direct line respects the chosen entry/exit sides (checking deltaX/deltaY in the auto case). If valid, it returns an empty via array for straight-line rendering. Otherwise, it computes a minimal orthogonal path with doglegs that properly enters from `fromSide` and exits to `toSide`.