# How Archify's Preview Mode Works: A Deep Dive into the Attribute-Driven Overlay System

> Explore Archify's preview mode. Discover how data attributes and a MotionGovernor create dynamic overlays for SVG elements, enhancing navigation without permanent changes.

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

---

**Archify's preview mode uses data attributes on SVG elements coordinated by a token-based MotionGovernor to render temporary highlights for chapters, legends, and relationships without permanent navigation.**

Archify implements a sophisticated preview system that allows users to temporarily visualize architectural relationships and chapters through CSS-driven overlays. According to the `tt-a1i/archify` source code, this system relies on modular JavaScript handlers that manipulate data attributes on the main SVG canvas, all coordinated by a central MotionGovernor to prevent conflicting interactions.

## The Three Pillars of Archify Preview Mode

The preview architecture rests on three distinct technical concepts that work together to create smooth, non-destructive visual feedback.

### Data-Attribute Driven Rendering

Rather than modifying DOM structures directly, Archify's preview mode expresses state entirely through **data attributes** on SVG elements. When a preview activates, the system sets attributes such as `data-chapter-preview`, `data-legend-preview-active`, or `data-relationship-preview-active` on the root SVG element. Individual nodes receive specific markers like `data-legend-preview-match`, `data-legend-preview-selected`, or `data-relationship-preview-source`. CSS rules target these attributes to render colored overlays, connection lines, and opacity changes without JavaScript manipulating styles directly.

### Modular Preview Handlers

Three specialized modules handle distinct preview types, each encapsulating its own attribute logic:

