Routing-First Progressive Disclosure Architecture in Diagram-Design Explained

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, 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, 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
  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 illustrates how markers and profiles are declared:


# 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 demonstrates marker-first resolution:

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 module implements lazy loading based on resolved profiles:

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

Summary

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 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 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 automatically discovers these markers without requiring changes to core routing logic, as documented in 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, 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 implementation uses dynamic import() statements to fetch modules like mermaidPanel.js or drawioPanel.js only when their respective profiles are active, keeping the initial bundle minimal.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →