# Interfaces L–T

Import these from `@grafloria/engine`.

## Interfaces

### `LayoutRun`

An in-flight, pre-emptible layout computation.

Pure and synchronous by construction: no DOM, no clock, no `Math.random()`.

```ts
interface LayoutRun
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `iteration` | `number` |  | Iterations completed so far. |
| `totalIterations` | `number` |  | Iterations this run would do if left alone — the denominator for progress. |

**Members**

- `step(): boolean` — Advance exactly one iteration.
- `snapshot(): LayoutResult` — The best answer so far. Must be safe to call at ANY point — before the
first step (returns the input positions), midway (returns the partial
simulation), or after the last (returns the final layout).

### `LayoutRunOptions`

Caller-side options that must NEVER cross the wire (they are not clonable).

```ts
interface LayoutRunOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `signal?` | `AbortSignal` |  | Cancel the run. Cooperative: takes effect within one slice. |
| `onProgress?` | `(progress: LayoutProgress) => void` |  | Streaming progress. Called on the caller's thread. |
| `timeBudgetMs?` | `number` |  | Give up after this long and return the best-so-far, flagged partial. |
| `sliceMs?` | `number` |  | Compute-between-yields, ms. Lower = promper cancellation, more overhead. |
| `stopAfterIteration?` | `number` |  | Deterministic pre-emption after N iterations. See LayoutRequestRun. |

### `LayoutSelectionReport`

What the auto-selector chose, and WHY. Returned on the layout result, so the
reasoning is available to a UI, a log line or a test — never hidden.

```ts
interface LayoutSelectionReport
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `chosen` | `string` |  | The candidate that won (its id, e.g. 'elk:layered:RIGHT'). |
| `algorithm` | `string` |  | The registered algorithm behind it. |
| `reason` | `string` |  | One sentence a human can read. |
| `shape` | `GraphShape` |  | What we worked out about the graph before choosing. |
| `candidates` | `CandidateScore[]` |  | Every candidate, scored, best first. Losers included on purpose. |

### `LayoutServePort`

The port surface the SERVER side needs — a worker's `self` satisfies it.

```ts
interface LayoutServePort
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `onmessage` | `((ev: { data: LayoutRequest }) => void) \| null` |  |  |

**Members**

- `postMessage(msg: LayoutResponse): void`

### `LayoutSnapshot`

Snapshot of node positions at a point in time

```ts
interface LayoutSnapshot
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` |  | Unique identifier for this snapshot |
| `timestamp` | `number` |  | Timestamp when snapshot was created |
| `positions` | `Map<string, { x: number; y: number }>` |  | Node positions |
| `description?` | `string` |  | Optional description |
| `algorithm?` | `string` |  | Layout algorithm used |
| `options?` | `any` |  | Layout options used |

### `NodeConstraint`

Constraint definition for a single node

```ts
interface NodeConstraint
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `nodeId` | `string` |  | ID of the node this constraint applies to |
| `type` | `ConstraintType` |  | Type of constraint |
| `position?` | `Position` |  | Fixed position for 'pin' constraint The node will be locked to this exact position |
| `value?` | `number` |  | Fixed value for 'fix-x' or 'fix-y' constraints - For 'fix-x': The X coordinate is locked to this value, Y can vary - For 'fix-y': The Y coordinate is locked to this value, X can vary |
| `boundary?` | `Boundary` |  | Boundary limits for 'boundary' constraint The node position will be clamped within these bounds |
| `priority?` | `number` |  | Priority of this constraint (higher = more important) Used when constraints conflict (default: 0) |

### `OverlapRemovalOptions`

```ts
interface OverlapRemovalOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `spacing?` | `number` |  | Gap to open up between two boxes that were overlapping. |

### `PackBox`

A box to pack, plus the id used to break ties deterministically.

```ts
interface PackBox
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` |  |  |
| `width` | `number` |  |  |
| `height` | `number` |  |  |

### `PackingOptions`

```ts
interface PackingOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `spacing?` | `number` |  | Gap between packed components. Defaults to the layout's `nodeSpacing`. |
| `aspectRatio?` | `number` |  | Target width/height of the packed result. 1.6 ≈ a landscape screen. |

### `PlacementOptions`

Options for calculating node placement

```ts
interface PlacementOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `node` | `NodeModel` |  | The node to place |
| `viewport` | `Rectangle` |  | Current viewport dimensions |
| `existingNodes` | `NodeModel[]` |  | Existing nodes in the diagram |
| `preferredPosition?` | `Point` |  | Preferred position (optional hint) |
| `respectManualPositions?` | `boolean` |  | Whether to respect manual positions of existing nodes |
| `spacing?` | `number` |  | Spacing between nodes |
| `padding?` | `number` |  | Padding from viewport edges |

### `PlacementResult`

Result of placement calculation

