# Routing-First Progressive Disclosure Architecture in Diagram-Design Explained

> Understand the routing-first progressive disclosure architecture in diagram-design. Discover how it efficiently loads modules based on user selection for a faster experience.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: architecture
- Published: 2026-09-06

---

**The routing-first progressive disclosure architecture in diagram-design resolves routing information before any UI components are revealed to the user, enabling lazy loading of heavy modules based on the selected profile.**

Diagram-design, developed by Cathryn Lavery, implements a unique architectural pattern that prioritizes route determination over immediate UI rendering. This approach ensures that the system only loads the components necessary for a specific diagram type, resulting in faster startup times and a more modular codebase. The architecture centers on **marker-first resolution**, where the system parses an input marker to select the appropriate router before any visual elements appear.

## Core Principles of the Architecture

### Marker-First Resolution

The architecture begins with **marker parsing**. According to [`docs/adr/0006-client-profiles-and-marker-first-resolution.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/adr/0006-client-profiles-and-marker-first-resolution.md), the engine examines a token (the marker) that identifies either a diagram type or a client profile. This marker determines which router handles the request.

Only after the router selection completes does the system proceed to reveal subsequent UI controls. This ordering guarantees that no unnecessary rendering code executes before the system knows what type of diagram it needs to support.

### Client Profiles

A **profile** describes a concrete rendering context such as `mermaid`, `drawio`, or `plantuml`. The router evaluates the profile early in the lifecycle, then **lazily loads** the heavyweight UI elements specific to that profile.

This profile-driven approach means:

- The mermaid profile loads mermaid-specific parsers and renderers
- The drawio profile initializes drawio-compatible components
- Unused profiles remain dormant in the codebase

### Static-by-Default Controllers

As documented in [`docs/adr/0001-static-by-default-single-pinned-controller.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/adr/0001-static-by-default-single-pinned-controller.md), controllers in diagram-design are **pinned to a single entry point**. They do not mutate after the initial routing decision.

This static binding delivers two benefits:

1. **Deterministic behavior** — the same input always produces the same routing outcome
2. **Simplified progressive disclosure** — UI components can trust that routing state will not change underneath them

## How the Routing-First Flow Works

The routing-first progressive disclosure architecture follows a strict five-step sequence:

