Archify Renderer Architecture: How Typed Renderers Share Geometry Utilities

Archify implements a typed-renderer architecture where five independent renderers import pure geometry helpers from a shared module to ensure consistent diagram layout across architecture, workflow, sequence, dataflow, and lifecycle diagrams.

Archify is a JSON-to-diagram rendering engine that transforms intermediate representation (JSON-IR) into self-contained HTML visualizations. The renderer architecture in the tt-a1i/archify repository cleanly separates diagram-type concerns from reusable geometric operations, enabling maintainable and performant code generation.

Overview of the Typed-Renderer Architecture

Archify organizes renderers by diagram type under archify/renderers/<type>/. Each renderer is a standalone ES module responsible for one visualization style:


archify/
 └─ renderers/
      ├─ architecture/
      │    └─ render‑architecture.mjs
      ├─ workflow/
      │    └─ render‑workflow.mjs
      ├─ sequence/
      │    └─ render‑sequence.mjs
      ├─ dataflow/
      │    └─ render‑dataflow.mjs
      ├─ lifecycle/
      │    └─ render‑lifecycle.mjs
      └─ shared/
           ├─ geometry.mjs
           ├─ utils.mjs
           └─ validator.mjs

This structure enforces single-responsibility at the directory level while promoting horizontal reuse through the shared/ subdirectory.

The Shared Geometry Module

All five renderers import from archify/renderers/shared/geometry.mjs. This module exports pure, side-effect-free functions for rectangle, segment, and point operations. Because the helpers carry no internal state, renderers can invoke them safely without risk of cross-contamination.

Core Geometry Functions

Function Signature Purpose
rectsOverlap (a, b, gap?) => boolean Detects axis-aligned rectangle intersection with optional clearance
segmentIntersectsRect (segment, rect, gap?) => boolean Determines if a line segment touches or crosses a rectangle
segmentRectClearance (segment, rect) => number | null Returns minimum distance between segment and rectangle, or 0 on intersection
segmentRectIntersectionLength (segment, rect) => number Computes overlapped length of segment inside rectangle
collectLabelRouteClearance ({labels, routedRelations, threshold}) => ClearanceInfo Aggregates clearance data for automatic edge-label routing

These functions enable renderers to measure, test, and adjust layout tables before emitting final SVG or HTML output.

How Renderers Use Shared Geometry Utilities

Import Pattern

Every renderer follows the same import convention:

// From any renderer (e.g., workflow)
import {
  rectsOverlap,
  segmentIntersectsRect,
  segmentRectClearance,
} from '../shared/geometry.mjs';

The relative path ../shared/ resolves consistently because all renderers sit at the same directory depth.

Workflow Renderer Example

In archify/renderers/workflow/render-workflow.mjs, collision detection and edge routing rely on shared helpers:

// archify/renderers/workflow/render-workflow.mjs
import { rectsOverlap, segmentRectClearance } from '../shared/geometry.mjs';

function placeStep(step, existingNodes) {
  const stepRect = { x: step.x, y: step.y, width: step.w, height: step.h };
  
  for (const node of existingNodes) {
    if (rectsOverlap(stepRect, node.rect, 8)) {
      // Resolve collision by adjusting stepRect position
    }
  }
  return stepRect;
}

function routeEdge(start, end, obstacles) {
  const segment = { start, end };
  const clearance = obstacles.reduce((c, obs) => {
    const cur = segmentRectClearance(segment, obs.rect);
    return cur === null ? c : Math.min(c, cur);
  }, Infinity);
  
  // Bend edge if clearance insufficient
  return clearance < 4 ? bendEdge(segment) : segment;
}

Architecture Renderer Example

The archify/renderers/architecture/render-architecture.mjs renderer applies the same helpers for component packing:

// archify/renderers/architecture/render-architecture.mjs
import { rectsOverlap, segmentIntersectsRect } from '../shared/geometry.mjs';

export function layoutComponents(components) {
  // Build component rectangles from JSON-IR
  
  // Ensure no two components overlap
  for (let i = 0; i < components.length; ++i) {
    for (let j = i + 1; j < components.length; ++j) {
      if (rectsOverlap(components[i].rect, components[j].rect, 6)) {
        // Adjust positions to resolve collision
      }
    }
  }
}

Notice that both renderers import overlapping function subsets—each takes only what it needs, and tree-shaking eliminates dead code in production bundles.

Benefits of the Shared Geometry Design

Archify's renderer architecture delivers four operational advantages:

  1. Consistency — All renderers apply identical geometric rules. A gap of 8 pixels means the same visual distance in workflow diagrams as in architecture diagrams.

  2. Maintainability — Geometry logic centralizes in one file. A bug fix to rectsOverlap propagates to every diagram type without individual renderer edits.

  3. Isolation — Renderers remain independent modules. Developers can test, refactor, or replace render-sequence.mjs without touching render-dataflow.mjs or the shared layer.

  4. Performance — Pure functions enable aggressive optimization. JavaScript engines can inline or memoize calls to segmentRectClearance, keeping render times low even for complex diagrams.

Key Source Files

File Role
archify/renderers/shared/geometry.mjs Pure geometry helpers used by all five renderers
archify/renderers/architecture/render-architecture.mjs Architecture diagram renderer
archify/renderers/workflow/render-workflow.mjs Workflow diagram renderer
archify/renderers/sequence/render-sequence.mjs Sequence diagram renderer
archify/renderers/dataflow/render-dataflow.mjs Dataflow diagram renderer
archify/renderers/lifecycle/render-lifecycle.mjs Lifecycle diagram renderer
archify/renderers/shared/utils.mjs Miscellaneous shared utilities
archify/renderers/shared/validator.mjs JSON schema validation across renderers

Summary

  • Archify uses a typed-renderer architecture with five specialized renderers under archify/renderers/<type>/
  • All renderers import pure geometry functions from archify/renderers/shared/geometry.mjs
  • Shared helpers include rectsOverlap, segmentRectClearance, and collectLabelRouteClearance for collision detection and edge routing
  • The pure-function design guarantees consistency, maintainability, isolation, and performance
  • Renderers build type-specific layouts then call shared utilities to validate and adjust geometry before output

Frequently Asked Questions

What diagram types does Archify support?

Archify supports five diagram types: architecture, workflow, sequence, dataflow, and lifecycle. Each has a dedicated renderer module under archify/renderers/.

Why use pure functions for geometry operations?

Pure functions eliminate side effects and state leakage between renderers. They also enable JavaScript engine optimizations like inlining and memoization, reducing render time for complex diagrams.

Can I add a new renderer without modifying existing code?

Yes. Create a new directory under archify/renderers/<your-type>/ with a render-<type>.mjs entry point. Import shared utilities from ../shared/geometry.mjs following the existing pattern. The typed-renderer architecture requires no changes to other renderers or the shared module.

How does Archify prevent diagram elements from overlapping?

Renderers call rectsOverlap(a, b, gap?) from the shared geometry module to detect collisions during layout. The optional gap parameter adds configurable padding between elements.

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 →