```ts
interface PlacementResult
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `position` | `Point` |  | Calculated position for the node |
| `success` | `boolean` |  | Whether placement was successful |
| `metadata?` | `{ /** * Grid position (for grid layouts) */ gridPosition?: { row: number; column: number }; /** * Pattern detected (for hybrid layouts) */ detectedPattern?: 'grid' \| 'tree' \| 'freeform'; /** * Reason for placement choice */ reason?: string; /** * Number of attempts made (for iterative placement) */ attempt?: number; /** * Allow additional metadata properties */ [key: string]: any; }` |  | Metadata about the placement decision |

### `Point2D`

Point in 2D space

```ts
interface Point2D
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `x` | `number` |  |  |
| `y` | `number` |  |  |

### `PortAwareLayoutOptions`

Configuration for port-aware layout

```ts
interface PortAwareLayoutOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `enabled` | `boolean` |  | Enable port-aware layout |
| `ports?` | `PortInfo[]` |  | Port information for all ports in the diagram |
| `autoAssignSides?` | `boolean` |  | Automatic port side assignment based on node connections |
| `autoOrderPorts?` | `boolean` |  | Automatic port ordering to minimize crossings |
| `inputSide?` | `PortSide` |  | Prefer inputs on specific side |
| `outputSide?` | `PortSide` |  | Prefer outputs on specific side |
| `portSpacing?` | `number` |  | Minimum spacing between ports (in pixels) |
| `usePortPositions?` | `boolean` |  | Whether to consider port positions in edge routing |
| `orderingStrategy?` | `'minimize-crossings' \| 'connection-based' \| 'group-based' \| 'manual'` |  | Strategy for port ordering |
| `nodeSidePreferences?` | `{ [nodeId: string]: { inputs?: PortSide; outputs?: PortSide; }; }` |  | Node-specific port side preferences |
| `portOrdering?` | `{ [nodeId: string]: string[]; // Ordered list of port IDs for this node }` |  | Per-port ordering constraints |

### `PortAwareLayoutResult`

Result of port-aware layout computation

```ts
interface PortAwareLayoutResult
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `portAssignments` | `Map<string, PortSide>` |  | Final port assignments (port ID -> side) |
| `portOrdering` | `Map<string, string[]>` |  | Final port ordering (node ID -> ordered port IDs) |
| `portPositions` | `Map<string, { x: number; y: number; side: PortSide }>` |  | Calculated port positions (port ID -> {x, y} relative to node) |
| `edgeCrossings` | `number` |  | Number of edge crossings |
| `wasOptimized` | `boolean` |  | Whether port positions were optimized |
| `autoAssignedPorts` | `string[]` |  | Ports that were automatically assigned sides |
| `autoOrderedPorts` | `string[]` |  | Ports that were automatically ordered |

### `PortInfo`

Information about a port for layout purposes

```ts
interface PortInfo
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` |  | Port unique identifier |
| `nodeId` | `string` |  | Node this port belongs to |
| `preferredSide?` | `PortSide` |  | Preferred side of the node |
| `direction?` | `PortFlowDirection` |  | Port direction |
| `offset?` | `number` |  | Position along the side (0-1, where 0 is top/left, 1 is bottom/right) |
| `fixed?` | `boolean` |  | Fixed position (prevents automatic ordering) |
| `priority?` | `number` |  | Priority for ordering (higher = more important) |
| `group?` | `string` |  | Group identifier for related ports |

### `PortRespectResult`

```ts
interface PortRespectResult
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `violations` | `number` |  | Links whose endpoint travels AGAINST the side its port faces. |
| `judged` | `number` |  | Links that could be judged (both ends resolvable, both nodes placed). |
| `score` | `number` |  | 100 = every port-constrained edge leaves in the direction its port faces. |
| `violatingLinks` | `string[]` |  | Which links violated, for the report. |

### `Position`

Position definition for pinned nodes

```ts
interface Position
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `x` | `number` |  |  |
| `y` | `number` |  |  |

### `QualityAssessmentOptions`

Options for quality assessment

```ts
interface QualityAssessmentOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `includeSuggestions?` | `boolean` |  | Whether to include detailed suggestions |
| `customWeights?` | `{ edgeCrossings?: number; nodeOverlap?: number; edgeLength?: number; nodeDistribution?: number; symmetry?: number; aspectRatio?: number; }` |  | Custom metric weights (overrides defaults) |
| `canvasDimensions?` | `{ width: number; height: number; }` |  | Canvas dimensions for aspect ratio calculation |

### `QualityMetric`

Individual quality metric

```ts
interface QualityMetric
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `string` |  | Metric name |
| `score` | `number` |  | Score (0-100, higher is better) |
| `weight` | `number` |  | Weight of this metric in overall score |
| `description` | `string` |  | Description of what this measures |
| `suggestions?` | `string[]` |  | Suggestions for improvement |

### `RadialLayoutOptions`

Also has every member of `UnifiedLayoutOptions`, `LayoutOptions`, `LayoutRunOptions`, listed on their own entries.

```ts
interface RadialLayoutOptions extends UnifiedLayoutOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `rootId?` | `string` |  | Centre of the rings. Defaults to a source node, else the hub. See pickRoot. |

### `RegisteredLayout`

What a registered layout engine must be able to do.

```ts
interface RegisteredLayout
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `string` |  |  |
| `adapter?` | `LayoutAdapter` |  | The underlying node/link algorithm, when the engine has one. |
| `handlesContainers?` | `boolean` |  | The layout arranges CONTAINERS itself — zones are part of its composition (the architecture layout puts regions on a grid and sizes their frames), so `engine.layout()` must not hand it to the nested-container path, which lays out one container at a time with some other engine. |

**Members**

- `apply(diagram: DiagramModel, options: UnifiedLayoutOptions): Promise<LayoutResult>`

### `ScalePlan`

A structural engine choice made without running a bake-off.

```ts
interface ScalePlan
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `candidates` | `LayoutCandidate[]` |  | Candidates to try, best-first; the first that runs wins. |
| `why` | `string` |  | The structural fact the pick rests on — goes into the report verbatim. |

### `ServeLayoutDeps`

```ts
interface ServeLayoutDeps
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `resolve?` | `(name: string) => LayoutAdapter \| undefined` |  | Name → algorithm. Injected, because the INLINE host resolves against the engine's live registry (so a host-registered custom layout still works), while a real worker resolves against whatever its own bundle registered — a function cannot be posted across a thread boundary, so an extension layout registered at runtime is inline-only, by physics rather than choice. |
| `now?` | `() => number` |  | The clock. Injected so tests can stop it lying. |

### `SpectralLayoutOptions`

Also has every member of `LayoutOptions`, listed on its own entry.

Spectral layout options

```ts
interface SpectralLayoutOptions extends LayoutOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `normalized?` | `boolean` |  | Use normalized Laplacian (default: true) |
| `dimensions?` | `number` |  | Number of dimensions to compute (default: 2) |
| `scale?` | `number` |  | Scale factor for positions (default: 500) |
| `center?` | `boolean` |  | Center the layout (default: true) |
| `convergenceThreshold?` | `number` |  | Power iteration convergence threshold (default: 1e-6) |
| `maxIterations?` | `number` |  | Maximum power iterations (default: 1000) |

### `SteppableLayoutAdapter`

Also has every member of `LayoutAdapter`, listed on its own entry.

A layout adapter that can be driven a step at a time.

Optional: `isSteppable()` is a type guard, and the host degrades gracefully
for adapters that are not.

```ts
interface SteppableLayoutAdapter extends LayoutAdapter
```

**Members**

- `createRun( nodes: NodeModel[], links: LinkModel[], options?: Partial<LayoutOptions> ): LayoutRun`

### `SubgraphLayoutOptions`

Configuration for subgraph layout

```ts
interface SubgraphLayoutOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `enabled` | `boolean` |  | Enable subgraph/group layout |
| `groups?` | `GroupInfo[]` |  | Group information for all groups in the diagram |
| `targetGroups?` | `string[]` |  | Specific group IDs to layout (if undefined, layout all) |
| `recursive?` | `boolean` |  | Whether to recursively layout nested groups |
| `defaultPadding?` | `number` |  | Default padding for groups without explicit padding |
| `boundaryHandling?` | `'strict' \| 'flexible' \| 'none'` |  | How to handle group boundaries |
| `layoutTopLevel?` | `boolean` |  | Whether to layout the top-level (non-grouped) nodes |
| `groupPositioning?` | `'compact' \| 'spacious' \| 'grid' \| 'manual'` |  | Strategy for positioning groups relative to each other |
| `groupSpacing?` | `number` |  | Spacing between groups |
| `autoResize?` | `boolean` |  | Whether to automatically resize groups to fit content |
| `maintainAspectRatio?` | `boolean` |  | Whether to maintain aspect ratio when resizing groups |
| `interGroupLinks?` | `'route-around' \| 'direct' \| 'hidden'` |  | How to handle links between groups |

### `SubgraphLayoutResult`

Result of subgraph layout computation

```ts
interface SubgraphLayoutResult
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `nodePositions` | `Map<string, { x: number; y: number; groupId?: string }>` |  | Node positions within their groups (node ID -> position) |
| `groupPositions` | `Map<string, { x: number; y: number }>` |  | Group positions (group ID -> position) |
| `groupSizes` | `Map<string, { width: number; height: number }>` |  | Computed group sizes (group ID -> size) |
| `laidOutGroups` | `string[]` |  | Groups that were laid out |
| `skippedGroups` | `string[]` |  | Groups that were skipped (fixed, collapsed, etc.) |
| `bounds` | `{ x: number; y: number; width: number; height: number }` |  | Overall bounds |
| `wasRecursive` | `boolean` |  | Whether groups were recursively laid out |

### `TreeLayoutOptions`

Also has every member of `UnifiedLayoutOptions`, `LayoutOptions`, `LayoutRunOptions`, listed on their own entries.

```ts
interface TreeLayoutOptions extends UnifiedLayoutOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `rootId?` | `string` |  | Root of the tree. Defaults to a source node (in-degree 0), else the hub. |
| `branchDirections?` | `Record<string, FlowDirection>` |  | Per-branch direction: the subtree rooted at this node flows this way instead of the tree's `direction`. A mind map is `{ 'child-a': 'LR', 'child-b': 'RL' }`. |