1. **Parse input** — The command line or API call provides a marker (e.g., `import-mermaid`) and optional profile flags
2. **Route selection** — The router matches the marker to a concrete command module like [`commands/import-mermaid.md`](https://github.com/cathrynlavery/diagram-design/blob/main/commands/import-mermaid.md)
3. **Profile resolution** — The selected module reads the profile and determines which rendering engine and assets are required
4. **Progressive UI load** — Only the UI pieces needed for the chosen profile initialize (menus, preview widgets, export options)
5. **Execution** — The command generates the diagram using the resolved routing and profile

## Code Examples from the Repository

### Defining a Marker in a Command File

The file [`commands/import-mermaid.md`](https://github.com/cathrynlavery/diagram-design/blob/main/commands/import-mermaid.md) illustrates how markers and profiles are declared:

```markdown

# import-mermaid

marker: import-mermaid
profile: mermaid
description: Import a Mermaid diagram and render it.

```

This metadata drives the routing decision before any UI code executes.

### Router Implementation Pattern

The core routing logic in [`src/router.js`](https://github.com/cathrynlavery/diagram-design/blob/main/src/router.js) demonstrates marker-first resolution:

```javascript
import { loadCommand } from './loader.js';

export function route(input) {
  const { marker, profile } = parseInput(input);
  const command = loadCommand(marker);           // ← routing first
  return command.run({ profile });               // ← progressive disclosure
}

```

Note the strict ordering: `loadCommand(marker)` completes before `command.run()` begins.

### Progressive UI Disclosure

The [`src/ui.js`](https://github.com/cathrynlavery/diagram-design/blob/main/src/ui.js) module implements lazy loading based on resolved profiles:

```javascript
export function discloseUI(profile) {
  if (profile === 'mermaid') {
    import('./ui/mermaidPanel.js').then(mod => mod.show());
  } else if (profile === 'drawio') {
    import('./ui/drawioPanel.js').then(mod => mod.show());
  }
  // Only the panel for the chosen profile is loaded.
}

```

Dynamic `import()` calls ensure that unused UI modules never enter the bundle.

## Benefits of Routing-First Progressive Disclosure

| Benefit | Mechanism |
|--------|-----------|
| **Performance** | Heavy modules load on-demand, reducing initial bundle size and startup time |
| **Extensibility** | New markers or profiles integrate without modifying core routing logic |
| **Predictability** | Fixed routing sequence guarantees consistent UI state for each diagram type |

## Key Implementation Files

- [`docs/adr/0006-client-profiles-and-marker-first-resolution.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/adr/0006-client-profiles-and-marker-first-resolution.md) — Marker-first routing and profile resolution strategy
- [`docs/adr/0001-static-by-default-single-pinned-controller.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/adr/0001-static-by-default-single-pinned-controller.md) — Static controller design underpinning the routing step
- [`docs/adr/0008-native-host-manifests-share-one-plugin-root.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/adr/0008-native-host-manifests-share-one-plugin-root.md) — Progressive disclosure implementation details
- [`commands/import-mermaid.md`](https://github.com/cathrynlavery/diagram-design/blob/main/commands/import-mermaid.md) — Example command file defining markers and profiles

## Summary

- **Routing-first progressive disclosure** means resolving the route before revealing any UI components
- **Marker-first resolution** in [`docs/adr/0006-client-profiles-and-marker-first-resolution.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/adr/0006-client-profiles-and-marker-first-resolution.md) drives the initial routing decision
- **Client profiles** enable lazy loading of profile-specific modules like mermaid or drawio components
- **Static-by-default controllers** in [`docs/adr/0001-static-by-default-single-pinned-controller.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/adr/0001-static-by-default-single-pinned-controller.md) ensure predictable, immutable routing state
- The architecture delivers improved performance, extensibility, and predictability through strict ordering and dynamic imports

## Frequently Asked Questions

### What makes routing-first progressive disclosure different from traditional lazy loading?

Traditional lazy loading typically defers module loading until a user interacts with a feature. Routing-first progressive disclosure, as implemented in diagram-design, makes the routing decision the **gatekeeper** for all subsequent loading. The system in [`src/router.js`](https://github.com/cathrynlavery/diagram-design/blob/main/src/router.js) resolves the marker and profile before any UI code executes, ensuring that only the exact modules needed for that specific diagram type ever load.

### How does the marker system support new diagram types?

Markers are declared in command files like [`commands/import-mermaid.md`](https://github.com/cathrynlavery/diagram-design/blob/main/commands/import-mermaid.md) using simple metadata. When adding a new diagram type, you create a new command file with its own marker and profile. The router in [`src/router.js`](https://github.com/cathrynlavery/diagram-design/blob/main/src/router.js) automatically discovers these markers without requiring changes to core routing logic, as documented in [`docs/adr/0006-client-profiles-and-marker-first-resolution.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/adr/0006-client-profiles-and-marker-first-resolution.md).

### Why are controllers static-by-default in this architecture?

Static controllers, described in [`docs/adr/0001-static-by-default-single-pinned-controller.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/adr/0001-static-by-default-single-pinned-controller.md), eliminate runtime mutation of routing state. This design choice supports progressive disclosure because UI components can safely assume that the routing decision remains constant throughout their lifecycle. Dynamic controller changes would introduce uncertainty about which UI modules should remain loaded.

### Can routing-first progressive disclosure improve application startup time?

Yes. The architecture's strict ordering ensures that heavy parsing, rendering, and UI modules load only after the lightweight routing phase completes. The [`src/ui.js`](https://github.com/cathrynlavery/diagram-design/blob/main/src/ui.js) implementation uses dynamic `import()` statements to fetch modules like [`mermaidPanel.js`](https://github.com/cathrynlavery/diagram-design/blob/main/mermaidPanel.js) or [`drawioPanel.js`](https://github.com/cathrynlavery/diagram-design/blob/main/drawioPanel.js) only when their respective profiles are active, keeping the initial bundle minimal.