- **Legend previews** ([`viewer/semantic-lens.js`](https://github.com/tt-a1i/archify/blob/main/viewer/semantic-lens.js)): Handle `PREVIEW_KINDS` constants including `MATCH`, `SELECTED`, and `PEER`, applying recursive highlighting through `previewLegend()` and cleaning up via `clearLegendPreview()`.
- **Chapter previews** ([`viewer/guided-views.js`](https://github.com/tt-a1i/archify/blob/main/viewer/guided-views.js)): Manage document-section highlighting through `previewChapter()` and `clearChapterPreview()`, setting `data-chapter-preview` attributes.
- **Relationship previews** ([`viewer/focus.js`](https://github.com/tt-a1i/archify/blob/main/viewer/focus.js)): Highlight specific edges and nodes using `previewRelationship()`, which reads `data-relationship-key` and `data-edge-key` attributes to draw connections between source and target elements.

### MotionGovernor Exclusivity

To prevent overlapping previews from conflicting, Archify employs a **token-based governor** exposed globally as `Archify.motionGovernor`. This lightweight coordinator guarantees only one preview type owns the interaction slot at any moment. When `previewChapter()` activates, it claims the governor token, temporarily blocking legend and relationship previews until the token releases.

## Implementation Details by Preview Type

Each preview type follows a consistent pattern: claim the governor, set data attributes, and register cleanup callbacks.

### Legend Previews in Semantic Lens

The [`viewer/semantic-lens.js`](https://github.com/tt-a1i/archify/blob/main/viewer/semantic-lens.js) module manages legend-driven highlights through three distinct visual tiers defined in `PREVIEW_KINDS`:

```javascript
const PREVIEW_KINDS = {
  MATCH: 'match',
  SELECTED: 'selected', 
  PEER: 'peer',
};

```

When `previewLegend(entry)` executes, it first validates the entry exists, then determines the preview kind via `previewLegendKind()`. The function marks the SVG with `data-legend-preview-active`, highlights the primary node with `data-legend-preview-match`, and applies kind-specific attributes (`data-legend-preview-selected` or `data-legend-preview-peer`) based on the entry type. If the entry contains edge members, it iterates through `entry.edge.members` to highlight connected elements.

To clear legend previews, `clearLegendPreview()` removes the global attribute and queries for all elements bearing `data-legend-preview-match`, `data-legend-preview-selected`, or `data-legend-preview-peer` attributes, stripping each to restore the default view.

### Chapter Previews in Guided Views

Chapter previews operate through [`viewer/guided-views.js`](https://github.com/tt-a1i/archify/blob/main/viewer/guided-views.js) using defensive programming principles. The `previewChapter(index)` function first checks if the requested view is already active by comparing `activePreviewIndex` and verifying `svg.getAttribute('data-chapter-preview')` matches `views[index].id`.

Upon activation, the function sets `data-chapter-preview` to the view's identifier and marks the corresponding chapter button with `data-preview-active="true"`. Crucially, it claims the MotionGovernor token through `Archify.motionGovernor.claim('chapter-preview', callback)`, which auto-releases after 5000ms or when explicitly cleared. The cleanup callback resets `previewOwnerToken` to zero and invokes `clearChapterPreview()`.

### Relationship Previews in Focus

The [`viewer/focus.js`](https://github.com/tt-a1i/archify/blob/main/viewer/focus.js) module handles relationship visualization through `previewRelationship(button, options)`. This function extracts relationship keys from `data-relationship-key` attributes, then marks matching edges via `data-edge-key` comparisons. It highlights source and target nodes by ID, setting `data-relationship-preview-source` and `data-relationship-preview-target` attributes respectively.

When `options.direct` is not `true`, the function also activates a visual indicator by setting `data-relationship-previewing="true"` on the appropriate chip element, providing users with feedback that an indirect relationship is being examined.

## The MotionGovernor Coordination Layer

Located in [`viewer/motion-governor.js`](https://github.com/tt-a1i/archify/blob/main/viewer/motion-governor.js), the MotionGovernor prevents race conditions between rapid user interactions. The implementation uses a simple object with `claim()` and `release()` methods:

```javascript
const governor = {
  current: null,
  claim(kind, onRelease) {
    if (this.current) return null;
    this.current = {kind, onRelease};
    setTimeout(() => {
      this.release(this.current);
    }, 5000);
    return this.current;
  },
  release(token) {
    if (this.current !== token) return;
    const {onRelease} = this.current;
    this.current = null;
    if (typeof onRelease === 'function') onRelease();
  }
};

```

The governor integrates into the global namespace through [`viewer/viewer-chrome-layout.js`](https://github.com/tt-a1i/archify/blob/main/viewer/viewer-chrome-layout.js), which exposes `window.Archify.motionGovernor` for cross-module access. This centralization ensures that chapter previews automatically suppress legend highlights, and relationship previews cannot interfere with active chapter navigation.

## Practical Code Examples

### Initializing a Legend Preview

```javascript
import {previewLegend, clearLegendPreview, LegendPreviewKinds} from './viewer/semantic-lens.js';

// Construct a legend entry highlighting a specific node as "selected"
const legendEntry = {
  id: 'arch-component-42',
  kind: LegendPreviewKinds.SELECTED,
  edge: {
    members: [] // Array of DOM elements to highlight
  }
};

// Activate the preview
previewLegend(legendEntry);

// Clear when done
clearLegendPreview();

```

### Starting a Chapter Preview

```javascript
import {previewChapter, clearChapterPreview} from './viewer/guided-views.js';

// Preview the chapter at index 3
const success = previewChapter(3);
if (success) {
  console.log('Chapter preview active for 5 seconds');
}

// Manual cleanup (optional - governor auto-releases)
clearChapterPreview();

```

### Triggering Relationship Highlights

```javascript
import {previewRelationship} from './viewer/focus.js';

// Select a button element containing relationship metadata
const relButton = document.querySelector('[data-relationship-key="user-auth-flow"]');

// Show indirect preview with UI chip
previewRelationship(relButton, {direct: false});

// The preview automatically clears via MotionGovernor timeout

```

## Summary

Archify's preview mode represents a clean separation of concerns between state management and visual rendering:

- **Attribute-based state** allows CSS to handle all visual changes while JavaScript manages data attributes on the SVG and its child elements.
- **Three specialized modules** handle distinct preview contexts: [`viewer/semantic-lens.js`](https://github.com/tt-a1i/archify/blob/main/viewer/semantic-lens.js) for legends, [`viewer/guided-views.js`](https://github.com/tt-a1i/archify/blob/main/viewer/guided-views.js) for chapters, and [`viewer/focus.js`](https://github.com/tt-a1i/archify/blob/main/viewer/focus.js) for relationships.
- **MotionGovernor coordination** prevents UI conflicts through a 5000ms token-based locking mechanism exposed globally via `Archify.motionGovernor`.
- **Recursive highlighting** supports complex legend hierarchies through chainable `previewLegend()` calls that traverse `entry.next` pointers.
- **Defensive cleanup** ensures transient UI states never persist through comprehensive attribute removal functions like `clearLegendPreview()` and `clearChapterPreview()`.

## Frequently Asked Questions

### How does Archify prevent multiple previews from overlapping?

Archify uses the **MotionGovernor** in [`viewer/motion-governor.js`](https://github.com/tt-a1i/archify/blob/main/viewer/motion-governor.js) to enforce exclusive access. When any preview activates—whether chapter, legend, or relationship—it calls `Archify.motionGovernor.claim()`, which returns a token only if no other preview currently holds the slot. If the governor is occupied, subsequent preview requests are ignored until the current token releases via timeout (5000ms) or explicit `release()` call.

### What are the different legend preview kinds available?

The [`viewer/semantic-lens.js`](https://github.com/tt-a1i/archify/blob/main/viewer/semantic-lens.js) module defines three preview kinds in the `PREVIEW_KINDS` constant: **MATCH** (standard highlighting), **SELECTED** (primary selection emphasis via `data-legend-preview-selected`), and **PEER** (related elements styling via `data-legend-preview-peer`). The `previewLegendKind()` function normalizes entry kinds to these constants, defaulting to MATCH for unknown values.

### How long does a preview remain active before auto-clearing?

All previews governed by the MotionGovernor automatically release after **5000 milliseconds** (5 seconds). This timeout is hardcoded in the `claim()` method within [`viewer/motion-governor.js`](https://github.com/tt-a1i/archify/blob/main/viewer/motion-governor.js) using `setTimeout()`. Developers can also clear previews immediately using the exported cleanup functions: `clearLegendPreview()`, `clearChapterPreview()`, or manual `governor.release(token)` calls.

### Can I extend the preview system for custom visualization types?

Yes. The modular architecture in [`viewer/guided-views.js`](https://github.com/tt-a1i/archify/blob/main/viewer/guided-views.js) demonstrates the extension pattern through its `preview()` dispatcher function. To add custom previews, create a new handler module that manages specific data attributes, then integrate it into the dispatcher. Ensure your implementation claims the MotionGovernor token via `Archify.motionGovernor.claim()` to maintain compatibility with existing preview modes and prevent visual conflicts.